Commit Diff


commit - b2cfc4e2e71d0f0a5113ddfbd93c8285cc4d74e4
commit + ed7c8e8d02c02bdbff1e88a6d8d1419f39af48ad
blob - /dev/null
blob + 9911f992adecbfd45ea14229ff7d354d2d925ab1 (mode 644)
--- /dev/null
+++ src/cmd/mk/NOTICE
@@ -0,0 +1,27 @@
+Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+Portions Copyright © 1995-1997 C H Forsyth (forsyth@caldo.demon.co.uk).  All rights reserved.
+Portions Copyright © 1997-1999 Vita Nuova Limited.  All rights reserved.
+Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Under a licence agreement with Lucent Technologies Inc. effective 1st March 2000,
+Vita Nuova Holdings Limited has the right to determine (within a specified scope)
+the form and content of sublicences for this software.
+
+Vita Nuova Holdings Limited now makes this software available as Free
+Software under the terms of the `GNU General Public LIcense, Version 2'
+(see the file LICENCE or http://www.fsf.org/copyleft/gpl.html for
+the full terms and conditions).  One of the conditions of that licence
+is that you must keep intact all notices that refer to that licence and to the absence of
+of any warranty: for this software, note that includes this NOTICE file in particular.
+  
+This suite of programs 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.
+
+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 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 above.
blob - /dev/null
blob + 3bd11ff2eaca9601f3bba2fe995d368e208599bf (mode 644)
--- /dev/null
+++ src/cmd/mk/README
@@ -0,0 +1,7 @@
+This is a Unix port of mk,
+originally done for the Inferno operating system.
+
+Russ Cox repackaged this to build as a standalone
+Unix program.  Send comments about packaging to
+Russ Cox <rsc@post.harvard.edu>
+
blob - /dev/null
blob + 979403bcaa561eb3cc02278e24360e4203b1ac50 (mode 644)
--- /dev/null
+++ src/cmd/mk/bufblock.c
@@ -0,0 +1,88 @@
+#include	"mk.h"
+
+static Bufblock *freelist;
+#define	QUANTA	4096
+
+Bufblock *
+newbuf(void)
+{
+	Bufblock *p;
+
+	if (freelist) {
+		p = freelist;
+		freelist = freelist->next;
+	} else {
+		p = (Bufblock *) Malloc(sizeof(Bufblock));
+		p->start = Malloc(QUANTA*sizeof(*p->start));
+		p->end = p->start+QUANTA;
+	}
+	p->current = p->start;
+	*p->start = 0;
+	p->next = 0;
+	return p;
+}
+
+void
+freebuf(Bufblock *p)
+{
+	p->next = freelist;
+	freelist = p;
+}
+
+void
+growbuf(Bufblock *p)
+{
+	int n;
+	Bufblock *f;
+	char *cp;
+
+	n = p->end-p->start+QUANTA;
+		/* search the free list for a big buffer */
+	for (f = freelist; f; f = f->next) {
+		if (f->end-f->start >= n) {
+			memcpy(f->start, p->start, p->end-p->start);
+			cp = f->start;
+			f->start = p->start;
+			p->start = cp;
+			cp = f->end;
+			f->end = p->end;
+			p->end = cp;
+			f->current = f->start;
+			break;
+		}
+	}
+	if (!f) {		/* not found - grow it */
+		p->start = Realloc(p->start, n);
+		p->end = p->start+n;
+	}
+	p->current = p->start+n-QUANTA;
+}
+
+void
+bufcpy(Bufblock *buf, char *cp, int n)
+{
+
+	while (n--)
+		insert(buf, *cp++);
+}
+
+void
+insert(Bufblock *buf, int c)
+{
+
+	if (buf->current >= buf->end)
+		growbuf(buf);
+	*buf->current++ = c;
+}
+
+void
+rinsert(Bufblock *buf, Rune r)
+{
+	int n;
+
+	n = runelen(r);
+	if (buf->current+n > buf->end)
+		growbuf(buf);
+	runetochar(buf->current, &r);
+	buf->current += n;
+}
blob - /dev/null
blob + cee937608f33530b5c539c412fea43a3ed64750f (mode 644)
--- /dev/null
+++ src/cmd/mk/job.c
@@ -0,0 +1,33 @@
+#include	"mk.h"
+
+Job *
+newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, Word *tar, Word *atar)
+{
+	register Job *j;
+
+	j = (Job *)Malloc(sizeof(Job));
+	j->r = r;
+	j->n = nlist;
+	j->stem = stem;
+	j->match = match;
+	j->p = pre;
+	j->np = npre;
+	j->t = tar;
+	j->at = atar;
+	j->nproc = -1;
+	j->next = 0;
+	return(j);
+}
+
+void
+dumpj(char *s, Job *j, int all)
+{
+	Bprint(&bout, "%s\n", s);
+	while(j){
+		Bprint(&bout, "job@%ld: r=%ld n=%ld stem='%s' nproc=%d\n",
+			j, j->r, j->n, j->stem, j->nproc);
+		Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprereq='%s'\n",
+			wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wtos(j->np, ' '));
+		j = all? j->next : 0;
+	}
+}
blob - /dev/null
blob + d7b68c76db9a229565833f12b4ea20aea22cf0ef (mode 644)
Binary files /dev/null and src/cmd/mk/mk.pdf differ
blob - /dev/null
blob + b78a89daa02206bc37af94154ceb2e1ac679cfe9 (mode 644)
--- /dev/null
+++ src/cmd/sam/README
@@ -0,0 +1,29 @@
+This is sam (not including samterm) from the 4th edition of Plan 9,
+with changes so that it can be compiled under unix.
+(Tested on Solaris 7 and Debian 3.0r1.)
+
+Some extra libraries are needed.  First, fetch libutf-2.0 and libfmt-2.0
+from
+	http://pdos.lcs.mit.edu/~rsc/software/
+
+(Beware that in libfmt/fmt.c there is a line that says:
+        'u',    __ifmt,         /* in Plan 9, __flagfmt */
+Thus, sam will have to fmtinstall the other thing.  Other ported programs
+may have to do the same.  The fmt library should probably print messages
+about bad format characters to stderr, since no one seems to check the
+return codes.)
+
+Compile and install those two libraries.  
+Set PREFIX in the Makefile to match, then compile sam.
+
+Your C compiler will emit many complaints of the form:
+  sam.c:496: warning: passing arg 1 of `bufread' from incompatible pointer type
+
+This is because the Plan 9 compiler has a slightly different (better,
+ala Oberon) type system than ISO C.  Popular compilers generate the right
+code, so in an act of civil disobediance I changed just enough to get
+it to compile, but left the type errors in.  Now the next C standard can
+adopt this extension, because at least one important C program uses it!
+
+-- Scott Schwartz,  4 July 2003
+
blob - /dev/null
blob + 656189182946baaedf6bbe934e2d7cc0f9497ff1 (mode 644)
--- /dev/null
+++ src/cmd/sam/_libc.h
@@ -0,0 +1,40 @@
+#define __USE_UNIX98  // for pread/pwrite, supposedly
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include "utf.h"
+#include "fmt.h"
+
+#define nil 0
+#define dup dup2
+#define exec execv
+#define seek lseek
+#define getwd getcwd
+#define USED(a)
+#define SET(a)
+
+enum {
+	OREAD = 0,
+	OWRITE = 1,
+	ORDWR = 2,
+	OCEXEC = 4,
+	ORCLOSE = 8
+};
+
+enum {
+	ERRMAX = 255
+};
+
+void exits(const char *);
+void _exits(const char *);
+int notify (void(*f)(void *, char *));
+int create(char *, int, int);
+int errstr(char *, int);
blob - /dev/null
blob + 2a36c23b211041202b6717f6a3704c10434002fb (mode 644)
--- /dev/null
+++ src/cmd/sam/err
@@ -0,0 +1,39 @@
+address.c: In function `filematch':
+address.c:159: warning: passing arg 1 of `bufreset' from incompatible pointer type
+address.c:160: warning: passing arg 1 of `bufinsert' from incompatible pointer type
+file.c: In function `mergeextend':
+file.c:117: warning: passing arg 1 of `bufread' from incompatible pointer type
+file.c: In function `fileinsert':
+file.c:275: warning: passing arg 1 of `bufinsert' from incompatible pointer type
+file.c: In function `filedelete':
+file.c:301: warning: passing arg 1 of `bufdelete' from incompatible pointer type
+file.c: In function `fileundelete':
+file.c:324: warning: passing arg 1 of `bufread' from incompatible pointer type
+file.c: In function `filereadc':
+file.c:339: warning: passing arg 1 of `bufread' from incompatible pointer type
+file.c: In function `fileload':
+file.c:405: warning: passing arg 1 of `bufload' from incompatible pointer type
+file.c: In function `fileundo':
+file.c:528: warning: passing arg 1 of `bufdelete' from incompatible pointer type
+file.c:546: warning: passing arg 1 of `bufinsert' from incompatible pointer type
+file.c: In function `fileclose':
+file.c:604: warning: passing arg 1 of `bufclose' from incompatible pointer type
+io.c: In function `readio':
+io.c:90: warning: passing arg 1 of `bufload' from incompatible pointer type
+io.c: In function `writeio':
+io.c:152: warning: passing arg 1 of `bufread' from incompatible pointer type
+mesg.c: In function `inmesg':
+mesg.c:248: warning: passing arg 1 of `bufread' from incompatible pointer type
+mesg.c: In function `snarf':
+mesg.c:568: warning: passing arg 1 of `bufread' from incompatible pointer type
+mesg.c: In function `setgenstr':
+mesg.c:612: warning: passing arg 1 of `bufread' from incompatible pointer type
+sam.c: In function `readcmd':
+sam.c:496: warning: passing arg 1 of `bufread' from incompatible pointer type
+sam.c: In function `copy':
+sam.c:676: warning: passing arg 1 of `bufread' from incompatible pointer type
+xec.c: In function `s_cmd':
+xec.c:234: warning: passing arg 1 of `bufread' from incompatible pointer type
+xec.c:243: warning: passing arg 1 of `bufread' from incompatible pointer type
+xec.c: In function `display':
+xec.c:401: warning: passing arg 1 of `bufread' from incompatible pointer type
blob - /dev/null
blob + d376acd0abc6ff518380fef76fe8d54eba199e9e (mode 644)
--- /dev/null
+++ src/cmd/sam/plumb.h
@@ -0,0 +1,17 @@
+typedef struct Plumbmsg Plumbmsg;
+
+struct Plumbmsg {
+        char *src;
+        char *dst;
+        char *wdir;
+        char *type;
+        char *attr;
+        char *data;
+        int ndata;
+};
+
+char *plumbunpackattr(char*);
+char *plumbpack(Plumbmsg *, int *);
+int plumbfree(Plumbmsg *);
+char *cleanname(char*);
+
blob - /dev/null
blob + 9a4b9a71b29c3ada0c2b8b24d7a34b201a9bab24 (mode 644)
--- /dev/null
+++ src/cmd/sam/string.c
@@ -0,0 +1,193 @@
+#include "sam.h"
+
+#define	MINSIZE	16		/* minimum number of chars allocated */
+#define	MAXSIZE	256		/* maximum number of chars for an empty string */
+
+
+void
+Strinit(String *p)
+{
+	p->s = emalloc(MINSIZE*RUNESIZE);
+	p->n = 0;
+	p->size = MINSIZE;
+}
+
+void
+Strinit0(String *p)
+{
+	p->s = emalloc(MINSIZE*RUNESIZE);
+	p->s[0] = 0;
+	p->n = 1;
+	p->size = MINSIZE;
+}
+
+void
+Strclose(String *p)
+{
+	free(p->s);
+}
+
+void
+Strzero(String *p)
+{
+	if(p->size > MAXSIZE){
+		p->s = erealloc(p->s, RUNESIZE*MAXSIZE); /* throw away the garbage */
+		p->size = MAXSIZE;
+	}
+	p->n = 0;
+}
+
+int
+Strlen(Rune *r)
+{
+	Rune *s;
+
+	for(s=r; *s; s++)
+		;
+	return s-r;
+}
+
+void
+Strdupl(String *p, Rune *s)	/* copies the null */
+{
+	p->n = Strlen(s)+1;
+	Strinsure(p, p->n);
+	memmove(p->s, s, p->n*RUNESIZE);
+}
+
+void
+Strduplstr(String *p, String *q)	/* will copy the null if there's one there */
+{
+	Strinsure(p, q->n);
+	p->n = q->n;
+	memmove(p->s, q->s, q->n*RUNESIZE);
+}
+
+void
+Straddc(String *p, int c)
+{
+	Strinsure(p, p->n+1);
+	p->s[p->n++] = c;
+}
+
+void
+Strinsure(String *p, ulong n)
+{
+	if(n > STRSIZE)
+		error(Etoolong);
+	if(p->size < n){	/* p needs to grow */
+		n += 100;
+		p->s = erealloc(p->s, n*RUNESIZE);
+		p->size = n;
+	}
+}
+
+void
+Strinsert(String *p, String *q, Posn p0)
+{
+	Strinsure(p, p->n+q->n);
+	memmove(p->s+p0+q->n, p->s+p0, (p->n-p0)*RUNESIZE);
+	memmove(p->s+p0, q->s, q->n*RUNESIZE);
+	p->n += q->n;
+}
+
+void
+Strdelete(String *p, Posn p1, Posn p2)
+{
+	memmove(p->s+p1, p->s+p2, (p->n-p2)*RUNESIZE);
+	p->n -= p2-p1;
+}
+
+int
+Strcmp(String *a, String *b)
+{
+	int i, c;
+
+	for(i=0; i<a->n && i<b->n; i++)
+		if(c = (a->s[i] - b->s[i]))	/* assign = */
+			return c;
+	/* damn NULs confuse everything */
+	i = a->n - b->n;
+	if(i == 1){
+		if(a->s[a->n-1] == 0)
+			return 0;
+	}else if(i == -1){
+		if(b->s[b->n-1] == 0)
+			return 0;
+	}
+	return i;
+}
+
+int
+Strispre(String *a, String *b)
+{
+	int i;
+
+	for(i=0; i<a->n && i<b->n; i++){
+		if(a->s[i] - b->s[i]){	/* assign = */
+			if(a->s[i] == 0)
+				return 1;
+			return 0;
+		}
+	}
+	return i == a->n;
+}
+
+char*
+Strtoc(String *s)
+{
+	int i;
+	char *c, *d;
+	Rune *r;
+	c = emalloc(s->n*UTFmax + 1);  /* worst case UTFmax bytes per rune, plus NUL */
+	d = c;
+	r = s->s;
+	for(i=0; i<s->n; i++)
+		d += runetochar(d, r++);
+	if(d==c || d[-1]!=0)
+		*d = 0;
+	return c;
+
+}
+
+/*
+ * Build very temporary String from Rune*
+ */
+String*
+tmprstr(Rune *r, int n)
+{
+	static String p;
+
+	p.s = r;
+	p.n = n;
+	p.size = n;
+	return &p;
+}
+
+/*
+ * Convert null-terminated char* into String
+ */
+String*
+tmpcstr(char *s)
+{
+	String *p;
+	Rune *r;
+	int i, n;
+
+	n = utflen(s);	/* don't include NUL */
+	p = emalloc(sizeof(String));
+	r = emalloc(n*RUNESIZE);
+	p->s = r;
+	for(i=0; i<n; i++,r++)
+		s += chartorune(r, s);
+	p->n = n;
+	p->size = n;
+	return p;
+}
+
+void
+freetmpstr(String *s)
+{
+	free(s->s);
+	free(s);
+}
blob - /dev/null
blob + db54d28d6a168d1604fd735ed94ad12290d0e6d6 (mode 644)
--- /dev/null
+++ src/cmd/sam/sys.c
@@ -0,0 +1,60 @@
+#include "sam.h"
+
+static int inerror=FALSE;
+
+/*
+ * A reasonable interface to the system calls
+ */
+
+void
+resetsys(void)
+{
+	inerror = FALSE;
+}
+
+void
+syserror(char *a)
+{
+	char buf[ERRMAX];
+
+	if(!inerror){
+		inerror=TRUE;
+		errstr(buf, sizeof buf);
+		dprint("%s: ", a);
+		error_s(Eio, buf);
+	}
+}
+
+int
+Read(int f, void *a, int n)
+{
+	char buf[ERRMAX];
+
+	if(read(f, (char *)a, n)!=n) {
+		if (lastfile)
+			lastfile->rescuing = 1;
+		errstr(buf, sizeof buf);
+		if (downloaded)
+			fprint(2, "read error: %s\n", buf);
+		rescue();
+		exits("read");
+	}
+	return n;
+}
+
+int
+Write(int f, void *a, int n)
+{
+	int m;
+
+	if((m=write(f, (char *)a, n))!=n)
+		syserror("write");
+	return m;
+}
+
+void
+Seek(int f, long n, int w)
+{
+	if(seek(f, n, w)==-1)
+		syserror("seek");
+}
blob - /dev/null
blob + b259968949cd7e5b8e680bf725ff0d92643a32ae (mode 644)
--- /dev/null
+++ src/cmd/sam/util.c
@@ -0,0 +1,54 @@
+#include "sam.h"
+
+void
+cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
+{
+	uchar *q;
+	Rune *s;
+	int j, w;
+
+	/*
+	 * Always guaranteed that n bytes may be interpreted
+	 * without worrying about partial runes.  This may mean
+	 * reading up to UTFmax-1 more bytes than n; the caller
+	 * knows this.  If n is a firm limit, the caller should
+	 * set p[n] = 0.
+	 */
+	q = (uchar*)p;
+	s = r;
+	for(j=0; j<n; j+=w){
+		if(*q < Runeself){
+			w = 1;
+			*s = *q++;
+		}else{
+			w = chartorune(s, (char*)q);
+			q += w;
+		}
+		if(*s)
+			s++;
+		else if(nulls)
+			*nulls = TRUE;
+	}
+	*nb = (char*)q-p;
+	*nr = s-r;
+}
+
+void*
+fbufalloc(void)
+{
+	return emalloc(BUFSIZE);
+}
+
+void
+fbuffree(void *f)
+{
+	free(f);
+}
+
+uint
+min(uint a, uint b)
+{
+	if(a < b)
+		return a;
+	return b;
+}
blob - /dev/null
blob + 09d60ec9cb3b19f17fdb87ee56bff20dbfa48d8f (mode 644)
--- /dev/null
+++ src/libdraw/allocimagemix.c
@@ -0,0 +1,43 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+Image*
+allocimagemix(Display *d, u32int color1, u32int color3)
+{
+	Image *t, *b;
+	static Image *qmask;
+
+	if(qmask == nil)
+		qmask = allocimage(d, Rect(0,0,1,1), GREY8, 1, 0x3F3F3FFF);
+		
+	if(d->screenimage->depth <= 8){	/* create a 2×2 texture */
+		t = allocimage(d, Rect(0,0,1,1), d->screenimage->chan, 0, color1);
+		if(t == nil)
+			return nil;
+
+		b = allocimage(d, Rect(0,0,2,2), d->screenimage->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->screenimage->chan, 1, color1);
+		if(t == nil)
+			return nil;
+
+		b = allocimage(d, Rect(0,0,1,1), d->screenimage->chan, 1, color3);
+		if(b == nil){
+			freeimage(t);
+			return nil;
+		}
+
+		draw(b, b->r, t, qmask, ZP);
+		freeimage(t);
+		return b;
+	}
+}
blob - /dev/null
blob + dca61bc0beabd20af3f4848e49732bb559bf9aad (mode 644)
--- /dev/null
+++ src/libdraw/bezier.c
@@ -0,0 +1,244 @@
+#include <u.h>
+#include <libc.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
+bezsplinepts(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;
+}
blob - /dev/null
blob + 22637dfadafbae63ddda09b55bbc80fa5fbf60e0 (mode 644)
--- /dev/null
+++ src/libdraw/border.c
@@ -0,0 +1,21 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+void
+border(Image *im, Rectangle r, int i, Image *color, Point sp)
+{
+	if(i < 0){
+		r = insetrect(r, i);
+		sp = addpt(sp, Pt(i,i));
+		i = -i;
+	}
+	draw(im, Rect(r.min.x, r.min.y, r.max.x, r.min.y+i),
+		color, nil, sp);
+	draw(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));
+	draw(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));
+	draw(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));
+}
blob - /dev/null
blob + eb30466cb61793dee0360924498ff9ec2f3d3920 (mode 644)
--- /dev/null
+++ src/libdraw/cloadimage.c
@@ -0,0 +1,49 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.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;
+}
blob - /dev/null
blob + 30a3d11e63e9a969b03993229f875643fd99d50b (mode 644)
--- /dev/null
+++ src/libdraw/computil.c
@@ -0,0 +1,38 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+/*
+ * compressed data are seuences 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;
+}
blob - /dev/null
blob + 3a6788a83e3abb110cf031aed4be78a7ba8ba70b (mode 644)
--- /dev/null
+++ src/libdraw/debug.c
@@ -0,0 +1,16 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+void
+drawsetdebug(int v)
+{
+	uchar *a;
+	a = bufimage(display, 1+1);
+	if(a == 0){
+		fprint(2, "drawsetdebug: %r\n");
+		return;
+	}
+	a[0] = 'D';
+	a[1] = v;
+}
blob - /dev/null
blob + b0c85e1dc037ea88b2d72e5e14f58e54f5259fd5 (mode 644)
--- /dev/null
+++ src/libdraw/defont.c
@@ -0,0 +1,402 @@
+#include <u.h>
+#include <libc.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;
+	}
+}
blob - /dev/null
blob + d3f83e8859975294320676ee3b302c1438c17581 (mode 644)
--- /dev/null
+++ src/libdraw/draw.c
@@ -0,0 +1,69 @@
+#include <u.h>
+#include <libc.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);
+}
blob - /dev/null
blob + c72fee26a737325752a67b228fd5d68887e39ad7 (mode 644)
--- /dev/null
+++ src/libdraw/drawrepl.c
@@ -0,0 +1,23 @@
+#include <u.h>
+#include <libc.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;
+}
+
blob - /dev/null
blob + 2c5c9848522fb0eed75f8f20226cd668048214af (mode 644)
--- /dev/null
+++ src/libdraw/egetrect.c
@@ -0,0 +1,116 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <cursor.h>
+#include <event.h>
+
+#define	W	Borderwidth
+
+static Image *tmp[4];
+static Image *red;
+
+static Cursor sweep={
+	{-7, -7},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07,
+	 0xE0, 0x07, 0xE0, 0x07, 0xE3, 0xF7, 0xE3, 0xF7,
+	 0xE3, 0xE7, 0xE3, 0xF7, 0xE3, 0xFF, 0xE3, 0x7F,
+	 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,},
+	{0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02,
+	 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x41, 0xE2,
+	 0x41, 0xC2, 0x41, 0xE2, 0x41, 0x72, 0x40, 0x38,
+	 0x40, 0x1C, 0x40, 0x0E, 0x7F, 0xE6, 0x00, 0x00,}
+};
+
+static
+void
+brects(Rectangle r, Rectangle rp[4])
+{
+	if(Dx(r) < 2*W)
+		r.max.x = r.min.x+2*W;
+	if(Dy(r) < 2*W)
+		r.max.y = r.min.y+2*W;
+	rp[0] = Rect(r.min.x, r.min.y, r.max.x, r.min.y+W);
+	rp[1] = Rect(r.min.x, r.max.y-W, r.max.x, r.max.y);
+	rp[2] = Rect(r.min.x, r.min.y+W, r.min.x+W, r.max.y-W);
+	rp[3] = Rect(r.max.x-W, r.min.y+W, r.max.x, r.max.y-W);
+}
+
+Rectangle
+egetrect(int but, Mouse *m)
+{
+	Rectangle r, rc;
+
+	but = 1<<(but-1);
+	esetcursor(&sweep);
+	while(m->buttons)
+		*m = emouse();
+	while(!(m->buttons & but)){
+		*m = emouse();
+		if(m->buttons & (7^but))
+			goto Return;
+	}
+	r.min = m->xy;
+	r.max = m->xy;
+	do{
+		rc = canonrect(r);
+		edrawgetrect(rc, 1);
+		*m = emouse();
+		edrawgetrect(rc, 0);
+		r.max = m->xy;
+	}while(m->buttons == but);
+
+    Return:
+	esetcursor(0);
+	if(m->buttons & (7^but)){
+		rc.min.x = rc.max.x = 0;
+		rc.min.y = rc.max.y = 0;
+		while(m->buttons)
+			*m = emouse();
+	}
+	return rc;
+}
+
+static
+void
+freetmp(void)
+{
+	freeimage(tmp[0]);
+	freeimage(tmp[1]);
+	freeimage(tmp[2]);
+	freeimage(tmp[3]);
+	freeimage(red);
+	tmp[0] = tmp[1] = tmp[2] = tmp[3] = red = nil;
+}
+
+void
+edrawgetrect(Rectangle rc, int up)
+{
+	int i;
+	Rectangle r, rects[4];
+
+	if(up && tmp[0]!=nil)
+		if(Dx(tmp[0]->r)<Dx(rc) || Dy(tmp[2]->r)<Dy(rc))
+			freetmp();
+
+	if(tmp[0] == 0){
+		r = Rect(0, 0, Dx(screen->r), W);
+		tmp[0] = allocimage(display, r, screen->chan, 0, -1);
+		tmp[1] = allocimage(display, r, screen->chan, 0, -1);
+		r = Rect(0, 0, W, Dy(screen->r));
+		tmp[2] = allocimage(display, r, screen->chan, 0, -1);
+		tmp[3] = allocimage(display, r, screen->chan, 0, -1);
+		red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
+		if(tmp[0]==0 || tmp[1]==0 || tmp[2]==0 || tmp[3]==0 || red==0)
+			drawerror(display, "getrect: allocimage failed");
+	}
+	brects(rc, rects);
+	if(!up){
+		for(i=0; i<4; i++)
+			draw(screen, rects[i], tmp[i], nil, ZP);
+		return;
+	}
+	for(i=0; i<4; i++){
+		draw(tmp[i], Rect(0, 0, Dx(rects[i]), Dy(rects[i])), screen, nil, rects[i].min);
+		draw(screen, rects[i], red, nil, ZP);
+	}
+}
blob - /dev/null
blob + 6830b9dcd4090cc7ada8470482c08888a4da64f8 (mode 644)
--- /dev/null
+++ src/libdraw/freesubfont.c
@@ -0,0 +1,17 @@
+#include <u.h>
+#include <libc.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);
+}
blob - /dev/null
blob + 9279eec46851d97c80045380d2b69a05f7243709 (mode 644)
--- /dev/null
+++ src/libdraw/getdefont.c
@@ -0,0 +1,60 @@
+#include <u.h>
+#include <libc.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;
+}
blob - /dev/null
blob + a050e4c447835ec10163411e6f7426420d811bb0 (mode 644)
--- /dev/null
+++ src/libdraw/getrect.c
@@ -0,0 +1,133 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <thread.h>
+#include <cursor.h>
+#include <mouse.h>
+
+#define	W	Borderwidth
+
+static Image *tmp[4];
+static Image *red;
+
+static Cursor sweep={
+	{-7, -7},
+	{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x07,
+	 0xE0, 0x07, 0xE0, 0x07, 0xE3, 0xF7, 0xE3, 0xF7,
+	 0xE3, 0xE7, 0xE3, 0xF7, 0xE3, 0xFF, 0xE3, 0x7F,
+	 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,},
+	{0x00, 0x00, 0x7F, 0xFE, 0x40, 0x02, 0x40, 0x02,
+	 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x41, 0xE2,
+	 0x41, 0xC2, 0x41, 0xE2, 0x41, 0x72, 0x40, 0x38,
+	 0x40, 0x1C, 0x40, 0x0E, 0x7F, 0xE6, 0x00, 0x00,}
+};
+
+static
+void
+brects(Rectangle r, Rectangle rp[4])
+{
+	if(Dx(r) < 2*W)
+		r.max.x = r.min.x+2*W;
+	if(Dy(r) < 2*W)
+		r.max.y = r.min.y+2*W;
+	rp[0] = Rect(r.min.x, r.min.y, r.max.x, r.min.y+W);
+	rp[1] = Rect(r.min.x, r.max.y-W, r.max.x, r.max.y);
+	rp[2] = Rect(r.min.x, r.min.y+W, r.min.x+W, r.max.y-W);
+	rp[3] = Rect(r.max.x-W, r.min.y+W, r.max.x, r.max.y-W);
+}
+
+Rectangle
+getrect(int but, Mousectl *mc)
+{
+	Rectangle r, rc;
+
+	but = 1<<(but-1);
+	setcursor(mc, &sweep);
+	while(mc->m.buttons)
+		readmouse(mc);
+	while(!(mc->m.buttons & but)){
+		readmouse(mc);
+		if(mc->m.buttons & (7^but))
+			goto Return;
+	}
+	r.min = mc->m.xy;
+	r.max = mc->m.xy;
+	do{
+		rc = canonrect(r);
+		drawgetrect(rc, 1);
+		readmouse(mc);
+		drawgetrect(rc, 0);
+		r.max = mc->m.xy;
+	}while(mc->m.buttons == but);
+
+    Return:
+	setcursor(mc, nil);
+	if(mc->m.buttons & (7^but)){
+		rc.min.x = rc.max.x = 0;
+		rc.min.y = rc.max.y = 0;
+		while(mc->m.buttons)
+			readmouse(mc);
+	}
+	return rc;
+}
+
+static
+void
+freetmp(void)
+{
+	freeimage(tmp[0]);
+	freeimage(tmp[1]);
+	freeimage(tmp[2]);
+	freeimage(tmp[3]);
+	freeimage(red);
+	tmp[0] = tmp[1] = tmp[2] = tmp[3] = red = nil;
+}
+
+static
+int
+max(int a, int b)
+{
+	if(a > b)
+		return a;
+	return b;
+}
+
+void
+drawgetrect(Rectangle rc, int up)
+{
+	int i;
+	Rectangle r, rects[4];
+
+	/*
+	 * BUG: if for some reason we have two of these going on at once
+	 * when we must grow the tmp buffers, we lose data.  Also if tmp
+	 * is unallocated and we ask to restore the screen, it would be nice
+	 * to complain, but we silently make a mess.
+	 */
+	if(up && tmp[0]!=nil)
+		if(Dx(tmp[0]->r)<Dx(rc) || Dy(tmp[2]->r)<Dy(rc))
+			freetmp();
+	if(tmp[0] == 0){
+		r = Rect(0, 0, max(Dx(display->screenimage->r), Dx(rc)), W);
+		tmp[0] = allocimage(display, r, screen->chan, 0, -1);
+		tmp[1] = allocimage(display, r, screen->chan, 0, -1);
+		r = Rect(0, 0, W, max(Dy(display->screenimage->r), Dy(rc)));
+		tmp[2] = allocimage(display, r, screen->chan, 0, -1);
+		tmp[3] = allocimage(display, r, screen->chan, 0, -1);
+		red = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DRed);
+		if(tmp[0]==0 || tmp[1]==0 || tmp[2]==0 || tmp[3]==0 || red==0){
+			freetmp();
+			drawerror(display, "getrect: allocimage failed");
+		}
+	}
+	brects(rc, rects);
+	if(!up){
+		for(i=0; i<4; i++)
+			draw(screen, rects[i], tmp[i], nil, ZP);
+		return;
+	}
+	for(i=0; i<4; i++){
+		draw(tmp[i], Rect(0, 0, Dx(rects[i]), Dy(rects[i])), screen, nil, rects[i].min);
+		draw(screen, rects[i], red, nil, ZP);
+	}
+}
blob - /dev/null
blob + b66417d4d53b195b4326a13ee48bd9c2287d0f59 (mode 644)
--- /dev/null
+++ src/libdraw/icossin.c
@@ -0,0 +1,140 @@
+#include	<u.h>
+#include	<libc.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];
+}
blob - /dev/null
blob + aa864e1a3050599564fb79adb38752f49114c815 (mode 644)
--- /dev/null
+++ src/libdraw/icossin2.c
@@ -0,0 +1,261 @@
+#include	<u.h>
+#include	<libc.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);
+}
blob - /dev/null
blob + a06b5927e5c1a4898fa29c219cd37409cf9dc3a3 (mode 644)
--- /dev/null
+++ src/libdraw/line.c
@@ -0,0 +1,35 @@
+#include <u.h>
+#include <libc.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){
+		fprint(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);
+}
blob - /dev/null
blob + d8d8c40bfe273fd8be6f6197d6606e82aef6803c (mode 644)
--- /dev/null
+++ src/libdraw/loadimage.c
@@ -0,0 +1,54 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+int
+loadimage(Image *i, Rectangle r, uchar *data, int ndata)
+{
+	long dy;
+	int n, bpl;
+	uchar *a;
+	int chunk;
+
+	chunk = i->display->bufsize - 64;
+
+	if(!rectinrect(r, i->r)){
+		werrstr("loadimage: bad rectangle");
+		return -1;
+	}
+	bpl = bytesperline(r, i->depth);
+	n = bpl*Dy(r);
+	if(n > ndata){
+		werrstr("loadimage: insufficient data");
+		return -1;
+	}
+	ndata = 0;
+	while(r.max.y > r.min.y){
+		dy = r.max.y - r.min.y;
+		if(dy*bpl > chunk)
+			dy = chunk/bpl;
+		if(dy <= 0){
+			werrstr("loadimage: image too wide for buffer");
+			return -1;
+		}
+		n = dy*bpl;
+		a = bufimage(i->display, 21+n);
+		if(a == nil){
+			werrstr("bufimage failed");
+			return -1;
+		}
+		a[0] = 'y';
+		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);
+		memmove(a+21, data, n);
+		ndata += n;
+		data += n;
+		r.min.y += dy;
+	}
+	if(flushimage(i->display, 0) < 0)
+		return -1;
+	return ndata;
+}
blob - /dev/null
blob + df6b0ec2f2dfc2cb6b5e3da3a355bdee0de52833 (mode 644)
--- /dev/null
+++ src/libdraw/mkfont.c
@@ -0,0 +1,55 @@
+#include <u.h>
+#include <libc.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;
+}
blob - /dev/null
blob + 88784adf50aff453b0b380e8b9375fd44fc98846 (mode 644)
--- /dev/null
+++ src/libdraw/newwindow.c
@@ -0,0 +1,27 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+/* Connect us to new window, if possible */
+int
+newwindow(char *str)
+{
+	int fd;
+	char *wsys;
+	char buf[256];
+
+	wsys = getenv("wsys");
+	if(wsys == nil)
+		return -1;
+	fd = open(wsys, ORDWR);
+	free(wsys);
+	if(fd < 0)
+		return -1;
+	rfork(RFNAMEG);
+	if(str)
+		snprint(buf, sizeof buf, "new %s", str);
+	else
+		strcpy(buf, "new");
+	return mount(fd, -1, "/dev", MBEFORE, buf);
+}
+
blob - /dev/null
blob + 96effaec83a4f9c1446f712c2caeeb0a5bd2e7ea (mode 644)
--- /dev/null
+++ src/libdraw/poly.c
@@ -0,0 +1,87 @@
+#include <u.h>
+#include <libc.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);
+		fprint(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);
+}
blob - /dev/null
blob + 2228628b8d09085e59913dae69fcf7b5bde55621 (mode 644)
--- /dev/null
+++ src/libdraw/rectclip.c
@@ -0,0 +1,25 @@
+#include <u.h>
+#include <libc.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;
+}
blob - /dev/null
blob + ffd24b47baafb77e5e6e319294faba03667845f6 (mode 644)
--- /dev/null
+++ src/libdraw/replclipr.c
@@ -0,0 +1,21 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+
+void
+replclipr(Image *i, int repl, Rectangle clipr)
+{
+	uchar *b;
+
+	b = bufimage(i->display, 22);
+	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;
+}
blob - /dev/null
blob + e8f7f51b1c44563b1119dc7d343feef8c32ce1fb (mode 644)
--- /dev/null
+++ src/libdraw/rgb.c
@@ -0,0 +1,99 @@
+#include <u.h>
+#include <libc.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;
+	u32int 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;
+}
blob - /dev/null
blob + 0628a8404f05268cbecb3dcf19c243806318b964 (mode 644)
--- /dev/null
+++ src/libdraw/stringbg.c
@@ -0,0 +1,51 @@
+#include <u.h>
+#include <libc.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);
+}
blob - /dev/null
blob + cc83473293fbe8899d023b59b869107c491ba396 (mode 644)
--- /dev/null
+++ src/libdraw/stringsubfont.c
@@ -0,0 +1,65 @@
+#include <u.h>
+#include <libc.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;
+}
blob - /dev/null
blob + d4a5de770c132621dca9e372fd9b089647715474 (mode 644)
--- /dev/null
+++ src/libdraw/test.c
@@ -0,0 +1,44 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <event.h>
+
+void
+eresized(int new)
+{
+	if(new && getwindow(display, Refnone) < 0){
+		fprint(2, "colors: can't reattach to window: %r\n");
+		exits("resized");
+	}
+	draw(screen, screen->r, display->white, nil, ZP);
+	flushimage(display, 1);
+}
+
+char *buttons[] =
+{
+	"exit",
+	0
+};
+
+Menu menu =
+{
+	buttons
+};
+
+void
+main(int argc, char *argv[])
+{
+	Mouse m;
+
+	initdraw(0,0,0);
+	eresized(0);
+	einit(Emouse);
+	for(;;){
+		m = emouse();
+		if(m.buttons == 4)
+			switch(emenuhit(3, &m, &menu)){
+			case 0:
+				exits(0);
+			}
+	}
+}
blob - /dev/null
blob + b82c25e913dc8b8e0e67691f7fc6883c732b9595 (mode 644)
--- /dev/null
+++ src/libdraw/window.c
@@ -0,0 +1,214 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.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){
+		werrstr("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, u32int 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, u32int val)
+{
+	return _allocwindow(nil, s, r, ref, val);
+}
+
+Image*
+_allocwindow(Image *i, Screen *s, Rectangle r, int ref, u32int val)
+{
+	Display *d;
+
+	d = s->display;
+	i = _allocimage(i, d, r, d->screenimage->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){
+    Ridiculous:
+		fprint(2, "top/bottom: ridiculous number of windows\n");
+		return;
+	}
+	if(n == 0)
+		return;
+	if(n > (w[0]->display->bufsize-100)/4)
+		goto Ridiculous;
+	/*
+	 * this used to check that all images were on the same screen.
+	 * we don't know the screen associated with images we acquired
+	 * by name.  instead, check that all images are on the same display.
+	 * the display will check that they are all on the same screen.
+	 */
+	d = w[0]->display;
+	for(i=1; i<n; i++)
+		if(w[i]->display != d){
+			fprint(2, "top/bottom: windows not on same screen\n");
+			return;
+		}
+
+	if(n==0)
+		return;
+	b = bufimage(d, 1+1+2+4*n);
+	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)
+{
+	if(w->screen == 0)
+		return;
+	topbottom(&w, 1, 0);
+}
+
+void
+topwindow(Image *w)
+{
+	if(w->screen == 0)
+		return;
+	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;
+}
blob - /dev/null
blob + b4dcff061c6f0da6cbcaf6dc4bf60499df50affe (mode 644)
--- /dev/null
+++ src/libdraw/writeimage.c
@@ -0,0 +1,185 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.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(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;
+}
blob - /dev/null
blob + 1ea985f00251189826de9643e8ccb549581b9671 (mode 644)
--- /dev/null
+++ src/libdraw/writesubfont.c
@@ -0,0 +1,45 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.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(write(fd, hdr, 3*12) != 3*12){
+   Err:
+		werrstr("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(write(fd, data, nb) != nb)
+		goto Err;
+	free(data);
+	return 0;
+}