V10/cmd/bcp/bcp.cpio

0707070035351137021006640007620000050000010260220476773366500001100000001573Bfeats.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* Bfeats.h - typedef, constants, and function declarations for Bfeats.
   INCLUDES
	Requires prior #include "BMask.h"
   */

typedef struct Bfeats {
	BMask bm;		/* bitmask (1 for each feature) */
	unsigned short mny;	/* number of feature indices in fa[] */
	unsigned short *fa;	/* fa[mny] of feature (ss) nos, no dups (malloc) */
	} Bfeats;

#define Init_Bfeats {Init_BMask,0,NULL}
#if MAIN
	Bfeats empty_Bfeats = Init_Bfeats;
#else
	extern Bfeats empty_Bfeats;
#endif

Bfeats *alloc_bfeats();
free_bfeats();
char *bfeats_toa();
Bfeats *dup_bfeats();
0707070035351137031006640007620000050000010260240476773366500001100000470007Bitmap.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* Bitmap.h:  2-D fixed-sized bitmaps */

/* BITMAP TEMPLATES: potentially MACHINE-DEPENDENT bit-packing */
#define Bm_h	54			/* height (no. bits) */
#define Bm_il	3			/* width (no. ints) */
#define Bm_ex_h	5			/* extra pixels allowed, top/bottom */
#define Bm_ex_w	16			/* extra pixels allowed, left/right */

#define Bm_wi	((int)(8*sizeof(int)))	/* width of an int in bits;  sizeof() is
					   unsigned: must coerce to signed so can
					   compare correctly with negative ints */
typedef unsigned int Bm_l[Bm_il];	/* bitmap line */
#define Bm_w	(Bm_wi*Bm_il)		/* width of bitmap (<= # bits in a Bm_l) */
#define Bm_w_ok (Bm_w+2*Bm_ex_w)	/* OK width (sides truncated to fit) */
#define Bm_h_ok (Bm_h+2*Bm_ex_h)	/* OK height (top/bot truncated to fit) */
#define Bm_area (Bm_w*Bm_h)		/* area of bitmap */
#define Bm_ni	(Bm_il*Bm_h)		/* no. ints in bitmap area */
#define Bm_ns	(2*Bm_ni)		/* no. of shorts in bitmap area */

typedef union Bm {		/* the rectangular array of bits */
	Bm_l l[Bm_h];
	int unsigned i[Bm_ni];
	short unsigned s[Bm_ns];
	} Bm;

typedef struct Bm_consts {
	unsigned int mask_all;		/* all bitmap bits set */
	unsigned int mask[Bm_wi];	/* constant mask bits (in int) */
	unsigned char Rbits[256]; 	/* Bytes with bits reversed */
	unsigned char Nbits[65536];	/* Nbits[i] = no. bits set in
					   (unsigned short) i */
	} Bm_consts;

/* The following 2076 lines are a static initialization for Bm_consts;
   it is written by program `mkbmc' which runs function `fwra_bm_consts' */
#if MAIN
Bm_consts bm_consts = { 
 0xffffffff, 
 { 0x1,0x2,0x4,0x8, 
   0x10,0x20,0x40,0x80, 
   0x100,0x200,0x400,0x800, 
   0x1000,0x2000,0x4000,0x8000, 
   0x10000,0x20000,0x40000,0x80000, 
   0x100000,0x200000,0x400000,0x800000, 
   0x1000000,0x2000000,0x4000000,0x8000000, 
   0x10000000,0x20000000,0x40000000,0x80000000 }, 
 { 00,0200,0100,0300,040,0240,0140,0340,020,0220,0120,0320,060,0260,0160,0360, 
   010,0210,0110,0310,050,0250,0150,0350,030,0230,0130,0330,070,0270,0170,0370, 
   04,0204,0104,0304,044,0244,0144,0344,024,0224,0124,0324,064,0264,0164,0364, 
   014,0214,0114,0314,054,0254,0154,0354,034,0234,0134,0334,074,0274,0174,0374, 
   02,0202,0102,0302,042,0242,0142,0342,022,0222,0122,0322,062,0262,0162,0362, 
   012,0212,0112,0312,052,0252,0152,0352,032,0232,0132,0332,072,0272,0172,0372, 
   06,0206,0106,0306,046,0246,0146,0346,026,0226,0126,0326,066,0266,0166,0366, 
   016,0216,0116,0316,056,0256,0156,0356,036,0236,0136,0336,076,0276,0176,0376, 
   01,0201,0101,0301,041,0241,0141,0341,021,0221,0121,0321,061,0261,0161,0361, 
   011,0211,0111,0311,051,0251,0151,0351,031,0231,0131,0331,071,0271,0171,0371, 
   05,0205,0105,0305,045,0245,0145,0345,025,0225,0125,0325,065,0265,0165,0365, 
   015,0215,0115,0315,055,0255,0155,0355,035,0235,0135,0335,075,0275,0175,0375, 
   03,0203,0103,0303,043,0243,0143,0343,023,0223,0123,0323,063,0263,0163,0363, 
   013,0213,0113,0313,053,0253,0153,0353,033,0233,0133,0333,073,0273,0173,0373, 
   07,0207,0107,0307,047,0247,0147,0347,027,0227,0127,0327,067,0267,0167,0367, 
   017,0217,0117,0317,057,0257,0157,0357,037,0237,0137,0337,077,0277,0177,0377 }, 
 { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   5,6,6,7,6,7,7,8,6,7,7,8,7,8,8,9,6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   6,7,7,8,7,8,8,9,7,8,8,9,8,9,9,10,7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   7,8,8,9,8,9,9,10,8,9,9,10,9,10,10,11,8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   8,9,9,10,9,10,10,11,9,10,10,11,10,11,11,12,9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   9,10,10,11,10,11,11,12,10,11,11,12,11,12,12,13,10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   10,11,11,12,11,12,12,13,11,12,12,13,12,13,13,14,11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15, 
   11,12,12,13,12,13,13,14,12,13,13,14,13,14,14,15,12,13,13,14,13,14,14,15,13,14,14,15,14,15,15,16 }
   };

#else
extern Bm_consts bm_consts;
#endif

double Bm_match();
char *BM_toa();
0707070035351137041006640007620000050000010260520476773366600001000000207047CCITT.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* CCITT.c - functions for CCITT compression/decompression of binary images.
   The following discussion is a summary of CCITT Recommendations T.4 and T.6
on facsimile coding schemes and coding control functions for Group 3 and Group
4 facsimile apparatus (drafted at Malaga-Torremolinos, 1984).  They describe
algorithms for invertible (lossless) compression and decompression of bilevel
(black-and-white, not grey) 2D rectangular images of arbitrary height and
width.  By convention the images are processed top-down, one horizontal scan
line at a time.  It is not strictly necessary to know the height of an image
before starting compression or decompression.  Width, however, must be known
in advance in some cases (discussed below), and must remain constant for the
whole image in all cases.  There are three distinct but intimately related
standards:  Group 3 1-dimensional, Group 3 2-dimensional, and Group 4.
VLSI hardware implementations always include all three.  The Group 3 encodings
are used in the vast installed base of FAX machines.  Group 4 is not used
in today's FAX machines, but seems to be the default standard in document image
archiving applications.
	The CCITT Group 3 FAX standard permits either 1-D or 2-D encoding.
It is not easy to tell from an encoding which was used.  Both 1-D and 2-D
assume fixed scanline length (in pixels), which must be known at encoding time.
	Group 3 1-D (g31) code uses fixed ``modified Huffman'' codes for
run-lengths, with two different code tables for black and white runs.  Each
line is assumed to begin with a (possibly 0-length) white run.  Of course,
the colors strictly alternate.  An empty (all-white) line is supposed to be
spelled out with a full pixel count, although some decoders won't complain
if just a 0-length count is used.  There are provisions for fill bits at the
end of lines to allow slow receiving equipment to keep up.  Each line ends with
an EOL code on which it may be possible to synchronize after transmission error.
	Group 3 2-D (g32) encoding tries to exploit the slowly-changing nature
of artwork from line to line.  It is a mixture of 1-D-coded lines and
``2-D''-coded lines describing small local changes relative to the immediately
prior ``reference'' line.  1-D coding recurs every few (`k') lines, so that
resynchronization is frequently possible.  K is usually 2 or 4, but the
standard permits any number, even infinity, since the coding method used on
a line is specified by which of two special EOLx codes is used to end the
prior line.
	CCITT Group 4 (g4) is like Group 3 2-D, but optimized to take advantage
of a lossless communications channel or reliable storage medium (such as computer
memory), where resynchronization is unnecessary.  Thus the first line is 2-D
encoded referenced to an imaginary initial blank line, k is always infinity,
and EOL's are not used at all.  It essential that the line-length be known in
advance of both encoding and decoding, so that line-breaks can be triggered when
that length is exceeded.  End of FAX buffer (end of page) is signaled by a
special EOFB code.
   On images of printed text and sparse line-graphics, g4-compressed files
are often 15-40X smaller than bitmap (packed bits), 5X than bitfile(9.5),
2X than g31, and 2X than rle | pack.
PERFORMANCE
   On 10 printed A4 pages (business letters, technical reports, etc),
at a resolution of 400 dpi:
	binary:		2020 Kbytes	CPU secs (to compress binary)
        pack:		 200 - 380	17
	bitfile(9.5):	 150 - 360	 ?
	rle:		 100 - 230	 7.5
        compress:	  90 - 155	14
	g31:		  85 - 190	13
	g32:		  55 - 110	13
	g4:		  30 -  70	13
   G4-compressed files are 15-40X smaller than binary, 5X than bitfile(9.5),
3.5X than rle, 2X than g31, and 2X than rle | pack.
*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "CPU.h"
#include "stdocr.h"
#include "rle.h"
#include "bitio.h"
#include "CCITT.h"

#define DEBUG 0		/* 0 disables compilation of all debugging code;
			   1 compiles, but must enable particular parts below */
#define NEW_TRAIL 1	/* enable new trailing-0 counts (has passed early tests) */
#define dbg_trail 0

DST_table *ccitt_table()
{   DST_context cx;
	if((cx.t = (DST_table *)malloc(sizeof(DST_table)))==NULL)
		abort("CCITT.c: build_tbl: can't alloc cx.t");
	/* All tables have e[DST_white], e[DST_black], & e[DST_2d] entries */
	cx.t->mny=3;
	if((cx.t->e=(DST_entry *)malloc(cx.t->mny*sizeof(DST_entry)))==NULL)
		abort("CCITT.c: build_tbl: can't alloc cx.t->e[%d]",cx.t->mny);

	cx.s = cx.c = DST_white;
	cx.l = 0;
	cx.t->e[cx.s].p[0] = '\0';
	cx.t->e[cx.s].l = 0;
	cx.t->e[cx.s].z = 0;
	build_transits(cx);

	cx.s = cx.c = DST_black;
	cx.l = 0;
	cx.t->e[cx.s].p[0] = '\0';
	cx.t->e[cx.s].l = 0;
	cx.t->e[cx.s].z = 0;
	build_transits(cx);

	cx.s = cx.c = DST_2d;
	cx.l = 0;
	cx.t->e[cx.s].p[0] = '\0';
	cx.t->e[cx.s].l = 0;
	cx.t->e[cx.s].z = 0;
	build_transits(cx);

#if DEBUG
	if(F) ccitt_err_tbl(cx.t);
#endif
	return(cx.t);
	}

DST_state new_state(t)
   DST_table *t;
{	t->mny++;
	if((t->e=(DST_entry *)realloc(t->e,t->mny*sizeof(DST_entry)))==NULL)
		abort("can't realloc t->[%d]",t->mny);
	return(t->mny-1);
	}

/* The entry described by `cx' exists in the table, and its prefix `p' is
   setup; create its transitions, and their next entries, recursively.  */
build_transits(cx)
    DST_context cx;
#define entry cx.t->e[cx.s]
#define transit entry.t[col]
{   DST_color col;
    DST_entry ne;	/* next entry */
    DST_context ncx;	/* next Context */
    char **s,**ss;	/* for searching code */
    short *c,*cs;
    int si,matching,longer;
    char svch,col_str[2];
	switch(cx.c) {
	    case DST_white:
		ss=codewht;
		cs=bitcwht;
		break;
	    case DST_black:
		ss=codeblk;
		cs=bitcblk;
		break;
	    case DST_2d:
		ss=code2d;
		cs=bitc2d;
		break;
	    };
    	for(col=0;col<=1;col++) {
		sprintf(col_str,"%1d",col);
		ncx = cx;  ncx.l++; 
		/* build a transition */
		strcpy(ne.p,entry.p); strcat(ne.p,col_str);
		ne.l = ncx.l;
		if(col==0) ne.z = entry.z+1; else ne.z = 0;
		/* count those that match new prefix */
		longer=matching=0;
		for(s=ss,c=cs,si=0; (*s)!=NULL; s++,c++,si++) {
			if(*c==ncx.l) {
				if(strcmp(*s,ne.p)==0) {
					matching++;
					switch(cx.c) {
					    case DST_white:
					    case DST_black:
						transit.a = itor(si);
						break;
					    case DST_2d:
						transit.a = si;
						break;
					    };
					};
				}
			else if(*c>ncx.l) {
				svch=(*s)[ncx.l]; (*s)[ncx.l] = '\0';
				if(strcmp(*s,ne.p)==0) {
					longer++;
					};
				(*s)[ncx.l]=svch;
				};
			};
		/* analyze results */
		if(matching==0&&longer>0) {
			/* no match yet; go deeper */
			transit.a = DST_action_NULL;
			ncx.s = transit.s = new_state(cx.t);
			strcpy(cx.t->e[ncx.s].p,ne.p);
			cx.t->e[ncx.s].l = ne.l;
			cx.t->e[ncx.s].z = ne.z;
			build_transits(ncx);
			}
		else if(matching==1&&longer==0) {
			/* unique leaf: good */
			/* picked up action earlier */
			switch(cx.c) {
			    case DST_white:
			    case DST_black:
				if(transit.a<=63) /* termination code */
					transit.s = flip_color(cx.c); 
				else /* makeup code */
					transit.s = cx.c;
				break;
			    case DST_2d:
				/* legal end of code */
				transit.s = DST_state_NULL;
				break;
			    };
			}
		else {	/* illegal transition */
			transit.a = DST_action_ERROR;
			transit.s = DST_state_NULL;
			};
		};
	}

ccitt_err_tbl(t)
    DST_table *t;
{   int d;
	ccitt_err_state(DST_white,t);
	ccitt_err_state(DST_black,t);
	ccitt_err_state(DST_2d,t);
	}

ccitt_err_state(s,t)
    DST_state s;
    DST_table *t;
{	err("%03d %s %2d %2d%*s %d %03d,%-4d  %d %03d,%-4d",
			s,t->e[s].p,t->e[s].l,t->e[s].z,14-strlen(t->e[s].p)," ",
			0,t->e[s].t[0].s,t->e[s].t[0].a,
			1,t->e[s].t[1].s,t->e[s].t[1].a
			);
	if(t->e[s].t[0].s>1) ccitt_err_state(t->e[s].t[0].s,t);
	if(t->e[s].t[1].s>1) ccitt_err_state(t->e[s].t[1].s,t);
	}

/* Translate a stream of bits in CCITT FAX Group 3 (1-D) compression format
   into a sequence of RLE_Lines.  Returns one (RLE_Line *) on each call (or NULL
   if EOF or error).  The first pixel (black or white) in each g31 line is
   assigned run index 0. */
RLE_Line *g31_to_rlel(t,f,bof)
    DST_table *t;
    BITFILE *f;
    boolean bof;	/* beginning of file */
#define dbg_g31r_r (0)	/* trace each run/EOL/ERR_SYN */
#define dbg_g31r_c (0)	/* trace each Huffman code (or, fill+EOL)*/
#define dbg_g31r_t (0)	/* trace each state-transition */
{   static DST_context cx;
    static RLE_Line rl;
    static RLE_Run *r;	/* prior, current runs */
    int run,biti,sync,si,bitv;
    boolean fill;
/* color of 1st run in each line */
#define g31_first_color DST_white
/* reverse Black/White in output image */
#define g31_negative 0
	if(bof){if(T) {	/* sync by skipping initial FILL & EOL code */
			sync=0;  while((bitv=getb(f))==0) sync++;
			if(bitv!=1||sync<11) {
#if DEBUG
				if(dbg_g31r_c) {
					fprintf(stderr,"BOF_ERR ");
					for(si=0;si<sync;si++) fprintf(stderr,"0");
					if(bitv==1) fprintf(stderr,"1\n");
					else fprintf(stderr,"?\n");
					};
#endif
				return(NULL);
				}
#if DEBUG
			else if(dbg_g31r_c){
				fprintf(stderr,"BOF_EOL ");
				for(si=0;si<sync;si++) fprintf(stderr,"0");
				fprintf(stderr,"1\n");
				};
#endif
			};
		/* start file expecting a run-code of a fixed color */
		cx.s = cx.c = g31_first_color;
		rl.y = -1;	/* assume first line is y==0 */
		};
	rl.y++;  rl.runs=0;  r = rl.r;  biti=run=0;
	while(T) switch(getb(f)) {
	    case 0 :  /* next bit is 0 */
		switch(t->e[cx.s].t[0].a) {
		    case DST_action_ERROR:
			/* bad code: try to resynchronize */
#if DEBUG
			if(dbg_g31r_t){
				fprintf(stderr,"%s %04d  %s0?...\n",
					(cx.c==DST_white)? "W": "B",
					t->e[cx.s].t[0].s,
					t->e[cx.s].p);
				};
#endif
			/* count trailing 0's so far (should be in table) */
#if !NEW_TRAIL
			sync=1;
			si=strlen(t->e[cx.s].p)-1;
			while(si>=0&&t->e[cx.s].p[si]=='0') {sync++; si--;};
			fill = (si<0);	/* all 0's:  may be fill bits */
#else
			sync=t->e[cx.s].z+1;
			fill = (sync>t->e[cx.s].l); /* all 0's:  maybe fill bits */
#endif
#if DEBUG
			if(dbg_trail) err("sync %d fill %d",sync,fill);
			if(dbg_g31r_c)fprintf(stderr,"ERR_SYN %s0?",t->e[cx.s].p);
#endif
			while(sync<11) {
				switch(bitv=getb(f)) {
					case 0:  sync++;
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"0");
#endif
						break;
					case 1:  sync=0;  fill=F;
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"1");
#endif
						break;
					case EOF:
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"<EOF>\n");
#endif
						return(NULL);  break;
					};
				};
			/* next `1' will synchronize */
			do {	switch(bitv=getb(f)) {
					case 0:
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"0");
#endif
						break;
					case 1:
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"1");
#endif
						break;
					case EOF:
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"<EOF>\n");
#endif
						return(NULL);  break;
					};
				}
			while(bitv!=1);
#if DEBUG
			if(dbg_g31r_c) fprintf(stderr,"\n");
			if(dbg_g31r_r) {
				if(fill) fprintf(stderr,"FILL_EOL\n");
				else fprintf(stderr,"ERR_SYN_EOL\n");
				};
#endif
			/* start next line expecting a run-code of a fixed color */
			cx.s = cx.c = g31_first_color;
			return(&rl);
			break;
		    case DST_action_NULL:
#if DEBUG
			if(dbg_g31r_t)fprintf(stderr,"%s %04d  %s0\n",
				(cx.c==DST_white)? "W": "B",
				t->e[cx.s].t[0].s,
				t->e[cx.s].p);
#endif
			cx.s = t->e[cx.s].t[0].s;
			break;
		    case DST_EOL:
#if DEBUG
			if(dbg_g31r_c)fprintf(stderr,"EOL     %s0\n",
				t->e[cx.s].p);
			if(dbg_g31r_r)fprintf(stderr,"EOL\n");
#endif
			/* start next line expecting a run-code of a fixed color */
			cx.s = cx.c = g31_first_color;
			return(&rl);
			break;
		    default:
#if DEBUG
			if(dbg_g31r_c)fprintf(stderr,"%s%6d %s0\n",
				(cx.c==DST_white)? "W": "B",
				t->e[cx.s].t[0].a,
				t->e[cx.s].p);
#endif
			if(t->e[cx.s].t[0].a<=63) {
				run += t->e[cx.s].t[0].a;
#if DEBUG
				if(dbg_g31r_r)fprintf(stderr,"%s%6d\n",
					(cx.c==DST_white)? "W": "B",
					run);
#endif
				biti += run;
				if(cx.c==DST_black^g31_negative) {
					/* end of black run */
					r->xe = biti-1;
					r++; rl.runs++;
					}
				else {	/* end of white run */
					r->xs = biti;
					};
				cx.c = flip_color(cx.c);
				run = 0;
				}
			else run += t->e[cx.s].t[0].a;
			cx.s = t->e[cx.s].t[0].s;
			break;
		    };
		break;
	    case 1:  /* next bit is 1 */
		switch(t->e[cx.s].t[1].a) {
		    case DST_action_ERROR:
			/* bad code: try to resynchronize */
#if DEBUG
			if(dbg_g31r_t){
				fprintf(stderr,"%s %04d  %s1?...\n",
					(cx.c==DST_white)? "W": "B",
					t->e[cx.s].t[1].s,
					t->e[cx.s].p);
				};
			if(dbg_g31r_c)fprintf(stderr,"ERR_SYN %s1?",t->e[cx.s].p);
#endif
			/* no trailing 0's; can't be fill bits */
			sync=0;
			while(sync<11) {
				switch(bitv=getb(f)) {
					case 0:  sync++;
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"0");
#endif
						break;
					case 1:  sync=0;
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"1");
#endif
						break;
					case EOF:
#if DEBUG
						if(dbg_g31r_c)
							fprintf(stderr,"<EOF>\n");
#endif
						return(NULL);  break;
					};
				};
			/* next `1' will synchronize */
			do {	switch(bitv=getb(f)) {
					case 0:
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"0");
#endif
						break;
					case 1:
#if DEBUG
						if(dbg_g31r_c) fprintf(stderr,"1");
#endif
						break;
					case EOF:
#if DEBUG
						if(dbg_g31r_c)
							fprintf(stderr,"<EOF>\n");
#endif
						return(NULL);  break;
					};
				}
			while(bitv!=1);
#if DEBUG
			if(dbg_g31r_c) fprintf(stderr,"\n");
			if(dbg_g31r_r) fprintf(stderr,"ERR_SYN_EOL\n");
#endif
			/* start next line expecting a run-code of a fixed color */
			cx.s = cx.c = g31_first_color;
			return(&rl);
			break;
		    case DST_action_NULL:
#if DEBUG
			if(dbg_g31r_t)fprintf(stderr,"%s %04d  %s1\n",
				(cx.c==DST_white)? "W": "B",
				t->e[cx.s].t[1].s,
				t->e[cx.s].p);
#endif
			cx.s = t->e[cx.s].t[1].s;
			break;
		    case DST_EOL:
#if DEBUG
			if(dbg_g31r_c)fprintf(stderr,"EOL     %s1\n",
				t->e[cx.s].p);
			if(dbg_g31r_r)fprintf(stderr,"EOL\n");
#endif
			/* start next line expecting a run-code of a fixed color */
			cx.s = cx.c = g31_first_color;
			return(&rl);
			break;
		    default:
#if DEBUG
			if(dbg_g31r_c)fprintf(stderr,"%s%6d %s1\n",
				(cx.c==DST_white)? "W": "B",
				t->e[cx.s].t[1].a,
				t->e[cx.s].p);
#endif
			if(t->e[cx.s].t[1].a<=63) {
				run += t->e[cx.s].t[1].a;
#if DEBUG
				if(dbg_g31r_r)fprintf(stderr,"%s%6d\n",
					(cx.c==DST_white)? "W": "B",
					run);
#endif
				biti += run;
				if(cx.c==DST_black^g31_negative) {
					/* end of black run */
					r->xe = biti-1;
					r++; rl.runs++;
					}
				else {	/* end of white run */
					r->xs = biti;
					};
				cx.c = flip_color(cx.c);
				run = 0;
				}
			else run += t->e[cx.s].t[1].a;
			cx.s = t->e[cx.s].t[1].s;
			break;
		    };
		break;
	    case EOF:
		return(NULL);
		break;
	    default:
		return(NULL);
		break;
	    };
	/* never come here:  return() variously from cases above */
	}

/* Translate a sequence of RLE_Line's (describing a binary image)
   into a file (a stream of bits) in CCITT FAX Group 3 (1-D) compression format.
   BOF_to_g31() must be called first; then call rlel_to_g31() for each line
   (including blank lines); finally, EOF_to_g31() must be called.  Each line's
   EOL and the RTC's first EOL are padded so they end on a byte boundary.
   */
/* debugging flags:  trace to stderr */
#define dbg_rg31_e (0)	/* entry */
#define dbg_rg31_r (0)	/* runs */
#define dbg_rg31_s (0)	/* bitstrings */

#if DEBUG
#define bits_g31(bits) { \
	cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;};  \
	if(dbg_rg31_s) fprintf(stderr,"%s",(bits)); \
	if(dbg_rg31_r) fprintf(stderr," "); \
	}
#define EOL_g31 { \
	if(dbg_rg31_r) fprintf(stderr,"EOL     "); \
	bits_g31(EOLSTRING); \
	if(dbg_rg31_r) fprintf(stderr,"\n"); \
	}
#else
#define bits_g31(bits) { \
	cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;};  \
	}
#define EOL_g31 { \
	bits_g31(EOLSTRING); \
	}
#endif

BOF_to_g31(f)
    BITFILE *f;	/* state of output bitfile */
{   char *cs;
	EOL_g31;
	}

rlel_to_g31(rl,wid,f)
    RLE_Line *rl;	/* line of runs:  if NULL, then blank */
    int wid;		/* width of an output line in pixels */
    BITFILE *f;		/* state of output bitfile */
{   int pi;		/* input pixel index on line */
    RLE_Run *rp,*pp,*sp;
    int runl,codi;
    char *cs,*p01;
#if DEBUG
#define Wrun_g31(rn) { \
	runl=(rn); \
	if(dbg_rg31_r) fprintf(stderr,"W %5d ",runl); \
	while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \
	p01=codewht[codi=rtoi(runl)]; bits_g31(p01); \
	if(codi>=64) {p01=codewht[runl%64]; bits_g31(p01);}; \
	if(dbg_rg31_r) fprintf(stderr,"\n"); \
	}
#else
#define Wrun_g31(rn) { \
	runl=(rn); \
	while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \
	p01=codewht[codi=rtoi(runl)]; bits_g31(p01); \
	if(codi>=64) {p01=codewht[runl%64]; bits_g31(p01);}; \
	}
#endif
#if DEBUG
#define Brun_g31(rn) { \
	runl=(rn); \
	if(dbg_rg31_r) fprintf(stderr,"B %5d ",runl); \
	while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \
	p01=codeblk[codi=rtoi(runl)]; bits_g31(p01); \
	if(codi>=64) {p01=codeblk[runl%64]; bits_g31(p01);}; \
	if(dbg_rg31_r) fprintf(stderr,"\n"); \
	}

#else
#define Brun_g31(rn) { \
	runl=(rn); \
	while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g31(p01); runl-=2560;}; \
	p01=codeblk[codi=rtoi(runl)]; bits_g31(p01); \
	if(codi>=64) {p01=codeblk[runl%64]; bits_g31(p01);}; \
	}
#endif
#if DEBUG
	if(dbg_rg31_e) err("rlel_to_g31(rl[y%d,r%d])",rl->y,rl->runs);
#endif
	if(rl!=NULL&&rl->runs>0) {
		pi=0;	/* bit to write next */
#if DEBUG
		if(dbg_rg31_e) err("rlel_to_g31(rl[y%d,r%d])",rl->y,rl->runs);
#endif
		for(sp=(rp=rl->r)+rl->runs; rp<sp; rp++) {
			Wrun_g31(rp->xs-pi);  pi=rp->xs;
			Brun_g31(rp->xe-pi+1);  pi=rp->xe+1;
			};
		if((--rp)->xe+1<wid) Wrun_g31(wid-rp->xe-1);
		}
	else {	
#if DEBUG
		if(dbg_rg31_e) err("rlel_to_g31(rl[y?,r0])");
#endif
		Wrun_g31(wid);  /* blank (all-white) scanline */
		};
	/* fill so that EOL ends on byte boundary */
	padb(f,0,8,EOLLENGTH);
#if DEBUG
	if(dbg_rg31_s) fprintf(stderr,"+0?");
#endif
	EOL_g31;
	}

EOF_to_g31(f)
    BITFILE *f;
{   char *cs;
	/* fill so that EOL ends on byte boundary */
	padb(f,0,8,EOLLENGTH);
#if DEBUG
	if(dbg_rg31_s) fprintf(stderr,"+0?");
#endif
	/* write RTC */
	EOL_g31;
	EOL_g31;
	EOL_g31;
	EOL_g31;
	EOL_g31;
	EOL_g31;
	}

/* Macro for use within g32_to_rlel, to read one 1-D Modified Huffman coded
   run-length of a given color, placing the result in a given variable.
   Exceptionally, goto trap_eol, trap_eof, or trap_code_err.
  */
#if DEBUG
#define g32_1d_run(C,V) { \
	run = 0; \
	do {	cx.tr.s = (C); \
	        do {	px = cx; \
			switch(bitv=getb(f)) { \
			    case 0 :  cx.tr=t->e[cx.tr.s].t[0];  break; \
			    case 1 :  cx.tr=t->e[cx.tr.s].t[1];  break; \
			    case EOF :  goto trap_eof;  break; \
			    }; \
			} \
		while(cx.tr.a==DST_action_NULL); \
		switch(cx.tr.a) { \
		    case DST_EOL : \
			if(dbg_g32r_c)fprintf(stderr,"EOL     %s\n",EOLSTRING); \
			goto trap_eol; \
			break; \
		    case DST_action_ERROR :  goto trap_code_err;  break; \
		    default : \
			if(dbg_g32r_c)fprintf(stderr,"%s%6d %s%d\n", \
				((C)==DST_white)? "W": "B", \
				cx.tr.a, \
				t->e[px.tr.s].p, \
				bitv); \
			run += cx.tr.a; \
			break; \
		    }; \
		} \
	while(cx.tr.a>63); \
	(V) = run; \
	}
#else
#define g32_1d_run(C,V) { \
	run = 0; \
	do {	cx.tr.s = (C); \
	        do {	px = cx; \
			switch(bitv=getb(f)) { \
			    case 0 :  cx.tr=t->e[cx.tr.s].t[0];  break; \
			    case 1 :  cx.tr=t->e[cx.tr.s].t[1];  break; \
			    case EOF :  goto trap_eof;  break; \
			    }; \
			} \
		while(cx.tr.a==DST_action_NULL); \
		switch(cx.tr.a) { \
		    case DST_EOL : \
			goto trap_eol; \
			break; \
		    case DST_action_ERROR :  goto trap_code_err;  break; \
		    default : \
			run += cx.tr.a; \
			break; \
		    }; \
		} \
	while(cx.tr.a>63); \
	(V) = run; \
	}
#endif

/* Translate a stream of bits in CCITT FAX Group 3 (2-D) compression format
   into a sequence of RLE_Lines.  Returns one (RLE_Line *) on each call (or NULL
   if EOF or error).  The first pixel (black or white) in each g32 line is
   assigned run index 0. */
RLE_Line *g32_to_rlel(t,f,bof)
    DST_table *t;
    BITFILE *f;
    boolean bof;	/* beginning of file */
#define dbg_g32r_e (0)	/* entry/exit */
#define dbg_g32r_r (0)	/* trace each run/EOL/ERR_SYN */
#define dbg_g32r_c (0)	/* trace each Huffman code (or, fill+EOL)*/
#define dbg_g32r_t (0)	/* trace each state-transition */
#define g32r_strict (1)	/* 1 is CORRECT: explicitly code the last black pel */
{   static RLE_Line rl0,rl1,*prl,*crl;	/* prior, current run-lines */
    RLE_Line *swrl;
    int bitv;		/* the last-read bit value */
    DST_context cx,px;	/* the current/prior decoding context */
    RLE_Run *cr,*pr,*pre;	/* into current/prior rle lines */	
    RLE_Run *pra0;	/* rightmost in prior line with xe<=a0 (if none: prl->r) */
    int run,sync,si,rtc_eols;
    boolean fill;
    /* pixel indices (0,1,...):  current-line a*; prior-line b*.
       a0 is the index of the most recently completely encoded bit */
    int a0,a1,a2,b1,b2;	
    DST_color a0_color;  /* a0's color:  same as a2 & b2, opposite of a1 & b1 */
    int a01,a12;	 /* lengths of runs a0-a1 & a1-a2 */
#define g32_first_color DST_white	/* color of 1st run in each line */
#define g32_negative (0)	/* if 1, invert Black/White on output */
#define swap_rl(f,b) {swrl=(f); (f)=(b); (b)=swrl;}
/* detect b1 & b2:  sensitive to a0, a0_color, and prior runs *pr *(pr+1) */
#define g32r_find_Bb1Wb2 { \
	/* find 1st black changing pel>a0 */ \
	/* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \
	while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \
	/* look beyond pra0 */ \
	pr=pra0;  while(pr<pre && (b1=pr->xs)<=a0) pr++; \
	/* move b2 to 1st changing white pel > b1 */ \
	if(pr<pre) b2=pr->xe+1; \
	else b1=b2=prl->len; \
	}
#define g32r_find_Wb1Bb2 { \
	/* find 1st white changing pel>a0 */ \
	/* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \
	while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \
	/* look beyond pra0 */ \
	pr=pra0;  while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \
	/* move b2 to 1st changing black pel > b1 */ \
	if(pr<pre) { \
		if((pr+1)<pre) b2=(pr+1)->xs; \
		else b2=prl->len; \
		} \
	else b1=b2=prl->len; \
	}
#define g32r_find_b1b2 {if(a0_color==DST_white) g32r_find_Bb1Wb2 else g32r_find_Wb1Bb2;}

#if DEBUG
if(dbg_g32r_e) fprintf(stderr,"g32_to_rlel(t,bf,bof%d)\n",bof);
#endif
if(bof){crl= &rl0;  crl->y= -1;  crl->len=0;  crl->runs=0;
	prl= &rl1;  prl->y= -1;  prl->len=0;  prl->runs=0;
	/* sync by skipping initial FILL & EOL code */
	sync=0;  while((bitv=getb(f))==0) sync++;
	if(bitv!=1||sync<11) {
#if DEBUG
		if(dbg_g32r_c) {
			fprintf(stderr,"BOF_ERR ");
			for(si=0;si<sync;si++) fprintf(stderr,"0");
			if(bitv==1) fprintf(stderr,"1\n");
			else fprintf(stderr,"?\n");
			};
#endif
		return(NULL);
		}
#if DEBUG
	else if(dbg_g32r_c){
		fprintf(stderr,"BOF_EOL ");
		for(si=0;si<sync;si++) fprintf(stderr,"0");
		fprintf(stderr,"1\n");
		};
#else
		;
#endif
	prl->y = -1;  crl->y = 0;
	}
else crl->y = prl->y + 1;

pre = (pra0=pr=prl->r) + prl->runs;	/* prior line */
crl->runs=0;  cr=crl->r-1;		/* current line */
/* start on an imaginary white pixel just to left of margin */
a0= -1;  a0_color = DST_white;	

/* check 1-D / 2-D bit immediately after prior EOL */
switch(bitv=getb(f)) {
    case 0 :  /* 2-dimensionally encoded line */
#if DEBUG
	if(dbg_g32r_c) fprintf(stderr,"2D_LINE 0\n");
#endif
	/* start b1/b2 on prior line's first black pixel, etc;
	   if none, then place off end of line */
	if(pr<pre) {b1=pr->xs; b2=pr->xe+1;} else b1=b2=prl->len;
	/* parse a sequence of 2D codes... */
	while(T/* exited only via goto trap_* and return */) {
		cx.tr.s = DST_2d;  cx.tr.a = DST_action_NULL;
#if DEBUG
		if(dbg_g32r_t)fprintf(stderr,"(%d,%d)\n",cx.tr.s,cx.tr.a);
#endif
        	do {	switch(bitv=getb(f)) {
			    case 0 :
			    case 1 :
				cx.tr=t->e[cx.tr.s].t[bitv];
				break;
			    case EOF:  goto trap_eof;  break;
			    };
#if DEBUG
			if(dbg_g32r_t)fprintf(stderr,"%d->(%d,%d)\n",
					bitv,cx.tr.s,cx.tr.a);
#endif
			}
		while(cx.tr.a==DST_action_NULL);
#if DEBUG
		if(dbg_g32r_t)fprintf(stderr,"%s %04d  %s0\n",
			(cx.c==DST_white)? "W": "B",
			cx.tr.s,
			t->e[cx.tr.s].p);
#endif
		switch(cx.tr.a) {
		    case i2D_V0:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"V0      %s\n",code2d[cx.tr.a]);
#endif
			a1=b1;
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black)
				{ crl->runs++;  (++cr)->xs = a0;  cr->xe = a0; };
#if g32r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g32r_find_b1b2;
			break;
		    case i2D_VR1:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"VR1     %s\n",code2d[cx.tr.a]);
#endif
			a1=b1+1;
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black)
				{ crl->runs++;  (++cr)->xs = a0;  cr->xe = a0; };
#if !g32r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g32r_find_b1b2;
			break;
		    case i2D_VR2:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"VR2     %s\n",code2d[cx.tr.a]);
#endif
			a1=b1+2;
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black)
				{ crl->runs++;  (++cr)->xs = a0;  cr->xe = a0; };
#if !g32r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g32r_find_b1b2;
			break;
		    case i2D_VR3:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"VR3     %s\n",code2d[cx.tr.a]);
#endif
			a1=b1+3;
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black)
				{ crl->runs++;  (++cr)->xs = a0;  cr->xe = a0; };
#if !g32r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g32r_find_b1b2;
			break;
		    case i2D_VL1:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"VL1     %s\n",code2d[cx.tr.a]);
#endif
			if((a1=b1-1)<0) err("g32_to_rlel: VL1 backs up to %d",a1);
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black)
				{ crl->runs++;  (++cr)->xs = a0;  cr->xe = a0; };
#if !g32_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g32r_find_b1b2;
			break;
		    case i2D_VL2:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"VL2     %s\n",code2d[cx.tr.a]);
#endif
			if((a1=b1-2)<0) err("g32_to_rlel: VL2 backs up to %d",a1);
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black)
				{ crl->runs++;  (++cr)->xs = a0;  cr->xe = a0; };
#if !g32r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g32r_find_b1b2;
			break;
		    case i2D_VL3:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"VL3     %s\n",code2d[cx.tr.a]);
#endif
			if((a1=b1-3)<0) err("g32_to_rlel: VL3 backs up to %d",a1);
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black)
				{ crl->runs++;  (++cr)->xs = a0;  cr->xe = a0; };
#if !g32r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g32r_find_b1b2;
			break;
		    case i2D_PASS:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"PASS    %s\n",code2d[cx.tr.a]);
#endif
			/* move a0 to b2; no change of color */
			a0=b2;	if(a0>=prl->len) goto trap_expecting_eol;
			if(a0_color==DST_black) cr->xe = a0;
#if !g32r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g32r_find_b1b2;
			break;
		    case i2D_HORIZ:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"HORIZ   %s\n",code2d[cx.tr.a]);
#endif
			if(a0_color==DST_white) {
				if(a0<0) a0=0;	/* first run in line starts at 0 */
				g32_1d_run(DST_white,a01);  a1 = a0 + a01;
				g32_1d_run(DST_black,a12);  a2 = a1 + a12;
				if(a12>0) /* Black run of >0 length */ {
					crl->runs++;
					(++cr)->xs = a1;
					cr->xe = a2-1;
					};
				a0 = a2;	/* still white */
				if(a0>=prl->len) goto trap_expecting_eol;
				/* encode a0 */
#if !g32r_strict
				if(a0==prl->len-1)
					{ a0++;  goto trap_expecting_eol; };
#endif
				g32r_find_Bb1Wb2;
				}
			else {	g32_1d_run(DST_black,a01);  a1 = a0 + a01;
				g32_1d_run(DST_white,a12);  a2 = a1 + a12;
				if(a01>0) /* Black run of >0 length */ {
					cr->xe = a1 - 1;
					}
				else {	/* 0-length: very peculiar: ignore */
					fprintf(stderr,
					   "g32_to_rlel: HORIZ B%d! W%d - ignore\n",
					   a01,a12);
					cr--; crl->runs--;
					};
				a0 = a2;	/* still black */
				if(a0>=prl->len) goto trap_expecting_eol;
				/* encode a0 */
				crl->runs++;  (++cr)->xs = a0;
#if !g32r_strict
				if(a0==prl->len-1) {
					cr->xe = a0;
					a0++;
					goto trap_expecting_eol;
					};
#endif
				g32r_find_Wb1Bb2;
				};
			break;
		    case i2D_EOL:
#if DEBUG
			if(dbg_g32r_c)
				fprintf(stderr,"EOL     %s\n",code2d[cx.tr.a]);
#endif
			goto trap_eol;
			break;
		    case DST_action_ERROR:  goto trap_code_err;  break;
		    };
		};
	break;
    case 1 :  /* 1-dimensionally encoded line */
#if DEBUG
	if(dbg_g32r_c) fprintf(stderr,"1D_LINE 1\n");
#endif
	/* read a sequence of 1-D runcodes... */
	while(T/* exit only via goto trap_X */) {
		g32_1d_run(a0_color,a01);
		a1 = ((a0>=0)? a0 : 0) + a01;
		if(a01>0) {
			/* encode a0 through a1-1 */
			if(a0_color==DST_black^g32_negative) {
				/* output-black run */
				crl->runs++;
				(++cr)->xs=((a0>=0)? a0 : 0);
				cr->xe=a1-1;
				};
			};
		a0=a1;
		a0_color=flip_color(a0_color);
		if(prl->len>0 && a0>=prl->len) goto trap_expecting_eol;
		};
	break;
    case EOF :  goto trap_eof;  break;
    };

/* come here via goto's: all these traps return() */

trap_expecting_eol:	/* come here expecting to see EOL or FILL+EOL */
	sync=0;  while((bitv=getb(f))==0) sync++;
	switch(bitv) {
	    case 1:
		if(sync==11) {
#if DEBUG
			if(dbg_g32r_c){
				fprintf(stderr,"EOL     %s\n",EOLSTRING);
				};
#endif
			goto trap_eol;
			}
		else if(sync>11) {
#if DEBUG
			if(dbg_g32r_c){
				fprintf(stderr,"FILLEOL ");
				for(si=0;si<sync-11;si++) fprintf(stderr,"0");
				fprintf(stderr,"+");
				fprintf(stderr,"%s\n",EOLSTRING);
				};
#endif
			goto trap_eol;
			}
		else {	
#if DEBUG
			if(dbg_g32r_c){
				fprintf(stderr,"NOT EOL ");
				for(si=0;si<sync;si++) fprintf(stderr,"0");
				fprintf(stderr,"1?");
				};
#endif
			sync=0;
			goto trap_eol_err;
			};
		break;
	    case EOF:  goto trap_eof;  break;
	    };
	goto trap_eol;

trap_code_err:
	/* unexpected coding sequence:
	   'px' holds last decoding context & 'bitv' latest bit value;
	   will attempt to resynchronize on next EOL */
#if DEBUG
	if(dbg_g32r_c)fprintf(stderr,"CODERR  %s%d?",
				t->e[px.tr.s].p,bitv);
#endif
	/* count trailing 0's so far (should be in table) */
#if !NEW_TRAIL
	if(bitv==0) sync=1; else sync=0;
	si=strlen(t->e[px.tr.s].p)-1;
	while(si>=0&&t->e[px.tr.s].p[si]=='0') {sync++; si--;};
	fill = (si<0);	/* all 0's:  may be fill bits */
#else
	if(bitv==0) sync=t->e[px.tr.s].z+1; else sync=t->e[px.tr.s].z;
	fill = (sync>t->e[px.tr.s].l); /* all 0's:  maybe fill bits */
#endif 
#if DEBUG
	if(dbg_trail)err("sync %d fill %d",sync,fill);
#endif
trap_eol_err:
	while(sync<11) {
		switch(bitv=getb(f)) {
			case 0:  sync++;
#if DEBUG
				if(dbg_g32r_c) fprintf(stderr,"0");
#endif
				break;
			case 1:  sync=0;
#if DEBUG
				if(dbg_g32r_c) fprintf(stderr,"1");
#endif
				break;
			case EOF:  goto trap_eof;  break;
			};
		};
	/* next `1' will synchronize */
	do {	switch(bitv=getb(f)) {
			case 0:
#if DEBUG
				if(dbg_g32r_c) fprintf(stderr,"0");
#endif
				break;
			case 1:
#if DEBUG
				if(dbg_g32r_c) fprintf(stderr,"1");
#endif
				break;
			case EOF:  goto trap_eof;  break;
			};
		}
	while(bitv!=1);
#if DEBUG
	if(dbg_g32r_c) fprintf(stderr," EOL\n");
#endif
	goto trap_eol;

trap_eol:	/* come here having seen (and reported) EOL */
	/* learn/check line-length */
	if(a0>=0) crl->len=a0; else crl->len=0;
	if(crl->len==0) {
		/* no pixels coded -- may be the 1st of 6 RTC EOLs */
		/* check suffix 1 bit */
		if((bitv=getb(f))!=1) goto trap_eol_err;
		rtc_eols=1;
#if DEBUG
		if(dbg_g32r_c)fprintf(stderr,"RTC_EOL +1 (%d)\n",rtc_eols);
#endif
		do {	sync=0;  while((bitv=getb(f))==0) sync++;
			switch(bitv) {
			    case 1:
				if(sync<11) {
#if DEBUG
					if(dbg_g32r_c){
						fprintf(stderr,"NOT RTC ");
						for(si=0;si<sync;si++)
							fprintf(stderr,"0");
						fprintf(stderr,"1?\n");
						};
#endif
					sync=0;
					goto trap_eol_err;
					};
				break;
			    case EOF:  goto trap_eof;  break;
			    };
			/* check suffix 1 bit */
			if((bitv=getb(f))!=1) goto trap_eol_err;
			rtc_eols++;
#if DEBUG
			if(dbg_g32r_c) {
				fprintf(stderr,"RTC_EOL ");
				for(si=0;si<sync;si++) fprintf(stderr,"0");
				fprintf(stderr,"1+1  (%d)\n",rtc_eols);
				};
#endif
			}
		while(rtc_eols<6);
		/* normal RTC */
#if DEBUG
		if(dbg_g32r_c)fprintf(stderr,"RTC\n");
#endif
		return(NULL);
		}
	else if(prl->len==0) {
#if DEBUG
		if(dbg_g32r_c)fprintf(stderr,"LINELEN %d\n",crl->len);
#endif
		}
	else if(crl->len!=prl->len) {
		err("g32_to_rlel: y%d: LINELEN changes c%d != p%d ? (force to %d)",
			crl->y,crl->len,prl->len,prl->len);
		crl->len = prl->len;
		};
	swap_rl(crl,prl);
	return(prl);

trap_eof:
#if DEBUG
	if(dbg_g32r_c) fprintf(stderr,"<EOF>\n");
#endif
	return(NULL);

    }

/* Translate a sequence of RLE_Line's (describing a binary image)
   into a file (a stream of bits) in CCITT FAX Group 3 (2-D) compression format.
   BOF_to_g32() must be called first;  then call rlel_to_g32() for each line
   (including blank lines); finally, EOF_to_g32() must be called.  Each line's
   EOL and the RTC's first EOL will be padded so they end on a byte boundary.
   */
/* debugging flags:  trace to stderr */
#define dbg_rg32_e (0)	/* entry */
#define dbg_rg32_r (0)	/* runs */
#define dbg_rg32_s (0)	/* bitstrings */
#define rg32_strict (1)	/* 1 is CORRECT: explicitly code the last black pel */

#if DEBUG
#define bits_g32(bits) { \
	cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;};  \
	if(dbg_rg32_s) fprintf(stderr,"%s",(bits)); \
	if(dbg_rg32_r) fprintf(stderr," "); \
	}
#else
#define bits_g32(bits) { \
	cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;};  \
	}
#endif
#if DEBUG
#define EOL_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"EOL     "); \
	bits_g32(EOLSTRING); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define EOL_g32 { \
	bits_g32(EOLSTRING); \
	}
#endif

BOF_to_g32(f)
    BITFILE *f;
{   char *cs;
	/* a NOP: no header for Group 3 (2-D) */
#if DEBUG
	if(dbg_rg32_e) fprintf(stderr,"BOF\n");
#endif
	};

rlel_to_g32(pl,cl,wid,f)
    RLE_Line *pl;	/* prior "reference" line: if NULL, use 1-D coding on cl */
    RLE_Line *cl;	/* current "coding" line: if NULL, is blank (all white) */
    int wid;		/* width of an output line in pixels */
    BITFILE *f;
{   int runl,codi;
    char *cs,*p01;
#if DEBUG
#define Wrun_g32(rn) { \
	runl=(rn); \
	if(dbg_rg32_r) fprintf(stderr,"W %5d ",runl); \
	while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \
	p01=codewht[codi=rtoi(runl)]; bits_g32(p01); \
	if(codi>=64) {p01=codewht[runl%64]; bits_g32(p01);}; \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define Wrun_g32(rn) { \
	runl=(rn); \
	while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \
	p01=codewht[codi=rtoi(runl)]; bits_g32(p01); \
	if(codi>=64) {p01=codewht[runl%64]; bits_g32(p01);}; \
	}
#endif
#if DEBUG
#define Brun_g32(rn) { \
	runl=(rn); \
	if(dbg_rg32_r) fprintf(stderr,"B %5d ",runl); \
	while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \
	p01=codeblk[codi=rtoi(runl)]; bits_g32(p01); \
	if(codi>=64) {p01=codeblk[runl%64]; bits_g32(p01);}; \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define Brun_g32(rn) { \
	runl=(rn); \
	while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g32(p01); runl-=2560;}; \
	p01=codeblk[codi=rtoi(runl)]; bits_g32(p01); \
	if(codi>=64) {p01=codeblk[runl%64]; bits_g32(p01);}; \
	}
#endif
#if DEBUG
#define V0_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"V0      "); \
	bits_g32(code2d[i2D_V0]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define V0_g32 { \
	bits_g32(code2d[i2D_V0]); \
	}
#endif
#if DEBUG
#define VR1_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"VR1     "); \
	bits_g32(code2d[i2D_VR1]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define VR1_g32 { \
	bits_g32(code2d[i2D_VR1]); \
	}
#endif
#if DEBUG
#define VR2_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"VR2     "); \
	bits_g32(code2d[i2D_VR2]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define VR2_g32 { \
	bits_g32(code2d[i2D_VR2]); \
	}
#endif
#if DEBUG
#define VR3_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"VR3     "); \
	bits_g32(code2d[i2D_VR3]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define VR3_g32 { \
	bits_g32(code2d[i2D_VR3]); \
	}
#endif
#if DEBUG
#define VL1_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"VL1     "); \
	bits_g32(code2d[i2D_VL1]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define VL1_g32 { \
	bits_g32(code2d[i2D_VL1]); \
	}
#endif
#if DEBUG
#define VL2_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"VL2     "); \
	bits_g32(code2d[i2D_VL2]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define VL2_g32 { \
	bits_g32(code2d[i2D_VL2]); \
	}
#endif
#if DEBUG
#define VL3_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"VL3     "); \
	bits_g32(code2d[i2D_VL3]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define VL3_g32 { \
	bits_g32(code2d[i2D_VL3]); \
	}
#endif
#if DEBUG
#define PASS_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"PASS    "); \
	bits_g32(code2d[i2D_PASS]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define PASS_g32 { \
	bits_g32(code2d[i2D_PASS]); \
	}
#endif
#if DEBUG
#define HORIZ_g32 { \
	if(dbg_rg32_r) fprintf(stderr,"HORIZ   "); \
	bits_g32(code2d[i2D_HORIZ]); \
	if(dbg_rg32_r) fprintf(stderr,"\n"); \
	}
#else
#define HORIZ_g32 { \
	bits_g32(code2d[i2D_HORIZ]); \
	}
#endif
#define detect_a1a2_BW { \
	/* find leftmost black changing pel > a0 */ \
	/* advance cra as far as possible s.t. cra->xe<=a0 */ \
	while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \
	/* look beyond cra, until cr->xs>a0 */ \
	cr=cra; while(cr<cre && (a1=cr->xs)<=a0) cr++; \
	if(cr<cre) a2=cr->xe+1; \
	else a1=a2=wid; \
	}
#define detect_a1a2_WB { \
	/* find leftmost white changing pel > a0 */ \
	/* advance cra as far as possible s.t. cra->xe<=a0 */ \
	while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \
	/* look beyond cra, until cr->xe+1>a0 */ \
	cr=cra;  while(cr<cre && (a1=cr->xe+1)<=a0) cr++; \
	if(cr<cre) { \
		if((cr+1)<cre) a2=(cr+1)->xs; \
		else a2=wid; \
		} \
	else a1=a2=wid; \
	}
#define detect_a1a2 {if(a0_color==DST_white) detect_a1a2_BW else detect_a1a2_WB;}
#define detect_b1b2_BW {\
	/* find leftmost black changing pel > a0 */ \
	/* advance pra as far as possible s.t. pra->xe<=a0 */ \
	while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \
	/* look beyond pra */ \
	pr=pra;  while(pr<pre && (b1=pr->xs)<=a0) pr++; \
	/* move b2 to 1st changing white pel > b1 */ \
	if(pr<pre) b2=pr->xe+1; \
	else b1=b2=wid; \
	}
#define detect_b1b2_WB {\
	/* find leftmost white changing pel > a0 */ \
	/* advance pra as far as possible s.t. pra->xe<=a0 */ \
	while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \
	/* look beyond pra */ \
	pr=pra;  while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \
	/* move b2 to 1st changing black pel > b1 */ \
	if(pr<pre) { \
		if((pr+1)<pre) b2=(pr+1)->xs; \
		else b2=wid; \
		} \
	else b1=b2=wid; \
	}
#define detect_b1b2 {if(a0_color==DST_white) detect_b1b2_BW else detect_b1b2_WB;}

#if DEBUG
	if(dbg_rg32_e) err("rlel_to_g32(pl[%d],cl[%d],w%d)",
				(pl==NULL)? -1: pl->runs,
				(cl==NULL)? -1: cl->runs,
				wid);
#endif
	/* fill so that EOL ends on byte boundary */
	padb(f,0,8,EOLLENGTH);
#if DEBUG
	if(dbg_rg32_s) fprintf(stderr,"FILL  +0?");
#endif
	EOL_g32;	/* begin with EOL (sic) */
	if(pl==NULL) /* use 1-D coding for *cl */ {
	    int pi;		/* input pixel index on line */
	    RLE_Run *rp,*pp,*sp;
		putb(1,f);
#if DEBUG
		if(dbg_rg32_r) fprintf(stderr,"1D_LINE 1\n");
#endif
		if(cl!=NULL&&cl->runs>0) {
			pi=0;	/* bit to write next */
			for(sp=(rp=cl->r)+cl->runs; rp<sp; rp++) {
				Wrun_g32(rp->xs-pi);  pi=rp->xs;
				Brun_g32(rp->xe-pi+1);  pi=rp->xe+1;
				};
			if((--rp)->xe+1<wid) Wrun_g32(wid-rp->xe-1);
			}
		else Wrun_g32(wid);  /* blank scanline */
		}
	else /* use 2-D coding for *cl */ {
	    RLE_Run *cr,*cre,*pr,*pre;	/* into current/prior rle lines */	
	    int a0,a1,a2,b1,b2;	 /* indices {0,1,...} of pixels */
	    DST_color a0_color;  /* a0's color:  same as a2 & b2, opp of a1 & b1 */
	    RLE_Run *cra;   /* rightmost in current st xe<=a0 (none: ==cl->r)  */
	    RLE_Run *pra;   /* rightmost in prior st xe<=a0 (none: ==pl->r) */
	    int a01,a12,a1b1;	/* lengths of runs a0-a1 a1-a2 a1-b1 */
		putb(0,f);
#if DEBUG
		if(dbg_rg32_r) fprintf(stderr,"2D_LINE 0\n");
#endif
		/* start on an imaginary white pixel just to left of margin */
		a0= -1;  a0_color = DST_white;	
		pre = (pra=pl->r) + pl->runs;	/* prior line's runs */
		/* start b1/b2 on prior line's first black pixel, etc;
		   if none, then place off end of line */
		if(pra<pre) {b1=pra->xs; b2=pra->xe+1;} else b1=b2=wid;
		if(cl!=NULL&&cl->runs>0) {
			cre = (cra=cl->r) + cl->runs;
			a1=cra->xs;  a2=cra->xe+1;
#if rg32_strict
			while(a0 < wid) {
#else
			while(a0 < wid-1) {
#endif
				/* a0, a1, a2, b1, b2 are as in CCITT Rec T.4 */
#if DEBUG
				if(dbg_rg32_r)
				    fprintf(stderr,"f%d(%d,%d,%d) b%d(%d,%d)\n",
					cra-(cl->r),a0,a1,a2,pra-(pl->r),b1,b2);
#endif
				if(b2<a1) /* PASS mode */ {
					PASS_g32;
					a0=b2;
					/* a0-color, a1, & a2 are unchanged */
					detect_b1b2;
					}
				else if((a1b1=(a1-b1))<=3 && a1b1>= -3) {
					/* VERTICAL mode */
					switch(a1b1) {
					    case -3:  VL3_g32;  break;
					    case -2:  VL2_g32;  break;
					    case -1:  VL1_g32;  break;
					    case 0:  V0_g32;  break;
					    case 1:  VR1_g32;  break;
					    case 2:  VR2_g32;  break;
					    case 3:  VR3_g32;  break;
					    };
					a0=a1;  a0_color=flip_color(a0_color);
					detect_a1a2;
					detect_b1b2;
					}
				else {	/* HORIZONTAL mode */
					HORIZ_g32;
					a01=a1-a0; if(a0== -1) a01--;
					a12=a2-a1;
					if(a0_color==DST_white) {
						Wrun_g32(a01);
						Brun_g32(a12);
						}
					else {	Brun_g32(a01);
						Wrun_g32(a12);
						};
					a0=a2;
					/* a0_color is unchanged */
					detect_a1a2;
					detect_b1b2;
					};
				};
			}
		else /* current line is blank */ {
			a1=a2=wid;
#if rg32_strict
			while(a0 < wid) {
#else
			while(a0 < wid-1) {
#endif
				/* a0, a1, a2, b1, b2 are as in CCITT Rec. T.4 */
#if DEBUG
				if(dbg_rg32_r)
				    fprintf(stderr,"f(%d,%d,%d) b%d(%d,%d)\n",
					a0,a1,a2,pra-(pl->r),b1,b2);
#endif
				if(b2<a1) /* PASS mode */ {
					PASS_g32;
					a0=b2;
					/* a0-color, a1, & a2 are unchanged */
					detect_b1b2;
					}
				else if((a1b1=a1-b1)<=3 && a1b1>= -3) {
					/* VERTICAL mode */
					switch(a1b1) {
					    case -3:  VL3_g32;  break;
					    case -2:  VL2_g32;  break;
					    case -1:  VL1_g32;  break;
					    case 0:  V0_g32;  break;
					    case 1:  VR1_g32;  break;
					    case 2:  VR2_g32;  break;
					    case 3:  VR3_g32;  break;
					    };
					a0=a1;  a0_color=flip_color(a0_color);
					/* a1, & a2 are unchanged */
					detect_b1b2;
					}
				else {	/* HORIZONTAL mode */
					HORIZ_g32;
					a01=a1-a0; if(a0== -1) a01--;
					a12=a2-a1;
					if(a0_color==DST_white) {
						Wrun_g32(a01);
						Brun_g32(a12);
						}
					else {	Brun_g32(a01);
						Wrun_g32(a12);
						};
					a0=a2;
					/* a0_color, a1, & a2 are unchanged */
					detect_b1b2;
					};
				};
			};
		};
	}

EOF_to_g32(f)
    BITFILE *f;
{   char *cs;
	padb(f,0,8,EOLLENGTH);  /* fill so that EOL ends on byte boundary */
#if DEBUG
	if(dbg_rg32_s) fprintf(stderr,"FILL  +0?");
#endif
	/* write RTC */
	EOL_g32;
	EOL_g32;
	EOL_g32;
	EOL_g32;
	EOL_g32;
	EOL_g32;
#if DEBUG
	if(dbg_rg32_e) fprintf(stderr,"EOF\n");
#endif
	}

/* Macro for use within g4_to_rlel, to read one 1-D Modified Huffman coded
   run-length of color C, placing the result in variable V.
   Exceptionally, goto trap_eol, trap_eof, or trap_code_err.
  */
#if DEBUG
#define g4_1d_run(C,V) { \
	run = 0; \
	do {	cx.tr.s = (C); \
	        do {	px = cx; \
			switch(bitv=getb(f)) { \
			    case 0 :  cx.tr=t->e[cx.tr.s].t[0];  break; \
			    case 1 :  cx.tr=t->e[cx.tr.s].t[1];  break; \
			    case EOF :  goto trap_eof;  break; \
			    }; \
			} \
		while(cx.tr.a==DST_action_NULL); \
		switch(cx.tr.a) { \
		    case DST_EOL : \
			if(dbg_g4r_c)fprintf(stderr,"EOL     %s\n",EOLSTRING); \
			goto trap_eol; \
			break; \
		    case DST_action_ERROR :  goto trap_code_err;  break; \
		    default : \
			if(dbg_g4r_c)fprintf(stderr,"%s%6d %s%d\n", \
				((C)==DST_white)? "W": "B", \
				cx.tr.a, \
				t->e[px.tr.s].p, \
				bitv); \
			run += cx.tr.a; \
			break; \
		    }; \
		} \
	while(cx.tr.a>63); \
	(V) = run; \
	}
#else
#define g4_1d_run(C,V) { \
	run = 0; \
	do {	cx.tr.s = (C); \
	        do {	px = cx; \
			switch(bitv=getb(f)) { \
			    case 0 :  cx.tr=t->e[cx.tr.s].t[0];  break; \
			    case 1 :  cx.tr=t->e[cx.tr.s].t[1];  break; \
			    case EOF :  goto trap_eof;  break; \
			    }; \
			} \
		while(cx.tr.a==DST_action_NULL); \
		switch(cx.tr.a) { \
		    case DST_EOL : \
			goto trap_eol; \
			break; \
		    case DST_action_ERROR :  goto trap_code_err;  break; \
		    default : \
			run += cx.tr.a; \
			break; \
		    }; \
		} \
	while(cx.tr.a>63); \
	(V) = run; \
	}
#endif

/* Translate a stream of bits in CCITT FAX Group 4 compression format, of known
   fixed line-length, into a sequence of RLE_Lines.  Returns one (RLE_Line *)
   on each call (or NULL if EOF or error).  The first pixel (black or white)
   in each g4 line is assigned run index 0.
   WARNING:  the RLE_Line returned must NOT be modified by the caller, since
   it is used to decode the next line. */
RLE_Line *g4_to_rlel(t,f,bof,len)
    DST_table *t;
    BITFILE *f;
    boolean bof;	/* beginning of file */
    int len;		/* line-length in pixels (used only on bof) */
#define dbg_g4r_e (0)	/* trace entry-to / exit-from function */
#define dbg_g4r_r (0)	/* trace each run/EOL/ERR_SYN */
#define dbg_g4r_c (0)	/* trace each Huffman code (or, fill+EOL)*/
#define dbg_g4r_t (0)	/* trace each state-transition */
#define g4r_strict (1)	/* 1 is CORRECT: explicitly code the last black pel */
{   static RLE_Line rl0,rl1,*prl,*crl;	/* prior, current run-lines */
    RLE_Line *swrl;
    int bitv;			/* the last-read bit value */
    DST_context cx,px;		/* the current/prior decoding context */
    RLE_Run *cr,*pr,*pre;	/* into current/prior rle lines */	
    RLE_Run *pra0;		/* rightmost in prior line with xe<=a0
				   (if none: prl->r) */
    int run,sync,si,rtc_eols;
    /* pixel indices (0,1,...):  current-line a*; prior-line b*.
       a0 is the index of the most recently completely encoded bit */
    int a0,a1,a2,b1,b2;	
    DST_color a0_color;  /* a0's color:  same as a2 & b2, opposite of a1 & b1 */
    int a01,a12;	/* lengths of runs a0-a1 & a1-a2 */
#define g4_first_color (DST_white)	/* color of 1st run in each line */
#define g4_negative (0)		/* if 1, invert Black/White on output */
#define swap_rl(f,b) {swrl=(f); (f)=(b); (b)=swrl;}
/* detect b1 & b2:  sensitive to a0, a0_color, and prior runs *pr *(pr+1) */
#define g4r_find_Bb1Wb2 { \
	/* find 1st black changing pel>a0 */ \
	/* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \
	while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \
	/* look beyond pra0 */ \
	pr=pra0;  while(pr<pre && (b1=pr->xs)<=a0) pr++; \
	/* move b2 to 1st changing white pel > b1 */ \
	if(pr<pre) b2=pr->xe+1; \
	else b1=b2=prl->len; \
	}
#define g4r_find_Wb1Bb2 { \
	/* find 1st white changing pel>a0 */ \
	/* advance pra0 as far as possible s.t. pra0->xe<=a0 */ \
	while((pra0+1)<pre && (pra0+1)->xe<=a0) pra0++; \
	/* look beyond pra0 */ \
	pr=pra0;  while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \
	/* move b2 to 1st changing black pel > b1 */ \
	if(pr<pre) { \
		if((pr+1)<pre) b2=(pr+1)->xs; \
		else b2=prl->len; \
		} \
	else b1=b2=prl->len; \
	}
#define g4r_find_b1b2 { \
	if(a0_color==DST_white) g4r_find_Bb1Wb2 else g4r_find_Wb1Bb2; \
	if(b1<=a0) err("g4_to_rlel: y%d: b1 %d <= a0 %d ?",crl->y,a0,b1); \
	}

	if(bof){/* initial reference line is all white, of known length */
		prl= &rl0;  prl->y= -1;  prl->len=len;  prl->runs=0;
		/* initial coding line has y-coordinate 0 */
		crl= &rl1;  crl->y=0;  crl->len=0;  crl->runs=0;
		}
	else crl->y = prl->y + 1;
#if DEBUG
	if(dbg_g4r_e)
		fprintf(stderr,
			"g4_to_rlel(t,f,bof%d,len%d) y%d,l%d\n",
			bof,len,prl->y,prl->len);
#endif
	
	pre = (pra0=pr=prl->r) + prl->runs;	/* prior line */
	crl->runs=0;  cr=crl->r-1;		/* current line */
	/* start on an imaginary white pixel just to left of margin */
	a0= -1;  a0_color = DST_white;
#if DEBUG
	a1=a2=b1=b2=0;  /* immaterial; looks better when debugging */
#endif

	/* start b1/b2 on prior line's first black pixel, etc;
	   if none, then place off end of line */
	if(pr<pre) {b1=pr->xs; b2=pr->xe+1;} else b1=b2=prl->len;
	/* parse a sequence of 2D codes... */
	while(T/* exit only via 'goto trap_X' */) {
		/* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */
#if DEBUG
		if(dbg_g4r_r)
			fprintf(stderr,"a(%d,%d,%d) b(%d,%d)\n",a0,a1,a2,b1,b2);
#endif
		cx.tr.s = DST_2d;  cx.tr.a = DST_action_NULL;
#if DEBUG
		if(dbg_g4r_t)fprintf(stderr,"(%d,%d)\n",cx.tr.s,cx.tr.a);
#endif
        	do {	switch(bitv=getb(f)) {
			    case 0 :
			    case 1 :
				cx.tr=t->e[cx.tr.s].t[bitv];
				break;
			    case EOF:  goto trap_eof;  break;
			    };
#if DEBUG
			if(dbg_g4r_t)fprintf(stderr,"%d->(%d,%d)\n",
					bitv,cx.tr.s,cx.tr.a);
#endif
			}
		while(cx.tr.a==DST_action_NULL);
#if DEBUG
		if(dbg_g4r_t)fprintf(stderr,"%s %04d  %s0\n",
			(cx.c==DST_white)? "W": "B",
			cx.tr.s,
			t->e[cx.tr.s].p);
#endif
		switch(cx.tr.a) {
		    case i2D_V0:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"V0      %s\n",code2d[cx.tr.a]);
#endif
			a1=b1;
			/* interpret (a0,a1-1] */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* interpret a0 */
			if(a0_color==DST_black) {
				if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
					err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
						crl->y,crl->runs,cr->xs,cr->xe);
				crl->runs++;  (++cr)->xs = a0;  cr->xe = a0;
				};
#if !g4r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g4r_find_b1b2;
			break;
		    case i2D_VR1:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"VR1     %s\n",code2d[cx.tr.a]);
#endif
			a1=b1+1;
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black) {
				if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
					err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
						crl->y,crl->runs,cr->xs,cr->xe);
				crl->runs++;  (++cr)->xs = a0;  cr->xe = a0;
				};
#if !g4r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g4r_find_b1b2;
			break;
		    case i2D_VR2:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"VR2     %s\n",code2d[cx.tr.a]);
#endif
			a1=b1+2;
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black) {
				if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
					err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
						crl->y,crl->runs,cr->xs,cr->xe);
				crl->runs++;  (++cr)->xs = a0;  cr->xe = a0;
				};
#if !g4r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g4r_find_b1b2;
			break;
		    case i2D_VR3:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"VR3     %s\n",code2d[cx.tr.a]);
#endif
			a1=b1+3;
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black) {
				if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
					err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
						crl->y,crl->runs,cr->xs,cr->xe);
				crl->runs++;  (++cr)->xs = a0;  cr->xe = a0;
				};
#if !g4r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g4r_find_b1b2;
			break;
		    case i2D_VL1:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"VL1     %s\n",code2d[cx.tr.a]);
#endif
			if((a1=b1-1)<=a0)
				err("g4_to_rlel: y%d: VL1 a1 %d <= a0 %d ?",
					crl->y,a1,a0);
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black) {
				if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
					err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
						crl->y,crl->runs,cr->xs,cr->xe);
				crl->runs++;  (++cr)->xs = a0;  cr->xe = a0;
				};
#if !g4r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g4r_find_b1b2;
			break;
		    case i2D_VL2:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"VL2     %s\n",code2d[cx.tr.a]);
#endif
			if((a1=b1-2)<=a0)
				err("g4_to_rlel: y%d: VL2 a1 %d <= a0 %d ?",
					crl->y,a1,a0);
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black) { 
				if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
					err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
						crl->y,crl->runs,cr->xs,cr->xe);
				crl->runs++;  (++cr)->xs = a0;  cr->xe = a0;
				};
#if !g4r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g4r_find_b1b2;
			break;
		    case i2D_VL3:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"VL3     %s\n",code2d[cx.tr.a]);
#endif
			if((a1=b1-3)<=a0)
				err("g4_to_rlel: y%d: VL3 a1 %d <= a0 %d ?",
					crl->y,a1,a0);
			/* encode a0 to a1-1 */
			if(a0_color==DST_black) cr->xe=a1-1;
			/* move a0 to a1 */
			a0=a1;  if(a0>=prl->len) goto trap_expecting_eol;
			a0_color = flip_color(a0_color);
			/* encode a0 */
			if(a0_color==DST_black) {
				if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
					err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
						crl->y,crl->runs,cr->xs,cr->xe);
				crl->runs++;  (++cr)->xs = a0;  cr->xe = a0;
				};
#if !g4r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g4r_find_b1b2;
			break;
		    case i2D_PASS:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"PASS    %s\n",code2d[cx.tr.a]);
#endif
			/* move a0 to b2; no change of color */
			a0=b2;	if(a0>=prl->len) goto trap_expecting_eol;
			if(a0_color==DST_black) cr->xe = a0;
#if !g4r_strict
			if(a0==prl->len-1)
				{ a0++;  goto trap_expecting_eol; };
#endif
			g4r_find_b1b2;
			break;
		    case i2D_HORIZ:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"HORIZ   %s\n",code2d[cx.tr.a]);
#endif
			if(a0_color==DST_white) {
				if(a0<0) a0=0;	/* first run in line starts at 0 */
				g4_1d_run(DST_white,a01);  a1 = a0 + a01;
				g4_1d_run(DST_black,a12);  a2 = a1 + a12;
				if(a12>0) /* Black run of >0 length */ {
				if(cr->xs>cr->xe&&cr->xs<prl->len&&cr->xe>0)
					err("g4_to_rlel: y%d: r%d[%d,%d] not monotone ?",
						crl->y,crl->runs,cr->xs,cr->xe);
					crl->runs++; (++cr)->xs = a1; cr->xe = a2-1;
					};
				a0 = a2;	/* still white */
				if(a0>=prl->len) goto trap_expecting_eol;
				/* encode a0 */
#if !g4r_strict
				if(a0==prl->len-1)
					{ a0++;  goto trap_expecting_eol; };
#endif
				g4r_find_Bb1Wb2;
				}
			else {	g4_1d_run(DST_black,a01);  a1 = a0 + a01;
				g4_1d_run(DST_white,a12);  a2 = a1 + a12;
				if(a01>0) /* Black run of >0 length */ {
					cr->xe = a1 - 1;
					}
				else {	/* 0-length: very peculiar: ignore */
					fprintf(stderr,
					   "g4_to_rlel: HORIZ B%d! W%d - ignore\n",
					   a01,a12);
					cr--; crl->runs--;
					};
				a0 = a2;	/* still black */
				if(a0>=prl->len) goto trap_expecting_eol;
				/* encode a0 */
				crl->runs++;  (++cr)->xs = a0;
#if !g4r_strict
				if(a0==prl->len-1) {
					cr->xe = a0;
					a0++;
					goto trap_expecting_eol;
					};
#endif
				g4r_find_Wb1Bb2;
				};
			break;
		    case i2D_EOL:
#if DEBUG
			if(dbg_g4r_c)
				fprintf(stderr,"EOL     %s\n",code2d[cx.tr.a]);
#endif
			goto trap_eol;
			break;
		    case DST_action_ERROR:  goto trap_code_err;  break;
		    };
		};

/* come here via goto's: all these traps return() */

trap_expecting_eol:	/* come here having detected (computed) end-of-line */
	/* learn/check/correct line-length */
	crl->len = (a0>0)? a0 : 0;
	if(crl->len!=prl->len) {
		err("g4_to_rlel: y%d: LINELEN changes c%d != p%d ? (force to %d)",
			crl->y,crl->len,prl->len,prl->len);
		crl->len = prl->len;
		};
	swap_rl(crl,prl);
#if DEBUG
	if(dbg_g4r_e)
		fprintf(stderr,
			"exit g4_to_rlel: expg_eol y%d,l%d\n",
			prl->y,prl->len);
#endif
	return(prl);

trap_eol:  /* come here having seen an EOL code (rare in Group 4) */
	/* It must be the first of two EOL codes making up the EOB signal */
	/* look for 2nd EOL */
	sync=0;  while((bitv=getb(f))==0) sync++;
	switch(bitv) {
	    case 1:
		if(sync==11) {
#if DEBUG
			if(dbg_g4r_c) {
				fprintf(stderr,"EOB_EOL %s\n",EOLSTRING);
				fprintf(stderr,"EOB\n");
				};
#endif
			}
		else {	
#if DEBUG
			if(dbg_g4r_c){
				fprintf(stderr,"NOT EOB ");
				for(si=0;si<sync;si++)
					fprintf(stderr,"0");
				fprintf(stderr,"1?\n");
				fprintf(stderr,"ABORT\n");
				};
#endif
			};
		break;
	    case EOF:  goto trap_eof;  break;
	    };
#if DEBUG
	if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: eol\n");
#endif
	return(NULL);

trap_code_err:
	/* unexpected coding sequence:
	   'px' holds last decoding context & 'bitv' latest bit value;
	   will attempt to resynchronize on next EOL */
#if DEBUG
	if(dbg_g4r_c)fprintf(stderr,"CODERR  %s%d? (px.tr.s=%d)\n",
				t->e[px.tr.s].p,bitv,px.tr.s);
#endif
	err("g4_to_rlel: code error");
#if DEBUG
	if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: code_err\n");
#endif
	return(NULL);

trap_eof:
#if DEBUG
	if(dbg_g4r_c) fprintf(stderr,"<EOF>\n");
	if(dbg_g4r_e) fprintf(stderr,"exit g4_to_rlel: eof\n");
#endif
	return(NULL);

    }

/* Translate a sequence of RLE_Line's (describing a binary image)
   into a file (a stream of bits) in CCITT FAX Group 4 compression format.
   BOF_to_g4() must be called first; then call rlel_to_g4() for each line
   (including blank lines); finally, EOF_to_g4() must be called.  The EOFB
   is padded (suffixed) with 0's to a byte boundary if necessary; no other
   filling or padding is performed.
   */
/* debugging flags:  trace to stderr */
#define dbg_rg4_e (0)	/* entry */
#define dbg_rg4_r (0)	/* runs */
#define dbg_rg4_c (0)	/* codes (bitstrings) */
#define rg4_strict (1)	/* 1 is CORRECT: explicitly code the last black pel */

#if DEBUG
#define bits_g4(bits) { \
	cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;};  \
	if(dbg_rg4_c) fprintf(stderr,"%s",(bits)); \
	if(dbg_rg4_r) fprintf(stderr," "); \
	}
#else
#define bits_g4(bits) { \
	cs=(bits); while(*cs!='\0') {putb(*cs-'0',f); cs++;};  \
	}
#endif
#if DEBUG
#define EOFB_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"EOFB    "); \
	bits_g4(EOFB); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define EOFB_g4 { \
	bits_g4(EOFB); \
	}
#endif

BOF_to_g4(f)
    BITFILE *f;
{   char *cs;
	/* a NOP: no header for Group 4 */
#if DEBUG
	if(dbg_rg4_e) fprintf(stderr,"BOF\n");
#endif
	};

rlel_to_g4(pl,cl,wid,f)
    RLE_Line *pl;	/* prior "reference" line */
    RLE_Line *cl;	/* current "coding" line: if NULL, is blank (all white) */
    int wid;		/* width of an output line in pixels */
    BITFILE *f;
{   int runl,codi;
    char *cs,*p01;
#if DEBUG
#define Wrun_g4(rn) { \
	runl=(rn); \
	if(dbg_rg4_r) fprintf(stderr,"W %5d ",runl); \
	while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \
	p01=codewht[codi=rtoi(runl)]; bits_g4(p01); \
	if(codi>=64) {p01=codewht[runl%64]; bits_g4(p01);}; \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define Wrun_g4(rn) { \
	runl=(rn); \
	while(runl>2560) {p01=codewht[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \
	p01=codewht[codi=rtoi(runl)]; bits_g4(p01); \
	if(codi>=64) {p01=codewht[runl%64]; bits_g4(p01);}; \
	}
#endif
#if DEBUG
#define Brun_g4(rn) { \
	runl=(rn); \
	if(dbg_rg4_r) fprintf(stderr,"B %5d ",runl); \
	while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \
	p01=codeblk[codi=rtoi(runl)]; bits_g4(p01); \
	if(codi>=64) {p01=codeblk[runl%64]; bits_g4(p01);}; \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define Brun_g4(rn) { \
	runl=(rn); \
	while(runl>2560) {p01=codeblk[rtoi(2560)]; bits_g4(p01); runl-=2560;}; \
	p01=codeblk[codi=rtoi(runl)]; bits_g4(p01); \
	if(codi>=64) {p01=codeblk[runl%64]; bits_g4(p01);}; \
	}
#endif
#if DEBUG
#define V0_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"V0      "); \
	bits_g4(code2d[i2D_V0]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define V0_g4 { \
	bits_g4(code2d[i2D_V0]); \
	}
#endif
#if DEBUG
#define VR1_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"VR1     "); \
	bits_g4(code2d[i2D_VR1]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define VR1_g4 { \
	bits_g4(code2d[i2D_VR1]); \
	}
#endif
#if DEBUG
#define VR2_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"VR2     "); \
	bits_g4(code2d[i2D_VR2]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define VR2_g4 { \
	bits_g4(code2d[i2D_VR2]); \
	}
#endif
#if DEBUG
#define VR3_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"VR3     "); \
	bits_g4(code2d[i2D_VR3]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define VR3_g4 { \
	bits_g4(code2d[i2D_VR3]); \
	}
#endif
#if DEBUG
#define VL1_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"VL1     "); \
	bits_g4(code2d[i2D_VL1]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define VL1_g4 { \
	bits_g4(code2d[i2D_VL1]); \
	}
#endif
#if DEBUG
#define VL2_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"VL2     "); \
	bits_g4(code2d[i2D_VL2]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define VL2_g4 { \
	bits_g4(code2d[i2D_VL2]); \
	}
#endif
#if DEBUG
#define VL3_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"VL3     "); \
	bits_g4(code2d[i2D_VL3]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define VL3_g4 { \
	bits_g4(code2d[i2D_VL3]); \
	}
#endif
#if DEBUG
#define PASS_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"PASS    "); \
	bits_g4(code2d[i2D_PASS]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define PASS_g4 { \
	bits_g4(code2d[i2D_PASS]); \
	}
#endif
#if DEBUG
#define HORIZ_g4 { \
	if(dbg_rg4_r) fprintf(stderr,"HORIZ   "); \
	bits_g4(code2d[i2D_HORIZ]); \
	if(dbg_rg4_r) fprintf(stderr,"\n"); \
	}
#else
#define HORIZ_g4 { \
	bits_g4(code2d[i2D_HORIZ]); \
	}
#endif
#define detect_a1a2_BW { \
	/* find leftmost black changing pel > a0 */ \
	/* advance cra as far as possible s.t. cra->xe<=a0 */ \
	while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \
	/* look beyond cra, until cr->xs>a0 */ \
	cr=cra; while(cr<cre && (a1=cr->xs)<=a0) cr++; \
	if(cr<cre) a2=cr->xe+1; \
	else a1=a2=wid; \
	}
#define detect_a1a2_WB { \
	/* find leftmost white changing pel > a0 */ \
	/* advance cra as far as possible s.t. cra->xe<=a0 */ \
	while((cra+1)<cre && (cra+1)->xe<=a0) cra++; \
	/* look beyond cra, until cr->xe+1>a0 */ \
	cr=cra;  while(cr<cre && (a1=cr->xe+1)<=a0) cr++; \
	if(cr<cre) { \
		if((cr+1)<cre) a2=(cr+1)->xs; \
		else a2=wid; \
		} \
	else a1=a2=wid; \
	}
#define detect_a1a2 {if(a0_color==DST_white) detect_a1a2_BW else detect_a1a2_WB;}
#define detect_b1b2_BW {\
	/* find leftmost black changing pel > a0 */ \
	/* advance pra as far as possible s.t. pra->xe<=a0 */ \
	while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \
	/* look beyond pra */ \
	pr=pra;  while(pr<pre && (b1=pr->xs)<=a0) pr++; \
	/* move b2 to 1st changing white pel > b1 */ \
	if(pr<pre) b2=pr->xe+1; \
	else b1=b2=wid; \
	}
#define detect_b1b2_WB {\
	/* find leftmost white changing pel > a0 */ \
	/* advance pra as far as possible s.t. pra->xe<=a0 */ \
	while((pra+1)<pre && (pra+1)->xe<=a0) pra++; \
	/* look beyond pra */ \
	pr=pra;  while(pr<pre && (b1=pr->xe+1)<=a0) pr++; \
	/* move b2 to 1st changing black pel > b1 */ \
	if(pr<pre) { \
		if((pr+1)<pre) b2=(pr+1)->xs; \
		else b2=wid; \
		} \
	else b1=b2=wid; \
	}
#define detect_b1b2 {if(a0_color==DST_white) detect_b1b2_BW else detect_b1b2_WB;}

    RLE_Run *cr,*cre,*pr,*pre;	/* into current/prior rle lines */	
    int a0,a1,a2,b1,b2;	 /* indices {0,1,...} of pixels */
    DST_color a0_color;  /* a0's color:  same as a2 & b2, opp of a1 & b1 */
    RLE_Run *cra;   /* rightmost in current st xe<=a0 (none: ==cl->r)  */
    RLE_Run *pra;   /* rightmost in prior st xe<=a0 (none: ==pl->r) */
    int a01,a12,a1b1;	/* lengths of runs a0-a1 a1-a2 a1-b1 */
#if DEBUG
	if(dbg_rg4_e) err("rlel_to_g4(pl[%d],cl[%d],w%d)",
				(pl==NULL)? -1: pl->runs,
				(cl==NULL)? -1: cl->runs,
				wid);
#endif
	/* start on an imaginary white pixel just to left of margin */
	a0= -1;  a0_color = DST_white;	
	pre = (pra=pl->r) + pl->runs;	/* prior line's runs */
	/* start b1/b2 on prior line's first black pixel, etc;
	   if none, then place off end of line */
	if(pra<pre) {b1=pra->xs; b2=pra->xe+1;} else b1=b2=wid;
	if(cl!=NULL&&cl->runs>0) {
		cre = (cra=cl->r) + cl->runs;
		a1=cra->xs;  a2=cra->xe+1;
#if rg4_strict
		while( a0 < wid ) {
#else
		while( a0 < wid-1 ) {
#endif
			/* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */
#if DEBUG
			if(dbg_rg4_r)
			    fprintf(stderr,"f%d(%d,%d,%d) b%d(%d,%d)\n",
				cra-(cl->r),a0,a1,a2,pra-(pl->r),b1,b2);
#endif
			if(b2<a1) /* PASS mode */ {
				PASS_g4;
				a0=b2;
				/* a0-color, a1, & a2 are unchanged */
				detect_b1b2;
				}
			else if((a1b1=(a1-b1))<=3 && a1b1>= -3) {
				/* VERTICAL mode */
				switch(a1b1) {
				    case -3:  VL3_g4;  break;
				    case -2:  VL2_g4;  break;
				    case -1:  VL1_g4;  break;
				    case 0:  V0_g4;  break;
				    case 1:  VR1_g4;  break;
				    case 2:  VR2_g4;  break;
				    case 3:  VR3_g4;  break;
				    };
				a0=a1;  a0_color=flip_color(a0_color);
				detect_a1a2;
				detect_b1b2;
				}
			else {	/* HORIZONTAL mode */
				HORIZ_g4;
				a01=a1-a0; if(a0== -1) a01--;
				a12=a2-a1;
				if(a0_color==DST_white) {
					Wrun_g4(a01);
					Brun_g4(a12);
					}
				else {	Brun_g4(a01);
					Wrun_g4(a12);
					};
				a0=a2;
				/* a0_color is unchanged */
				detect_a1a2;
				detect_b1b2;
				};
			};
		}
	else /* current line is blank */ {
		a1=a2=wid;
#if rg4_strict
		while( a0 < wid ) {
#else
		while( a0 < wid-1 ) {
#endif
			/* a0, a1, a2, b1, b2 are as defined in CCITT Rec. T.6 */
#if DEBUG
			if(dbg_rg4_r)
			    fprintf(stderr,"f(%d,%d,%d) b%d(%d,%d)\n",
				a0,a1,a2,pra-(pl->r),b1,b2);
#endif
			if(b2<a1) /* PASS mode */ {
				PASS_g4;
				a0=b2;
				/* a0-color, a1, & a2 are unchanged */
				detect_b1b2;
				}
			else if((a1b1=a1-b1)<=3 && a1b1>= -3) {
				/* VERTICAL mode */
				switch(a1b1) {
				    case -3:  VL3_g4;  break;
				    case -2:  VL2_g4;  break;
				    case -1:  VL1_g4;  break;
				    case 0:  V0_g4;  break;
				    case 1:  VR1_g4;  break;
				    case 2:  VR2_g4;  break;
				    case 3:  VR3_g4;  break;
				    };
				a0=a1;  a0_color=flip_color(a0_color);
				/* a1, & a2 are unchanged */
				detect_b1b2;
				}
			else {	/* HORIZONTAL mode */
				HORIZ_g4;
				a01=a1-a0; if(a0== -1) a01--;
				a12=a2-a1;
				if(a0_color==DST_white) {
					Wrun_g4(a01);
					Brun_g4(a12);
					}
				else {	Brun_g4(a01);
					Wrun_g4(a12);
					};
				a0=a2;
				/* a0_color, a1, & a2 are unchanged */
				detect_b1b2;
				};
			};
		};
	}

EOF_to_g4(f)
    BITFILE *f;
{   char *cs;
	/* write EOFB */
	EOFB_g4;
#if DEBUG
	if(dbg_rg4_e) fprintf(stderr,"EOF\n");
#endif
	}

0707070035351137051006640007620000050000010261160476773366600001000000024315CCITT.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* CCITT Group 3 FAX compression codes */
#define EOLSTRING	"000000000001"
#define EOLLENGTH	12		/* length of EOLSTRING */
#define MAXCODELEN	24

#define DST_EOL -3

/* translate a runlength value <=2560 to an index into the Huffman code table;
   if the index is >=64, then must repeat for (r%64) */
#define rtoi(r) (((r)<64)? (r): 64+((r)/64))
/* translate an index into the Huffman code table to a runlength value */
#define itor(i) (((i)<64)? (i): (((i)>64)? (((i)-64)*64): DST_EOL))

/* Black run code table */
  static char *codeblk[] = {
	/* code			run-length value */
	"0000110111",		/* 0, */
	"010",			/* 1, */
	"11",			/* 2, */
	"10",			/* 3, */
	"011",			/* 4, */
	"0011",			/* 5, */
	"0010",			/* 6, */
	"00011",		/* 7, */
	"000101",		/* 8, */
	"000100",		/* 9, */
	"0000100",		/* 10, */
	"0000101",		/* 11, */
	"0000111",		/* 12, */
	"00000100",		/* 13, */
	"00000111",		/* 14, */
	"000011000",		/* 15, */
	"0000010111",		/* 16, */
	"0000011000",		/* 17, */
	"0000001000",		/* 18, */
	"00001100111",		/* 19, */
	"00001101000",		/* 20, */
	"00001101100",		/* 21, */
	"00000110111",		/* 22, */
	"00000101000",		/* 23, */
	"00000010111",		/* 24, */
	"00000011000",		/* 25, */
	"000011001010",		/* 26, */
	"000011001011",		/* 27, */
	"000011001100",		/* 28, */
	"000011001101",		/* 29, */
	"000001101000",		/* 30, */
	"000001101001",		/* 31, */
	"000001101010",		/* 32, */
	"000001101011",		/* 33, */
	"000011010010",		/* 34, */
	"000011010011",		/* 35, */
	"000011010100",		/* 36, */
	"000011010101",		/* 37, */
	"000011010110",		/* 38, */
	"000011010111",		/* 39, */
	"000001101100",		/* 40, */
	"000001101101",		/* 41, */
	"000011011010",		/* 42, */
	"000011011011",		/* 43, */
	"000001010100",		/* 44, */
	"000001010101",		/* 45, */
	"000001010110",		/* 46, */
	"000001010111",		/* 47, */
	"000001100100",		/* 48, */
	"000001100101",		/* 49, */
	"000001010010",		/* 50, */
	"000001010011",		/* 51, */
	"000000100100",		/* 52, */
	"000000110111",		/* 53, */
	"000000111000",		/* 54, */
	"000000100111",		/* 55, */
	"000000101000",		/* 56, */
	"000001011000",		/* 57, */
	"000001011001",		/* 58, */
	"000000101011",		/* 59, */
	"000000101100",		/* 60, */
	"000001011010",		/* 61, */
	"000001100110",		/* 62, */
	"000001100111",		/* 63  */
	EOLSTRING,		/* EOL */
	"0000001111",		/* 64, */
	"000011001000",		/* 128, */
	"000011001001",		/* 192, */
	"000001011011",		/* 256, */
	"000000110011",		/* 320, */
	"000000110100",		/* 384, */
	"000000110101",		/* 448, */
	"0000001101100",	/* 512, */
	"0000001101101",	/* 576, */
	"0000001001010",	/* 640, */
	"0000001001011",	/* 704, */
	"0000001001100",	/* 768, */
	"0000001001101",	/* 832, */
	"0000001110010",	/* 896, */
	"0000001110011",	/* 960, */
	"0000001110100",	/* 1024, */
	"0000001110101",	/* 1088, */
	"0000001110110",	/* 1152, */
	"0000001110111",	/* 1216, */
	"0000001010010",	/* 1280, */
	"0000001010011",	/* 1344, */
	"0000001010100",	/* 1408, */
	"0000001010101",	/* 1472, */
	"0000001011010",	/* 1536, */
	"0000001011011",	/* 1600, */
	"0000001100100",	/* 1664, */
	"0000001100101",	/* 1728  */
				/* extended length: */
	"00000001000",		/* 1792, */
	"00000001100",		/* 1856, */
	"00000001101",		/* 1920, */
	"000000010010",		/* 1984, */
	"000000010011",		/* 2048, */
	"000000010100",		/* 2112, */
	"000000010101",		/* 2176, */
	"000000010110",		/* 2240, */
	"000000010111",		/* 2304, */
	"000000011100",		/* 2368, */
	"000000011101",		/* 2432, */
	"000000011110",		/* 2496, */
	"000000011111",		/* 2560  */
	NULL			/* are there codes beyond 2560? */
	};
/* No. bits in the codes in the above table */
  static short bitcblk[] = {
	10,3,2,2,3,4,4,5,6,6,		/*  0 -  9 */
	7,7,7,8,8,9,10,10,10,11,	/* 10 - 19 */
	11,11,11,11,11,11,12,12,12,12,	/* 20 - 29 */
	12,12,12,12,12,12,12,12,12,12,	/* 30 - 39 */
	12,12,12,12,12,12,12,12,12,12,	/* 40 - 49 */
	12,12,12,12,12,12,12,12,12,12,	/* 50 - 59 */
	12,12,12,12,			/* 60 - 63 */
	12,				/* EOL */
	10,				/* 64 */
	12,12,12,12,12,12,		/* 128 - 448 */
	13,13,13,13,13,13,13,13,13,	/* 512 - */
	13,13,13,13,13,13,13,13,13,
	13,13, 				/* - 1728 */
	11,11,11,			/* 1792 - 1920 */
	12,12,12,12,12,12,12,12,12,12,	/* 1984 - 2560 */
	/* for codes over 2560 */
	14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
	-1
	};

/* White run code table */
  static char *codewht[] = {
	/* code			run-length value */
	"00110101",		/* 0, */
	"000111",		/* 1, */
	"0111",			/* 2, */
	"1000",			/* 3, */
	"1011",			/* 4, */
	"1100",			/* 5, */
	"1110",			/* 6, */
	"1111",			/* 7, */
	"10011",		/* 8, */
	"10100",		/* 9, */
	"00111",		/* 10, */
	"01000",		/* 11, */
	"001000",		/* 12, */
	"000011",		/* 13, */
	"110100",		/* 14, */
	"110101",		/* 15, */
	"101010",		/* 16, */
	"101011",		/* 17, */
	"0100111",		/* 18, */
	"0001100",		/* 19, */
	"0001000",		/* 20, */
	"0010111",		/* 21, */
	"0000011",		/* 22, */
	"0000100",		/* 23, */
	"0101000",		/* 24, */
	"0101011",		/* 25, */
	"0010011",		/* 26, */
	"0100100",		/* 27, */
	"0011000",		/* 28, */
	"00000010",		/* 29, */
	"00000011",		/* 30, */
	"00011010",		/* 31, */
	"00011011",		/* 32, */
	"00010010",		/* 33, */
	"00010011",		/* 34, */
	"00010100",		/* 35, */
	"00010101",		/* 36, */
	"00010110",		/* 37, */
	"00010111",		/* 38, */
	"00101000",		/* 39, */
	"00101001",		/* 40, */
	"00101010",		/* 41, */
	"00101011",		/* 42, */
	"00101100",		/* 43, */
	"00101101",		/* 44, */
	"00000100",		/* 45, */
	"00000101",		/* 46, */
	"00001010",		/* 47, */
	"00001011",		/* 48, */
	"01010010",		/* 49, */
	"01010011",		/* 50, */
	"01010100",		/* 51, */
	"01010101",		/* 52, */
	"00100100",		/* 53, */
	"00100101",		/* 54, */
	"01011000",		/* 55, */
	"01011001",		/* 56, */
	"01011010",		/* 57, */
	"01011011",		/* 58, */
	"01001010",		/* 59, */
	"01001011",		/* 60, */
	"00110010",		/* 61, */
	"00110011",		/* 62, */
	"00110100",		/* 63  */
	EOLSTRING,		/* EOL */
	"11011",		/* 64, */
	"10010",		/* 128, */
	"010111",		/* 192, */
	"0110111",		/* 256, */
	"00110110",		/* 320, */
	"00110111",		/* 384, */
	"01100100",		/* 448, */
	"01100101",		/* 512, */
	"01101000",		/* 576, */
	"01100111",		/* 640, */
	"011001100",		/* 704, */
	"011001101",		/* 768, */
	"011010010",		/* 832, */
	"011010011",		/* 896, */
	"011010100",		/* 960, */
	"011010101",		/* 1024, */
	"011010110",		/* 1088, */
	"011010111",		/* 1152, */
	"011011000",		/* 1216, */
	"011011001",		/* 1280, */
	"011011010",		/* 1344, */
	"011011011",		/* 1408, */
	"010011000",		/* 1472, */
	"010011001",		/* 1536, */
	"010011010",		/* 1600, */
	"011000",		/* 1664, */
	"010011011",		/* 1728  */
				/* extended length: */
	"00000001000",		/* 1792, */
	"00000001100",		/* 1856, */
	"00000001101",		/* 1920, */
	"000000010010",		/* 1984, */
	"000000010011",		/* 2048, */
	"000000010100",		/* 2112, */
	"000000010101",		/* 2176, */
	"000000010110",		/* 2240, */
	"000000010111",		/* 2304, */
	"000000011100",		/* 2368, */
	"000000011101",		/* 2432, */
	"000000011110",		/* 2496, */
	"000000011111",		/* 2560  */
	NULL			/* are there codes beyond 2560? */
	};
/* no. bits in the codes in the above table */
  static short bitcwht[] = {
	8,6,4,4,4,4,4,4,5,5,		/*  0 -  9 */
	5,5,6,6,6,6,6,6,7,7,		/* 10 - 19 */
	7,7,7,7,7,7,7,7,7,8,		/* 20 - 29 */
	8,8,8,8,8,8,8,8,8,8,		/* 30 - 39 */
	8,8,8,8,8,8,8,8,8,8,		/* 40 - 49 */
	8,8,8,8,8,8,8,8,8,8,		/* 50 - 59 */
	8,8,8,8,			/* 60 - 63 */
	12,				/* EOL */
	5,5,				/* 64,128 */
	6,				/* 192 */
	7,				/* 256 */
	8,8,8,8,8,8,			/* 320 - 640 */
	9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,	/* 704 - 1600 */
	6,				/* 1664 */
	9,				/* 1728 */
	11,11,11,			/* 1792,1856,1920 */
	12,12,12,12,12,12,12,12,12,12,	/* 1984 - 2560 */
	/* for codes over 2560 */
	14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
	-1
	};

/* 2-D codes (indices into code2d[] table) */
#define i2D_V0 0
#define i2D_VR1 1
#define i2D_VR2 2
#define i2D_VR3 3
#define i2D_VL1 4
#define i2D_VL2 5
#define i2D_VL3 6
#define i2D_PASS 7
#define i2D_HORIZ 8
#define i2D_EOL 9

  static char *code2d[] = {
	"1",			/* V0 */
	"011",			/* VR1 */
	"000011",		/* VR2 */
	"0000011",		/* VR3 */
	"010",			/* VL1 */
	"000010",		/* VL2 */
	"0000010",		/* VL3 */
	"0001",			/* PASS */
	"001",			/* HORIZ */
	EOLSTRING,		/* EOL */
	NULL };
  static short bitc2d[] = { 1,3,6,7,3,6,7,4,3,12 };

#define EOL0STRING	"0000000000010"
#define EOL1STRING	"0000000000011"
#define EOFB		"000000000001000000000001"

  static char *spare1d[] = {
	"000000001",		/* 0, */
	"0000000001",		/* 0, */
	"00000000001",		/* 0  */
	NULL };
  static char *spare2d[] = {
	"0000001",		/* 0, */
	"00000001",		/* 0, */
	"000000001",		/* 0, */
	"0000000001",		/* 0, */
	"00000000001",		/* 0  */
	NULL };

/* State-transition table for decoding CCITT G3-1 */

/* bit colors; also, starting index in table of 1-D codes*/
#define DST_color short
#define DST_white 0
#define DST_black 1

#define flip_color(c) ((c)? 0: 1)

#define DST_2d 2	/* starting index in table of 2-D codes */

#define DST_state short	/* state-id: index into DST_tbl.e[] */
#define DST_state_NULL (-1)
#define DST_state_ERROR (-2)

#define DST_action int
#define DST_action_NULL (-1)
#define DST_action_ERROR (-2)

/* transition in finite-state machine */
typedef struct DST_transit {
	DST_action a;	/* action to perform */
	DST_state s;	/* next state */
	} DST_transit;
typedef struct DST_entry {
	char p[MAXCODELEN+1];	/* code prefix so far (in ASCII) */
	short l;		/* strlen(.p) */
	short z;		/* no. of trailing "0"'s in .p */
	DST_transit t[2];	/* two transitions: on 0 & 1 */
	} DST_entry;
typedef struct DST_table {
	int mny;	/* no. entries so far */
	DST_entry *e;	/* array in malloc space:
				e[DST_white] starts white 1-D codes;
				e[DST_black] starts black 1-D codes;
				e[DST_2d] starts 2-D codes */
	} DST_table;
typedef struct DST_context {
	DST_color c;	/* current run-color */
	int l;		/* length of current code in bits: 0..(len-1) */
	DST_table *t;	/* table */
	DST_state s;	/* current state */
	DST_transit tr;	/* current state/action */
	} DST_context;


DST_table *ccitt_table();
RLE_Line *g31_to_rlel();
int rlel_to_g31();
RLE_Line *g32_to_rlel();
int rlel_to_g32();
RLE_Line *g4_to_rlel();
int rlel_to_g4();
0707070035351137061006640007620000050000010261170476773366600000600000010272CPU.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/*     T. Thompson - ATT-BL HO - portable versions     */
/*     C. Macey - ATT-DSG LZ - portable versions       */

/* Specify the environment:  CPU, OS, graphics, etc.
   This is an attempt to maintain a single master source tailorable at compile
   time, while encapsulating as many as possible of the required #if's and
   #ifdef's in this one file.
   OS-dependent #includes are triggered by these prior statements:
	#define LIBC_INCL 1		-- strcpy(), etc
	#define VALUES_INCL 1		-- math constants (PI etc)
	#define FILE_TREE_INCL 1	-- UNIX file-tree walking
   */

/* CPUs with some support: */
#define VAX 0
#define CRAY 1
#define SUN 2		/* including SPARC */
#define ATT3B 3
#define I386 4
#define MIPS 5		/* including SGI */

/*** Select CPU here: */
#define CPU VAX


/* Operating systems with some support: */
#define V9_OS 1		/* ATT-BL research UNIX, 9th edition */
#define SV_OS 2		/* ATT UNIX System V */
#define SUN_OS	3	/* Sun OS 4.x */

/*** Select OS here: */
#define OS V9_OS


/* Graphics display environments with some support: */
#define NO_GRAPHICS 0	/* defeat all graphics */
#define Y_GRAPHICS 1	/* the Y graphics interface (used in 1127 for Metheus) */
#define SUN_GRAPHICS 2	/* Tim Thompson's Sun interface */
#define X_GRAPHICS 3    /* Mark Tuomenoksa's X interface */

/*** Select graphics environment here: */
#define GRAPHICS Y_GRAPHICS


/* OCR installation directory */
#ifndef OCRDIR
#define OCRDIR "/usr/ocr"
#endif

/*** Miscellaneous arcane options:  best left alone **/

#define FILE_TREE (1)		/* set to zero to defeat UNIX file tree code */


/*** END OF SELECTIONS ** The rest of this file merely implements their effects */

/* define byte ordering in CPU */

#if CPU == SUN || CPU == MIPS
#define BIG_ENDIAN 1
#endif

/* deal with compilers that don't like (void *) */

#if CPU == MIPS
#define VOID char
#else
#define VOID void
#endif

/* include libc functions defs, if necessary */

#if LIBC_INCL

#if OS == V9_OS || CPU == CRAY
#include <libc.h>
#else
#if OS == SV_OS || OS == SUN_OS || CPU == MIPS
#include <string.h>
#endif
#endif

#endif

/* include values */

#if VALUES_INCL
#include <values.h>
#endif

/* UNIX file-tree-walk includes */

#if FILE_TREE_INCL

#if CPU==VAX || CPU==CRAY || CPU==MIPS
#include <sys/types.h>
#include <sys/stat.h>
#include <ftw.h>
#else
#if CPU==SUN || CPU==I386
#include <sys/types.h>
#include <sys/stat.h>
#include "myftw.h"  /* T. Thompson's version */
#endif
#endif

#endif

#if CPU==SUN||CPU==ATT3B||CPU==MIPS||CPU==I386
#define sgn(V) (((V)>0)? 1: (((V)<0)? -1: 0))
#endif 

#if CPU==SUN||CPU==ATT3B||CPU==MIPS
/* These are all big-endian machines */
#define swapshortin(x) (((x)<<8)&0xff00)|(((x)>>8)&0xff)
#define swapintin(x) \
		((((x)<<24)&0xff000000)| \
		 (((x)<<8) &0x00ff0000)| \
		 (((x)>>8) &0x0000ff00)| \
		 (((x)>>24)&0x000000ff))
/* The order of bytes in an int */
#define INDEX0 3
#define INDEX1 2
#define INDEX2 1
#define INDEX3 0
/* disable fast trick for picking out a short from an int */
#define USESHIFT	/* cf. skewlib.c */
#else
#define swapshortin(x) (x)
#define swapintin(x) (x)
#define INDEX0 0
#define INDEX1 1
#define INDEX2 2
#define INDEX3 3
#endif

/* global max no. classes -- gradually being made dynamic everywhere */
#if CPU==SUN
#define MAX_CL 128
#else
#define MAX_CL 3200	/* adequate for JIS Level 1 */
#endif

/* include char types (is this really necessary?) */

#if CTYPE_INCL

#if CPU == SUN
#include <string.h>
#else
#include <ctype.h>
#endif

#endif

/* includes for atan2 special configurations */

#if ATAN_INCL

#if CPU == CRAY
#define use_fast_atan2 F
#include "CRAY.h"
#else
#define use_fast_atan2 T
#endif

#endif

/* regular expression includes (fix to use standard regexp?) */

#if REGEXP_INCL

#if OS == V9_OS
#include <regexp.h>
#else
#include "regexp.h"
#endif

#endif

/* Use of the graphics display */

#if CPU != CRAY
#define SHOW_GRAPHICS 1
#endif

#ifndef PI
#define PI 3.14159265358979323846
#endif
0707070035351137071006640007620000050000010261230476773366600001000000027244Coord.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/*     T. J. Thompson - ATT-BL HO - improvements       */

/* Coord.c - function bodies for basic Coordinate geometry.
   See Coord.h for associated defines, typedefs, etc.
   */

#include <stdio.h>
#include <math.h>
#include <string.h>
#define ATAN_INCL 1
#include "CPU.h"
#include "boole.h"
#include "Units.h"
#include "Coord.h"

/* Added by Tim Thompson ... */
int Readvax = 0;

VOID
setreadvax()
{
	char *getenv();
	char *p = getenv("READVAX");
	/* any non-null value of READVAX will set it */
	if ( p!=NULL && strlen(p)>0 )
		Readvax = 1;
}

/* ... */

/* Convert a real value, a units specification, and a resolution
   into a value in scanner coordinates. */
int vto_scoor(v,u,r)
    double v;	/* value in special units */
    char u;	/* units: one of UNITS (see ric.h) */
    int r;	/* resolution in pixels/inch */
{   int c;
	switch(u) {
	    case 'i':	/* inches */
		c = (int)(v*r + 0.5);
		break;
	    case 'c':	/* cm */
		c = (int)((v*r/2.54) + 0.5);
		break;
	    case 'p':	/* points */
		c = (int)((v*INCHES_PER_POINT*r) + 0.5);
		break;
	    case 'P':	/* picas */
		c = (int)((v*12.0*INCHES_PER_POINT*r) + 0.5);
		break;
	    case 's':	/* scanner pixel (Scoor) */
	    case 'u':	/* basic unit */
		c = (int)(v + 0.5);
		break;
	    default:
		c = (int)(v + 0.5);
		break;
	    };
	return(c);
	}

/* Return pointer to empty Sp from malloc space */
Sp *alloc_sp()
{   Sp *spp;
	if((spp=(Sp *)malloc(sizeof(Sp)))==NULL)
		abort("alloc_sp: can't");
	*spp = zero_Sp;
	return(spp);
	}

/* Free Sp from malloc space */
free_sp(spp)
    Sp *spp;
{	free(spp);
	}

Sp *ato_sp(s)
    char *s;
{   char *d;
    static Sp p;
    char *p_x,*p_y;
#define SP_DELIM "(), "
	d = strdup(s);
	p_x = strtok(d,SP_DELIM);
	p_y = strtok((char *)0,SP_DELIM);
	if(p_x==NULL||p_y==NULL)
		{free(d); return(NULL);};
	p.x = atoi(p_x);
	p.y = atoi(p_y);
	free(d);
	return(&p);
	}

char *sp_toa(sp)
    Sp *sp;
#define sp_toa_distinct (5)
{   static char s[sp_toa_distinct][40];
    static int sp_toa_cur = -1;
	sp_toa_cur = (sp_toa_cur+1)%sp_toa_distinct;
	sprintf(s[sp_toa_cur],"(%d,%d)",sp->x,sp->y);
	return(s[sp_toa_cur]);
	}

/* Read a list of Sp's (in ascii) from file *fp, into set *spsp */
frda_sps(fp,spsp)
    FILE *fp;
    Sps *spsp;
#define MAX_SPS_LINE (80)
{   Sp *spp,**bb;
    long seek;
    char line[MAX_SPS_LINE+1];
	*spsp = empty_Sps;
	seek = ftell(fp);
	/* count all points quickly, in advance */
	while(!feof(fp)) {
		line[0] = '\0';
		fgets(line,MAX_SPS_LINE,fp);
		if(strlen(line)>0) {
			spsp->mny++;
			};
		};
	if((spsp->pa=(Sp **)malloc((spsp->mny+1)*sizeof(Sp *)))==NULL)
		abort("frda_sps: can't alloc spsp->pa[%d]",spsp->mny+1);
	/* next, reread points */
	fseek(fp,(long)seek,0);
	bb=spsp->pa;
	while(!feof(fp)) {
		line[0] = '\0';
		fgets(line,MAX_SPS_LINE,fp);
		if(strlen(line)>0) {
			*(spp = alloc_sp()) = *ato_sp(line);
			*(bb++) = spp;
			};
		};
	*bb = NULL;
	}

err_sps(p)
    Sps *p;
{   int i;
    Sp **s;
	fprintf(stderr,"Sps: %d points: ",p->mny);
	if(p->mny>0) for(s=p->pa; (*s)!=NULL; s++) {
		fprintf(stderr,"%s ",sp_toa(*s));
		};
	fprintf(stderr,"\n");
	}

Sp *append_sp_sps(sp,sps)
   Sp *sp;
   Sps *sps;
{	if(sps->mny>0) {
		if((sps->pa=(Sp **)realloc(sps->pa,(sps->mny+2)*sizeof(Sp *)))==NULL)
			abort("append_sp_sps: can't realloc sps->pa[%d]",sps->mny+2);
		}
	else {	sps->mny=0;
		if((sps->pa=(Sp **)malloc((sps->mny+2)*sizeof(Sp *)))==NULL)
			abort("append_sp_sps: can't alloc sps->pa[%d]",sps->mny+2);
		};
	sps->pa[sps->mny++] = sp;
	sps->pa[sps->mny] = NULL;
	}

/* Return pointer to local static Sps which holds a duplicate of the
   given Sps (all contents are freshly malloc'ed) */
Sps *dup_sps(old)
    Sps *old;
{   static Sps new;
    Sp **o,**n;
	if(old->mny>0) {
		new.mny = old->mny;
		if((new.pa=(Sp **)malloc((new.mny+1)*sizeof(Sp *)))==NULL)
			abort("dup_sps: can't alloc new.pa[%d]",new.mny+1);
		for(o=old->pa,n=new.pa; *o!=NULL; o++,n++) {
			*(*n = alloc_sp()) = **o;
			};
		*n = NULL;
		}
	else new = empty_Sps;
	return(&new);
	}

free_sps(p)
   Sps *p;
{	if(p->pa!=NULL) free(p->pa);
	*p = empty_Sps;
	}

Sp *append_sp_spa(sp,spa)
   Sp *sp;
   Spa *spa;
{	if(spa->mny>0) {
		if((spa->a=(Sp *)realloc(spa->a,(spa->mny+1)*sizeof(Sp)))==NULL)
			abort("append_sp_spa: can't alloc spa->a[%d]",spa->mny+1);
		}
	else {	spa->mny=0;
		if((spa->a=(Sp *)malloc((spa->mny+1)*sizeof(Sp)))==NULL)
			abort("append_sp_spa: can't alloc spa->a[%d]",spa->mny+1);
		};
	spa->a[spa->mny++] = *sp;
	}

err_spa(p)
    Spa *p;
{   int i;
    Sp *sp;
	fprintf(stderr,"Spa: %d points: ",p->mny);
	for(i=0,sp=p->a;i<p->mny;i++,sp++) {
		fprintf(stderr,"%s ",sp_toa(sp));
		};
	fprintf(stderr,"\n");
	}

free_spa(p)
   Spa *p;
{	if(p->a!=NULL) free(p->a);
	*p = empty_Spa;
	}

/* Rotate the Scanner point `(x,y') about origin `*orp' by angle `ang',
   and return pointer to the result.  This is slow, but no matter. */
Sp *rotate_Sp(ang,orp,x,y)
    double ang;
    Sp *orp;
    int x,y;
{   static Sp res;
    Sp of;
	of.x = x - orp->x;  of.y = y - orp->y;
	res.x = (short)(((cos(ang)*of.x - sin(ang)*of.y)) + orp->x + 0.5);
	res.y = (short)(((sin(ang)*of.x + cos(ang)*of.y)) + orp->y + 0.5);
	return(&res);
	}

/* Horizontally shear the Scanner point `(x,y') about origin `*orp' by shear
   angle `ang', and return pointer to the result.  `Ang' is close to 90 degrees.
   This is slow, but no matter. */
Sp *hshear_Sp(ang,orp,x,y)
    double ang;
    Sp *orp;
    int x,y;
{   static Sp res;
    Scoor of_y,tr_x;
	res.x = (short)(orp->x - (y - orp->y)*tan(ang-(90.0*DtoR)) + 0.5);
	res.y = orp->y;
	return(&res);
	}

/* Return pointer to initialized Edge from malloc space */
Edge *alloc_edge()
{   Edge *ep;
	if((ep=(Edge *)malloc(sizeof(Edge)))==NULL)
		abort("alloc_edge: can't");
	*ep = empty_Edge;
	return(ep);
	}

/* Free Edge from malloc space */
free_edge(ep)
    Edge *ep;
{	free(ep);
	}

char *edge_toa(ep)
	Edge *ep;
{   static char s[40];
	strcpy(s,sp_toa(&(ep->a)));
	strcat(s,"-");
	strcat(s,sp_toa(&(ep->b)));
	return(s);
	}

Edge *ato_edge(s)
    char *s;
{   char *d;
    static Edge e;
    char *a_x,*a_y,*b_x,*b_y;
#define EDGE_DELIM "(),- "
	d = strdup(s);
	a_x = strtok(d,EDGE_DELIM);
	a_y = strtok((char *)0,EDGE_DELIM);
	b_x = strtok((char *)0,EDGE_DELIM);
	b_y = strtok((char *)0,EDGE_DELIM);
	if(a_x==NULL||a_y==NULL||b_x==NULL||b_y==NULL)
		{free(d); return(NULL);};
	e.a.x = atoi(a_x);
	e.a.y = atoi(a_y);
	e.b.x = atoi(b_x);
	e.b.y = atoi(b_y);
	free(d);
	return(&e);
	}

/* Return pointer to empty Bbx from malloc space */
Bbx *alloc_bbx()
{   Bbx *bxp;
	if((bxp=(Bbx *)malloc(sizeof(Bbx)))==NULL)
		abort("alloc_bbx: can't");
	*bxp = empty_Bbx;
	return(bxp);
	}

/* Free Bbx from malloc space */
free_bbx(bxp)
    Bbx *bxp;
{	free(bxp);
	}

char *bbx_toa(bxp)
	Bbx *bxp;
{   static char s[40];
	strcpy(s,sp_toa(&(bxp->a)));
	strcat(s,sp_toa(&(bxp->b)));
	return(s);
	}

Bbx *ato_bbx(s)
    char *s;
{   char *d;
    static Bbx bx;
    char *a_x,*a_y,*b_x,*b_y;
#define BBX_DELIM "(), "
	d = strdup(s);
	a_x = strtok(d,BBX_DELIM);
	a_y = strtok((char *)0,BBX_DELIM);
	b_x = strtok((char *)0,BBX_DELIM);
	b_y = strtok((char *)0,BBX_DELIM);
	if(a_x==NULL||a_y==NULL||b_x==NULL||b_y==NULL)
		{free(d); return(NULL);};
	bx.a.x = atoi(a_x);
	bx.a.y = atoi(a_y);
	bx.b.x = atoi(b_x);
	bx.b.y = atoi(b_y);
	free(d);
	return(&bx);
	}

Bbx *expand_bbx(bxp,X)
    Bbx *bxp;
    int X;		/* expansion code */
{   static Bbx xbx;
	xbx = *bxp;
	switch(X) {
	    case -3:
		xbx.a.x += 2;
		xbx.a.y += 2;
		xbx.b.x -= 1;
		xbx.b.y -= 1;
		break;
	    case -2:
		xbx.a.x += 1;
		xbx.a.y += 1;
		xbx.b.x -= 1;
		xbx.b.y -= 1;
		break;
	    case -1:
		xbx.a.x += 1;
		xbx.a.y += 1;
		break;
	    case 0:
		break;
	    case 1:
		xbx.b.x += 1;
		xbx.b.y += 1;
		break;
	    case 2:
		xbx.a.x -= 1;
		xbx.a.y -= 1;
		xbx.b.x += 1;
		xbx.b.y += 1;
		break;
	    case 3:
		xbx.a.x -= 1;
		xbx.a.y -= 1;
		xbx.b.x += 2;
		xbx.b.y += 2;
		break;
	    default:
		break;
	    };
	return(&xbx);
	}

/* Predicate:  Is most of Bbx 1 inside Bbx 2?  ``Most'' is defined
   as more than half of the first Bbx's area inside BBx 2.*/
boolean bbx_inside_most(b1,b2)
    Bbx *b1,*b2;
{   struct {		/* overlap between blob box and selection box */
	Bbx bx;		/* Bbx of intersection */
	Sp sd;		/* side-lengths of overlap box, >=0 */
	long area;	/* area is square pixels, >=0 */
	} ov;
	if(!bbx_inside_any(b1,b2)) return(F);
	else if(bbx_inside_all(b1,b2)) return(T);
	else {	/* compute overlap box */
		ov.bx.a.x = ((b1)->a.x>(b2)->a.x)? (b1)->a.x: (b2)->a.x;
		ov.bx.a.y = ((b1)->a.y>(b2)->a.y)? (b1)->a.y: (b2)->a.y;
		ov.bx.b.x = ((b1)->b.x<(b2)->b.x)? (b1)->b.x: (b2)->b.x;
		ov.bx.b.y = ((b1)->b.y<(b2)->b.y)? (b1)->b.y: (b2)->b.y;
		ov.sd.x = bbx_wid(&ov.bx);  if(ov.sd.x<0) ov.sd.x=0;
		ov.sd.y = bbx_hgt(&ov.bx);  if(ov.sd.y<0) ov.sd.y=0;
		ov.area = ov.sd.x*ov.sd.y;
		return( (ov.area>0) && ( 2*ov.area > bbx_area(b1) ) );
		};
	}

Bbx *translate_bbx(bxp,off)
    Bbx *bxp;
    Sp off;
{   static Bbx res;
	res.a.x = bxp->a.x + off.x;
	res.a.y = bxp->a.y + off.y;
	res.b.x = bxp->b.x + off.x;
	res.b.y = bxp->b.y + off.y;
	return(&res);
	}

/* Free Bbxs (but not the contents) */
free_bbxs(bxsp)
    Bbxs *bxsp;
{   Bbx **b;
	if(bxsp->mny>0) {
		if(bxsp->pa!=NULL) free(bxsp->pa);
		};
	*bxsp = empty_Bbxs;
	}

/* Free Bbxs (and the individually-malloc'ed contents) */
free_bbxs_etc(bxsp)
    Bbxs *bxsp;
{   Bbx **b;
	if(bxsp->mny>0) {
		for(b=bxsp->pa; (*b)!=NULL; b++) free(*b);
		if(bxsp->pa!=NULL) free(bxsp->pa);
		};
	*bxsp = empty_Bbxs;
	}

/* Return pointer to local static Bbxs which holds a duplicate of the
   given Bbxs (all contents are freshly malloc'ed) */
Bbxs *dup_bbxs(old)
    Bbxs *old;
{   static Bbxs new;
    Bbx **o,**n;
	if(old->mny>0) {
		new.mny = old->mny;
		new.alloc = old->alloc;
		new.incr = old->incr;
		if((new.pa=(Bbx **)malloc((new.alloc)*sizeof(Bbx *)))==NULL)
			abort("dup_bbxs: can't alloc new.pa[%d]",new.alloc);
		for(o=old->pa,n=new.pa; *o!=NULL; o++,n++) {
			*(*n = alloc_bbx()) = **o;
			};
		*n = NULL;
		}
	else new = empty_Bbxs;
	return(&new);
	}

Bbx *append_bbx(bxp,bxsp)
   Bbx *bxp;
   Bbxs *bxsp;
{	if(bxsp->mny>0) {
		if((bxsp->mny+2)>bxsp->alloc) {
			bxsp->alloc += bxsp->incr;
			if( ( bxsp->pa =
			      (Bbx **)realloc(bxsp->pa,bxsp->alloc*sizeof(Bbx *)) )
			    ==NULL )
				abort("append_bbx: can't alloc bxsp->pa[%d]",bxsp->alloc);
			};
		}
	else {	bxsp->mny=0;
		if(bxsp->pa!=NULL) free(bxsp->pa);
		bxsp->alloc=0;
		while((bxsp->mny+2)>bxsp->alloc) bxsp->alloc += bxsp->incr;
		if((bxsp->pa=(Bbx **)malloc(bxsp->alloc*sizeof(Bbx *)))==NULL)
			abort("append_bbx: can't alloc bxsp->a[%d]",bxsp->alloc);
		};
	bxsp->pa[bxsp->mny++] = bxp;
	bxsp->pa[bxsp->mny] = NULL;
	}

frda_bbxs(fp,bxsp)
    FILE *fp;
    Bbxs *bxsp;
#define MAX_BBX_LINE (80)
{   Bbx *bxp,**bb;
    long seek;
    char line[MAX_BBX_LINE+1];
	*bxsp = empty_Bbxs;
	seek = ftell(fp);
	/* count all boxes quickly, in advance */
	while(!feof(fp)) {
		line[0] = '\0';
		fgets(line,MAX_BBX_LINE,fp);
		if(strlen(line)>0) {
			bxsp->mny++;
			};
		};
	if((bxsp->pa=(Bbx **)malloc((bxsp->mny+1)*sizeof(Bbx *)))==NULL)
		abort("frda_bbxs: can't alloc bxsp->pa[%d]",bxsp->mny+1);
	bxsp->alloc = bxsp->mny+1;
	/* next, reread boxes */
	fseek(fp,(long)seek,0);
	bb=bxsp->pa;
	while(!feof(fp)) {
		line[0] = '\0';
		fgets(line,MAX_BBX_LINE,fp);
		if(strlen(line)>0) {
			*(bxp = alloc_bbx()) = *ato_bbx(line);
			*(bb++) = bxp;
			};
		};
	*bb = NULL;
	}

fwra_bbxs(fp,bxsp)
    FILE *fp;
    Bbxs *bxsp;
{   Bbx **b;
	if(bxsp->mny>0) for(b=bxsp->pa; *b!=NULL; b++) {
		fputs(bbx_toa(*b),fp);
		fputs("\n",fp);
		};
	fflush(fp);
	}
0707070035351137101006640007620000050000010261240476773366600001000000017772Coord.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* Coord.h - defines, typedefs, Inits, empties, and function declarations
   for basic Coordinate geometry data items.
   See Coord.c for associated functions.
   */

/* Round signed floating-pt no. F:
   (a) ROUND - to nearest integer;
   (b) ROUND_UP - up to next int;
   (c) ROUND_DN - down to prior int.
   Evaluates the argument exactly once. */
static double _round,_round_up,_round_dn;
#define ROUND(F) ((int)(((_round=(F))>=0.0)? _round+0.5: _round-0.5))
#define ROUND_UP(F) ((int)(((_round_up=(F))>=0.0)? _round_up+0.999999: _round_up))
#define ROUND_DN(F) ((int)(((_round_dn=(F))>=0.0)? _round_dn: _round_dn-0.999999))

/* The basic unit is the scanner pixel, located in the X,Y plane.  As in many
   graphics coordinate systems, X increases left-to-right, while Y increases
   top-down.  Pixel coordinates are usually integer values.  The physical extent
   of integer coordinate `x' along the real X-axis is the half-open interval
   [x,x+1), and similarly for Y.  The actual digitizing resolution (e.g.
   pixels/inch) represented can vary from document to document, and is almost
   always known to the algorithms.  X & Y resolution can be different, though
   for simplicity of discussion we will usually assume that they are equal,
   i.e. that pixels are square.  Thus pixel (x,y) may be thought of as the region
   [x,x+1)X[y,y+1) in the real plane.
	Half-pixel resolution is also supported, with its own data types for
   clarity.  However, to avoid distracting struggles with the type system, they
   are for the most part #defined to be identical to ordinary coordinates.  The
   principle effect is that the limits of scanner coordinates have been halved
   to allow for safe use of half-pixels everywhere.  (This still permits images
   80 inches square at 400 pixels/inch, assuming `short' is at least 16-bit 2's
   complement.)
	Half-pixel coordinates can also be used to describe boundaries of regions,
   as a set of ideal point locations at the corners and edge midpoints of pixels.
   The half-pixel data type is used; boundary points are identified by flags
   in the Bdy "boundary" structure, and may be displayed differently.   */

#define Scoor short	/* Scanner pixel coordinate value */
#define Hcoor Scoor	/* Half-pixel coordinate value */
#define Bcoor Hcoor	/* Half-pixel boundary coordinate value */

/* Each Scoor value `v' is associated of course with two Hcoor values `a' < `b'.
   Conventionally, the physical extent of the `a' half-coordinate is the real
   interval [v,v+0.5), and `b' is [v+0.5,v+1). */
#define StoHa(S) ((S)*2)
#define StoHb(S) ((S)*2+1)
#define HtoS(H) ((H)/2)

/* The 3 half-pixel boundary points of a pixel coordinate `C' are: */
#define StoBa(S) (StoHa((S)))		/* minimum of interval */
#define StoBb(S) (StoHb((S)))		/* midpoint of interval */
#define StoBc(S) (StoHa((S)+1))		/* maximum of interval */

#define Scoor_MIN (SHRT_MIN/2)	/* minimum possible value */
#define Scoor_MAX (SHRT_MAX/2)	/* maximum possible value */

#define Hcoor_MIN (SHRT_MIN)	/* minimum possible value */
#define Hcoor_MAX (SHRT_MAX)	/* maximum possible value */

#define fwri_Scoor(F,V) fwri_int2((F),(V))
#define frdi_Scoor(F) frdi_int2(F)

#define fwri_Hcoor(F,V) fwri_int2((F),(V))
#define frdi_Hcoor(F) frdi_int2(F)

#define fwri_Bcoor(F,V) fwri_int2((F),(V))
#define frdi_Bcoor(F) frdi_int2(F)

typedef struct Sp {	/* point: pixel address */
	Scoor x;	/* increases left-to-right: Scoor_MIN is left of image */
	Scoor y;	/* increases down:  Scoor_MIN is top of image */
	} Sp;
#define Hp Sp		/* Half-pixel point */

#define Init_Zero_Sp {0,0}
#define Init_Min_Sp {Scoor_MIN,Scoor_MIN}
#define Init_Max_Sp {Scoor_MAX,Scoor_MAX}

#if MAIN
Sp zero_Sp = Init_Zero_Sp;
#else
extern Sp zero_Sp;
#endif

#define fwri_Sp(F,P) { fwri_Scoor((F),(P)->x); fwri_Scoor((F),(P)->y); }
#define frdi_Sp(F,P) (feof(F)? 0: ( \
	(P)->x=frdi_Scoor(F), \
	(P)->y=frdi_Scoor(F), \
	(ferror(F)? -errno: 1) ) )

/* Is Sp *p1 exactly equal to Sp *p2? */
#define sp_eq(p1,p2) ( \
	((p1)->x == (p2)->x) \
    	 && ((p1)->y == (p2)->y) \
	)

typedef struct Sps {	/* Set of Points */
	int mny;	/* no. points (mny==0 ==> pa==NULL) */
	Sp **pa;	/* NULL-terminated Sp *pa[mny+1] (malloc space)*/
	} Sps;

#define Init_Sps {0,NULL}
#if MAIN
Sps empty_Sps = Init_Sps;
#else
extern Sps empty_Sps;
#endif

typedef struct Spa {	/* array of Points */
	int mny;	/* no. points in array */
	Sp *a;		/* Sp a[mny] (malloc space)*/
	} Spa;
/** #define Pointa Spa **/  /* OBSOLESCENT */

#define Init_Spa {0,NULL}
#if MAIN
Spa empty_Spa = Init_Spa;
#else
extern Spa empty_Spa;
#endif

/* An edge is an ordered pair of vertices. */
typedef struct Edge {
	Sp a,b;		/* endpoints */
	} Edge;

#define Init_Edge {Init_Zero_Sp,Init_Zero_Sp}
#if MAIN
Edge empty_Edge = Init_Edge;
#else
extern Edge empty_Edge;
#endif

#define fwri_Edge(F,P) { fwri_Sp((F),&((P)->a)); fwri_Sp((F),&((P)->b)); }
#define frdi_Edge(F,P) ( feof(F)? 0: ( \
	frdi_Sp(F,&((P)->a)), \
	frdi_Sp(F,&((P)->b)), \
	(ferror(F)? -errno: 1) ) )

/* A bounding box is a rectangle */
typedef struct {	/* bounding box: inclusive of boundary values */
	Sp a;		/* top-left corner */
	Sp b;		/* bottom-right corner */
	} Bbx;

typedef struct DSp {	/* point: pixel address */
	double x;	/* increases down the page, MinScoor at top */
	double y;	/* increases across the page, MinScoor at left */
	} DSp;

#define Init_Bbx {Init_Max_Sp,Init_Min_Sp}
#define Init_Max_Bbx {Init_Min_Sp,Init_Max_Sp}
#if MAIN
Bbx empty_Bbx = Init_Bbx;
Bbx max_Bbx = Init_Max_Bbx;
#else
extern Bbx empty_Bbx;
extern Bbx max_Bbx;
#endif

#define fwri_Bbx(F,P) { fwri_Sp((F),&((P)->a)); fwri_Sp((F),&((P)->b)); }
#define frdi_Bbx(F,P) ( feof(F)? 0: ( \
	frdi_Sp(F,&((P)->a)), \
	frdi_Sp(F,&((P)->b)), \
	(ferror(F)? -errno: 1) ) )

/* OBSOLESCENT: */
#if MAIN
Bbx null_Bbx = {Init_Max_Sp,Init_Min_Sp};
#else
extern Bbx null_Bbx;
#endif

/* height, width, area of Bbx in pixels */
#define bbx_hgt(bxp) ((bxp)->b.y-(bxp)->a.y+1)
#define bbx_wid(bxp) ((bxp)->b.x-(bxp)->a.x+1)
#define bbx_area(bxp) (bbx_hgt((bxp))*bbx_wid((bxp)))

/* Is Bbx *b1 exactly equal to Bbx *b2? */
#define bbx_eq(b1,b2) ( \
	((b1)->a.x == (b2)->a.x) \
    	 && ((b1)->a.y == (b2)->a.y) \
    	 && ((b1)->b.x == (b2)->b.x) \
    	 && ((b1)->b.y == (b2)->b.y) \
	)

/* Is Bbx *b1 wholly inside Bbx *b2? */
#define bbx_inside_all(b1,b2) ( \
	((b1)->a.x >= (b2)->a.x) \
    	 && ((b1)->a.y >= (b2)->a.y) \
    	 && ((b1)->b.x <= (b2)->b.x) \
    	 && ((b1)->b.y <= (b2)->b.y) \
	)

/* Is any of Bbx *b1 inside Bbx *b2? */
#define bbx_inside_any(b1,b2) ( \
	((b1)->a.x <= (b2)->b.x) \
	&& ((b1)->a.y <= (b2)->b.y) \
	&& ((b1)->b.x >= (b2)->a.x) \
	&& ((b1)->b.y >= (b2)->a.y) \
	)

typedef struct Bbxs {	/* A set of Bbxs */
	int mny;	/* if mny==0, then pa==NULL */
	Bbx **pa;	/* NULL-terminated array (in malloc space) of `mny+1'
			   pointers to Bbxs (in malloc space) */
	int alloc;	/* no. slots in pa[] actually allocated (>=mny+1) */
	int incr;	/* no. slots in pa[] to reallocate at a time */
	} Bbxs;

#define Init_Bbxs {0,NULL,0,512}
#if MAIN
Bbxs empty_Bbxs = Init_Bbxs;
#else
extern Bbxs empty_Bbxs;
#endif

Sp *alloc_sp();
free_sp();
char *sp_toa();		/* Sp to ascii printable string */
Sp *ato_sp();		/* Sp from ascii printable string */
frda_sps();
Sps *dup_sps();
Sp *append_sp_sps();
Sp *append_sp_spa();
Sp *rotate_Sp();	/* rotate Sp about given fixed-point */
Sp *hshear_Sp();	/* horiz-shear Sp about given fixed-point */
Edge *alloc_edge();
free_edge();
char *edge_toa();	/* Edge to ascii printable string */
Edge *ato_edge();	/* Edge from ascii printable string */
Bbx *alloc_bbx();
Bbx *append_bbx();
Bbxs *dup_bbxs();
char *bbx_toa();	/* Bbx to ascii printable string */
Bbx *ato_bbx();		/* Bbx from ascii printable string */
Bbx *translate_bbx();
boolean bbx_inside_most();	/* Is Bbx 1 mostly inside Bbx 2? */
Bbx *expand_bbx();
0707070035351137111006640007620000050000010261300476773366600000700000016417Path.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* Path.c - Path functions */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#define FILE_TREE_INCL 1
#include "CPU.h"
#include "Path.h"

#define dbg_FTW (0)

/* Return full path string in Path *pp, starting at level `sl';
   if the level is too deep or the name at level `sl' is null, return null string.
   */
char *path_toa(pp,sl)
    Path *pp;
    int sl;	/* starting level: 0 is first */
{   int len,lvl;
    static char s[MAX_PATH_DEPTH*(32)];
	s[0] = '\0';
	if( sl<=pp->level && pp->name[sl]!=NULL && pp->name[sl][0]!='\0' ) {
		for(lvl=sl; lvl<=pp->level; lvl++) {
			strcat(s,pp->name[lvl]);
			strcat(s,"/");
			};
		};
	if((len=strlen(s))>0) s[len-1] = '\0';
	return(s);
	}

/* no. slashes in a name */
int slashes(n)
    char *n;
{   register int res;
    register char *c;
	res=0;
	c=n;
	while(*c!='\0') {
		if(*c=='/') res++;
		c++;
		};
	return(res);
	}

/* basename */
char *bname(n)
    char *n;
{   register char *res,*c;
	res=n-1;
	c=n;
	while(*c!='\0') {
		if(*c=='/') res=c;
		c++;
		};
	return(res+1);
	}

#if CPU==VAX || CPU==CRAY

int process_file_tree_node(n,s,code,S)
    char *n;
    struct stat *s;
    int code;
    struct FTW *S;
/* Uses global `path_process' structure */
{   char *out_n;
    int persist;
    struct stat sbuf;
	switch(code) {
	   case FTW_F:	if(dbg_FTW)err("visit file %s %s %d",n,n+(S->base),S->level);
			if(S->level>0) {
				if(path_process.path.name[S->level]!=NULL)
					free(path_process.path.name[S->level]);
				path_process.path.name[S->level]=strdup(n+(S->base));
				};
			path_process.path.level = S->level;
			out_n = strdup(path_toa(&path_process.path,0));
			if(dbg_FTW)err("file: %s ==> %s",n,out_n);
			(*path_process.process)(n,out_n,path_process.arg);
			if(out_n!=NULL) free(out_n);
			break;
	   case FTW_SL:	if(dbg_FTW)err("visit link %s %s %d",n,n+(S->base),S->level);
			S->quit = FTW_FOLLOW;	 /* follow symbolic link */
			break;
	   case FTW_D:	/* pre-visit of directory */
			if(dbg_FTW)err("visit dir %s %s %d",n,n+(S->base),S->level);
			if(S->level>0) {
				if(path_process.path.name[S->level]!=NULL)
					free(path_process.path.name[S->level]);
				path_process.path.name[S->level]=strdup(n+(S->base));
				};
			path_process.path.level = S->level;
			out_n = path_toa(&path_process.path,0);
			if(dbg_FTW)err("dir:   %s --> %s",n,out_n);
			if(out_n[0]=='\0') /* no output name */ break;
			/* ensure directory named out_n exists */
			if(stat(out_n,&sbuf)==0) {
				/* file exists */
				if(!(sbuf.st_mode&S_IFDIR)) {
					/* not a directory - try to remove */
					if(unlink(out_n)==0) {
						if(mkdir(out_n,0777)!=0) {
							/* irrecoverable mkdir */
							abort("can't mkdir %s",
								out_n);
							};
						}
					else {	/* irrecoverable unlink */
						abort("can't unlink %s",out_n);
						};
					};
				}
			else if(errno==ENOENT) {
				/* file doesn't exist */
				if(mkdir(out_n,0777)!=0) {
					/* irrecoverable mkdir */
					abort("can't mkdir %s",out_n);
					};
				}
			else {	/* irrecoverable stat */
				abort("can't stat %s",out_n);
				};
			break;
	   case FTW_DP:	/* post-visit of directory: ignore it*/
			break;
	   case FTW_DNR:
			err("can't read dir %s (FTW_DNR) - ignore it",n);
			break;
	   case FTW_NS:
			err("can't stat %s (FTW_NS) - ignore it",n);
			break;
	   case FTW_NSL:
			if(0)	/* happens if file is missing */
			err("can't stat symbolic link %s (FTW_NSL) - ignore it",n);
			break;
	   default:
			err("unexpected FTW code %d - ignore it",code);
			break;
	   };
	return(0);
	}

#else
#if CPU==MIPS
int process_file_tree_node(n,s,code)
    char *n;		/* name of the object */
    struct stat *s;	/* info. about object */
    int code;
/* Uses global `path_process' structure */
#define lvl path_process.path.level
{   char *out_n;
    int persist;
    struct stat sbuf;
    char *bn;
	lvl = slashes(n) - path_process.sl0;
	bn = bname(n);	
	switch(code) {
	   case FTW_F:	if(dbg_FTW) err("visit file %s, bn %s, lvl %d",n,bn,lvl);
			if(lvl>0) {
				if(path_process.path.name[lvl]!=NULL)
					free(path_process.path.name[lvl]);
				path_process.path.name[lvl]=strdup(bn);
				};
			out_n = strdup(path_toa(&path_process.path,0));
			if(dbg_FTW)err("file: %s ==> %s",n,out_n);
			(*path_process.process)(n,out_n,path_process.arg);
			if(out_n!=NULL) free(out_n);
			break;
	   case FTW_D:	/* pre-visit of directory */
			if(dbg_FTW) err("visit dir %s, bn %s, lvl %d",n,bn,lvl);
			if(lvl>0) {
				if(path_process.path.name[lvl]!=NULL)
					free(path_process.path.name[lvl]);
				path_process.path.name[lvl]=strdup(bn);
				};
			out_n = path_toa(&path_process.path,0);
			if(dbg_FTW)err("dir:  %s --> %s",n,out_n);
			if(out_n[0]=='\0') /* no output name */ break;
			/* ensure directory named out_n exists */
			if(stat(out_n,&sbuf)==0) {
				/* file exists */
				if(!(sbuf.st_mode&S_IFDIR)) {
					/* not a directory - try to remove */
					if(unlink(out_n)==0) {
						if(mkdir(out_n,0777)!=0) {
							/* irrecoverable mkdir */
							abort("can't mkdir %s",
								out_n);
							};
						}
					else {	/* irrecoverable unlink */
						abort("can't unlink %s",out_n);
						};
					};
				}
			else if(errno==ENOENT) {
				/* file doesn't exist */
				if(mkdir(out_n,0777)!=0) {
					/* irrecoverable mkdir */
					abort("can't mkdir %s",out_n);
					};
				}
			else {	/* irrecoverable stat */
				abort("can't stat %s",out_n);
				};
			break;
	   case FTW_DNR:
			err("can't read dir %s (FTW_DNR) - ignore it",n);
			break;
	   case FTW_NS:
			err("can't stat %s (FTW_NS) - ignore it",n);
			break;
	   default:
			err("unexpected FTW code %d - ignore it",code);
			break;
	   };
	return(0);
	}

#endif
#endif

/* Process every leaf file (non-directory) in the file-tree rooted at `in_ftn'.
   If `in_ftn' is itself a leaf, then only it is processed.  If it is a directory,
   then a corresponding file-tree is built, rooted at `out_ftn', and paths
   to its leaves created by `mkdir's as required;  for each pair of corresponding
   leaf filenames, `process' is called.  The filenames have not yet been opened.
   If `out_ftn' is the empty string, then no output file-tree will be generated
   and the corresponding output filenames will all be null.  If `in_ftn' is the
   empty string, then `process' is called only once, with the input filename
   empty.  Pass 'arg' to 'process' as third argument. */
process_file_trees(process,in_ftn,out_ftn,arg)
    VOID (*process)();
    char *in_ftn;	/* may be empty */
    char *out_ftn;	/* may be empty */
    VOID *arg;		/* passed to '(*process)()' as 3rd argument */
/* Uses global `path_process' structure */
{   int level;
	if(in_ftn[0]=='\0') (*process)(in_ftn,out_ftn,arg);
	else {	if(dbg_FTW) err("process_file_trees(%s,%s)",in_ftn,out_ftn);
		path_process.path.level = 0;
		path_process.path.name[0] = out_ftn;
		path_process.sl0 = slashes(in_ftn);
		for(level=1; level<MAX_PATH_DEPTH; level++)
			path_process.path.name[level] = NULL;
		path_process.process = process;
		path_process.arg = arg;
		if(ftw(in_ftn,process_file_tree_node,MAX_PATH_DEPTH)<0)
			err("ftw error: errno %d",errno);
		};
	}
0707070035351137121006640007620000050000010261310476773366700000700000001611Path.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* Path.h - Path names */

#define MAX_PATH_DEPTH (16)	/* maximum expected names in path */

typedef struct Path {
	int level;			/* current level */
	char *name[MAX_PATH_DEPTH];	/* name[0] is output root name;
					   the rest are basenames (both input
					   and output) */
	} Path;

typedef struct Path_process {
	int sl0;		/* no. slashes in input root name */
	Path path;
	VOID (*process)();
	VOID *arg;		/* passed as 3rd arg to (*process)() */
	} Path_process;

Path_process path_process;	/* controls file-tree processing */

char *path_toa();	/* see Path.c */
0707070035351137131006640007620000050000010261330476773367000000700000404335Text.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* Text.c - functions for Document-image file ("dim" file) handling

   General Introduction
   --------------------

   Dim files describe a document as a collection of records of these types:
	Page	full page
	Block	block (often a column) of text
	Txtln	line of text
	Word	word
	Char	character, isolated symbol, `graph'
	Interp	interpretation of a character (result of classification)
	Sfeats	scalar features of a character
	Shapes	local shape features of a character
	Bfeats	binary indicator features of a character
	Blob	connected component (maximal subset of 8-connected black pixels)
	Lag 	line-adjacency graph of runs
	Run	horizontal run of black pixels
        Pixel   bilevel (black/white) picture element (symbols are expected to
		be black against a white background); usually square

   They may be organized hierarchically --
	a Page may own :  Blocks, Txtlns, Words, Chars, & Blobs
	  a Block may own :  Blocks, Txtlns, Words, Chars, & Blobs
	    a Txtln may own :  Txtlns, Words, Chars, & Blobs
	      a Word may own :  Words, Chars & Blobs
	        a Char may own :  Blobs, Interps, Sfeats, Shapes, & Bfeats
	          a Blob may own :  Runs (variously represented)
		    a Run owns :  black Pixels
    Note that the hierarchy is strict except that Blocks, Txtlns, & Words may
    own records of their own type.  This serves several functions:
    --  a Block may own other Blocks, conventionally nested within it, to
	represent a physical or logical page layout decomposition;
    --  a Txtln may have alternative interpretations & segmentations into Words;
    --  a Word may have alternative segmentations into Chars.

    For each record type R, there should exist these data-structures:
	R			struct
	Init_R			#define'd initialization string
	empty_R			an extern ``empty'' (initialized) instance of R
    Also there are library functions (in which _R is spelled in lower-case):
	R *alloc_R()		allocate memory and initialize to ``empty''
	free_R(R *)		free memory (only of record R, not what it owns)
	free_R_etc(R *,ids)	free R and what it owns (as specified by `ids')
	R *dup_R(R *)		return distinct copy, with duplicated contents
	R *dup_R_etc(R *,ids)	return distinct copy, duplicated contents & parts
	char *R_toa(R *)	convert to printable ASCII string
	frdb_R(FILE *, R *)	fread R (binary) from file thru pointer
	frdb_R_etc(",",ids)	fread R (binary) and what it owns (as specified)
	fwrb_R(FILE *, R *)	fwrite R (binary) to file thru pointer
	fwrb_R_etc(",",ids)	fwrite R (binary) and what it owns (as specified)
    (some of these may be unimplemented if they haven't yet been needed)

    I/O conventions:
    --	frd?_... return one of:
	    1  normal & successful
	    0  EOF
	   <0  I/O errors
	Quite a few functions don't obey this rule yet.
	Many intermediate fns that don't directly perform I/O
	don't bother passing back status from fns they call.
	Those that perform I/O directly often complain to stderr and exit(2).
	The situation is fairly chaotic, and has already caused bugs.

    Generally:
    --	An `etc' argument is a set of Ident bits specifying a set of record types;
	it is passed along unchanged in calls to other _etc functions.
    --  `fwrb_R_etc' fns obey the `etc' instructions carefully,  writing only those
	record types specified
    --  `frdb_R_etc' fns mostly ignore `etc', blindly reading everything they
	see (since they aren't clever enough to skip past yet);  however, the
	Blob-reading fns look at the Runs_?? bits to select a main memory
	format for Runs
    --	`frdb_R_etc' uses alloc_Y to allocate all new Y
    --	`fwrb_R_etc', however, does NOT free anything: this must be done explicitly
	afterwards.

    Ownership of a set of records is implemented by two fields in the owner record:
    (1) a count of the number of members, and (2) either a ``set'' or a ``list''
    pointer:
	set:  to a NULL-terminated array of pointers to records
	list: to the first in a singly-linked, NULL-terminated, chain
    sets are used for sets of Blocks, Txtlns, Words, Chars, and Blobs
    lists are used for Interpl, and for Blobs owned by Chars, since they tend
	to be fewer

    Blobs and Runs are treated more elaborately than other records.  Blobs are
    collected in lists when owned by Chars, but in sets otherwise --
    the motivation was that the Char lists are usually very short, and the malloc
    overhead of creating them might be unpleasant -- however, maintaining two
    kinds of sets has caused other headaches; it might be good someday to
    abolish lists in favor of sets throughout.
    Runs can often be compressed to about half the usual size by using char
    fields instead of shorts, and this is done automatically when writing to files.    There is both a set and a list form of Run.

    The peripheral file format is:
    - deliberately decoupled from the internal (main memory) format:  i.e.
	the main memory structs can be (and are) changed frequently for
	purposes of experimentation without forcing frequent reformatting
	of the (by now large) backlog of archived files (particularly the
	character image databases).  To bring such files up-to-date, the program
	`renew' should be used: it must be edited to reflect changes since
	the last overhaul of the file format.
    - designed to be ``scannable'': that is, one can skip rapidly from record
	to record (using the Ident headers) without minding the hierarchy.
	This is most useful for the graphics editor "met", where it permits
	quick response at the outset.  It is also used widely in the
	off-line training programs, where main memory is at a premium.
    - machine-independent:  floating-point representations are forced to
	fixed point and scaled to integer; all integer representations are
	written as a sequence of bytes in a fixed order, via putc()/getc().
	fwrite()/fread() are never used for binary I/O.  This seems to work
	on virtually all UNIX machines.  See fioi.h.

    CCITT Group 4 encodings have been implemented and are available
    as a peripheral file format for Blobs.  They offer a large compression
    factor (x8) over RunF and RunFS records, and the CPU overhead is not
    excessive.  It turns out that the connectivity information represented
    explicitly in Run records but lost in ccitt-g4 can be recovered in linear
    time and space (see fix_lag()); in practice the extra recovery time is
    negligible and the extra space is 0.  This is possible because Blobs are
    known to be connected:  if not, then (I suspect that) superlinear time is
    required in general to recover the lag.

  */

#include <stdio.h>
#include <math.h>
#define LIBC_INCL 1
#include "CPU.h"
#include "stdocr.h"
#include "rle.h"
#include "Text.h"
#include "bitio.h"
#include "CCITT.h"

	long fseek(),lseek();

#define dbg_fwrb T	/* failsafe consistency checking */
#define dbg_frdb T	/* failsafe consistency checking */
#define dbg_fwrb_runs F	/* announce no. bytes used to write each Blob's Runs */
#define dbg_frdb_runs F	/* announce no. bytes used to write each Blob's Runs */

/* return ASCII string describing ident bits */
char *ident_toa(id)
	Ident id;
{	static char s[80];
	s[0]='\0';
    if((id&IsALL)==IsALL) strcat(s,"ALL");
    else {
	if(id&IsPage) {
		strcat(s,"PG");
		if(id&(Page_label)) {
			strcat(s,".");
			if(id&Page_label) strcat(s,"l");
			};
		}
	if(id&IsBlock) {
		strcat(s,"BK");
		if(id&(Block_wst|Block_label)) {
			strcat(s,".");
			if(id&Block_wst) strcat(s,"w");
			if(id&Block_label) strcat(s,"l");
			};
		};
	if(id&IsTxtln) {
		strcat(s,"TL");
		if(id&(Txtln_basl|Txtln_size|Txtln_label)) {
			strcat(s,".");
			if(id&Txtln_basl) strcat(s,"b");
			if(id&Txtln_size) strcat(s,"s");
			if(id&Txtln_label) strcat(s,"l");
			};
		};
	if(id&IsWord) {
		strcat(s,"WD");
		if(id&(Word_spelled|Word_label)) {
			strcat(s,".");
			if(id&Word_spelled) strcat(s,"s");
			if(id&Word_label) strcat(s,"l");
			};
		};
	if(id&IsWordInterp) {
		strcat(s,"WI");
		if(id&(Word_spelled|Word_numeric|Word_initcap|Word_allcaps|Word_hyphens|Word_slashes|Word_termhyp|Word_endsent)) {
			strcat(s,".");
			if(id&Word_spelled) strcat(s,"s");
			if(id&Word_numeric) strcat(s,"n");
			if(id&Word_initcap) strcat(s,"i");
			if(id&Word_allcaps) strcat(s,"a");
			if(id&Word_hyphens) strcat(s,"-");
			if(id&Word_slashes) strcat(s,"/");
			if(id&Word_termhyp) strcat(s,"h");
			if(id&Word_endsent) strcat(s,".");
			};
		};
	if(id&IsChar) {
		strcat(s,"CH");
		if(id&(Char_spelled|Char_confused|Char_termhyp|Char_omit|Char_label|Char_ranparms)) {
			strcat(s,".");
			if(id&Char_spelled) strcat(s,"s");
			if(id&Char_confused) strcat(s,"c");
			if(id&Char_termhyp) strcat(s,"h");
			if(id&Char_omit) strcat(s,"o");
			if(id&Char_label) strcat(s,"l");
			if(id&Char_ranparms) strcat(s,"r");
			if(id&Char_split) strcat(s,"S");
			if(id&Char_merged) strcat(s,"M");
			};
		};
	if(id&IsInterp) {
		strcat(s,"IN");
		if(id&Interp_spelled) {
			strcat(s,".s");
			};
		};
	if(id&IsBlob) {
		strcat(s,"BB");
		if( id&(Blob_lm|Blob_rm|Blob_tm|Blob_bm
			 |Blob_chopt|Blob_chopb|Blob_chopl|Blob_chopr
			 |Blob_small|Blob_local)
		         ) {
			strcat(s,".");
			if(id&(Blob_tm|Blob_bm|Blob_lm|Blob_rm)) {
				if(id&Blob_lm) strcat(s,"l");
				if(id&Blob_rm) strcat(s,"r");
				if(id&Blob_tm) strcat(s,"t");
				if(id&Blob_bm) strcat(s,"b");
				};
			if(id&(Blob_chopt|Blob_chopb|Blob_chopl|Blob_chopr)) {
				if(id&Blob_chopl) strcat(s,"L");
				if(id&Blob_chopr) strcat(s,"R");
				if(id&Blob_chopt) strcat(s,"T");
				if(id&Blob_chopb) strcat(s,"B");
				};
			if(id&Blob_small) strcat(s,"s");
			if(id&Blob_local) strcat(s,"o");
			};
		}
	    };
	return(s);
	}

/* convert a conventional character-code to a record type */
Ident cto_ident(c)
    char c;
{   Ident type;
	switch(c) {
	    case 'b':
		type=IsBlob;  break;
	    case 'B': case 'k':
		type=IsBlock;  break;
	    case 'c':
		type=IsChar;  break;
	    case 'i':
		type=IsInterp;  break;
	    case 'p':  case 'P':
		type=IsPage;  break;
	    case 'r':
		type=IsRun;  break;
	    case 't': case 'l':
		type=IsTxtln;  break;
	    case 'w':
		type=IsWord;  break;
	    case 'y':
		type=IsBdy;  break;
	    };
	return(type);
	}

Ident cto_flag(c,type)
    char c;
    Ident type;
{   Ident flag;
	flag = IsNONE;
	if(type&IsPage) {
		switch(c) {
			case 'l': flag |= Page_label; break;
			};
		}
	else if(type&IsBlock) {
		switch(c) {
			case 'w': flag |= Block_wst; break;
			case 'l': flag |= Block_label; break;
			};
		}
	else if(type&IsTxtln) {
		switch(c) {
			case 'b': flag |= Txtln_basl; break;
			case 's': flag |= Txtln_size; break;
			case 'l': flag |= Txtln_label; break;
			};
		}
	else if(type&IsWord) {
		switch(c) {
			case 's': flag |= Word_spelled; break;
			case 'n': flag |= Word_numeric; break;
			case 'i': flag |= Word_initcap; break;
			case 'a': flag |= Word_allcaps; break;
			case '-': flag |= Word_hyphens; break;
			case '/': flag |= Word_slashes; break;
			case 'h': flag |= Word_termhyp; break;
			case '.': flag |= Word_endsent; break;
			case 'l': flag |= Word_label; break;
			};
		}
	else if(type&IsChar) {
		switch(c) {
			case 's': flag |= Char_spelled; break;
			case 'c': flag |= Char_confused; break;
			case 'h': flag |= Char_termhyp; break;
			case 'o': flag |= Char_omit; break;
			case 'l': flag |= Char_label; break;
			case 'r': flag |= Char_ranparms; break;
			case 'S': flag |= Char_split; break;
			case 'M': flag |= Char_merged; break;
			};
		}
	else if(type&IsBlob) {
		switch(c) {
			case 'B': flag |= Blob_chopb; break;
			case 'L': flag |= Blob_chopl; break;
			case 'R': flag |= Blob_chopr; break;
			case 'T': flag |= Blob_chopt; break;
			case 'b': flag |= Blob_bm; break;
			case 'l': flag |= Blob_lm; break;
			case 'o': flag |= Blob_local; break;
			case 'r': flag |= Blob_rm; break;
			case 's': flag |= Blob_small; break;
			case 't': flag |= Blob_tm; break;
			};
		}
	else if(type&IsInterp) {
		switch(c) {
			case 's': flag |= Interp_spelled; break;
			};
		};
	return(flag);
	}

#if FRDI
/* read only the Ident of the next record; if EOF, return 0 */
Ident frdb_ident(fp)
    FILE *fp;
{   Ident ident;
	ident = frdi_Ident(fp);
#if dbg_frdb_toa
	err("frdb_ident: %s",ident_toa(ident));
#endif
	if(feof(fp)) return(0);
	else return(ident);
	}
#else
/* read only the Ident of the next record; return 0 iff EOF */
Ident frdb_ident(fp)
    FILE *fp;
{   Ident ident;
    int stat;
	if((stat=fread(&ident,sizeof(Ident),1,fp))!=1) {
		if(stat==0) return(0);
		else abort("frdb_ident: can't fread, status %d",stat);
		};
	if( Readvax ) ident = swapintin(ident);
#if dbg_frdb_toa
	err("frdb_ident: %s",ident_toa(ident));
#endif
	if(feof(fp)) return(0);
	else return(ident);
	}
#endif

#if FRDI
/* read label into malloc space */
char *frdb_label(f)
    FILE *f;
{   register char *res;
	res=frdi_str(f);
#if dbg_frdb_toa
	err("frdb_label: \"%s\"",res);
#endif
	return(res);
	}
#else
/* read label into malloc space */
char *frdb_label(fp)
    FILE *fp;
{   static char s[MAX_LABEL_LEN];
    char *c,*ce,*l;
    int ch;
	ce=(c=s)+MAX_LABEL_LEN-1;
	while((c<ce)&&((ch=getc(fp))!=EOF)&&(ch!='\0')) *(c++) = ch;
	*c='\0';
	if(c==ce) {
		/* label is truncated; find end of it */
		while(((ch=getc(fp))!=EOF)&&(ch!='\0')) ;
		};
	if((l=strdup(s))==NULL)
		abort("frdb_label: can't dup char *s[%d]",strlen(s));
#if dbg_frdb_toa
	err("frdb_label: \"%s\"",l);
#endif
	return(l);
	}
#endif

/* skip label */
fskb_label(fp)
    FILE *fp;
{   int ch;
	while(((ch=getc(fp))!=EOF)&&(ch!='\0')&&(ch!='\n')) ;
	if(ch==EOF) return(0); else return(1);
	}

/* Skip the REST of this record (the Ident is assumed to have been read),
   and return the Ident of the next record in the file;
   else return:
	 0	EOF
	-1	I/O error
	-2	not one of: Page, Block, Txtln, Char, Interp
   */
char *pp_toa(ppp)
    Pp *ppp;
{    static char s[30];
	sprintf(s,"(%0.2f,%0.2f)",ppp->x,ppp->y);
	return(s);
	}

/* return integer string in the range 00-99 */
char *merit_toa(m)
    Merit m;
{   static char s[3];
    int im;
	im = (int)(m * 100);
	if(im>99) im=99; else if(im<0) im=0;
	if(im<10) {
		s[0] = '0';
		sprintf(s+1,"%d",im);
		}
	else sprintf(s,"%2d",im);
	s[3] = '\0';
	return(s);
	}

char *pts_toa(p)
    Pts p;
{   static char s[10];
	sprintf(s,"%g",((int)((p*10.0)+0.5))/10.0);
	return(s);
	}

Bdy *alloc_bdy()
{    Bdy *p;
	if((p=(Bdy *)malloc(sizeof(Bdy)))==NULL)
		abort("alloc_bdy: can't malloc");
	else {	*p = empty_Bdy;
		return(p);
		};
	}

Bdys *alloc_bdys()
{    Bdys *p;
	if((p=(Bdys *)malloc(sizeof(Bdys)))==NULL)
		abort("alloc_bdys: can't malloc");
	else {	*p = empty_Bdys;
		return(p);
		};
	}

char *bdyedge_toa(bep)
    BdyEdge *bep;
{   static char s[80];
    char aps[20];
	strcpy(aps,sp_toa(bep->ap));
	sprintf(s,"%s,%s p%d c%s a%0.2f",
		aps, sp_toa(bep->bp),
		bep->per,
		pp_toa(&(bep->ctr)),
		(bep->ang/PI)*180.0);
	return(s);
	}

free_bdyedges(besp)
    BdyEdges *besp;
{   register BdyEdge *bep,**bepp;
	if(besp->pa!=NULL) {
		if(besp->mny>0) {
			for(bep= *(bepp=besp->pa); bep!=NULL; bep= *(++bepp))
				free(bep);
			};
		free(besp->pa);
		};
	*besp = empty_BdyEdges;
	}

/* Skip past the "TYPE=document-image\n\n" (or "TYPE=dim\n\n") ASCII header from
   file *fp, read and check the Doc record, and, if all's well, return 1.
   If an immediate EOF, return 0.  If not EOF, and no "TYPE=" header,
   leave fp as it was, and return -1.  If a malformed "TYPE=" header, leave fp
   as it was, and return -2. */
int skip_type(fp)
    FILE *fp;
{   int ich,stat;
    long seek;
#define MAX_TYPE_HDR_LEN (100)
    char type_eq[MAX_TYPE_HDR_LEN+1];
    register char *pcp,*ccp,*ecp;
    int version;

	seek = ftell(fp);
	/* test for EOF */
	if(feof(fp) || (ich=getc(fp))==EOF)
		/* premature EOF*/ return(0);
	if((type_eq[0]=ich)!='T') {
		/* no "TYPE=" header */
		ungetc(ich,fp);		/* fast, guaranteed push-back */
		return(-1);
		};
	/* try to read the rest of "TYPE=" */
	for(ecp=(ccp=type_eq+1)+4; ccp<ecp; ccp++) {
		if(feof(fp) || (ich=getc(fp))==EOF) {
			/* no "TYPE=" header */
			fseek(fp,seek,0);
			return(-1);
			}
		else *ccp=ich;
		}
	*ccp='\0';
	/* check for "TYPE=" so far */
	if(strcmp(type_eq,"TYPE=")==0) {
		/* read rest of ASCII header */
		ccp=(pcp=type_eq+3)+1;  ecp=type_eq+MAX_TYPE_HDR_LEN;
		do {	ccp++; pcp++;
			if((ich=getc(fp))==EOF) {
				/* malformed "TYPE=" header */
				fseek(fp,seek,0);
				return(-2);
				}
			else *ccp=ich;
			}
		while(ccp<ecp && (*ccp!='\n'||*pcp!='\n'));
		if(ccp==ecp) {
			/* malformed "TYPE=" header */
			fseek(fp,seek,0);
			return(-2);
			};
		*pcp='\0';
		/* check that it is "TYPE=document-image\n\n" or "TYPE=dim\n\n" */
		if(strcmp(type_eq,"TYPE=document-image")!=0
		   && strcmp(type_eq,"TYPE=dim")!=0) {
			/* malformed "TYPE=" header */
			fseek(fp,seek,0);
			return(-2);
			};
#if dbg_frdb_toa
		err("skip_type: \"%s\\n\\n\"",type_eq);
#endif
		return(1);	/* normal and successful TYPE= header */
		}
	else {	/* no "TYPE=" header */
		fseek(fp,seek,0);
		return(-1);
		};
	}

Doc *alloc_doc()
{    Doc *p;
	if((p=(Doc *)malloc(sizeof(Doc)))==NULL)
		abort("alloc_doc: can't malloc");
	else {	*p = empty_Doc;
		return(p);
		};
	}

char *doc_toa(p)
    Doc *p;
{    static char s[80];
	sprintf(s,"Doc v%d p%d l%s",
		p->version,
		p->ps.mny,
		(p->l!=NULL)? p->l: "");
	return(s);
	}

#if FWRI
/* write the given doc (record only) */
fwrb_doc(f,p)
    FILE *f;
    Doc *p;
{   int stat;
	fwri_uint1(f,p->version);
	fwri_uint2(f,p->ps.mny);
#if dbg_fwrb_toa
	err("fwrb_doc: %s",doc_toa(p));
#endif
 	if(p->l!=NULL) {
		fwri_ch(f,'l');
		fwrb_label(f,p->l);
		}
	else fwri_ch(f,'\0');
	}
#else
fwrb_doc(f,p)
    FILE *f;
    Doc *p;
{}
#endif

#if FRDI
/* read a Doc record (only) - it must be next in the file;
   don't immediately read its parts; return 0 iff immediate EOF.
   Check for correct version no: if fails, abort.  */
int frdb_doc(f,p)
    FILE *f;
    Doc *p;
{   char qlabel;
	*p = empty_Doc;
	if(feof(f))
		return(0);
	p->version=frdi_uint1(f);
	p->ps.mny=frdi_uint2(f);
	if((qlabel=frdi_ch(f))=='l')
		p->l=frdb_label(f);
#if dbg_frdb_toa
	err("frdb_doc: %s",doc_toa(p));
#endif
	if(ferror(f)) return(-errno); else return(1);
	}
#else
int frdb_doc(f,p)
    FILE *f;
    Doc *p;
{	return(1);
	}
#endif

#if FWRI
/* Write the initial Doc record */
put_doc(f)
    FILE *f;
{   Doc doc;
	doc = empty_Doc;
	doc.version = DIM_VERSION;
	doc.ps.mny = 1;
	fwrb_doc(f,&doc);
	}
#else
put_doc(f)
    FILE *f;
{}
#endif

#if FRDI
/* read, check, discard, and skip past the Doc record */
int skip_doc(f)
    FILE *f;
{   Doc doc;
	frdb_doc(f,&doc);
	if(doc.version!=DIM_VERSION)
		abort("skip_doc: version %d != DIM_VERSION %d",
			doc.version,DIM_VERSION);
	if(doc.l!=NULL) free(doc.l);
	return(1);
	}
#else
int skip_doc(f)
    FILE *f;
{   Doc doc;
	return(1);
	}
#endif

Page *alloc_page()
{    Page *p;
	if((p=(Page *)malloc(sizeof(Page)))==NULL)
		abort("alloc_page: can't malloc");
	alloc_census(Page,1);
	*p = empty_Page;
	return(p);
	}

char *page_toa(p)
    Page *p;
{    static char s[80];
	sprintf(s,"%s bx%s res%d,%d sk%0.2f,sh%0.2f bk%d l%d c%d b%d",
		ident_toa(p->ident),
		bbx_toa(&(p->bx)),
		p->res_x,p->res_y,
		(p->skew/PI)*180.0,
		(p->shear/PI)*180.0,
		p->bks.mny,p->ls.mny,p->cs.mny,p->bs.mny,
		(p->l!=NULL)? p->l: "");
	return(s);
	}

#if FWRI
/* write the given page (record only) */
fwrb_page(f,p)
    FILE *f;
    Page *p;
{   int stat;
#if dbg_fwrb
	if(f==stdout||f==stderr||ftell(f)<=0L) {
		fprintf(f,"TYPE=dim\n\n");
#if dbg_fwrb_toa
		err("fwrb_page: \"TYPE=dim\\n\\n\"");
#endif
		put_doc(f);
		};
	if((!(p->ident&IsPage))||(p->ident&(IsALL&(~IsPage))))
		err("fwrb_page: %s",page_toa(p));
	if(p->ident&Page_label && p->l==NULL) {
		err("fwrb_page: Page_label set but .l==NULL");
		p->ident &= ~Page_label;
		};
#endif
	fwri_Ident(f,p->ident);
	fwri_Bbx(f,&(p->bx));
	fwri_int2(f,p->res_x);
	fwri_int2(f,p->res_y);
	fwri_Radians(f,p->skew);
	fwri_Radians(f,p->shear);
	fwri_uint2(f,p->bks.mny);
	fwri_uint2(f,p->ls.mny);
	fwri_uint2(f,p->ws.mny);
	fwri_uint2(f,p->cs.mny);
	fwri_uint3(f,p->bs.mny);
#if dbg_fwrb_toa
	err("fwrb_page: %s",page_toa(p));
#endif
 	if(p->ident&Page_label) fwrb_label(f,p->l);
	}
#else
/* write the given page (record only) */
fwrb_page(fp,pp)
    FILE *fp;
    Page *pp;
{   PageF pf;
    int stat;
#if dbg_fwrb
	if((!(pp->ident&IsPage))||(pp->ident&(IsALL&(~IsPage))))
		err("fwrb_page: %s",page_toa(pp));
#endif
	memset(&pf,'\0',sizeof(pf));
	pf.ident = pp->ident;
	pf.res_x=pp->res_x;
	pf.res_y=pp->res_y;
	pf.bx=pp->bx;
	pf.skew=pp->skew;
	pf.shear=pp->shear;
	pf.bkmny=pp->bks.mny;
	pf.lmny=pp->ls.mny;
	pf.wmny=pp->ws.mny;
	pf.cmny=pp->cs.mny;
	pf.bmny=pp->bs.mny;
	if(fp==stdout||fp==stderr||ftell(fp)<=0L) {
		fprintf(fp,"TYPE=document-image\n\n");
#if dbg_fwrb_toa
		err("fwrb_page: \"TYPE=document-image\\n\\n\"");
#endif
		};
	if((stat=fwrite(&pf,sizeof(PageF),1,fp))!=1)
		abort("fwrb_page: can't fwrite - status %d",stat);
#if dbg_fwrb_toa
	err("fwrb_page: %s",page_toa(pp));
#endif
 	if(pf.ident&Page_label) fwrb_label(fp,pp->l);
	}
#endif

/* write a page and its specified parts */
fwrb_page_etc(fp,pp,etc)
    FILE *fp;
    Page *pp;
    Ident etc;
{   static Ident parts = (IsBlock|IsTxtln|IsWord|IsChar|IsBlob);
    Page pg;
   	if((etc&parts)!=parts) /* write selected parts */ {
		pg = *pp;
		if(!(etc&IsBlock)) pg.bks.mny=0;
		if(!(etc&IsTxtln)) pg.ls.mny=0;
		if(!(etc&IsWord)) pg.ws.mny=0;
		if(!(etc&IsChar)) pg.cs.mny=0;
		if(!(etc&IsBlob)) pg.bs.mny=0;
		pp = &pg;	/* write modified record */
		};
	fwrb_page(fp,pp);
	fwrb_blocks_etc(fp,pp->bks,etc);
	fwrb_txtlns_etc(fp,pp->ls,etc);
	fwrb_words_etc(fp,pp->ws,etc);
	fwrb_chars_etc(fp,pp->cs,etc);
	fwrb_blobs_etc(fp,pp->bs,etc);
	}

/* write a page and its specified parts, ASCII (INCOMPLETE) */
fwra_page_etc(fp,pp,etc)
    FILE *fp;
    Page *pp;
    Ident etc;
{   static Ident parts = (IsBlock|IsTxtln|IsWord|IsChar|IsBlob);
    Page pg;
   	if((etc&parts)!=parts) /* write selected parts */ {
		pg = *pp;
		if(!(etc&IsBlock)) pg.bks.mny=0;
		if(!(etc&IsTxtln)) pg.ls.mny=0;
		if(!(etc&IsWord)) pg.ws.mny=0;
		if(!(etc&IsChar)) pg.cs.mny=0;
		if(!(etc&IsBlob)) pg.bs.mny=0;
		pp = &pg;	/* write modified record */
		};
	if(etc&IsPage) fwrb_page(fp,pp);
	fwrb_blocks_etc(fp,pp->bks,etc);
	fwrb_txtlns_etc(fp,pp->ls,etc);
	fwrb_words_etc(fp,pp->ws,etc);
	fwrb_chars_etc(fp,pp->cs,etc);
	fwrb_blobs_etc(fp,pp->bs,etc);
	}

#if FRDI
/* read a Page record (only) - it must be next in the file;
   don't immediately read its parts; return 0 iff immediate EOF  */
int frdb_page(f,p)
    FILE *f;
    Page *p;
{   char *pfc;	/* for debugging */
    int stat;
	switch(skip_type(f)) {
	    case 1:  /* "TYPE=" header */
		skip_doc(f);
		break;
	    case 0:  /* immediate EOF */
		return(0);
		break;
	    case -1:  /* no "TYPE=" header */
		break;
	    case -2:  /* garbled "TYPE=" header */
		abort("frdb_page: garbled \"TYPE=\" header");
		break;
	    };
	*p = empty_Page;
	if(feof(f))
		return(0);
	p->ident=frdi_Ident(f);
	frdi_Bbx(f,&(p->bx));
	p->res_x=frdi_int2(f);
	p->res_y=frdi_int2(f);
	p->skew=frdi_Radians(f);
	p->shear=frdi_Radians(f);
	p->bks.mny=frdi_uint2(f);
	p->ls.mny=frdi_uint2(f);
	p->ws.mny=frdi_uint2(f);
	p->cs.mny=frdi_uint2(f);
	p->bs.mny=frdi_uint3(f);
#if dbg_frdb
	if((!(p->ident&IsPage))||(p->ident&(IsALL&(~IsPage))))
		err("frdb_page: %s",page_toa(p));
#endif
#if dbg_frdb_toa
	err("frdb_page: %s",page_toa(p));
#endif
 	if(p->ident&Page_label) p->l = frdb_label(f);
	if(ferror(f)) return(-errno); else return(1);
	}
#else
/* read a Page record (only) - it must be next in the file;
   don't immediately read its parts; return T iff not early EOF  */
int frdb_page(fp,pp)
    FILE *fp;
    Page *pp;
{   PageF pf;
    char *pfc;	/* for debugging */
    int stat;
	if((stat=skip_type(fp))!=1 /* "TYPE=" header */
	    && stat!=-1 /* no "TYPE=" header */ ) {
		/* premature EOF or error */ return(stat);
		};
	if((stat=fread(&pf,sizeof(PageF),1,fp))!=1)
		/* premature EOF*/ return(stat);
	pfc = (char *)&pf;
	*pp = empty_Page;
	pp->ident=pf.ident;
	pp->res_x=pf.res_x;
	pp->res_y=pf.res_y;
	pp->bx=pf.bx;
	pp->skew=pf.skew;
	pp->shear=pf.shear;
	pp->bks.mny = pf.bkmny;	pp->bks.bpa=NULL;
	pp->ls.mny = pf.lmny;	pp->ls.lpa=NULL;
	pp->ws.mny = pf.wmny;	pp->ws.wpa=NULL;
	pp->cs.mny = pf.cmny;	pp->cs.cpa=NULL;
	pp->bs.mny = pf.bmny;	pp->bs.bpa=NULL;
#if dbg_frdb_toa
	err("frdb_page: %s",page_toa(pp));
#endif
 	if(pp->ident&Page_label) pp->l = frdb_label(fp);
#if dbg_frdb
	if((!(pp->ident&IsPage))||(pp->ident&(IsALL&(~IsPage))))
		err("frdb_page: %s",page_toa(pp));
#endif
	return(stat);
	}
#endif

/* Read a page and selected parts */
int frdb_page_etc(fp,pp,etc)
    FILE *fp;
    Page *pp;
    Ident etc;
{   int stat;
	if((etc&IsALL)==IsALL) {
	    long here;
		/* In order to minimize malloc time to read an often huge file,
		   malloc and then free storage roughly equal to what's needed */
 		if( /* DEFEATED */ F && (here=ftell(fp))>=0 && fseek(fp,0,2)>=0 ) {
			/* *fp is connected to a file, not a pipe */
 			free(malloc(ftell(fp)));
 			fseek(fp,here,0);
 			};
		};
	if((stat=frdb_page(fp,pp))!=1) return(stat);
	if(etc&IsBlock && pp->bks.mny>0)
		frdb_blocks_etc(fp,&(pp->bks),etc);
	else pp->bks = empty_Blocks;
	if(etc&IsTxtln && pp->ls.mny>0)
		frdb_txtlns_etc(fp,&(pp->ls),etc);
	else pp->ls = empty_Txtlns;
	if(etc&IsWord && pp->ws.mny>0)
		frdb_words_etc(fp,&(pp->ws),etc);
	else pp->ws = empty_Words;
	if(etc&IsChar && pp->cs.mny>0)
		frdb_chars_etc(fp,&(pp->cs),etc);
	else pp->cs = empty_Chars;
	if(etc&IsBlob && pp->bs.mny>0)
		frdb_blobs_etc(fp,&(pp->bs),etc);
	else pp->bs = empty_Blobs;
	return(1/*normal return*/);
	}

free_page_etc(p,etc)
    Page *p;
    Ident etc;
{	free_blocks_etc(&(p->bks),etc);
	free_txtlns_etc(&(p->ls),etc);
	free_words_etc(&(p->ws),etc);
	free_chars_etc(&(p->cs),etc);
	free_blobs_etc(&(p->bs),etc);
	if(p->ident&Page_label && p->l!=NULL) {
		free(p->l);  p->l=NULL;  p->ident &= ~Page_label;
		};
	if(etc&IsPage) {
		free(p);
		free_census(Page,1);
		};
	}

/* return a pointer to a distinct and duplicate copy of record Page *p,
   created out of malloc space */
Page *dup_page(p)
    Page *p;
{   Page *dup;
	dup=alloc_page();  *dup = *p;  return(dup);
	}

/* Return a pointer to a distinct and duplicate copy of Page *p, and its parts
   as specified by `etc', created out of malloc space. */
Page *dup_page_etc(p,etc)
    Page *p;
    Ident etc;
{   Page *dup;
	dup = dup_page(p);
	if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(p->bs),etc);
	else dup->bs = empty_Blobs;
	if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(p->cs),etc);
	else dup->cs = empty_Chars;
	if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(p->ws),etc);
	else dup->ws = empty_Words;
	if(etc&IsTxtln&&dup->ls.mny>0) dup->ls = *dup_txtlns_etc(&(p->ls),etc);
	else dup->ls = empty_Txtlns;
	if(etc&IsBlock&&dup->bks.mny>0) dup->bks = *dup_blocks_etc(&(p->bks),etc);
	else dup->bks = empty_Blocks;
	return(dup);
	}

Block *alloc_block()
{    Block *p;
	if((p=(Block *)malloc(sizeof(Block)))==NULL)
		abort("alloc_block: can't malloc");
	alloc_census(Block,1);
	*p = empty_Block;
	return(p);
	}

char *block_toa(p)
    Block *p;
{   static char s[80];
	sprintf(s,"%s bx%s sk%0.2f,sh%0.2f wst%0.2f m%s bk%d l%d w%d c%d b%d",
		ident_toa(p->ident),
		bbx_toa(&(p->bx)),
		p->skew/DtoR,
		p->shear/DtoR,
		p->wst,
		merit_toa(p->m),
		p->bks.mny,p->ls.mny,p->ws.mny,p->cs.mny,p->bs.mny,
		(p->l!=NULL)? p->l: "");
	return(s);
	}

#if FWRI
fwrb_block(f,p)
    FILE *f;
    Block *p;
{   int stat;
#if dbg_fwrb
	if((!(p->ident&IsBlock))||(p->ident&(IsALL&(~IsBlock))))
		err("fwrb_block: %s",block_toa(p));
	if(p->ident&Block_label && p->l==NULL) {
		err("fwrb_page: Block_label set but .l==NULL");
		p->ident &= ~Block_label;
		};
#endif
	fwri_Ident(f,p->ident);
	fwri_Bbx(f,&(p->bx));
	fwri_Radians(f,p->skew);
	fwri_Radians(f,p->shear);
	fwri_Ems(f,p->wst);
	fwri_Merit(f,p->m);
	fwri_uint2(f,p->bks.mny);
	fwri_uint2(f,p->ls.mny);
	fwri_uint2(f,p->ws.mny);
	fwri_uint2(f,p->cs.mny);
	fwri_uint3(f,p->bs.mny);
#if dbg_fwrb_toa
	err("fwrb_block: %s",block_toa(p));
#endif
 	if(p->ident&Block_label) fwrb_label(f,p->l);
	}
#else
fwrb_block(fp,bkp)
    FILE *fp;
    Block *bkp;
{   BlockF bf;
    int stat;
#if dbg_fwrb
	if((!(bkp->ident&IsBlock))||(bkp->ident&(IsALL&(~IsBlock))))
		err("fwrb_block: %s",block_toa(bkp));
#endif
	memset(&bf,'\0',sizeof(bf));
	bf.ident = bkp->ident;
	bf.bx = bkp->bx;
	bf.wst = bkp->wst;
	bf.skew = bkp->skew;
	bf.shear = bkp->shear;
	bf.lmny = bkp->ls.mny;
	bf.wmny = bkp->ws.mny;
	bf.cmny = bkp->cs.mny;
	bf.bmny = bkp->bs.mny;
#if dbg_fwrb_toa
	err("fwrb_block: %s",block_toa(bkp));
#endif
	if((stat=fwrite(&bf,sizeof(BlockF),1,fp))!=1)
		abort("fwrb_block: can't fwrite - status %d",stat);
	}
#endif

fwrb_blocks_etc(fp,bks,etc)
    FILE *fp;
    Blocks bks;
    Ident etc;
{   register Block *bkp,**bkpp;
	if(bks.mny>0) for(bkp= *(bkpp=bks.bpa); bkp!=NULL; bkp= *(++bkpp))
		fwrb_block_etc(fp,bkp,etc);
	}

fwrb_block_etc(fp,bkp,etc)
    FILE *fp;
    Block *bkp;
    Ident etc;
{   static Ident parts = (IsTxtln|IsWord|IsChar|IsBlob);
    Block bk;
   	if((etc&parts)!=parts) /* write selected parts */ {
		bk = *bkp;
		if(!(etc&IsTxtln)) bk.ls.mny=0;
		if(!(etc&IsWord)) bk.ws.mny=0;
		if(!(etc&IsChar)) bk.cs.mny=0;
		if(!(etc&IsBlob)) bk.bs.mny=0;
		bkp = &bk;	/* write modified record */
		};
	fwrb_block(fp,bkp);
	fwrb_txtlns_etc(fp,bkp->ls,etc);
	fwrb_words_etc(fp,bkp->ws,etc);
	fwrb_chars_etc(fp,bkp->cs,etc);
	fwrb_blobs_etc(fp,bkp->bs,etc);
	}

#if FRDI
int frdb_block(f,p)
    FILE *f;
    Block *p;
{	*p = empty_Block;
	if(feof(f))
		return(0);
	p->ident=frdi_Ident(f);
	frdi_Bbx(f,&(p->bx));
	p->skew=frdi_Radians(f);
	p->shear=frdi_Radians(f);
	p->wst=frdi_Ems(f);
	p->m=frdi_Merit(f);
	p->bks.mny=frdi_uint2(f);
	p->ls.mny=frdi_uint2(f);
	p->ws.mny=frdi_uint2(f);
	p->cs.mny=frdi_uint2(f);
	p->bs.mny=frdi_uint3(f);
#if dbg_frdb_toa
	err("frdb_block: %s",block_toa(p));
#endif
#if dbg_frdb
	if((!(p->ident&IsBlock))||(p->ident&(IsALL&(~IsBlock))))
		err("frdb_block: %s",block_toa(p));
#endif
 	if(p->ident&Block_label) p->l = frdb_label(f);
	if(ferror(f)) return(-errno); else return(1);
	}
#else
int frdb_block(fp,bkp)
    FILE *fp;
    Block *bkp;
{   BlockF bf;
    int stat;
	if((stat=fread(&bf,sizeof(BlockF),1,fp))!=1)
		abort("frdb_block: can't fread - status %d",stat);
	*bkp = empty_Block;
	bkp->ident = bf.ident;
	bkp->bx = bf.bx;
	bkp->skew = bf.skew;
	bkp->shear = bf.shear;
	bkp->wst = bf.wst;
	bkp->ls.mny = bf.lmny;
	bkp->ws.mny = bf.wmny;
	bkp->cs.mny = bf.cmny;
	bkp->bs.mny = bf.bmny;
#if dbg_frdb
	if((!(bkp->ident&IsBlock))||(bkp->ident&(IsALL&(~IsBlock))))
		err("frdb_block: %s",block_toa(bkp));
#endif
#if dbg_frdb_toa
	err("frdb_block: %s",block_toa(bkp));
#endif
 	if(bkp->ident&Block_label) bkp->l = frdb_label(fp);
	if(ferror(fp)) return(-errno); else return(1);
	}
#endif

frdb_block_etc(fp,bkp,etc)
    FILE *fp;
    Block *bkp;
    Ident etc;
{   BlockF bf;
    int stat;
	frdb_block(fp,bkp);
	if(etc&IsTxtln && bkp->ls.mny>0)
		frdb_txtlns_etc(fp,&(bkp->ls),etc);
	else bkp->ls = empty_Txtlns;
	if(etc&IsWord && bkp->ws.mny>0)
		frdb_words_etc(fp,&(bkp->ws),etc);
	else bkp->ws = empty_Words;
	if(etc&IsChar && bkp->cs.mny>0)
		frdb_chars_etc(fp,&(bkp->cs),etc);
	else bkp->cs = empty_Chars;
	if(etc&IsBlob && bkp->bs.mny>0)
		frdb_blobs_etc(fp,&(bkp->bs),etc);
	else bkp->bs = empty_Blobs;
	if(ferror(fp)) return(-errno); else return(1);
	}

/* read number of blocks, and their parts */
frdb_blocks_etc(fp,bksp,etc)
    FILE *fp;
    Blocks *bksp;
    Ident etc;
{   int bi;
    register Block *bkp,**bkpp;
	if(bksp->mny<=0) {
		*bksp = empty_Blocks;
		return(1);
		};

	if((bkpp=bksp->bpa=(Block **)malloc((bksp->mny+1)*sizeof(Block *)))==NULL)
		abort("can't alloc Blocks.bpa array");
	for(bi=0; bi<bksp->mny; bi++) {
		*(bkpp++) = bkp = alloc_block();
		frdb_block_etc(fp,bkp,etc);
		};
	*bkpp = NULL;
	if(ferror(fp)) return(-errno); else return(1);
	}

free_block_etc(p,etc)
    Block *p;
    Ident etc;
{	free_txtlns_etc(&(p->ls),etc);
	free_words_etc(&(p->ws),etc);
	free_chars_etc(&(p->cs),etc);
	free_blobs_etc(&(p->bs),etc);
	if(p->ident&Block_label && p->l!=NULL) {
		free(p->l);  p->l=NULL;  p->ident &= ~Block_label;
		};
	if(etc&IsBlock) {
		free(p);
		free_census(Block,1);
		};
	}

/* Unconditionally free the malloc-space array of pointers, and empty the set.
   Don't free the records that it owned.
   */
free_blocks(p)
    Blocks *p;
{   	if(p->bpa!=NULL) { free(p->bpa);  p->bpa = NULL; }
	p->mny = 0;
	}

free_blocks_etc(p,etc)
    Blocks *p;
    Ident etc;
{   register Block *bkp,**bkpp;
	if(p->mny>0&&(etc&IsBlock))
		for(bkp= *(bkpp=p->bpa); bkp!=NULL; bkp= *(++bkpp))
			free_block_etc(bkp,etc);
   	free_blocks(p);
	}

/* return a pointer to a distinct and duplicate copy of *bkp,
   created out of malloc space */
Block *dup_block(bkp)
    Block *bkp;
{   Block *dup;
	dup=alloc_block();
	*dup = *bkp;
	return(dup);
	}

/* Return a pointer to a distinct and duplicate copy of *bkp, and its parts
   as specified by `etc', created out of malloc space. */
Block *dup_block_etc(bkp,etc)
    Block *bkp;
    Ident etc;
{   Block *dup;
	dup = dup_block(bkp);
	if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(bkp->bs),etc);
	else dup->bs = empty_Blobs;
	if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(bkp->cs),etc);
	else dup->cs = empty_Chars;
	if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(bkp->ws),etc);
	else dup->ws = empty_Words;
	if(etc&IsTxtln&&dup->ls.mny>0) dup->ls = *dup_txtlns_etc(&(bkp->ls),etc);
	else dup->ls = empty_Txtlns;
	return(dup);
	}

/* Return a pointer to a distinct local static duplicate of non-empty *bksp.
   Its bkpa array is created newly out of malloc space.
   If etc&IsBlock, all its Blocks are also duplicated,
   else the contents of bkpa point to the old unduplicated Blocks.
   */
Blocks *dup_blocks_etc(bksp,etc)
    Blocks *bksp;
    Ident etc;		/* parts to duplicate */
{   static Blocks dup;
    register Block **bkpp,**dpp;
	if((dup.mny = bksp->mny)<=0) dup = empty_Blocks;
	else {	if((dup.bpa=(Block **)malloc((dup.mny+1)*sizeof(Block *)))==NULL)
			abort("can't dup bks.bpa");
		for(bkpp=bksp->bpa,dpp=dup.bpa; *bkpp!=NULL; bkpp++,dpp++) {
			if(etc&IsBlock) *dpp = dup_block_etc(*bkpp,etc);
			else *dpp = *bkpp;
			};
		*dpp = NULL;
		};
	return(&dup);
	}

/* Append a block to the end of a blocks set. 
   Return appended Block *. */
Block *append_block(bkp,bksp)
    Block *bkp;
    Blocks *bksp;
{   register Block *rp,**rpp,**npp;
	if(bksp->mny==0) {
		if((bksp->bpa=(Block **)malloc(2*sizeof(Block *)))==NULL)
			abort("append_block: can't malloc bksp->bpa");
		}
	else {	if((bksp->bpa=(Block **)realloc(
				bksp->bpa,
				(bksp->mny+2)*sizeof(Block *))
				)==NULL)
			abort("append_block: can't realloc bksp->bpa");
		};
	bksp->bpa[bksp->mny] = bkp;
	bksp->bpa[++bksp->mny] = NULL;
	return(bkp);
	}

/* remove a block from a blocks set */
remove_block(bkp,bksp)
    Block *bkp;
    Blocks *bksp;
{   register Block *rp,**rpp,**npp;
	if(bksp->mny==0) err("can't remove Block - Blocks empty");
	else {	for(rp= *(rpp=bksp->bpa); rp!=NULL; rp= *(++rpp)) if(rp==bkp) break;
		if(rp==NULL) err("can't remove Block - not found");
		else {	/* move later entries up */
			npp=rpp+1;
			do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
			if((--(bksp->mny))==0) {free(bksp->bpa); bksp->bpa=NULL;};
			/* don't bother to realloc downwards */
			};
		};
	}

ConstPitch *alloc_constpitch()
{    ConstPitch *p;
	if((p=(ConstPitch *)malloc(sizeof(ConstPitch)))==NULL)
		abort("can't alloc ConstPitch");
	else {	*p = empty_ConstPitch;
		return(p);
		};
	}

char *constpitch_toa(p)
    ConstPitch *p;
{    static char s[80];
	sprintf(s,"{w%.3f,o%d,r%.1f}",
		p->w,p->o,p->r);
	return(s);
	}

free_constpitch(p)
    ConstPitch *p;
{	free(p);
	}

Txtln *alloc_txtln()
{    Txtln *p;
	if((p=(Txtln *)malloc(sizeof(Txtln)))==NULL)
		abort("can't alloc Txtln");
	alloc_census(Txtln,1);
	*p = empty_Txtln;
	return(p);
	}

char *txtln_toa(p)
    Txtln *p;
{    static char s[80];
	sprintf(s,"%s bx%s sz%s ba%d cw%s m%s l%d w%d c%d b%d %s",
		ident_toa(p->ident),
		bbx_toa(&(p->bx)),
		pts_toa(p->size),
		p->basl,
		/** proj omitted **/
		((p->cp!=NULL)? constpitch_toa(p->cp): "0"),
		merit_toa(p->m),
		p->ls.mny,p->ws.mny,p->cs.mny,p->bs.mny,
		(p->l!=NULL)? p->l: "");
	return(s);
	}

#if FWRI
fwrb_txtln(f,p)
    FILE *f;
    Txtln *p;
{
#if dbg_fwrb
	if((!(p->ident&IsTxtln))||(p->ident&(IsALL&(~IsTxtln))))
		err("fwrb_txtln: %s",txtln_toa(p));
	if(p->ident&Txtln_label && p->l==NULL) {
		err("fwrb_page: Txtln_label set but .l==NULL");
		p->ident &= ~Txtln_label;
		};
#endif
	fwri_Ident(f,p->ident);
	fwri_Bbx(f,&(p->bx));
	fwri_Pts(f,p->size);
	fwri_Scoor(f,p->basl);
	/* fwri_?(f,p->proj); */
	/* fwri_ConstPitch(f,p->cp); */
	fwri_Merit(f,p->m);
	fwri_uint2(f,p->ls.mny);
	fwri_uint2(f,p->ws.mny);
	fwri_uint2(f,p->cs.mny);
	fwri_uint3(f,p->bs.mny);
#if dbg_fwrb_toa
	err("fwrb_txtln: %s",txtln_toa(p));
#endif
	if(p->ident&Txtln_label) fwrb_label(f,p->l);
	}
#else
fwrb_txtln(fp,lp)
    FILE *fp;
    Txtln *lp;
{   TxtlnF lf;
    int stat;
#if dbg_fwrb
	if((!(lp->ident&IsTxtln))||(lp->ident&(IsALL&(~IsTxtln))))
		err("fwrb_txtln: %s",txtln_toa(lp));
#endif
	memset(&lf,'\0',sizeof(lf));
	lf.ident = lp->ident;
	lf.bx = lp->bx;
	lf.basl = lp->basl;
	lf.size = lp->size;
	if(lp->proj!=NULL) lf.pmny = lp->bx.b.y - lp->bx.a.y + 1;
	else lf.pmny = 0;
	/* ignore lp->cp for now */
	lf.wmny = lp->ws.mny;
	lf.cmny = lp->cs.mny;
	lf.bmny = lp->bs.mny;
	if((stat=fwrite(&lf,sizeof(TxtlnF),1,fp))!=1)
		abort("can't write TxtlnF, status %d",stat);
#if dbg_fwrb_toa
	err("fwrb_txtln: %s",txtln_toa(lp));
#endif
	if(lf.ident&Txtln_label) fwrb_label(fp,lp->l);
	}
#endif

fwrb_txtlns_etc(fp,ls,etc)
    FILE *fp;
    Txtlns ls;
    Ident etc;
{   register Txtln *lp,**lpp;
	if(ls.mny>0) for(lp= *(lpp=ls.lpa); lp!=NULL; lp= *(++lpp))
		fwrb_txtln_etc(fp,lp,etc);
	}

fwrb_txtln_etc(fp,lp,etc)
    FILE *fp;
    Txtln *lp;
    Ident etc;
{   static Ident parts = (IsWord|IsChar|IsBlob);
    Txtln tl;
   	if((etc&parts)!=parts) /* write selected parts */ {
		tl = *lp;
		if(!(etc&IsWord)) tl.ws.mny=0;
		if(!(etc&IsChar)) tl.cs.mny=0;
		if(!(etc&IsBlob)) tl.bs.mny=0;
		lp = &tl;	/* write modified record */
		};
	fwrb_txtln(fp,lp);
	if(lp->proj!=NULL) {/* write projection array someday */};
	fwrb_words_etc(fp,lp->ws,etc);
	fwrb_chars_etc(fp,lp->cs,etc);
	fwrb_blobs_etc(fp,lp->bs,etc);
	}

#if FRDI
int frdb_txtln(f,p)
    FILE *f;
    Txtln *p;
{	*p = empty_Txtln;
	if(feof(f))
		return(0);
	p->ident=frdi_Ident(f);
	frdi_Bbx(f,&(p->bx));
	p->size=frdi_Pts(f);
	p->basl=frdi_Scoor(f);
	/* p->proj=frdi_?(f); */
	/* p->cp=frdi_ConstPitch(f); */
	p->m=frdi_Merit(f);
	p->ls.mny=frdi_uint2(f);
	p->ws.mny=frdi_uint2(f);
	p->cs.mny=frdi_uint2(f);
	p->bs.mny=frdi_uint3(f);
#if dbg_frdb
	if((!(p->ident&IsTxtln))||(p->ident&(IsALL&(~IsTxtln))))
		err("frdb_txtln: %s",txtln_toa(p));
#endif
#if dbg_frdb_toa
	err("frdb_txtln: %s",txtln_toa(p));
#endif
	if(p->ident&Txtln_label) p->l = frdb_label(f);
	if(ferror(f)) return(-errno); else return(1);
	}
#else
int frdb_txtln(fp,lp)
    FILE *fp;
    Txtln *lp;
{   TxtlnF lf;
    int stat;
	if((stat=fread(&lf,sizeof(TxtlnF),1,fp))!=1)
		abort("can't read TxtlnF, status %d",stat);
	*lp = empty_Txtln;
	lp->ident = lf.ident;
	lp->bx = lf.bx;
	lp->basl = lf.basl;
	lp->size = lf.size;
	if(lf.pmny>0) lp->proj=(short *)malloc(lf.pmny);
	else lp->proj = NULL;
	lp->cp = NULL;
	lp->ws.mny = lf.wmny;
	lp->cs.mny = lf.cmny;
	lp->bs.mny = lf.bmny;
#if dbg_frdb
	if((!(lp->ident&IsTxtln))||(lp->ident&(IsALL&(~IsTxtln))))
		err("frdb_txtln: %s",txtln_toa(lp));
#endif
#if dbg_frdb_toa
	err("frdb_txtln: %s",txtln_toa(lp));
#endif
	if(lp->ident&Txtln_label) lp->l = frdb_label(fp);
	if(ferror(fp)) return(-errno); else return(1);
	}
#endif

frdb_txtln_etc(fp,lp,etc)
    FILE *fp;
    Txtln *lp;
    Ident etc;
{   TxtlnF lf;
    int stat;
	frdb_txtln(fp,lp);
	if(lp->proj!=NULL) {/* read projection array someday */};
	if(etc&IsWord && lp->ws.mny>0)
		frdb_words_etc(fp,&(lp->ws),etc);
	else lp->ws = empty_Words;
	if(etc&IsChar && lp->cs.mny>0)
		frdb_chars_etc(fp,&(lp->cs),etc);
	else lp->cs = empty_Chars;
	if(etc&IsBlob && lp->bs.mny>0)
		frdb_blobs_etc(fp,&(lp->bs),etc);
	else lp->bs = empty_Blobs;
	if(ferror(fp)) return(-errno); else return(1);
	}

/* read number of txtlns, and parts */
frdb_txtlns_etc(fp,lsp,etc)
    FILE *fp;
    Txtlns *lsp;
    Ident etc;
{   int li;
    register Txtln *lp,**lpp;
	if(lsp->mny<=0) {
		*lsp = empty_Txtlns;
		return(1);
		};
	if((lpp=lsp->lpa=(Txtln **)malloc((lsp->mny+1)*sizeof(Txtln *)))==NULL)
		abort("can't alloc Txtlns.lpa array");
	for(li=0; li<lsp->mny; li++) {
		*(lpp++) = lp = alloc_txtln();
		frdb_txtln_etc(fp,lp,etc);
		};
	*lpp = NULL;
	if(ferror(fp)) return(-errno); else return(1);
	}

/* Append a txtln to the end of a txtlns set. 
   Do NOT maintain Txtlns in order sorted ascending on Txtln.bx.a.y.
   Return appended Txtln *. */
Txtln *append_txtln(lp,lsp)
    Txtln *lp;
    Txtlns *lsp;
{   register Txtln *rp,**rpp,**npp;
	if(lsp->mny==0) {
		if((lsp->lpa=(Txtln **)malloc(2*sizeof(Txtln *)))==NULL)
			abort("append_txtln: can't malloc lsp->lpa");
		}
	else {	if((lsp->lpa=(Txtln **)realloc(
				lsp->lpa,
				(lsp->mny+2)*sizeof(Txtln *))
				)==NULL)
			abort("append_txtln: can't realloc lsp->lpa");
		};
	lsp->lpa[lsp->mny] = lp;
	lsp->lpa[++lsp->mny] = NULL;
	return(lp);
	}

/* remove a txtln from a txtlns set */
remove_txtln(lp,lsp)
    Txtln *lp;
    Txtlns *lsp;
{   register Txtln *rp,**rpp,**npp;
	if(lsp->mny==0) err("can't remove Txtln - Txtlns empty");
	else {	for(rp= *(rpp=lsp->lpa); rp!=NULL; rp= *(++rpp)) if(rp==lp) break;
		if(rp==NULL) err("can't remove Txtln - not found");
		else {	/* move later entries up */
			npp=rpp+1;
			do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
			if((--(lsp->mny))==0) {free(lsp->lpa); lsp->lpa=NULL;};
			/* don't bother to realloc downwards */
			};
		};
	}

free_txtln_etc(p,etc)
    Txtln *p;
    Ident etc;
{	free_words_etc(&(p->ws),etc);
	free_chars_etc(&(p->cs),etc);
	free_blobs_etc(&(p->bs),etc);
	if(p->ident&Txtln_label && p->l!=NULL) {
		free(p->l);  p->l=NULL;  p->ident &= ~Txtln_label;
		};
	if(etc&IsTxtln) {
		if(p->l!=NULL) free(p->l);
		free(p);
		free_census(Txtln,1);
		};
	}

/* Unconditionally free the malloc-space array of pointers, and empty the set.
   Don't free the records that it owned.
   */
free_txtlns(lsp)
    Txtlns *lsp;
{   	if(lsp->lpa!=NULL) { free(lsp->lpa); lsp->lpa = NULL; }
	lsp->mny = 0;
	}

free_txtlns_etc(lsp,etc)
    Txtlns *lsp;
    Ident etc;
{   register Txtln *lp,**lpp;
	if(lsp->mny>0&&(etc&IsTxtln))
		for(lp= *(lpp=lsp->lpa); lp!=NULL; lp= *(++lpp))
			free_txtln_etc(lp,etc);
   	free_txtlns(lsp);
	}

/* return a pointer to a distinct and duplicate copy of *lp,
   created out of malloc space */
Txtln *dup_txtln(lp)
    Txtln *lp;
{   Txtln *dup;
	if((dup=(Txtln *)malloc(sizeof(Txtln)))==NULL)
		abort("can't dup Txtln");
	alloc_census(Txtln,1);
	*dup = *lp;
	return(dup);
	}

/* Return a pointer to a distinct and duplicate copy of *lp, and its parts
   as specified by `etc', created out of malloc space. */
Txtln *dup_txtln_etc(lp,etc)
    Txtln *lp;
    Ident etc;
{   Txtln *dup;
	dup = dup_txtln(lp);
	if(etc&IsBlob&&dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(lp->bs),etc);
	else dup->bs = empty_Blobs;
	if(etc&IsChar&&dup->cs.mny>0) dup->cs = *dup_chars_etc(&(lp->cs),etc);
	else dup->cs = empty_Chars;
	if(etc&IsWord&&dup->ws.mny>0) dup->ws = *dup_words_etc(&(lp->ws),etc);
	else dup->ws = empty_Words;
	return(dup);
	}

/* Return a pointer to a distinct local static duplicate of non-empty *lsp.
   Its lpa array is created newly out of malloc space.
   If etc&IsTxtln, all its Txtlns are also duplicated,
   else the contents of lpa point to the old unduplicated Txtlns.
   */
Txtlns *dup_txtlns_etc(lsp,etc)
    Txtlns *lsp;
    Ident etc;		/* parts to duplicate */
{   static Txtlns dup;
    register Txtln **lpp,**dpp;
	if((dup.mny = lsp->mny)<=0) dup = empty_Txtlns;
	else {	if((dup.lpa=(Txtln **)malloc((dup.mny+1)*sizeof(Txtln *)))==NULL)
			abort("can't dup ls.lpa");
		for(lpp=lsp->lpa,dpp=dup.lpa; *lpp!=NULL; lpp++,dpp++) {
			if(etc&IsTxtln) *dpp = dup_txtln_etc(*lpp,etc);
			else *dpp = *lpp;
			};
		*dpp = NULL;
		};
	return(&dup);
	}

Word *alloc_word()
{    Word *p;
	if((p=(Word *)malloc(sizeof(Word)))==NULL)
		abort("can't alloc Word");
	alloc_census(Word,1);
	*p = empty_Word;
	return(p);
	}

char *word_toa(p)
    Word *p;
{    static char s[80];
	sprintf(s,"%s bx%s ws%0.2f c%d b%d m%s w%d",
		ident_toa(p->ident),
		bbx_toa(&(p->bx)),
		p->wsp,
		p->cs.mny,p->bs.mny,merit_toa(p->m),p->ws.mny);
	return(s);
	}

/* Are two Words identical?  A not quite exhaustively-detailed test. */
boolean eq_word(w1,w2)
    Word *w1,*w2;
{   register Char **c1,**c2;
	if(w1->cs.mny!=w2->cs.mny) return(F);
	for(c1=w1->cs.cpa,c2=w2->cs.cpa; *c1!=NULL; c1++,c2++) {
		if((*c1)->area!=(*c2)->area) return(F);
		if(!bbx_eq(&((*c1)->bx),&((*c2)->bx))) return(F);
		if((*c1)->bmny!=(*c2)->bmny) return(F);
		};
	/* don't bother to compare Blob lists in detail (they aren't
	   in any particular order). */
	return(T);
	}

/* Compute a hash key for this Word that is likely to indicate whether or
   not it is geometrically identical to another Word. */
int hash_word(w)
    Word *w;
{   register int k;
    register Char **c;
	if(w->cs.mny==0) return(0);
	k = w->bx.a.x * w->bx.a.y * w->bx.b.x * w->bx.b.y;
	for(c=w->cs.cpa; (*c)!=NULL; c++) {
		k += (*c)->bx.a.x * (*c)->bx.a.y * (*c)->bx.b.x
			* (*c)->bx.b.y * (*c)->bmny * (*c)->area;
		};
	return(k);
	}

#if FWRI
fwrb_word(f,p)
    FILE *f;
    Word *p;
{
#if dbg_fwrb
	if((!(p->ident&IsWord))||(p->ident&(IsALL&(~IsWord))))
		err("fwrb_word: %s",word_toa(p));
	if(p->ident&Word_label && p->l==NULL) {
		err("fwrb_page: Word_label set but .l==NULL");
		p->ident &= ~Word_label;
		};
#endif
	fwri_Ident(f,p->ident);
	fwri_Bbx(f,&(p->bx));
	fwri_int2(f,p->wsp*UCHAR_MAX);
	fwri_Merit(f,p->m);
	fwri_Prob(f,p->p);
	fwri_uint2(f,p->ws.mny);
	fwri_uint2(f,p->cs.mny);
	fwri_uint3(f,p->bs.mny);
	/* fwri_int4(f,p->hash); */
#if dbg_fwrb_toa
	err("fwrb_word: %s",word_toa(p));
#endif
	if(p->ident&Word_label) fwrb_label(f,p->l);
	}
#else
fwrb_word(fp,wp)
    FILE *fp;
    Word *wp;
{   WordF wf;
    int stat;
#if dbg_fwrb
	if((!(wp->ident&IsWord))||(wp->ident&(IsALL&(~IsWord))))
		err("fwrb_word: %s",word_toa(wp));
#endif
	memset(&wf,'\0',sizeof(wf));
	wf.ident = wp->ident;
	wf.bx = wp->bx;
	wf.wsp = wp->wsp;
	wf.m = wp->m;
	wf.wmny = wp->ws.mny;
	wf.cmny = wp->cs.mny;
	wf.bmny = wp->bs.mny;
	if((stat=fwrite(&wf,sizeof(WordF),1,fp))!=1)
		abort("can't write WordF, status %d",stat);
#if dbg_fwrb_toa
	err("fwrb_word: %s",word_toa(wp));
#endif
	if(wf.ident&Word_label) fwrb_label(fp,wp->l);
	}
#endif

fwrb_words_etc(fp,ws,etc)
    FILE *fp;
    Words ws;
    Ident etc;
{   register Word *wp,**wpp;
	if(ws.mny>0) for(wp= *(wpp=ws.wpa); wp!=NULL; wp= *(++wpp))
		fwrb_word_etc(fp,wp,etc);
	}

fwrb_word_etc(fp,wp,etc)
    FILE *fp;
    Word *wp;
    Ident etc;
{   static Ident parts = (IsWord|IsChar|IsBlob);
    Word wd;
   	if((etc&parts)!=parts) /* write selected parts */ {
		wd = *wp;
		if(!(etc&IsWord)) wd.ws.mny=0;
		if(!(etc&IsChar)) wd.cs.mny=0;
		if(!(etc&IsBlob)) wd.bs.mny=0;
		wp = &wd;	/* write modified record */
		};
	fwrb_word(fp,wp);
	if(etc&IsWord) fwrb_words_etc(fp,wp->ws,IsALL);
	fwrb_chars_etc(fp,wp->cs,etc);
	fwrb_blobs_etc(fp,wp->bs,etc);
	}

#if FRDI
int frdb_word(f,p)
    FILE *f;
    Word *p;
{	*p = empty_Word;
	if(feof(f))
		return(0);
	p->ident=frdi_Ident(f);
	frdi_Bbx(f,&(p->bx));
	p->wsp=frdi_int2(f)/(float)UCHAR_MAX;
	p->m=frdi_Merit(f);
	p->p=frdi_Prob(f);
	p->ws.mny=frdi_uint2(f);
	p->cs.mny=frdi_uint2(f);
	p->bs.mny=frdi_uint3(f);
	/* p->hash=frdi_int4(f); */
#if dbg_frdb
	if((!(p->ident&IsWord))||(p->ident&(IsALL&(~IsWord))))
		err("frdb_word: %s",word_toa(p));
#endif
#if dbg_frdb_toa
	err("frdb_word: %s",word_toa(p));
#endif
	if(p->ident&Word_label) p->l = frdb_label(f);
	if(ferror(f)) return(-errno); else return(1);
	}
#else
int frdb_word(fp,wp)
    FILE *fp;
    Word *wp;
{   WordF wf;
    int stat;
	if((stat=fread(&wf,sizeof(WordF),1,fp))!=1)
		abort("can't read WordF, status %d",stat);
	*wp = empty_Word;
	wp->ident = wf.ident;
	wp->bx = wf.bx;
	wp->wsp = wf.wsp;
	wp->m = wf.m;
	wp->ws.mny = wf.wmny;
	wp->cs.mny = wf.cmny;
	wp->bs.mny = wf.bmny;
#if dbg_frdb
	if((!(wp->ident&IsWord))||(wp->ident&(IsALL&(~IsWord))))
		err("frdb_word: %s",word_toa(wp));
#endif
#if dbg_frdb_toa
	err("frdb_word: %s",word_toa(wp));
#endif
	if(wp->ident&Word_label) wp->l = frdb_label(fp);
	if(ferror(fp)) return(-errno); else return(1);
	}
#endif

frdb_word_etc(fp,wp,etc)
    FILE *fp;
    Word *wp;
    Ident etc;
{   WordF cf;
    int stat;
	frdb_word(fp,wp);
	frdb_words_etc(fp,&(wp->ws),IsALL); /* rd alternatives entirely, if any */
	if(etc&IsChar && wp->cs.mny>0)
		frdb_chars_etc(fp,&(wp->cs),etc);
	else wp->cs = empty_Chars;
	if(etc&IsBlob && wp->bs.mny>0)
		frdb_blobs_etc(fp,&(wp->bs),etc);
	else wp->bs = empty_Blobs;
	if(ferror(fp)) return(-errno); else return(1);
	}

/* read words, and their parts */
frdb_words_etc(fp,wsp,etc)
    FILE *fp;
    Words *wsp;
    Ident etc;
{   int wi;
    register Word *wp,**wpp;
	if(wsp->mny<=0) {
		*wsp = empty_Words;
		return(1);
		};
	if((wpp=wsp->wpa=(Word **)malloc((wsp->mny+1)*sizeof(Word *)))==NULL)
		abort("can't alloc Words.wpa array");
	for(wi=0; wi<wsp->mny; wi++) {
		*(wpp++) = wp = alloc_word();
		frdb_word_etc(fp,wp,etc);
		};
	*wpp = NULL;
	if(ferror(fp)) return(-errno); else return(1);
	}

/* remove a word from a words set */
remove_word(wp,wsp)
    Word *wp;
    Words *wsp;
{   register Word *rp,**rpp,**npp;
	if(wsp->mny==0) err("can't remove Word - Words empty");
	else {	for(rp= *(rpp=wsp->wpa); rp!=NULL; rp= *(++rpp)) if(rp==wp) break;
		if(rp==NULL) err("can't remove Word - not found");
		else {	/* move later entries up */
			npp=rpp+1;
			do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
			if((--(wsp->mny))==0) {free(wsp->wpa); wsp->wpa=NULL;};
			/* don't bother to realloc downwards */
			};
		};
	}

/* Remove a Word from a Txtln's Words set.
   Shrink the Txtln's Bbx if the Word abuts it on the left or right.
   Ensure that the first Word in the line has wsp==0.0
   BUG:  doesn't update wsp of trailing Word */
remove_word_txtln(wp,lp)
    Word *wp;
    Txtln *lp;
{   register Word *cwp,**wpp;
	remove_word(wp,&(lp->ws));
	if(lp->ws.mny>0) {
	   	if(wp->bx.a.x==lp->bx.a.x || wp->bx.b.x==lp->bx.b.x) {
			/* recompute possibly shrunken bx */
			lp->bx=empty_Bbx;
			for(cwp= *(wpp=lp->ws.wpa); cwp!=NULL; cwp= *(++wpp))
				merge_bbx(&(cwp->bx),&(lp->bx));
			};
		(lp->ws.wpa[0])->wsp=0.0;
		};
	}

/* Append a word to the end of a words set.
   Do NOT maintain set in order ascending on Word.bx.a.x.
   Return the appended Word. */
Word *append_word(wp,wsp)
    Word *wp;
    Words *wsp;
{	if(wsp->mny==0) {
		if((wsp->wpa=(Word **)malloc(2*sizeof(Word *)))==NULL)
			abort("append_word: can't malloc wsp->wpa");
		}
	else {	if((wsp->wpa=(Word **)realloc(
				wsp->wpa,
				(wsp->mny+2)*sizeof(Word *))
				)==NULL)
			abort("append_word: can't realloc wsp->wpa");
		};
	wsp->wpa[wsp->mny++] = wp;
	wsp->wpa[wsp->mny] = NULL;
	return(wp);
	}

/* Insert a Word into a Words set.  Words is assumed to be sorted ascending
   on Word.bx.a.x, and this order is maintained.
   Words with equal Word.bx.a.x are stored in the order that they were
   inserted:  so that the first one inserted remains the first among equals
   (this feature is important for certain WordSet applications).
   Return inserted (Word *) */
Word *insert_word(wp,wsp)
    Word *wp;
    Words *wsp;
{   register Word **wpp,*nwp,*pwp;
	if(wsp->mny==0) {
		if((wsp->wpa=(Word **)malloc(2*sizeof(Word *)))==NULL)
			abort("insert_word: can't malloc wsp->wpa");
		wsp->wpa[wsp->mny] = wp;
		}
	else {	if((wpp=wsp->wpa=(Word **)realloc(
				wsp->wpa,
				(wsp->mny+2)*sizeof(Word *))
				)==NULL)
			abort("insert_word: can't realloc wsp->wpa");
		while(((*wpp)!=NULL)&&(*wpp)->bx.a.x<=wp->bx.a.x) wpp++;
		/* **wpp is now 1st entry > *wp in sorted order; insert
		   new word just before it */
		pwp=wp;
		do {	nwp= *wpp;
			*(wpp++)=pwp;
			pwp=nwp;
			}
		while(pwp!=NULL);
		};
	wsp->wpa[++wsp->mny] = NULL;
	return(wp);
	}

/* Insert a Word into the Words owned by a given Txtln,
   maintaining the Txtln's Bbx and sorted order in the Words set.
   Return the inserted Word * */
Word *insert_word_txtln(wp,lp)
    Word *wp;
    Txtln *lp;
{	merge_bbx(&(wp->bx),&(lp->bx));
	return(insert_word(wp,&(lp->ws)));
	}

/* Free wordinterp and its parts as specified in etc.
   Always free its strings (if any).
   If etc&IsWordInterp, free the record itself also.
*/
free_wordinterp_etc(p,etc)
    WordInterp *p;
    Ident etc;
{	if(p->s!=NULL) { free(p->s);  p->s=NULL; };
	if(p->pp!=NULL) { free(p->pp);  p->pp=NULL; };
	if(p->by!=NULL) { free(p->by);  p->by=NULL; };
	if(p->po!=NULL) { free(p->po);  p->po=NULL; };
	if(p->ps!=NULL) { free(p->ps);  p->ps=NULL; };
	if(etc&IsWordInterp) free(p);
	}

/* Duplicate (return ptr to local static copy of) a WordInterp.
   Always free its strings (if any).
   'etc' is ignored.
*/
WordInterp *dup_wordinterp_etc(p,etc)
    WordInterp *p;
    Ident etc;
{   static WordInterp d;
	d = *p;
	if(p->s!=NULL) d.s = strdup(p->s);
	if(p->pp!=NULL) d.pp = strdup(p->pp);
	if(p->by!=NULL) d.by = strdup(p->by);
	if(p->po!=NULL) d.po = strdup(p->po);
	if(p->ps!=NULL) d.ps = strdup(p->ps);
	return(&d);
	}

/* Unconditionally free the malloc-space array of pointers, and empty the set.
   Don't free the records that it owned.
   */
free_words(wsp)
    Words *wsp;
{   	if(wsp->wpa!=NULL) { free(wsp->wpa); wsp->wpa = NULL; }
	wsp->mny = 0;
	}

free_words_etc(wsp,etc)
    Words *wsp;
    Ident etc;
{   register Word *wp,**wpp;
    int wi;
	if(wsp->mny>0&&(etc&IsWord))
		for(wp= *(wpp=wsp->wpa); wp!=NULL; wp= *(++wpp))
			free_word_etc(wp,etc);
   	free_words(wsp);
	}

/* return a pointer to a distinct and duplicate copy of *wp,
   created out of malloc space */
Word *dup_word(wp)
    Word *wp;
{   Word *dup;
	if((dup=(Word *)malloc(sizeof(Word)))==NULL)
		abort("can't dup Word");
	alloc_census(Word,1);
	*dup = *wp;
	return(dup);
	}

/* Return a pointer to a distinct and duplicate copy of *wp, and ALL it owns,
   created out of malloc space. (HOW they are duplicated is controlled by flags
   in etc.) */
Word *dup_word_etc(wp,etc)
    Word *wp;
    Ident etc;
{   Word *dup;
	dup = dup_word(wp);
	if(dup->ws.mny>0) dup->ws = *dup_words_etc(&(wp->ws),etc);
	else dup->ws = empty_Words;
	if(dup->cs.mny>0) dup->cs = *dup_chars_etc(&(wp->cs),etc);
	else dup->cs = empty_Chars;
	if(dup->bs.mny>0) dup->bs = *dup_blobs_etc(&(wp->bs),etc);
	else dup->bs = empty_Blobs;
	return(dup);
	}

/* Return a pointer to a distinct local static duplicate of non-empty *wsp.
   Its wpa array is created newly out of malloc space.
   If etc&IsWord, all its Words are also duplicated,
   else the contents of wpa point to the old unduplicated Words.
   */
Words *dup_words_etc(wsp,etc)
    Words *wsp;
    Ident etc;		/* parts to duplicate */
{   static Words dup;
    register Word **wpp,**dpp;
	if((dup.mny=wsp->mny)<=0) dup = empty_Words;
	else {	if((dup.wpa=(Word **)malloc((dup.mny+1)*sizeof(Word *)))==NULL)
			abort("can't dup ws.wpa");
		for(wpp=wsp->wpa,dpp=dup.wpa; *wpp!=NULL; wpp++,dpp++) {
			if(etc&IsWord) *dpp = dup_word_etc(*wpp,etc);
			else *dpp = *wpp;
			};
		*dpp = NULL;
		};
	return(&dup);
	}

WordInterp *alloc_wordinterp()
{    WordInterp *p;
	if((p=(WordInterp *)malloc(sizeof(WordInterp)))==NULL)
		abort("can't alloc WordInterp");
	else {	*p = empty_WordInterp;
		return(p);
		};
	}

char *wordinterp_toa(p)
    WordInterp *p;
{    static char s[80];
	sprintf(s,"%s %s %s|%s|%s|%s",
		ident_toa(p->ident),
		((p->s!=NULL)? p->s: ""),
		((p->pp!=NULL)? p->pp: ""),
		((p->by!=NULL)? p->by: ""),
		((p->po!=NULL)? p->po: ""),
		((p->ps!=NULL)? p->ps: "")
		);
	return(s);
	}

/* Free Word and its parts, as specified by etc.
   Always free the pointer-arrays of ws, cs & bs.
   If etc&IsWord, free all Words in ws also.
   If etc&IsChar, free all Chars in cs also.
   If etc&IsBlob, free all Blobs in bs also.
*/
free_word_etc(p,etc)
    Word *p;
    Ident etc;
#define dbg_fwe (F)
{	if(dbg_fwe) {
		err("free_word_etc: %s",word_toa(p));
		err("free_word_etc: %s",ident_toa(etc));
		err_census_all;
		};
	free_words_etc(&(p->ws),IsALL);
	free_chars_etc(&(p->cs),etc);
	free_blobs_etc(&(p->bs),etc);
	if(p->ident&Word_label && p->l!=NULL) {
		free(p->l);  p->l=NULL;  p->ident &= ~Word_label;
		};
	if(etc&IsWord) free_word(p);
	if(dbg_fwe) err_census_all;
	}

free_word(wp)
    Word *wp;
{	free(wp);
	free_census(Word,1);
	}

fwrb_sfeats(fp,sfv)
    FILE *fp;
    SFv sfv;
{   register Pval *vp,*vq;
	for(vq=(vp=sfv)+SF_MNY; vp<vq; vp++)
		fwri_int3(fp,USHRT_MAX*(*vp)+0.5);
#if dbg_fwrb_toa
	/** err("fwrb_sfeats: %s",sfeats_toa(sfv)); **/
#endif
	}

int frdb_sfeats(fp,sfv)
    FILE *fp;
    SFv sfv;
{   register Pval *vp,*vq;
	for(vq=(vp=sfv)+SF_MNY; vp<vq; vp++)
		*vp = frdi_int3(fp)/((Pval)USHRT_MAX);
#if dbg_frdb_toa
	/** err("frdb_sfeats: %s",sfeats_toa(sfv)); **/
#endif
	}

/* return ptr to local static copy of Shapes of given size */
Shapes *alloc_shapes(mny)
    int mny;
{   static Shapes shs;
	shs.mny = shs.alloc = mny;
	if((shs.sa=(Nb_s *)malloc(shs.alloc*sizeof(Nb_s)))==NULL)
		abort("can't alloc Shapes.sa[%d]",shs.alloc);
	return(&shs);
	}

fwrb_shapes(fp,p)
    FILE *fp;
    Shapes *p;	/* on entry, p->mny has already been written */
{   int dim;
    register Nb_s *sp,*sq;
    register Pval *vp;
	if(p->mny>0&&p->sa!=NULL) {
		for(sq=(sp=p->sa)+p->mny; sp<sq; sp++) {
			dim=Sh_dim[sp->t&(~Sh_tiny)];
			fwri_uint1(fp,(sp->t&0x7F)|((sp->t&Sh_tiny)?0x80:0x00));
			fwri_int2(fp,(*(vp=sp->p))*SHRT_MAX);
			if(dim>1) { fwri_int2(fp,(*(++vp))*SHRT_MAX);
			 if(dim>2) { fwri_int2(fp,(*(++vp))*SHRT_MAX);
			  if(dim>3) { fwri_int2(fp,(*(++vp))*SHRT_MAX);
				} } };
			};
		};
#if dbg_fwrb_toa
	/** err("fwrb_shapes: %s",shapes_toa(p)); **/
#endif
	}

int frdb_shapes(fp,p)
    FILE *fp;
    Shapes *p;	/* on entry, p->mny has already been read */
{   register Nb_s *sp,*sq;
    register Pval *vp;
    uint1 ui1;
    int dim;
    
	if(p->mny>0) {
		*p = *alloc_shapes(p->mny);
		for(sq=(sp=p->sa)+p->mny; sp<sq; sp++) {
			ui1 = frdi_uint1(fp);
			sp->t = ui1&0x7F|((ui1&0x80)?Sh_tiny:0);
			dim=Sh_dim[sp->t&(~Sh_tiny)];
			*(vp=sp->p) = ((float)frdi_int2(fp))/SHRT_MAX;
			if(dim>1) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX;
			 if(dim>2) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX;
			  if(dim>3) { *(++vp) = ((float)frdi_int2(fp))/SHRT_MAX;
				} } };
			};
		}
	else {	p->alloc = 0;
		if(p->sa!=NULL) free(p->sa);
		p->sa = NULL;
		};
#if dbg_frdb_toa
	/** err("frdb_shapes: %s",shapes_toa(p)); **/
#endif
	}

fwra_shapes_etc(fp,p,t)
    FILE *fp;
    Shapes *p;
    char *t;	/* string of shape types (empty => all) */
{   Nb_s *s;
    int i,j;
    char a[80],f[10];
	for(i=0,s=p->sa; i<p->mny; i++,s++) {
		if(t[0]=='\0'||strchr(t,Sh_nam[s->t&(~Sh_tiny)])!=NULL) {
			sprintf(a,"%c%c ",
				Sh_nam[s->t&(~Sh_tiny)],
				(s->t&Sh_tiny)?'\'':' '
				);
			for(j=0;j<Sh_dim[s->t&(~Sh_tiny)];j++) {
				sprintf(f," %0.3f",s->p[j]);
				strcat(a,f);
				};
			fprintf(fp,"%s\n",a);
			};
		};
	}

err_shapes(shp)
    Shapes *shp;
{   int si,di;
    Nb_s *sp;
	fprintf(stderr,"shapes %d:\n",shp->mny);
	for(si=0,sp=shp->sa; si<shp->mny; si++,sp++) {
		fprintf(stderr,"  %c",Sh_nam[sp->t]);
		for(di=0; di<Sh_dim[sp->t]; di++)
			fprintf(stderr," %6.3f",sp->p[di]);
		fprintf(stderr,"\n");
		};
	}

/* Unconditionally free the malloc-space array of pointers, and empty the set.
   Don't free the records that it owned.
   */
free_shapes(shp)
    Shapes *shp;
{	if(shp->sa!=NULL) {
		if(shp->alloc<=0) abort("can't free unalloc'ed shapes");
		else { free(shp->sa); shp->sa=NULL; };
		};
	shp->mny = shp->alloc = 0;
	}

/* functions for RanParms */

RanParms *alloc_ranparms()
{    RanParms *rp;
	if((rp=(RanParms *)malloc(sizeof(RanParms)))==NULL)
		abort("alloc_ranparms: can't alloc");
	*rp = empty_RanParms;
	return(rp);
	}

free_ranparms(ran)
    RanParms *ran;
{   	free(ran);
	}

RanParms *dup_ranparms(p)
    RanParms *p;
{   RanParms *dup;
	dup = alloc_ranparms();
	*dup = *p;
	return(dup);
	}

char *ranparms_toa(ran,select)
    RanParms *ran;
    char *select;	/* a string, subset of: "*rpabejkstxy" if "*" or "" ALL */
{   static char s[200];
    char p[20];
    char *cp;
    static char select_all[] = "abejkprstxy";
	s[0]='\0';
	if(select[0]=='*'||select[0]=='\0') select=select_all;
	for(cp=select; *cp!='\0'; cp++) {
	    switch(*cp) {
		case 'a':  sprintf(p,"a%0.3f ",ran->skew/DtoR);  strcat(s,p);  break;
		case 'b':  sprintf(p,"b%0.3f ",ran->bhgt);  strcat(s,p);  break;
		case 'e':  sprintf(p,"e%0.3f ",ran->blur);  strcat(s,p);  break;
		case 'j':  sprintf(p,"j%0.3f ",ran->jitter);  strcat(s,p);  break;
		case 'k':  sprintf(p,"k%0.3f ",ran->kern);  strcat(s,p);  break;
		case 'p':  sprintf(p,"p%g ",ran->size);  strcat(s,p);  break;
		case 'r':  sprintf(p,"r%d,%d ",ran->res_x,ran->res_y);  strcat(s,p);  break;
		case 's':  sprintf(p,"s%0.4f ",ran->speckle);  strcat(s,p);  break;
		case 't':  sprintf(p,"t%0.3f ",ran->thresh);  strcat(s,p);  break;
		case 'x':  sprintf(p,"x%0.3f ",ran->xscale);  strcat(s,p);  break;
		case 'y':  sprintf(p,"y%0.3f ",ran->yscale);  strcat(s,p);  break;
		};
	    };
	return(s);
	}

RanParms *ato_ranparms(s)
    char *s;
{   static RanParms ran;
    char *f,n,*v;
#define TOKEN_SEP "=, \n"
	f=strtok(s,TOKEN_SEP);
	while(f!=NULL&&strlen(f)>0) {
		n=f[0];  v=f+1;
		switch(n) {
		    case 'r':	/* res */
			ran.res_x = atoi(v);
			v=strtok((char *)0,TOKEN_SEP);
			ran.res_y = atoi(v);
			break;
		    case 'p':	ran.size = atof(v);  break;
		    case 'a':	ran.skew = atof(v)*DtoR;  break;
		    case 'b':	ran.bhgt = atof(v);  break;
		    case 'e':	ran.blur = atof(v);  break;
		    case 'j':	ran.jitter = atof(v);  break;
		    case 'k':	ran.kern = atof(v);  break;
		    case 's':	ran.speckle = atof(v);  break;
		    case 't':	ran.thresh = atof(v);  break;
		    case 'x':	ran.xscale = atof(v);  break;
		    case 'y':	ran.yscale = atof(v);  break;
		    };
		f=strtok((char *)0,TOKEN_SEP);
		};
	return(&ran);
	}

#if FWRI
fwrb_ranparms(f,p)
    FILE *f;
    RanParms *p;
{	fwri_int2(f,p->res_x);
	fwri_int2(f,p->res_y);
	fwri_Pts(f,p->size);
	fwri_Radians(f,p->skew);
	fwri_Ems(f,p->bhgt);
	fwri_int3(f,p->blur*10000.0);
	fwri_int3(f,p->jitter*10000.0);
	fwri_int3(f,p->kern*10000.0);
	fwri_int3(f,p->speckle*10000.0);
	fwri_int3(f,p->thresh*10000.0);
	fwri_int3(f,p->xscale*10000.0);
	fwri_int3(f,p->yscale*10000.0);
#if dbg_fwrb_toa
	err("fwrb_ranparms: %s",ranparms_toa(p));
#endif
	}
#else
fwrb_ranparms(f,p)
    FILE *f;
    RanParms *p;
{   	if((fwrite(p,sizeof(RanParms),1,f))!=1) return(0);
#if dbg_fwrb_toa
	err("fwrb_ranparms: %s",ranparms_toa(p));
#endif
	}
#endif

#if FRDI
int frdb_ranparms(f,p)
    FILE *f;
    RanParms *p;
{	*p = empty_RanParms;
	if(feof(f))
		return(0);
	p->res_x=frdi_int2(f);
	p->res_y=frdi_int2(f);
	p->size=frdi_Pts(f);
	p->skew=frdi_Radians(f);
	p->bhgt=frdi_Ems(f);
	p->blur=frdi_int3(f)/10000.0;
	p->jitter=frdi_int3(f)/10000.0;
	p->kern=frdi_int3(f)/10000.0;
	p->speckle=frdi_int3(f)/10000.0;
	p->thresh=frdi_int3(f)/10000.0;
	p->xscale=frdi_int3(f)/10000.0;
	p->yscale=frdi_int3(f)/10000.0;
#if dbg_frdb_toa
	err("frdb_ranparms: %s",ranparms_toa(p));
#endif
	if(ferror(f)) return(-errno); else return(1);
	}
#else
int frdb_ranparms(fp,ran)
    FILE *fp;
    RanParms *ran;
{   	if((fread(ran,sizeof(RanParms),1,fp))<1) return(0);
#if dbg_frdb_toa
	err("frdb_ranparms: %s",ranparms_toa(ran));
#endif
	}
#endif

Char *alloc_char()
{    Char *p;
	if((p=(Char *)malloc(sizeof(Char)))==NULL)
		abort("can't alloc Char");
	alloc_census(Char,1);
	*p = empty_Char;
	return(p);
	}

char *char_toa(cp)
    Char *cp;
{   static char s[100],bfs[24];
	if(cp->bfsp==NULL) strcpy(bfs,"0");
	else if(cp->bfsp->bm.n==0) strcpy(bfs,"0");
	else if(cp->bfsp->bm.mny==0) sprintf(bfs,"%d",cp->bfsp->bm.n);
	else sprintf(bfs,"%d,%d",cp->bfsp->bm.n,cp->bfsp->bm.mny);
	sprintf(s,"%s bx%s w%d,h%d cs%d bl%d ar%d pe%d sf%d sh%d bf%s i%d",
		ident_toa(cp->ident),
		bbx_toa(&(cp->bx)),
		bbx_wid(&cp->bx),bbx_hgt(&cp->bx),
		cp->csp,
		cp->bmny,
		cp->area,cp->per,
		(cp->sfv==NULL)? 0: 1,
		cp->sh.mny,
		bfs,
		cp->il.mny
		);
	return(s);
	}

/* compute the centroid of the Char (offset from bx.a) */
Pp *char_centroid(cp)
    Char *cp;
{   static Pp c;
    Pp *bc;	/* blob centroid */
    Blob *bp;
    int bi;
	c.x = c.y = 0.0;
	for(bi=0, bp=cp->fi; bi<cp->bmny; bi++, bp=bp->n) {
		bc = blob_centroid(bp);
		c.x += bp->area * (bc->x + (cp->bx.a.x - cp->bx.a.x));
		c.y += bp->area * (bc->y + (cp->bx.a.y - cp->bx.a.y));
		};
	c.x /= cp->area;
	c.y /= cp->area;
	return(&c);
	}

#if FWRI
fwrb_char(f,p)
    FILE *f;
    Char *p;
{
#if dbg_fwrb
	if((!(p->ident&IsChar))||(p->ident&(IsALL&(~IsChar))))
		err("fwrb_char: %s",char_toa(p));
	if(p->ident&Char_label && p->l==NULL) {
		err("fwrb_page: Char_label set but .l==NULL");
		p->ident &= ~Char_label;
		};
	if(p->ident&Char_ranparms && p->rp==NULL) {
		err("fwrb_page: Char_ranparms set but .rp==NULL");
		p->ident &= ~Char_ranparms;
		};
#endif
	fwri_Ident(f,p->ident);
	fwri_Bbx(f,&(p->bx));
	fwri_Scoor(f,p->csp);
	fwri_uint4(f,p->area);
	fwri_uint4(f,p->per);
	fwri_Scoor(f,p->basl);
	fwri_uint3(f,p->bmny);
	fwri_uint2(f,p->il.mny);
	fwri_uint1(f,(p->sfv!=NULL)?SF_MNY:0);
	fwri_uint2(f,p->sh.mny);
	fwri_uint2(f,(p->bfsp!=NULL)?p->bfsp->bm.n:0);
#if dbg_fwrb_toa
	err("fwrb_char: %s",char_toa(p));
#endif
	if(p->ident&Char_label) fwrb_label(f,p->l);
	if(p->ident&Char_ranparms) fwrb_ranparms(f,p->rp);
	}
#else
fwrb_char(fp,cp)
    FILE *fp;
    Char *cp;
{   CharF cf;
    int stat;
#if dbg_fwrb
	if((!(cp->ident&IsChar))||(cp->ident&(IsALL&(~IsChar))))
		err("fwrb_char: %s",char_toa(cp));
#endif
	memset(&cf,'\0',sizeof(cf));
	if(cp->ident&Char_ranparms && cp->rp==NULL)
		cp->ident &= ~Char_ranparms;
	cf.ident = cp->ident | IsChar;
	cf.bx = cp->bx;
	cf.csp = cp->csp;
	cf.area = cp->area;
	cf.per = cp->per;
	/* basl omitted */
	cf.bmny = cp->bmny;
	cf.imny = cp->il.mny;
	cf.sfmny = (cp->sfv!=NULL)?SF_MNY:0;
	cf.shmny = cp->sh.mny;
	if(cp->bfsp!=NULL) cf.bfmny = cp->bfsp->bm.n; else cf.bfmny=0;
	if((stat=fwrite(&cf,sizeof(CharF),1,fp))!=1)
		abort("can't write CharF, status %d",stat);
#if dbg_fwrb_toa
	err("fwrb_char: %s",char_toa(cp));
#endif
	if(cf.ident&Char_ranparms) fwrb_ranparms(fp,cp->rp);
	if(cf.ident&Char_label) fwrb_label(fp,cp->l);
	}
#endif

fwrb_chars_etc(fp,cs,etc)
    FILE *fp;
    Chars cs;
    Ident etc;
{   register Char *cp,**cpp;
	if(cs.mny>0) for(cp= *(cpp=cs.cpa); cp!=NULL; cp= *(++cpp))
		fwrb_char_etc(fp,cp,etc);
	}

fwrb_char_etc(fp,cp,etc)
    FILE *fp;
    Char *cp;
    Ident etc;
{   static Ident parts = (IsInterp|IsBlob|IsShapes|IsBfeats|IsSfeats);
    Char ch;
   	if((etc&parts)!=parts) /* write selected parts */ {
		ch = *cp;
		if(!(etc&IsInterp)) ch.il.mny=0;
		if(!(etc&IsBlob)) ch.bmny=0;
		if(!(etc&IsSfeats)) ch.sfv = NULL;
		if(!(etc&IsShapes)) ch.sh = empty_Shapes;
		if(!(etc&IsBfeats)) ch.bfsp = NULL;
		cp = &ch;	/* write modified record */
		};
	fwrb_char(fp,cp);
	if(cp->sfv!=NULL) fwrb_sfeats(fp,cp->sfv);
	if(cp->sh.mny>0) fwrb_shapes(fp,&(cp->sh));
#if CPU!=CRAY
	if(cp->bfsp!=NULL) fwrb_bfeats(fp,cp->bfsp);
#endif
	fwrb_interpl_etc(fp,cp->il,etc);
	if(cp->bmny>0) fwrb_blobl_etc(fp,cp->bmny,cp->fi,etc);
	}

#if FRDI
int frdb_char(f,p)
    FILE *f;
    Char *p;
{   int sf_mny,bf_mny;
	*p = empty_Char;
	if(feof(f))
		return(0);
	p->ident=frdi_Ident(f);
	frdi_Bbx(f,&(p->bx));
	p->csp=frdi_Scoor(f);
	p->area=frdi_uint4(f);
	p->per=frdi_uint4(f);
	p->basl=frdi_Scoor(f);
	p->bmny=frdi_uint3(f);
	p->il.mny=frdi_uint2(f);
	if((sf_mny=frdi_uint1(f))>0) {
		if((p->sfv=(Pval *)malloc(sf_mny*sizeof(Pval)))==NULL)
			abort("frdb_char: can't alloc p->sfv[%d]",sf_mny);
		memset(p->sfv,'\0',sf_mny*sizeof(Pval));
		};
	p->sh.mny=frdi_uint2(f);
	if((bf_mny=frdi_uint2(f))>0) {
		p->bfsp = alloc_bfeats(bf_mny,0);
		};
#if dbg_frdb
	if((!(p->ident&IsChar))||(p->ident&(IsALL&(~IsChar))))
		err("frdb_char: %s",char_toa(p));
#endif
#if dbg_frdb_toa
	err("frdb_char: %s",char_toa(p));
#endif
	if(p->ident&Char_label) p->l = frdb_label(f);
	if(p->ident&Char_ranparms) {
		p->rp = alloc_ranparms();
		frdb_ranparms(f,p->rp);
		};
	if(ferror(f)) return(-errno); else return(1);
	}
#else
int frdb_char(fp,cp)
    FILE *fp;
    Char *cp;
{   CharF cf;
    int stat;
	if((stat=fread(&cf,sizeof(CharF),1,fp))!=1)
		abort("frdb_char: can't read CharF, status %d",stat);
	*cp = empty_Char;
	cp->ident = cf.ident;
	cp->bx = cf.bx;
	cp->csp = cf.csp;
	cp->area = cf.area;
	cp->per = cf.per;
	cp->basl = 0;
	cp->bmny = cf.bmny;
	cp->il.mny = cf.imny;
	if(cf.sfmny>0) {
		if((cp->sfv=(Pval *)malloc(SF_MNY*sizeof(Pval)))==NULL)
			abort("frdb_char: can't alloc cp->sfv[%d]",SF_MNY);
		memset(cp->sfv,'\0',SF_MNY*sizeof(Pval));
		}
	else cp->sfv = NULL;
	cp->sh.mny = cf.shmny;
#if CPU!=CRAY
#if dbg_frdb
	if((!(cp->ident&IsChar))||(cp->ident&(IsALL&(~IsChar))))
		err("frdb_char: %s",char_toa(cp));
#endif
#endif
#if dbg_frdb_toa
	err("frdb_char: %s",char_toa(cp));
#endif
	if(cp->ident&Char_ranparms) {
		cp->rp = alloc_ranparms();
		frdb_ranparms(fp,cp->rp);
		};
	if(cp->ident&Char_label) cp->l = frdb_label(fp);
#if CPU!=CRAY
	if(cf.bfmny>0) cp->bfsp = alloc_bfeats(cf.bfmny,0);
	else 
#endif
	     cp->bfsp = NULL;
	if(ferror(fp)) return(-errno); else return(1);
	}
#endif

frdb_char_etc(fp,cp,etc)
    FILE *fp;
    Char *cp;
    Ident etc;
{	frdb_char(fp,cp);
	if(cp->sfv!=NULL) frdb_sfeats(fp,cp->sfv);
	if(cp->sh.mny>0) frdb_shapes(fp,&(cp->sh));
#if CPU!=CRAY
	if(cp->bfsp!=NULL) {
		frdb_bfeats(fp,cp->bfsp);
		};
#endif
	if(cp->il.mny>0) {
		frdb_interpl_etc(fp,&(cp->il),etc);
		/**if(!(etc&IsInterp)) free_interpl_etc(&(cp->il),IsALL);**/
		};
	if(etc&IsBlob && cp->bmny>0)
		frdb_blobl_etc(fp,cp->bmny,&(cp->fi),etc);
	else { cp->bmny = 0; cp->fi = NULL; };
	if(ferror(fp)) return(-errno); else return(1);
	}

/* read a set of chars, and parts */
frdb_chars_etc(fp,csp,etc)
    FILE *fp;
    Chars *csp;
    Ident etc;
{   int ci;
    register Char *cp,**cpp;
	if(csp->mny<=0) {
		*csp = empty_Chars;
		return(1);
		};
	if((cpp=csp->cpa=(Char **)malloc((csp->mny+1)*sizeof(Char *)))==NULL)
		abort("frdb_chars_etc:  can't alloc Chars.cpa array");
	for(ci=0; ci<csp->mny; ci++) {
		*(cpp++) = cp = alloc_char();
		frdb_char_etc(fp,cp,etc);
		};
	*cpp = NULL;
	if(ferror(fp)) return(-errno); else return(1);
	}

/* return a pointer to a distinct and duplicate copy of *cp;
   it is created out of malloc space.
   RanParms & label are treated as an integral part of the Char. */
Char *dup_char(cp)
    Char *cp;
{   Char *dup;
	if((dup=(Char *)malloc(sizeof(Char)))==NULL)
		abort("can't dup Char");
	alloc_census(Char,1);
	*dup = *cp;
	if(dup->ident&Char_label && dup->l!=NULL)
		dup->l = strdup(cp->l);
	else {dup->ident &= ~Char_label; dup->l = NULL;};
	if(dup->ident&Char_ranparms && dup->rp!=NULL)
		dup->rp = dup_ranparms(cp->rp);
	else {dup->ident &= ~Char_ranparms; dup->rp = NULL;};
	return(dup);
	}

/* return a pointer to a distinct and duplicate copy of *cp and those of
   its lists as specified by etc.  (Does not conform to practice for dup_word_etc.)
   */
Char *dup_char_etc(cp,etc)
    Char *cp;
    Ident etc;
{   Char *dup;
	dup = dup_char(cp);
	if(dup->bmny>0&&etc&IsBlob) dup->fi = dup_blobl_etc(cp->fi,etc);
	else {dup->bmny=0; dup->fi=NULL;};
	if(dup->il.mny>0&&etc&IsInterp) dup->il = *dup_interpl_etc(&(cp->il),etc);
	else dup->il = empty_Interpl;
	/**
	if(dup->sfv!=NULL>0&&etc&IsSfeats) dup->sfv = dup_sfeats(cp->sfv);
	else dup->sfv = NULL;
	if(dup->sh.mny>0&&etc&IsShapes) dup->sh = *dup_shapes(&cp->sh);
	else dup->sh = empty_Shapes;
	**/
#if CPU!=CRAY
	if(dup->bfsp!=NULL>0&&etc&IsBfeats) dup->bfsp = dup_bfeats(cp->bfsp);
	else 
#endif
	     dup->bfsp = NULL;
	return(dup);
	}

/* Return a pointer to a local static duplicate of non-empty *csp.
   Its cpa array is new, created out of malloc space.
   If etc&IsChar, all its Characters are also duplicated,
   else the contents of cpa point to the old unduplicated Chars.
   */
Chars *dup_chars_etc(csp,etc)
    Chars *csp;
    Ident etc;		/* parts to duplicate */
{   static Chars dup;
    register Char **cpp,**dpp;
	if((dup.mny=csp->mny)<=0) dup = empty_Chars;
	else {	if((dup.cpa=(Char **)malloc((dup.mny+1)*sizeof(Char *)))==NULL)
			abort("can't dup cs.cpa");
		for(cpp=csp->cpa,dpp=dup.cpa; (*cpp)!=NULL; cpp++,dpp++) {
			if(etc&IsChar) *dpp = dup_char_etc(*cpp,etc);
			else *dpp = *cpp;
			};
		*dpp = NULL;
		};
	return(&dup);
	}

err_chars(p)
    Chars *p;
{   register Char **cpp;
	fprintf(stderr,"Chars %d: ",p->mny);
	if(p->mny>0) for(cpp=p->cpa; (*cpp)!=NULL; cpp++)
		fprintf(stderr,"%X ",*cpp);
	fprintf(stderr,"\n");
	}

/* Make a Char out of a single Blob.  Return a freshly-allocated Char
   that owns the given Blob as is (not duplicated, copied or freed).
   The Blob's next pointer is set to NULL. */
Char *char_of_blob(b)
    Blob *b;
{   Char *c;
	c=alloc_char();
	c->bx = b->bx;
	c->area = b->area;
	c->per = b->per;
	c->bmny = 1;
	c->fi = b;
	b->n = NULL;
	return(c);
	}

Interp *alloc_interp()
{   Interp *new;
	if((new=(Interp *)malloc(sizeof(Interp)))==NULL)
		abort("alloc_interp: can't malloc");
	alloc_census(Interp,1);
	*new = empty_Interp;
	return(new);
	}

Interp *dup_interp(ip)
    Interp *ip;
{   Interp *dup;
	if((dup=(Interp *)malloc(sizeof(Interp)))==NULL)
		abort("dup_interp: can't malloc");
	alloc_census(Interp,1);
	*dup = *ip;
	return(dup);
	}

/* Print the interpl */
fwra_interpl(fp,ilp)
    FILE *fp;
    Interpl *ilp;
{   register Interp *cp;
	fprintf(fp,"Interpl[%d] ",ilp->mny);
	for(cp=ilp->fi; cp!=NULL; cp=cp->n) {
		fprintf(fp," %s --",interp_toa(cp));
		};
	fprintf(fp,"\n");
	}

/* Print the interpl very briefly */
fwra_interpl_brief(fp,ilp)
    FILE *fp;
    Interpl *ilp;
{   register Interp *ip;
	for(ip=ilp->fi; ip!=NULL; ip=ip->n) {
		fprintf(fp,"%s %s  ",ip->ci.c,merit_toa(ip->m));
		};
	fprintf(fp,"\n");
	}

err_interpl(ilp)
    Interpl *ilp;
{	fwra_interpl(stderr,ilp);
	}

/* return the address of a local static copy of the given Interpl,
   for which each Interp is a duplicate of those in the given list */
Interpl *dup_interpl_etc(ilp,etc)
    Interpl *ilp;
    Ident etc;
{   static Interpl lis;
    register Interp *cp,*pp,*dp;
	lis = *ilp;
	if(ilp->fi==NULL) return(NULL);
	for(pp=NULL,cp=ilp->fi; cp!=NULL; pp=dp,cp=cp->n) {
		dp=dup_interp(cp);
		if(pp==NULL) lis.fi = dp;
		else pp->n = dp;
		};
	pp->n=NULL;
	return(&lis);
	}

/* Return a pointer to a local static duplicate of *isp.
   Its pa array is new, created out of malloc space.
   If etc&IsInterp, all its Interps are also duplicated,
   else the contents of pa point to the old unduplicated Interps.
   */
Interps *dup_interps_etc(isp,etc)
    Interps *isp;
    Ident etc;		/* parts to duplicate */
{   static Interps dup;
    register Interp **ipp,**dpp;
	dup = *isp;
	if(dup.mny<=0) dup = empty_Interps;
	else {	if((dup.pa=(Interp **)malloc((dup.mny+1)*sizeof(Interp *)))==NULL)
			abort("can't dup (Interp *)is.pa[%d]",(dup.mny+1));
		for(ipp=isp->pa,dpp=dup.pa; *ipp!=NULL; ipp++,dpp++) {
			if(etc&IsInterp) *dpp = dup_interp(*ipp);
			else *dpp = *ipp;
			};
		*dpp = NULL;
		};
	return(&dup);
	}

free_interps_etc(isp,etc)
    Interps *isp;
    Ident etc;		/* parts to free */
{   register Interp **ipp,**dpp;
	if(etc&IsInterp) {
		/* free contents */
		for(ipp=isp->pa; *ipp!=NULL; ipp++) free_interp(*ipp);
		};
	if(isp->pa!=NULL) { free(isp->pa); isp->pa = NULL; };
	isp->mny = 0;
	}

/* remove a char from a chars set */
remove_char(cp,csp)
    Char *cp;
    Chars *csp;
{   register Char *rp,**rpp,**npp;
	if(csp->mny==0) err("remove_char: can't - Chars empty");
	else {	for(rp= *(rpp=csp->cpa); rp!=NULL; rp= *(++rpp)) if(rp==cp) break;
		if(rp==NULL) err("remove_char: can't - not found");
		else {	/* move later entries up */
			npp=rpp+1;
			do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
			if((--(csp->mny))==0) {free(csp->cpa); csp->cpa=NULL;};
			/* don't bother to realloc downwards */
			};
		};
	}

/* Append a char to the end of a chars set. 
   Do NOT attempt to maintain Chars in order sorted ascending on Char.bx.a.x.
   Return appended Char *. */
Char *append_char(cp,csp)
    Char *cp;
    Chars *csp;
{   register Char *rp,**rpp,**npp;
	if(csp->mny==0) {
		if((csp->cpa=(Char **)malloc(2*sizeof(Char *)))==NULL)
			abort("append_char: can't malloc csp->cpa[%d]",2);
		}
	else {	if((csp->cpa=(Char **)realloc(
				csp->cpa,
				(csp->mny+2)*sizeof(Char *))
				)==NULL)
			abort("append_char: can't realloc csp->cpa[%d]",
				(csp->mny+2));
		};
	csp->cpa[csp->mny] = cp;
	csp->cpa[++csp->mny] = NULL;
	return(cp);
	}

/* Insert a Char into a Chars set.  Chars is assumed to be sorted ascending
   on on Char.bx.a.x, and this order is maintained.
   Return inserted Char * */
Char *insert_char(cp,csp)
    Char *cp;
    Chars *csp;
{   register Char **cpp,*ncp,*pcp;
	if(csp->mny==0) {
		if((csp->cpa=(Char **)malloc(2*sizeof(Char *)))==NULL)
			abort("insert_char: can't malloc csp->cpa[%d]",2);
		csp->cpa[csp->mny] = cp;
		}
	else {	if((cpp=csp->cpa=(Char **)realloc(
				csp->cpa,
				(csp->mny+2)*sizeof(Char *))
				)==NULL)
			abort("insert_char: can't realloc csp->cpa[%d]",csp->mny+2);
		while(((*cpp)!=NULL)&&(*cpp)->bx.a.x<cp->bx.a.x) cpp++;
		/* **cpp is now 1st entry >= *cp in sorted order */
		pcp=cp;
		do {	ncp= *cpp;
			*(cpp++)=pcp;
			pcp=ncp;
			}
		while(pcp!=NULL);
		};
	csp->cpa[++csp->mny] = NULL;
	return(cp);
	}

/* Append the contents of a "source" chars set to a "destination" chars set.
   Merely copy (Char *) pointers:  don't duplicate Chars.
   Do NOT attempt to maintain Chars in order sorted ascending on Char.bx.a.x.
   Return destination (Chars *). */
Chars *append_chars(s,d)
    Chars *s;	/* source */
    Chars *d;	/* destination */
{   register Char *rp,**rpp,**npp;
	if(s->mny==0) return(d);
	if(d->mny==0) {
		if((d->cpa=(Char **)malloc((s->mny+1)*sizeof(Char *)))==NULL)
			abort("append_chars: can't malloc d->cpa[%d]",2);
		}
	else {	if((d->cpa=(Char **)realloc(
				d->cpa,
				(d->mny+s->mny+1)*sizeof(Char *))
				)==NULL)
			abort("append_chars: can't realloc d->cpa[%d]",
				(d->mny+s->mny+1));
		};
	memcpy(d->cpa+d->mny,s->cpa,(s->mny+1)*sizeof(Char *));
	d->mny += s->mny;
	return(d);
	}

/* Insert a Char into the Chars owned by a given Word,
   maintaining order in set, and updating the Word's bx */
Char *insert_char_word(cp,wp)
    Char *cp;
    Word *wp;
{	merge_bbx(&(cp->bx),&(wp->bx));
	return(insert_char(cp,&(wp->cs)));
	}

free_char_etc(p,etc)
    Char *p;	/* !=NULL */
    Ident etc;
{	if(etc&IsBlob) free_blobl_etc(&(p->bmny),&(p->fi),etc);
	if(etc&IsInterp) free_interpl(&(p->il));
	if(etc&IsSfeats && p->sfv!=NULL) { free(p->sfv); p->sfv=NULL; };
	if(etc&IsShapes) free_shapes(&(p->sh));
#if CPU!=CRAY
	if(etc&IsBfeats && p->bfsp!=NULL) { free_bfeats(p->bfsp); p->bfsp=NULL; };
#endif
	if(etc&IsChar) {
		if(p->ident&Char_label && p->l!=NULL) {
			free(p->l);  p->l=NULL;
			p->ident &= ~Char_label;
			};
		if(p->ident&Char_ranparms && p->rp!=NULL) {
			free_ranparms(p->rp);  p->rp=NULL;
			p->ident &= ~Char_ranparms;
			};
		free(p);
		free_census(Char,1);
		};
	}

/* Unconditionally free the malloc-space array of pointers, and empty the set.
   Don't free the records that it owned.
   */
free_chars(csp)
    Chars *csp;
{   	if(csp->cpa!=NULL) { free(csp->cpa); csp->cpa = NULL; }
	csp->mny = 0;
	}

free_chars_etc(csp,etc)
    Chars *csp;
    Ident etc;
{   register Char *cp,**cpp;
	if(csp->mny>0&&(etc&IsChar))
		for(cp= *(cpp=csp->cpa); cp!=NULL; cp= *(++cpp))
			free_char_etc(cp,etc);
	free_chars(csp);
	}

/** Blob handling:
	alloc_blob_pool(sz,debug) - create pool of free blob records
	free_blob_pool() - free the pool
Blob	*alloc_blob() - allocate a new blob (in pool)
	free_blob(bp) -  free a specified blob
	free_blob_runs(bp) - free a blob & the runs in its blob set
	free_blobl_etc(int *,Blob **,etc) - free blobs etc in char's blob list
	out_blob(bp) - print (ascii) to stdout
	fwrb_blob(fp,bp) - write binary Blob (only) to fp
        fwrb_blob_etc(fp,bp,etc) - write binary Blob & specified parts to fp
        frdb_blob_etc(fp,bp,etc) - read binary Blob & parts in specified form
	frdb_runfs(fp,bp,max) - read *bp's (binary) RunF's from fp
	err_blob(s,bp) - print (ascii) to stderr
	err_blob_runs(s,bp) - print Blob & its Runs (ascii) to stderr
	err_blob_runfs(s,bp) - print Blob & its RunFs (ascii) to stderr
	err_blob_briefly(s,bp) - print (ascii) to stderr
	err_blobf(s,bp) - print file-format blob (ascii) to stderr
	err_blob_stats() - report blob statistics
	blob_small(bp) - test whether its runs' data can be compressed to chars
 BUGS
     most fread/fwrite/fseek should be read/write/lseek, for speed
     -- but how to choose?
 **/

/* make (empty) pool of `size' Blobs (return F if can't allocate) */
boolean alloc_blob_pool(size,dbg)
    int size;
    boolean dbg;
{   register Blob *cbp, *cbq, *pbp;
	blob_max=size;
	if((blob_pool=(Blob *)malloc(blob_max*sizeof(Blob)))==NULL) return(F);
	blob_debug = dbg;
	pbp= &blob_fr;
	/* link up all blobs into free list using only first-ptrs */
	for(cbq=(cbp=blob_pool)+blob_max; cbp<cbq; cbp++) {
		pbp->n = cbp;
		pbp = cbp;
		};
	pbp->n = NULL;	/* marks end of free list */
	blob_fr_mny = blob_max;  blob_hi=0;  blob_chopped = 0;
	hi_blob_no = 0;
	return(T);
	}

free_blob_pool()
{	free(blob_pool);
	}

Blob *alloc_blob()
{    Blob *p;
	if((p=(Blob *)malloc(sizeof(Blob)))==NULL)
		abort("alloc_blob: can't");
	alloc_census(Blob,1);
	*p = empty_Blob;
	return(p);
	}

/* Unconditionally free this Blob record. */
free_blob(bp)
    Blob *bp;
{	free(bp);
	free_census(Blob,1);
	}

/* Allocate new Blob record and assign to it the next blob no */
Blob *alloc_pool_blob()
{	register Blob *bp;
	if((bp = blob_fr.n)==NULL) {
		err("too many alloc_blob() calls - aborting:");
#ifdef STATS
		err_blob_stats();
#endif
		exit(1);
		};
	blob_fr.n = bp->n;
#ifdef STATS
	blob_fr_mny--;
	if(blob_hi<(blob_max-blob_fr_mny)) blob_hi = blob_max-blob_fr_mny;
#endif
	bp->no = hi_blob_no++;
	return(bp);
	}

free_pool_blob(bp)
	Blob *bp;
{
	if(blob_debug&&bp==NULL) abort("free_pool_blob: can't free a NULL Blob");
#ifdef STATS
	blob_fr_mny++;
	if(blob_debug&&(blob_fr_mny>blob_max)) {
		err("free_pool_blob: too many free_blob() calls - aborting:");
#ifdef STATS
		err_blob_stats();
#endif
		exit(1);
		};
#endif
	bp->n = blob_fr.n;
	blob_fr.n = bp;
	}

/* free the runs belonging to this blob */
free_runs(bp)
    Blob *bp;
{   register Run *crp,*nrp;
	if(bp->ident&Runs_ff) {
		if(bp->r.ff!=NULL) free(bp->r.ff);
		bp->r.ff=NULL;
		}
	else if(bp->ident&Runs_f) {
		for(crp=bp->r.f; crp!=NULL; crp=nrp) {
			nrp=crp->n;
			free_run(crp);
			};
		}
	else if(bp->ident&Runs_seek) /* none to free */ ;
	}

/* free blob *bp and those parts (runs) specified */
free_blob_etc(bp,etc)
    Blob *bp;
    Ident etc;
{	if(etc&IsRun) free_runs(bp);
	if(etc&IsBlob) free_blob(bp);
	}

/* return a pointer to a distinct and duplicate copy of *bp;
   it is created out of malloc space */
Blob *dup_blob(bp)
    Blob *bp;
{   Blob *dup;
	if((dup=(Blob *)malloc(sizeof(Blob)))==NULL)
		abort("dup_blob: can't malloc");
	alloc_census(Blob,1);
	*dup = *bp;
	return(dup);
	}

/* return a pointer to a distinct and duplicate copy of *bp and what it owns,
   as described by etc; created out of malloc space */
Blob *dup_blob_etc(bp,etc)
    Blob *bp;
    Ident etc;
{   Blob *dup;
	dup = dup_blob(bp);
	if(bp->runs>0) {
		if(bp->ident&Runs_ff) {
		    int ri;
		    RunF *rp,*drp;
			if((dup->r.ff=
			    (RunF *)malloc(bp->runs*sizeof(RunF)))==NULL)
				abort("dup_blob_etc: can't malloc RunF[%d]",
					bp->runs);
			for(ri=0,rp=bp->r.ff,drp=dup->r.ff; ri<bp->runs; ri++)
				*(drp++) = *(rp++);
			}
		else abort("dup_blob_etc: only Runs_ff implemented");
		};
	return(dup);
	}

/* Return a pointer to a local static duplicate of non-empty *bsp.
   Its bpa array is created newly out of malloc space.
   If etc&IsBlob, all its Blobs are also fresh duplicates,
   else the contents of bpa point to the old unduplicated Blobs.
   */
Blobs *dup_blobs_etc(bsp,etc)
    Blobs *bsp;
    Ident etc;		/* parts to duplicate */
{   static Blobs dup;
    register Blob **bpp,**dpp;
	if((dup.mny = bsp->mny)<=0) dup = empty_Blobs;
	else {	if((dup.bpa=(Blob **)malloc((dup.mny+1)*sizeof(Blob *)))==NULL)
			abort("dup_blobs_etc: can't malloc bs.bpa[%d]",dup.mny+1);
		for(bpp=bsp->bpa,dpp=dup.bpa; *bpp!=NULL; bpp++,dpp++) {
			if(etc&IsBlob) *dpp = dup_blob_etc(*bpp,etc);
			else *dpp = *bpp;
			};
		*dpp = NULL;
		};
	return(&dup);
	}

/* Split the given Blobs into two, *b0 & *b1, according to the value 0 or !0
   respectively returned by the function s(b,a) applied to each Blob *b and
   blind argument *a.
   s() will be evaluated exactly once for each Blob, and the Blob's will be
   assigned in the order found in the original Blobs.  Only pointers to Blob's
   are created;  the Blob's themselves are not duplicated.  The original Blobs
   record is unchanged.
   */
split_blobs(b,s,a,b0,b1)
    Blobs *b;
    int (*s)();
    VOID *a;		/* passed transparently to s() */
    Blobs *b0,*b1;
{   char *sel,*sp;
    register Blob *bp,**bpp;
    Blob **b0pp;
    Blob **b1pp;
  	*b0 = *b1 = empty_Blobs;
	if(b->mny<=0) return;
	if((sel=(char *)malloc(b->mny))==NULL)
		abort("split_blobs: can't malloc sel[%d]",b->mny);
	for(bp= *(bpp=b->bpa),sp=sel; bp!=NULL; bp= *(++bpp),sp++)
		if(*sp = s(bp,a)) b1->mny++; else b0->mny++;
	if(b0->mny>0)
		if((b0->bpa=(Blob **)malloc((b0->mny+1)*sizeof(Blob *)))==NULL)
			abort("split_blobs: can't malloc b0->bpa[%d]",b0->mny+1);
	if(b1->mny>0)
		if((b1->bpa=(Blob **)malloc((b1->mny+1)*sizeof(Blob *)))==NULL)
			abort("split_blobs: can't malloc b1->bpa[%d]",b1->mny+1);
	b0pp=b0->bpa;
	b1pp=b1->bpa;
	for(bp= *(bpp=b->bpa),sp=sel; bp!=NULL; bp= *(++bpp),sp++)
		if(*sp) *(b1pp++)=bp; else *(b0pp++)=bp;
	if(b0->mny>0) *b0pp=NULL;
	if(b1->mny>0) *b1pp=NULL;
	free(sel);
	}

/* Return the address of the first in a list of Blobs, duplicated from
   the given list. */
Blob *dup_blobl_etc(bp,etc)
    Blob *bp;
    Ident etc;
{   Blob *fi,*cp,*pp,*dp;
	if(bp==NULL) return(NULL);
	for(pp=NULL,cp=bp; cp!=NULL; pp=dp,cp=cp->n) {
		dp=dup_blob_etc(cp,etc);
		if(pp==NULL) fi = dp;
		else pp->n = dp;
		};
	pp->n=NULL;
	return(fi);
	}

/* Prepend this blob to the given Char's bloblist; update Char's bx, area, & per.
   Inverse of `remove_blobl()'. */
Blob *insert_blobl(bp,cp)
    Blob *bp;
    Char *cp;
{   register Blob *pbp,*nbp;
	if(cp->bmny>0) bp->n = cp->fi;
	else bp->n = NULL;
	cp->fi = bp;
	cp->bmny++;
	merge_bbx(&(bp->bx),&(cp->bx));
	cp->area += bp->area;
	cp->per += bp->per;
	return(bp);
	}

/* Remove this blob from a char's bloblist; update Char's bx, area, per.
   Inverse of `insert_blobl()'. */
remove_blobl(bp,cp)
    Blob *bp;
    Char *cp;
{   Blob *rp,*pp;
    Bbx bx;		/* Char's new Bbx */
	if(cp->bmny==1) {  /* frequent case */
		cp->fi=NULL; cp->bmny=0;
		}
	else if(cp->bmny>1){
		bx=empty_Bbx;
		pp=NULL;
		for(rp=cp->fi; rp!=NULL; pp=rp,rp=rp->n) {
			if(rp==bp) break;
			else {	if(bx.a.x > rp->bx.a.x) bx.a.x = rp->bx.a.x;
				if(bx.a.y > rp->bx.a.y) bx.a.y = rp->bx.a.y;
				if(bx.b.x < rp->bx.b.x) bx.b.x = rp->bx.b.x;
				if(bx.b.y < rp->bx.b.y) bx.b.y = rp->bx.b.y;
				};
			};
		if(rp!=NULL) {	/* remove from list */
			if(pp==NULL) cp->fi=bp->n;
			else pp->n=bp->n;
			cp->bmny--;
			for(rp=bp->n; rp!=NULL; rp=rp->n) {
				if(bx.a.x > rp->bx.a.x) bx.a.x = rp->bx.a.x;
				if(bx.a.y > rp->bx.a.y) bx.a.y = rp->bx.a.y;
				if(bx.b.x < rp->bx.b.x) bx.b.x = rp->bx.b.x;
				if(bx.b.y < rp->bx.b.y) bx.b.y = rp->bx.b.y;
				};
			cp->bx = bx;
			}
		else err("remove_blobl: can't - not found");
		}
	else err("remove_blobl: can't - Blobl empty");
	cp->area -= bp->area;
	cp->per -= bp->per;
	}

/* prepend this blob to the given Blob list */
Blob *prepend_blobl(bp,blp)
    Blob *bp;
    Blobl *blp;
{   register Blob *pbp,*nbp;
	if(blp->mny>0) bp->n = blp->fi;
	else {	bp->n = NULL;
		blp->la = bp;
		};
	blp->fi = bp;
	blp->mny++;
	return(bp);
	}

/* append this blob to the given Blob list */
Blob *append_blobl(bp,blp)
    Blob *bp;
    Blobl *blp;
{   register Blob *pbp,*nbp;
	if(blp->mny==0) blp->fi = bp;
	else blp->la->n = bp;
	blp->la = bp;
	bp->n = NULL;
	blp->mny++;
	return(bp);
	}

/* remove a blob from a blobs set */
remove_blob(bp,bsp)
    Blob *bp;
    Blobs *bsp;
{   register Blob *rp,**rpp,**npp;
	if(bsp->mny==0) err("remove_blob: can't - Blobs empty");
	else {	for(rp= *(rpp=bsp->bpa); rp!=NULL; rp= *(++rpp)) if(rp==bp) break;
		if(rp==NULL) err("remove_blob: can't - not found");
		else {	/* move later entries up */
			npp=rpp+1;
			do *(rpp++)= *(npp++); while ((*rpp)!=NULL);
			if((--(bsp->mny))==0) {free(bsp->bpa); bsp->bpa=NULL;};
			/* don't bother to realloc downwards */
			};
		};
	}

/* Append a blob to the end of a blobs set. 
   Return appended Blob *. */
Blob *append_blob(p,sp)
    Blob *p;
    Blobs *sp;
{   register Blob *rp,**rpp,**npp;
	if(sp->mny==0) {
		if((sp->bpa=(Blob **)malloc(2*sizeof(Blob *)))==NULL)
			abort("append_blob: can't malloc sp->bpa[2]");
		}
	else {	if((sp->bpa=(Blob **)realloc(
				sp->bpa,
				(sp->mny+2)*sizeof(Blob *))
				)==NULL)
			abort("append_blob: can't realloc sp->bpa[%d]",sp->mny+2);
		};
	sp->bpa[sp->mny] = p;
	sp->bpa[++sp->mny] = NULL;
	return(p);
	}

/* Append Blobs *p1 to Blobs *p2.  On return, *p1 is unchanged, *p2 is in general
   longer, and all the Blob's owned by *p1 are now also owned by *p2. */
append_blobs_blobs(p1,p2)
    Blobs *p1,*p2;
{   int mny;
    register Blob **pp1,**pp2;
	if(p1->mny==0) return;
	if(p2->mny==0) { *p2 = *dup_blobs_etc(p1,IsNONE); return; };
	mny = p2->mny + p1->mny;
	if((p2->bpa=(Blob **)realloc(p2->bpa,(mny+1)*sizeof(Blob *)))==NULL)
		abort("append_blobs_blobs: can't realloc p2->bpa[%d]",mny+1);
	pp1=p1->bpa;  pp2=p2->bpa+p2->mny;  while(*pp1!=NULL) *(pp2++) = *(pp1++);
	*pp2 = NULL;
	p2->mny = mny;
	}

free_blobl_etc(mnyp,fip,etc)
    int *mnyp;
    Blob **fip;
    Ident etc;
{   register Blob *bp,*nbp;
	if(*mnyp>0) {
		for(bp= *fip; bp != NULL; bp=nbp)
			{ nbp=bp->n; free_blob_etc(bp,etc); };
		};
	*mnyp=0;
	*fip=NULL;
	}

/* Unconditionally free the malloc-space array of pointers, and empty the set.
   Don't free the records that it owned.
   */
free_blobs(bsp)
    Blobs *bsp;
{   	if(bsp->bpa!=NULL) { free(bsp->bpa); bsp->bpa=NULL; };
	bsp->mny = 0;
	}

free_blobs_etc(bsp,etc)
   Blobs *bsp;
   Ident etc;
{  register Blob *bp, **bpp;
	if(bsp->mny>0&&(etc&IsBlob)) for(bp= *(bpp=bsp->bpa); bp!=NULL; bp= *(++bpp))
		free_blob_etc(bp,etc);
	free_blobs(bsp);
	}

Blobs *blobl_to_blobs(blp)
    Blobl *blp;
{   static Blobs bs;
    register Blob *bp,**bpp;
	bs = empty_Blobs;
	bs.mny = blp->mny;
	if(bs.mny>0) {
		if((bs.bpa=(Blob **)malloc((bs.mny+1)*sizeof(Blob *)))==NULL)
			abort("blobl_to_blobs: can't malloc Blobs.bpa[%d]",bs.mny+1);
		for(bp=blp->fi,bpp=bs.bpa; bp!=NULL; bp=bp->n,bpp++)
			*bpp = bp;
		*bpp = NULL;
		};
	return(&bs);
	}

int bp_tod(bp)
    Blob *bp;
{	if(bp==NULL) return(-2);
	else return(bp-blob_pool);
	}

/* test whether for this Blob, each runs's data fields could all be compressed
   from a short to a char */
boolean blob_small(bp)
    Blob *bp;
{	if(bp->runs>255) return(F);
	if(bbx_wid(&bp->bx)>255) return(F);
	if(bbx_hgt(&bp->bx)>255) return(F);
	return(T);
	}

char *blob_toa(bp)
    Blob *bp;
{   char s1[80];
    static char s[80];
    Scoor hgt,wid;
	if(bp==NULL) strcpy(s,"NULL");
	else {	hgt = bp->bx.b.y - bp->bx.a.y + 1;
		wid = bp->bx.b.x - bp->bx.a.x + 1;
		sprintf(s1,"%s bx%s w%d,h%d ar%d pe%d r.",
			ident_toa(bp->ident),
			bbx_toa(&(bp->bx)),
			wid,
			hgt,
			bp->area,
			bp->per
			);
		if(bp->ident&Runs_f) strcat(s1,"f");
		else if(bp->ident&Runs_ff) strcat(s1,"ff");
		else if(bp->ident&Runs_seek) strcat(s1,"sk");
		else if(bp->ident&Runs_g4) strcat(s1,"g");
		else strcat(s1,"?");
		sprintf(s,"%s%d",s1,bp->runs);
		};
	return(s);
	}

/* compute the centroid of the Blob, w.r.t bx.a */
Pp *blob_centroid(bp)
    Blob *bp;
{   static Pp c;
    RunF *rfp;
    int ri,area;
	c.x = c.y = 0.0;
	if(bp->ident&Runs_ff) {
		for(ri=0, rfp=bp->r.ff; ri<bp->runs; ri++, rfp++) {
			c.x += (area=(rfp->xe-rfp->xs+1)) * (rfp->xe+rfp->xs);
			c.y += area * rfp->y;
			};
		c.x /= 2.0*bp->area;
		c.y /= bp->area;
		}
	else abort("blob_centroid: only Runs_ff supported");
	return(&c);
	}

/* write (printably) to stdout */
out_blob(bp)
    Blob *bp;
{   Run *crp;
    static char pad[] = "     ";
    short y;
	if(bp==NULL) fprintf(stderr,"Bb NULL.\n");
	else fprintf(stdout,"%s\n",blob_toa(bp));
	fprintf(stdout,"%sy%d:",pad,bp->bx.a.y);
	for(crp=bp->r.f,y=crp->y; crp!=NULL; crp=crp->n) {
		if(crp->y!=y) {
			fprintf(stdout,"\n%sy%d:",pad,crp->y);
			y=crp->y;
			};
		fprintf(stdout," [%d,%d]",crp->xs,crp->xe);
		};
	fprintf(stdout,"\n");
	}

#if FWRI
/* Write blob record (only) to FILE *f.
   Check whether Blob is ``small'' and label *p accordingly. */
fwrb_blob(f,p)
    FILE *f;
    Blob *p;
{
#if dbg_fwrb
	if((!(p->ident&IsBlob))||(p->ident&(IsALL&(~IsBlob))))
		err("fwrb_blob: %s",blob_toa(p));
#endif
	if(blob_small(p)) p->ident |= Blob_small; else p->ident &= ~Blob_small;
	fwri_Ident(f,p->ident);
	/* fwri_Seq(f,p->no); */
	fwri_Bbx(f,&(p->bx));
	fwri_uint4(f,p->area);
	fwri_uint4(f,p->per);
	/* don't write .n */
	fwri_Merit(f,p->m);
	fwri_uint3(f,p->runs);
	fwri_uint2(f,((p->bdsp==NULL)? 0: p->bdsp->mny));
#if dbg_fwrb_toa
	err("fwrb_blob: %s",blob_toa(p));
#endif
	}
#else
/* Write blob record (only) to FILE *fp.
   Check whether Blob is ``small'' and label *bp accordingly. */
fwrb_blob(fp,bp)
    FILE *fp;
    Blob *bp;
{   BlobF bf;
#if dbg_fwrb
	if((!(bp->ident&IsBlob))||(bp->ident&(IsALL&(~IsBlob))))
		err("fwrb_blob: %s",blob_toa(bp));
#endif
	memset(&bf,'\0',sizeof(bf));
	if(blob_small(bp)) bp->ident |= Blob_small;
	else bp->ident &= ~Blob_small;
	bf.ident = bp->ident;
	bf.bx=bp->bx;
	bf.area=bp->area;
	bf.per=bp->per;
	bf.runs=bp->runs;
	if(bp->bdsp==NULL) bf.bdys=0;
	else bf.bdys=bp->bdsp->mny;
	if(blob_debug) err_blobf("",&bf);
	if(fwrite(&bf,sizeof(BlobF),1,fp)!=1)
		abort("fwrb_blob: can't fwrite");
#if dbg_fwrb_toa
	err("fwrb_blob: %s",blob_toa(bp));
#endif
	}
#endif

/* Write detailed description of Runs to stderr. */
Blob *err_runs(name,bp)
    char *name;
    Blob *bp;
{   Run *rp;
    RunF *rfp,*rfe;
    int ri;
	if(bp->ident&Runs_f) {
		fprintf(stderr,"%s Runs_f[%d] in %s:\n",
			name,bp->runs,bbx_toa(&bp->bx));
		for(rp=bp->r.f,ri=0; rp!=NULL; rp=rp->n,ri++) {	
			fprintf(stderr,"  %2d: %d[%d,%d]\n",
				ri,rp->y,rp->xs,rp->xe);
			};
		}
	else if(bp->ident&Runs_ff) {
		fprintf(stderr,"%s Runs_ff[%d] in %s: ",
			name,bp->runs,bbx_toa(&(bp->bx)));
		for(rfe=(rfp=bp->r.ff)+bp->runs,ri=0; rfp<rfe; rfp++,ri++) {	
			fprintf(stderr," %d:%d[%d,%d]",
				ri,rfp->y,rfp->xs,rfp->xe);
			};
		fprintf(stderr,"\n");
		}
	else if(bp->ident&Runs_seek) {
		goto unsupported;
		}
	else {	goto unsupported;
		};
	return;
unsupported:
	abort("err_runs: %s unsupported",ident_toa(bp->ident));
	}

/* Convert the type of Runs in *bp to the type specified by id.
   Supported:  only bp->ident&Runs_f to id&Runs_ff.
   Return pointer to local static duplicate of *bp.
   */
Blob *runs_to_runs(bp,id)
    Blob *bp;
    Ident id;
{   static Blob b;
    register Run *rp;
    RunF *rfp;

	b = *bp;
	if(bp->ident&Runs_f) {
		if(id&Runs_ff) {
			b.ident &= ~(Runs_f|Blob_small);
			b.ident |= Runs_ff;
			if(blob_small(bp)) b.ident |= Blob_small;
			if((b.r.ff=(RunF *)malloc(b.runs*sizeof(RunF)))==NULL)
				abort("runs_to_runs: can't malloc Blob.r.ff[%d]",
						b.runs);							for(rp=bp->r.f,rfp=b.r.ff; rp!=NULL; rp=rp->n,rfp++) {	
				/* y, xs, xe will be relative to Blob.bx.a */
				rfp->y = rp->y - bp->bx.a.y;
				rfp->xs = rp->xs - bp->bx.a.x;
				rfp->xe = rp->xe - bp->bx.a.x;
				/* above,below connecting indices are relative to
				   the sequence no. of this run (ac>0 & bc>0) */
				if((rfp->ad = rp->ad)!=0)
					rfp->ac = rp->u.no - rp->ac->u.no;
				else rfp->ac = 0;
				if((rfp->bd = rp->bd)!=0)
					rfp->bc = rp->bc->u.no - rp->u.no;
				else rfp->bc = 0;
				if(0) err_runf("   ",rfp);
				};
			}
		else {	goto unsupported;
			};
		}
	else if(bp->ident&Runs_ff) {
		if(bp->ident&Blob_small) {
			goto unsupported;
			}
		else {	goto unsupported;
			};
		}
	else if(bp->ident&Runs_seek) {
		goto unsupported;
		}
	else {	goto unsupported;
		};
	return(&b);

unsupported:
	abort("runs_to_runs: %s --> %s unsupported",
		ident_toa(bp->ident),ident_toa(id));
	}

#if CPU!=CRAY
/* Write these RunFs to FILE *fp in CCITT Group 4 format.
   BUG:  uses bitio to one end of a pipe, just to store the entire
   byte-stream so it can be counted; then, it is copied to *fp.
   This fails on large bitmaps since the space available for pipe
   buffering is limited by system constraints and can run out at any
   time (symptom: the user process hangs in I state).  Also, since
   it relies so heavily on streams, it may not prove to be very portable.
   Should be rewritten with an expandable byte-buffer of some kind,
   which requires that the `putting' function in bitio be user-selectable.
   */
fwrb_runfs_g4(fp,bxp,runs,ff)
    FILE *fp;
    Bbx *bxp;
    int runs;
    RunF *ff;
#define dbg_fwrb_runfs_g4_detail F
{   RLE_Line l0,l1;
    RLE_Line *cl,*pl,*swap;	/* current/prior/swap line */
    int wid,hgt;		/* width,height of rectangular box of pixels */
    BITFILE *bf;
    int iri;
    RunF *irp;
    RLE_Run *crp;
    static int pipe_fd[2] = {-1,-1};
    static FILE *pipe_fp[2] = {NULL,NULL};
    unsigned long bytes,bi;
    int och;
	/* buffer g4 code in a pipe in order to count it */
	if(pipe_fd[0]==-1) {
		pipe(pipe_fd);
		if((pipe_fp[0] = fdopen(pipe_fd[0],"r"))==NULL)
			abort("fwrb_runfs_g4: can't open pipe \"r\", fd=%d",
				pipe_fd[0]);
		if((pipe_fp[1] = fdopen(pipe_fd[1],"w"))==NULL)
			abort("fwrb_runfs_g4: can't open pipe \"w\", fd=%d",
				pipe_fd[1]);
		/* leave this pipe open for the duration of the process */
		};
	/* treat pipe_fp[1] as a sequence of bits */
	if((bf=bopen(pipe_fp[1],"w"))==NULL)
		abort("fwrb_runfs_g4: can't open bitfile");
	wid = bbx_wid(bxp);  hgt=bbx_hgt(bxp);
	BOF_to_g4(bf);
	cl= &l0;  pl= &l1;  cl->len = pl->len = wid;  cl->y=0;  pl->runs=0;
	iri=0;  irp=ff;
	do {	/* build current RLE_Line */
		crp=cl->r;
		while(iri<runs&&irp->y==cl->y) {
			crp->xs=irp->xs;
			crp->xe=irp->xe;
			if(dbg_fwrb_runfs_g4_detail)
				err("i%d:  y%d x[%d,%d]",
					iri,cl->y,crp->xs,crp->xe);
			iri++; irp++; crp++;
			};
		cl->runs = crp-cl->r;
		/* write current RLE_line to file */
		rlel_to_g4(pl,cl,wid,bf);
		/* save current line as prior */
		swap=pl;  pl=cl;  cl=swap;  cl->runs=0;  cl->y=pl->y+1;
		}
	while(cl->y<hgt);
	/** By policy, don't append EOFB (i.e. omit EOF_to_g4(bf)) **/
	bytes = bclose(bf);
	if(dbg_fwrb_runs) err("fwrb_runfs_g4: %d bytes",bytes);
#if FWRI
	fwri_uint4(fp,bytes);
#else
	fwrite(&bytes,sizeof(bytes),1,fp);
#endif
	/* copy contents in pipe to fp */
	fflush(pipe_fp[1]);
	for(bi=0;bi<bytes;bi++) {
		putc(och=getc(pipe_fp[0]),fp);
#if dbg_fwrb_runs
		fprintf(stderr,"%02x",(unsigned char)och);
#endif
		};
	if(dbg_fwrb_runs) fprintf(stderr,"\n");
	}
#else
fwrb_runfs_g4(fp,bxp,runs,ff)
    FILE *fp;
    Bbx *bxp;
    int runs;
    RunF *ff;
{	abort("fwrb_runfs_g4: unimplemented on Cray");
	}
#endif

#if CPU != CRAY
/* Read a connected group of Runs in CCITT Group 4 format, into an array of RunFs.
   Return:  1 if normal & successful, 0 if EOF, and -1 if error.
   */
int frdb_g4_runfs(fp,bxp,runs,ff)
    FILE *fp;
    Bbx *bxp;	/* their bounding box, shrink-wrapped to fit exactly */
    int runs;	/* expect exactly this number of runs */
    RunF *ff;	/* space for `runs' RunFs */
#define dbg_frdb_g4_runfs_detail F
{   RLE_Line *cl;	/* current line */
    int wid,hgt;	/* width,height of rectangular box of pixels */
    int y;		/* height of current line */
    boolean bof;
    BITFILE *bf;
    static DST_table *tbl = NULL;
    int iri;
    RLE_Run *irp;
    int ori;
    RunF *orp;
    unsigned long bytes,g4_bytes;
#if FRDI
	bytes=frdi_uint4(fp);
#else
	fread(&bytes,sizeof(bytes),1,fp);
#endif
	if(dbg_frdb_runs) err("frdb_g4_runfs: %d bytes",bytes);
	/* read FILE *fp as a sequence of bits */
	if((bf=bopen(fp,"r"))==NULL)
		abort("frdb_g4_runfs: can't open bitfile");
	if(tbl==NULL) {
		tbl=ccitt_table();
		if(dbg_frdb_g4_runfs_detail) ccitt_err_tbl(tbl);
		};
	wid=bbx_wid(bxp);  hgt=bbx_hgt(bxp);
	y=0;  bof=T;  ori=0;  orp=ff;
	while((y<hgt)&&(cl=g4_to_rlel(tbl,bf,bof,wid))!=NULL) {
		/* copy runs to RunF ff[] */
		for(iri=0,irp=cl->r; iri<cl->runs; iri++,irp++) {
			if(dbg_frdb_g4_runfs_detail)
				err("o%d i%d:  y%d x[%d,%d]",
					ori,iri,y,irp->xs,irp->xe);
			if(ori<runs) {
				orp->y = y;  orp->xs = irp->xs;  orp->xe = irp->xe;
				orp++;
				}
			else err("frdb_g4_runfs: too many runs: ori%d >= runs%d",
				ori,runs);
			ori++;
			};
		y++;  bof=F;
		};
	if(cl==NULL) {
		err("frdb_g4_runfs: unexpected EOF");
		return(0);
		};
	/* recover connectivity among runs, on the assumption that they
	   are still in increasing lexicographic order on (y,xs) */
	fix_lag(orp-ff,(char *)ff,Runs_ff);
	if(ori!=runs) {
		err("frdb_g4_runfs: expected %d runs, but read %d",runs,ori);
		return(-1);
		};
	if((g4_bytes=bclose(bf))!=bytes) {
		err("frdb_g4_runfs: expected %d bytes, but read %d",
			bytes,g4_bytes);
		return(-1);
		};
	if(ferror(fp)) return(-errno); else return(1);
	}
#else
int frdb_g4_runfs(fp,bxp,runs,ff)
    FILE *fp;
    Bbx *bxp;	/* exact bounding box, shrink-wrapped to fit */
    int runs;	/* expect exactly this number of runs */
    RunF *ff;	/* space for `runs' RunFs */
{	abort("frdb_g4_runfs:  unimplemented on Cray");
	}
#endif

/* Write blob, etc to FILE *fp in binary format.
   If !(etc&IsBlob), then do nothing.
   else write Blob record and:
     If etc&IsRun, then also try to write Runs:
       If Blob.runs==0, write no runs.
       else
	   if etc&Runs_g4, write in CCITT G4 format
		compact but needs large streams; may not port well;
	   else write in Runs_ff format
	        if blob is small enough, use compressed RunFS form on output.

    */
fwrb_blob_etc(fp,bp,etc)
    FILE *fp;
    Blob *bp;
    Ident etc;
{   Ident sv_ident;
    int sv_runs;
    Run *rp;
    RunF rf;
    register RunF *rfp, *rfq;
    RunFS *rsp;
#if FWRI
    RunFS rfs;
#else
    static RunFS rfsa[256];
#endif
    int ri;
	if(!(etc&IsBlob)) return;

	sv_ident = bp->ident;
        sv_runs = bp->runs;
	if(etc&IsRun) {
		/* decide which Runs_* bits should be set on output */
		bp->ident &= ~(Runs_f|Runs_ff|Runs_seek|Runs_g4);
		if(etc&Runs_g4) {
			bp->ident |= Runs_g4;
			}
		else {	/* assume Runs_ff is wanted */
			bp->ident |= Runs_ff;
			};
		}
	else {	bp->ident &= ~(IsRun|Runs_f|Runs_ff|Runs_seek|Runs_g4);
		bp->runs = 0;
		};
	fwrb_blob(fp,bp);
	bp->ident = sv_ident;
	bp->runs = sv_runs;

	if(bp->runs==0) return;

	if(etc&Runs_g4) {
		/* write CCITT Group 4 encoding for Runs */
		if(bp->ident&Runs_ff) {
			fwrb_runfs_g4(fp,&(bp->bx),bp->runs,bp->r.ff);
			}
		else abort("fwrb_blob_etc: etc&Runs_g4 but !(id&Runs_ff)");
		}
	else {	/* Assume Runs_ff format is desired */
		if(bp->ident&Runs_f) {
			rp=bp->r.f;	
			if(bp->ident&Blob_small) { /* use compressed Run records */
				if(blob_debug) err("small");
				/* can use small local static array */
#if FWRI
				rsp= &rfs;
#else
				rsp=rfsa;
#endif
				while(rp!=NULL) {
					/* y, xs, xe will be relative to Blob.bx.a */
					rsp->y = rp->y - bp->bx.a.y;
					rsp->xs = rp->xs - bp->bx.a.x;
					rsp->xe = rp->xe - bp->bx.a.x;
					/* above,below connecting run indices are relative to
					   the sequence no. of this run (ac>0 & bc>0) */
					if((rsp->ad = rp->ad)!=0)
						rsp->ac = rp->u.no - rp->ac->u.no;
					else rsp->ac = 0;
					if((rsp->bd = rp->bd)!=0)
						rsp->bc = rp->bc->u.no - rp->u.no;
					else rsp->bc = 0;
					if(blob_debug) err_runfs("  ",rsp);
					rp=rp->n;
#if FWRI
					fwri_RunFS(fp,rsp);
#else
					rsp++;
#endif
					};
#if !FWRI
				if(fwrite(rfsa,sizeof(RunFS),bp->runs,fp)!=bp->runs)
					abort("fwrb_blob_etc: can't fwrite RunFS[%d]",bp->runs);
				if(dbg_fwrb_runs)
					err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunFS));
#endif
				}
			else {	if(blob_debug) err("large");
				while(rp!=NULL) {	
					/* y, xs, xe will be relative to Blob.bx.a */
					rf.y = rp->y - bp->bx.a.y;
					rf.xs = rp->xs - bp->bx.a.x;
					rf.xe = rp->xe - bp->bx.a.x;
					/* above,below connecting run indices are relative to
					   the sequence no. of this run (ac>0 & bc>0) */
					if((rf.ad = rp->ad)!=0)
						rf.ac = rp->u.no - rp->ac->u.no;
					else rf.ac = 0;
					if((rf.bd = rp->bd)!=0)
						rf.bc = rp->bc->u.no - rp->u.no;
					else rf.bc = 0;
					if(blob_debug) err_runf("   ",&rf);
		
					/* since there may be many, won't use a local array */
#if FWRI
					fwri_RunF(fp,&rf);
#else
					if(fwrite(&rf,sizeof(RunF),1,fp)!=1)
						abort("fwrb_blob_etc: can't fwrite RunF");
#endif
					rp=rp->n;
					};
				if(dbg_fwrb_runs)
					err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunF));
				};
			}
		else if(bp->ident&Runs_ff) {
			if(bp->ident&Blob_small) { /* use compressed Run records */
				if(blob_debug) err("small");
				/* can use small local static array */
#if FWRI
				rsp= &rfs;
#else
				rsp=rfsa;
#endif
				for(rfp=bp->r.ff,ri=0; ri<bp->runs; rfp++,ri++) {
					rsp->y = rfp->y;
					rsp->xs = rfp->xs;
					rsp->xe = rfp->xe;
					rsp->ad = rfp->ad;
					rsp->bd = rfp->bd;
					rsp->ac = rfp->ac;
					rsp->bc = rfp->bc;
#if FWRI
					fwri_RunFS(fp,rsp);
#else
					rsp++;
#endif
					};
#if !FWRI
				if(fwrite(rfsa,sizeof(RunFS),bp->runs,fp)!=bp->runs)
					abort("fwrb_blob_etc: can't fwrite RunFS[%d]",bp->runs);
				if(dbg_fwrb_runs)
					err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunFS));
#endif
				}
			else {	if(blob_debug) err("large");
#if FWRI
				for(rfq=(rfp=bp->r.ff)+bp->runs; rfp<rfq; rfp++) {
					fwri_RunF(fp,rfp);
					};

#else
				if(fwrite(bp->r.ff,sizeof(RunF),bp->runs,fp)!=bp->runs)
					abort("fwrb_blob_etc: can't fwrite RunF[%d]",bp->runs);
				if(dbg_fwrb_runs)
					err("fwrb_blob_etc: %d bytes",bp->runs*sizeof(RunF));
#endif
				};
			};
		}; 
	}

/* Read a given Blob's RunF's (binary) from FILE *fp; return F on EOF.
   If bp->runs<=max, read the RunF's into bp->r.ff, and set Runs_ff bit.
   otherwise ignore them all and set bp->r.ff==NULL.  */
int frdb_runfs(fp,bp,max)
    FILE *fp;
    Blob *bp;	/* *bp's fields already set up */
    int max;	/* maximum no. RunF records expected */
{   register RunFS *rsp,*rsq;
    static RunFS rfsa[256];
    register RunF *rfp,*rfq;
	if(bp->r.ff!=NULL && bp->runs <= max) {
		bp->ident |= Runs_ff;  bp->ident &= ~(Runs_f|Runs_seek);
		if(bp->ident&Blob_small) {
			if(blob_debug) err("small");
#if FRDI
			for(rsq=(rsp=rfsa)+bp->runs; rsp<rsq; rsp++) {
				frdi_RunFS(fp,rsp);
				};
#else
			if(fread(rfsa,sizeof(RunFS),bp->runs,fp) < bp->runs)
				return(0);
#endif
			/* copy compressed RunFS's into RunF's */
			for(rsq=(rsp=rfsa)+bp->runs,rfp=bp->r.ff;
			       rsp<rsq;
				  rsp++,rfp++) {
				/* beware sign extension from unsigned chars */
				if(blob_debug) err_runfs("   ",rsp);
				rfp->y = 0377&rsp->y;
				rfp->xs = 0377&rsp->xs;
				rfp->xe = 0377&rsp->xe;
				rfp->ad = 0377&rsp->ad;
				rfp->bd = 0377&rsp->bd;
				rfp->ac = 0377&rsp->ac;
				rfp->bc = 0377&rsp->bc;
				};
			}
		else {	if(blob_debug) err("large");
#if FRDI
			for(rfq=(rfp=bp->r.ff)+bp->runs; rfp<rfq; rfp++)
				frdi_RunF(fp,rfp);
#else
			if(fread(bp->r.ff,sizeof(RunF),bp->runs,fp) != bp->runs)
				return(F);
#endif
			};
		}
	else {	bp->ident &= ~(Runs_ff|Runs_f);
		bp->ident |= Runs_seek;
		bp->r.seek=ftell(fp);
		/* skip past excessive no. of runs */
/** What if FRDI?? **/
		if(bp->ident&Blob_small)
			fseek(fp,(long)((bp->runs)*sizeof(RunFS)),1);
		else
			fseek(fp,(long)((bp->runs)*sizeof(RunF)),1);
		};
	if(ferror(fp)) return(-errno); else return(1);
	}

#if FRDI
/* read a Blob record (only) into *p */
int frdb_blob(f,p)
    FILE *f;
    Blob *p;
{   int bdy_mny;
	*p = empty_Blob;
	if(feof(f))
		return(0);
	p->ident=frdi_Ident(f);
	/* p->no=frdi_Seq(f); */
	frdi_Bbx(f,&(p->bx));
	p->area=frdi_uint4(f);
	p->per=frdi_uint4(f);
	/* don't read .n */
	p->m=frdi_Merit(f);
	p->runs=frdi_uint3(f);
	if((bdy_mny=frdi_uint2(f))>0) {
		p->bdsp = alloc_bdys();
		p->bdsp->mny = bdy_mny;
		};
#if dbg_frdb
	if((!(p->ident&IsBlob))||(p->ident&(IsALL&(~IsBlob))))
		err("frdb_blob: %s",blob_toa(p));
#endif
#if dbg_frdb_toa
	err("frdb_blob: %s",blob_toa(p));
#endif
	if(ferror(f))
		return(-errno);
	else return(1);
	}
#else
/* read a Blob record (only) into *bp;  return F if EOF */
int frdb_blob(fp,bp)
    FILE *fp;
    Blob *bp;
{   BlobF bf;
	if(fread(&bf,sizeof(BlobF),1,fp)!=1) return(0);
	if(blob_debug) err_blobf("bf",&bf);
	bp->ident=bf.ident;
	bp->no = 0;
	bp->bx=bf.bx;
	bp->area=bf.area;
	/*bp->per=bf.per;*/
	bp->runs=bf.runs;
	/*bp->bdys=bf.bdys;*/
	bp->n = NULL;
	bp->r.f = NULL;
	bp->bdsp = NULL;
#if dbg_frdb
	if((!(bp->ident&IsBlob))||(bp->ident&(IsALL&(~IsBlob))))
		err("frdb_blob: %s",blob_toa(bp));
#endif
#if dbg_frdb_toa
	err("frdb_blob: %s",blob_toa(bp));
#endif
	if(ferror(fp)) return(-errno); else return(1);
	}
#endif

err_blob(s,bp)
    char *s;
    Blob *bp;
{	fprintf(stderr,"%s ",s);
	if(bp==NULL) fprintf(stderr,"Blob NULL.\n");
	else fprintf(stderr,
		"Blob %d: x[%d,%d],y[%d,%d] ar%d ft%s r(#%d f%d)\n",
		bp->no,bp->bx.a.x,bp->bx.b.x,bp->bx.a.y,bp->bx.b.y,
		bp->area,ident_toa(bp->ident),bp->runs,rp_tod(bp->r.f));
	}

err_blob_runs(s,bp)
    char *s;
    Blob *bp;
{   Run *crp;
    char cs[20];
	fprintf(stderr,"%s ",s);
	err_blob(s,bp);
	if(bp!=NULL&&bp->runs>0&&bp->r.f!=NULL) {
		sprintf(cs,"%*s",strlen(s)+2," ");
		for(crp=bp->r.f; crp!=NULL; crp=crp->n) err_run(cs,crp);
		};
	}

err_blob_runfs(s,bp)
    char *s;
    Blob *bp;
{   RunF *crp;
    int ri;
    char cs[20];
	fprintf(stderr,"%s ",s);
	err_blob_briefly("",bp);
	if(bp!=NULL&&bp->runs>0&&bp->r.ff!=NULL) {
		sprintf(cs,"%*s",strlen(s)+2," ");
		for(crp=bp->r.ff,ri=0; ri<bp->runs; crp++,ri++) err_runf(cs,crp);
		};
	}

err_blobf(s,bp)
    char *s;
    BlobF *bp;
{   Run *crp;
    char cs[20];
	fprintf(stderr,"%s ",s);
	if(bp==NULL) fprintf(stderr,"BlobF NULL.\n");
	else fprintf(stderr,
		"BlobF: x[%d,%d],y[%d,%d] ar%d ft%s #r%d\n",
		bp->bx.a.x,bp->bx.b.x,bp->bx.a.y,bp->bx.b.y,
		bp->area,ident_toa(bp->ident),bp->runs);
	}

err_blob_briefly(s,bp)
    char s[];
    Blob *bp;
{   Run *crp;
	if(bp==NULL) err("%s Blob NULL.",s);
	else { fprintf(stderr,
			"%s Blob #%d: bx(%d,%d),(%d,%d) ar%d f%s runs%d ",
			s,
			bp->no,
			bp->bx.a.x,bp->bx.a.y,bp->bx.b.x,bp->bx.b.y,
			bp->area,
			ident_toa(bp->ident),
			bp->runs);
		fprintf(stderr,"\n");
		};
	}

err_blob_stats()
{	err("Blob stats:  %d now, %d total, %d hi-water\n",
			blob_max-blob_fr_mny,hi_blob_no+1,blob_hi);
	}

/* write blob list starting at fi */
fwrb_blobl_etc(fp,mny,fi,etc)
    FILE *fp;
    int mny;
    Blob *fi;
    Ident etc;
{   int bi;
    Blob *bp;
	if(mny>0) for(bi=0,bp=fi; bi<mny; bi++,bp=bp->n) {
		if(bp!=NULL) fwrb_blob_etc(fp,bp,etc);
		else {	err("fwrb_blobl_etc: bmny==%d but %dth (Blob *) is NULL",
				mny,bi);
			break;
			};
		};
	}

fwrb_blobs_etc(fp,bs,etc)
    FILE *fp;
    Blobs bs;
    Ident etc;
{   register Blob *bp,**bpp;
	if(bs.mny==0) return;
	for(bp= *(bpp=bs.bpa); bp!=NULL; bp= *(++bpp))
		fwrb_blob_etc(fp,bp,etc);
	}

/* read a set of blobs, and their parts */
frdb_blobs_etc(fp,bsp,etc)
    FILE *fp;
    Blobs *bsp;
    Ident etc;		/* read only the parts indicated */
{   int bi;
    register Blob *bp,**bpp;
	if(bsp->mny<=0) {
		*bsp = empty_Blobs;
		return(1);
		};

	if((bpp=bsp->bpa=(Blob **)malloc((bsp->mny+1)*sizeof(Blob *)))==NULL)
		abort("frdb_blobs_etc: can't alloc Blobs.bpa[%d]",bsp->mny+1);
	for(bi=0; bi<bsp->mny; bi++) {
		*(bpp++) = bp = alloc_blob();
		if(!frdb_blob_etc(fp,bp,etc))
			abort("frdb_blobs_etc: unexpected EOF");
		};
	*bpp = NULL;
	if(ferror(fp)) return(-errno); else return(1);
	}

/* Read a blob record into *bp, and then read its parts as specified by etc.
   If there aren't any runs, return normally.
   If etc&IsRun is false, then set Runs_seek and proceed as described below.
   If etc&Runs_ff, then the contents of r.ff is examined:
   	if NULL, then space is allocated here for `runs' RunF's;
   	if non-NULL, then on the assumption that it points to space for
   	at least `runs' many, they are read into it.
   If etc&Runs_seek, then the ftell value is placed in r.seek,
	and the runs are simply skipped over.
   The Runs_f (list) option is unimplemented.
   The Blob is marked with the appropriate Runs_X bit.
   Return:  1 if normal & successful, 0 if EOF, and -1 if error.
    */
int frdb_blob_etc(fp,bp,etc)
    FILE *fp;
    Blob *bp;
    Ident etc;
{   int stat;
	if((stat=frdb_blob(fp,bp))!=1)
		return(stat);
	if(bp->runs<=0) {
		bp->runs = 0;
		bp->r.ff = NULL;
		bp->ident &= ~(Runs_f|Runs_seek|Runs_g4);
		bp->ident |= Runs_ff;
		return(1);
		};

	if(!(etc&IsRun)) {
		etc |= IsRun|Runs_seek;
		etc &= ~(Runs_f|Runs_ff|Runs_g4);
		};
	if (!(etc&(Runs_f|Runs_ff|Runs_g4|Runs_seek)) || etc&Runs_ff) {
		/* Want to deliver Runs in Runf ff[] format */
		if(bp->r.ff==NULL) {
			if( (bp->r.ff=
			    (RunF *)malloc(bp->runs*sizeof(RunF)))==NULL)
				abort("frdb_blob_etc: can't alloc r.ff[%d]",bp->runs);
			};
		if(bp->ident&Runs_g4) {
			/* Runs are in CCITT Group 4 format */
			stat=frdb_g4_runfs(fp,&(bp->bx),bp->runs,bp->r.ff);
			}
		else {	/* Runs are in RunF or RunFS format */
			stat=frdb_runfs(fp,bp,bp->runs);
			};
		bp->ident |= Runs_ff;  bp->ident &= ~(Runs_f|Runs_seek|Runs_g4);
		return(stat);
		}
	else if(etc&Runs_seek) {
		bp->ident |= Runs_seek;  bp->ident &= ~(Runs_ff|Runs_f);
		bp->r.seek=ftell(fp);	/* save seek addr */
		/* skip past runs */
		if(bp->ident&Blob_small)
			fseek(fp,(long)((bp->runs)*sizeof(RunFS)),1);
		else	fseek(fp,(long)((bp->runs)*sizeof(RunF)),1);
		}
	else /* (etc&Runs_f) || (etc&Runs_g4) */ {
		abort("frdb_blob_etc:  Runs_f & Runs_g4 etc option unimplemented");
 		};
	if(ferror(fp)) return(-errno); else return(1);
	}

/* read a number of blobs, and their parts, into linked-list (mny, *fi);
   return T iff not EOF  */
boolean frdb_blobl_etc(fp,bmny,fip,etc)
    FILE *fp;
    int bmny;
    Blob **fip;
    Ident etc;
{   int bi;
    register Blob *bp,**bpp;
    RunF *rp;
    int stat;
	if(bmny<=0) return(1);
	bi=0; bpp=fip;
	do {	bp=alloc_blob();
		if((stat=frdb_blob_etc(fp,bp,etc))!=1) return(stat);
		*bpp=bp;  bpp= &(bp->n);
		}
	while((++bi)<bmny);
	*bpp=NULL;
	if(ferror(fp)) return(-errno); else return(1);
	}

char *interp_toa(ip)
    Interp *ip;
{   static char s[80];
    char ms[3],shs[3],szs[3],hts[3],prs[3];
	strcpy(ms,merit_toa(ip->m));
	strcpy(shs,merit_toa(ip->mshap));
	strcpy(szs,merit_toa(ip->msize));
	strcpy(hts,merit_toa(ip->mbhgt));
	strcpy(prs,merit_toa(ip->p));
	sprintf(s,"%s %s sz%s ba%d m%s (sh%s sz%s ht%s) p%s",
		ident_toa(ip->ident),
#if CPU!=CRAY
		classid_toa(&(ip->ci)),
#else
		ip->ci.c,
#endif
		pts_toa(ip->size),
		ip->basl,
		ms,shs,szs,hts,prs);
	return(s);
	}

frdb_interpl_etc(fp,ilp,etc)
    FILE *fp;
    Interpl *ilp;
    Ident etc;
{   int ii,stat;
    Interp *ip,*pp;
	if(ilp->mny<=0) {
		*ilp = empty_Interpl;
		return(1);
		};

	for(ii=0; ii<ilp->mny; ii++) {
		ip=alloc_interp();
		if(ii==0) ilp->fi = ip;
		else pp->n = ip;
		if((stat=frdb_interp(fp,ip))!=1) return(stat);
		pp=ip;
		};
	ip->n = NULL;
	if(ferror(fp)) return(-errno); else return(1);
	}

#if FRDI
int frdb_interp(f,p)
    FILE *f;
    Interp *p;
{   int stat;
	*p = empty_Interp;
	if(feof(f))
		return(0);
	p->ident=frdi_Ident(f);
	frdi_ClassId(f,&(p->ci));
	p->mshap=frdi_Merit(f);
	p->size=frdi_Pts(f);
	p->msize=frdi_Merit(f);
	p->basl=frdi_Scoor(f);
	p->mbhgt=frdi_Merit(f);
	p->m=frdi_Merit(f);
	p->p=frdi_Prob(f);
#if dbg_frdb
	if((!(p->ident&IsInterp))||(p->ident&(IsALL&(~IsInterp))))
		err("frdb_interp: %s",interp_toa(p));
#endif
	if(ferror(f)) return(-errno); else return(1);
	}
#else
int frdb_interp(fp,ip)
    FILE *fp;
    Interp *ip;
{   InterpF inf;
    int stat;
	if((stat=fread(&inf,sizeof(InterpF),1,fp))!=1) {
		err("can't fread InterpF, status %d",stat);
		return(stat);
		};
	*ip = empty_Interp;
	ip->ident = inf.ident;
	ip->ci = inf.ci;
	ip->clp = NULL;
	ip->clsp = NULL;
	ip->mshap = inf.mshap;
	ip->size = inf.size;
	ip->msize = inf.msize;
	ip->basl = inf.basl;
	ip->mbhgt = inf.mbhgt;
	ip->m = inf.m;
#if dbg_frdb
	if((!(ip->ident&IsInterp))||(ip->ident&(IsALL&(~IsInterp))))
		err("frdb_interp: %s",interp_toa(ip));
#endif
	if(ferror(fp)) return(-errno); else return(1);
	}
#endif

free_interpl(ilp)
    Interpl *ilp;
{   int ii;
    Interp *ip,*np;
	if(ilp->mny>0) {
		for(ip=ilp->fi; ip!=NULL; ip=np) { np=ip->n; free_interp(ip); }
		ilp->mny=0;
		};
	ilp->fi=NULL;
	};

fwrb_interpl_etc(fp,is,etc)
    FILE *fp;
    Interpl is;
    Ident etc;
{   Interp *ip;
    int ii;
	if(is.mny>0) for(ii=0,ip=is.fi; ii<is.mny; ii++,ip=ip->n)
		fwrb_interp_etc(fp,ip,etc);
	}

/* remove this Interp from the Interp-list */
remove_interpl(ip,ilp)
    Interp *ip;
    Interpl *ilp;
{   Interp *rp,*pp;
	if(ilp->mny==1) {  /* frequent case */
		ilp->fi=NULL; ilp->mny=0;
		}
	else if(ilp->mny>1){
		pp=NULL;
		for(rp=ilp->fi; rp!=ip&&rp!=NULL; pp=rp,rp=rp->n) ;
		if(rp!=NULL) {	/* remove from list */
			if(pp==NULL) ilp->fi=ip->n;
			else pp->n=ip->n;
			ilp->mny--;
			}
		else err("remove_interpl: can't - not found");
		}
	else err("remove_interpl: can't - Interpl empty");
	}

/* prepend this Interp to the Interp-list */
prepend_interpl(ip,ilp)
    Interp *ip;
    Interpl *ilp;
{   Interp *rp,*pp;
	ip->n = ilp->fi;
	ilp->fi = ip;
	ilp->mny++;
	}

fwrb_interp_etc(fp,ip,etc)
    FILE *fp;
    Interp *ip;
    Ident etc;
{	fwrb_interp(fp,ip);
	}

#if FWRI
fwrb_interp(f,p)
    FILE *f;
    Interp *p;
{   InterpF inf;
    int stat;
#if dbg_fwrb
	if((!(p->ident&IsInterp))||(p->ident&(IsALL&(~IsInterp))))
		err("fwrb_interp: %s",interp_toa(p));
#endif
	fwri_Ident(f,p->ident);
	fwri_ClassId(f,&(p->ci));
	fwri_Merit(f,p->mshap);
	fwri_Pts(f,p->size);
	fwri_Merit(f,p->msize);
	fwri_Scoor(f,p->basl);
	fwri_Merit(f,p->mbhgt);
	fwri_Merit(f,p->m);
	fwri_Prob(f,p->p);
#if dbg_fwrb_toa
	err("fwrb_interp: %s",interp_toa(p));
#endif
	}
#else
fwrb_interp(fp,ip)
    FILE *fp;
    Interp *ip;
{   InterpF inf;
    int stat;
#if dbg_fwrb
	if((!(ip->ident&IsInterp))||(ip->ident&(IsALL&(~IsInterp))))
		err("fwrb_interp: %s",interp_toa(ip));
#endif
	memset(&inf,'\0',sizeof(inf));
	inf.ident = ip->ident;
	inf.ci = ip->ci;
	inf.mshap = ip->mshap;
	inf.size = ip->size;
	inf.msize = ip->msize;
	inf.basl = ip->basl;
	inf.mbhgt = ip->mbhgt;
	inf.m = ip->m;
	if((stat=fwrite(&inf,sizeof(InterpF),1,fp))!=1)
		abort("fwrb_interp: can't fwrite, status %d",stat);
#if dbg_fwrb_toa
	err("fwrb_interp: %s",interp_toa(ip));
#endif
	}
#endif

/** Run handling:
	alloc_run_pool -create pool of free run records
	free_run_pool -	free entire pool
	alloc_run -	allocate a new run from pool
	free_run - 	free a specified run (into pool)
	err_run -	print Run (ascii) to stderr
	err_runb -	print Run (ascii) to stderr (after added to blob set)
	err_runf -	print RunF (ascii) to stderr (after added to blob set)
	err_runfs -	print RunFS (ascii) to stderr (after added to blob set)
	err_run_stats - report statistics to stderr
   **/

/* RunPool functions: variable-size pool, speed-optimized alloc/free */

/* Initialize pool of Runs with increment `incr' (return F if can't allocate) */
boolean alloc_run_pool(incr,dbg)
    int incr;
    boolean dbg;	/* trace actions on Runs */
{   register Run *crp, *prp;
    register int i;
	_RunPool.incr = incr;
	_RunPool.pools = 1;
	if((_RunPool.pool=(Run **)malloc(_RunPool.pools*sizeof(Run *)))==NULL)
		return(F);
	if((_RunPool.pool[_RunPool.pools-1] =
	    (Run *)malloc(_RunPool.incr*sizeof(Run)))==NULL) {
		free(_RunPool.pool);
		return(F);
		};
	_RunPool.next = 0;
	_RunPool.free = NULL;
#if STATS
	_RunPool.total = 0;
#endif
	_RunPool.dbg = dbg;
	if(_RunPool.dbg) err("alloc_run_pool: incr%d",_RunPool.incr);
	return(T);
	}

free_run_pool()
{   register int i;
	for(i=0; i<_RunPool.pools; i++) free(_RunPool.pool[i]);
	free(_RunPool.pool);
	}

/* The ``hard'' case of allocating runs from RunPool: can't be inline */
Run *hard_alloc_run()
{	_RunPool.pools++;
	if((_RunPool.pool=
		(Run **)realloc(_RunPool.pool,_RunPool.pools*sizeof(Run *)))==NULL)
		abort("alloc_Run: can't realloc");
	if((_RunPool.cur=_RunPool.pool[_RunPool.pools-1] =
	    (Run *)malloc(_RunPool.incr*sizeof(Run)))==NULL)
		abort("alloc_Run: can't malloc");
	_RunPool.next=1;
	*(_RunPool.cur) = empty_Run;
	return(_RunPool.cur);
	}

int rp_tod(rp)
    Run *rp;
{	return((int)rp);
	}

char *runf_toa(rp)
    RunF *rp;
{  static char s[80];
   char s1[80];
	strcpy(s,"RunF ");
	if(rp==NULL) strcat(s,"NULL");
	else {	sprintf(s1,
			"y%d,x[%d,%d] lag(ad%d,bd%d ac%d,bc%d)",
			rp->y,rp->xs,rp->xe, 
			rp->ad,rp->bd, rp->ac,rp->bc );
		strcat(s,s1);
		};
	return(s);
	}

char *runfs_toa(rp)
    RunFS *rp;
{  static char s[80];
   char s1[80];
	strcpy(s,"RunFS ");
	if(rp==NULL) strcat(s,"NULL");
	else {	sprintf(s1,
			"y%d,x[%d,%d] lag(ad%d,bd%d ac%d,bc%d)",
			rp->y,rp->xs,rp->xe, 
			rp->ad,rp->bd, rp->ac,rp->bc );
		strcat(s,s1);
		};
	return(s);
	}

err_run(s,rp)
	char *s;
	Run *rp;
{	fprintf(stderr,"%s ",s);
	if(rp==NULL) fprintf(stderr,"Run NULL.\n");
	else fprintf(stderr,
		"Run %d: y%d,x[%d,%d] l(n%d) t(o%x ad%d,bd%d ac%d,bc%d)\n",
		rp_tod(rp), rp->y,rp->xs,rp->xe, 
		rp_tod(rp->n),
#if CPU!=CRAY
		(int)rp->u.o,
#else
		0,
#endif
		rp->ad,rp->bd,
		rp_tod(rp->ac),
		rp_tod(rp->bc) );
	}

/* print Run after it has been added to Blob set */
err_runb(s,rp)
	char *s;
	Run *rp;
{	fprintf(stderr,"%s ",s);
	if(rp==NULL) fprintf(stderr,"Run NULL.\n");
	else fprintf(stderr,
		"Run %d: y%d,x[%d,%d] l(n%d) t(no%d ad%d,bd%d ac%d,bc%d)\n",
		rp_tod(rp), rp->y,rp->xs,rp->xe, 
		rp_tod(rp->n),
		rp->u.no, rp->ad,rp->bd, rp_tod(rp->ac),rp_tod(rp->bc) );
	}

err_runf(s,rp)
	char *s;
	RunF *rp;
{	fprintf(stderr,"%s ",s);
	if(rp==NULL) fprintf(stderr,"RunF NULL.\n");
	else fprintf(stderr,
		"RunF: y%d,x[%d,%d] t(ad%d,bd%d ac%d,bc%d)\n",
		rp->y,rp->xs,rp->xe, 
		rp->ad,rp->bd, rp->ac,rp->bc );
	}

err_runfs(s,rp)
	char *s;
	RunFS *rp;
{   RunF rf;
	rf.y = 0377&rp->y;
	rf.xs = 0377&rp->xs;
	rf.xe = 0377&rp->xe;
	rf.ad = 0377&rp->ad;
	rf.bd = 0377&rp->bd;
	rf.ac = 0377&rp->ac;
	rf.bc = 0377&rp->bc;
	err_runf(s,&rf);
	}

int runs_of_blob(p,ra,max)
    Blob *p;
    RLE_Yrun *ra;
    int max;
{   int runs,ri;
    RunF *rfp;
	runs = p->runs;
	if(runs>max) {
		err("runs_of_blob: max exceeded - skip this blob");
		runs = 0;
		}
	else if(runs>0) {
		if(p->ident&Runs_ff) {
			for(ri=0,rfp=p->r.ff; ri<runs; ri++,rfp++) {
				ra->y = p->bx.a.y + rfp->y;
				ra->xs = p->bx.a.x + rfp->xs;
				ra->xe = p->bx.a.x + rfp->xe;
				ra++;
				};
			}
		else {	err("runs_of_blob: handle only Runs_ff - skip this blob");
			runs = 0;
			};
		};
	return(runs);
	}

int no_runs_of_blobl(p)
    Blobl *p;
{   int runs;
    Blob *pp;
	runs = 0;
	if(p->mny>0) for(pp=p->fi; pp!=NULL; pp=pp->n) runs += pp->runs;
	return(runs);
	}

int runs_of_blobl(p,ra,max)
    Blobl *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
    Blob *pp;
	runs = 0;
	if(p->mny>0) for(pp=p->fi; pp!=NULL; pp=pp->n)
		runs += runs_of_blob(pp,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_char(p)
    Char *p;
{   int runs;
    Blobl bl;
	runs = 0;
	bl.mny = p->bmny;  bl.fi = p->fi;
	runs += no_runs_of_blobl(&bl);
	return(runs);
	}

int runs_of_char(p,ra,max)
    Char *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
    Blobl bl;
	runs = 0;
	bl.mny = p->bmny;  bl.fi = p->fi;
	runs += runs_of_blobl(&bl,ra,max);
	return(runs);
	}

/* ascending lexicographic order on y,xs */
int rn_asc(r1,r2)
   RLE_Yrun *r1,*r2;
{	if(r1->y < r2->y) return(-1);
	else if(r1->y==r2->y) {
		if(r1->xs < r2->xs) return(-1);
		else if (r1->xs == r2->xs) return(0);
		else return(1);
		}
	else return(1);
	}

RLE_Lines *rlines_of_char(chp)
    Char *chp;
{   static RLE_Lines rls;
    int no_runs,cy,ri;
    RLE_Run *lr;
    RLE_Yrun *ra,*cr;
    RLE_Line *cl;
	/* count runs */
	no_runs = no_runs_of_char(chp);
	/* allocate runs array */
	if((ra=(RLE_Yrun *)malloc(no_runs*sizeof(RLE_Yrun)))==NULL)
		abort("rlines_of_char: can't malloc ra[%d]",no_runs);
	runs_of_char(chp,ra,no_runs);
	/* sort runs ascending on (y,xs) */
	qsort(ra,no_runs,sizeof(RLE_Yrun),rn_asc);
	/* count RLE_lines.mny */
	rls.mny = 0; cy=Scoor_MIN;
	for(ri=0,cr=ra; ri<no_runs; ri++,cr++)
		if(cr->y!=cy) {
			rls.mny++;
			cy = cr->y;
			};
	/* allocate RLE_lines */
	if((rls.rla=(RLE_Line *)malloc(rls.mny*sizeof(RLE_Line)))==NULL)
		abort("rlines_of_page: can't malloc rls.rla[%d]",rls.mny);
	/* fill in RLE_lines */
	cy=Scoor_MIN;  cl=rls.rla-1;
	for(ri=0,cr=ra; ri<no_runs; ri++,cr++) {
		if(cr->y!=cy) {
			cl++;
			cl->y = cy = cr->y;
			cl->runs = 0;
			lr = cl->r;
			};
		lr->xs = cr->xs;  lr->xe = cr->xe;  lr++;  cl->runs++;
		};
	free(ra);
	return(&rls);
	}

int asc_merit(m1,m2)
    Merit *m1,*m2;
{	if(*m1 < *m2) return(-1);
	else if(*m1 > *m2) return(1);
	else return(0);
	}

/* Word merit is computed as a function of the merit of its Chars.
   No Chars forces merit to 0.0.
   The result is dominated by the weakest merit in the Word, slightly
   improved by the others. */
Merit wordmerit(w)
    Word *w;
{   register Char *cp,**cpp;
    static int m_alloc = 0;
    static Merit *ma;	/* ma[m_alloc] */
    int mi;
    Merit m;
    double wgt,sumwgt;
    
	if(w->cs.mny<=0) return(0.0);
	if(w->cs.mny>m_alloc) {
		if(m_alloc==0) {
			m_alloc=w->cs.mny;
			if((ma=(Merit *)malloc(m_alloc*sizeof(Merit)))==NULL)
				abort("wordmerit: can't malloc ma[%d]",m_alloc);
			}
		else {	m_alloc=w->cs.mny;
			if((ma=(Merit *)realloc(ma,m_alloc*sizeof(Merit)))==NULL)
				abort("wordmerit: can't realloc ma[%d]",m_alloc);
			};
		};
	for(cp= *(cpp=w->cs.cpa),mi=0; cp!=NULL; cp= *(++cpp),mi++) {
		if(cp->area==0 || cp->il.mny==0) ma[mi]=0.0;
		else ma[mi] = cp->il.fi->m;
		};
	qsort(ma,w->cs.mny,sizeof(Merit),asc_merit);
#define DOM (5.0)
	/* The worst merit is DOM times more significant than second worst, which
	   is DOM times more significant than the third worst, and so on.
	   */
	m=ma[0];  sumwgt=wgt=1.0;
	for(mi=1; mi<w->cs.mny; mi++) {
		m += ma[mi]*(wgt /= DOM);  sumwgt += wgt;
		};
	m /= sumwgt;
	return(m);
	}

WordSet *alloc_wordset(top,cut,cap)
    double top;		/* initial maximum merit (is never reduced) */
    double cut;		/* cut ratio:  don't keep merit < cut*top */
    int cap;		/* capacity: maximum no. at a time (0 ==> no limit) */
{   WordSet *res;
	if((res=(WordSet *)malloc(sizeof(WordSet)))==NULL)
		abort("alloc_wordset: can't");
	*res = empty_WordSet;
	res->top = top;
	res->cut = cut;
	if((res->cap = cap)==0) res->cap=INT_MAX;
	return(res);
	}

int free_wordset_etc(s,etc)
    WordSet *s;
    Ident etc;
{   int high;
	free_words_etc(&(s->ws),etc);
	high = s->high;
	free(s);
	return(high);
	}

/* Find the maximum-merit word in the set; among ties, pick the first seen. */
Word *find_max_wordset(s)
    WordSet *s;
{   register Word *max,**wpp;
	max=NULL;
	if(s->ws.mny>0) for(wpp=s->ws.wpa; *wpp!=NULL; wpp++) {
		if(max==NULL || max->m < (*wpp)->m) max=(*wpp);
		};
	return(max);
	}

/* Find the maximum-merit word in the set; among ties, pick the last seen. */
Word *find_min_wordset(s)
    WordSet *s;
{   register Word *min,**wpp;
	min=NULL;
	if(s->ws.mny>0) for(wpp=s->ws.wpa; *wpp!=NULL; wpp++) {
		if(min==NULL || min->m >= (*wpp)->m) min=(*wpp);
		};
	return(min);
	}

/* Insert a Word (without duplicating it).
   Update top, min, max, & high.
   If the new word's merit is equal to the current maximum, it does not become
   become the new maximum.
   If the new word's merit is equal to the current minimum, it becomes
   the new minimum.
   */
put_wordset(w,s)
    Word *w;	/* must have w->m set up */
    WordSet *s;
{	insert_word(w,&(s->ws));
	if(max_wordset(s)==NULL || max_wordset(s)->m < w->m) {
		max_wordset(s) = w;
		if(s->top < max_wordmerit(s)) s->top = max_wordmerit(s);
		};
	if(min_wordset(s)==NULL || min_wordset(s)->m >= w->m)
		min_wordset(s) = w;
	if(s->high < s->ws.mny) s->high = s->ws.mny;
	}

/* Remove a Word (without freeing it). Maintain min/max, but don't prune items.
   Also, don't lower top or high. */
Word *get_wordset(w,s)
    Word *w;
    WordSet *s;
{	if(w==NULL || s->ws.mny==0) return(NULL);
	remove_word(w,&s->ws);
	if(s->ws.mny==0) {
		max_wordset(s) = NULL;
		min_wordset(s) = NULL;
		}
	else {	if(w==max_wordset(s)) max_wordset(s) = find_max_wordset(s);
		if(w==min_wordset(s)) min_wordset(s) = find_min_wordset(s);
		};
	return(w);
	}

/* Remove a Word (without freeing it).  Maintain min/max.  Don't lower top. */
Word *remove_wordset(w,s,n)
    Word *w;
    WordSet *s;
    char *n;
{   register Word *gw;
#if dbg_ws
	if(w!=NULL) err("remove_wordset: %X %s",w,word_toa(w));
	else err("remove_wordset: NULL");
#endif
	gw=get_wordset(w,s);
#if dbg_ws
	err_wordset(s,n);
#endif
	return(gw);
	}

/* Check whether a given Word is identical to any already in a given set.
   Word *w must have its hash key set up. */
boolean member_wordset(w,s)
    Word *w;
    WordSet *s;
{   register Word **ww;
	if(s->ws.mny>0) {
		for(ww=s->ws.wpa; (*ww)!=NULL; ww++) {
			if(w->hash==(*ww)->hash && eq_word(w,(*ww)))
				return(T);
			};
		};
	return(F);
	}

/* Insert a Word into a set, maintaining uniqueness, a ``range'' property, and
   a maximum capacity.
   Uniqueness is maintained by refusing to insert words that are identical
   (eq_word()) to a word already in the set (or in set `u').
   The range property is that every word in the set must have merit no less
   than `s->cut' times the lifetime maximum for the set `s->top'.
   Maximum capacity is maintained as follows:  if insertion would mean more
   members than `cap', then either (a) the insertion is refused (if its
   merit is less than the current `min', or (b) the current `min' is deleted
   (and silently freed in its entirety), and the insertion occurs.
   The inserted Word is not duplicated.  If, as a result of an insertion,
   some of its words no longer satisfy the range property, they are silently
   removed (and freed in their entirety).
   Return T iff the Word is actually inserted.
   */
boolean insert_wordset(w,s,n,u)
    Word *w;
    WordSet *s;
    char *n;	/* name of set `s' */
    WordSet *u;	/* if !=NULL, also check uniqueness here */
{   Word *fr;
#if dbg_ws
	err("insert_wordset: %X %s",w,word_toa(w));
#endif
	if((w->m = wordmerit(w)) >= (s->cut * s->top)) {
		w->hash = hash_word(w);
		if(member_wordset(w,s) || (u!=NULL&&member_wordset(w,u)))
			/* don't insert */
			return(F);
		if(s->ws.mny==s->cap) /* at capacity */ {
			if(w->m <= min_wordmerit(s)) /* too poor */ return(F);
			else {	fr = remove_wordset(min_wordset(s),s);
				free_word_etc(fr,IsALL);
				};
			};
		put_wordset( w, s );
		if(max_wordset(s)==w) /* this has become the new maximum */ {
			while(min_wordmerit(s) < (s->cut * s->top)) {
				fr = remove_wordset(min_wordset(s),s);
				free_word_etc(fr,IsALL);
				};
			};
#if dbg_ws
		err_wordset(s,n);
#endif
		return(T);
		}
	else {
#if dbg_ws
		err_wordset(s,n);
#endif
		return(F);
		};
	}

err_wordset(s,n)
    WordSet *s;
    char *n;	/* name of set */
{   char m1[10],m2[10];
    register Word *wp,**wpp;
	fprintf( stderr,"WordSet %s: t%g c%g [%s/%X,%s/%X] m%d h%d: ",
		n,
		s->top,s->cut,
		strcpy(m1,merit_toa(max_wordmerit(s))),max_wordset(s),
		strcpy(m2,merit_toa(min_wordmerit(s))),min_wordset(s),
		s->ws.mny,s->high );
	if(s->ws.mny>0) for(wp= *(wpp=s->ws.wpa); wp!=NULL; wp= *(++wpp))
		fprintf(stderr,"%X/%s/%d ",wp,merit_toa(wp->m),wp->cs.mny);
	fprintf(stderr,"\n");
	}

translate_txtln(lp,off)
    Txtln *lp;
    Sp off;
{	lp->bx = *translate_bbx(&lp->bx,off);
	lp->basl += off.y;
	translate_chars(lp->cs,off);
	}

translate_chars(csp,off)
    Chars *csp;
    Sp off;
{   register Char *cp,**cpp;
	for(cp= *(cpp=csp->cpa); cp!=NULL; cp= *(++cpp))
		translate_char(cp,off);
	}

translate_char(cp,off)
    Char *cp;
    Sp off;
{	cp->bx = *translate_bbx(&cp->bx,off);
	translate_blobl(cp,off);
	}

translate_blobs(b,off)
    Blobs *b;
    Sp off;
{   register Blob *bp,**bpp;
	if(b->mny>0) for ( bp= *(bpp=b->bpa); bp!=NULL; bp= *(++bpp) )
		translate_blob(bp,off);
	}

translate_blobl(cp,off)
    Char *cp;
    Sp off;
{   int bi;
    register Blob *bp;
	for(bi=0,bp=cp->fi; bi<cp->bmny&&bp!=NULL; bi++,bp=bp->n)
		translate_blob(bp,off);
	}

translate_blob(bp,off)
    Blob *bp;
    Sp off;
{	bp->bx = *translate_bbx(&bp->bx,off);
	}

0707070035351137141006640007620000050000010262240476773367000000700000107063Text.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* Text.h - typedefs, constants, and function declarations for document-images
	(see Text.c for companion functions.)
   INCLUDES
	requires prior:
		#include "stdocr.h"
 */

#define dbg_fwrb_toa (F)	/* err("%s",R_toa()) for each record written */
#define dbg_frdb_toa (F)	/* err("%s",R_toa()) for each record read */

#define DIM_VERSION (0)		/* current version no. of Dim-file format */

#include "Bfeats.h"

#define Ident int	/* identification bits [MUST BE >=32 bits] */

#define fwri_Ident(F,V) fwri_uint4((F),(V))
#define frdi_Ident(F) frdi_uint4(F)

/* Ident bits */
/* identifies external file record type(s) */
#define IsPage		04000000000
#define IsBlock		02000000000
#define IsTxtln		01000000000
#define IsWord		00020000000
#define IsChar		00400000000
#define IsBlob		00200000000
#define IsRun		00100000000	/* should be IsRuns or IsLag */
#define IsRuns		(IsRun)
#define IsInterp	00040000000	/* Char interpretation */
#define IsBdy		00010000000
#define IsShapes	00004000000
#define IsLag		00002000000
#define IsBfeats	00001000000
#define IsSfeats	00000400000
#define IsWordInterp	00000200000
/* Runs:  set in Blob records' ids.
   At most one of these may be set in main memory.
   Only Runs_ff or Runs_g4 may be set in peripheral file format. */
#define Runs_f		00000010000	/* Runs are in list, starting *.r.f */
#define Runs_ff		00000020000	/* RunFs are in array, at *.r.ff */
#define Runs_seek	00000040000	/* Runs are still in file, at *.seek */
#define Runs_g4		00000100000	/* Runs are in CCITT Group 4 format */

/* CCITT Group 4 format in peripheral files consists of (a) an unsigned long count,
   then (b) that many bytes of Group 4 encoding exactly as in CCITT
   Recommendation T.6, except that no EOFB code is appended, since the end of
   the bitmap can be detected using the bounding box of the owning Blob.
   Instead, the last scan line of the bitmap is merely padded to the nearest
   full byte with '0' bits.  This compresses the representation by about
   a factor of 8 on average, compared to RunF/RunFS encoding. */

#define IsALL (IsPage|IsBlock|IsTxtln|IsWord|IsChar|IsBlob|IsRun|IsBdy|IsInterp|IsShapes|IsLag|IsBfeats|IsSfeats|IsWordInterp)
#define IsNONE		0


/* Enable optional debugging-support code to maintain a count of selected record
   types that are allocated using alloc_* free_* and dup_* functions.  The counts
   are in units of records, not bytes.  By design, has no effect at all on
   correctness.  */
#define ALLOC_CENSUS (0)

#if ALLOC_CENSUS

typedef struct Census {
	int Page_mny;
	int Block_mny;
	int Txtln_mny;
	int Word_mny;
	int Char_mny;
	int Blob_mny;
	int Run_mny;
	int Interp_mny;
	int Bfeats_mny;
	int BMask_mny;
	} Census;

#define Init_Census {0,0,0,0,0,0,0,0,0,0}
#if MAIN
Census empty_Census = Init_Census;
Census _CENSUS = Init_Census;
#else
extern Census empty_Census;
extern Census _CENSUS;
#endif

#define alloc_census(id,n) _CENSUS./**/id/**/_mny += (n)
#define free_census(id,n) _CENSUS./**/id/**/_mny -= (n)
#define err_census(S,C) err("%s P%d B%d l%d w%d c%d b%d r%d i%d bf%d bm%d",\
	S,(C)->Page_mny,(C)->Block_mny,(C)->Txtln_mny,(C)->Word_mny,\
	(C)->Char_mny,(C)->Blob_mny,(C)->Run_mny,(C)->Interp_mny,\
	(C)->Bfeats_mny,(C)->BMask_mny )
#define err_census_all err_census("allocated: ",&(_CENSUS))
#define err_census_rec(rp) { \
	Census *cs;  cs = (Census *)census_rec((rp)); \
	err_census(ident_toa((rp)->ident),cs); \
	}
#else

#define alloc_census(i,n)
#define free_census(i,n)
#define err_census(s,c)
#define err_census_all
#define err_census_rec(r)

#endif


/* Most record types can own an ASCII label, which is simply a
   '\0'-terminated string.  Its uses are varied. */
#define MAX_LABEL_LEN 128	/* maximum no. characters in a label string */

#if FWRI

#if dbg_fwrb_toa
#define fwrb_label(F,L) { \
	fwri_str((F),(L)); \
	err("fwrb_label: \"%s\"",(L)); \
	}
#else
#define fwrb_label(F,L) { \
	fwri_str((F),(L)); \
	}
#endif

#else

#if dbg_fwrb_toa
#define fwrb_label(F,L) { \
	fputs((L),(F)); \
	fputc('\0',(F)); \
	err("fwrb_label: \"%s\"",(L)); \
	}
#else
#define fwrb_label(F,L) { \
	fputs((L),(F)); \
	fputc('\0',(F)); \
	}
#endif

#endif

char *frdb_label();

/* A boundary is an ordered list of vertices.
   In some uses, it is assumed to close:  in this case, the first point
   is not repeated at the end.
   `vn' counts the no. vertices.  bdy_trace omits consecutive duplicates and
   compresses horizontal and vertical runs.
   `per' counts the no. of pixels on the 8-connected boundary.  An attempt has been
   made not to count consecutive duplicate pixels, but this may be buggy.
   `ren' counts the number of run-ends touched.  Each run contributes two ends,
   even if it is one pixel long.  The sum of ren-counts among all bdys for a blob
   should equal exactly twice the no. runs.
   Note that vn<=per and vn<=2*ren, and (probably) ren<=per.
   A ``smoothed'' version (courtesy of John Hobby) may be given in s[],
   expressed in fractional pixels.
   */
typedef struct Bdy {
	Ident ident;	/* shows type of boundary */
	Bbx bx;		/* bounding box (usually relative to blob's bx.a) */
	long per;	/* no. pixels in 8-connected perimeter */
	int ren;	/* no. run-ends touched */
	int vn;		/* no. distinct vertices in v[] */
	Sp *v;		/* array of vn+1 vertices, v[0]==v[vn] (malloc space) */
	short fr;	/* fraction of pixels used in smoothed outline */
	int sn;		/* no. distinct smoothed vertices in s[] */
	Sp *s;		/* array of sn+1 vertices, s[0]==s[sn] (malloc space) */
	int an;		/* no. vertices in polygonal approximation */
	Sp **ap;	/* approx'n: array of an ptrs into v[] (in malloc space) */
	float err;	/* error tolerance used for approximation */
	int hn;		/* no. vertices in convex hull of polygonal approx'n */
	Sp ***hpp;	/* convex hull: array of hn ptrs into ap[] (malloc) */
	struct Bdy *n;	/* for use when a member of a linked-list */
	} Bdy;

#define Init_Bdy {IsBdy,Init_Bbx,0,0,0,NULL,1,0,NULL,0,NULL,0.0,0,NULL,NULL}
#if MAIN
Bdy empty_Bdy = Init_Bdy;
#else
extern Bdy empty_Bdy;
#endif

#define Bdy_verts	00000000001	/* vertices */
#define Bdy_approx	00000000002	/* polygonal approx'n */
#define Bdy_hull	00000000004	/* convex hull */
#define Bdy_ALL		(Bdy_verts|Bdy_approx|Bdy_hull)
#define Bdy_ccw		00000000100	/* winding order is counter-clockwise*/
#define Bdy_half	00000000200	/* uses half-pixel boundary points */

/* A boundaries-set is an ordered list of boundaries.
   In some uses, they are used to enclose a connected region:  in this case,
   all are closed, and the first is conventionally the exterior and the others
   are interior boundaries.  The interior is then always to the left
   of the boundary:  that is, the exterior boundary is oriented counter-
   clockwise, and the interior boundaries clockwise */
typedef struct Bdys {
	int mny;	/* no. boundaries */
	long per;	/* perimeter of all bdys */
	Bdy *b;		/* array of boundaries (malloc space) (sometimes first) */
	} Bdys;

#define Init_Bdys {0,0,NULL}
#if MAIN
Bdys empty_Bdys = Init_Bdys;
#else
extern Bdys empty_Bdys;
#endif

/* A boundary edge is an ordered pair of vertices along a boundary.  It implicitly
   describes an 8-connected sequence of pixels from a to b, inclusive.  Also
   used for straight-line approximations to the set of pixels, and the convex hull
   of such an approximation. */
typedef struct BdyEdge {
	Bdy *byp;	/* boundary to which it belongs */
	Sp *ap,*bp;	/* ptrs into byp->v */
	long per;	/* perimeter:  no. 8-connected pixels */
	Pp ctr;		/* centroid */
	Radians ang;	/* ls-fitted angle (directed roughly from a to b) */
	Pp a;		/* endpoints a & b (with sub-pixel precision) */
	Pp b;
	} BdyEdge;

#define Init_BdyEdge {NULL,NULL,NULL,0,Init_Zero_Pp,0.0,Init_Zero_Pp,Init_Zero_Pp}
#if MAIN
BdyEdge empty_BdyEdge = Init_BdyEdge;
#else
extern BdyEdge empty_BdyEdge;
#endif

/* Ordered set of BdyEdges */
typedef struct BdyEdges {
	int mny;
	BdyEdge **pa;	/* NULL-terminated array of pointers to BdyEdges */
	} BdyEdges;

#define Init_BdyEdges {0,NULL}
#if MAIN
BdyEdges empty_BdyEdges = Init_BdyEdges;
#else
extern BdyEdges empty_BdyEdges;
#endif

/* Moments of a region (or boundary-list) of pixels */

typedef struct Moments {
	/* 0th moment */
	int M00;	/* area: sum of 1 */
	/* 1st moments */
	int M10;	/* sum of xi */
	int M01;	/* sum of yi */
	Pp c;		/* centroid: M10/M00, M01/M00 */
	/* 2nd moments (relative to centroid) */
	float M20;	/* sum of rxi*rxi */
	float M11;	/* sum of rxi*ryi */
	float M02;	/* sum of ryi*ryi */
	Radians a;	/* orientation angle, in [-PI/2,PI/2) (radians) */
	Pp d;		/* directional vector of principal axis */
	} Moments;

#define Init_Moments {0,0,0,{0.0,0.0},0.0,0.0,0.0,0.0,{0.0,0.0}}
#if MAIN
Moments zero_Moments = Init_Moments;
#else
extern Moments zero_Moments;
#endif

/* functions in Text.c */
Bdy *alloc_bdy();
Bdys *alloc_bdys();

/* functions in Bdy.c */
Bdys *dup_bdys_etc();
Bdy *dup_bdy_etc();
Bdys *boundaries();
char *moments_toa();
Moments *bdy_moments();
boolean fit_bdyedge();
BdyEdge *dup_bdyedge();
BdyEdge *append_bdyedge();
remove_bdyedge();
free_bdyedges();
BdyEdges *dup_bdyedges();

/* Each Run is initially inserted into a `line set', owned by its scan Line.
   Later, as connections are discovered, it joins a `tree set'.
   When the forest of trees of which it is a part is finally complete, the Run
   is removed from its `line set', and added to a `blob set'.
   */

typedef struct Run {	/* internal (main memory) record */
	Scoor y, xs, xe;	/* coordinates of black interval (y,[xs,xe]) */
	struct Run *n;		/* line & blob sets: next Run */
	unsigned short ad, bd;	/* tree set: above,below degrees (no. conn'd)*/
	struct Run *ac, *bc;	/* tree set: above,below leftmost connections */
	union {	struct Tree *o;	/* tree set: owner Tree */
		int no;		/* blob set: sequence no. 0,1,... in set */
		} u;		/* (overlain fields) */
	} Run;

#define Init_Run {0,0,0,NULL,0,0,NULL,NULL}
#if MAIN
Run empty_Run = Init_Run;
#else
extern Run empty_Run;
#endif

/* Peripheral file format.  `ac' and `bc' are relative to the position
   of this run in the canonical run order. */
typedef struct RunF {	/* external (peripheral file) record (full size) */
	Scoor y, xs, xe;	/* coordinates of black interval (y,[xs,xe]) */
	unsigned short ad, bd;	/* above,below degrees */
	unsigned short ac, bc;	/* above,below leftmost connections (indices) */
	} RunF;

#define Init_RunF {0,0,0,0,0,0,0}
#if MAIN
RunF empty_RunF = Init_RunF;
#else
extern RunF empty_RunF;
#endif

#define fwri_RunF(F,P) { \
	fwri_Scoor((F),(P)->y); \
	fwri_Scoor((F),(P)->xs); \
	fwri_Scoor((F),(P)->xe); \
	fwri_uint2((F),(P)->ad); \
	fwri_uint2((F),(P)->bd); \
	fwri_uint2((F),(P)->ac); \
	fwri_uint2((F),(P)->bc); \
	}

#define frdi_RunF(F,P) ( feof(F)? 0 : ( \
	(P)->y=frdi_Scoor(F), \
	(P)->xs=frdi_Scoor(F), \
	(P)->xe=frdi_Scoor(F), \
	(P)->ad=frdi_uint2(F), \
	(P)->bd=frdi_uint2(F), \
	(P)->ac=frdi_uint2(F), \
	(P)->bc=frdi_uint2(F), \
	(ferror(F)? -errno: 1) ) )

/* In `well-behaved' text, the overwhelming majority of Blobs are small
   enough that all their Runs can be encoded using character data fields,
   a factor of two saving, which is important since a dense IEEE proceedings
   page blob file would otherwise require 2.3Mbytes */
typedef struct RunFS {	/* external (peripheral file) record (small size) */
	unsigned char y, xs, xe;/* coordinates of black interval (y,[xs,xe]) */
	unsigned char ad, bd;	/* above,below degrees */
	unsigned char ac, bc;	/* above,below leftmost connections (indices) */
	} RunFS;

#define Init_RunFS {0,0,0,0,0,0,0}
#if MAIN
RunFS empty_RunFS = Init_RunFS;
#else
extern RunFS empty_RunFS;
#endif

#define fwri_RunFS(F,P) { \
	fwri_uint1((F),(P)->y); \
	fwri_uint1((F),(P)->xs); \
	fwri_uint1((F),(P)->xe); \
	fwri_uint1((F),(P)->ad); \
	fwri_uint1((F),(P)->bd); \
	fwri_uint1((F),(P)->ac); \
	fwri_uint1((F),(P)->bc); \
	}

#define frdi_RunFS(F,P) ( feof(F)? 0: ( \
	(P)->y=frdi_uint1(F), \
	(P)->xs=frdi_uint1(F), \
	(P)->xe=frdi_uint1(F), \
	(P)->ad=frdi_uint1(F), \
	(P)->bd=frdi_uint1(F), \
	(P)->ac=frdi_uint1(F), \
	(P)->bc=frdi_uint1(F), \
	(ferror(F)? -errno: 1) ) )

/* Set of runs.  PROPOSED NEW FORMAT.  Not yet incorporated widely. */
typedef struct Runs {
	Ident ident;	/* IsRuns & Runs_fi, Runs_ff, Runs_fs, or Runs_sk flags */
	int mny;	/* no. runs */
	union {	/* access to runs */
		struct Run *fi;	  /* first run of singly-linked list */
		struct RunF *ff;  /* top of RunF[mny] array */
		struct RunFS *fs; /* top of RunFS[mny] array */
		long sk;	  /* seek(F,seek,0) will find them in file F */
		} r;
	} Runs;

#define Init_Runs {IsRuns,0}	/* NOTE: can't initialize union */
#if MAIN
Runs empty_Runs = Init_Runs;
#else
extern Runs empty_Runs;
#endif

/* INTERNAL management */

#if !MAIN
extern
#endif
struct {
	int incr;		/* size of each pool[i] */
	int pools;		/* no. of pools allocated */
	Run **pool;		/* malloc space Run pool[pools][0..incr-1] */
	int next;		/* the next avail Run is:  pool[pools-1][next] */
	Run *free;		/* head of free lifo list (NULL if none) */
	Run *cur;		/* most-recently allocated Run */
	int total;		/* total no. ever allocated */
	boolean dbg;
	} _RunPool
#if MAIN
	= {0,0,NULL,0,NULL,NULL,0,F}
#endif
;

/* Run management routines (Text.c) */
boolean	alloc_run_pool();
	free_run_pool();
Run	*hard_alloc_run();
	err_run();
	err_runb();
	err_runf();
	err_runfs();
	err_run_stats();

/* Allocate a Run from the RunPool (returns (Run *)) -- mostly inline */
#define alloc_run() ( _RunPool.total++, (_RunPool.free!=NULL)? \
	(_RunPool.cur=_RunPool.free,_RunPool.free=_RunPool.cur->n, \
		*(_RunPool.cur)=empty_Run,_RunPool.cur): \
	( (_RunPool.next<_RunPool.incr)? \
	  (_RunPool.cur=_RunPool.pool[_RunPool.pools-1]+(_RunPool.next++), \
		*(_RunPool.cur)=empty_Run,_RunPool.cur): \
	  hard_alloc_run() ) )

/* Free a Run back into the RunPool -- entirely inline */
#define free_run(rp) { (rp)->n = _RunPool.free; _RunPool.free = (rp); }

/* EXTERNAL file format:
   If BlobF.runs is zero, then conventionally the Runs have simply been omitted.
   The RunF.y, RunF.xs, & RunF.xe coordinates are offsets from BlobF.bx.a 
   (their blob's left-top corner).  RunF.ac & RunF.bc index into an array of
   only those RunF records belonging to the current BlobF, in ascending
   lexicographic order on (RunF.y,RunF.xs) -- so that they are in the range
   [0,BlobF.runs-1].
 IMPROVEMENTS:
  */

/* some subroutines are too lazy to handle indefinitely large blobs */
#define Runs_Max 10000	

/* A Blob is (formally) a maximal 8-connected set of black pixels.
   The connectivity algorithm finds them in strictly increasing order on
   (y,xe) of its Run with highest (y,xe).
   */

typedef struct Blob {	/* internal (main memory) record */
	Ident ident;	/* identification bits */
	Seq no;		/* blob sequence no */
	Bbx bx;
	long area;
	long per;
	struct Blob *n;	/* free set: next blob */
	Merit m;	/* Only used locally (not for peripheral file) */
	Runs *rsp;	/* runs (not yet used) */
	Bdys *bdsp;	/* boundaries (in malloc space); NULL if none */
	/* presently in use (but planned to be replaced by Runs) */
	int runs;
	union {	/* to find runs */
		struct Run *f;		/* blob set: first run */
		struct RunF *ff;	/* top of RunF array */
		long seek;		/* seek(f,seek,0) will find them */
		} r;
	} Blob;

#define Init_Blob {IsBlob,0,Init_Bbx,0,0,NULL,0.0,NULL,NULL,0,}
#if MAIN
Blob empty_Blob = Init_Blob;
#else
extern Blob empty_Blob;
#endif

typedef struct Blobs {	/* Blob set */
	int mny;	/* the number of pointers in set */
	Blob **bpa;	/* pts to NULL-terminated array[mny+1] of pointers */
	} Blobs;

#define Init_Blobs {0,NULL}
#if MAIN
Blobs empty_Blobs = Init_Blobs;
#else
extern Blobs empty_Blobs;
#endif

/* Singly-linked list of Blobs.  Only forward `next' links Blob.n are used. */
typedef struct Blobl {	/* Blob list */
	int mny;	/* the number in set */
	Blob *fi;	/* to first */
	Blob *la;	/* to last */
	} Blobl;

#define Init_Blobl {0,NULL,NULL}
#if MAIN
Blobl empty_Blobl = Init_Blobl;
#else
extern Blobl empty_Blobl;
#endif

typedef struct BlobF {	/* external file format */
	Ident ident;	/* identification bits: IsBlob must be set */
	Bbx bx;
	long area;
	long per;
	int runs;	/* no. runs to follow */
	short bdys;	/* no. bdys to follow */
	} BlobF;

/* Blob identification bits */
#define Blob_lm		00000000001	/* touches left margin */
#define Blob_rm		00000000002	/* touches right margin */
#define Blob_tm		00000000004	/* touches top margin */
#define Blob_bm		00000000010	/* touches bottom margin */
#define Blob_chopt	00000000020	/* chopped (at the top) */
#define Blob_chopb	00000000040	/* chopped (at the bottom) */
#define Blob_chopl	00000002000	/* chopped (at the left) */
#define Blob_chopr	00000004000	/* chopped (at the right) */
#define Blob_small	00000000200	/* its runs (can be) compressed x2 */
#define Blob_local	00000000400	/* unassigned:  avail for local pgm use */

/* INTERNAL management: */

int hi_blob_no;		/* current highest blob no */

/* Blobs are allocated from a pool of free ones */
int blob_max;
Blob *blob_pool;
Blob blob_fr;		/* head of list of free blobs */
int blob_fr_mny;
int blob_hi;		/* high-water mark in blob pool */
int blob_chopped;	/* total no. of blobs that were chopped */
boolean blob_debug;	/* debug traces? */

/* EXTERNAL file format:
   A Blob file consists of an arbitrary number of:
       BlobF record, followed by BlobF.runs instances of:
           RunF record
   If BlobF.runs is zero, then conventionally the Runs have simply been omitted.
   The RunF.y, RunF.xs, & RunF.xe coordinates are relative offsets from BlobF.bx.a 
   (their blob's left-top corner).  RunF.ac & RunF.bc index into an array of
   only those RunF records belonging to the current BlobF, in ascending
   lexicographic order on (RunF.y,RunF.xs) -- so that they are in the range
   [0,BlobF.runs-1].  If ad(or, bd)==0, the ac(or, bc) is undefined (conn sets
   them conventionally to 0).
   */

/* Blob management routines (conBlob.c) */
Blob	*alloc_blob();
	free_blob();
boolean	alloc_blob_pool();
	free_blob_pool();
Blob	*alloc_pool_blob();
	free_pool_blob();
	out_blob();
        fwrb_blob_etc();
boolean frdb_blob_etc();
boolean	frdb_runfs();
	err_blob();
	err_blob_runs();
	err_blob_runfs();
	err_blob_briefly();
	err_blobf();
	err_blob_stats();
boolean	blob_small();

/* Compute height-above-baseline in ems of Char *cp w.r.t. Txtln *lp,
   on a page of y-resolution res.  The txtln's `basl' & `size' must be set up. */
#define char_bhgt(cp,lp,res) \
	((((cp)->bx.b.y - (lp)->basl)/(double)(res)*INS_PER_PT*(lp)->size))

/* an Interpretation of a Char */
typedef struct Interp {
	Ident ident;
	struct Cl *clp;		
	struct Class *clsp;
	ClassId ci;		/* class id (font, size, name, variant) */
	Merit mshap;		/* shape merit in [0,1] */
	Pts size;		/* implied text size */
	Merit msize;		/* size merit in [0,1] */
	Scoor basl;		/* implied absolute baseline location */
	Merit mbhgt;		/* height-above-baseline merit in [0,1] */
	Merit m;		/* match merit (due to mshap, msize, & mbhgt) */
	Prob p;			/* approximate probability */
	struct Interp *n;	/* next in singly-linked list */
	} Interp;

#define Init_Interp {IsInterp,NULL,NULL,Init_ClassId,0.0,0.0,0.0,0,0.0,0.0,0.0,NULL}
#if MAIN
Interp empty_Interp = Init_Interp;
#else
extern Interp empty_Interp;
#endif

/* Interp.ident flags: */
#define Interp_spelled	00000000001	/* has passed a spelling check */

#define free_interp(i) {free((i)); free_census(Interp,1); }

typedef struct InterpF {
	Ident ident;
	ClassId ci;		/* class id (font, size, name, variant) */
	Merit mshap;		/* shape merit */
	Pts size;		/* implied text size (in points) */
	Merit msize;		/* size merit */
	Scoor basl;		/* implied baseline location */
	Merit mbhgt;		/* height-above-baseline merit */
	Merit m;		/* match merit (due to shp, siz, hgt) */
	} InterpF;

/* a list of interpretations */
typedef struct Interpl {
	short mny;		/* no. in list */
	struct Interp *fi;	/* first in list (mny==0 -> fi==NULL) */
	} Interpl;

#define Init_Interpl {0,NULL}
#if MAIN
Interpl empty_Interpl = Init_Interpl;
#else
extern Interpl empty_Interpl;
#endif

/* a set of interpretations */
typedef struct Interps {
	short mny;		/* no. in set */
	struct Interp **pa;	/* NULL-terminated array of ptrs (malloc spc) */
	Merit m;		/* combined merit (normalized product) */
	} Interps;

#define Init_Interps {0,NULL,0.0}
#if MAIN
Interps empty_Interps = Init_Interps;
#else
extern Interps empty_Interps;
#endif

typedef struct Shapes {
	short mny;	/* no. items in set */
	short alloc;	/* no. items that can fit in array (alloc>=mny) */
	Nb_s *sa;	/* ptr to contiguous array (malloc space) */
	} Shapes;

#define Init_Shapes {0,0,NULL}
#if MAIN
Shapes empty_Shapes = Init_Shapes;
#else
extern Shapes empty_Shapes;
#endif

#define SH_INCR (20)	/* Shapes are allocated by this increment */

#define init_sh(sh) { \
	(sh)->alloc = SH_INCR; \
	if(((sh)->sa=(Nb_s *)malloc((sh)->alloc*sizeof(Nb_s)))==NULL) \
		abort("can't alloc sh->sa[%d]",(sh)->alloc); \
	(sh)->mny = 0; \
	}

#define add_sh(s,sh) { \
	if((sh)->mny==(sh)->alloc) { \
		(sh)->alloc += SH_INCR; \
		if(((sh)->sa=(Nb_s *)realloc((sh)->sa,(sh)->alloc*sizeof(Nb_s)))==NULL) \
			abort("can't alloc (sh)->sa[%d]",(sh)->alloc); \
		}; \
	(sh)->sa[(sh)->mny++] = *(s); \
	}

/* Parameters governing the pseudo-random generation of a Char image
   using a 1st-order statistical model of imaging. */ 
typedef struct RanParms {
	short res_x;	/* -r resolution (scanner pels/inch) */
	short res_y;	/*    (for now, equal to res_x) */
	Pts size;	/* -p size of text */
	Radians skew;	/* -a skew angle */
	Ems bhgt;	/* -b height above baseline */
	float blur;	/* -e blurring std err (scanner pels) */
	float jitter;	/* -j jitter std err (scanner pels) */
	float kern;	/* -k kerning std err (scanner pels) */
	float speckle;	/* -s pel-wise additive noise std err (scanner pels) */
	float thresh;	/* -t threshold for binarization */
	float xscale;	/* -x horizontal scaling (dimensionless) */
	float yscale;	/* -y vertical scaling (dimensionless) */
	} RanParms;
#define Init_RanParms {0,0,0.0,0.0,0.0,0.7,0.0,0.0,0.125,0.25,1.0,1.0}
#if MAIN
RanParms empty_RanParms = Init_RanParms;
#else
extern RanParms empty_RanParms;
#endif

RanParms *alloc_ranparms();
RanParms *dup_ranparms();
char *ranparms_toa();
RanParms *ato_ranparms();
fwrb_ranparms();
int frdb_ranparms();

/* Char - a character:  isolated, elementary symbol of the writing system;
   linguists might call this a `graph' */
typedef struct Char {
	Ident ident;		/* feature bits */
	Bbx bx;
	Scoor csp;		/* space before character in Txtln (abs. coords) */
	long area;		/* no. pixels */
	long per;		/* perimeter (all bdys) */
	Scoor basl;		/* baseline (absolute coordinates, local copy) */
	/* next should be Blobl */
	int bmny;		/* no. blobs in Char */
	struct Blob *fi;	/* 1st in list (p.n ptrs) (bmny==0 -> fi==NULL) */
	Pval *sfv;		/* scalar-features (SFv) */
	Shapes sh;		/* set of shapes (size- & loc'n-invariant) */
	Bfeats *bfsp;		/* binary features */
	RanParms *rp;		/* randomizing parameters */
	Interpl il;		/* interpretations */
	char *l;		/* label (ASCII string in malloc space) */
	} Char;

#define Init_Char {IsChar,Init_Bbx,0,0L,0L,Scoor_MIN,0,NULL,NULL,Init_Shapes,NULL,NULL,Init_Interpl,NULL}
#if MAIN
Char empty_Char = Init_Char;
#else
extern Char empty_Char;
#endif

/* Char.ident flags: */
#define Char_spelled	00000000001	/* Its 1st Interp is in correct spelling */
#define Char_confused	00000000002	/* The classifier may have confused this */
#define Char_termhyp	00000000004	/* a terminal hyphen of its Word */
#define Char_omit	00000000010	/* can be omitted */
#define Char_label	00000000020	/* has an ASCII string label */
#define Char_ranparms	00000000040	/* has RanParms */
#define Char_split	00000000100	/* resulted from splitting a Char */
#define Char_merged	00000000200	/* resulted from merging Chars */

typedef struct Chars {
	int mny;	/* mny==0 -> cpa==NULL */
	Char **cpa;	/* pts to NULL-term'd array of ptrs (in malloc space) */
	} Chars;

#define Init_Chars {0,NULL}
#if MAIN
Chars empty_Chars = Init_Chars;
#else
extern Chars empty_Chars;
#endif

/* CharF - Char external file format */
typedef struct CharF {
	Ident ident;		/* feature bits: IsChar must be set */
	Bbx bx;
	Scoor csp;		/* space before character in Txtln (abs. coords) */
	long area;
	long per;
	short bmny;		/* no. blobs to follow */
	short imny;		/* no. interpretations (follows immediately) */
	short sfmny;		/* no. scalar features (follows immediately) */
	short shmny;		/* no. shape features (follows immediately) */
	short bfmny;		/* no. binary features (follows immediately) */
	/* if ident&Char_ranparms, RanParms follows CharF */
	/* if ident&Char_label, label follows CharF ('\0'-terminated string) */
	} CharF;

Char *alloc_char();		/* in Text.c */
Char *append_char();
Char *insert_char();
Char *insert_char_word();
Char *dup_char();
Char *dup_char_etc();
Chars *append_chars();
Chars *dup_chars_etc();

typedef struct Words {
	int mny;		/* mny==0 -> wpa==NULL */
	struct Word **wpa;	/* pts to NULL-term'd array of ptrs */
	} Words;

#define Init_Words {0,NULL}
#if MAIN
Words empty_Words = Init_Words;
#else
extern Words empty_Words;
#endif

/* Word - one or more Chars lying in a textline close together.
   wsp (word space) is always >=0 and is scaled by xheight (of Txtln) */
typedef struct Word {
	Ident ident;		/* feature bits */
	Bbx bx;
	float wsp;		/* space before word (multiple of wst*em) */
	Merit m;		/* Word merit (function of its Char's merits) */
	Prob p;			/* probability */
	Words ws;		/* set of alternative segmentations */
	Chars cs;
	Blobs bs;
	char *l;		/* label (ASCII string in malloc space) */
	int hash;		/* hash key for fast equality checking */
	} Word;

#define Init_Word {IsWord,Init_Bbx,0.0,0.0,0.0,Init_Words,Init_Chars,Init_Blobs,NULL,0}
#if MAIN
Word empty_Word = Init_Word;
#else
extern Word empty_Word;
#endif

/* Word-interpretation (as printable ASCII string).
   All string fields must point to malloc-space strings.
   */
typedef struct WordInterp {
	Ident ident;	/* identifies word type */
	char *s;	/* entire string = pp+by+po+ps */
	char *pp;	/* punctuation prefix */
	char *by;	/* body of word */
	char *po;	/* possessive ('s 'S) or negative (n't N'T) suffix */
	char *ps;	/* punctuation suffix */
	} WordInterp;

#define Init_WordInterp {IsWordInterp,NULL,NULL,NULL,NULL,NULL}
#if MAIN
WordInterp empty_WordInterp = Init_WordInterp;
#else
extern WordInterp empty_WordInterp;
#endif

WordInterp *dup_wordinterp_etc();

/* Word.ident & WordInterp.ident flags: */
#define Word_spelled	00000000001	/* by spells correctly */
#define Word_wf		00000000002	/* s is well-formed */
#define Word_ok		00000000004	/* s is ok ("acceptable") */
#define Word_numeric	00000000010	/* by is numeric */
#define Word_initcap	00000000020	/* by has initial capital */
#define Word_allcaps	00000000040	/* by is all caps */
#define Word_hyphens	00000000100	/* by has imbedded hyphens */
#define Word_slashes	00000000200	/* by has imbedded slashes */
#define Word_endsent	00000000400	/* end of sentence: ps has .!? */
#define Word_termhyp	00000001000	/* some interpretation ends with hyphen */
#define Word_label	00000002000	/* has an ASCII string label */
#define Word_allalp	00000004000	/* s is all alphabetic */
#define Word_bodalp	00000010000	/* by is all alphabetic */

/* WordF - Word external file format */
typedef struct WordF {
	Ident ident;		/* feature bits: IsWord must be set */
	Bbx bx;
	float wsp;		/* space before word (multiple of thr) */
	float m;		/* merit */
	short wmny;		/* no. Words (in Word.ws) to follow this Word */
	short cmny;		/* no. Chars to follow this Word */
	short bmny;		/* no. Blobs to follow this Word */
	/* if ident&Word_label, label follows WordF ('\0'-terminated string) */
	} WordF;

/* constant pitch model for a Txtln */
typedef struct ConstPitch {
	Ems w;		/* Character pitch */
	Scoor o;	/* origin (one of the character break points) */
	float r;	/* max/min autocorrelation ratio - the larger the better */
	} ConstPitch;

#define Init_ConstPitch {0.0,0,0.0}
#if MAIN
ConstPitch empty_ConstPitch = Init_ConstPitch;
#else
extern ConstPitch empty_ConstPitch;
#endif

typedef struct Txtlns {
	short mny;
	struct Txtln **lpa;	/* to array of Txtln's (if mny==0, lpa==NULL) */
	} Txtlns;

#define Init_Txtlns {0,NULL}
#if MAIN
Txtlns empty_Txtlns = Init_Txtlns;
#else
extern Txtlns empty_Txtlns;
#endif

/* Text Line */
#define Txtln_label	00000000004	/* has an ASCII string label */
#define Txtln_size	00000000002	/* dominant text size chosen */
#define Txtln_basl	00000000001	/* dominant baseline chosen */

typedef struct Txtln {
	Ident ident;
	Bbx bx;
	Pts size;	/* dominant text size (0 means unknown) */
	Scoor basl;	/* dominant baseline (absolute y coordinate) */
	short *proj;	/* ptr to malloc space projection array */
	ConstPitch *cp;	/* ptr to malloc space constant-pitch model */
	Merit m;	/* merit */
	Txtlns ls;	/* alternative Txtln segmentations */
	Words ws;	/* sorted asc. on x */
	Chars cs;	/* sorted asc. on bx.a.x */
	Blobs bs;	/* misc. non-char blobs */
	char *l;	/* label (ASCII string in malloc space) */
	} Txtln;

#define Init_Txtln {IsTxtln,Init_Bbx,0.0,0,NULL,NULL,0.0,Init_Txtlns,Init_Words,Init_Chars,Init_Blobs,NULL}
#if MAIN
Txtln empty_Txtln = Init_Txtln;
#else
extern Txtln empty_Txtln;
#endif

/* Text Line */
typedef struct TxtlnF {
	Ident ident;	/* IsTxtln must be set */
	Bbx bx;
	Scoor basl;	/* baseline (absolute y coordinate) */
	Pts size;	/* text size (<=0.0 means none is known) */
	short pmny;	/* no. shorts in projection array to follow */
	float m;	/* merit */
	short lmny;	/* no. alternative txtlns to follow */
	short wmny;	/* no. words to follow */
	short cmny;	/* no. chars to follow */
	int bmny;	/* no. blobs to follow */
	/* if ident&Txtln_label, label follows TxtlnF ('\0'-terminated string) */
	} TxtlnF;

/* blocks of text */
typedef struct Blocks {
	short mny;		/* if mny==0, bpa==NULL */
	struct Block **bpa;	/* to NULL-term'd array of ptrs */
	} Blocks;

#define Init_Blocks {0,NULL}
#if MAIN
Blocks empty_Blocks = Init_Blocks;
#else
extern Blocks empty_Blocks;
#endif

/* block of text */
typedef struct Block {
	Ident ident;
	Bbx bx;		/* bounding box of block */
	Radians skew;	/* skew angle (as correction to Page.skew) */
	Radians shear;	/* shear angle (as correction to Page.shear) */
	Ems wst;	/* word-space threshhold */
	Merit m;	/* merit */
	Blocks bks;	/* Blocks nested within this one */
	Txtlns ls;
	Words ws;
	Chars cs;
	Blobs bs;
	char *l;	/* label (ASCII string in malloc space) */
	} Block;

#define Init_Block {IsBlock,Init_Bbx,0.0,0.0,0.0,0.0,Init_Blocks,Init_Txtlns,Init_Words,Init_Chars,Init_Blobs,NULL}
#if MAIN
Block empty_Block = Init_Block;
#else
extern Block empty_Block;
#endif

/* Ident bits for Blocks */
#define Block_wst	00000000001	/* word-space-thresh set up */
#define Block_label	00000000002	/* has an ASCII string label */

#define Block_mb (1)

/* block of text */
typedef struct BlockF {
	Ident ident;	/* IsBlock must be set */
	Bbx bx;
	Ems wst;	/* word-space threshold */
	float skew;
	float shear;
#if Block_mb
	float m;
	short bkmny;
#endif
	short lmny;
	short wmny;
	int cmny;
	int bmny;
	/* if ident&Block_label, label follows BlockF ('\0'-terminated string) */
	} BlockF;

/* page */
typedef struct Page {
	Ident ident;
	Bbx bx;			/* extreme indices in pixels */
	short res_x;		/* resolution in pixels/inch:  x & y */
	short res_y;
	Radians skew;		/* skew angle */
	Radians shear;		/* shear correction */
	Blocks bks;		/* blocks */
	Txtlns ls;		/* textlines (those not in any block) */
	Words ws;		/* words (not in any textline) */
	Chars cs;		/* chars (not in any word) */
	Blobs bs;		/* blobs (not in any char) */
	char *l;		/* label (ASCII string in malloc space) */
	} Page;

#define Init_Page {IsPage,Init_Bbx,0,0,0.0,0.0,Init_Blocks,Init_Txtlns,Init_Words,Init_Chars,Init_Blobs,NULL}
#if MAIN
Page empty_Page = Init_Page;
#else
extern Page empty_Page;
#endif

#define Page_label	00000000001	/* has a label */

/* Pages of text */
typedef struct Pages {
	unsigned short mny;	/* if mny==0, pa==NULL */
	struct Page **pa;	/* to NULL-term'd array of ptrs */
	} Pages;

#define Init_Pages {0,NULL}
#if MAIN
Pages empty_Pages = Init_Pages;
#else
extern Pages empty_Pages;
#endif

typedef struct PageF {
	Ident ident;		/* IsPage bit must be set */
	short res_x,res_y;	/* resolution in pixels/inch:  x & y */
	Bbx bx;			/* extreme indices in pixels */
	float skew;		/* original page skew angle, radians */
	float shear;		/* original page shear angle, radians */
	short bkmny;		/* no. blocks */
	short lmny;		/* no. textlines (not in any block) */
	short wmny;		/* no. words (not in any textline) */
	int cmny;		/* no. chars (not in any word) */
	int bmny;		/* no. blobs (not in any char)) */
	/* if ident&Page_label, label follows PageF ('\0'-terminated string) */
	} PageF;

#define Page_new	00000000001	/* Page is in ``new'' format */

/* Each Dim-file begins with a Doc record */
typedef struct Doc {
	unsigned short version;		/* file format version number */
	Pages ps;
	char *l;		/* ASCII label */
	} Doc;

#define Init_Doc {0,Init_Pages,NULL}
#if MAIN
Doc empty_Doc = Init_Doc;
#else
extern Doc empty_Doc;
#endif

char *ident_toa();
Ident cto_ident();
Ident cto_flag();
char *merit_toa();
Page *alloc_page();
char *page_toa();
Page *dup_page();
Page *dup_page_etc();
Block *alloc_block();
char *block_toa();
Block *dup_block();
Block *dup_block_etc();
Block *append_block();
Blocks *dup_blocks_etc();
ConstPitch *alloc_constpitch();
char *constpitch_toa();
Txtln *alloc_txtln();
char *txtln_toa();
Word *alloc_word();
char *word_toa();
boolean eq_word();
int hash_word();
Char *alloc_char();
char *char_toa();
Pp *char_centroid();
Char *char_of_blob();
char *interp_toa();
char *blob_toa();
Pp *blob_centroid();
char *runf_toa();
char *runfs_toa();
char *pp_toa();
char *bdyedge_toa();
Blob *dup_blob();
Blob *dup_blob_etc();
Blob *dup_blobl_etc();
Blob *runs_to_runs();
Blobs *dup_blobs_etc();
Blobs *blobl_to_blobs();
Interp *alloc_interp();
Interp *dup_interp();
Interpl *dup_interpl_etc();
Interps *dup_interps_etc();
Word *append_word();
Word *insert_word();
Word *insert_word_txtln();
Word *dup_word();
Word *dup_word_etc();
Words *dup_words_etc();
Txtln *dup_txtln();
Txtln *dup_txtln_etc();
Txtlns *dup_txtlns_etc();
Block *dup_block();
Block *dup_block_etc();
Radians add_ang();
Radians subtract_ang();

/* in-line macroes */

/* Merge the `source' Bbx into the `destination' Bbx, expanding the dest Bbx
   as required.  The source Bbx is unmodified.  Usage:
	merge_bbx(s,d)
	    Bbx *s,*d;
*/
#define merge_bbx(s,d) { \
	if((s)->a.x < (d)->a.x) (d)->a.x = (s)->a.x; \
	if((s)->a.y < (d)->a.y) (d)->a.y = (s)->a.y; \
	if((s)->b.x > (d)->b.x) (d)->b.x = (s)->b.x; \
	if((s)->b.y > (d)->b.y) (d)->b.y = (s)->b.y; \
	}

/* Experimental implementation of a data structure for maintaining a set
   of distinct Words whose merit falls within a dynamically-varying range.
   This implementation is worst-case quadratic time.
   BUGS:  insert_wordset shouldn't duplicate the word.
   */

#define dbg_ws (0)	/* if !=0, enable WordSet debugging tracing */

typedef struct WordSet {
	double cut;	/* cut-fraction */
	int cap;	/* capacity: maximum number permitted at any time */
	double top;	/* maximum merit seen since allocation */
	Words ws;	/* sorted by top-choice merit */
	Word *max,*min;	/* maximum/minimum entries currently in ws */
	int high;	/* high-water:  max. no. entries in history */
	} WordSet;
#define Init_WordSet {1.0,INT_MAX,0.0,Init_Words,NULL,NULL,0}
#if MAIN
WordSet empty_WordSet = Init_WordSet;
#else
extern WordSet empty_WordSet;
#endif

#define size_wordset(s) ((s)->ws.mny)
#define top_wordset(s) ((s)->top)
#define max_wordset(s) ((s)->max)
#define min_wordset(s) ((s)->min)
#define max_wordmerit(s) ((max_wordset((s))!=NULL)? (max_wordset((s)))->m: 0.0)
#define min_wordmerit(s) ((min_wordset((s))!=NULL)? (min_wordset((s)))->m: 0.0)

Merit wordmerit();
WordSet *alloc_wordset();
boolean insert_wordset();
Word *remove_wordset();
int free_wordset_etc();
err_wordset();
0707070035351137151006640007620000050000010263160476773367000001000000001554Units.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

#define UNITS "icpPsu"	/* units notation for:  inches, cm, points, picas,
			   scanner pixel (Scoor), and basic unit (also Scoor) */

#define INCHES_PER_POINT (0.0138)	/* cf. Chicago Manual of Style */

#define RADIANS_PER_DEGREE (PI/180.0)
#define DtoR (RADIANS_PER_DEGREE)	/* degrees * DtoR = radians */

#define Radians double		/* angle in radians */

/* machine-independent I/O has a resolution of 0.1 second of arc */
#define fwri_Radians(F,V) fwri_int3((F),(V)*2062648.1)
#define frdi_Radians(F) (frdi_int3(F)/(Radians)2062648.1)
0707070035351137161006640007620000050000010263200476773367000001000000012421abort.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* abort.h - three terse message, warning, and abort functions.
	out(s,a,...)	 print message to stdout
	err(s,a,...)	 print warning to stderr
	abort(s,a,...)	 complain to stderr and exit abnormally.
   The 's' argument is a printf string, and the 'a',... are (up to 15) arguments
   matching %-fields.  These routines prefix the program name and append `\n' to
   the printf string, then write to:
	  `out': stdout
	  `err' & `abort': stderr
   Abort also says " - abort", and exits abnormally.
   This #include should be preceded by `#define CMDNAME "xxx"'  so that `xxx:'
   will be prefixed to msg and abort strings. */

#ifndef CMDNAME
#define CMDNAME "hsb"
#endif

#define MSGMAX 120

#ifndef boolean
#define boolean int
#define T 1
#define F 0
#endif

/* WARNING: these function-call versions do not port well:
   e.g. floating-point arguments are botched on MIPS and SGI machines */

out(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
    char *s;
{   static char m[MSGMAX];
	strcpy(m,CMDNAME);
	strcat(m,": ");
	strcat(m,s);
	strcat(m,"\n");
	fprintf(stdout,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
	}

err(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
    char *s;
{   char m[MSGMAX];
	strcpy(m,CMDNAME);
	strcat(m,": ");
	strcat(m,s);
	strcat(m,"\n");
	fprintf(stderr,m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
	}

abort(s,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15)
    char *s;
{   static char m[MSGMAX];
	strcpy(m,s);
	strcat(m," - abort");
	err(m,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15);
	exit(1);
	}

/* These hybrid macro/function forms ports well, but are awkward to use... */

char *_F(s)
   char *s;
{  static char m[MSGMAX];
	strcpy(m,CMDNAME);
	strcat(m,": ");
	strcat(m,s);
	strcat(m,"\n");
	return(m);
	}

#define out0(Z) fprintf(stdout,_F(Z))
#define out1(Z,A) fprintf(stdout,_F(Z),A)
#define out2(Z,A,B) fprintf(stdout,_F(Z),A,B)
#define out3(Z,A,B,C) fprintf(stdout,_F(Z),A,B,C)
#define out4(Z,A,B,C,D) fprintf(stdout,_F(Z),A,B,C,D)
#define out5(Z,A,B,C,D,E) fprintf(stdout,_F(Z),A,B,C,D,E)
#define out6(Z,A,B,C,D,E,F) fprintf(stdout,_F(Z),A,B,C,D,E,F)
#define out7(Z,A,B,C,D,E,F,G) fprintf(stdout,_F(Z),A,B,C,D,E,F,G)
#define out8(Z,A,B,C,D,E,F,G,H) fprintf(stdout,_F(Z),A,B,C,D,E,F,G,H)
#define out9(Z,A,B,C,D,E,F,G,H,I) fprintf(stdout,_F(Z),A,B,C,D,E,F,G,H,I)
#define out10(Z,A,B,C,D,E,F,G,H,I,J) fprintf(stdout,_F(Z),A,B,C,D,E,F,G,H,I,J)
#define out11(Z,A,B,C,D,E,F,G,H,I,J,K) fprintf(stdout,_F(Z),A,B,C,D,E,F,G,H,I,J,K)

#define err0(Z) fprintf(stderr,_F(Z))
#define err1(Z,A) fprintf(stderr,_F(Z),A)
#define err2(Z,A,B) fprintf(stderr,_F(Z),A,B)
#define err3(Z,A,B,C) fprintf(stderr,_F(Z),A,B,C)
#define err4(Z,A,B,C,D) fprintf(stderr,_F(Z),A,B,C,D)
#define err5(Z,A,B,C,D,E) fprintf(stderr,_F(Z),A,B,C,D,E)
#define err6(Z,A,B,C,D,E,F) fprintf(stderr,_F(Z),A,B,C,D,E,F)
#define err7(Z,A,B,C,D,E,F,G) fprintf(stderr,_F(Z),A,B,C,D,E,F,G)
#define err8(Z,A,B,C,D,E,F,G,H) fprintf(stderr,_F(Z),A,B,C,D,E,F,G,H)
#define err9(Z,A,B,C,D,E,F,G,H,I) fprintf(stderr,_F(Z),A,B,C,D,E,F,G,H,I)
#define err10(Z,A,B,C,D,E,F,G,H,I,J) fprintf(stderr,_F(Z),A,B,C,D,E,F,G,H,I,J)
#define err11(Z,A,B,C,D,E,F,G,H,I,J,K) fprintf(stderr,_F(Z),A,B,C,D,E,F,G,H,I,J,K)

char *_G(s)
   char *s;
{  static char m[MSGMAX];
	strcpy(m,CMDNAME);
	strcat(m,": ");
	strcat(m,s);
	strcat(m," - abort\n");
	return(m);
	}

#define abort0(Z) fprintf(stderr,_G(Z))
#define abort1(Z,A) fprintf(stderr,_G(Z),A)
#define abort2(Z,A,B) fprintf(stderr,_G(Z),A,B)
#define abort3(Z,A,B,C) fprintf(stderr,_G(Z),A,B,C)
#define abort4(Z,A,B,C,D) fprintf(stderr,_G(Z),A,B,C,D)
#define abort5(Z,A,B,C,D,E) fprintf(stderr,_G(Z),A,B,C,D,E)
#define abort6(Z,A,B,C,D,E,F) fprintf(stderr,_G(Z),A,B,C,D,E,F)
#define abort7(Z,A,B,C,D,E,F,G) fprintf(stderr,_G(Z),A,B,C,D,E,F,G)
#define abort8(Z,A,B,C,D,E,F,G,H) fprintf(stderr,_G(Z),A,B,C,D,E,F,G,H)
#define abort9(Z,A,B,C,D,E,F,G,H,I) fprintf(stderr,_G(Z),A,B,C,D,E,F,G,H,I)
#define abort10(Z,A,B,C,D,E,F,G,H,I,J) fprintf(stderr,_G(Z),A,B,C,D,E,F,G,H,I,J)
#define abort11(Z,A,B,C,D,E,F,G,H,I,J,K) fprintf(stderr,_G(Z),A,B,C,D,E,F,G,H,I,J,K)

boolean ask_more()
{   FILE *tty;
    char reply[20];
    static int skip = 0;
	if(skip<=0) {
		fputs("MORE? ",(tty=fopen("/dev/tty","w")));  fclose(tty);
		fgets(reply,20,(tty=fopen("/dev/tty","r")));  fclose(tty);
		switch (reply[0]) {
			case '\0': case 'y': case 'Y':
				return(T);
			case 'n': case 'N': case 'q': case 'Q':
				return(F);
			case '0': case '1': case '2': case '3': case '4':
			case '5': case '6': case '7': case '8': case '9':
				skip = atoi(reply);
				return(T);
			case '*':
				skip = INT_MAX;
				return(T);
			default:
				skip = 0;
				return(T);
			};
		}
	else skip--;
	return(T);
	}

boolean ask_quit()
{   FILE *tty;
    char reply[20];
	fputs("QUIT? ",(tty=fopen("/dev/tty","w")));  fclose(tty);
	fgets(reply,20,(tty=fopen("/dev/tty","r")));  fclose(tty);
	switch (reply[0]) {
		case 'y': case 'Y':
			return(F);
		case 'n': case 'N': case 'q': case 'Q':
			return(T);
		};
	return(F);
	}

0707070035351137171006640007620000050000010263220476773367100000600000171751bcp.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/*     T. J. ThompsonT - ATT-BL HO - extensions        */

/* bcp.c - translate among binary image file formats, optionally trimming,
	shifting, scaling, and rotating the image on the fly.  Scaling is by
	arbitrary real factors, separately in X & Y.  Rotation is still crude and
	slow.
   USAGE:
	bcp [options...] [I [O]]
   I/O:
	If O is omitted, all output is concatenated to stdout.
	If I is also omitted, all input is read from stdin.
	If I is a filename, it is the sole input;  but, if it is a directory name,
	then every leaf of its file tree is processed in turn; and, in this case,
	if O also is specified, it is forced to become the root directory
	of an isomorphic tree of output files (this use of Unix file trees
	may be defeated using compile-time option FILE_TREE).

	[PROPOSED:  An input file may be a catenation of pages.  These may vary
	in TYPE and other parameters.  They will all be translated to the same
	output type, and catenated to one file, each with a complete translated
	header.  Generally, a complete picfile header must be repeated at the
	top of each page:  exceptions include TYPE=cdf, which packs pages in its
	own peculiar way.]

   OPTIONS:
	NOTE:  lengths, distances, and pixel indices are assumed to be in
	units of pixels (scanner units), unless one of "icpPs" is appended,
	meaning inches, cm, points, picas, or (explicitly) scanner pixels.
        This applies to option:  -w (seems buggy).

	-B[io]	read/write bitfile(9.5) format (doesn't use TYPE= header).
		[doesn't run-length encode yet:  may be bulky.]
	-M	write TYPE=bitmap format.
	-P	write Postscript format (only on Suns; by Tim Thompson, ATT-BL HO)
	-Rx[,y] force output resolutions to x,y (overrides -xX[,Y]) (pixels/inch).
		Requires a RES=X Y line in the header.
	-R=	Force the output resolution to be equal to the greater of
		the input resolutions.
	-S	write Sun rasterfile format (only on Suns; by Tim Thompson,
		ATT-BL HO)
	-Tt	when reading TYPE=dump, binarize the image by thresholding each
		pixel value as follows:  (pixel<t)? black: white. (default: -T128)
	-Ww	shrink-wrap output around black artwork, surrounding it with equal
		margins of width w (pixels), then translate so that the left-top
		corner of the margin box is at 0,0 (works only with TYPE=document-
		image input). (w must be >= 0)
	-Zx[,y]	set input resolution to RES=x y (overriding existing RES, if any)
	-b	write binary format (TYPE=binary)
	-d?	trace to stderr:
		-dR	comment on any change in resolution
		-dc	point out oddities in cdf files which are, by default,
			silently corrected
		-dh	file headers (a good first debugging step)
		-dm	margins
		-dr	runs (exhaustive, voluminous)
		-ds	status and summary statistics (brief)
	-g31	write CCITT FAX Group 3 1-dim encoding
	  -31	  ditto
	-g32	write CCITT FAX Group 3 2-dim encoding (see also -k option)
	  -32	  ditto
	-g4	write CCITT FAX Group 4 encoding (the default output format)
	  -4	  ditto
	-kK	set the 'k' for g32 encoding on output (default: -k4)
	-oX,Y	offset the result by X,Y (merely shift the bounding box)
	-p	write TYPE=dump NCHAN=1 format; input binary pixels
		are mapped to grey as follows: (pixel==white)? 255: 0.
	-r	write rle format (this is Pavlidis' obsolescent OCR format) 
	-t[lrbN] top of the page is really at the left/right/bottom;
		after all other transformations are carried out, the image
		will be rotated to bring the real top of page to the top.
		By arbitrary convention, the top-left corner of the rotated
		image will be equal to the top-left corner of the image
		resulting from all the other transformations.
		[UNFINISHED, UNDER DEVELOPMENT:  -tr & -tb; -tN, where N is a
		numeric string, is interpreted as a counterclockwise rotation by
		N degrees: for now, only handle +/-20 degrees.  The present code
		for -tN is slow and subject to aliasing.]
	-v	reverse video:  swap black and white
	-wL,T,R,B  specify window to select:
		(L,T) is the left-top (origin) and (R,B) the OPEN right-bottom
		corner (i.e. the corner coordinates are not included.)   A '%'
		argument defaults to the input window parameter.
		[NOTE: since non-zero L,T windows are still not everywhere well
		supported (by pcp, met, etc), it might be best to shift the
		new L,T to 0,0 on output -- but this is not done now.]
	-xX[,Y]	expansion factor(s), horizontally and vertically;
		if only one is specified, they are assumed equal
		(default: -x1.0,1.0)  May be overridden by -Rx[,y].
		Requires a RES=X Y line in the header.
DESCRIPTION
        This translates among these formats of binary images:
   ccitt-g31, ccitt-g32, ccitt-g4, picture (TYPE=dump NCHAN=1), binary, rle, 
   bitfile(9.5), cdf, Sun rasterfile (TYPE=bitmap), and Postscript.  All require
   a TYPE= header in picfile format (see below), except bitfile(9.5) (as a result,
   to read these, must use special option: -Bi).  Most require WINDOW=ox oy cx cy
   and RES=x y header lines also.
	Optionally, the image may be modified on the fly by the following
   operations performed in this order:
	trimming - a subset of the input image is selected (-w option)
	shifting - the origin is shifted (-o)
	scaling - real scaling factors are applied, in X & Y separately (-x, -R)
	rotation - by 90, 180, 270 degrees - UNDER DEVELOPMENT (-t option)
	reverse-video - swap black and white (-v option)
   Note that scaling changes the effective digitizing resolution by arbitrary
   real factors (expansion or contraction), in X and Y separately.  Presently,
   this is accomplished naively by replication or deletion of pixels.  If it is
   ever desired to apply more interesting image-processing techniques (such as
   smoothing and resampling), the required changes may be safely confined to
   functions transform_rlels() (in bcp.c) & transform_rlel() (in rlelib.c).
   Accepts TYPE=document-image (or TYPE=dim), flattening its hierarchy,
   and writes it out as a single page image.
PICFILE FORMAT (briefly summarized; see picture(5))
   Each picture file comprises an ASCII header followed by binary data.
   The header is terminated by two newlines (an empty line).  A typical header is:
        TYPE=ccitt-g4
        WINDOW=0 0 640 480
        RES=300 300
			(note the final empty line)
   TYPE must come first.  The other lines may come in any order.  WINDOW gives
   the x,y coordinates of the upper left corner (inclusive) and lower right
   corners (exclusive).  Typically, an image of WxH pixels will be described
   by WINDOW=0 0 W H.  RES=X Y gives the digitizing resolution horizontally and
   vertically, in integral pixels/inch.  Supported TYPEs include:

   dump     A two-dimensional array of pixel structures.  NCHAN=1 is required:
	    one byte per pixel.  On input, the grey pixel values are thresholded
	    to binary (see option -T).  On output, black is 0 and white is 255.

   bitmap   One bit/pixel, packed into bytes high-order bit first.  Black is `1'.
	    Each horizontal row is padded to a 16-bit boundary with `0'.
	    (This is identical to Sun rasterfile format, except for the ASCII
	    header.)

   ccitt-g4 CCITT FAX Group 4 compressed image.  Similarly, ccitt-g31 means
	    Group 3/1-D and ccitt-g32 means Group 3/2-D.

   (Obsolescent 112 formats:
    rle	    A run-length coding, better for binary images (see rle.h).
    binary  1 bit/pixel, packed into bytes low-order bit first.  Black is `1'.
	    Each horizontal row is padded to a full byte with `0'.)

    NOTE:  bitfile(9.5) doesn't use an ASCII header.

   (Odd formats in use outside 112, sometimes very heavily:
    cdf	    supported on input only, and only the first page of several.
    tiff    not yet supported.)

IMPLEMENTATION STATUS
        CCITT FAX ``uncompressed'' (or, ``transparent'') mode is not implemented,
   either while encoding or decoding.
   	Cdf is an input-only option;  Sun rasterfile and Postscript are output-only options.
   Postscript output is useful only for very small images.
        Rotations are only partially implemented, and are slow.

KNOWN BUGS (30 May 89)
	WINDOW=OX OY CX CY where OX or OY are non-zero is not handled correctly
   for every combination of file types.
	Unit gets passed wrongly to vto_scoor().
	Rle can't be both inout and output (design flaw: they share a buffer).
	Beware off-by-one errors (top or bottom line omitted); has not been
   carefully checked for all file type combinations.

AUTHORS
	Dec 1988 - Henry S. Baird (AT&T Bell Labs MH) - first working draft
	Mar 1989 - Tim Thompson (BL HO) - extensions for SunOS, bug fixes, etc
*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "CPU.h"
#define MAIN 1
#include "stdocr.h"
#include "rle.h"
#include "pic.h"
#include "Text.h"
   /* Ugly stubs just to prevent Text.h dragging in many other *.h & *.o files */
   Bfeats *alloc_bfeats(){}; free_bfeats(){}; Bfeats *dup_bfeats(){};
   fwrb_bfeats(){}; frdb_bfeats(){}; fix_lag(){}; char *classid_toa(){};
#include "Bitmap.h"
#include "CCITT.h"
#include "bitio.h"
#if FILE_TREE
#include "Path.h"
#endif
#define CMDNAME "bcp"
#include "abort.h"

double atof(),sin(),cos();
char *strchr();

/* Runtime options values */
static struct {
	boolean from_bitfile;	/* -Bi */
	boolean to_bitfile;	/* -Bo */
	boolean to_bitmap;	/* -M */
	boolean to_g31;		/* -g31 or -31 */
	boolean to_g32;		/* -g32 or -32 */
	boolean to_g4;		/* -g4 or -4 */
	boolean to_rle;		/* -r */
	boolean to_bin;		/* -b */
	boolean to_pic;		/* -p */
	boolean to_post;	/* -P */
	boolean to_rast;	/* -S */
	boolean omit_hdr;	/* -O */
	Sp out_res;		/* -R (-1 = unspecified; -2 = force-equal) */
	Scoor shrinkwrap;	/* -W (-1 = unspecified) */
	Sp in_res;		/* -Z (SHRT_MIN,SHRT_MIN = unspecified) */
	int g32_k;		/* -k */
	int metheus;		/* -m */
	Sp offset;		/* -o */
	boolean dbg_any;
	boolean dbg_R;		/* -dR */
	boolean dbg_c;		/* -dc */
	boolean dbg_h;		/* -dh */
	boolean dbg_m;		/* -dm */
	boolean dbg_r;		/* -dr */
	boolean dbg_s;		/* -ds */
	boolean show;		/* -s */
	char top;		/* -tT takes on values: 't', 'l', 'r', 'b', 'a' */
	float top_angle;	/* -t angular value (set if top=='a') (Radians) */
	int thresh;		/* -Tt */
	boolean reverse;	/* -v */
	char *optarg_l;		/* -w?,,, */
	char *optarg_t;		/* -w,?,, */
	char *optarg_r;		/* -w,,?, */
	char *optarg_b;		/* -w,,,? */
	Bbx trim;		/* output margins resulting from -w */
	Pp expand;		/* -x */
	char *in_fn;
	char *out_fn;
} _O = {
	F, F, F, F, F, T, F, F, F, F, F,
	F, {-1,-1}, -1, {SHRT_MIN,SHRT_MIN}, 4, -1, Init_Zero_Sp,
	F, F, F, F, F, F, F, F,
	't',0.0,
	128,
	F,
	NULL, NULL, NULL, NULL,
	Init_Max_Bbx,
	{1.0,1.0},
	NULL, NULL };	

parse_args(arc,arv)
    int arc; char **arv;
{	/* getopt support */
	int optch;
	extern int optind;
	extern char *optarg;

    char *metheus_ev,metheus_digit;
    char *fs;

	/* default metheus number */
	if((metheus_ev=(char *)getenv("FB"))!=NULL) {
		metheus_digit = metheus_ev[(int)strlen(metheus_ev)-1];
		if((int)isdigit(metheus_digit)) {
			_O.metheus = (metheus_digit - '0');
			};
		};

	while((optch=getopt(arc,arv,"B:MOPR:ST:W:Z:3:4bd:g:k:m:o:prst:vw:x:"))!=EOF)
		switch(optch) {
			case 'B':
				switch(*optarg) {
				    case 'o':
					_O.to_bitfile = T;
					_O.to_g4 = F;
					break;
				    case 'i':
					_O.from_bitfile = T;
					break;
				    default:
					abort("option -B%s is illegal",optarg);
					break;
				    };
				break;
			case 'M':  _O.to_bitmap = T;  _O.to_g4 = F; break;
			case 'O':  _O.omit_hdr = T; break;
			case 'P':
#if CPU==SUN
				_O.to_post = T;  _O.to_g4 = F;
#else
				abort("-P option available only on Suns");
#endif
				break;
			case 'R':
				if(*optarg=='=') {
					_O.out_res.x = _O.out_res.y = -2;
					fs=NULL;
					}
				else if((fs=strtok(optarg,","))!=NULL) {
					if(strcmp(fs,"%")!=0) {
						_O.out_res.x = atoi(fs);
						};
					};
				if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) {
					if(strcmp(fs,"%")!=0) {
						_O.out_res.y = atoi(fs);
						};
					}
				else _O.out_res.y = _O.out_res.x;
				break;
			case 'S':
#if CPU==SUN
				_O.to_rast = T;  _O.to_g4 = F;
#else
				abort("-S option available only on Suns");
#endif
				break;
			case 'T':  _O.thresh=atoi(optarg);  break;
			case 'W':  _O.shrinkwrap=atoi(optarg);
				if(_O.shrinkwrap<0) {
					err("-W%d must be >=0; force to -W0",
						_O.shrinkwrap);
					_O.shrinkwrap=0;
					};
				break;
			case 'Z':
				if((fs=strtok(optarg,","))!=NULL) {
					if(strcmp(fs,"%")!=0) {
						_O.in_res.x = atoi(fs);
						};
					};
				if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) {
					if(strcmp(fs,"%")!=0) {
						_O.in_res.y = atoi(fs);
						};
					}
				else _O.in_res.y = _O.in_res.x;
				break;
			case '3':
				switch (*optarg) {
				    case '1':
					_O.to_g31=T;
					_O.to_g4=F;
					break;
				    case '2':
					_O.to_g32=T;
					_O.to_g4=F;
					break;
				    default:
				        abort("bad option: -g3%s",optarg);
					break;
				    };
				break;
			case '4':  _O.to_g4=T;  break;
			case 'b':
				_O.to_bin=T;
				_O.to_g4=F;
				break;
			case 'd':
				_O.dbg_any=T;
				switch(*optarg) {
				    case 'R':  _O.dbg_R = T;  break;
				    case 'c':  _O.dbg_c = T;  break;
				    case 'h':  _O.dbg_h = T;  break;
				    case 'm':  _O.dbg_m = T;  break;
				    case 'r':  _O.dbg_r = T;  break;
				    case 's':  _O.dbg_s = T;  break;
				    };
				break;
			case 'g':  
				switch (optarg[0]) {
				    case '3':
					switch (optarg[1]) {
					    case '1':
						_O.to_g31=T;
						_O.to_g4=F;
						break;
					    case '2':
						_O.to_g32=T;
						_O.to_g4=F;
						break;
					    default:
					        abort("bad option: -g%s",optarg);
						break;
					    };
					break;
				    case '4':  _O.to_g4=T;  break;
				    default:
					abort("bad option: -g%s",optarg);
					break;
				    };
				break;
			case 'k':  _O.g32_k = atoi(optarg); break;
			case 'm':  _O.metheus = atoi(optarg); break;
			case 'o':
				if((fs=strtok(optarg,","))!=NULL) {
					if(strcmp(fs,"%")!=0)
						_O.offset.x = atoi(fs);
					};
				if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) {
					if(strcmp(fs,"%")!=0)
						_O.offset.y = atoi(fs);
					};
				break;
			case 'p':
				_O.to_pic=T;
				_O.to_g4=F;
				break;
			case 'r':
				_O.to_rle = T;
				_O.to_g4 = F;
				break;
			case 's':  _O.show = T;  break;
			case 't':  _O.top = *optarg;
				if(strchr("0123456789.+-",_O.top)!=NULL) {
					_O.top = 'a';	/* angular value */
					_O.top_angle = atof(optarg)*DtoR;
					};
				break;
			case 'v':  _O.reverse = T;  break;
			case 'w':
				if( (fs=strtok(optarg,","))!=NULL
					&& strlen(fs)>0 && strcmp(fs,"%")!=0 )
						_O.optarg_l = strdup(fs);
				if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL
					&& strlen(fs)>0 && strcmp(fs,"%")!=0 )
						_O.optarg_t = strdup(fs);
				if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL
					&& strlen(fs)>0 && strcmp(fs,"%")!=0 )
						_O.optarg_r = strdup(fs);
				if( fs!=NULL && (fs=strtok((char *)0,","))!=NULL
					&& strlen(fs)>0 && strcmp(fs,"%")!=0 )
						_O.optarg_b = strdup(fs);
				break;
			case 'x':
				if((fs=strtok(optarg,","))!=NULL) {
					if(strcmp(fs,"%")!=0) {
						if(*fs=='/')
						  _O.expand.x = 1.0/atof(fs+1);
						else _O.expand.x = atof(fs);
						if(_O.expand.x<=0.0)
						  _O.expand.x=1.0;
						};
					};
				if(fs!=NULL&&(fs=strtok((char *)0,","))!=NULL) {
					if(strcmp(fs,"%")!=0) {
						if(*fs=='/')
						  _O.expand.y = 1.0/atof(fs+1);
						else _O.expand.y = atof(fs);
						if(_O.expand.y<=0.0)
						  _O.expand.y=1.0;
						};
					}
				else _O.expand.y = _O.expand.x;
				break;
			default: break;
			};
	switch(arc-optind) {
	    case 2:
		_O.out_fn = strdup(arv[optind+1]);
	    case 1:	
		_O.in_fn = strdup(arv[optind]);
	    case 0:
		break;
	    default:
		abort("<= two filenames expected");
		break;
	    };
	if(_O.show&&_O.metheus==-1) {
		err("FB=/dev/omM not specified, using /dev/om0");
		_O.metheus = 0;
		};
	}

unimplemented()
{	abort("unimplemented");
	}

typedef struct Copy_arg {
	boolean bop;	/* beginning of page */
	PIC_hdr *ph;
	int wid;	/* bbx_wid(&(ph->bx)) (for speed) */
	BITFILE *bf;
	DST_table *tbl;	/* for CCITT input */
	int k;		/* CCITT Group 3 2-D k */
	int thresh;	/* for input pic files */
	RLE_Lines rles;	/* for TYPE=document-image or TYPE=dim */
	} Copy_arg;
#define Init_Copy_arg {T,NULL,INT_MIN,NULL,NULL,4,128,Init_RLE_Lines}
#if MAIN
Copy_arg empty_Copy_arg = Init_Copy_arg;
#else
extern Copy_arg empty_Copy_arg;
#endif

/* SOURCES:  return the next RLE_Line from the given file type, with run indices
   shifted to lie within [ a->ph->bx.a.x, a->ph->bx.b.x ].
   **** BUGS:  not all handle non-zero a->ph->bx.a.x yet.
   */

/* Handles non-zero a->ph->bx.a.x. */
RLE_Line *cdf_mrlc_source(a)
    Copy_arg *a;
#define dbg_cdf (0)
{   static RLE_Line rl;
    int n;	/* no. pixels decoded */
    int col;	/* color:  0=white, 1=black */
    int byte;	/* input byte */
    int nb;	/* no. bytes read for this line */
    int ni;	/* nibble index: 0=1st (low-order), 1=2nd(high-order) */
    int nib;	/* current nibble */
    int mult;	/* multiplier for current nibble */
    int run;	/* no. pixels in current run */
    RLE_Run *rp;
#define toggle_color() {if(col) col=0; else col=1;}
/* get next byte into `byte' */
#define getbyte()  { \
	if((byte=getc(a->ph->fp))==EOF) goto eof; nb++; \
	if(dbg_cdf) err("byte0x%x",byte); \
	}
/* get next nibble into `nib' */
#define getnib()  { \
	if(ni) { getbyte();  ni=0;  nib=byte&0x0F; } \
	else { ni=1;  nib=(byte>>4); } \
	if(dbg_cdf) err("nib0x%x byte0x%x ni%d",nib,byte,ni); \
	}
/* get next run into `run' */
#define getrun()  { \
	run=0;  mult=1; \
	do {getnib();  run += mult * (nib&0x07);  mult *= 8;} while(nib&0x08); \
	if(dbg_cdf) err("run%d %c",run,((col)? 'B': 'W')); \
	}
	a->bop = F;
	n=0; col=0; ni=1; nb=0; rp=rl.r;
	do {	getrun();
		if(col) {/* black run */
			if(run>0) { /* ... of >0 length */
				rp->xs = a->ph->bx.a.x + n+1;
				rp->xe = a->ph->bx.a.x + (n+=run);
				if((rp-rl.r)>0 && ((rp-1)->xe >= rp->xs-1) ) {
					if(_O.dbg_c) err("cdf_mrlc_source: abutting black runs [%d,%d] & [%d,%d] - merged",
						(rp-1)->xs,(rp-1)->xe,
						rp->xs,rp->xe );
					/* merge with prior black run */
					(rp-1)->xe = rp->xe;
					}
				else rp++;
				}
			else {	/* zero-length black run */
				if( _O.dbg_c && (rp-rl.r)>0 )
					err("cdf_mrlc_source: zero-length black run [%d,%d] in middle of line - ignored",
					n,n);
				};
			}
		else {	/* white run */
			n+=run;
			};
		toggle_color();
		}
	while(n<a->wid);
	/* read 2 EOL nibbles */
	getnib(); getnib();
	rl.runs = rp - rl.r;
	rl.len = a->wid;
	if(rl.runs>0 && rl.r[rl.runs-1].xe>=a->wid) {
		if(_O.dbg_c)
		    err("cdf_mrlc_source: run [%d,%d] in line of length %d - truncated",
			rl.r[rl.runs-1].xs,rl.r[rl.runs-1].xe,a->wid);
		rl.r[rl.runs-1].xe = a->wid-1;
		if(rl.r[rl.runs-1].xs>rl.r[rl.runs-1].xe) {
			rl.runs--;
			};
		};
	rl.y = a->ph->cy++;
	if(_O.dbg_r) nerr_RLE_Line("cdf_source: ",&rl);
	return(&rl);

eof:	if(dbg_cdf)
		err("cdf_mrlc_source: unexpected EOF, input line %d",a->ph->cy);
	return(NULL);
	}

int no_runs_of_page(p)
    Page *p;
{   int runs;
	runs = 0;
	runs += no_runs_of_blocks(&p->bks);
	runs += no_runs_of_txtlns(&p->ls);
	runs += no_runs_of_words(&p->ws);
	runs += no_runs_of_chars(&p->cs);
	runs += no_runs_of_blobs(&p->bs);
	return(runs);
	}

int runs_of_page(p,ra,max)
    Page *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
	runs = 0;
	runs += runs_of_blocks(&p->bks,ra,max);
	runs += runs_of_txtlns(&p->ls,ra+runs,max-runs);
	runs += runs_of_words(&p->ws,ra+runs,max-runs);
	runs += runs_of_chars(&p->cs,ra+runs,max-runs);
	runs += runs_of_blobs(&p->bs,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_blocks(p)
    Blocks *p;
{   int runs;
    Block *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp))
		runs += no_runs_of_block(pp);
	return(runs);
	}

int runs_of_blocks(p,ra,max)
    Blocks *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
    Block *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp))
		runs += runs_of_block(pp,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_block(p)
    Block *p;
{   int runs;
	runs = 0;
	runs += no_runs_of_txtlns(&p->ls);
	runs += no_runs_of_words(&p->ws);
	runs += no_runs_of_chars(&p->cs);
	runs += no_runs_of_blobs(&p->bs);
	return(runs);
	}

int runs_of_block(p,ra,max)
    Block *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
	runs = 0;
	runs += runs_of_txtlns(&p->ls,ra+runs,max-runs);
	runs += runs_of_words(&p->ws,ra+runs,max-runs);
	runs += runs_of_chars(&p->cs,ra+runs,max-runs);
	runs += runs_of_blobs(&p->bs,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_txtlns(p)
    Txtlns *p;
{   int runs;
    Txtln *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->lpa); pp!=NULL; pp= *(++ppp))
		runs += no_runs_of_txtln(pp);
	return(runs);
	}

int runs_of_txtlns(p,ra,max)
    Txtlns *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
    Txtln *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->lpa); pp!=NULL; pp= *(++ppp))
		runs += runs_of_txtln(pp,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_txtln(p)
    Txtln *p;
{   int runs;
	runs = 0;
	runs += no_runs_of_words(&p->ws);
	runs += no_runs_of_chars(&p->cs);
	runs += no_runs_of_blobs(&p->bs);
	return(runs);
	}

int runs_of_txtln(p,ra,max)
    Txtln *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
	runs = 0;
	runs += runs_of_words(&p->ws,ra+runs,max-runs);
	runs += runs_of_chars(&p->cs,ra+runs,max-runs);
	runs += runs_of_blobs(&p->bs,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_words(p)
    Words *p;
{   int runs;
    Word *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->wpa); pp!=NULL; pp= *(++ppp))
		runs += no_runs_of_word(pp);
	return(runs);
	}

int runs_of_words(p,ra,max)
    Words *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
    Word *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->wpa); pp!=NULL; pp= *(++ppp))
		runs += runs_of_word(pp,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_word(p)
    Word *p;
{   int runs;
	runs = 0;
	runs += no_runs_of_chars(&p->cs);
	runs += no_runs_of_blobs(&p->bs);
	return(runs);
	}

int runs_of_word(p,ra,max)
    Word *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
	runs = 0;
	runs += runs_of_chars(&p->cs,ra+runs,max-runs);
	runs += runs_of_blobs(&p->bs,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_chars(p)
    Chars *p;
{   int runs;
    Char *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->cpa); pp!=NULL; pp= *(++ppp))
		runs += no_runs_of_char(pp);
	return(runs);
	}

int runs_of_chars(p,ra,max)
    Chars *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
    Char *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->cpa); pp!=NULL; pp= *(++ppp))
		runs += runs_of_char(pp,ra+runs,max-runs);
	return(runs);
	}

int no_runs_of_blobs(p)
    Blobs *p;
{   int runs;
    Blob *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp))
		runs += pp->runs;
	return(runs);
	}

int runs_of_blobs(p,ra,max)
    Blobs *p;
    RLE_Yrun *ra;
    int max;
{   int runs;
    Blob *pp,**ppp;
	runs = 0;
	if(p->mny>0) for(pp= *(ppp=p->bpa); pp!=NULL; pp= *(++ppp))
		runs += runs_of_blob(pp,ra+runs,max-runs);
	return(runs);
	}

/* ascending lexicographic order on y,xs */
int local_rn_asc(r1,r2)
   RLE_Yrun *r1,*r2;
{	if(r1->y < r2->y) return(-1);
	else if(r1->y==r2->y) {
		if(r1->xs < r2->xs) return(-1);
		else if (r1->xs == r2->xs) return(0);
		else return(1);
		}
	else return(1);
	}

RLE_Lines *rle_lines_of_page(pgp)
    Page *pgp;
{   static RLE_Lines rls;
    int no_runs,cy,ri;
    RLE_Yrun *ra,*cr;
    RLE_Run *lr;
    RLE_Line *cl;
	/* count runs */
	no_runs = no_runs_of_page(pgp);
	if(_O.dbg_r) err("no_runs %d",no_runs);
	/* allocate runs array */
	if((ra=(RLE_Yrun *)malloc(no_runs*sizeof(RLE_Yrun)))==NULL)
		abort("rle_lines_of_page: can't malloc ra[%d]",no_runs);
	runs_of_page(pgp,ra,no_runs);
	/* sort runs ascending on (y,xs) */
	qsort(ra,no_runs,sizeof(RLE_Yrun),local_rn_asc);
	/* count RLE_lines.mny */
	rls.mny = 0; cy=INT_MIN;
	for(ri=0,cr=ra; ri<no_runs; ri++,cr++)
		if(cr->y!=cy) {
			rls.mny++;
			cy = cr->y;
			};
	/* allocate RLE_lines */
	if((rls.rla=(RLE_Line *)malloc(rls.mny*sizeof(RLE_Line)))==NULL)
		abort("rle_lines_of_page: can't malloc rls.rla[%d]",rls.mny);
	/* fill in RLE_lines */
	cy=INT_MIN;  cl=rls.rla-1;
	for(ri=0,cr=ra; ri<no_runs; ri++,cr++) {
		if(cr->y!=cy) {
			cl++;
			cl->y = cy = cr->y;
			cl->runs = 0;
			lr = cl->r;
			};
		lr->xs = cr->xs;  lr->xe = cr->xe;  lr++;  cl->runs++;
		};
	free(ra);
	return(&rls);
	}

Bbx *bbx_of_rle_lines(rlsp)
    RLE_Lines *rlsp;
{   static Bbx res;
    Bbx r;
    int li,ri;
    RLE_Line *lp;
    RLE_Run *rp;
	res = empty_Bbx;
	for(li=0,lp=rlsp->rla; li<rlsp->mny; li++,lp++) {
		r.a.y = r.b.y = lp->y;
		for(ri=0,rp=lp->r; ri<lp->runs; ri++,rp++) {
			r.a.x = rp->xs;
			r.b.x = rp->xe;
			merge_bbx(&r,&res);
			};
		};
	return(&res);
	}

translate_rle_lines(r,p)
    RLE_Lines *r;
    Sp p;
{   int li,ri;
    RLE_Line *lp;
    RLE_Run *rp;
	for(li=0,lp=r->rla; li<r->mny; li++,lp++) {
		lp->y += p.y;
		for(ri=0,rp=lp->r; ri<lp->runs; ri++,rp++) {
			rp->xs += p.x;
			rp->xe += p.x;
			};
		};
	}

RLE_Line *binary_source(a)
    Copy_arg *a;
{   static RLE_Line rl;
    unsigned char *inline;
	a->bop = F;
	if(PIC_rline(a->ph,&inline)==1) {
		rl.runs =
		    rlbr(inline,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r);
		rl.y = a->ph->cy;
		rl.len = a->wid;
		if(_O.dbg_r) nerr_RLE_Line("binary_source: ",&rl);
		return(&rl);
		}
	else {	if(_O.dbg_r) nerr_RLE_Line("binary_source: ",NULL);
		return(NULL);
		};
	}

RLE_Line *bitmap_source(a)
    Copy_arg *a;
{   static RLE_Line rl;
    unsigned char *inline;
    register unsigned char *cp,*ep,*rb;
	a->bop = F;
	if(PIC_rline(a->ph,&inline)==1) {
		/* reverse bit order in each byte */
		rb=bm_consts.Rbits;
		ep=(cp=inline)+a->ph->bpl;
		while(cp<ep) { *cp = rb[*cp]; cp++; };
		rl.runs =
		    rlbr(inline,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r);
		rl.y = a->ph->cy;
		rl.len = a->wid;
		if(_O.dbg_r) nerr_RLE_Line("bitmap_source: ",&rl);
		return(&rl);
		}
	else {	if(_O.dbg_r) nerr_RLE_Line("binary_source: ",NULL);
		return(NULL);
		};
	}

RLE_Line *bitfile_source(a)
    Copy_arg *a;
#define dbg_Bi (F)
{   static RLE_Line rl;
    unsigned char *cp,*ep,*pp;
    int ch,ci;
	a->bop = F;
	/* copy current line to prior */
	memcpy(a->ph->pline,a->ph->line,a->ph->bpl);
	/* read one binary raster line */
	ep=(cp=a->ph->line)+a->ph->bpl;
	while(cp<ep) {
		if((ch=getc(a->ph->fp))!=EOF) {
			if(ch<127) {
				if(dbg_Bi) err("cb: %o",ch);
				if((fread(cp,1,2*ch,a->ph->fp))==2*ch) {
					cp += 2*ch;
					}
				else return(NULL);
				}
			else {	ch &= 0x7F;
				if(dbg_Bi) err("cb: 0200+%o",ch);
				if((fread(cp,1,2,a->ph->fp))==2) {
					cp += 2;
					for(ci=0;ci<ch-1;ci++,cp+=2) {
						*cp = *(cp-2);
						*(cp+1) = *(cp-1);
						};
					}
				else return(NULL);
				};
			}
		else return(NULL);
		};
	/* reverse bit-order, & xor with prior line */
	for(ep=(cp=a->ph->line)+a->ph->bpl,pp=a->ph->pline; cp<ep; cp++,pp++) {
		*cp = bm_consts.Rbits[*cp] ^ *pp;
		if(dbg_Bi) err("db: %o = ?? ^ %o",*cp,*pp);
		};
	rl.runs =
	    rlbr(a->ph->line,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,rl.r);
	rl.y = ++a->ph->cy;
	rl.len = a->wid;
	if(_O.dbg_r) nerr_RLE_Line("bitfile_source: ",&rl);
	return(&rl);
	}

RLE_Line *dim_source(a)
    Copy_arg *a;
{   static RLE_Line *rlp,*rlq,rl;
	if(a->bop) {
		a->ph->cy = a->ph->bx.a.y-1;
		rlq=(rlp=a->rles.rla)+a->rles.mny;
		};
	if(_O.dbg_r) {
		err("dim_source: a->bop %d a->ph->cy %d",a->bop,a->ph->cy);
		nerr_RLE_Line("*rlp",rlp);
		};
	a->bop = F;
	a->ph->cy++;
	if(rlp<rlq) {
		if(a->ph->cy < rlp->y) {
			rl.y = a->ph->cy;
			rl.runs = 0;
			rl.len = a->wid;
			if(_O.dbg_r) nerr_RLE_Line("dim_source: ",&rl);
			return(&rl);
			}
		else if(a->ph->cy == rlp->y) {
			rlp->len = a->wid;
			rlp++;
			if(_O.dbg_r) nerr_RLE_Line("dim_source: ",rlp-1);
			return(rlp-1);
			}
		else {	while(rlp<rlq && a->ph->cy>rlp->y) rlp++;
			if(rlp>=rlq) {
				if(_O.dbg_r) nerr_RLE_Line("dim_source: NULL");
				return(NULL);
				}
			else {	rlp->len = a->wid;
				rlp++;
				if(_O.dbg_r) nerr_RLE_Line("dim_source: ",rlp-1);
				return(rlp-1);
				};
			};
		}
	else {	if(_O.dbg_r) nerr_RLE_Line("dim_source: NULL");
		return(NULL);
		};
	}

RLE_Line *rle_source(a)
    Copy_arg *a;
{   static RLE_Line *rl;
	a->bop = F;
	if((rl=RLE_get_Line(a->ph->bx.a.x,a->ph->bx.b.x))!=NULL) {
		a->ph->cy = rl->y;
		rl->len = a->wid;
		if(_O.dbg_r) nerr_RLE_Line("rle_source: ",rl);
		return(rl);
		}
	else {	if(_O.dbg_r) nerr_RLE_Line("rle_source: ",NULL);
		return(NULL);
		};
	}

/* Read next line of runs from pic file, with runs shifted to lie in the range
   [ a->ph->bx.a.x, a->ph->bx.b.x ]. */
RLE_Line *pic_source(a)
    Copy_arg *a;
{   static RLE_Line rl;
    unsigned char *inline;
	a->bop = F;
	if(PIC_rline(a->ph,&inline)==1) {
		rl.runs = trcr(inline,
			0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->bx.a.x,
			a->thresh,rl.r);
		rl.y = a->ph->cy;
		rl.len = a->wid;
		if(_O.dbg_r) nerr_RLE_Line("pic_source: ",&rl);
		return(&rl);
		}
	else {	if(_O.dbg_r) nerr_RLE_Line("pic_source: ",NULL);
		return(NULL);
		};
	}

/* Read next line of runs from g31 file, with runs shifted to lie in the range
   [ a->ph->bx.a.x, a->ph->bx.b.x ]. */
RLE_Line *g31_source(a)
    Copy_arg *a;
{   static RLE_Line *rlp,rl;
    RLE_Run *rp,*ep,*np;
	if((rlp=g31_to_rlel(a->tbl,a->bf,a->bop))!=NULL) {
		a->bop = F;
		rlp->y = ++a->ph->cy;
		rlp->len = a->wid;
		if(a->ph->bx.a.x!=0) {
			/* must shift run indices */
			rl.y = rlp->y;
			rl.len = rlp->len;
			if((rl.runs=rlp->runs)>0) {
				for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) {
					np->xs = rp->xs + a->ph->bx.a.x;
					np->xe = rp->xe + a->ph->bx.a.x;
					};
				};
			if(_O.dbg_r) nerr_RLE_Line("g31_source: ",&rl);
			return(&rl);
			}
		else {	if(_O.dbg_r) nerr_RLE_Line("g31_source: ",rlp);
			return(rlp);
			};
		}
	else {	if(_O.dbg_r) nerr_RLE_Line("g31_source: ",NULL);
		return(NULL);
		};
	}

/* Read next line of runs from g32 file, with runs shifted to lie in the range
   [ a->ph->bx.a.x, a->ph->bx.b.x ]. */
RLE_Line *g32_source(a)
    Copy_arg *a;
{   static RLE_Line *rlp,rl;
    RLE_Run *rp,*ep,*np;
	if((rlp=g32_to_rlel(a->tbl,a->bf,a->bop))!=NULL) {
		a->bop = F;
		rlp->y = ++a->ph->cy;
		rlp->len = a->wid;
		if(a->ph->bx.a.x!=0) {
			/* must shift run indices */
			if(_O.dbg_r) err("g32_source: shift +%d",a->ph->bx.a.x);
			rl.y = rlp->y;
			rl.len = rlp->len;
			if((rl.runs=rlp->runs)>0) {
				for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) {
					np->xs = rp->xs + a->ph->bx.a.x;
					np->xe = rp->xe + a->ph->bx.a.x;
					};
				};
			if(_O.dbg_r) nerr_RLE_Line("g32_source: ",&rl);
			return(&rl);
			}
		else {	if(_O.dbg_r) nerr_RLE_Line("g32_source: ",rlp);
			return(rlp);
			};
		}
	else {	if(_O.dbg_r) nerr_RLE_Line("g32_source: ",NULL);
		return(NULL);
		};
	}

/* Read next line of runs from g4 file, after shifting runs to lie in the range
   [ a->ph->bx.a.x, a->ph->bx.b.x ]. */
RLE_Line *g4_source(a)
    Copy_arg *a;
{   static RLE_Line *rlp,rl;
    RLE_Run *rp,*ep,*np;
	if((rlp=g4_to_rlel(a->tbl,a->bf,a->bop,a->wid))!=NULL) {
		a->bop = F;
		rlp->y = ++a->ph->cy;
		rlp->len = a->wid;
		if(a->ph->bx.a.x!=0) { /* shift runs */
			rl.y = rlp->y;
			rl.len = rlp->len;
			if((rl.runs=rlp->runs)>0) {
				for(ep=(rp=rlp->r)+rlp->runs,np=rl.r; rp<ep; rp++,np++ ) {
					np->xs = rp->xs + a->ph->bx.a.x;
					np->xe = rp->xe + a->ph->bx.a.x;
					};
				};
			if(_O.dbg_r) nerr_RLE_Line("g4_source: ",&rl);
			return(&rl);
			}
		else {	if(_O.dbg_r) nerr_RLE_Line("g4_source: ",rlp);
			return(rlp);
			};
		}
	else {	a->bop = F;
		if(_O.dbg_r) nerr_RLE_Line("g4_source: ",NULL);
		return(NULL);
		};
	}

binary_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   int stat;
	if(_O.dbg_r) nerr_RLE_Line("binary_sink: ",rl);
	if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; }
	if(rl!=NULL) {
		memset(a->ph->line,'\0',a->ph->bpl);
		if(rl->runs>0) {
		    /* convert *rl to binary, using ``little-endian'' bit-order */
		    brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line);
		    };
		if((stat=PIC_wline(a->ph,a->ph->line))!=1)
			abort("binary_sink: can't write: stat %d",stat);
		};
	return(1);
	}

bitmap_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   int stat;
	if(_O.dbg_r) nerr_RLE_Line("bitmap_sink: ",rl);
	if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; }
	if(rl!=NULL) {
		memset(a->ph->line,'\0',a->ph->bpl);
		if(rl->runs>0) {
		    /* convert *rl to binary, using ``big-endian'' bit-order */
		    brrlb(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line);
		    };
		if((stat=PIC_wline(a->ph,a->ph->line))!=1)
			abort("bitmap_sink: can't write: stat %d",stat);
		};
	return(1);
	}

/* Write bitfile(9.5) format */
bitfile_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
#define dbg_Bo (F)
{   int stat;
    int ci,towrite;
    register unsigned char uc,*cp,*pp,*ep;
	if(_O.dbg_r||dbg_Bo) nerr_RLE_Line("bitfile_sink: ",rl);
	if(a->bop) { PIC_put_hdr(a->ph); a->bop=F; }
	if(rl!=NULL) {
		/* copy current to prior */
		memcpy(a->ph->pline,a->ph->line,a->ph->bpl);
		memset(a->ph->line,'\0',a->ph->bpl);
		if(rl->runs>0) {
			/* convert *rl to binary, using ``big-endian'' bit-order */
			brrlb(rl->runs,rl->r,
				a->ph->bx.a.x,a->ph->bx.b.x,
				0,a->ph->line);
			if(dbg_Bo) {
			    unsigned char *cb,*eb;
				fprintf(stderr,"a->ph->line: ");
				for(eb=(cb=a->ph->line)+a->ph->bpl;cb<eb;cb++)
					fprintf(stderr,"%02X",*cb);
				fprintf(stderr,"\n");
				};
			};
		/* break up output into blocks of 2*126 bytes;
		   SHOULD also try run-length coding */
		ci=0;  while((towrite=a->ph->bpl-ci) > 0) {
			if(towrite >= 2*127) towrite=2*126;
			/* write control byte for block */
			uc = towrite/2;
			if(dbg_Bo) err("cb: %02X",uc);
			putc(uc,a->ph->fp);
			for(ep=(cp=a->ph->line+ci)+towrite,pp=a->ph->pline+ci;
			     cp<ep; cp++,pp++) {
				/* write XOR byte */
				uc = *cp ^ *pp;
				if(dbg_Bo) err("db %d: %02X = c%02X ^ p%02X",cp-a->ph->line,uc,*cp,*pp);
				putc(uc,a->ph->fp);
				};
			ci += towrite;
			};
		}
	else {	free(a->ph->line);  a->ph->line=NULL;
		free(a->ph->pline);  a->ph->pline=NULL;
		fflush(a->ph->fp);
		};
	}

rle_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{	if(_O.dbg_r) nerr_RLE_Line("rle_sink: ",rl);
	if(a->bop) {
	    RIC_hdr rh;
		rh.bx = a->ph->bx;
		rh.res_x = a->ph->res_x;
		rh.res_y = a->ph->res_y;
		RLE_put_hdr(fileno(a->ph->fp),&rh,1);
		a->ph->cy = a->ph->bx.a.y-1;
		a->bop=F;
		};
	if(rl!=NULL) {
		if(rl->runs>0) RLE_put_Line(fileno(a->ph->fp),rl);
		a->ph->cy++;
		}
	else RLE_close(fileno(a->ph->fp));
	return(1);
	}

/* Write next line of runs to g31 file, after shifting runs to lie in the range
   [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */
g31_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   int stat;
    RLE_Line crl;
    RLE_Run *rp,*ep,*np;
	if(_O.dbg_r) nerr_RLE_Line("g31_sink: ",rl);
	if(a->bop) {
		PIC_put_hdr(a->ph);
		/* treat FILE *a->ph->fp as a sequence of bits */
		if((a->bf=bopen(a->ph->fp,"w"))==NULL)
			abort("g31_sink: can't open bitfile");
		BOF_to_g31(a->bf);
		a->bop=F;
		};
	if(rl!=NULL) {
		/* check that rl->len is consistent with a->ph */
		if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) {
			err("g31_sink: rl->len %d != wid(a->ph.bx) %d",
				rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1);
			rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1;
			};
		if(rl->runs>0) {
			if(a->ph->bx.a.x!=0) { /* shift runs */
				crl.y = rl->y;
				crl.len = rl->len;
				crl.runs = rl->runs;
				for(ep=(rp=rl->r)+rl->runs,np=crl.r;
				     rp<ep;
				      rp++,np++) {
					np->xs = rp->xs - a->ph->bx.a.x;
					np->xe = rp->xe - a->ph->bx.a.x;
					};
				rlel_to_g31(&crl,crl.len,a->bf);
				}
			else rlel_to_g31(rl,rl->len,a->bf);
			}
		else rlel_to_g31(NULL,rl->len,a->bf);
		a->ph->cy++;
		}
	else {	EOF_to_g31(a->bf);
		bclose(a->bf);
		};
	return(1);
	}

/* Write next line of runs to g32 file, after shifting runs to lie in the range
   [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */
g32_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   static RLE_Line prl;
    RLE_Line *pl;
    RLE_Line crl;
    RLE_Run *rp,*ep,*np;
    	if(_O.dbg_r) nerr_RLE_Line("g32_sink: ",rl);
	if(a->bop) {
		PIC_put_hdr(a->ph);
		/* treat FILE *a->ph->fp as a sequence of bits */
		if((a->bf=bopen(a->ph->fp,"w"))==NULL)
			abort("can't open bitfile");
		BOF_to_g32(a->bf);
		a->bop=F;
		prl.runs = 0;
		};
	if(rl!=NULL) {
		/* check that rl->len is consistent with a->ph */
		if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) {
			err("g32_sink: rl->len %d != wid(a->ph.bx) %d",
				rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1);
			rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1;
			};
		prl.len = rl->len;
		prl.y = rl->y - 1;
		if(((a->ph->cy+1-a->ph->bx.a.y)%a->k)==0) pl=NULL; else pl=&prl;
		if(rl->runs>0) {
			if(a->ph->bx.a.x!=0) { /* shift runs */
				crl.y = rl->y;
				crl.len = rl->len;
				crl.runs = rl->runs;
				for(ep=(rp=rl->r)+rl->runs,np=crl.r;
				     rp<ep;
				      rp++,np++) {
					np->xs = rp->xs - a->ph->bx.a.x;
					np->xe = rp->xe - a->ph->bx.a.x;
					};
				rlel_to_g32(pl,&crl,crl.len,a->bf);
				prl.y=crl.y;
				prl.len=crl.len;
				prl.runs=crl.runs;
				memcpy(prl.r,crl.r,2*prl.runs*sizeof(short));
				}
			else {	rlel_to_g32(pl,rl,rl->len,a->bf);
				prl.y=rl->y;
				prl.len=rl->len;
				prl.runs=rl->runs;
				memcpy(prl.r,rl->r,2*prl.runs*sizeof(short));
				};
			}
		else {	rlel_to_g32(pl,NULL,rl->len,a->bf);
			prl.y=rl->y;
			prl.len=rl->len;
			prl.runs=0;
			}
		a->ph->cy++;
		}
	else {	EOF_to_g32(a->bf);
		bclose(a->bf);
		prl.runs = 0;
		};
	return(1);
	}

/* Write next line of runs to g4 file, after shifting runs to lie in the range
   [ 0, a->ph->bx.b.x - a->ph->bx.a.x ]. */
g4_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   static RLE_Line prl;
    RLE_Line crl;
    RLE_Run *rp,*ep,*np;
	if(_O.dbg_r) nerr_RLE_Line("g4_sink: ",rl);
	if(a->bop) {
		PIC_put_hdr(a->ph);
		/* treat FILE *a->ph->fp as a sequence of bits */
		if((a->bf=bopen(a->ph->fp,"w"))==NULL)
			abort("can't open bitfile");
		BOF_to_g4(a->bf);
		a->bop=F;
		prl.runs = 0;
		};
	if(rl!=NULL) {
		/* check that rl->len is consistent with a->ph */
		if(rl->len != a->ph->bx.b.x - a->ph->bx.a.x + 1) {
			err("g4_sink: rl->len %d != wid(a->ph.bx) %d",
				rl->len, a->ph->bx.b.x - a->ph->bx.a.x + 1);
			rl->len = a->ph->bx.b.x - a->ph->bx.a.x + 1;
			};
		if(rl->runs>0) {
			if(a->ph->bx.a.x!=0) { /* shift runs */
				crl.y = rl->y;
				crl.len = rl->len;
				crl.runs = rl->runs;
				for(ep=(rp=rl->r)+rl->runs,np=crl.r;
				     rp<ep;
				      rp++,np++) {
					np->xs = rp->xs - a->ph->bx.a.x;
					np->xe = rp->xe - a->ph->bx.a.x;
					};
				rlel_to_g4(&prl,&crl,crl.len,a->bf);
				prl.y=crl.y;
				prl.len=crl.len;
				prl.runs=crl.runs;
				memcpy(prl.r,crl.r,2*prl.runs*sizeof(short));
				}
			else {	rlel_to_g4(&prl,rl,rl->len,a->bf);
				prl.y=rl->y;
				prl.len=rl->len;
				prl.runs=rl->runs;
				memcpy(prl.r,rl->r,2*prl.runs*sizeof(short));
				};
			}
		else {	rlel_to_g4(&prl,NULL,rl->len,a->bf);
			prl.runs=0;
			}
		a->ph->cy++;
		}
	else {	EOF_to_g4(a->bf);
		bclose(a->bf);
		prl.runs = 0;
		};
	return(1);
	}

pic_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   int stat;
	if(_O.dbg_r) nerr_RLE_Line("pic_sink: ",rl);
	if(a->bop) {
		PIC_put_hdr(a->ph);
		a->bop=F;
		};
	if(rl!=NULL) {
		crrl(rl->runs,rl->r,0,a->ph->bx.b.x-a->ph->bx.a.x,a->ph->line);
		if((stat=PIC_wline(a->ph,a->ph->line))!=1)
			abort("pic_sink: can't write: stat %d",stat);
		};
	return(1);
	}

#if CPU==SUN
post_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   int stat;
	if(_O.dbg_r) nerr_RLE_Line("post_sink: ",rl);
	if (a->bop) {
		PIC_put_hdr(a->ph);	/* needed for allocation of h->line? */
		POST_start(a->ph);
		a->bop = F;
		};
	if(rl!=NULL) {
		memset(a->ph->line,'\0',a->ph->bpl);
		if(rl->runs>0) {
		    /* convert *rl to binary, using ``little-endian'' bit-order */
		    brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line);
		    };
		if((stat=POST_wline(a->ph,a->ph->line))!=1)
			abort("post_sink: can't write: stat %d",stat);
		}
	else {	POST_end();
		};
	return(1);
	}
#else
post_sink() {abort("-P postscript output unimplemented");};
#endif

#if CPU==SUN
rast_sink(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   int stat;
	if(_O.dbg_r) nerr_RLE_Line("rast_sink: ",rl);
	if (a->bop) {
		PIC_put_hdr(a->ph);	/* needed for allocation of h->line? */
		RAST_start(a->ph);
		a->bop = F;
		};
	if(rl!=NULL) {
		memset(a->ph->line,'\0',a->ph->bpl);
		if(rl->runs>0) {
		    /* convert *rl to binary, using ``little-endian'' bit-order */
		    brrl(rl->runs,rl->r,a->ph->bx.a.x,a->ph->bx.b.x,0,a->ph->line);
		    };
		if((stat=RAST_wline(a->ph,a->ph->line))!=1)
			abort("rast_sink: can't write: stat %d",stat);
		}
	else {	RAST_end();
		};
	return(1);
	}
#else
rast_sink() {abort("-S sunraster output unimplemented");};
#endif

/* Save RLE_Line *rl in buffer, as packed binary, using ``little-endian''
   bit-packing order, rounding each line to the nearest int for speed.
   If a->bop, malloc a complete, contiguous buffer holding the entire page,
   and initialize its contents to zeroes.
   On each call with rl!=NULL, convert the given line to binary & save in buffer.
   When called with rl==NULL but a!=NULL, signalling end-of-page, do nothing.
   Normally, return kludgey (unsigned int *)1, like other sink functions.
   When called with rl==NULL && a==NULL, return pointer to buffer.
   It is the responsibility of the calling code to free the buffer. */
unsigned int *binary_buffer(rl,a)
    RLE_Line *rl;
    Copy_arg *a;
{   static unsigned int *buf = NULL;
    static int ipl = 0;	/* ints/line */
    int bufsz;		/* (bytes) */
    unsigned int *result;
#define BITS_PER_INT (8*sizeof(int))
	if(a!=NULL && a->bop) {
		/* round up to int boundary */
		ipl = (bbx_wid(&(a->ph->bx))+BITS_PER_INT-1)/BITS_PER_INT;
		bufsz = sizeof(int)*ipl*bbx_hgt(&(a->ph->bx));
		if((buf=(unsigned int *)malloc(bufsz))==NULL)
			abort("binary_buffer: can't alloc int buf[%d]",bufsz/sizeof(int));
		memset(buf,'\0',bufsz);
		a->bop=F;
		};
	if(rl!=NULL) {
		/* convert *rl to binary, using ``little-endian'' bit-order */
		if(rl->runs>0) {
		        /* *rl --> binary, with ``little-endian'' bit-order */
#if BIG_ENDIAN
			brrlb( rl->runs, rl->r, a->ph->bx.a.x, a->ph->bx.b.x,
				0, buf+(ipl*(rl->y-a->ph->bx.a.y)) );
#else
			brrl( rl->runs, rl->r, a->ph->bx.a.x, a->ph->bx.b.x,
				0, buf+(ipl*(rl->y-a->ph->bx.a.y)) );
#endif
			};
		return((unsigned int *)1);
		}
	else {	if(a!=NULL) return((unsigned int *)1);
		else {	result = buf;
			buf = NULL;  ipl = 0;
			return(result);
			};
		};
	}

/* Rotate binary buffer *buf (whose shape is specified by a->ph->bx),
   through angle tra->rot, and write the resulting stream of RLE_Line's to
   sink() one at a time, along with a rotated version of *a as the 2nd argument.
   Only PI/2 is supported; UNDER DEVELOPMENT:  other multiples of PI/2 and
   small arbitrary angles. */
rotate_binary_buffer(buf,tra,sink,a)
    unsigned int *buf;
    Transform_rlel_arg *tra;
    int (*sink)();	/* takes args:  (RLE_Line *), and int */
    Copy_arg *a;
{   register int ipl;		/* ints/line in binary buffer */
    Copy_arg ra;		/* rotated */
    RLE_Line rl;
#define TINY_ANG (PI/1000)
	/* round up to int boundary */
	ipl = (bbx_wid(&(a->ph->bx))+BITS_PER_INT-1)/BITS_PER_INT;
	ra = *a;
	ra.bop=T;
	if((ra.ph = (PIC_hdr *)malloc(sizeof(PIC_hdr)))==NULL)
		abort("rotate_binary_buffer: can't malloc ra.ph");
	*(ra.ph) = *(a->ph);
	/* by arbitrary convention, rotated bx.a will coincide with input bx.a */
	if(tra->rot <= PI/2+TINY_ANG && tra->rot >= PI/2-TINY_ANG) {
	    int ey,ii;
	    register RLE_Run *rp;
	    register unsigned int *cb,*eb,bm,obm;
	    register short rx;
		ra.ph->bx.b.x = a->ph->bx.a.x + bbx_hgt(&(a->ph->bx)) - 1;
		ra.ph->bx.b.y = a->ph->bx.a.y + bbx_wid(&(a->ph->bx)) - 1;
		rl.len = ra.wid = bbx_wid(&(ra.ph->bx));
		rl.y = ra.ph->bx.a.y;  ey=ra.ph->bx.b.y;
		ii=0;  bm=01;
		do {	obm=0;	/* assume 0 left of margin */
			rp=rl.r-1;
			rx=ra.ph->bx.a.x;
			cb=(eb=buf+ii)+((rl.len-1)*ipl);
			do {	if((*cb & bm)!=obm) {
					if(obm) { rp->xe=rx-1;  obm=0; }
					else { (++rp)->xs=rx;  obm=bm; };
					};
				rx++;
				}
			while( (cb -= ipl) >= eb );
			if(obm) rp->xe=rx-1;
			rl.runs = rp - rl.r + 1;
			sink(&rl,&ra);
			if((bm<<=1)==0) {ii++; bm=01;};
			}
		while((++rl.y)<=ey);
		}
	else if(tra->rot <= PI+TINY_ANG && tra->rot >= PI-TINY_ANG) {
		rl.len = ra.wid;
		abort("rotate_binary_buffer: tra->rot==%g deg unimplemented",
			tra->rot/DtoR);
		}
	else if(tra->rot <= 3*PI/2+TINY_ANG && tra->rot >= 3*PI/2-TINY_ANG) {
		ra.ph->bx.b.x = a->ph->bx.a.x + bbx_hgt(&(a->ph->bx)) - 1;
		ra.ph->bx.b.y = a->ph->bx.a.y + bbx_wid(&(a->ph->bx)) - 1;
		rl.len = ra.wid = bbx_wid(&(ra.ph->bx));
		abort("rotate_binary_buffer: tra->rot==%g deg unimplemented",
			tra->rot/DtoR);
		}
	else if(tra->rot <= 20.0*DtoR && tra->rot >= -20.0*DtoR) {
	    /* rotation by ``small'' angle */
	    Sp ce;		/* center of image to be rotated */
	    double rcos,rsin;	/* real rotation vector (cos,sin) */
	    double irx,iry;	/* current rotated pixel location */
	    register int sx,sy,ex,ey,rx,ry;
	    register RLE_Run *rp;
	    register int pel,opel;
	    register int orx,ory;
		if(0) err("rotate_binary_buffer: tra->rot==%g deg under development",
			tra->rot/DtoR);
		/* conventionally, keep the same window as the input image,
		   while rotating about its midpoint */
		rl.len = ra.wid = bbx_wid(&(ra.ph->bx));
		sx = ra.ph->bx.a.x;  ex = ra.ph->bx.b.x;
		sy = ra.ph->bx.a.y;  ey = ra.ph->bx.b.y;
		ce.x = sx + bbx_wid(&(ra.ph->bx))/2;
		ce.y = sy + bbx_hgt(&(ra.ph->bx))/2;
		rcos = cos(tra->rot);  rsin = sin(tra->rot);
		for(ory=sy; ory<=ey; ory++) {
			opel=0;	/* left of output margin: assume pel==0 */
			rp=rl.r-1;
			irx = ((rcos*(sx - ce.x) - rsin*(ory - ce.y))) + ce.x;
			iry = ((rsin*(sx - ce.x) + rcos*(ory - ce.y))) + ce.y;
			for(orx=sx; orx<=ex; orx++) {
				rx = (int)(irx + 0.5);  ry = (int)(iry + 0.5);
				if(rx<sx || rx>ex || ry<sy || ry>ey)
					/* outside input image:  assume pel==0 */
					pel=0;
				else /* look at bit within input image */ {
				    int ix,iy,bx;
					iy = (ry-sy)*ipl;
					ix = rx/BITS_PER_INT;
					bx = rx%BITS_PER_INT;
#if BIG_ENDIAN
					pel = (buf[ iy + ix ] & (01<<(BITS_PER_INT-bx-1))) ? 1 : 0;
#else
					pel = (buf[ iy + ix ] & (01<<bx)) ? 1 : 0;
#endif
					};
				if(pel!=opel) {
					if(opel) { rp->xe=orx-1;  opel=0; }
					else { (++rp)->xs=orx;  opel=pel; };
					};
				/* step one pel to the right in output image */
				irx += rcos;  iry += rsin;
				};
			if(opel) rp->xe=orx-1;
			rl.runs = rp - rl.r + 1;
			rl.y = ory;
			sink(&rl,&ra);
			};
		}
	else {	abort("rotate_binary_buffer: tra->rot==%g deg unimplemented",
			tra->rot/DtoR);
		};
	sink(NULL,&ra);	/* signal end-of-page */
	}

/* Copy a source of RLE_Lines to a sink of RLE_Lines, transforming them
   by trimming, shifting, scaling, truncation, and rotation.
      The source is function ir(), which returns non-empty lines only,
   or NULL on end of page.  It is passed `bop=T' on beginning of page.
   On return from ir(), ia->ph->cy holds the index of the line, whose height is
   guaranteed to lie in the range [ia->ph->bx.a.y,ia->ph->bx.b.y].
   All input runs are guaranteed to lie in [ia->ph->bx.a.x,ia->ph->bx.b.x].
   The maximum length (in pels) of each source line is ia->wid.
      The sink function or() takes two arguments:
	RLE_Line *rl;	==NULL on end-of-page
	Copy_arg *a;
   The lines sent to the sink must be in unbroken ascending integer 
   sequence of rl->y (thus blank lines must be explicitly sent).   At all times,
   oa->ph->cy is the line last written.  After the first call to or(),
   oa->ph->cy lies in the range [oa->ph->bx.a.y,oa->ph->bx.b.y].
      Trimming, shifting, scaling, and truncation are performed either
   here or in  function transform_rlel().  Rotation is handled specially:
   the complete output image (after all other transformations have been
   performed) is saved in an intermediate buffer (as packed binary), then
   rotated.  Rotation is much slower than the other operations, mainly due
   to the necessity of touching every pixel.  (Manhattan rotations might be
   faster if the buffer held RLE_lines, but then it would be next-to-impossible
   to extend to arbitrary rotations someday.)
   */
transform_rlels(ir,ia,or,oa,tra)
    RLE_Line *(*ir)();	/* return next RLE_Line */
    Copy_arg *ia;	/* used here (bop & wid) & passed to ir() */
    int (*or)();	/* write next RLE_Line */
    Copy_arg *oa;	/* used here (bop && ph->bx.*.y) & passed to or() */
    Transform_rlel_arg *tra;
{   RLE_Line *irl,*orl;
    static RLE_Line rl0 = Init_RLE_Line;  /* empty line */
    int tr_y;		/* transformed y */
    int (*sv_or)();
	if(tra->rot!=0.0) {
		/* if must rotate the image, first buffer the entire
		   set of output RLE_Lines */
		sv_or = or;
		or = (int (*)())binary_buffer;
		};
	/* signal beginning of page; reset in source() & sink() functions */
	ia->bop=oa->bop=T;	
	/* set first output line number to write */
	tra->dy = (tra->sy = oa->ph->bx.a.y);
	while((irl=ir(ia))!=NULL) {
		if(F&&_O.dbg_r) nerr_RLE_Line("trans.i: ",irl);
		/* trim input lines' Y */
		if(irl->y < tra->tr.a.y) continue;
		if(irl->y > tra->tr.b.y) break;
		/* compute the output Y that is equal to the last
		   of the group of transformed equivalent Y's */
		tr_y = (int)((irl->y + tra->off.y + 1)*tra->scl.y) - 1;
		/* truncate if necessary */
		if(tr_y>oa->ph->bx.b.y) tr_y = oa->ph->bx.b.y;
		/* supply implicit blank line(s) of the same length */
		while(tra->sy < tr_y) {
			rl0.len = ia->wid;
			transform_rlel(&rl0,tra,or,oa);
			};
		irl->len = ia->wid;
		transform_rlel(irl,tra,or,oa);
		};
	/* supply terminating blank line(s) of the same length */
	while(tra->sy < oa->ph->bx.b.y) {
		rl0.len = ia->wid;
		transform_rlel(&rl0,tra,or,oa);
		};
	transform_rlel(NULL,tra,or,oa);   /* signal end of page */
	/* read input until end of page occurs; this is required
	   to support catenated pages */
	while(irl!=NULL) irl=ir(ia);
	if(tra->rot!=0.0) {
	    unsigned int *buf;
		buf = binary_buffer(NULL,NULL);
		if(buf!=NULL) {	
			rotate_binary_buffer(buf,tra,sv_or,oa);
			free(buf);
			};
		};
	}

process_page(i,o)
    Copy_arg *i,*o;
{   RLE_Line *(*source)();
    int (*sink)();
    char unit,*up,cpy[40];		/* units character */
    Transform_rlel_arg tra;

	i->wid = bbx_wid(&(i->ph->bx));

	_O.trim = max_Bbx;	/* start by trimming nothing */
	/* translate units in option arguments */
	if(_O.optarg_l!=NULL) {
		strcpy(cpy,_O.optarg_l);
		if((up=strpbrk(cpy,UNITS))!=NULL) {
			unit= *up;  *up='\0';
			_O.trim.a.x=vto_scoor(atof(cpy),unit,i->ph->res_x);
			}
		else /* assume scanner coordinates */
			_O.trim.a.x=atoi(cpy);
		};
	if(_O.optarg_r!=NULL) {
		strcpy(cpy,_O.optarg_r);
		if((up=strpbrk(cpy,UNITS))!=NULL) {
			unit= *up;  *up='\0';
			_O.trim.b.x=vto_scoor(atof(cpy),unit,i->ph->res_x);
			}
		else /* assume scanner coordinates */
			_O.trim.b.x=atoi(cpy);
		_O.trim.b.x--;	/* -w coordinate is open, Bbx is closed */
		};
	if(_O.optarg_t!=NULL) {
		strcpy(cpy,_O.optarg_t);
		if((up=strpbrk(cpy,UNITS))!=NULL) {
			unit= *up;  *up='\0';
			_O.trim.a.y=vto_scoor(atof(cpy),unit,i->ph->res_y);
			}
		else /* assume scanner coordinates */
			_O.trim.a.y=atoi(cpy);
		};
	if(_O.optarg_b!=NULL) {
		strcpy(cpy,_O.optarg_b);
		if((up=strpbrk(cpy,UNITS))!=NULL) {
			unit= *up;  *up='\0';
			_O.trim.b.y=vto_scoor(atof(cpy),unit,i->ph->res_y);
			}
		else /* assume scanner coordinates */
			_O.trim.b.y=atoi(cpy);
		_O.trim.b.y--;	/* -w coordinate is open, Bbx is closed */
		};
	/* Modified output margins may lie OUTSIDE the input window as well
	   as within it. */
	if(_O.trim.a.x==Scoor_MIN) _O.trim.a.x=i->ph->bx.a.x;
	if(_O.trim.b.x==Scoor_MAX) _O.trim.b.x=i->ph->bx.b.x;
	if(_O.trim.a.y==Scoor_MIN) _O.trim.a.y=i->ph->bx.a.y;
	if(_O.trim.b.y==Scoor_MAX) _O.trim.b.y=i->ph->bx.b.y;
	if(_O.dbg_m) err("trim: %s",bbx_toa(&(_O.trim)));

	if(strcmp(i->ph->type,"binary")==0) { source = binary_source; }
	else if(strcmp(i->ph->type,"bitmap")==0) { source = bitmap_source; }
	else if(strcmp(i->ph->type,"bitfile")==0) { source = bitfile_source; }
	else if(strcmp(i->ph->type,"document-image")==0) { source = dim_source; }
	else if(strcmp(i->ph->type,"dim")==0) { source = dim_source; }
	else if(strcmp(i->ph->type,"rle")==0) {
	    RIC_hdr rh;
		/* reopen RLE file to use system I/O (awkward, obsolescent) */
		lseek(fileno(i->ph->fp),0L,0);
		RLE_open(fileno(i->ph->fp),&rh);
		i->ph->cy = i->ph->bx.a.y-1;
		source = rle_source;
		}
	else if(strcmp(i->ph->type,"pico")==0
		||strcmp(i->ph->type,"dump")==0) {
		i->thresh = _O.thresh;
		source = pic_source;
		}
	else if(strcmp(i->ph->type,"ccitt-g31")==0) {
		if((i->bf=bopen(i->ph->fp,"r"))==NULL)
			abort("can't open bitfile");
		i->tbl = ccitt_table();
		source = g31_source;
		}
	else if(strcmp(i->ph->type,"ccitt-g32")==0) {
		if((i->bf=bopen(i->ph->fp,"r"))==NULL)
			abort("can't open bitfile");
		i->tbl = ccitt_table();
		source = g32_source;
		}
	else if(strcmp(i->ph->type,"ccitt-g4")==0) {
		if((i->bf=bopen(i->ph->fp,"r"))==NULL)
			abort("can't open bitfile");
		i->tbl = ccitt_table();
		source = g4_source;
		}
	else if(strcmp(i->ph->type,"cdf-mrlc")==0) { source = cdf_mrlc_source; }
	else abort("Input file TYPE=%s unsupported",i->ph->type);

	if(_O.dbg_h) err("In %s",PIC_hdr_toa(i->ph));

	/* Adjudicate -R and -x options */
	if(_O.out_res.x==-2) {
		/* -R= specified:  force resolutions to be equal to the greater */
		if(i->ph->res_x < i->ph->res_y) {
			_O.out_res.x = _O.out_res.y = i->ph->res_y;
			}
		else if(i->ph->res_y < i->ph->res_x) {
			_O.out_res.x = _O.out_res.y = i->ph->res_x;
			}
		else _O.out_res.x = _O.out_res.y = i->ph->res_x;
		};
	if(_O.out_res.x!=-1) {	/* -Rx specified; override -xX */
		_O.expand.x = ((double)_O.out_res.x)/i->ph->res_x;
		if(_O.dbg_R && _O.expand.x!=1.0)
			err("horizontal resolution changed: x%g (%d -> %d)",
				_O.expand.x,i->ph->res_x,_O.out_res.x);
		};
	if(_O.out_res.y!=-1) {	/* -R,y specified; override -x,Y */
		_O.expand.y = ((double)_O.out_res.y)/i->ph->res_y;
		if(_O.dbg_R && _O.expand.y!=1.0)
			err("vertical resolution changed: x%g (%d -> %d)",
				_O.expand.y,i->ph->res_y,_O.out_res.y);
		};

	/* Setup image transformation parameters */
	tra = empty_Transform_rlel_arg;
	tra.tr = _O.trim;
	tra.off = _O.offset;
	tra.scl = _O.expand;
	tra.wh.x = bbx_wid(&(tra.tr));
	tra.wh.y = bbx_hgt(&(tra.tr));
	tra.rev = _O.reverse;
	if(tra.scl.x!=1.0) {
		tra.wh.x = (int)(tra.wh.x*tra.scl.x+0.5);
		};
	if(tra.scl.y!=1.0) {
		tra.wh.y = (int)(tra.wh.y*tra.scl.y+0.5);
		};
	switch(_O.top) {
	    case 't':  /* default */ break;
	    case 'l':  /* top is really at left */
		tra.rot = (Radians)(PI/2);
		break;
	    case 'b':  /* top is really at bottom */
		tra.rot = (Radians)(PI);
		break;
	    case 'r':  /* top is really at right */
		tra.rot = (Radians)((3*PI)/2);
		break;
	    case 'a':  /* rotation angle given */
		tra.rot = _O.top_angle;
		break;
	    };
	/* is the transform the identity? (speed-optimized special case) */
	tra.ident = ( (bbx_eq(&(tra.tr),&(i->ph->bx)))
			&& (tra.scl.x==1.0)
			&& (tra.scl.y==1.0)
			&& (tra.off.x==0)
			&& (tra.off.y==0)
			&& (tra.rot==0.0) );

	/* compute transformed output box & resolution;
	   don't rotate here (see transform_rlels()) */
	if(tra.ident) {
		o->ph->bx = i->ph->bx;
		o->ph->res_x = i->ph->res_x;
		o->ph->res_y = i->ph->res_y;
		}
	else {	o->ph->bx = tra.tr;
		o->ph->bx.a.x += tra.off.x;
		o->ph->bx.b.x += tra.off.x;
		o->ph->bx.a.y += tra.off.y;
		o->ph->bx.b.y += tra.off.y;
		if(tra.scl.x!=1.0) {
			o->ph->bx.a.x = tra.scl.x*o->ph->bx.a.x;
			o->ph->bx.b.x = o->ph->bx.a.x + tra.wh.x-1;
			};
		if(tra.scl.y!=1.0) {
			o->ph->bx.a.y = tra.scl.y*o->ph->bx.a.y;
			o->ph->bx.b.y = o->ph->bx.a.y + tra.wh.y-1;
			};
		o->ph->res_x = (i->ph->res_x*tra.scl.x + 0.5);
		o->ph->res_y = (i->ph->res_y*tra.scl.y + 0.5);
		};

	if(_O.to_bin)
		{ strcpy(o->ph->type,"binary"); sink = binary_sink; }
	else if(_O.to_bitfile)
		{ strcpy(o->ph->type,"bitfile"); sink = bitfile_sink; }
	else if(_O.to_bitmap)
		{ strcpy(o->ph->type,"bitmap"); sink = bitmap_sink; }
	else if (_O.to_rle) {
		if(strcmp(i->ph->type,"rle")==0)
			abort("can't both read and write TYPE=rle - sorry");
		strcpy(o->ph->type,"rle"); sink = rle_sink;
		}
	else if(_O.to_g31) { strcpy(o->ph->type,"ccitt-g31"); sink = g31_sink; }
	else if(_O.to_g32) {
		strcpy(o->ph->type,"ccitt-g32");
		o->k = _O.g32_k;
		sink = g32_sink;
		}
	else if(_O.to_g4) { strcpy(o->ph->type,"ccitt-g4");  sink = g4_sink; }
	else if(_O.to_pic) { strcpy(o->ph->type,"dump");  sink = pic_sink; }
#if CPU==SUN
	else if(_O.to_post) { strcpy(o->ph->type,"postscript"); sink = post_sink; }
#endif
#if CPU==SUN
	else if(_O.to_rast) { strcpy(o->ph->type,"sunraster"); sink = rast_sink; }
#endif
	if(i->ph->misc!=NULL) {
		o->ph->misc = i->ph->misc;
		i->ph->misc = NULL;
		};
	if(_O.dbg_h) err("Out %s",PIC_hdr_toa(o->ph));

	transform_rlels(source,i,sink,o,&tra);

	/* Synchronize filedes pointer with stream pointer */
	lseek(fileno(o->ph->fp),o->ph->seek = ftell(o->ph->fp),0);
	}

/* A file may be a catenation of pages. */
process_fps(i,o)
    FILE *i,*o;
{   Copy_arg ia,oa;
    int stat;
	ia = oa = empty_Copy_arg;
	ia.ph = alloc_PIC_hdr(i);
	oa.ph = alloc_PIC_hdr(o);

	stat=PIC_get_hdr(ia.ph);
	if(_O.dbg_h && stat!=1) err("PIC_get_hdr() returns status %d",stat);

	/* enforce bitfile(9) I/O restrictions */
	if(_O.from_bitfile && strcmp(ia.ph->type,"bitfile")!=0)
		abort("-Bi requires input to be bitfile(9.5) format");
	if(!_O.from_bitfile && strcmp(ia.ph->type,"bitfile")==0) {
		/* TYPE= is missing, erroneously:  refuse to recognize it */
		abort("TYPE=... header is missing");
		};

	if(strcmp(ia.ph->type,"document-image")==0
	   || strcmp(ia.ph->type,"dim")==0) {
	    Page pg;
		skip_doc(i);
		if(frdb_page_etc(i,&pg,IsALL)==1) {
			ia.ph->bx = pg.bx;
			ia.ph->res_x = pg.res_x;
			ia.ph->res_y = pg.res_y;
			ia.rles = *rle_lines_of_page(&pg);
			if(_O.shrinkwrap!=-1) {
			    Sp trans;
				ia.ph->bx = *bbx_of_rle_lines(&ia.rles);
				ia.ph->bx.a.x -= _O.shrinkwrap;
				ia.ph->bx.a.y -= _O.shrinkwrap;
				ia.ph->bx.b.x += _O.shrinkwrap;
				ia.ph->bx.b.y += _O.shrinkwrap;
				if(bbx_area(&(ia.ph->bx))<=0)
				    abort("-W%d shrinks to nothing",_O.shrinkwrap);
				trans.x = -ia.ph->bx.a.x; trans.y = -ia.ph->bx.a.y;
				translate_rle_lines(&ia.rles,trans);
				ia.ph->bx.b.x = bbx_wid(&ia.ph->bx)-1;
				ia.ph->bx.b.y = bbx_hgt(&ia.ph->bx)-1;
				ia.ph->bx.a.x = ia.ph->bx.a.y = 0;
				};
			free_page_etc(&pg,IsALL&(~IsPage));
			}
		else {	free_page_etc(&pg,IsALL&(~IsPage));
			abort("can't read document-image file");
			};
		};
	if(_O.in_res.x!=SHRT_MIN&&_O.in_res.y!=SHRT_MIN) {
		/* force input RES to given values */
		if(ia.ph->res_x!=0 || ia.ph->res_y!=0) {
			err("input: RES=%d %d overridden by -Z%d,%d\n",
				ia.ph->res_x,ia.ph->res_y,_O.in_res.x,_O.in_res.y);
			};
		ia.ph->res_x = _O.in_res.x;
		ia.ph->res_y = _O.in_res.y;
		};
	if(ia.ph->res_x<=0 || ia.ph->res_y<=0)
		err("input: RES=%d %d may cause problems (set using -Zx,y)",
			ia.ph->res_x,ia.ph->res_y);

	while(strlen(ia.ph->type)>0 && stat==1 && !feof(i)
		&& !ferror(i) && !ferror(o)) {
		process_page(&ia,&oa);
		if( strcmp(ia.ph->type,"cdf")==0
		    || strcmp(ia.ph->type,"cdf-mrlc")==0 ) {
			stat=CDF_next_page(ia.ph);
			}
		else {	if((stat=PIC_get_hdr(ia.ph))==1) {
				/* enforce bitfile(9) I/O restrictions */
				if(_O.from_bitfile && strcmp(ia.ph->type,"bitfile")!=0)
					abort("-Bi means input must be picfile");
				if(!_O.from_bitfile && strcmp(ia.ph->type,"bitfile")==0) {
					/* TYPE= is missing, erroneously:  silently quit */
					if(_O.dbg_h) err("strange input before normal EOF - ignored");
					strcpy(ia.ph->type,"");
					};
				};
			};
		if(_O.dbg_h && stat!=1)
			err("PIC_get_hdr() returns status %d",stat);
		};

	/* EOF or error */
	free_PIC_hdr(ia.ph);
	free_PIC_hdr(oa.ph);
	}

#if FILE_TREE
/* Process filenames:  if NULL, use stdin/stdout;  if files, read them;
   if directories, create a parallel file tree and process the leaves
   pairwise. */
process_fns(i,o)
    char *i;		/* may be NULL; not yet fopened for read */
    char *o;		/* may be NULL; not yet fopened for write */
#define dbg_ft (F)
{   FILE *i_fp;
    FILE *o_fp;
    char *branch;
	if(dbg_ft) err("processs(\"%s\",\"%s\")",i,o);
	branch=path_toa(&path_process.path,1);
	if(dbg_ft&&branch[0]!='\0') err("%s",branch);
	if(i==NULL||i[0]=='\0') i_fp=stdin;
	else if( (i_fp=fopen(i,"r"))==NULL ) {
		err("can't open input file %s - skip it",i);
		return;
		};
	if(o==NULL||o[0]=='\0') o_fp=stdout;
	else if( (o_fp=fopen(o,"w"))==NULL ) {
		err("can't open output file %s - skip it",o);
		return;
		};
	process_fps(i_fp,o_fp);
	if(i_fp!=stdin) fclose(i_fp);
	if(o_fp!=stdout) fclose(o_fp); else fflush(o_fp);
	};
#else
/* Process filenames:  if NULL, use stdin/stdout;  if files, open and process them.
   */
process_fns(i_fn,o_fn)
    char *i_fn;		/* may be NULL; not yet fopened for read */
    char *o_fn;		/* may be NULL; not yet fopened for write */
{   FILE *i_fp;
    FILE *o_fp;
	if(i_fn==NULL||strlen(i_fn)==0) i_fp = stdin;
	else {	if((i_fp=fopen(i_fn,"r"))==NULL)
			abort("can't open input file %s",i_fn);
		};
	if(o_fn==NULL||strlen(o_fn)==0) o_fp = stdout;
	else {	if((o_fp=fopen(o_fn,"w"))==NULL)
			abort("can't open output file %s",o_fn);
		};
	process_fps(i_fp,o_fp);
	if(i_fp!=stdin) fclose(i_fp);
	if(o_fp!=stdout) fclose(o_fp); else fflush(o_fp);
	};
#endif

main(arc,arv)
    int arc; char **arv;
{	parse_args(arc,arv);
#if FILE_TREE
	process_file_trees(process_fns,_O.in_fn,_O.out_fn);
#else
	process_fns(_O.in_fn,_O.out_fn);
#endif
	}

nerr_RLE_Line(s,rl)
    char *s;
    RLE_Line *rl;
{   RLE_Run *r;
    int ri;
	if(rl==NULL) fprintf(stderr,"%15s RLEL NULL.\n",s);
	else {	fprintf(stderr,"%15s RLEL y%d r%d l%d: ",s,rl->y,rl->runs,rl->len);
		for(ri=0,r=rl->r; ri<rl->runs; ri++,r++)
			fprintf(stderr,"[%d,%d] ",r->xs,r->xe);
		fprintf(stderr,"\n");
		};
	}
0707070035351137201006640007620000050000010263350476773367100001000000030702bitio.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* bitio.h - view a stream file as a sequence of binary values, hiding the
   bit- and byte-packing format of the file.  The format of input and output
   files may differ.   Reading and writing are performed by macroes for speed;
   the price for this is that the file formats must be fixed at compile time.

SYNOPSIS
	#include <stdio.h>
	#include "bitio.h"

	BITFILE *bopen(stream,type);
	    FILE *stream;
	    char *type;

	int getb(bitfile);
	    BITFILE *bitfile;

	putb(bit,bitfile);
	    int bit;

	padb(bitfile,bit,bdy,len);
	    int bit,bdy,len;

	char *bbuffer(bitfile);

	unsigned long bsize(bitfile);
	
	unsigned long bflush(bitfile);

	unsigned long bclose(bitfile);

COMPILER DEPENDENCIES
   The compiler's data types must include:
	unsigned char:  8 bits each
	unsigned short: 2 unsigned chars each
	unsigned int:   2 unsigned shorts each
DESCRIPTION
	Bopen views the named stream file as a bit file to be read (if type is "r")
   or written (if type is "w" or "wb").   The stream file must already have been
   fopen(3)ed, and the first bit to be read/written will be the first bit in its
   next byte in getc(3)/putc(3) order.  Bopen returns a pointer which identifies
   the bitfile to the other functions.  System or stream I/O to/from the
   associated stream should not be used until after bclose is called.
	If bopen's type is "wb", then the entire output stream will be buffered
   in main memory until bflush or bclose are called.  At any time, bbuffer
   returns this buffer's address and bsize its length in bytes.
	Getb returns the next bit from the named bitfile.  It returns EOF on
   end of file or read error.  EOF may occur on a byte, short, or int boundary,
   depending on file format.
	Putb appends the given bit to the named bitfile.
	Padb writes 'bit' enough times (possibly 0) so that if a bitstring
   of length 'len' were written next it would end on a 'bdy'-bit boundary
   (may do the wrong thing if 'bdy' doesn't divide UINT_MAX).
	Bflush ensures that all written bits have been written to the stream
   via putc(3).  The output is padded with 0 bits to a byte, short, or int
   boundary, depending on file format.  It returns the number of bytes (not bits)
   written since bopen or the last bflush.  The bitfile remains open.  It does not
   fflush(3) the associated stream.  
	Bclose causes a bflush and frees all buffers.  It returns the total
   number of bytes (not bits) read/written since bopen.  It fflush(3)'es,
   but does not fclose(3) the associated stream.

        Bitfile formats are selected at compile time: see `FORMAT:' at the
   end of this file.  The formats for input and output may differ.  Formats
   include:
   a	each bit is an ASCII character: '0' or '1', in putc(3) order; not padded.
   0	the low-order (0001) bit in each byte is first ("little-endian"), and
	bytes are in putc(3) order; EOF and padding at a byte boundary.
   1	the high-order (0200) bit in each byte is first ("big-endian"), and
	bytes are in putc(3) order; EOF and padding at a byte boundary.
   10	the low-order (0001) bit in each byte is first ("little-endian"), but
	bytes are reversed (in each pair) from putc(3) order;  EOF and padding
	at a short boundary.
   11	the high-order (0200) bit in each byte is first ("big-endian"), but
	bytes are reversed (in each pair) from putc(3) order; EOF and padding
	at a short boundary.
   Planned (data structures are in place; code will be implemented if needed):
   100	the low-order (0001) bit in each byte is first ("little-endian"), and
	bytes (in each pair) are in putc(3) order; but shorts (in each pair)
	are reversed from putc(3) order;  EOF and padding at an int boundary.
   101, 110, 111 - by obvious analogy
BUGS
	Putting to an input bitfile or getting from an output bitfile is
   erroneous, but is not checked for.
*/

#define BUFFERED (T)	/* enable buffering of output */

typedef struct BITFILE {
	FILE *fp;		/* associated stream */
	char type;		/* one of 'r','w' */
	int ic;			/* byte just read */
	unsigned long nb;	/* no. bytes read/written since bopen */
	unsigned long alloc;	/* no. bytes allocated in buffer */
	char *buf;		/* buffer (in malloc space) */
	char *cp;		/* next char in buffer */
	unsigned int n;		/* no. bits written so far (mod UINT_MAX) */
	unsigned char cm;	/* single-bit mask */
	unsigned short sm;	/* single-bit mask */
	unsigned int im;	/* single-bit mask */
	union {	struct {	/* used to reorder char & short order */
			union {	struct {
					unsigned char c0;
					unsigned char c1;
					} cc;
				unsigned short s;
				} s0;
			union {	struct {
					unsigned char c0;
					unsigned char c1;
					} cc;
				unsigned short s;
				} s1;
			} ss;
		unsigned int i;
		} i;
	} BITFILE;
#define Init_BITFILE {NULL,'\0',0,0L,0L,NULL,NULL,0,0,0}
#if MAIN
BITFILE empty_BITFILE = Init_BITFILE;
#else
extern BITFILE empty_BITFILE;
#endif

/* Code common to all formats: */
#if MAIN
BITFILE *bopen_rw(s,t)
    FILE *s;
    char *t;
{   BITFILE *f;
	if((f=(BITFILE *)malloc(sizeof(BITFILE)))==NULL) {
		err("bopen: can't alloc");
		return(NULL);
		};
	*f = empty_BITFILE;
	f->fp = s;
	f->type = *t;
	return(f);
	}
#else
BITFILE *bopen_rw();
#endif

#define bbuffer(f) ((f)->buf)
#define bsize(f) ((bbuffer(f)!=NULL)? ((f)->cp - (f)->buf): 0L)

#if !BUFFERED
#define bputc(c,f) putc((c),(f)->fp)
#define bbflush(f) (0L)
#else
#define BITFILE_incr (512)	/* buffer allocations are in these increments */

#if MAIN
brealloc(f)
    BITFILE *f;
{   int nbuf;	/* no. bytes in buffer */
	nbuf = bsize(f);
	f->alloc += BITFILE_incr;
	if((f->buf=(char *)realloc(f->buf,f->alloc))==NULL)
		abort("");
	f->cp = f->buf + nbuf;
	}
#endif

#define bputc(c,f) { \
	if((f)->buf==NULL) putc((c),(f)->fp); \
	else {	if(bsize(f)==(f)->alloc) brealloc(f); \
		*(++((f)->cp))=(c); \
		} \
	}

#if MAIN
unsigned long bbflush(f)
    BITFILE *f;		/* f->buf!=NULL && bsize(f)>0 */
{   register char *cp,*cq;
    unsigned long nbuf;
	nbuf = bsize(f);
	for(cq=(cp=f->buf)+nbuf; cp<cq; cp++) putc(*cp,f->fp);
	f->cp=f->buf;
	return(nbuf);
	}
#else
unsigned long bbflush();
#endif
#endif

/* Code particular to each format: */

/* Format a:  ASCII file, one printable char ('0' or '1') per bit: */
#define bopen_r_a(s) bopen_rw((s),"r")
#define bopen_w_a(s) bopen_rw((s),"w")
#define getb_a(f) ( (((f)->ic=getc((f)->fp))!=EOF)? \
			((f)->nb++, \
			 ((f)->ic=='0')? \
				0: \
				(((f)->ic=='1')? 1: EOF)): \
			EOF )
#define putb_a(b,f) { if((b)) bputc('1',f); else bputc('0',f); (f)->nb++; }
#define bflush_a(f) ( (bsize(f)>0)? bbflush(f): (0L) )

/* Format 0:  the low-order bit (0001) in each byte is first ("little-endian"),
   and bytes are in putc(3) order; */
#if MAIN
BITFILE *bopen_r_0(s)
    FILE *s;
{   BITFILE *f;
	if((f=bopen_rw(s,"r"))!=NULL) {
		f->cm=0000;
		};
	return(f);
	}
#else
BITFILE *bopen_r_0();
#endif
#if MAIN
BITFILE *bopen_w_0(s)
    FILE *s;
{   BITFILE *f;
	if((f=bopen_rw(s,"w"))!=NULL) {
		f->i.ss.s0.cc.c0=0000;
		f->cm=0001;
		};
	return(f);
	}
#else
BITFILE *bopen_w_0();
#endif
#define getb_0(f) ( ((f)->cm)? \
			( ((f)->cm&(f)->ic)? \
				((f)->cm<<=1,1): \
				((f)->cm<<=1,0) ): \
			( (((f)->ic=getc((f)->fp))==EOF)? \
				EOF: \
				( (f)->nb++, \
				  (f)->cm=0001, \
				  ((f)->cm&(f)->ic)? \
					((f)->cm<<=1,1): \
					((f)->cm<<=1,0) ) ) )
#define putb_0(b,f) { \
	if((b)) (f)->i.ss.s0.cc.c0 |= (f)->cm; \
	if( !((f)->cm<<=1) ) { \
		bputc((f)->i.ss.s0.cc.c0,f); \
		(f)->nb++; \
		(f)->i.ss.s0.cc.c0=0000; (f)->cm=0001; \
		}; \
	(f)->n++; \
	}
#define bflush_0(f) (padb((f),0,8,0), (bsize(f)>0)? bbflush(f): 0L)

/* Format 1:  the high-order bit (0200) in each byte is first ("big-endian"), and
   bytes are in putc(3) order; */
#if MAIN
BITFILE *bopen_r_1(s)
    FILE *s;
{   BITFILE *f;
	if((f=bopen_rw(s,"r"))!=NULL) {
		f->cm=0000;
		};
	return(f);
	}
#else
BITFILE *bopen_r_1();
#endif
#if MAIN
BITFILE *bopen_w_1(s)
    FILE *s;
{   BITFILE *f;
	if((f=bopen_rw(s,"w"))!=NULL) {
		f->i.ss.s0.cc.c0=0000;
		f->cm=0200;
		};
	return(f);
	}
#else
BITFILE *bopen_w_1();
#endif
#define getb_1(f) ( ((f)->cm)? \
			( ((f)->cm&(f)->ic)? \
				((f)->cm>>=1,1): \
				((f)->cm>>=1,0) ): \
			( (((f)->ic=getc((f)->fp))==EOF)? \
				EOF: \
				( (f)->nb++, \
				  (f)->cm=0200, \
				  ((f)->cm&(f)->ic)? \
					((f)->cm>>=1,1): \
					((f)->cm>>=1,0) ) ) )
#define putb_1(b,f) { \
	if((b)) (f)->i.ss.s0.cc.c0 |= (f)->cm; \
	if( !((f)->cm>>=1) ) { \
		bputc((f)->i.ss.s0.cc.c0,f); \
		(f)->nb++; \
		(f)->i.ss.s0.cc.c0=0000; (f)->cm=0200; \
		}; \
	(f)->n++; \
	}
#define bflush_1(f) (padb((f),0,8,0), (bsize(f)>0)? bbflush(f): 0L)

/* Format 10: the low-order (0001) bit in each byte is first ("little-endian"), and
   bytes are reversed (in each pair) from putc(3) order;
 */
#if MAIN
BITFILE *bopen_r_10(s)
    FILE *s;
{   BITFILE *f;
	if((f=bopen_rw(s,"r"))!=NULL) {
		f->sm=0000000;
		};
	return(f);
	}
#else
BITFILE *bopen_r_10();
#endif
#if MAIN
BITFILE *bopen_w_10(s)
    FILE *s;
{   BITFILE *f;
	if((f=bopen_rw(s,"w"))!=NULL) {
		f->i.ss.s0.s=0000000;
		f->sm=0000001;
		};
	return(f);
	}
#else
BITFILE *bopen_w_10();
#endif
#define getb_10(f) ( ((f)->sm)? \
			( ((f)->sm&(f)->i.ss.s0.s)? \
				((f)->sm<<=1,1): \
				((f)->sm<<=1,0) ): \
			( (((f)->ic=getc((f)->fp))==EOF)? \
				EOF: \
				( (f)->nb++, \
				  (f)->i.ss.s0.cc.c1=(f)->ic&0377, \
				  ( (((f)->ic=getc((f)->fp))==EOF)? \
					EOF: \
					( (f)->nb++, \
					  (f)->i.ss.s0.cc.c0=(f)->ic&0377, \
				  	  (f)->sm=0000001, \
				  	  ((f)->sm&(f)->i.ss.s0.s)? \
						((f)->sm<<=1,1): \
						((f)->sm<<=1,0) ) ) ) ) )
#define putb_10(b,f) { \
	if((b)) (f)->i.ss.s0.s |= (f)->sm; \
	if( !((f)->sm<<=1) ) { \
		bputc((f)->i.ss.s0.cc.c1,f); \
		(f)->nb++; \
		bputc((f)->i.ss.s0.cc.c0,f); \
		(f)->nb++; \
		(f)->i.ss.s0.s=0000000; (f)->sm=0000001; \
		}; \
	(f)->n++; \
	}
#define bflush_10(f) (padb((f),0,16,0), (bsize(f)>0)? bbflush(f): 0L)

/* Format 11:  the high-order (0200) bit in each byte is first ("little-endian"),
   and bytes are reversed (in each pair) from putc(3) order.
 */
#if MAIN
BITFILE *bopen_r_11(s)
    FILE *s;
{   BITFILE *f;
	if((f=bopen_rw(s,"r"))!=NULL) {
		f->sm=0000000;
		};
	return(f);
	}
#else
BITFILE *bopen_r_11();
#endif
#if MAIN
BITFILE *bopen_w_11(s)
    FILE *s;
{   BITFILE *f;
	if((f=bopen_rw(s,"w"))!=NULL) {
		f->i.ss.s0.s=0000000;
		f->sm=0100000;
		};
	return(f);
	}
#else
BITFILE *bopen_w_11();
#endif
#define getb_11(f) ( ((f)->sm)? \
			( ((f)->sm&(f)->i.ss.s0.s)? \
				((f)->sm>>=1,1): \
				((f)->sm>>=1,0) ): \
			( (((f)->ic=getc((f)->fp))==EOF)? \
				EOF: \
				( (f)->nb++, \
				  (f)->i.ss.s0.cc.c0=(f)->ic&0377, \
				  ( (((f)->ic=getc((f)->fp))==EOF)? \
					EOF: \
					( (f)->nb++, \
					  (f)->i.ss.s0.cc.c1=(f)->ic&0377, \
				  	  (f)->sm=0100000, \
				  	  ((f)->sm&(f)->i.ss.s0.s)? \
						((f)->sm>>=1,1): \
						((f)->sm>>=1,0) ) ) ) ) )
#define putb_11(b,f) { \
	if((b)) (f)->i.ss.s0.s |= (f)->sm; \
	if( !((f)->sm>>=1) ) { \
		bputc((f)->i.ss.s0.cc.c0,f); \
		(f)->nb++; \
		bputc((f)->i.ss.s0.cc.c1,f); \
		(f)->nb++; \
		(f)->i.ss.s0.s=0000000; (f)->sm=0100000; \
		}; \
	(f)->n++; \
	}
#define bflush_11(f) (padb((f),0,16,0), (bsize(f)>0)? bbflush(f): 0L)

/**************************************************************/
/* FORMAT: may be selected here (input and output may differ) */

/* Input: */
#define bopen_r(s) bopen_r_0((s))
#define getb(f) getb_0(f)
/* Output: */
#define bopen_w(s) bopen_w_0((s))
#define putb(b,f) putb_0((b),(f))
#define bflush(f) bflush_0(f)

/**************************************************************/

/* Code common to all formats: */
#if MAIN
BITFILE *bopen(s,t)
    FILE *s;
    char *t;
{   BITFILE *res;
	if(*(t)=='r') res=bopen_r(s);
	else if(*(t)=='w') {
		res=bopen_w(s);
#if BUFFERED
		if(*(t+1)=='b') {
			res->alloc = BITFILE_incr;
			if((res->buf=(char *)malloc(res->alloc))==NULL)
				abort("bopen: can't alloc buffer");
			res->cp = res->buf;
			};
#endif
		}
	else abort("bopen: bad type: \"%s\"",t);
	return(res);
	}
#else
BITFILE *bopen();
#endif

#if MAIN
padb(f,b,B,l)
    BITFILE *f;
    char b;
    int l,B;
{	while(((f)->n+(l))%(B)) putb((b),(f));
	}
#endif

#if MAIN
unsigned long bclose(f)
    BITFILE *f;
{   unsigned long nb,nbuf;
	if(f->type=='w') {
		nbuf=bflush(f);
		fflush(f->fp);
#if BUFFERED
		if(f->buf!=NULL) { free(f->buf); f->buf=NULL; }
#endif
		};
	nb=f->nb;
	free(f);
	return(nb);
	}
#else
unsigned long bclose();
#endif
0707070035350557131006640007620000050000010263430476773367100001000000000615boole.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* boole.h */

#define boolean int
#define T 1
#define F 0
0707070035350321011006640007620000050000010263450476773367100000700000020537fioi.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* fioi.h - buffered I/O of machine-, OS-, and compiler-independent binary values.

   Machine-, OS-, and compiler-independence of 'fioi' functions require that:
      1) chars are exactly 8 bits and their contents are invariant under I/O;
      2) the order of chars, as written by putc() and read by getc(), is
	 also invariant, across all machines, OS, and compilers.
   Both of these requirements are customarily met by UNIX OS & tools.

   All values are written/read as a stream of char's, ultimately
   using putc() & getc() macroes.
   To maximize speed, macroes are used wherever possible:
   -  the first argument F of each macro is a stream (FILE *).
   -  write macroes have the form fwri_TYPE(F,value); `value' is assigned to
      a variable of type TYPE before it is written (so compiler-dependent type
      coercions may apply).
   - read macroes have the form frdi_TYPE(F), returning a value of type TYPE.
   Arguments to these macroes are evaluated exactly once.
   */

/** MACHINE-DEPENDENT CUSTOMIZATION OF TYPES **/
/* For each machine, all these types must be supported in the sense that
   some roughly-equivalent machine-supported type exists.  If an exact
   equivalent doesn't exist, pick the shortest that is at least as long
   (in no. bytes), if possible.  If there is no machine representation
   at least as long as specified, the only penalty will be the inevitable one:
   when a value is read, it may be truncated to the maximum value that can be
   represented.
   */
#define int1 char		/* 8-bit signed 2's complement integer */
#define int2 short		/* 16-bit signed 2's complement integer */
#define int3 int		/* 24-bit signed 2's complement integer */
#define int4 int		/* 32-bit signed 2's complement integer */
#define int8 long		/* 64-bit signed 2's complement integer */
#define uint1 unsigned char	/* 8-bit unsigned integer */
#define uint2 unsigned short	/* 16-bit unsigned integer */
#define uint3 unsigned int	/* 24-bit unsigned integer */
#define uint4 unsigned int	/* 32-bit unsigned integer */
#define uint8 unsigned long	/* 64-bit unsigned integer */

/* IEEE 64-bit floating point format */
typedef struct Ieeed {
	int8 l;
	int8 h;
	} Ieeed;

/* Cope with unsigned chars on 3B2 & compensate for bug on MIPS */
#if CPU!=ATT3B && CPU!=MIPS
#define toint1(c) (int1)(c)
#else
#if MAIN
int toint1(c)
    register int c;
{	if ( ((1<<7)&c) !=0 ) return(c-256);
	else return c;
	}
#else
extern int toint1();
#endif
#endif

/** THE REST OF THIS FILE IS MACHINE-, OS-, and COMPILER-INDEPENDENT **/

typedef struct Fioi {
	int1 i1;
	int2 i2;
	int3 i3;
	int4 i4;
	int8 i8;
	uint1 ui1;
	uint2 ui2;
	uint3 ui3;
	uint4 ui4;
	uint8 ui8;
	char str[100];
	} Fioi;
#define Init_Fioi {0,0,0,0,0,0,0,0,0,0,""}
#if MAIN
Fioi _Fioi = Init_Fioi;
#else
extern Fioi _Fioi;
#endif

/* Characters */
#define fwri_ch(F,V) putc((V),(F))
#define frdi_ch(F) getc((F))

#if T	/* TRANSITIONAL:  used to read:  "#if FWRI" */
/* Strings are '\0'-terminated both in main memory & in peripheral files. */
#define fwri_str(F,S) { fputs((S),(F)); putc('\0',(F)); }
#else
/* Strings are '\0'-terminated in the variable and '\n'-terminated in the file.
   BAD, OBSOLESCENT POLICY:  both should use '\0'-termination */
#define fwri_str(F,S) { fputs((S),(F)); putc('\n',(F)); }
#endif

#define MAX_FIO_STRLEN (128)

#if T	/* TRANSITIONAL:  used to read:  "#if FRDI" */

/* Strings are '\0'-terminated both in main memory & in peripheral files. */
/*** TRANSITIONAL PATCH:  accept '\n' as a terminator also;  this will be disabled
     as soon as all classifier tables have been recreated with FWRI==T. ***/
/* Read string of maximum length MAX_FIO_STRLEN; return pointer to malloc space */
#if MAIN
char *frdi_str(f)
    FILE *f;
{   static char s[MAX_FIO_STRLEN+1];
    register int ch;
    register char *c,*ce;
    char *res;
	ce=(c=s)+MAX_FIO_STRLEN;
	while((c<ce)&&((ch=getc(f))!=EOF)&&(ch!='\0')&&(ch!='\n')) *(c++) = ch;
	*c='\0';
	if(c==ce) /* label is truncated; find end of it */ {
		while(((ch=getc(f))!=EOF)&&(ch!='\0')&&(ch!='\n')) ;
		};
	if((res=(char *)strdup(s))==NULL)
		abort("frdi_str: can't dup char *s[%d]",strlen(s));
	return(res);
	}
#else
char *frdi_str();
#endif
/* 's' is an already-allocated buffer of known length >=N (including '\0') */
#if MAIN
int frdi_strn(f,s,n)
    FILE *f;
    char s[];
    int n;
{   register int ch;
    register char *c,*ce;
	ce=(c=s)+n-1;
	while((c<ce)&&((ch=getc(f))!=EOF)&&(ch!='\0')&&(ch!='\n')) *(c++) = ch;
	*c='\0';
	if(c==ce) /* label is truncated; find end of it */ {
		while(((ch=getc(f))!=EOF)&&(ch!='\0')&&(ch!='\n')) ;
		};
	if(ch==EOF) return(0); else if(ferror(f)) return(-errno); else return(1);
	}
#else
int frdi_strn();
#endif

#else

/* Strings are '\0'-terminated in the variable and '\n'-terminated in the file.
   BAD, OBSOLESCENT POLICY:  both should use '\0'-termination */
/* Read string of maximum length MAX_FIO_STRLEN; return pointer to malloc space */
#if MAIN
char *frdi_str(f)
    FILE *f;
{   static char s[MAX_FIO_STRLEN+1];
    register int ch;
    register char *c,*ce;
    char *res;
	ce=(c=s)+MAX_FIO_STRLEN;
	while((c<ce)&&((ch=getc(f))!=EOF)&&(ch!='\n')) *(c++) = ch;
	*c='\0';
	if(c==ce) /* label is truncated; find end of it */ {
		while(((ch=getc(f))!=EOF)&&(ch!='\n')) ;
		};
	if((res=(char *)strdup(s))==NULL)
		abort("frdi_str: can't dup char *s[%d]",strlen(s));
	return(res);
	}
#else
char *frdi_str();
#endif
/* S is an already-allocated buffer of known length >=N (including '\0') */
#define frdi_strn(F,S,N) ( feof(F)? 0 : ( \
	fgets((S),(N),(F)), \
	( (((S)[strlen((S))-1])=='\n')? (S)[strlen((S))-1]='\0': 1 ), \
	(ferror(F)? -errno: 1) ) )

#endif

/* Integers (unsigned and signed) are written low-order byte first. */
#define fwri_uint1(F,V) fwri_ch((F),(uint1)(V))
#define frdi_uint1(F) ((uint1)frdi_ch((F)))

#define fwri_uint2(F,V) { fwri_uint1((F),_Fioi.ui2=(V)); \
			fwri_uint1((F),_Fioi.ui2>>8); }
#define frdi_uint2(F) ((uint2)( _Fioi.ui2=frdi_uint1((F)), \
			(frdi_uint1((F))<<8)|_Fioi.ui2 ))

#define fwri_uint3(F,V) { fwri_uint2((F),_Fioi.ui3=(V)); \
			fwri_uint1((F),_Fioi.ui3>>16); }
#define frdi_uint3(F) ((uint3)( _Fioi.ui3=frdi_uint2((F)), \
			(frdi_uint1((F))<<16)|_Fioi.ui3 ))

#define fwri_uint4(F,V) { fwri_uint2((F),_Fioi.ui4=(V)); \
			fwri_uint2((F),_Fioi.ui4>>16); }
#define frdi_uint4(F) ((uint4)( _Fioi.ui4=frdi_uint2((F)), \
			(frdi_uint2((F))<<16)|_Fioi.ui4 ))

#define fwri_uint8(F,V) { fwri_uint4((F),_Fioi.ui8=(V)); \
			fwri_uint4((F),_Fioi.ui8>>32); }
#define frdi_uint8(F) ((uint8)( _Fioi.ui8=frdi_uint4((F)), \
			(frdi_uint4((F))<<32)|_Fioi.ui8 ))

/* Signed integers are assumed to be 2's complement.
   Note the suppression of inappropriate sign-extensions using judicious
   unsigned reads. */

#define fwri_int1(F,V) fwri_ch((F),_Fioi.i1=(V))
#define frdi_int1(F) (toint1(frdi_ch((F))))

#define fwri_int2(F,V) { fwri_int1((F),_Fioi.i2=(V)); \
			fwri_int1((F),_Fioi.i2>>8); }
#define frdi_int2(F) ((int2)( _Fioi.i2=frdi_uint1((F)), \
			(frdi_int1((F))<<8)|_Fioi.i2 ))

#define fwri_int3(F,V) { fwri_int2((F),_Fioi.i3=(V)); \
			fwri_int1((F),_Fioi.i3>>16); }
#define frdi_int3(F) ((int3)( _Fioi.i3=frdi_uint2((F)), \
			(frdi_int1((F))<<16)|_Fioi.i3 ))

#define fwri_int4(F,V) { fwri_int2((F),_Fioi.i4=(V)); \
			fwri_int2((F),_Fioi.i4>>16); }
#define frdi_int4(F) ((int4)( _Fioi.i4=frdi_uint2((F)), \
			(frdi_int2((F))<<16)|_Fioi.i4 ))

#define fwri_int8(F,V) { fwri_int4((F),_Fioi.i8=(V)); \
			fwri_int4((F),_Fioi.i8>>32); }
#define frdi_int8(F) ((int8)( _Fioi.i8=frdi_uint4((F)), \
			(frdi_int4((F))<<32)|_Fioi.i8 ))


/* Floating point */
#if MAIN
/* See Marsha Grabow & George Gilmer & KT */
void
dtoieeed(ieee,native)
    Ieeed *ieee;
    double native;
{
	double fr, ho, f;
	int iexp;

	if(native < 0) {
		dtoieeed(ieee, -native);
		ieee->h |= 0x80000000L;
		return;
	}
	if(native == 0) {
		ieee->l = 0;
		ieee->h = 0;
		return;
	}
	fr = frexp(native, &iexp);
	f = 2097152L;		/* shouldnt use fp constants here */
	fr = modf(fr*f, &ho);
	ieee->h = ho;
	ieee->h &= 0xfffffL;
	ieee->h |= (iexp+1022L) << 20;
	f = 65536L;
	fr = modf(fr*f, &ho);
	ieee->l = ho;
	ieee->l <<= 16;
	ieee->l |= (long)(fr*f);
}
#else
void dtoieeed();
#endif
0707070035350321111006640007620000050000010263500476773367100000700000002300font.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* font.h - typedefs, etc for font-characteristic functions:
   The baseline is defined by the locus of bottoms of all characters that
   have no descenders and are not punctuation.
   The top is the top of characters without risers (negative).
   The `rise' is the (negative) height of risers (above baseline), and `descent'
   is the positive) distance below baseline.
    */

/* font attributes, in absolute scanner coordinates */
typedef struct FontAttr {
	Scoor body;		/* point size */
	Scoor xhgt;		/* x-height */
	Scoor ascd;		/* height of ascenders (above xheight, >0) */
	Scoor caph;		/* capital height (above baseline, >0) */
	Scoor desc;		/* height of descenders (below baseline, >0) */
	Scoor doth;		/* height of punctuation dots */
	} FontAttr;

#ifdef MAIN
FontAttr *ps_to_attr();	/* pointsize, digit'n resol'n --> attributes */
xhgt_to_ps();
caph_to_ps();
#endif
0707070035350320471006640007620000050000010263510476773367200000700000124016jslr.c/* AT&T PROPRIETARY:  Developed at AT&T Expense        */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* rlbr - run-length encode a binary raster line
  `rasp' is a raster line of bits.  rasp[0] is the leftmost byte in the line and
   the 001 bit is the leftmost bit in each byte ("little-endian").
   Analyzes the line into a series of runs of `1's, placing them into array
   `runs'.  Observes margins:  starts at `lm' bit and continues through `rm'; bits
   outside margins are assumed 0.   A `run' is two shorts (the starting &
   ending indices of the run of `1's, inclusive).  The indices are shifted
   so that the index of `lm' becomes `olm'.  Returns the number of runs.
   NOTES:
	The contents of the raster-line are restored to their orginal
   state on return. The user must ensure that:
	(1) margins fall within `rasp';
   	(2) `rasp' has one extra byte at the end for use by this routine; and
   	(3) `runs' is big enough to hold the worst-case no. of runs that could
	     result, which is (rm-lm)/2+1.
   */

int rlbr(rasp,lm,rm,olm,runp)
	char unsigned rasp[];	/* binary raster line (with 1 extra byte at end) */
	int lm,rm;	/* left,right margin bit indices within raster */
	int olm;	/* on output, `lm' index has become `olm' */
	short runp[];	/* array of run-segments [xs,xe] (pairs of short) */
{	register char unsigned *bp,*ep;	/* byte pointers into raster line */
	register short cb;	/* x_coordinate of 1st bit of current byte */
	register short *xp;	/* ptr to x-coordinate in run-length array */
	register short prior;	/* prior bit, coded 0400 or 0000 */

	char unsigned *lbp,*rbp;	/* ptrs to margin bytes */
	int lo,ro;			/* `offset' of margin bits in bytes */
	char unsigned svlb,svrb,svrrb;	/* unmodified copies of margin bytes */
	
	if(lm>rm) return(0);
	/* compute margins' bytes, save copies, set bits outside margins to 0 */
	lbp=rasp+(lm/8);  svlb= *lbp;
	/* force bits left of lm to 0 */
	lo=lm%8;  if(lo>0) *lbp &= (0377<<lo);
	rbp=rasp+(rm/8); svrb= *rbp;
	/* force bits right of rm to 0 */
	ro=rm%8;  if(ro<7) *rbp &= (0377>>(7-ro));
	/* place a 0000 byte to right of margin byte, to force good termination */
	svrrb= *(rbp+1);  *(rbp+1)='\0';

	/* MAIN LOOP */
	prior=0000;	/* act as if there's a 0 byte to left of margin byte */
	xp=runp;
	bp=lbp;
	ep=rbp+2;
	cb=(-lo+olm);
	do {	switch( prior | *(bp++) ) {
			/* contents of rlbr.c1 come below here */
case 00: break;
case 01: *(xp++)=cb; *(xp++)=cb; break;
case 02: *(xp++)=cb+1; *(xp++)=cb+1; break;
case 03: *(xp++)=cb; *(xp++)=cb+1; break;
case 04: *(xp++)=cb+2; *(xp++)=cb+2; break;
case 05: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; break;
case 06: *(xp++)=cb+1; *(xp++)=cb+2; break;
case 07: *(xp++)=cb; *(xp++)=cb+2; break;
case 010: *(xp++)=cb+3; *(xp++)=cb+3; break;
case 011: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; break;
case 012: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; break;
case 013: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; break;
case 014: *(xp++)=cb+2; *(xp++)=cb+3; break;
case 015: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; break;
case 016: *(xp++)=cb+1; *(xp++)=cb+3; break;
case 017: *(xp++)=cb; *(xp++)=cb+3; break;
case 020: *(xp++)=cb+4; *(xp++)=cb+4; break;
case 021: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; break;
case 022: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; break;
case 023: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; break;
case 024: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; break;
case 025: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; break;
case 026: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; break;
case 027: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; break;
case 030: *(xp++)=cb+3; *(xp++)=cb+4; break;
case 031: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; break;
case 032: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; break;
case 033: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; break;
case 034: *(xp++)=cb+2; *(xp++)=cb+4; break;
case 035: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; break;
case 036: *(xp++)=cb+1; *(xp++)=cb+4; break;
case 037: *(xp++)=cb; *(xp++)=cb+4; break;
case 040: *(xp++)=cb+5; *(xp++)=cb+5; break;
case 041: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 042: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 043: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 044: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 045: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 046: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 047: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 050: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 051: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 052: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 053: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 054: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 055: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 056: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 057: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; break;
case 060: *(xp++)=cb+4; *(xp++)=cb+5; break;
case 061: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+5; break;
case 062: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; break;
case 063: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; break;
case 064: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; break;
case 065: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; break;
case 066: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; break;
case 067: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; break;
case 070: *(xp++)=cb+3; *(xp++)=cb+5; break;
case 071: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 072: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 073: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 074: *(xp++)=cb+2; *(xp++)=cb+5; break;
case 075: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; break;
case 076: *(xp++)=cb+1; *(xp++)=cb+5; break;
case 077: *(xp++)=cb; *(xp++)=cb+5; break;
case 0100: *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0101: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0102: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0103: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0104: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0105: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0106: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0107: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0110: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0111: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0112: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0113: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0114: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0115: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0116: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0117: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0120: *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0121: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0122: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0123: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0124: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0125: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0126: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0127: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0130: *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0131: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0132: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0133: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0134: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0135: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0136: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0137: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; break;
case 0140: *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0141: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0142: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0143: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0144: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0145: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0146: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0147: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0150: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0151: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0152: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0153: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0154: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0155: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0156: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0157: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; break;
case 0160: *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0161: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0162: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0163: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0164: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0165: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0166: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0167: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0170: *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0171: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0172: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0173: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0174: *(xp++)=cb+2; *(xp++)=cb+6; break;
case 0175: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+6; break;
case 0176: *(xp++)=cb+1; *(xp++)=cb+6; break;
case 0177: *(xp++)=cb; *(xp++)=cb+6; break;
case 0200: *(xp++)=cb+7; prior=0400; break;
case 0201: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+7; prior=0400; break;
case 0202: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+7; prior=0400; break;
case 0203: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+7; prior=0400; break;
case 0204: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+7; prior=0400; break;
case 0205: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+7; prior=0400; break;
case 0206: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+7; prior=0400; break;
case 0207: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+7; prior=0400; break;
case 0210: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break;
case 0211: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break;
case 0212: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break;
case 0213: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break;
case 0214: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break;
case 0215: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break;
case 0216: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break;
case 0217: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+7; prior=0400; break;
case 0220: *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0221: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0222: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0223: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0224: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0225: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0226: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0227: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0230: *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0231: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0232: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0233: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0234: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0235: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0236: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0237: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+7; prior=0400; break;
case 0240: *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0241: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0242: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0243: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0244: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0245: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0246: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0247: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0250: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0251: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0252: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0253: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0254: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0255: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0256: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0257: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0260: *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0261: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0262: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0263: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0264: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0265: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0266: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0267: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0270: *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0271: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0272: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0273: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0274: *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0275: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0276: *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0277: *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+7; prior=0400; break;
case 0300: *(xp++)=cb+6; prior=0400; break;
case 0301: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+6; prior=0400; break;
case 0302: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+6; prior=0400; break;
case 0303: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+6; prior=0400; break;
case 0304: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; prior=0400; break;
case 0305: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; prior=0400; break;
case 0306: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+6; prior=0400; break;
case 0307: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+6; prior=0400; break;
case 0310: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break;
case 0311: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break;
case 0312: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break;
case 0313: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break;
case 0314: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break;
case 0315: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break;
case 0316: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break;
case 0317: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+6; prior=0400; break;
case 0320: *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0321: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0322: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0323: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0324: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0325: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0326: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0327: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0330: *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0331: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0332: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0333: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0334: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0335: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0336: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0337: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+6; prior=0400; break;
case 0340: *(xp++)=cb+5; prior=0400; break;
case 0341: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+5; prior=0400; break;
case 0342: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; prior=0400; break;
case 0343: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+5; prior=0400; break;
case 0344: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; prior=0400; break;
case 0345: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; prior=0400; break;
case 0346: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; prior=0400; break;
case 0347: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; prior=0400; break;
case 0350: *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break;
case 0351: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break;
case 0352: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break;
case 0353: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break;
case 0354: *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break;
case 0355: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break;
case 0356: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break;
case 0357: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; prior=0400; break;
case 0360: *(xp++)=cb+4; prior=0400; break;
case 0361: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+4; prior=0400; break;
case 0362: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; prior=0400; break;
case 0363: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+4; prior=0400; break;
case 0364: *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; prior=0400; break;
case 0365: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; prior=0400; break;
case 0366: *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; prior=0400; break;
case 0367: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; prior=0400; break;
case 0370: *(xp++)=cb+3; prior=0400; break;
case 0371: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+3; prior=0400; break;
case 0372: *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; prior=0400; break;
case 0373: *(xp++)=cb; *(xp++)=cb+1; *(xp++)=cb+3; prior=0400; break;
case 0374: *(xp++)=cb+2; prior=0400; break;
case 0375: *(xp++)=cb; *(xp++)=cb; *(xp++)=cb+2; prior=0400; break;
case 0376: *(xp++)=cb+1; prior=0400; break;
case 0377: *(xp++)=cb; prior=0400; break;

case 0400: *(xp++)=cb-1; prior=0000; break;
case 0401: *(xp++)=cb; prior=0000; break;
case 0402: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; prior=0000; break;
case 0403: *(xp++)=cb+1; prior=0000; break;
case 0404: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; prior=0000; break;
case 0405: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; prior=0000; break;
case 0406: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; prior=0000; break;
case 0407: *(xp++)=cb+2; prior=0000; break;
case 0410: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; prior=0000; break;
case 0411: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; prior=0000; break;
case 0412: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; prior=0000; break;
case 0413: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; prior=0000; break;
case 0414: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; prior=0000; break;
case 0415: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; prior=0000; break;
case 0416: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; prior=0000; break;
case 0417: *(xp++)=cb+3; prior=0000; break;
case 0420: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break;
case 0421: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break;
case 0422: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break;
case 0423: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break;
case 0424: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break;
case 0425: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break;
case 0426: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break;
case 0427: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; prior=0000; break;
case 0430: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+4; prior=0000; break;
case 0431: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; prior=0000; break;
case 0432: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; prior=0000; break;
case 0433: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; prior=0000; break;
case 0434: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+4; prior=0000; break;
case 0435: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; prior=0000; break;
case 0436: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+4; prior=0000; break;
case 0437: *(xp++)=cb+4; prior=0000; break;
case 0440: *(xp++)=cb-1; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0441: *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0442: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0443: *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0444: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0445: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0446: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0447: *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0450: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0451: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0452: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0453: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0454: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0455: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0456: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0457: *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; prior=0000; break;
case 0460: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break;
case 0461: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break;
case 0462: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break;
case 0463: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break;
case 0464: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break;
case 0465: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break;
case 0466: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break;
case 0467: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; prior=0000; break;
case 0470: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+5; prior=0000; break;
case 0471: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; prior=0000; break;
case 0472: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; prior=0000; break;
case 0473: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; prior=0000; break;
case 0474: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+5; prior=0000; break;
case 0475: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; prior=0000; break;
case 0476: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+5; prior=0000; break;
case 0477: *(xp++)=cb+5; prior=0000; break;
case 0500: *(xp++)=cb-1; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0501: *(xp++)=cb; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0502: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0503: *(xp++)=cb+1; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0504: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0505: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0506: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0507: *(xp++)=cb+2; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0510: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0511: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0512: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0513: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0514: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0515: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0516: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0517: *(xp++)=cb+3; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0520: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0521: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0522: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0523: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0524: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0525: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0526: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0527: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0530: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0531: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0532: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0533: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0534: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0535: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0536: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0537: *(xp++)=cb+4; *(xp++)=cb+6; *(xp++)=cb+6; prior=0000; break;
case 0540: *(xp++)=cb-1; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0541: *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0542: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0543: *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0544: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0545: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0546: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0547: *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0550: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0551: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0552: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0553: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0554: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0555: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0556: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0557: *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+6; prior=0000; break;
case 0560: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break;
case 0561: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break;
case 0562: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break;
case 0563: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break;
case 0564: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break;
case 0565: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break;
case 0566: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break;
case 0567: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; prior=0000; break;
case 0570: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+6; prior=0000; break;
case 0571: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+6; prior=0000; break;
case 0572: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; prior=0000; break;
case 0573: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; prior=0000; break;
case 0574: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+6; prior=0000; break;
case 0575: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+6; prior=0000; break;
case 0576: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+6; prior=0000; break;
case 0577: *(xp++)=cb+6; prior=0000; break;
case 0600: *(xp++)=cb-1; *(xp++)=cb+7; break;
case 0601: *(xp++)=cb; *(xp++)=cb+7; break;
case 0602: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+7; break;
case 0603: *(xp++)=cb+1; *(xp++)=cb+7; break;
case 0604: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+7; break;
case 0605: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+7; break;
case 0606: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+7; break;
case 0607: *(xp++)=cb+2; *(xp++)=cb+7; break;
case 0610: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; break;
case 0611: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; break;
case 0612: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; break;
case 0613: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+7; break;
case 0614: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+7; break;
case 0615: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+7; break;
case 0616: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+7; break;
case 0617: *(xp++)=cb+3; *(xp++)=cb+7; break;
case 0620: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0621: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0622: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0623: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0624: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0625: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0626: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0627: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0630: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0631: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0632: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0633: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0634: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0635: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0636: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0637: *(xp++)=cb+4; *(xp++)=cb+7; break;
case 0640: *(xp++)=cb-1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0641: *(xp++)=cb; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0642: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0643: *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0644: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0645: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0646: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0647: *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0650: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0651: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0652: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0653: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0654: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0655: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0656: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0657: *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0660: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0661: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0662: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0663: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0664: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0665: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0666: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0667: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0670: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0671: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0672: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0673: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0674: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0675: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0676: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0677: *(xp++)=cb+5; *(xp++)=cb+7; break;
case 0700: *(xp++)=cb-1; *(xp++)=cb+6; break;
case 0701: *(xp++)=cb; *(xp++)=cb+6; break;
case 0702: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+6; break;
case 0703: *(xp++)=cb+1; *(xp++)=cb+6; break;
case 0704: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; break;
case 0705: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+6; break;
case 0706: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+6; break;
case 0707: *(xp++)=cb+2; *(xp++)=cb+6; break;
case 0710: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0711: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0712: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0713: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0714: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0715: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0716: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0717: *(xp++)=cb+3; *(xp++)=cb+6; break;
case 0720: *(xp++)=cb-1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0721: *(xp++)=cb; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0722: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0723: *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0724: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0725: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0726: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0727: *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0730: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0731: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0732: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0733: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0734: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0735: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0736: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0737: *(xp++)=cb+4; *(xp++)=cb+6; break;
case 0740: *(xp++)=cb-1; *(xp++)=cb+5; break;
case 0741: *(xp++)=cb; *(xp++)=cb+5; break;
case 0742: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+5; break;
case 0743: *(xp++)=cb+1; *(xp++)=cb+5; break;
case 0744: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; break;
case 0745: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+5; break;
case 0746: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+5; break;
case 0747: *(xp++)=cb+2; *(xp++)=cb+5; break;
case 0750: *(xp++)=cb-1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 0751: *(xp++)=cb; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 0752: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 0753: *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 0754: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 0755: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 0756: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+3; *(xp++)=cb+5; break;
case 0757: *(xp++)=cb+3; *(xp++)=cb+5; break;
case 0760: *(xp++)=cb-1; *(xp++)=cb+4; break;
case 0761: *(xp++)=cb; *(xp++)=cb+4; break;
case 0762: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+4; break;
case 0763: *(xp++)=cb+1; *(xp++)=cb+4; break;
case 0764: *(xp++)=cb-1; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; break;
case 0765: *(xp++)=cb; *(xp++)=cb+2; *(xp++)=cb+2; *(xp++)=cb+4; break;
case 0766: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+2; *(xp++)=cb+4; break;
case 0767: *(xp++)=cb+2; *(xp++)=cb+4; break;
case 0770: *(xp++)=cb-1; *(xp++)=cb+3; break;
case 0771: *(xp++)=cb; *(xp++)=cb+3; break;
case 0772: *(xp++)=cb-1; *(xp++)=cb+1; *(xp++)=cb+1; *(xp++)=cb+3; break;
case 0773: *(xp++)=cb+1; *(xp++)=cb+3; break;
case 0774: *(xp++)=cb-1; *(xp++)=cb+2; break;
case 0775: *(xp++)=cb; *(xp++)=cb+2; break;
case 0776: *(xp++)=cb-1; *(xp++)=cb+1; break;
case 0777: break;

			/* contents of jslr.c1 come above here */
			};
		cb += 8;
		}
	while(bp<ep);
	/* restore margin bytes */
	*lbp = svlb;
	*rbp = svrb;
	*(rbp+1) = svrrb;
	return((xp-runp)/2);
	};
0707070035350320511006640007620000050000010263540476773367200001100000001652limits.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* Extreme values of integral types (conforms to Oct 1, 86 draft ANSI C std) */
#define CHAR_BIT 8
#define SCHAR_MIN -128
#define SCHAR_MAX 127
#define UCHAR_MIN 0
#define UCHAR_MAX 255
#define CHAR_MIN SCHAR_MIN	/* type char sign-extends */
#define CHAR_MAX SCHAR_MAX	/* type char sign-extends */

#define SHRT_MIN -32768
#define SHRT_MAX 32767
#define USHRT_MIN 0
#define USHRT_MAX 65535

#define INT_MIN -2147483648
#define INT_MAX 2147483647
#define UINT_MIN 0
#define UINT_MAX 4294967295

#define LONG_MIN -2147483648
#define LONG_MAX 2147483647
#define ULONG_MIN 0
#define ULONG_MAX 4294967295
0707070035351106241006640007620000050000010263560476773367300001000000025436myftw.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/*
 *	ftw - file tree walk
 *
 *	int ftw (path, fn, depth)  char *path; int (*fn)(); int depth;
 *
 *	Given a path name, ftw starts from the file given by that path
 *	name and visits each file and directory in the tree beneath
 *	that file.  If a single file has multiple links within the
 *	structure, it will be visited once for each such link.
 *	For each object visited, fn is called with four arguments.
 *	The fourth can often be ignored; it is a pointer, say S,
 *	declared "struct FTW *S", discussed in more detail below.
 *	The first contains the path name of the object, the second
 *	contains a pointer to a stat buffer which will usually hold
 *	appropriate information for the object and the third contains
 *	an integer value giving additional information about the
 *	object, as follows:
 *
 *		FTW_F	The object is a file for which stat was
 *			successful.  It does not guarantee that the
 *			file can actually be read.
 *
 *		FTW_D	The object is a directory for which stat and
 *			open for read were both successful.  This is
 *			a preorder visit -- objects in the directory
 *			are yet to be visited.
 *
 *		FTW_DNR	The object is a directory for which stat
 *			succeeded, but which cannot be read.  Because
 *			the directory cannot be read, fn will not be
 *			called for any descendants of this directory.
 *
 *		FTW_DP	The object is a directory for which stat and
 *			open for read were both successful.  This is
 *			a postorder visit -- everything in the directory
 *			has already been visited.
 *
 *		FTW_NS	Lstat failed on the object.  If errno is EACCES,
 *			then the failure stems from lack of
 *			appropriate permission.  This indication will
 *			be given, for example, for each file in a directory
 *			with read but no execute permission.  Whenever
 *			stat fails, it is not possible to determine
 *			whether this object is a file or a directory.
 *			The stat buffer passed to fn will contain garbage.
 *
 *		FTW_SL  The object is a symbolic link.  Set S->quit
 *			(a component of the structure pointed to by
 *			the fourth parameter to fn) to FTW_FOLLOW to
 *			have the link followed and the object to which
 *			it points visited.
 *
 *		FTW_NSL Lstat succeeded, but stat failed on the object.
 *			This is only possible when following a symbolic
 *			link.
 *
 *	Among the components of the structure to which the fourth
 *	parameter, S, to fn points is S->quit.  If the caller sets
 *	S->quit to FTW_SKR, then no more files in the current directory
 *	will be visited.  (The current directory is the one containing
 *	the object being visited.)  If the third parameter to fn is
 *	FTW_D and the caller sets S->quit to FTW_SKD, then this directory
 *	(the one named in the first parameter to fn) will be skipped.
 *
 *	Other components pointed to by the fourth parameter S are
 *	the current recursion level S->level (top level = 0) and
 *	the offset S->base in the pathname of the current object
 *	(the first parameter to fn) of the object's base name.
 *	By expanding the definition of struct FTW given below and
 *	including the files included below, one can arrange for
 *	S to point to a larger structure, components of which can
 *	be initialized (for example) on calls to fn with third
 *	parameter FTW_D.
 *
 *	If fn returns nonzero, ftw stops and returns the same value
 *	to its caller.  Ftw only initiates a nonzero return if malloc
 *	fails; in this case ftw sets errno to ENOMEM and returns -1.
 *
 *	The third argument to ftw does not limit the depth to which
 *	ftw will go.  Rather, it limits the depth to which ftw will
 *	go before it starts recycling file descriptors.  In general,
 *	it is necessary to use a file descriptor for each level of the
 *	tree, but they can be recycled for deep trees by saving the position,
 *	closing, re-opening, and seeking.  It is possible to start
 *	recycling file descriptors by sensing when we have run out, but
 *	in general this will not be terribly useful if fn expects to be
 *	able to open files.  We could also figure out how many file descriptors
 *	are available and guarantee a certain number to fn, but we would not
 *	know how many to guarantee, and we do not want to impose the extra
 *	overhead on a caller who knows how many are available without
 *	having to figure it out.
 *
 *	It is possible for ftw to die with a memory fault in the event
 *	of a file system so deeply nested that the stack overflows.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include "myftw.h"	/* not <ftw.h>, for portability to Suns */
/*
 * Struct FTW (whose definition starts at the end of ftw.h) must
 * must include at least the integers quit, base, and level.
 */

#define FTW_PATHLEN0 1000
#define FTW_PATHINC 1000
#ifndef S_IFLNK
#define lstat stat
#endif
#ifdef S_IFSOCK
#include <sys/dir.h>
#else
#include "ndir.h"
#endif
#ifndef ENOMEM
#include <errno.h>
#endif

	extern int errno;

/*
 *  Each generation of ftw1 (the real ftw) allocates one copy, R, of the
 *  following structure; it passes a pointer to this structure when it
 *  recursively invokes itself.  These structures are chained together,
 *  so that if it becomes necessary to recycle file descriptors, then
 *  the oldest descriptor (the one at the shallowest depth still open)
 *  can be recycled.
 */

	struct FTW_rec {
		struct FTW_rec *prev;
		long here;	/* seek to here when reopening at this level */
		DIR *fd;	/* file descriptor at this level */
		};

/*
 *  One instance, T, of the following structure is allocated by ftw; a
 *  pointer to it is passed to all generations of ftw1 (the real ftw).
 *  T could often be a global variable, but this way the parameter fn
 *  can invoke ftw for an independent tree walk.
 *  Component T->path points to storage for the object path-names;
 *  this storage may be relocated by realloc if T->path needs to be
 *  more than T->pathlast characters long.
 *  T->path[T->pathnext] is the next free character in the pathnames.
 *  T->depth = parameter depth to ftw.  T->lastout is the deepest level at
 *  which a file descriptor has been recycled.
 */

	struct FTW_top {
		int (*fn)();
		char *path;
		unsigned pathlast, pathnext;
		int lastout;
		int depth;
		};

static ftw_1_();

int
ftw (path, fn, depth)
	char *path;
	int (*fn)();
	int depth;
{
	struct FTW_top T;
	struct FTW_rec R;
	struct FTW S;
	int rc;
	char *malloc(), *strcpy();

	T.depth = depth;
	T.lastout = -1;
	T.fn = fn;
	S.quit = 0;
	S.level = -1;

	/* initialize S.base, T.pathnext... */
		{
		register char c, *p, *q;
		for (p = q = path; c = *p; p++) if (c == '/') q = p + 1;
		S.base = q - path;
		T.pathnext = p - path;
		}

	T.pathlast = T.pathnext + FTW_PATHLEN0;
	T.path = malloc(T.pathlast);
	if (!T.path) { errno = ENOMEM; return -1; }
	strcpy(T.path, path);
	rc = ftw_1_(&R, &T, 0, &S);
	free(T.path);
	return rc;
}

int
static
ftw_1_ (R, T, level, S1)
	register struct FTW_rec *R;
	register struct FTW_top *T;
	int level;
	struct FTW *S1;
{
	int rc, n;
	DIR *fd;
	struct direct *dirp;
	char *component, *path;
	struct stat sb;
	struct FTW_rec mr;
	unsigned nextsave;
	struct FTW S;
	char *realloc();
	long lseek();

	mr.prev = R;
	path = T->path;
	S.level = level;
	S.quit = 0;
	S.base = S1->base;

	/* Try to get file status.  If unsuccessful, errno will say why. */
	if (lstat(path, &sb) < 0) {
		rc = (*T->fn) (path, &sb, FTW_NS, &S);
		S1->quit = S.quit;
		return rc;
		};

	/*
	 *	The stat succeeded, so we know the object exists.
	 *	If not a directory, call the user function and return.
	 */
#ifdef S_IFLNK
	if ((sb.st_mode & S_IFMT) == S_IFLNK) {
		rc = (*T->fn) (path, &sb, FTW_SL, &S);
		S1->quit = S.quit;
		if (rc || S.quit == FTW_SKR) return rc;
		if (S.quit != FTW_FOLLOW) return 0;
		S1->quit = S.quit = 0;
		if (stat(path, &sb) < 0) {
			rc = (*T->fn) (path, &sb, FTW_NSL, &S);
			S1->quit = S.quit;
			return rc;
			};
		}
#endif
		
	if ((sb.st_mode & S_IFMT) != S_IFDIR) {
		rc = (*T->fn) (path, &sb, FTW_F, &S);
		S1->quit = S.quit;
		return rc;
		}

	/*
	 *	The object was a directory.
	 *
	 *	Open a file to read the directory
	 */
	mr.fd = fd = opendir(path);

	/*
	 *	Call the user function, telling it whether
	 *	the directory can be read.  If it can't be read
	 *	call the user function or indicate an error,
	 *	depending on the reason it couldn't be read.
	 */
	if (!fd) {
		rc = (*T->fn) (path, &sb, FTW_DNR, &S);
		S1->quit = S.quit;
		return rc;
		}

	/* We could read the directory.  Call user function. */
	rc = (*T->fn) (path, &sb, FTW_D, &S);
	if (rc != 0)
		goto rtrn;
	if (S.quit == FTW_SKD) goto rtrn;
	if (S.quit == FTW_SKR) {S1->quit = FTW_SKR; goto rtrn;}

	/* Make sure path is big enough to hold generated pathnames. */

	n = nextsave = T->pathnext;
	if (n + MAXNAMLEN + 1 >= T->pathlast) {
		T->pathlast += FTW_PATHINC;
		path = T->path = realloc(T->path, T->pathlast);
		if (!path) {
			errno = ENOMEM;
			rc = -1;
			goto rtrn;
			}
		}
	
	/* Create a prefix to which we will append component names */

	if (n > 0 && path[n-1] != '/') path[n++] = '/';
	component = path + n;

	/*
	 *	Read the directory one component at a time.
	 *	We must ignore "." and "..", but other than that,
	 *	just create a path name and call self to check it out.
	 */
	while (dirp = readdir(fd)) {
		if (dirp->d_ino != 0
		    && strcmp (dirp->d_name, ".") != 0
		    && strcmp (dirp->d_name, "..") != 0) {
			int i;
			struct FTW_rec *pr;

			/* Append the component name to the working path */
			strcpy(component, dirp->d_name);
			T->pathnext = n + strlen(dirp->d_name);

			/*
			 *	If we are about to exceed our depth,
			 *	remember where we are and close the file.
			 */
			if (level - T->lastout >= T->depth) {
				pr = &mr;
				i = T->lastout++;
				while (++i < level) pr = pr->prev;
				pr->here = telldir(pr->fd);
				closedir(pr->fd);
			}

			/*
			 *	Do a recursive call to process the file.
			 */
			S.quit = 0;
			S.base = n;
			rc = ftw_1_(&mr, T, level+1, &S);
			if (rc != 0 || S.quit == FTW_SKR) {
				if (level > T->lastout) closedir(fd);
				T->pathnext = nextsave;
				return rc;
			}

			/*
			 *	If we closed the file, try to reopen it.
			 */
			if (level <= T->lastout) {
				char c = path[nextsave];
				path[nextsave] = 0;
				T->lastout = level - 1;
				mr.fd = fd = opendir(path);
				if (!fd) {
					rc = (*T->fn) (path, &sb, FTW_DNR, &S);
					S1->quit = S.quit;
					T->pathnext = nextsave;
					return rc;
					}
				path[nextsave] = c;
				seekdir(fd, mr.here);
				}
			}
		}
	T->pathnext = nextsave;
	path[nextsave] = 0;

	/*
	 *	We got out of the subdirectory loop.  Call the user
	 *	function again at the end and clean up.
	 */

	rc = (*T->fn) (path, &sb, FTW_DP, &S);
	S1->quit = S.quit;
rtrn:
	closedir(fd);
	return rc;
}
0707070035350320551006640007620000050000010263640476773367300001000000002137myftw.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/*
 *	Codes for the third argument to the user-supplied function
 *	which is passed as the second argument to ftw...
 */

#define	FTW_F	0	/* file */
#define	FTW_D	1	/* directory */
#define	FTW_DNR	2	/* directory without read permission */
#define	FTW_NS	3	/* unknown type, stat failed */
#define FTW_DP	4	/* directory, postorder visit */
#define FTW_SL	5	/* symbolic link */
#define FTW_NSL 6	/* stat failed (errno = ENOENT) on symbolic link */

/*	Values the user-supplied function may wish to assign to
	component quit of struct FTW...
 */

#define FTW_SKD 1	/* skip this directory (2nd par = FTW_D) */
#define FTW_SKR 2	/* skip rest of current directory */
#define FTW_FOLLOW 3	/* follow symbolic link */

struct FTW { int quit, base, level;
#ifndef FTW_more_to_come
	};
#endif
0707070035350320571006640007620000050000010263660476773367300000600000003730pic.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* pic.h -  picture files.  See man page for picfile(5).
   They have an ascii header, terminated by \n\n; see PIC_hdr for its data fields.
   The rest is binary scanner data. Each `PIC_hdr.bpl' bytes holds one scan-line's
   pixels, 1 bit/pixel.  A `1' bit means black.  The order of the bytes in a line
   is left-to-right across the page.  The low-order bit in a byte is the left-most.
   Conventionally, X-coordinates start at 0, at the left of the page, and
   increase to the right.  Y-coordinates start at 0 at the top of the page,
   and increase down.
   NOTE:  must be preceded by #include "Coord.h"
   */

typedef struct PIC_hdr {
	/* Contents of picfile ASCII header (or other structure) */
	char type[40];		/* "rle" "dump" "binary" "ccitt-g4" "imdir" etc */
	Bbx bx;			/* WINDOW (bounding box) */
	short res_x;		/* resolution in pixels/inch (x,y may differ) */
	short res_y;
	char *parms;		/* PARMS= string */
	char *misc;		/* all other unexpected header lines, catenated */
	/* the following are used by I/O routines */
	FILE *fp;
	long seek;		/* current seek address */
	int bpl;		/* bytes per line (in file) */
	unsigned char *line;	/* one line of picture (malloc space) */
	unsigned char *pline;	/* prior line of picture (malloc space) */
	Scoor cy;		/* index no. of *line */
	} PIC_hdr;
#define Init_PIC_hdr {"",Init_Bbx,0,0,NULL,NULL,NULL,0L,0,NULL,NULL,0}
#if MAIN
    PIC_hdr empty_PIC_hdr = Init_PIC_hdr;
#else
    extern PIC_hdr empty_PIC_hdr;
#endif

/* these functions are in /usr/hsb/ocr/piclib.c */
PIC_hdr *alloc_PIC_hdr();
int PIC_get_hdr();
PIC_put_hdr();
err_PIC_line();
PIC_skip();
int PIC_rline();
int PIC_wline();
char *PIC_hdr_toa();
0707070035350320561006640007620000050000010263700476773367300001100000044413piclib.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* piclib.c - picture-file public functions.
   alloc_PIC_hdr()	- allocate initialized PIC_hdr, associate with FILE *
   free_PIC_hdr()	- free PIC_hdr & all malloc'ed fields
   PIC_get_hdr()	- get picture-file header
   PIC_rline()		- read one line of picture data
   PIC_put_hdr()	- get picture-file header
   PIC_wline()		- write one line of picture data
   err_PIC_Line()	- print line on stderr
   PIC_hdr_toa()	- PIC_hdr to ascii printable string
   (PIC_* functions use system I/O, for speed)
   */

#include <stdio.h>
#include <math.h>
#include <string.h>
#include "boole.h"
#include "limits.h"	/* numeric extreme values */
#include "Units.h"
#include "Coord.h"
#include "pic.h"

#define PIC_debug (0)
double atof();

PIC_hdr *alloc_PIC_hdr( fp )
    FILE *fp;	/* already-open file descr */
{   PIC_hdr *h;
	if((h=(PIC_hdr *)malloc(sizeof(PIC_hdr)))==NULL)
		abort("piclib: alloc_PIC_hdr: can't alloc");
	*h = empty_PIC_hdr;
	h->fp = fp;
	return(h);
	}

free_PIC_hdr( h )
    PIC_hdr *h;
{	if(h->parms!=NULL) free(h->parms);
	if(h->line!=NULL) free(h->line);
	if(h->pline!=NULL) free(h->pline);
	if(h->misc!=NULL) free(h->misc);
	free(h);
	}

/* system I/O variation on fgets(3), except it replaces \n with \0,
   and returns the number of chars read (including \0) */
int PIC_fgets(bf,max,fd)
	char *bf;
	int max;
	int fd;
{   char *cp;
    int stat,mny;
	cp=bf; mny=0;
	while(((stat=read(fd,cp,1))==1)&&(++mny<max)&&((*cp)!='\n')) cp++;
	if(stat!=1) return(stat);
	else if(mny>=max) return(-1);
	*cp='\0';
	return(mny);
	}

/* Read picture file header from file descr fileno(h->fp), set up the rest of the
   header, and return status:  1 OK, 0 EOF, <0 error */
int PIC_get_hdr( h )
    PIC_hdr *h;
#define HL_MAX 300
#define HTERM "=, 	\n"	/* terminations for header words: "=,<sp><tab>" */
{   char *cp,*parm,hline[HL_MAX],oline[HL_MAX],*hl;
    int status,nrd,ch,mny;
	/* synchronize FILE * ptr with file descr ptr */
	fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0);
	hline[0]='\0';
	if((mny=read(fileno(h->fp),hline,5))!=5)
		return(0);
	if(!(hline[0]=='T' && hline[1]=='Y' && hline[2]=='P'
		&& hline[3]=='E' && hline[4]=='=')) {
		/* no "TYPE=" header; don't accept */
		if(0) /* don't accept */ {
			if(PIC_debug)
				err("PIC_get_hdr: can't find TYPE=... header");
			return(-1);
			}
		else /* accept as bitfile format (OBSOLESCENT) */ {
			strcpy(h->type,"bitfile");
			h->res_x = h->res_y = 0;
			fseek(h->fp,h->seek+2L,0);	/* back up to byte no. 2 */
			/* read window */
			if((ch=getc(h->fp))!=EOF) { h->bx.a.x = ch;
			 if((ch=getc(h->fp))!=EOF) { h->bx.a.x += (ch<<8);
			  if((ch=getc(h->fp))!=EOF) { h->bx.a.y = ch;
			   if((ch=getc(h->fp))!=EOF) { h->bx.a.y += (ch<<8);
			    if((ch=getc(h->fp))!=EOF) { h->bx.b.x = ch;
			     if((ch=getc(h->fp))!=EOF) { h->bx.b.x += (ch<<8);
			      if((ch=getc(h->fp))!=EOF) { h->bx.b.y = ch;
			       if((ch=getc(h->fp))!=EOF) { h->bx.b.y += (ch<<8); }}}}}}}}
			else return(0/*EOF*/);
			h->bx.b.x--;  h->bx.b.y--;
			/* synchronize file descr ptr with FILE * ptr */
			lseek(fileno(h->fp),h->seek = ftell(h->fp),0);
			};
		}
	else {
	    if((status=PIC_fgets(hline+5,HL_MAX-5,fileno(h->fp)))<=0)
		return(status);
	    strcpy(oline,hline);
	    hl=hline;  while(*hl==' ') hl++;  /* strip initial blanks */
	    while(strlen(hl)>1) {
		if(PIC_debug) err("PIC_get_hdr:  hl \"%s\"",hl);
		parm=strtok(hl,HTERM);
		if(parm!=NULL&&strcmp(parm,"TYPE")==0) {
			if((parm=strtok(0,HTERM))!=NULL) {
				strcpy(h->type,parm);
				if( (strcmp(h->type,"dump")==0)
				    || (strcmp(h->type,"pico")==0)
				    || (strcmp(h->type,"rle")==0)
				    || (strcmp(h->type,"binary")==0)
				    || (strcmp(h->type,"bitmap")==0)
				    || (strcmp(h->type,"dim")==0)
				    || (strcmp(h->type,"document-image")==0)
				    || (strcmp(h->type,"ccitt-g31")==0)
				    || (strcmp(h->type,"ccitt-g32")==0)
				    || (strcmp(h->type,"ccitt-g4")==0)
				    || (strcmp(h->type,"cdf")==0)
				    || (strcmp(h->type,"tiff")==0)
				    ) /* these types are expected */ {
					if(PIC_debug)
						err("PIC_get_hdr:  good TYPE=\"%s\"",h->type);
					}
				else {	if(PIC_debug)
						err("PIC_get_hdr:  unexpected TYPE=\"%s\"",h->type);
					return(-1);
					};
				}
			else {	if(PIC_debug)
					err("PIC_get_hdr:  1st line must be TYPE=...");
					
				return(-1);
				};
			}
		else if(parm!=NULL&&strcmp(parm,"WINDOW")==0) {
			if((parm=strtok(0,HTERM))!=NULL) h->bx.a.x=atoi(parm);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) h->bx.a.y=atoi(parm);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) h->bx.b.x=atoi(parm)-1;
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) h->bx.b.y=atoi(parm)-1;
			else return(-1);
			}
		else if(parm!=NULL&&strcmp(parm,"RES")==0) {
			if((parm=strtok(0,HTERM))!=NULL)
				h->res_x=(int)(atof(parm)+0.5);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL)
				h->res_y=(int)(atof(parm)+0.5);
			else return(-1);
			}
		else if(parm!=NULL&&strcmp(parm,"NCHAN")==0) {
		    int nchan;
			if((parm=strtok(0,HTERM))!=NULL) nchan=atoi(parm);
			else return(-1);
			if(nchan!=1) {
				err("PIC_get_hdr: NCHAN=%d illegal: must be 1",nchan);
				return(-1);
				};
			}
		else if(parm!=NULL&&strcmp(parm,"PARMS")==0) {
		    int nchan;
			if((parm=strtok(0,"\n"))!=NULL) {
				h->parms = strdup(parm);
				}
			else return(-1);
			}
		else if(parm!=NULL) {
		    char *cat;
			/* save all header lines with unexpected keywords */
			if(h->misc==NULL) h->misc=(char *)malloc(strlen(oline)+2);
			else {	cat=(char *)malloc(strlen(h->misc)+strlen(oline)+2);
				strcpy(cat,h->misc);
				free(h->misc);
				h->misc=cat;
				};
			strcat(h->misc,oline);
			strcat(h->misc,"\n");
			}
		else return(-1);
		if((status=PIC_fgets(hline,HL_MAX,fileno(h->fp)))<=0)
			return(status);
	        strcpy(oline,hline);
	    	hl=hline;  while(*hl==' ') hl++;  /* strip initial blanks */
		};
	    };

	if(strcmp(h->type,"cdf")==0) {
	    int stat;
		/* Compund Document Format has binary header */
		/* synchronize FILE * ptr with file descr ptr */
		fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0);
		if((stat=CDF_get_hdr(h)) != 1) return(stat);
		};

	if(strcmp(h->type,"tiff")==0) {
	    int stat;
		/* Tagged Image File Format has abinary header */
		/* synchronize FILE * ptr with file descr ptr */
		fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0);
		if((stat=TIFF_get_hdr(h)) != 1) return(stat);
		};

	/* may want to allocate a line buffer here */
	h->bpl = bbx_wid(&(h->bx));
	if(strcmp(h->type,"binary")==0)
		h->bpl = (h->bpl+7)/8;		/* round up to byte boundary */
	else if(strcmp(h->type,"bitfile")==0)
		h->bpl = 2*((h->bpl+15)/16);	/* round up to 2-byte boundary */
	else if(strcmp(h->type,"bitmap")==0)
		h->bpl = 2*((h->bpl+15)/16);	/* round up to 2-byte boundary */
	else if( strcmp(h->type,"rle")==0
		|| strcmp(h->type,"dim")==0
		|| strcmp(h->type,"document-image")==0
		|| strcmp(h->type,"cdf")==0
		|| strcmp(h->type,"cdf-mrlc")==0
		|| strcmp(h->type,"cdf-g31")==0
		|| strcmp(h->type,"cdf-g32")==0
		|| strcmp(h->type,"cdf-g4")==0
		|| strcmp(h->type,"tiff")==0 )
		h->bpl = 0;
	if(h->bpl==0) h->line = NULL;
	else {	/* allocate one extra byte in line buffer as a favor to RLE */
		if((h->line = (unsigned char *) malloc(h->bpl+1))==NULL) {
			fprintf(stderr,
				"piclib: PIC_get_hdr: can't alloc h->line (%d bytes) - abort\n",
				h->bpl+1);
			return(-1);
			};
		memset(h->line,'\0',h->bpl);
		if(strcmp(h->type,"bitfile")==0) {
			if((h->pline = (unsigned char *) malloc(h->bpl+1))==NULL) {
				fprintf(stderr,
					"piclib: PIC_get_hdr: can't alloc h->pline (%d bytes) - abort\n",
					h->bpl+1);
				return(-1);
				};
			};
		};
	h->cy = h->bx.a.y-1;	/* just prior to 1st line */
	/* synchronize FILE * ptr with file descr ptr */
	fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0);
	return(1);
	}

/* Read next page from AT&T Image Director file header from file descr
   fileno(h->fp), set up the rest of the header, and return status:
   1 OK, 0 EOF, <0 error */
int CDF_next_page( h )
    PIC_hdr *h;
{	return(-1);	/* unimplemented */
	}

#define HASHEADER(h) ((strcmp((h)->type,"postscript")!=0&&strcmp((h)->type,"sunraster")!=0))

/* Read AT&T Image Director file header from file descr fileno(h->fp),
   set up the rest of the header, and return status:  1 OK, 0 EOF, <0 error */
int CDF_get_hdr( h )
    PIC_hdr *h;
{   char *cp,*parm,hline[HL_MAX];
    int status,nrd,ch,mny;
#define dbg_cdf (0)
typedef struct CDF_file {
	unsigned char raw[16];
	unsigned char op,np,at;
	unsigned int l1,l2,len;
	} CDF_file;
typedef struct CDF_page {
	unsigned char raw[16];
	unsigned char op,pn,at;
	unsigned char f1,f2,f3,f4;
        unsigned int ptr;
	} CDF_page;
typedef struct CDF_recd {
	unsigned char raw[16];
	unsigned char op,a1,a2,a3;
        unsigned int len;
	Bbx bx;
	} CDF_recd;
    CDF_file fh;
    CDF_page ph;
    CDF_recd rh;
    
	if(dbg_cdf) err("CDF_get_hdr: enter %s",PIC_hdr_toa(h));
	/* synchronize FILE * ptr with file descr ptr */
	fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0);
	strcpy(h->type,"cdf");

	/* Read CDF File header */
	if(fread(fh.raw,1,16,h->fp)!=16) return(0);
	fh.op = fh.raw[0];
	fh.np = fh.raw[1];
	fh.at = fh.raw[2];
	fh.l1 = fh.raw[4]+256*fh.raw[5];
	fh.l2 = fh.raw[6]+256*fh.raw[7];
	fh.len = fh.raw[12]+256*(fh.raw[13]+256*(fh.raw[14]+256*fh.raw[15]));
	if(dbg_cdf) err("CDF_get_hdr: file hdr: op0x%x p%d at0x%x lim1:%u lim2:%u len%u",
		fh.op,fh.np,fh.at,fh.l1,fh.l2,fh.len);
	if(fh.op!=0xA0&&fh.op!=0xAF) abort("CDF_get_hdr: file must be CDF type");
	if(fh.np!=1) err("CDF_get_hdr: file has %d pages - ignore all but 1st",fh.np);
	switch(fh.at>>4) {
	    case 0:	h->res_x = h->res_y = 100;  break;
	    case 1:	h->res_x = h->res_y = 200;  break;
	    case 2:	h->res_x = h->res_y = 300;  break;
	    default:	err("CDF_get_hdr: file has unknown resolution nibble 0x%x -- assume 400 dpi",fh.at>>4);
			h->res_x = h->res_y = 400;
			break;
	    };
	h->bx.a.x = h->bx.a.y = 0;
	h->bx.b.x = fh.l1;
	h->bx.b.y = fh.l2;
	if(fh.op==0xAF) {
		abort("CDF_get_hdr: file has continuation header");
		};

	/* Read 1st page table entry */
	if(fread(ph.raw,1,16,h->fp)!=16) return(0);
	ph.op = ph.raw[0];
	ph.pn = ph.raw[1];
	ph.at = ph.raw[2];
	ph.ptr = ph.raw[12]+256*(ph.raw[13]+256*(ph.raw[14]+256*ph.raw[15]));
	if(dbg_cdf) err("CDF_get_hdr: page hdr: op0x%x p%d at0x%x ptr%u",
		ph.op,ph.pn,ph.at,ph.ptr);
	if(ph.op!=0x80&&ph.op!=0x8F)
		abort("CDF_get_hdr: page opcode 0x%x is peculiar",ph.op);
	if(ph.pn!=1) err("CDF_get_hdr: page %d out of order - read anyway",ph.pn);
	switch(ph.at&0x0F) {	/* low nibble */
	    case 0:	/* portrait */  break;
	    case 1:	/* landscape */
	    default:	err("CDF_get_hdr: page has peculiar format nibble 0x%x -- assume 40portrait",ph.at&0x0F);
			break;
	    };
	switch(ph.at>>4) {	/* high nibble */
	    case 0xF:	/* background is white */  break;
	    default:	err("CDF_get_hdr: page has peculiar color nibble 0x%x -- assume white",ph.at>>4);
			break;
	    };
	/* seek top of Page */
	fseek(h->fp,h->seek+=ph.ptr,0);

	/* Read CDF Record header */
	if(fread(rh.raw,1,16,h->fp)!=16) return(0);
	rh.op = rh.raw[0];
	rh.a1 = rh.raw[1];
	rh.a2 = rh.raw[2];
	rh.a3 = rh.raw[3];
	rh.len = rh.raw[4]+256*rh.raw[5];
	rh.bx.a.x = rh.raw[8]+256*rh.raw[9];
	rh.bx.a.y = rh.raw[10]+256*rh.raw[11];
	rh.bx.b.x = rh.raw[12]+256*rh.raw[13];
	rh.bx.b.y = rh.raw[14]+256*rh.raw[15];
	if(dbg_cdf) err("CDF_get_hdr: record hdr: op0x%x a0x%x,0x%x,0x%x len%u bx%s",
		rh.op,rh.a1,rh.a2,rh.a3,rh.len,bbx_toa(&rh.bx));
	switch(rh.op) {
	    case 0x20: /* Image */ break;
	    case 0x01: /* End of Page */ 
	    case 0x10: /* Text */ 
	    case 0x1F: /* Text + cont. */ 
	    case 0x50: /* Text Document */ 
	    case 0x5F: /* Text Document + cont. */ 
	    case 0x40: case 0x41: case 0x42: case 0x43: case 0x44:
	    case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4A:
	    case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F:
			/* Graphics */ 
	    default:
		abort("CDF_get_hdr: record not Image");
	    };
	if(rh.a2!=0x01) err("CDF_get_hdr: record not opaque - assume opaque");
	switch(rh.a3&0x0F) {	/* compression algorithm */
	    case 1:	/* modified run-length code */
		strcat(h->type,"-mrlc");
		break;
	    case 0:	/* raw */
		abort("CDF_get_hdr: record compression 0x%x is legal but unsupported",rh.a3&0x0F);
		break;
	    case 2:	/* ccitt_g31 */
		strcat(h->type,"-g31");
		abort("CDF_get_hdr: record compression 0x%x is legal but unsupported",rh.a3&0x0F);
		break;
	    case 3:	/* ccitt_g32 or ccitt_g4 */
		strcat(h->type,"-g32");
		abort("CDF_get_hdr: record compression 0x%x is legal but unsupported",rh.a3&0x0F);
		break;
	    default:
		abort("CDF_get_hdr: record compression 0x%x is peculiar",rh.a3&0x0F);
		break;
	    };
	switch(rh.a3>>4) {	/* resolution */
	    case 0:
		h->res_y = 100;
		break;
	    case 1:
		h->res_y = 200;
		break;
	    case 2:
		h->res_y = 300;
		break;
	    default:
		err("CDF_get_hdr: record vert resolution peculiar 0x%x - assume 200 dpi",
			rh.a3>>4);
		h->res_y = 200;
		break;
	    };
	/* synchronize file descr ptr with FILE * ptr */
	lseek(fileno(h->fp),h->seek = ftell(h->fp),0);
	if(dbg_cdf) err("CDF_get_hdr: normal exit %s",PIC_hdr_toa(h));
	return(1);
	}

/* Read Tagged Image Format File (TIFF) header, from file descr fileno(h->fp),
   set up the rest of the PIC header, and return status:  1 OK, 0 EOF, <0 error */
int TIFF_get_hdr( h )
    PIC_hdr *h;
{	err("TIFF not yet supported");
	return(-1);
	}

/* Write header to picture file, to file descriptor fileno(h->fp), and initialize
   line buffer and cy. */
PIC_put_hdr( h )
   PIC_hdr *h;
{   char *cp,*parm,hline[HL_MAX];
    int status,nrd;
    unsigned short s;
#define put_ushort(S) { s=(S); putc(s&0377,h->fp); putc(s>>8,h->fp); }

	/* write type header */
	if( strcmp(h->type,"bitfile")==0 ) {	/* bitfile header */
		put_ushort(0);
		}
	else if(HASHEADER(h)) {
		sprintf(hline,"TYPE=%s\n",h->type);
		  write(fileno(h->fp),hline,strlen(hline));
		};
	if(strcmp(h->type,"pico")==0
	    || strcmp(h->type,"dump")==0) {
		sprintf(hline,"NCHAN=1\n");
		  write(fileno(h->fp),hline,strlen(hline));
		};

	/* write window */
	h->bpl = bbx_wid(&(h->bx));
	if(strcmp(h->type,"binary")!=0
		&& strcmp(h->type,"bitfile")!=0
		&& strcmp(h->type,"bitmap")!=0
		&& HASHEADER(h)) {
		sprintf(hline,"WINDOW=%d %d %d %d\n",
				h->bx.a.x,h->bx.a.y,h->bx.b.x+1,h->bx.b.y+1);
		  write(fileno(h->fp),hline,strlen(hline));
		}
	else if(strcmp(h->type,"binary")==0) {
		h->bpl = (h->bpl+7)/8;	/* round up to byte boundary */
		sprintf(hline,"WINDOW=%d %d %d %d\n",
				h->bx.a.x,h->bx.a.y,h->bx.b.x+1,h->bx.b.y+1);
		  write(fileno(h->fp),hline,strlen(hline));
		}
	else if(strcmp(h->type,"bitmap")==0) {
		h->bpl = 2*((h->bpl+15)/16);	/* round up to 2-byte boundary */
		sprintf(hline,"WINDOW=%d %d %d %d\n",
				h->bx.a.x,h->bx.a.y,h->bx.b.x+1,h->bx.b.y+1);
		  write(fileno(h->fp),hline,strlen(hline));
		}
	else if(strcmp(h->type,"sunraster")!=0 ) {	/* bitfile window */
		h->bpl = 2*((h->bpl+15)/16);  /* round up to 2-byte boundary */
		put_ushort(h->bx.a.x);  put_ushort(h->bx.a.y);
		put_ushort(h->bx.b.x+1);  put_ushort(h->bx.b.y+1);
		fflush(h->fp);
		};
	if( ((h->res_x!=0||h->res_y!=0)) && (HASHEADER(h))
		&& strcmp(h->type,"bitfile")!=0 ) {
		sprintf(hline,"RES=%d %d\n",h->res_x,h->res_y);
		  write(fileno(h->fp),hline,strlen(hline));
		};
	if(h->parms!=NULL && strlen(h->parms)>0 && strcmp(h->type,"bitfile")!=0 ) {
		sprintf(hline,"PARMS=%s\n",h->parms);
		  write(fileno(h->fp),hline,strlen(hline));
		};
	if(h->misc!=NULL && strlen(h->misc)>0 && strcmp(h->type,"bitfile")!=0 ) {
		write(fileno(h->fp),h->misc,strlen(h->misc));
		};
	/* terminating blank line */
	if( HASHEADER(h) && strcmp(h->type,"bitfile")!=0 ) {
		hline[0] = '\n';
		write(fileno(h->fp),hline,1);
		};

	if(strcmp(h->type,"rle")==0) { h->bpl = 0;  h->line = NULL; }
	else {	/* allocate one extra byte in line buffer as a favor to RLE */
		if((h->line = (unsigned char *) malloc(h->bpl+1))==NULL) {
			fprintf(stderr,
				"piclib: PIC_put_hdr: can't alloc h->line (%d bytes) - abort\n",
				h->bpl+1);
			return(-1);
			};
		if(strcmp(h->type,"bitfile")==0) {
			memset(h->line,'\0',h->bpl);
			if((h->pline = (unsigned char *) malloc(h->bpl+1))==NULL) {
				fprintf(stderr,
					"piclib: PIC_put_hdr: can't alloc h->pline (%d bytes) - abort\n",
					h->bpl+1);
				return(-1);
				};
			};
		};
	h->cy = h->bx.a.y-1;	/* just prior to 1st line */
	/* synchronize FILE * ptr with file descr ptr */
	fseek(h->fp,h->seek = lseek(fileno(h->fp),0L,1),0);
	}

err_PIC_line(h,sl)
	PIC_hdr *h;
	char *sl;
#define BPL 20	/* bytes to display per line */
{   char *cp,*ep;
    int bpl;		/* bytes per display line */
	bpl=0;
	for(cp=sl,ep=sl+h->bpl; cp!=ep; cp++) {
		fprintf(stderr,"%o ",0377&(*cp));
		if((++bpl)%BPL==0) fprintf(stderr,"\n   ");
		};
	if((bpl)%BPL!=0)fprintf(stderr,"\n");
	}

/* Skip `y' lines of PIC file */
PIC_skip(h,y)
    PIC_hdr *h;
    int y;
{	lseek(fileno(h->fp),(long)(y*h->bpl),1);
	h->seek += y*h->bpl;
	h->cy += y;
	}

/* Read next full line of picture data, and if OK update line & cy;
   return status:  1 OK, 0 EOF, -1 ERR.
   Free buffer in header on EOF. */
int PIC_rline(h,lbpp)
    PIC_hdr *h;
    unsigned char **lbpp;
{   int stat;
	if( (stat=read(fileno(h->fp),h->line,h->bpl)) == h->bpl) {
		*lbpp=h->line;
		h->seek += h->bpl;
		h->cy++;
		if(PIC_debug) err("read %d bytes from fileno(h->fp) - OK",stat);
		return(1);
		}
	else { /* EOF or ERR */
		*lbpp=NULL;
		free(h->line);  h->line = NULL;
		if(PIC_debug) err("read from fileno(h->fp) stat%d",stat);
		if((stat>=0)&&(stat<h->bpl)) return(0 /*EOF*/);
		else return(-1);
		};
	}

/* write a full line of picture data, returning status:  1 OK, 0 EOF, -1 ERR */
int PIC_wline(h,line)
    PIC_hdr *h;
    unsigned char *line;
{   int stat;
	if( (stat=write(fileno(h->fp),line,h->bpl)) == h->bpl) {
		h->seek += h->bpl;
		h->cy++;
		if(PIC_debug) err("wrote %d bytes to fd%d - OK",stat,fileno(h->fp));
		return(1);
		}
	else { /* ERR */
		err("write to fd%d stat%d",fileno(h->fp),stat);
		if((stat>=0)&&(stat<h->bpl)) return(0 /*EOF*/);
		else return(-1);
		};
	}

char *PIC_hdr_toa(h)
    PIC_hdr *h;
{   static char s[120];
	sprintf(s,"{type=%s bx%s res%d,%d bpl%d cy%d sk%d}",
		h->type,
		bbx_toa(&(h->bx)),
		h->res_x,h->res_y,
		h->bpl,
		h->cy,
		h->seek
		);
	return(s);
	}
0707070035351135641006640007620000050000010264030476773367300001200000032256postlib.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     T. Thompson - ATT-BL HO - first versions        */
/* Routines for generating PostScript from RLE. */
/* The routines at the bottom of this file, which */
/* do the actual conversion to postscript, were */
/* hacked out of 'sun2ps'.  The original header */
/* giving credit to its authors is there. */

/* The 'binary' version of the output is collected in a */
/* temporary file, which is then fed back to the routines */
/* that generate postscript in a run-length-encoded form. */
/* Ideally it should just convert the original run-length */
/* encoding directly, but the REAL bottleneck is the */
/* PostScript printer, of course.  Printing an 800 by 800 */
/* pixel image takes 5 minutes. */

#include <stdio.h>
#include <math.h>
#include <string.h>
#include "CPU.h"
#include "boole.h"
#include "limits.h"     /* numeric extreme values */
#include "Units.h"
#include "Coord.h"
#include "pic.h"

FILE *Fp, *tmpfile();
int Raswidth;
int Raslength;
int Rasbytes;	/* bytes per row */
int Inv = 0;
int Aspect = 1;		/* if non-zero, retain original aspect ratio */
int Land = 0;		/* if non-zero, print in landscape mode */
char Revbyte[256];
/*  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */
char Revnib[16] = {
    0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
    };
 
void
POST_start(h)
PIC_hdr *h;
{
	int n, v;

	/* build a table of reversed bytes */
	for ( n=0; n<256; n++ )
		Revbyte[n] = Revnib[(n>>4)&0xf] | Revnib[n&0xf]<<4;

	h->bpl = (h->bpl+7)/8;
	Rasbytes = h->bpl;
	Raslength = h->bpl * h->bx.b.y;
	Raswidth = h->bx.b.x;
	postmain(1,NULL,Raswidth,h->bx.b.y);
#if CPU==SUN
	Fp = tmpfile();
#else
	Fp = fopen("tmp.postlib.0","rw");
#endif
}

void
POST_end()
{
	int c;
	rewind(Fp);
	(VOID) Encode(Raslength, Inv);
	PrintPostScriptClosing();
	fclose(Fp);
}

/* write a full line of picture data, returning status:  1 OK, 0 EOF, -1 ERR */
int POST_wline(h,line)
    PIC_hdr *h;
    unsigned char *line;
{   int stat;
        if( (stat=fwrite(line,1,h->bpl,Fp)) == h->bpl) {
                h->seek += h->bpl;
                h->cy++;
                return(1);
                }
        else { /* ERR */
                err("write to fd%d stat%d",fileno(h->fp),stat);
                if((stat>=0)&&(stat<h->bpl)) return(0 /*EOF*/);
                else return(-1);
                };
        }

/******************************************************************************
*									      *
*	File:         sun2ps.c						      *
*	Author:       Glenn Boysko					      *
*	Organization: Case Western Reserve University			      *
*	EMail:	      {decvax, sun}!mandrill!boysko			      *
*		      boysko@mandrill.cwru.edu				      *
*	Created:      Wed Mar 23 9:25pm					      *
*	Contents:     Sun Rasterfile to PostScript image (using a run-length  *
*			encoding scheme.)				      *
*									      *
*	(Adapted from "postimage" filter by J. R. Bammi.)		      *
*									      *
*	@(#)sun2ps.c	1.8
******************************************************************************/

/*
 * Usage:
 *  sun2ps [-s sizex sizey] [-t transx transy] [-r rot] [-l] [-i] [-a] file ...
 *
 *	-s sizex sizey   = size of postscript image - default 7.5 x 10 inches.
 *	-t transx transy = translate image - default 0.5 0.5 inches
 *	-r rotate	 = rotate image     - default 0 degress
 *      -l		 = landscape (overrides *all* settings.) 
 *	-i		 = inverse image - default no inverse 
 *				(Inverse enabled implies white on black.)
 *	-a		 = maintain correct aspect ratio - default none.
 *
 */

/* Sun standard raster file format (as obtained by screendump(1)).
 *
 * Header	(8 16-bit quantities)
 * Color Map
 * Image
 *
 */

/* Header Format:
 * 
 * ras_magic		(int)	Raster Magic number 0x59a66a95
 * ras_width		(int)	Width of image in pixels.
 * ras_height		(int)	Height of image in pixels.
 * ras_depth		(int)	Bits per pixel.	Either 1 or 8 bits.
 * ras_length		(int)	Length of image in bytes.
 * ras_type		(int)	Type of file. Assumed to be RT_STANDARD (1) if
 *				produced by a screendump command.
 * ras_maptype		(int)	Type of color map. 
 * ras_maplength	(int)	Length of color map in bytes.
 *
 */

/* Ras_maplength bytes of Color map data. */

/* Ras_length bytes of Image data. */

/* Buffer and Input Modes... */
#define LITERAL	0
#define COPY	1
#define IGNORE	2

/* Transmission Variables. */
int BufCount;

unsigned char Buffer[128],
     	      CurrByte,
     	      NextByte,
     	      *BufferP = Buffer;

/* Diagnostic Variables. */
int	DiagNLongRuns = 0,
     	DiagMaxRunLength = 0,
     	DiagNumRuns = 0;
double	DiagSumRunLength = 0;

postmain(argc,argv,width,height)
int argc;
char **argv;
int width, height;
{
     char      *filename;
     double 	sizex, sizey, transx, transy, rotate;

     extern double atof();
     
     filename = "STDIN";
     sizex = 7.5;
     sizey = 10.0;
     transx = transy = 0.5;
     rotate = 0.0;
     
     while(--argc > 0)
     {
	  ++argv;
	  if((*argv)[0] == '-')
	  {
	       switch((*argv)[1])
	       {
		 case 'l':
		 case 'L':
		    Land = 1;
		    break;
		    
		 case 's':
		 case 'S':
		    sizex = atof(*++argv);
		    sizey = atof(*++argv);
		    argc -= 2;
		    break;
		    
		 case 't':
		 case 'T':
		    transx = atof(*++argv);
		    transy = atof(*++argv);
		    argc -= 2;
		    break;
		    
		 case 'r':
		 case 'R':
		    rotate = atof(*++argv);
		    argc--;
		    break;
		    
		 case 'I':
		 case 'i':
		    Inv = 1;
		    break;
		    
		 case 'A':
		 case 'a':
		    Aspect = 1;
		    break;
		    
		 default:
		    fprintf(stderr,"Illegal switch %c - ignored\n",
			    (*argv)[1]);
	       }
	  }
     }
     if (Land)
     {
	  transx = 8.0;
	  transy = 0.5;
	  sizex  = 10.0;
	  sizey  = 7.5;
	  rotate = 90.0;
     }
	if (Aspect) {
		if ((sizex / width) < (sizey / height)) {
			sizey = sizex * (height * 1.0 / width);
		}
		else {
			sizex = sizey * (width * 1.0 / height);
		}
	}
	PrintPostScriptRoutines(height, width, 1 /*depth*/ ,
			     transx, transy, sizex, sizey, rotate);
}

/******************************************************************************
*	I/O Routines.							      *
******************************************************************************/
int
gb()		/* Get a byte from Fp. */
{
     int byte;
     
     if (!feof(Fp))
	  byte = getc(Fp);
     else
	  Error("Premature EOF.\n");
     if (ferror(Fp))
	  Error("I/O Error.\n");
     return(Revbyte[byte]);
}

SendHex(Byte)		/* Send a Hex char to Stdout. */
unsigned char Byte;
{
     static int LineCount = 0;

     printf("%02x",  0xff & Byte);
     if (++LineCount == Rasbytes)
     {
	  putchar('\n');
	  LineCount = 0;
     }
}
     
int
SendBuffer(Inv)		/* Send a buffer to Stdout. Return BytesSent. */
int Inv;
{
     int i, BytesSent;
     
     if (BufferMode() == LITERAL)
     {
	  SendHex( (unsigned char) 0xff & BufCount );
	  for (i = 0; i < BufCount+1; i++)
	  {
	       SendHex( (Inv) ? Buffer[i] : ~Buffer[i]);
	  }
	  BytesSent = BufCount+2;
     }
     else if (BufferMode() == COPY)
     {
	  SendHex( (unsigned char) 0xff & (0x100 + BufCount) );
	  SendHex( (Inv) ? Buffer[0] : ~Buffer[0]);
	  BytesSent = 2;
	  DiagRecLRun(mag(BufCount)+1);
     }
     return(BytesSent);
}

/******************************************************************************
*	Utility Routines.						      *
******************************************************************************/
int
mag(Byte)	/* Magitude of a signed char. */
int Byte;
{
     if (Byte & 0x80)
     {
	  /* Signed */
	  Byte = ~(--Byte);
     }
     return( 0xff & Byte );
}
	  
/******************************************************************************
*	Buffer Management Routines.					      *
******************************************************************************/
int
InputMode()
{
     if (CurrByte == NextByte)
	  return(COPY);
     return(LITERAL);
}

int
BufferMode()
{
     if (BufCount >= 0 && BufCount <= 127)
	  return(LITERAL);
     else if (BufCount >= -127 && BufCount <= -1)
	  return(COPY);
     return(IGNORE);
}

InitLitMode(NBytes, Inv)
int *NBytes, Inv;
{
     BufferP    = Buffer;
     BufCount   = -1;
     ContLitMode(NBytes, Inv);
}

ContLitMode(NBytes, Inv)
int *NBytes, Inv;
{
     if (BufCount == 127)
     {
	  SendBuffer(Inv);
	  BufferP  = Buffer;
	  BufCount = -1;
     }
     *BufferP++ = CurrByte;
     BufCount++;
     CurrByte   = NextByte;
     NextByte   = (unsigned char) gb();
     (*NBytes)--;
}
     
InitCopyMode(NBytes, Inv)
int *NBytes, Inv;
{
     BufferP    = Buffer;
     *BufferP++ = CurrByte;
     BufCount   = -1;
     CurrByte   = (unsigned char) gb();
     NextByte   = (unsigned char) gb();
     *NBytes   -= 2;
}

ContCopyMode(NBytes, Inv)
int *NBytes, Inv;
{
     if (BufCount == -127)
     {
	  SendBuffer(Inv);
	  InitCopyMode(NBytes, Inv);
	  DiagNLongRuns++;
     }
     BufCount--;
     CurrByte   = NextByte;
     NextByte   = gb();
     (*NBytes)--;
}

/******************************************************************************
*	Encoding Algorithm.						      *
******************************************************************************/
int
Encode(NBytes, Inv)
int NBytes, Inv;
{
     int BytesSent = 0;
     
     /* Initialize Buffer, BufCount, NextByte, CurrByte */
     CurrByte = (unsigned char) gb();
     NextByte = (unsigned char) gb();
     if (InputMode() == LITERAL)
     {
	  InitLitMode(&NBytes, Inv);
     }
     else
     {
	  InitCopyMode(&NBytes, Inv);
     }
     while (NBytes > 3)
     {
	  switch(BufferMode())
	  {
	    case LITERAL:
	       if (InputMode() == COPY)
	       {
		    BytesSent += SendBuffer(Inv);
		    InitCopyMode(&NBytes, Inv);
	       }
	       else
	       {
		    ContLitMode(&NBytes, Inv);
	       }
	       break;
	    case COPY:
	       if (CurrByte == Buffer[0])
	       {
		    ContCopyMode(&NBytes, Inv);
	       }
	       else
	       {
		    BytesSent += SendBuffer(Inv);
		    if (InputMode() == COPY)
		    {
			 InitCopyMode(&NBytes, Inv);
		    }
		    else
		    {
			 InitLitMode(&NBytes, Inv);
		    }
	       }
	       break;
	    default:
	       Error("Bad Buffer Mode... Sorry\n");
	       break;
	  }
     }
     BytesSent += SendBuffer(Inv);
     /* Send out rem'g 2-3 bytes in LITERAL mode. */
     Buffer[0] = CurrByte;
     Buffer[1] = NextByte;
     if (NBytes == 3)
	  Buffer[2] = gb();
     BufCount = NBytes-1;
     BytesSent += SendBuffer(Inv);
     return(BytesSent);
}

/******************************************************************************
*	Diagnostic Routines.						      *
******************************************************************************/
DiagRecLRun(Rlength)
int Rlength;
{
#ifdef DIAGS
     if (Rlength > DiagMaxRunLength)
	  DiagMaxRunLength = Rlength;
     DiagSumRunLength += Rlength;
     DiagNumRuns++;
#endif
}

Diags()
{
#ifdef DIAGS
     fprintf(stderr, "Longest Run (<= 128) = %d\n", DiagMaxRunLength);
     fprintf(stderr, "Number of Runs over 128 = %d\n", DiagNLongRuns);
     fprintf(stderr, "Average Run Length of %d. (%d Runs)\n",
	     (int) DiagSumRunLength / DiagNumRuns, DiagNumRuns);
#endif
}

/******************************************************************************
*	PostScript Output Routines. 					      *
******************************************************************************/
PrintPostScriptRoutines(ras_h, ras_w, ras_d, tx, ty, sx, sy, rot)
int ras_h, ras_w, ras_d;
double tx, ty, sx, sy, rot;
{
     printf("%%!\n/inch {72 mul} def\n");
     printf("/bpp %d def\n", ras_d);
     printf("/scanlines %d def\n", ras_h);
     printf("/scansize %d def\n", ras_w);
     printf("/bitmapx\n{");
     printf(" %d %d %d [%d 0 0 %d 0 %d] ", ras_w, ras_h, ras_d, ras_w, 
	    -ras_h, ras_h);
     printf("{currentfile readrlehexstring pop } image\n} def\n");
     printf("gsave\n");
     printf("%f inch %f inch translate\n",tx, ty);
     printf("%f rotate\n", rot );
     printf("%f inch %f inch scale\n", sx, sy);
     printf("/readrlehexstring\t%% rle_file => decoded_string boolean\n");
     printf("{\n\t/fileptr exch def\n\tfileptr 1 string readhexstring {");
     printf("\n\t\t0 get dup 128 and 0 eq\n");
     printf("\t\t{ 1 add /Buffer exch string def\n");
     printf("\t\t\tfileptr Buffer readhexstring\n\t\t}\n\t\t{");
     printf(" 256 exch sub /BufCount exch def\n");
     printf("\t\t\t/Buffer BufCount 1 add string def\n");
     printf("\t\t\t/RunInt fileptr 1 string readhexstring");
     printf(" pop 0 get def\n");
     printf("\t\t\t0 1 BufCount { RunInt Buffer 3 1 roll put } for\n");
     printf("\t\t\tBuffer true\n\t\t} ifelse\n\t}\n\t{ false } ifelse\n");
     printf("} def\n");
     printf("/clipathx\n{\tnewpath\n\t0 0 moveto\n\t%f inch 0", sx);
     printf(" lineto\n\t%f inch %f inch lineto\n\t0 %f inch lineto\n",
	    sx, sy, sy);
     printf("\tclosepath\n} def\nclipathx clip\n");
     printf("bitmapx\n");
}

PrintPostScriptClosing()
{     
     printf("\ngrestore\n");
     printf("showpage\n");
}

/******************************************************************************
*	Error Routine.							      *
******************************************************************************/
Error(S1, S2, S3)
char *S1, *S2, *S3;
{
     fprintf(stderr, S1, S2, S3);
     exit(-1);
}
0707070035351136011006640007620000050000010264130476773367300001200000005002rastlib.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     T. Thompson - ATT-BL HO - first version         */
/* Routines for generating PostScript from RLE. */
/* The routines at the bottom of this file, which */
/* do the actual conversion to postscript, were */
/* take from 'sun2ps'.  The original header */
/* giving credit to its authors is there. */

/* The 'binary' version of the output is collected in a */
/* temporary file, which is then fed back to the routines */
/* that generate postscript in a run-length-encoded form. */
/* Ideally it should just convert the original run-length */
/* encoding directly, but this is just a hack.  The REAL */
/* bottleneck is the PostScript printer, of course.  */
/* Printing an 800 by 800 pixel image takes 5 minutes. */

#include <stdio.h>
#include <math.h>
#include <string.h>
#include "CPU.h"
#include "boole.h"
#include "limits.h"     /* numeric extreme values */
#include "Units.h"
#include "Coord.h"
#include "pic.h"
#include <sys/types.h>
#include <suntool/sunview.h>
#include <pixrect/pixrect.h>
#include <pixrect/pr_io.h>

int Raswidth;
int Raslength;
extern char Revbyte[256];
extern char Revnib[16];

static FILE *fout;
 
void
RAST_start(h)
PIC_hdr *h;
{
	int n, v;
	struct rasterfile rh;

	/* build a table of reversed bytes */
	for ( n=0; n<256; n++ )
		Revbyte[n] = Revnib[(n>>4)&0xf] | Revnib[n&0xf]<<4;

	fout = h->fp;
	h->bpl = (h->bpl+7)/8;
	Raslength = h->bpl * h->bx.b.y;
	Raswidth = h->bx.b.x;

	rh.ras_magic = RAS_MAGIC;
	rh.ras_width = h->bx.b.x;
	rh.ras_height = h->bx.b.y;
	rh.ras_depth = 1;
	rh.ras_length = Raslength;
	rh.ras_type = RT_STANDARD;
	rh.ras_maptype = RMT_NONE;
	rh.ras_maplength = 0;
	pr_dump_header(fout,&rh,(colormap_t*)0);
}

void
RAST_end()
{
}

/* write a full line of picture data, returning status:  1 OK, 0 EOF,
-1 ERR */
int RAST_wline(h,line)
    PIC_hdr *h;
    unsigned char *line;
{   int stat;
	int n;

	for ( n=h->bpl; n>0; n-- ) {
		if ( putc(Revbyte[*line++],fout) == EOF )
			break;
	}
	if ( n == 0 ) {
                h->seek += h->bpl;
                h->cy++;
                return(1);
                }
        else { /* ERR */
                err("write to fd%d stat%d",fileno(h->fp),stat);
                if((stat>=0)&&(stat<h->bpl)) return(0 /*EOF*/);
                else return(-1);
                };
        }
0707070035351135651006640007620000050000010264150476773367300000600000003030ric.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* ric.h -  Ricoh IS-30 scanner constants, typedefs, function declarations
   The scanner program `rscan' creates a file (typically >1Mbyte).
   It has an ascii header, terminated by \n\n -- see RIC_hdr for its data fields.
   The rest is binary scanner data. Each `RIC_hdr.bpl' bytes holds one scan-line's
   pixels, 1 bit/pixel.  A `1' bit means black.  The order of the bytes in a line
   is left-to-right across the page.  The low-order bit in a byte is the left-most.
   Conventionally, X-coordinates start at 0, at the left of the page, and
   increase to the right.  Y-coordinates start at 0 at the top of the page,
   and increase down.

   REQUIRES:  prior #include "Coord.h"
   */

typedef struct {	/* Scanner file header */
	short res_x,res_y;  /* resolution in pixels/inch (x,y may differ) */
	short bpl;	/* bytes per scan line */
	Bbx bx;		/* bounding box (pixel indices 0,1,...) */
	} RIC_hdr;

/* these routines are found in /usr/hsb/ricoh/riclib.c */
int RIC_get_hdr();	/* args: fd, (RIC_hdr *); returns: 1==OK, 0==EOF, -1=ERR */
int RIC_line();		/* arg: (char **); returns: 1==OK, 0==EOF, -1==ERR */
RIC_skip();		/* arg: int no. lines to skip */
char *S_hdr_toa();	/* RIC_hdr in printable-string form */

0707070035351135321006640007620000050000010264160476773367300001100000011466riclib.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* riclib.c - Ricoh scanner-file public functions:

RIC_* functions use system I/O, for speed...
   int RIC_get_hdr(fd,RIC_hdr *) - get scanner-file header
   int RIC_line(char **)	- read one line of scanner data
	err_RIC_Line(char *,RIC_hdr) - print on stderr
   int RIC_oline(char **)	- write one line of scanner data
   char *RIC_hdr_toa()	- RIC_hdr to ascii printable string
   */

#include <stdio.h>
#include <math.h>
#include <string.h>
#include "CPU.h"
#include "stdocr.h"

#define RIC_debug 0

/* treated as local static: */
int RIC_fd;		/* file descr. */
int RIC_bpl;		/* bytes per line */
char *RIC_bf = NULL;	/* (malloc space *) holds one line of scanner data */

/* system I/O variation on fgets(3), except it replaces \n with \0,
   and returns the number of chars read (including \0) */
int RIC_fgets(bf,max,fd)
	char *bf;
	int max;
	int fd;
{   char *cp;
    int stat,mny;
	cp=bf; mny=0;
	while(((stat=read(fd,cp,1))==1)&&(++mny<max)&&((*cp)!='\n')) cp++;
	if(stat!=1) return(stat);
	else if(mny>=max) return(-1);
	*cp='\0';
	return(mny);
	}

/* read header from scanner file, return status:  1 OK, 0 EOF, -1 error */
int RIC_get_hdr( fd, hp )
	int fd;		/* should have been open'ed earlier */
	RIC_hdr *hp;
#define HL_MAX 80
#define HTERM "=, 	\n"	/* terminations for header words: "=,<sp><tab>" */
{   char *cp,*parm,hline[HL_MAX];
    int status,nrd;
	RIC_fd = fd;
	if((status=RIC_fgets(hline,HL_MAX,RIC_fd))<=0) return(status);
	while(strlen(hline)>1) {
		if(RIC_debug) err("hline \"%s\"",hline);
		parm=strtok(hline,HTERM);
		if(parm!=NULL&&strcmp(parm,"TYPE")==0) {
			if((parm=strtok(0,HTERM))!=NULL
				&&strcmp(parm,"binary")==0) ;
			else return(-1);
			}
		else if(parm!=NULL&&strcmp(parm,"WINDOW")==0) {
			if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.x=atoi(parm);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.y=atoi(parm);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.x=atoi(parm)-1;
			else return(-1);
			hp->bpl=(hp->bx.b.x-hp->bx.a.x+1+7)/8;
			if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.y=atoi(parm)-1;
			else return(-1);
			}
		else if(parm!=NULL&&strcmp(parm,"RES")==0) {
			if((parm=strtok(0,HTERM))!=NULL) hp->res_x=atoi(parm);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) hp->res_y=atoi(parm);
			else return(-1);
			}
		else return(-1);
		if((status=RIC_fgets(hline,HL_MAX,RIC_fd))<=0) return(status);
		};
	RIC_bpl=hp->bpl;
	/* allocate one extra byte in scanner buffer as a favor to RLE */
	if((RIC_bf = (char *) malloc(RIC_bpl+1))==NULL) {
		fprintf(stderr,
			"riclib:  can't alloc RIC_bf (%d bytes) - abort\n",
			RIC_bpl+1);
		return(-1);
		};
	return(1);
	}

/* write header to scanner file */
RIC_put_hdr( fd, hp )
	int fd;		/* should have been open'ed earlier */
	RIC_hdr *hp;
{   char *cp,*parm,hline[HL_MAX];
    int status,nrd;
	sprintf(hline,"TYPE=binary\n");
	write(fd,hline,strlen(hline));
	sprintf(hline,"WINDOW=%d %d %d %d\n",
			hp->bx.a.x,hp->bx.a.y,hp->bpl,hp->bx.b.y+1);
	write(fd,hline,strlen(hline));
	sprintf(hline,"RES=%d %d\n\n",hp->res_x,hp->res_y);
	write(fd,hline,strlen(hline));
	}

err_RIC_line(sl,shdr)
	char *sl;
	RIC_hdr shdr;
#define BPL 20	/* bytes to display per line */
{   char *cp,*ep;
    int bpl;		/* bytes per display line */
	bpl=0;
	for(cp=sl,ep=sl+shdr.bpl; cp!=ep; cp++) {
		fprintf(stderr,"%o ",0377&(*cp));
		if((++bpl)%BPL==0) fprintf(stderr,"\n   ");
		};
	if((bpl)%BPL!=0)fprintf(stderr,"\n");
	}

/* skip `y' lines, starting from current read pointer */
RIC_skip(y)
	int y;
{	lseek(RIC_fd,(long)(y*RIC_bpl),1);
	}

/* read next full line of scanner data, return status:  1 OK, 0 EOF, -1 ERR */
int RIC_line(lbpp)
	char **lbpp;
{   int stat;
	if( (stat=read(RIC_fd,RIC_bf,RIC_bpl)) == RIC_bpl) {
		*lbpp=RIC_bf;
		if(RIC_debug) err("read %d bytes from RIC_fd - OK",stat);
		return(1);
		}
	else { /* EOF or ERR */
		*lbpp=NULL;
		free(RIC_bf);
		if(RIC_debug) err("read from RIC_fd stat%d",stat);
		if((stat>=0)&&(stat<RIC_bpl)) return(0 /*EOF*/);
		else return(-1);
		};
	}

/* write a full line of scanner data, returning status:  1 OK, 0 EOF, -1 ERR */
int RIC_oline(fd,bf)
	int fd;
	char *bf;
{   int stat;
	if( (stat=write(fd,bf,RIC_bpl)) == RIC_bpl) {
		if(RIC_debug) err("wrote %d bytes to fd%d - OK",stat,fd);
		return(1);
		}
	else { /* ERR */
		err("write to fd%d stat%d",fd,stat);
		if((stat>=0)&&(stat<RIC_bpl)) return(0 /*EOF*/);
		else return(-1);
		};
	}

char *RIC_hdr_toa(hp)
	RIC_hdr *hp;
{   static char s[40];
	sprintf(s,"{res%d,%d bpl%d bx%s}\n",
		hp->res_x,hp->res_y,
		hp->bpl,
		bbx_toa(&(hp->bx)));
	return(s);
	}

0707070035351135311006640007620000050000010264170476773367400000600000007317rle.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* A rle file consists of any number of:
	`scan_line's, each of which has the form:
		(short) bytes_mny, followed by bytes_mny bytes in the form:
   			(packed short) runs_mny
				if >0, then followed by runs_mny runs
				else if ==0, then followed by:
					(packed short) blank_lines_mny skipped, -1
					(packed short) runs_mny (>0), then...
						...runs_mny runs
   A `run' is two (packed short) oxs,oxe which are
	both offset counts >=0 from the prior `?x?' (starts at 0 at left margin).
	Suppose that xs, xe are the corresponding accumulated pixel indices,
	then xs is the pixel index of the first black pixel of the run,
	and xe the pixel index of the first white pixel following the run.
   A `packed short' is a byte if its value is <128, else two bytes `HIGH' & `LOW'
	with the 0200 bit of its HIGH byte set.
   */

#define HIGH(A) ((A>>8)&0177)
#define LOW(A) (A&0377)

/* run-length-encoding constants, typedefs */

/* The following assumes a worst case page width of 17 inches (Legal page, >ISO A2)
   and worst case digitizing resolution of 400 pixels/inch (e.g. CCITT Group 4),
   for a maximum of 6800 pixels/line */
#define RLE_RUNS 3401	/* maximum no. runs in a line */
#define RLE_BYTES 6800	/* maximum no. data bytes in a rle line (enough?) */

typedef struct RLE_Run {
	short xs;	/* x-coord of first pixel in run */
	short xe;	/* x-coord of last pixel in run (NOT first following) */
	} RLE_Run;
#define Init_RLE_Run {0,0}

typedef struct DRLE_Run {
	short xs;	/* x-coord of first pixel in run */
	short xe;	/* x-coord of last pixel in run (NOT first following) */
	struct DRLE_Run *next;
	} DRLE_Run;

typedef struct RLE_Yrun {
	short y,xs,xe;
	} RLE_Yrun;
#define Init_RLE_Yrun {0,0,0}

typedef struct RLE_Line {
	short y;	/* y-coord of line */
	short len;	/* length of line in pixels (white+black) */
	short runs;	/* no. of runs */
	RLE_Run r[RLE_RUNS];
	} RLE_Line;
#define Init_RLE_Line {0,0,0,Init_RLE_Run}


typedef struct DRLE_Line {	/* dynamically allocated version */
	DRLE_Run *r;		/* first run */
	DRLE_Run *lastr;	/* last run */
	} DRLE_Line;
#define Init_DRLE_Line {0,0}

typedef struct RLE_Lines {
	int mny;
	RLE_Line *rla;	/* array of RLE_Lines */
	} RLE_Lines;
#define Init_RLE_Lines {0,NULL}
#if MAIN
RLE_Lines empty_RLE_Lines = Init_RLE_Lines;
#else
extern RLE_Lines empty_RLE_Lines;
#endif

typedef struct Transform_rlel_arg {
	boolean ident;	/* if T, then no change (speed-optimization) */
	Bbx tr;		/* trim:  select just this window of input */
	Sp off;		/* offset:  translate by off.x,off.y */
	Pp scl;		/* scale:  X & Y expansion factors (about 0,0) */
	Sp wh;		/* truncate:  exact maximum output width,height */
	Radians rot;	/* rotate:  angle (multiple of PI/4) */
	boolean rev;	/* reverse:  swap black and white */
	int sy;		/* next integer line no. to write */
	double dy;	/* next real line no. to write */
	} Transform_rlel_arg;
#define Init_Transform_rlel_arg {T,Init_Bbx,Init_Zero_Sp,{1.0,1.0},Init_Zero_Sp,0.0,F,0,0.0}
#if MAIN
Transform_rlel_arg empty_Transform_rlel_arg = Init_Transform_rlel_arg;
#else
extern Transform_rlel_arg empty_Transform_rlel_arg;
#endif

#ifdef MAIN
/* these routines are found in rlelib.c */

boolean RLE_open();	/* arg: (FILE *) */
RLE_Line *RLE_line();	/* args: l,r - left,right interval */
RLE_Line *RLE_get_Line();  /*  args: l,r - left,right interval */
int RLE_run();		/* arg: (RLE_Run *) */
fwrb_rlines();		/* args: (FILE *), (RLE_Lines *) */
insert_rlel();
#endif
0707070035351135301006640007620000050000010264210476773367400001100000047356rlelib.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     T. Pavlidis - ATT-BL MH - first versions        */
/*     H. S. Baird - ATT-BL MH - first versions        */

/* rlelib.c - subroutines for writing/reading run-length-encoded format files.
   BUG:  Uses system I/O for speed, but sacrifices machine-independence:
   should use fioi.h macroes instead.
   See rle.h for summary of rle file and format of public functions.
   Writing a rle file:
	fd=creat()
	RLE_put_hdr(fd,hp)	- once: allocate buffers, write header
	RLE_put_Line(fd,lp)	- repeatedly
	RLE_close(fd)		- once: flush and deallocate buffers
   Reading a rle file:
	fd=open()
	RLE_open(fd,hp)		- once: read header, 1st line into buffer
	RLE_get_Line(l,r)	- repeatedly (on EOF, deallocates buffer)
   The user can read line-at-a-time or run-at-a-time, but should not intermix them:
        line-at-a-time:
            (RLE_Line *) RLE_get_Line(l,r) - return ptr to next line with some run
			in the interval [l,r];
			read from opened file (NULL if EOF, abort on error)
			allocates large buffer and frees it when done
        run-at-a-time:
	    int RLE_get_Run(&R) - read next run into (RLE_Run) R
			returns the line number (-1 for EOF, abort on ERROR)
			does not allocate large buffer;
			if only a few runs will be used, can be faster
 */

#include <stdio.h>
#define LIBC_INCL 1
#include "CPU.h"
#include "stdocr.h"
#include "rle.h"

#define RLE_dbg F
#define dbg_rd F
#define dbg_wr F

/* Treated as local static: */
typedef struct RLE_global {
	int fd;			/* rle file descriptor */
	boolean eof;
	int cy, cx;		/* current line no., x-coord */
	short runs, nrun;	/* no. runs, next run in current line */
	RLE_Line *lp;		/* pointer to line (malloc space) */
	int bpl;		/* maximum no. bytes in packed rle line */
	char *bf;	 	/* I/O buffer (malloc space) */
	int bfsize;		/* size of buffer */
	char *cp;		/* cur. ptr, into bf */
	} RLE_global;
#define Init_RLE_global {0,F,-1,-1,0,0,NULL,0,NULL,0,NULL}
RLE_global _RLE = Init_RLE_global;

RLE_put_hdr( fd, rhp, bufn )
    int fd;
    RIC_hdr *rhp;
    int bufn;	/* minimum number of lines to buffer locally */
{   char hdr[100];
    int stat;
	sprintf(hdr,"TYPE=rle\nWINDOW=%d %d %d %d\nRES=%d %d\n\n",
		/* use half-open WINDOW convention: l&t closed, r&b open*/
		rhp->bx.a.x,rhp->bx.a.y,rhp->bx.b.x+1,rhp->bx.b.y+1,
		rhp->res_x,rhp->res_y);
	if((stat=write(fd,hdr,strlen(hdr)))!=strlen(hdr)) {
		abort("rlelib: can't put hdr, stat %d",stat);
		};
	_RLE.fd = fd;
	_RLE.cy = rhp->bx.a.y-1;
	_RLE.bpl = rhp->bx.b.x-rhp->bx.a.x+9;	/* maximum bytes per line */
	_RLE.bfsize = bufn*_RLE.bpl;
	if((_RLE.bf=(char *)malloc(_RLE.bfsize))==NULL)
		abort("can't alloc _RLE.bf[%d]",_RLE.bfsize);
	_RLE.cp = _RLE.bf;
	}

#define PUT(A,B) { if((A)<128) *(B)++ = (A); \
		else { *(B)++ = HIGH(A) | 0200; *(B)++ = LOW(A); } \
		}

/* write out a non-blank line of runs */
RLE_put_Line(fd,rlp)
	int fd;		/* file descr (already open) */
	RLE_Line *rlp;
{   register char *bp;
    short blank_lines_mny;	/* the number of preceding blank lines, minus 1 */
    register RLE_Run *rp,*ep;
    Scoor xsofar;
    short bytes_mny;
    int stat;		/* I/O status */
	if((_RLE.bfsize-(_RLE.cp-_RLE.bf)) < _RLE.bpl) {
		/* not enough room left in buffer for worst-case line */
		RLE_flush();
		};
	/* leave space for (short) bytes_mny count */
	bp=_RLE.cp+sizeof(short);  
	if((blank_lines_mny=(rlp->y-_RLE.cy-1))>0) /* blank lines were skipped */ {
		PUT(0,bp);	/* ``0 runs'' signals blank lines */
		PUT(blank_lines_mny,bp);
		};
	_RLE.cy=rlp->y;
	PUT(rlp->runs,bp);
	xsofar=0;
	for(rp=rlp->r,ep=rp+rlp->runs; rp!=ep; rp++) {
		PUT(rp->xs-xsofar,bp);  xsofar = rp->xs;
		PUT(rp->xe-xsofar+1,bp);  xsofar = rp->xe+1;
		};
	/* go back & write no. bytes at top of line */
	*((short *) _RLE.cp) = bp-_RLE.cp-sizeof(short);
	_RLE.cp = bp;
	if(dbg_wr) err("RLE_put_Line y%d nh%d",_RLE.cy,bytes_mny-2);
	};

/* write out a set of runs */
RLE_put_Lines(fd,rlsp)
	int fd;		/* file descr (already open) */
	RLE_Lines *rlsp;
{   int i;
    RLE_Line *rlp;
	for(i=0,rlp=rlsp->rla; i<rlsp->mny; i++,rlp++)
		RLE_put_Line(fd,rlp);
	}

RLE_flush()
{   int bytes;
    int stat;
	if((bytes=(_RLE.cp-_RLE.bf))>0)
		if(stat=write(_RLE.fd,_RLE.bf,bytes)!=bytes)
			abort("can't write _RLE.bf[%d], status %d",bytes,stat);
	_RLE.cp = _RLE.bf;
	}

RLE_close(fd)
   int fd;
{	RLE_flush();
	if(_RLE.bf!=NULL) free(_RLE.bf);
	_RLE.bf = _RLE.cp = NULL;
	_RLE.bfsize = 0;
	}

/* ``open'' RLE_file for reading:
   save filedes, read header, and read first line into buffer */
boolean RLE_open( fd, hp )
	int fd;
	RIC_hdr *hp;
{	_RLE.fd = fd;
	/* read header */
	RLE_get_hdr( fd, hp );
	if(_RLE.bf!=NULL) free(_RLE.bf);
	_RLE.bfsize = _RLE.bpl;
	if((_RLE.bf=(char *)malloc(_RLE.bfsize))==NULL)
		abort("can't alloc _RLE.bf[%d]",_RLE.bfsize);
	/* read first non-blank line */
	_RLE.cy = hp->bx.a.y-1;
	if (!RLE_rdbf()) return(F);
	_RLE.eof = F;
	return(T);
	}

/* read next short from rle-line buffer, updating arg ptr */
short RLE_gshort(p)
	char **p;
{	register n;
	register char *q;
	q = *p;
	if((*q)&0200) {
		n = (((*q & 0177)<<8)&077400) | (*(q+1) & 0377);
		(*p)++;
		}
	else n = *q;
	(*p)++;
	return(n);
	}

/* system I/O variation on fgets(3), except it replaces \n with \0,
   and returns the number of chars read (including \0) */
int RLE_fgets(bf,max,fd)
	char *bf;
	int max;
	int fd;
{   char *cp;
    int stat,mny;
	cp=bf; mny=0;
	while(((stat=read(fd,cp,1))==1)&&(++mny<max)&&((*cp)!='\n')) cp++;
	if(stat!=1) return(stat);
	else if(mny>=max) return(-1);
	*cp='\0';
	return(mny);
	}

/* read ascii header from rle file, convert to RIC_hdr,
   return status:  1 OK, 0 EOF, -1 error */
int RLE_get_hdr( fd, hp )
	int fd;		/* should have been open'ed earlier */
	RIC_hdr *hp;
#define HL_MAX 80
#define HTERM "=, 	\n"	/* terminations for header words: "=,<sp><tab>" */
{   char *cp,*parm,hline[HL_MAX];
    int status,nrd;
	if((status=RLE_fgets(hline,HL_MAX,fd))<=0) return(status);
	while(strlen(hline)>1) {
		if(RLE_dbg) err("hline \"%s\"",hline);
		parm=strtok(hline,HTERM);
		if(parm!=NULL&&strcmp(parm,"TYPE")==0) {
			if((parm=strtok(0,HTERM))!=NULL
				&&strcmp(parm,"rle")==0) ;
			else return(-1);
			}
		else if(parm!=NULL&&strcmp(parm,"WINDOW")==0) {
			/* assume half-open WINDOW: l&t closed, r&b open */
			if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.x=atoi(parm);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) hp->bx.a.y=atoi(parm);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.x=atoi(parm)-1;
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) hp->bx.b.y=atoi(parm)-1;
			else return(-1);
			}
		else if(parm!=NULL&&strcmp(parm,"RES")==0) {
			if((parm=strtok(0,HTERM))!=NULL) hp->res_x=atoi(parm);
			else return(-1);
			if((parm=strtok(0,HTERM))!=NULL) hp->res_y=atoi(parm);
			else return(-1);
			}
		else return(-1);
		if((status=RLE_fgets(hline,HL_MAX,fd))<=0) return(status);
		};
	/* maximum possible no. bytes in a packed rle line */
	_RLE.bpl = hp->bpl = hp->bx.b.x-hp->bx.a.x+9;
	if(dbg_rd) fprintf(stderr,"rlelib: RLE_get_hdr: %s\n",RIC_hdr_toa(hp));
	return(1);
	}

/* read the next run into *Rp, and return line number
   (-1 for EOF, abort on error) */
int RLE_get_Run( Rp )
	RLE_Run *Rp;
{	if(_RLE.nrun >= _RLE.runs) {	/* no more, try to read next line */
		if (!RLE_rdbf()) /* EOF */ return(-1); 
		};
	/* another run */
	Rp->xs = (_RLE.cx += RLE_gshort(&_RLE.cp));
	Rp->xe = (_RLE.cx += RLE_gshort(&_RLE.cp)) - 1;
	_RLE.nrun++;
	return(_RLE.cy);
	}

/* Return ptr to the next line with at least one run overlapping the margins
   [lm,rm]. The reported runs are not trimmed to fit exactly within margins.
   If no more lines, return NULL.  On error, abort */
RLE_Line *RLE_get_Line(lm,rm)
	int lm, rm;		/* left, right margins */
{	register int rr;	/* runs read */
	register RLE_Run *rp;	/* write ptr */

	do {	if(_RLE.eof) {
			free(_RLE.lp);  _RLE.lp = NULL;
			free(_RLE.bf);  _RLE.bf = NULL;
			return(NULL);
			};
		if(_RLE.lp==NULL) { /* allocate space for RLE_Line */
			_RLE.lp = (RLE_Line *) malloc(sizeof(RLE_Line));
			if(_RLE.lp==NULL) {
				abort("rlelib:  can't malloc RLE_Line (%d bytes)",
					sizeof(RLE_Line));
				};
			};
		_RLE.lp->y = _RLE.cy;
		/* guaranteed to be at least one run in line */
		rr=0;  rp=_RLE.lp->r;  _RLE.lp->runs=0;
		/* skip runs that are outside left margin */
		do	RLE_get_Run(rp);
		while((rr++ < _RLE.runs) && (rp->xe < lm));
		/* accept runs until cross right margin */
		while(rp->xs <= rm) {
			_RLE.lp->runs++;	/* count accepted runs */
			if(rr++ >= _RLE.runs) break;
			RLE_get_Run(++rp);
			};
		/* look ahead to next line */
		if (!RLE_rdbf()) /* EOF */ _RLE.eof=T;
		}
	while(_RLE.lp->runs==0);	/* as result of margins, some lines may empty */
	return(_RLE.lp);
	}

/* read next line buffer - return F if EOF, abort on error
   sideffects:  sets up _RLE.cp, _RLE.cy, _RLE.cx, _RLE.runs, _RLE.nrun */
boolean RLE_rdbf()
{   short nh;
	if(dbg_rd) err("enter RLE_rdbf");
	/* get number of bytes holding RLE of a scan line */
	if( read(_RLE.fd,&nh,sizeof(short)) != sizeof(short)) {
		return(F); /* normal EOF */
		};
	if( Readvax )
		nh = swapshortin( nh );
	if(dbg_rd) err("rlelib: RLE_rdbf: nh %d",nh);
	if(nh > _RLE.bpl) {
		abort("rlelib: too many bytes in line: %d > %d(_RLE.bpl)",
			nh,_RLE.bpl);
		};

	/* get those bytes */
	if( read(_RLE.fd,_RLE.bf,nh) != nh) {
		abort("rlelib: rle line truncated");
		};
	if(dbg_rd) {
		int bi;
		err("rlelib: RLE_rdbf: _RLE.bf[0-%d] octal:",nh-1);
		for(bi=0;bi<nh;bi++)
			fprintf(stderr," 0%o",0377&(_RLE.bf[bi]));
		fprintf(stderr,"\n");
		};

	/*	decode the bytes	*/
	_RLE.cp = _RLE.bf;
	_RLE.runs = RLE_gshort(&_RLE.cp);
	if(dbg_rd) err("rlelib: _RLE.runs %d",_RLE.runs);
	if(_RLE.runs==0) {	/* blank lines seen */
		_RLE.cy += RLE_gshort(&_RLE.cp);
		_RLE.runs = RLE_gshort(&_RLE.cp);
		if(dbg_rd)
			err("rlelib: _RLE.cy %d _RLE.runs %d",_RLE.cy,_RLE.runs);
		};
	if(_RLE.runs>RLE_RUNS || _RLE.runs<1) {
		abort("rlelib: illegal no. runs %d in line",_RLE.runs);
		};
	_RLE.cy++;
	if(dbg_rd) err("rlelib: RLE_rdbf: _RLE.runs %d _RLE.cy %d",_RLE.runs,_RLE.cy);
	_RLE.cx = _RLE.nrun = 0;	/* next run will be first */
	if(dbg_rd) err("rlelib: RLE_rdbf: T exit");
	return(T);
	}

/* brrl - compute a binary raster line from a run-length-encoded scanline.
   runa[] is an array of shorts, grouped in pairs (xs,xe) to describe the starting
   and ending index (inclusive) of each run of black pixels (1 bits).
   xe >= xs > xe.  The runs are in strictly ascending order on xs.
   lm & rm are the left and right margin indices of pixels, outside of which the
   pixels are forced to be white.  rm >= lm.  The `lm'th pixel is written
   into the `olm'th bit of the output raster (olm>=0).
   rasp[] is a raser line of chars; on entry, it is assumed to have been zeroed
   out.  rasp[0] holds the  leftmost byte in the line and the 001 bit of each
   byte is the leftmost bit in that byte.
   The user must ensure that rasp[] is at least (rm-lm+olm+9)/8 bytes long.
   Returns the number of black pixels in the raster line.
   NOTE:  this uses the ``little-endian'' convention, in which the leftmost pixel
   in a byte is placed in the least-significant bit (0x01).  See `brrlb()' below
   for the alternative ``big-endian'' version.
   */
int brrl(runs,runa,lm,rm,olm,rasp)
    int runs;		/* number of run-segments in runa[] */
    short runa[];	/* array of run-segments [xs,xe] (pairs of short) */
    int lm,rm;		/* left,right margin bit indices within raster */
    int olm;		/* `lm'th input pixel will be written to `olm'th bit */
    char unsigned rasp[];	/* binary raster line (zeroed out on entry) */
{   int pixels,bi;
    RLE_Run r,*rp,*re;
	pixels = 0;
	re = (rp = (RLE_Run *) runa) + runs;
	while(rp<re && rp->xe<lm) rp++; 	/* skip runs to the left of 'lm' */
	while(rp<re && rp->xs<=rm) {
		/* truncate to margins */
		if((r.xs = rp->xs)<lm) r.xs = lm;
		if((r.xe = rp->xe)>rm) r.xe = rm;
		/* shift to output indices */
		r.xs += olm-lm;   r.xe += olm-lm;
		/** SLOW **/
		for(bi=r.xs; bi<=r.xe; bi++) rasp[bi/8] |= (01)<<(bi%8);
		pixels += r.xe-r.xs+1;
		rp++;
		};
	return(pixels);
	}

/* ``big-endian'' version of brrl:  bits are packed so that the leftmost
   pixel is placed in the high-order bit (0x80) of each byte.
   */
int brrlb(runs,runa,lm,rm,olm,rasp)
    int runs;
    short runa[];
    int lm,rm,olm;
    char unsigned rasp[];
{   int pixels,bi;
    RLE_Run r,*rp,*re;
	pixels = 0;
	re = (rp = (RLE_Run *) runa) + runs;
	while(rp<re && rp->xe<lm) rp++; /* skip runs to the left of 'lm' */
	while(rp<re && rp->xs<=rm) {
		/* truncate to margins */
		if((r.xs = rp->xs)<lm) r.xs = lm;
		if((r.xe = rp->xe)>rm) r.xe = rm;
		/* shift to output indices */
		r.xs += olm-lm;   r.xe += olm-lm;
		/** SLOW **/
		for(bi=r.xs; bi<=r.xe; bi++) rasp[bi/8] |= (0200)>>(bi%8);
		pixels += r.xe-r.xs+1;
		rp++;
		};
	return(pixels);
	}

/* crrl - compute a character raster line from a run-length-encoded scanline.
   runa[] is an array of shorts, grouped in pairs (xs,xe) to describe the starting
   and ending index (inclusive) of each run of black pixels (1 bits): xs<=xe.
   The runs are in strictly ascending order on xs.  lm & rm are the left and
   right margin indices, outside of which pixels are forced to be white.  rm >= lm.
   rasp[] is a raster line, one unsigned char per pixel; rasp[0] holds the
   leftmost pixel.  The user must ensure that rasp[] is at least (rm-lm+1)
   bytes long.  Black pixels are encoded as 0, white as 255.  Returns the number
   of black pixels in the raster line.
   */
#define WHITE_pel 0377
#define BLACK_pel 0000
int crrl(runs,runa,lm,rm,rasp)
    int runs;		/* number of run-segments in runa[] */
    short runa[];	/* array of run-segments [xs,xe] (pairs of short) */
    int lm,rm;		/* left,right margin bit indices within raster */
    unsigned char rasp[];	/* char raster line */
{   int pixels,bi,wid;
    RLE_Run r,*rp,*re;
    unsigned char *cp,*ep;
	wid=rm-lm+1;
	memset(rasp,WHITE_pel,wid);
	re = (rp = (RLE_Run *) runa) + runs;
	while(rp<re&&rp->xe<lm) rp++; 	/* skip runs to the left of 'lm' */
	if(rp>=re) return(0);

	r = *rp;  r.xs -= lm;  r.xe -= lm;
	pixels = 0;
	do {	/* truncate left,right margin */
		if(r.xs<0) r.xs = 0;
		if(r.xe>(wid-1)) r.xe = wid-1;
		/* write r into raster line */
		pixels += (r.xe-r.xs+1);
		for(cp=rasp+r.xs,ep=rasp+r.xe; cp<=ep; cp++) *cp = BLACK_pel;
		/* step to next run */
		r = *(++rp);  r.xs -= lm;  r.xe -= lm;
		}
	while(r.xs<=(wid-1)&&rp<re);
	return(pixels);
	}

/* trcr - threshold & run-length-encode a char raster line.  `rasp' is a raster
   line, one unsigned char per pixel: rasp[0] is the leftmost pixel in the line.
   Pixels with value < 'thresh' are translated to black, else white.  
   Analyzes the line into a series of runs of `1's, placing them into array
   `runs'.  Observes margins:  starts at `lm' bit and continues through `rm';
   bits outside the margins are assumed 0.   A `run' is two shorts (the starting &
   ending indices of the run of `1's, inclusive).  The indices are shifted
   so that the `lm'th pixel goes to run index `olm'.  Returns the number of runs.
   NOTE:  The user must ensure that: (1) margins fall within `rasp[]';
   (2) `runp[]' is big enough to hold the worst-case no. of runs that can result
   ((rm-lm+2)/2).  The contents of the raster-line are unmodified.
   */
int trcr(rasp,lm,rm,olm,thresh,runp)
    char unsigned rasp[];	/* binary raster line (with 1 extra byte at end) */
    int lm,rm;	/* left,right margin indices within raster */
    int olm;	/* `lm' pixel goes to `olm' run index */
    int thresh;
    short runp[];	/* array of run-segments [xs,xe] (pairs of short) */
#define dbg_trcr (T)
{   unsigned char *cp,*ep;
    short x,*xp;
    int cv,pv;	/* current,prior binary pixel value */
	ep=(cp=rasp+lm)+rm;  x=olm;  xp=runp;
	pv=0;	/* assume pixels left of 'lm' are 0 */
	while (cp<=ep) {
		if((*cp)<thresh) {
			/* black pixel */
			cv=1;
			if(pv==0) { *xp = x; xp++; };
			}
		else {	/* white pixel */
			cv=0;
			if(pv==1) { *xp = x-1; xp++; };
			};
		pv=cv;  x++;
		cp++;
		};
	if(pv==1) { *xp = x-1; xp++; };	/* assume pixels right of 'rm' is 0 */
	return((xp-runp)/2);
	}

/* Transform a sequence of rle-lines using trimming, offsetting, scaling,
   truncation, and reverse-video.  Scaling may lead to interpolation or
   decimation of lines, so an input line may be mapped into 0, 1, or more
   output lines.
   Input lines may be buffered, and there may be latency.  To flush buffers,
   this must be called with NULL argument at end of the sequence.  Each output
   line will be passed to function `sink()', which returns 1 if OK and 0 to quit.     Quits are passed back immediately with no latency.  Sink's 1st arg RLE_Line
   *l is a line of runs in output coordinates, whose `len' is the maximum length
   of the line.  l==NULL means end of sequence.
   Return 1 if OK, 0 to quit.   A copy of *l is passed to sink().
   a->sy is incremented for every line written to the sink, and is attached to
   the output lines as *.y.
   */
int transform_rlel(l,a,sink,sa)
    RLE_Line *l;	/* NULL if end of sequence */
    Transform_rlel_arg *a;
    int (*sink)();	/* takes args:  (RLE_Line *), and int */
    VOID *sa;		/* passed to sink() as 2nd arg */
{   RLE_Line m,r;
    register RLE_Run *rp,*ep,*mp;
    RLE_Run mr,mm,rr;
    int rm;
    int o_a_x,o_b_x;	/* maximum output index */
	if(l==NULL) {
		sink(NULL,sa);
		return(1);
		};
	m.len = l->len;
	m.runs = l->runs;
	if(a->ident) {
		if(m.runs>0) memcpy(m.r,l->r,2*m.runs*sizeof(short));
		m.y = a->sy;
		if(sink(&m,sa)==0) return(0);
		else {	a->sy++;
			return(1);
			};
		};
	/* maximum permissable output bounds */
	o_a_x = (int)((a->tr.a.x + a->off.x)*a->scl.x);
	o_b_x = o_a_x + a->wh.x - 1;
	if(a->sy<=((int)a->dy)) {
		/* compute runs to be ouput: rp - input runs; mp - output runs*/
		mp=(m.r - 1);
		for(ep=(rp=l->r)+l->runs; rp<ep; rp++) {
			/* trim using a->tr */
			mr = *rp;
			if(mr.xe < a->tr.a.x) /* off left margin */ continue;
			if(mr.xs > a->tr.b.x) /* off right margin */ break;
			if(mr.xs < a->tr.a.x) /* extends left too far */
				mr.xs=a->tr.a.x;
			if(mr.xe > a->tr.b.x) /* extends right too far */
				mr.xe=a->tr.b.x;

			/* offset using a->off */
			mr.xs += a->off.x;
			mr.xe += a->off.x;

			/* expand using a->scl */
			mr.xs = (int)(mr.xs*a->scl.x);
			mr.xe = ((int)((mr.xe+1)*a->scl.x))-1;
			if(mr.xe<mr.xs) mr.xe=mr.xs;

			/* truncate to maximum output width */
			if(mr.xe<o_a_x) /* off left margin */ continue;
			if(mr.xs>o_b_x) /* off right margin */ break;
			if(mr.xs<o_a_x) /* extends left too far */ mr.xs=o_a_x; 
			if(mr.xe>o_b_x) /* extends right too far */ mr.xe=o_b_x;
			/* store */
			if(mp < m.r) /* first */ *(++mp) = mr;
			else /* can merge with prior run? */ {
				if(mp->xe >= (mr.xs-1)) /* yes */ mp->xe = mr.xe;
				else /* no */ *(++mp) = mr;
				};
			};
		m.runs = mp - m.r + 1;
		m.len = a->wh.x;
		do {	m.y = a->sy;
			if(a->rev) {
				/* r = reverse-video(m) */
				rp=r.r;  rr.xs=o_a_x;
				for(ep=(mp=m.r)+m.runs; mp<ep; mp++) {
					if(rr.xs<mp->xs) {
						rr.xe=mp->xs-1;
						*(rp++)=rr;
						};
					rr.xs=mp->xe+1;
					};
				if(rr.xs<=o_b_x) {
					rr.xe=o_b_x;
					*(rp++)=rr;
					};
				r.runs = rp-r.r;
				r.len = m.len;
				r.y = m.y;
				if(sink(&r,sa)==0) return(0);
				}
			else {	if(sink(&m,sa)==0) return(0); };
			a->sy++;
			}
		while(a->sy<=((int)a->dy));
		};
	a->dy += a->scl.y;
	return(1);
	}

/* Insert a (copy of) the given RLE_Line in the RLE_Lines */
insert_rlel(rlp,rlsp)
    RLE_Line *rlp;
    RLE_Lines *rlsp;
{	abort("insert_rlel:  unimplemented");
	}

err_RLE_line(s,rl)
    char *s;		/* name */
    RLE_Line *rl;
{   RLE_Run *r;
    int ri;
	if(rl==NULL) fprintf(stderr,"RLEL %10s NULL\n",s);
	else {	fprintf(stderr,"RLEL %10s y%d r%d l%d: ",
				s,rl->y,rl->runs,rl->len);
		for(ri=0,r=rl->r;ri<rl->runs;ri++,r++)
			fprintf(stderr,"[%d,%d] ",r->xs,r->xe);
		fprintf(stderr,"\n");
		};
	}

0707070035351135271006640007620000050000010264220476773367400001100000047346stdocr.h/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     H. S. Baird - ATT-BL MH - first versions        */
/* stdocr.h -- conventional OCGR constants, typedefs, and file formats
 NOTE: sensitive to prior:
	`#define MAIN 1'
	`#define CPU ?'
	`#define OS ?' */

extern int errno;	/* UNIX system call error number */

#ifndef MAIN
#define MAIN 0
#endif

#define FWRI (T)	/* use machine-independent format for dim-file writes */
#define FRDI (T)	/* use machine-independent format for dim-file reads */

#ifndef PI
#define PI 3.1415926535
#endif

extern int Readvax;	/* T. Thompson flag:  see Coord.c */

#include "limits.h"	/* machine-dependent numeric extreme values */
#include "fioi.h"	/* machine-independent types and binary I/O */
#include "boole.h"	/* boolean type */
#include "Units.h"	/* OCR-specific units */
#include "Coord.h"	/* scanner coordinates & basic geometry */
#include "ric.h"	/* ricoh scanner page & file formats */

/* 5620 dimensions, in dots */
#define Width5620 800
#define Height5620 1024

/* used (in clc.c) to compute absolute maximum value of natural 
   log values used in Bayesian binary weights */
#define LOG_ABS_MAX 3.0

#define Merit float		/* heuristic ``merit'' takes on values in [0,1] */
/* machine-independent I/O:  range [0.0-1.0], precision .0000153 */
#define fwri_Merit(F,V) fwri_uint2((F),((V)*USHRT_MAX))
#define frdi_Merit(F) (frdi_uint2(F)/(Merit)USHRT_MAX)

#define Prob float		/* ``probability'' takes on values in [0,1] */
/* machine-independent I/O:  range [0.0-1.0], precision .0000153 */
#define fwri_Prob(F,V) fwri_uint2((F),((V)*USHRT_MAX))
#define frdi_Prob(F) (frdi_uint2(F)/(Prob)USHRT_MAX)

#define Pts float		/* text-size units: ``points'' (1/72) inch */
/* machine-independent I/O:  range [0,655.36], precision 0.01 ([0,9.1] inches) */
#define fwri_Pts(F,V) fwri_uint2((F),((V)*100.0))
#define frdi_Pts(F) (frdi_uint2(F)/100.0)

#define Ems float		/* em-space units */
/* machine-independent I/O:  range [-32.768,32.767], precision 0.001 */
#define fwri_Ems(F,V) fwri_int2((F),((V)*1000.0))
#define frdi_Ems(F) (frdi_int2(F)/1000.0)

/* class name - long enough to be a unix file name */
#define Cln_len (14)		/* maximum no. chars (DIRSIZ in some UNIX's) */
#define Cln_lenp (Cln_len+1)	/* maximum size of array */
typedef char Cln[Cln_lenp];
#define fwri_Cln(F,S) fwri_str((F),(S))
#define frdi_Cln(F,S) frdi_strn((F),(S),Cln_lenp)

/* font name */
#define Fontn_len (Cln_len)		/* maximum no. chars */
#define Fontn_lenp (Cln_lenp)		/* maximum size of array */
typedef char Fontn[Fontn_lenp];
#define fwri_Fontn(F,S) fwri_str((F),(S))
#define frdi_Fontn(F,S) frdi_strn((F),(S),Fontn_lenp)

typedef struct ClassId {
	Fontn f;	/* font name */
	Pts s;		/* size in points */
	Cln c;		/* printable symbol name (``class-name'') */
	short v;	/* symbol variant no. 0,1,... */
	} ClassId;

#define Init_ClassId {"",0.0,"",0}
#if MAIN
ClassId empty_ClassId = Init_ClassId;
#else
extern ClassId empty_ClassId;
#endif
char *classid_toa();	/* in chcln.c */
#define eq_classid(a,b) ((!strcmp((a).f,(b).f))&&((a).s==(b).s)&&(!strcmp((a).c,(b).c))&&((a).v==(b).v))

#define fwri_ClassId(F,P) { \
	fwri_Fontn((F),(P)->f); \
	fwri_Pts((F),(P)->s); \
	fwri_Cln((F),(P)->c); \
	fwri_uint1((F),(P)->v); \
	}
#define frdi_ClassId(F,P) ( feof(F)? 0: ( \
	frdi_Fontn((F),(P)->f), \
	(P)->s=frdi_Pts(F), \
	frdi_Cln((F),(P)->c), \
	(P)->v=frdi_uint1(F), \
	(ferror(F)? -errno: 1) ) )

/* Convert variant no. to ASCII character, and vice versa */
#define vtoc(V) (((V)<=9)?('0'+(V)):(((V)<=35)?('a'+((V)-10)):('A'+((V)-36))))
#define ctov(C) ((((C)>='0')&&((C)<='9'))?((C)-'0'):((((C)>='a')&&((C)<='z'))?(10+((C)-'a')):(36+((C)-'A'))))

/* parametric values: */
#define Pval float
/* machine-independent I/O:  precision 0.0001 & range [-838.8608,838.8607] */
#define fwri_Pval(F,V) fwri_int4((F),(V)*1000.0)
#define frdi_Pval(F) (frdi_int4(F)/1000.0)

typedef struct {	/* parametric point */
	Pval x;
	Pval y;
	} Pp;

#define Init_Zero_Pp {0.0,0.0}
#if MAIN
Pp zero_Pp = Init_Zero_Pp;
#else
extern Pp zero_Pp;
#endif

#define fwri_Pp(F,P) { fwri_Pval((F),(P)->x); fwri_Pval((F),(P)->y); }
#define frdi_Pp(F,P) ( feof(F)? 0: ( \
	(P)->x=frdi_Pval(F), \
	(P)->y=frdi_Pval(F), \
	(ferror(F)? -errno: 1) ) )

/* metrics:  ABSS, EUCL, MAXV */
#define ABSS 'a'
#define EUCL 'e'
#define MAXV 'm'
typedef short Metric;

#define fwri_Metric(F,V) fwri_ch((F),(V))
#define frdi_Metric(F) (frdi_ch(F))

/* a vectorized blob file is a sequence of blob-descriptions.
   a blob-description is a sequence of "vector" records; there are two
   types of blob descriptions:
	DOT:
		'D'-vector (with bounding box)
	CHAR:
		'C'-vector, followed by:
			one 'B'-vector (bounding-box), and
			any number of: 'S' (stroke),
				       'G' (edge),
				       'O' (hole),
			               'A' (arc),
				       'C' (corner),
				       'P' (end-point), and
				       'V' & 'W' (boundary angles - 1 each),
			and terminated with one 'E' vector (giving classname)
   */

#define Vrec_len 5
typedef short Vrec[Vrec_len];
   
/* subshape values */
/* #define U 0     uninitialized */
#define NA (SHRT_MAX)	/* deliberately not-assigned (classifier failure) */

#define Dim short	/* specifies dimension 1,..,MaxDim */
#define MaxDim 4

#define fwri_Dim(F,V) fwri_uint1((F),(V))
#define frdi_Dim(F) (frdi_uint1(F))

#define Seq int		/* sequence nos;  indices into tables */
#define FISeq 0		/* first value */
#define NLSeq -1	/* conventional NULL value */
#define S1Seq 0200000000  /* special bit 1 of Seq */
#define S2Seq 0100000000  /* special bit 2 of Seq */
#define NSSeq 0077777777  /* non-special bits */

#define fwri_Seq(F,V) fwri_int4((F),(V))
#define frdi_Seq(F) (frdi_int4(F))

typedef short Liv;	/* limit value: scaled and truncated from floating-pt */
#define Liv_MAX (SHRT_MAX)
#define Liv_MIN (SHRT_MIN)

#define fwri_Liv(F,V) fwri_int2((F),(V))
#define frdi_Liv(F) (frdi_int2(F))

typedef short Lit;	/* limit type, two flavors: */
#define MN 0		/* 	min:  MN < v */
#define MX 1		/*	max:  v <= MX */

typedef Liv Ivl[2];	/* interval:  ( Ivl[MN], Ivl[MX] ] */

typedef Ivl Rec[MaxDim];   /* rectangular parallelopiped of limits in DIM-space */

/* a normalized blob file is a sequence of:
	Nb_h	header, followed by Nb_h.ss of:
		Nb_s	contour shapes */
typedef struct {
	ClassId ci;	/* class name */
	Bbx bb;		/* bounding box */
	Pval rsz;	/* raw character size (Ems) */
	Pval bht;	/* height-above-baseline (Ems) */
	Pval rwd;	/* width (Ems) */
	Pval rar;	/* area (square-Ems) */
	Pval rpe;	/* perimiter (Ems) */
	Pval asp;	/* aspect ratio (h/w) */
	Pval blk;	/* fraction of Bbx area that is black */
	Pval per;	/* perimeter of blob as multiple of Bbx perim */
	Pval gale;	/* Gale's feature:  incl. angle 'tween 2 longest sides */
	short ss;	/* no. of shapes to follow */
	} Nb_h;

#define MAX_SHAPES_EACH	1024	/* Max no. shapes per Blob/Char/item */

/* Shape is tiny (below threshold, may be pruned):  a flag ORed into shape type */
#define Sh_tiny (0x80)

/* Shape types: */
#define U 0	/* uninitialized */
#define Sh_FI 1	/* first shape no. */
#define Sh_B 1	/* blob (connected black region) */
#define Sh_H 2	/* hole (connected white region) */
#define Sh_S 3	/* stroke (undirected line-segment) */
#define Sh_E 4	/* edge (directed line-segment along boundary) */
#define Sh_C 5  /* concavity (intrusion from convex hull): its `cover' edge */
#define Sh_D 6  /* direction and depth of concavity */
#define Sh_A 7	/* locally-maximal convex arc (encloses black) */
#define Sh_V 8  /* locally-maximal concave arc (encloses white) */
#define Sh_P 9	/* endpoint (0-junction) */
#define Sh_T 10	/* detail (left- and right-facing ticks) */
#define Sh_X 11 /* crossing (X) */
#define Sh_Y 12 /* global scalar variables, combined */
#define Sh_Z 13 /* more global scalar variables, combined */
#define Sh_LA 13 /* last of variable-no-of-occurences shape-types */
#define Sh_MNY (Sh_LA+1)
#define SHS_MNY (Sh_MNY)

#if (MAIN)
	/* shape-names, given shape-type */
	char Sh_nam[SHS_MNY] =
	{'U', 'B', 'H', 'S', 'E', 'C', 'D', 'A', 'V', 'P', 'T', 'X', 'Y', 'Z'};
	/* "dimension" -- no parameters in normalized form */
	short Sh_dim[SHS_MNY] =
	{ 0,   3,   3,   4,   4,   4,   4,   4,   4,   4,   3,   2,   3,   1};
	/* absolute minimum parametric values possible -- must be >= -1.0
	   (see norm.c & fiodict.c) */
	Pval Sh_MN[SHS_MNY][MaxDim]
		   = { { 0.0,  0.0,  0.0,  0.0},	/* U */
		       {-0.5, -0.5, -0.5/*see mkd*/},   /* B */
		       {-0.5, -0.5, -0.5/*see mkd*/},   /* H */
		       {-0.5, -0.5, -0.5, -0.5},	/* S */
		       {-0.5, -0.5, -0.5, -0.5},	/* E */
		       {-0.5, -0.5, -0.5, -0.5},	/* C */
		       {-0.5, -0.5, -0.5, -0.5},	/* D */
		       {-0.5, -0.5, -0.5, -0.5},	/* A */
		       {-0.5, -0.5, -0.5, -0.5},	/* V */
		       {-0.5, -0.5, -0.5, -0.5},	/* P */
		       {-0.5, -0.5, -0.5},  		/* T */
		       {-0.5, -0.5},  			/* X */
		       {-0.5, -0.5, -0.5},	  	/* Y */
		       {-0.5}			  	/* Z */
			 };
	/* absolute maximum parametric value possible -- must be <= 1.0
	   (see norm.c & fiodict.c) */
	Pval Sh_MX[SHS_MNY][MaxDim]
		   = { { 0.0,  0.0,  0.0,  0.0},	/* U */
		       {0.5, 0.5, 1.0/*see mkd*/},      /* B */
		       {0.5, 0.5, 1.0/*see mkd*/},      /* H */
		       {0.5, 0.5, 0.5, 0.5},	        /* S */
		       {0.5, 0.5, 0.5, 0.5},	        /* E */
		       {0.5, 0.5, 0.5, 0.5},	        /* C */
		       {0.5, 0.5, 0.5, 0.5},	        /* D */
		       {0.5, 0.5, 0.5, 0.5},	        /* A */
		       {0.5, 0.5, 0.5, 0.5},	        /* V */
		       {0.5, 0.5, 0.5, 0.5},	        /* P */
		       {0.5, 0.5, 0.5},  		/* T */
		       {0.5, 0.5},  			/* X */
		       {0.5, 0.5, 0.5},	  		/* Y */
		       {0.5}			  	/* Z */
			 };
	/* minimum magnitude of (r,i) part of certain shapes */
	Pval A_ri_minmag = 0.25;
	Pval P_ri_minmag = 0.25;
#else
	extern char Sh_nam[];
	extern short Sh_dim[];
	extern Pval Sh_MN[][MaxDim];
	extern Pval Sh_MX[][MaxDim];
	extern Pval A_ri_minmag;
	extern Pval P_ri_minmag;
#endif

#define MIN_SD 0.001	/* minimum std-dev permitted */

typedef Pval Spar[MaxDim];	/* shape parameters */

typedef struct Nb_s {
	short t;	/* shape type: one of U S O A C etc, perhaps |Sh_tiny */
	Spar p;		/* parametric values */
	} Nb_s;

/* indices into parametric values */
/* blobs */
#define B_x 0	/* (x,y) location of dot wrt bounding-box */
#define B_y 1
#define B_r 2	/* size of dot */
/* holes */
#define H_x 0	/* (x,y) location of center wrt bounding-box */
#define H_y 1
#define H_r 2	/* size of hole */
/* strokes */
#define S_x 0	/* (x,y) location of stroke center wrt bounding box */
#define S_y 1
#define S_r 2	/* (r,i) real-imag parts of rotation-length vector; */
#define S_i 3   /*   rotation angle *2 since strokes have only [0,PI] range */
/* edges */
#define E_x 0	/* (x,y) location of edge center wrt bounding box */
#define E_y 1
#define E_r 2	/* (r,i) real-imag parts of direction-length vector */
#define E_i 3 
/* concavity hull edge */
#define C_x 0	/* (x,y) location of center of hull-bdy edge wrt bounding-box */
#define C_y 1
#define C_r 2	/* (r,i) real-imag parts of hull-bdy edge */
#define C_i 3
/* concavity depth & direction */
#define D_x 0	/* (x,y) location of center of depth & direction vector */
#define D_y 1
#define D_r 2	/* (r,i) real-imag parts of depth & direction vector */
#define D_i 3
/* locally-maximal convex arc */
#define A_x 0	/* (x,y) location of center of enclosed area */
#define A_y 1
#define A_r 2	/* (r,i) real-imag parts of `incompleteness' vector */
#define A_i 3
/* locally-maximal concave arc */
#define V_x 0	/* (x,y) location of center of enclosed area */
#define V_y 1
#define V_r 2	/* (r,i) real-imag parts of `incompleteness' vector */
#define V_i 3
/* endpoint */
#define P_x 0	/* (x,y) location of center of hull-bdy wrt bounding-box */
#define P_y 1
#define P_r 2	/* (r,i) real-imag parts of direction-depth vector */
#define P_i 3
/* ticks:  left-, right-, top-, & bottom-facing extrema near ends */
#define T_x 0	/* signed distance from centroid along principal axis */
#define T_y 1	/* signed perpendicular distance from axis */
#define T_a 2	/* angle of principal axis, within worst-case range */
/* crossings */
#define X_x 0	/* (x,y) location of crossing wrt bounding-box */
#define X_y 1
/* global scalars, combined */
#define Y_a 0	/* log(aspect_ratio=hgt/wid) */
#define Y_b 1	/* ratio of area to bbx_area */
#define Y_p 2	/* ratio of perimeter to bbx_perimeter */
/* global scalars, combined (more) */
#define Z_g 0	/* Gale's feature: included angle between two longest bdy edges */

/* scalar features field indices */
#define SF_RSZ 0	/* relative size (height in ems) */
#define SF_BHT 1	/* height above baseline (ems) */
#define SF_RWD 2	/* relative width (ems) */
#define SF_RAR 3	/* relative area (square-ems) */
#define SF_RPE 4	/* relative perimeter (ems) */
#define SF_ASP 5	/* aspect-ratio */
#define SF_BLK 6	/* fraction of Bbx that is black */
#define SF_PER 7	/* ratio of perimeter to BBx per */
#define SF_GALE 8	/* Gale's feature: incl. ang. between 2 longest edges */
#define SF_N 8		/* index of last var that's not an occurrence-count */
#define SF_MNY (SF_N+Sh_LA+1)

#if MAIN
	/* ``Is this feature available early enough to be used in fast scalar-
	   feature preclassifier?'' (Must not depend on shape analysis.) */
	boolean SFfeature[SF_MNY] = {
		F, F, F, F, F, T, T, T, F,
		T, T, T, T, T, T, T, T, T, T, T, F, F };
	/* ``Is this feature discrete (integer-valued)?'' (Affects construction
	   of scalar-decision tree preclassifier.) */
	boolean SFdiscrete[SF_MNY] = {
		F, F, F, F, F, F, F, F, F,
		T, T, T, T, T, T, T, T, T, T, T, T, T };
#else
	extern boolean SFfeature[];
	extern boolean SFdiscrete[];
#endif

typedef Pval SFv[SF_MNY];

/* blob tracer (boundary angles) features field indices */
#define TR_MNY 8

typedef Pval TRv[TR_MNY];

/* tracer decision-tree header */
typedef struct TRtr {
	struct SFdnode *TRd;	/* array of decision-nodes */
	struct Cl ***clist;	/* list of (class-ptr)-lists */
	} TRtr;

/* Ss - sub-shape list-item */
typedef struct Ss {
	Seq seq;	/* globally unique sequence no */
	Seq shs;	/* shape-hdr seq no */
	Seq cls;	/* class sequence no */
	short no;	/* sub-shape number (0,1,2..., NA) */
	float focc;	/* fraction of training set w/ >=1 occurrence */
	float fdup;	/* fraction of training set w/ >=2 occurrence */
	Spar me;	/* mean parameters */
	Spar sd;	/* std-dev parameters */
	Spar min;	/* min limits (for fast checking) */
	Spar max;	/* max limits (for fast checking) */
	Rec r;		/* rectangular parallelopiped in Liv space */
	Pval fr;	/* fraction of training set covered */
	short nuse;	/* for current blob, no. uses */
	float nocc;	/* occurrences: no. blobs with >=1 of these */
	float ndup;	/* duplicates: no. blobs with >=2 of these */
	float mind;	/* minimum scaled distance from cluster among uses */
	float merit;	/* merit score resulting from 'nuse' matches to this */
	struct Ss *ne;	/* ptr to next in list */
	} Ss;

#define MAX_SS 8192	/* see 'kdt.h' for reasons */

/* BMask:  1-d, variable-length packed bitstring (N = no. bits).  The string
   is stored in an array of (unsigned int).  It is often accessed via a fast
   ascending sequence of 'short' pointers (unsigned short *) or (unsigned char *):
   in these cases, enough are used to completely cover all the (unsigned int)s,
   even though that may be more than enough, to ensure that the result is
   insensitive to machine-dependent short-order-in-ints and char-order-in-shorts.
      BMask_ni(N)    no. unsigned ints holding bit-data
      BMask_si(N)    no. unsigned shorts covering bit-data (exactly 2x _ni)
      BMask_ci(N)    no. unsigned chars covering bit-data (exactly 4x _ni)
      BMask_size(N)  total no. bytes in, or pointed to by BMask:
			sizeof(n) + sizeof(mny) + sizeof(r) + sizeof(malloc space) 
      */
#define BMask_ni(N) (((N)+(8*sizeof(unsigned int))-1)/(8*sizeof(unsigned int)))
#define BMask_si(N) (2*BMask_ni(N))
#define BMask_ci(N) (4*BMask_ni(N))
#define BMask_size(N) (3*sizeof(unsigned int)+(BMask_ci((N))))

typedef struct BMask {
	unsigned int n;			/* no. of bits stored (==N above) */
	unsigned int mny;		/* no. bits set to 1 */
	unsigned int r;			/* represents `r' BMasks altogether */
	union {	/* packed bits: 0th bit is 01 */
		unsigned int *i;	/* malloc space: int [Bmask_ni] */
		unsigned short *s;	/* malloc space: short [Bmask_si] */
		int ii;			/* index into (unsigned int)[] array */
		int si;			/* index into (unsigned short)[] array */
		} u;
	} BMask;

#define Init_BMask {0,0,0,}
#if MAIN
	BMask empty_BMask = Init_BMask;
#else
	extern BMask empty_BMask;
#endif


typedef struct BMasks {
	unsigned short mny;	/* no. BMasks */
	unsigned short r;	/* represents `r' BMasks altogether */
	unsigned short shallow;	/* 0 <= shallow <= mny */
	unsigned short alloc;	/* no. items allocated in .a[] */
	union {	BMask *a;	/* array[mny] of BMasks */
		int bi;		/* index into (BMask)[] array */
		} u;
	} BMasks;

#define Init_BMasks {0,0,0,0,}
#if MAIN
	BMasks empty_BMasks = Init_BMasks;
#else
	extern empty_BMasks;
#endif

/* Sh - shape list-item */
typedef struct Sh {
	Seq seq;	/* unique sequence no. */
	short t;	/* shape type: S, H, X, etc */
	short nss;	/* no. sub-shapes in the list */
	float mess;	/* mean no. sub-shapes in training set */
	float sdss;	/* std-dev of sub-shapes in training set */
	float NAocc;	/* prob at least one shape not-assigned */
	float NAdup;	/* prob more than one not-assigned */
	Ss NAss;	/* "not-assigned" data */
	Ss *fi;		/* first sub-shape  */
	Ss *la;		/* last sub-shape */
	struct Sh *ne;	/* next shape */
	} Sh;

/* Cl - class list-item */
typedef struct Cl {
	Seq seq;	/* unique sequence no. 0,1,... */
	Cln c;		/* class name */
	float shNA;	/* fraction of shapes unassigned */
	float blDP;	/* fraction of blobs w/ >=1 duplicate shape-match*/
	float blAL;	/* average extra alternate shape-matches / blob */
	SFv sf_me;	/* scalar-features:  means, std-devs */
	SFv sf_sd;
	BMask bm;	/* canonical BMask */
	BMasks bms;	/* additional representative BMask records */
	Sh *sha[Sh_MNY];	/* table of pointers to shape-types */
	Sh *fi;			/* first owned shape */
	Sh *la;			/* last owned shape */
	short unmat[Sh_MNY];	/* counts of unmatched shapes/shape-type */
	struct Ssm *ssmfi;	/* first sub-shape match for this class */
	TRtr *tr;		/* pointer to tracer decision tree (if any) */
	TRv tr_me;		/* tracer-features:  means, std-devs */
	TRv tr_sd;
	float m_me;		/* mean, std-err of merit (in training set) */
	float m_sd;
	float bayes;	/* Bayesian merit: a posteriori log-probability */
	Merit m01;	/* Haming, etc. merit in range [0,1] */
	Merit merit;	/* sort and truncate based on this merit */
	short pass;	/* the last classification method this class passed */
	int ch_mny;	/* No. Chars of this class in a subset */
	int ss_mny;	/* No. Chars with given feature */
	boolean force_reseg;	/* forcibly resegment Chars of this Class */
	struct Cl *ne;	/* next class */
	} Cl;

/* MAX_CL (max no. of classes) is defined in CPU.h */
#define MAX_SH (MAX_CL*SH_MNY)

typedef struct Classes {
	int mny;	/* number of items in array */
	Cl **clpa;	/* Cl *clpa[cl_mny+1]: NULL-term'd array of ptrs */
	} Classes;
#define Init_Classes {0,NULL}
#if MAIN
Classes empty_Classes = Init_Classes;
#else
extern Classes empty_Classes;
#endif

typedef struct Ssm {	/* sub-shape match record */
	Seq isn;	/* input shape sequence no (w/in blob) */
	Cl *clp;	/* owning class, shape, sub-shape... */
	Sh *shp;
	Ss *ssp;
	float mind;	/* distance to closest assigned sub-shape */
	boolean alt;	/* T if this is an alternative (not the first) */
	struct Ssm *ne;	/* next, prior ptrs in list */
	struct Ssm *pr;
	} Ssm;

/* return pathname of OCR directory; if environment variable OCRDIR
   is set, it is used; otherwise #defined variable OCRDIR is used. */
#if MAIN
char *getenv();
char *ocrdir()
{   char *ocrdir_ev;
	if((ocrdir_ev=getenv("OCRDIR"))!=NULL) {
		return(ocrdir_ev);
		}
	else return(OCRDIR);
	}
#else
char *ocrdir();
#endif
0707070035351135261006640007620000050000010264330476773367400001100000033171sunlib.c/* Copyright (c) 1989, 1990 AT&T --- All Rights Reserved.              */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.                */
/* The copyright notice does not imply actual or intended publication. */
/* AUTHORS:                                            */
/*     T. Thompson - ATT-BL HO - first versions        */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <pixrect/pixrect.h>
#include <pixrect/pixfont.h>
#include <suntool/sunview.h>
#include <suntool/canvas.h>
#include "met.h"
#include "boole.h"
#include "Coord.h"

#define XYSCALE(x,y) (x=(x-obotx)*scx+botx),(y=(y-oboty)*scy+boty)

struct pixrect *source_pixrect;

Frame Mainframe;
Canvas Win;
int Winfd;
Pixwin *Pw;
int Key = -1;
int Mousex;
int Mousey;
int Colorval;

/* CMAPSIZE MUST BE A POWER OF 2 (restriction in sun colormap stuff)*/
#define CMAPSIZE 8

#define DEFAULTCOLOR (CMAPSIZE-1)

#define S_WHITE 0
#define S_RED 1
#define S_GREEN 2
#define S_BLUE 3
#define S_GREY 4
#define S_AQUA 5
#define S_YELLOW 6
#define S_BLACK 7

int mycolors[CMAPSIZE][3] = {
	255, 255, 255,	/* white */
	230, 0, 75,	/* red */
	0, 200, 0,	/* green */
	0, 0, 200,	/* blue */
	200, 200, 200,	/* grey */
	0, 160, 170,	/* aqua */
	250, 220, 0,	/* yellow */
	0,0,0		/* foreground (black) */
};


void domouse();

extern int Debug;

extern event_proc();

static int
	boty = 32767,		/* screen bottom y */
	botx = 0,			/* screen bottom x */
	topx = 32767,		/* screen top x */
	topy = 0,			/* screen top y */
	oboty = 0,			/* user's bottom y */
	obotx = 0,			/* user's bottom x */
	otopy = 32767,		/* user's top y */
	otopx = 32767;		/* user's top x */

static double
	scx = 1.0,			/* scale factor x */
	scy = 1.0			/* scale factor y */
;
static int lastx = 0;
static int lasty = 0;
static int lmode = 3;		/* drawing mode (default is xor)*/

int Prevlmode = 3;

#define signof(x) ((x)>=0.0?(1):(-1))
#define absof(x) ((x)>=0.0?(x):(-x))

void flushout() { }

short bsy_pixrect_data[] = {
/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16
 */
	0x7FFE,0x4002,0x200C,0x1A38,0x0FF0,0x07E0,0x03C0,0x0180,
	0x0180,0x0240,0x0520,0x0810,0x1108,0x23C4,0x47E2,0x7FFE
};
mpr_static(busy_pixrect, 16, 16, 1, bsy_pixrect_data);

int childpid;

Rect sweeparect();

om_open()
{
	Rect r;

	r = sweeparect();

	notify_errno = NOTIFY_OK;

	Mainframe = window_create((Window)NULL, FRAME,
		FRAME_LABEL, "ocr",
		0 );
	Win = window_create(Mainframe, CANVAS, 0);
        Pw = canvas_pixwin(Win);

	window_set(Mainframe, WIN_X, r.r_left,
			WIN_Y, r.r_top, 0);
	window_set(Win, WIN_WIDTH, r.r_width,
			WIN_HEIGHT, r.r_height, 0);

	window_fit(Win);
	window_fit(Mainframe);

	window_set(Mainframe, WIN_SHOW, TRUE, 0);

	Winfd = (int) window_get(Win, WIN_FD);

	if ( notify_errno != NOTIFY_OK ) {
		notify_perror("ocr");
		exit(1);
	}

	setcolormap();

	set_color(DEFAULTCOLOR);
	linemod("solid");

	window_set(Win,
		WIN_CONSUME_PICK_EVENTS,
			WIN_NO_EVENTS,
			WIN_ASCII_EVENTS,
			WIN_MOUSE_BUTTONS,
			LOC_MOVE,
			/* LOC_DRAG, */
			LOC_WINEXIT, LOC_WINENTER,
			LOC_RGNEXIT, LOC_RGNENTER, 0,
		0);

	window_set(Win, WIN_EVENT_PROC, event_proc, 0);

	space(0,0,M_WID,M_HGT);
	interact();
}

/***********************************************************/
/* The code below was taken from the 'dumpregion' program. */
/***********************************************************/

/*
 * Copyright Richard Tobin 1987.  You may freely copy, modify and distribute
 * this program in source form provided this comment remains intact.
 *
 * Richard Tobin,                    JANET: R.Tobin@uk.ac.ed             
 * AI Applications Institute,        ARPA:  R.Tobin%uk.ac.ed@nss.cs.ucl.ac.uk
 * Edinburgh University.             UUCP:  ...!ukc!ed.ac.uk!R.Tobin
 */

#include <sys/file.h>
#include <suntool/fullscreen.h>

short nwdata[] = {
#include </usr/include/images/stretchNW.cursor>
};
mpr_static(nwpixrect, 16, 16, 1, nwdata);

short sedata[] = {
#include </usr/include/images/stretchSE.cursor>
};
mpr_static(sepixrect, 16, 16, 1, sedata);

Rect rect = {0,0,0,0};

Rect
sweeparect()
{
    int wfd, n;
    struct fullscreen *fs;
    Event event;
    Pixwin *pw;
    int left, right, top, bottom, temp;
    Window win;
    double w;
    Rect r;

    win = window_create(0, FRAME,
			FRAME_OPEN_RECT, &rect,
			WIN_CONSUME_PICK_EVENTS,
			WIN_ASCII_EVENTS,
			 LOC_MOVE, WIN_MOUSE_BUTTONS, 0,
			0);

    wfd = (int)window_get(win, WIN_FD);
    fs = fullscreen_init(wfd);
    pw = fs->fs_pixwin;

    window_set(win,
	       WIN_CURSOR, cursor_create(CURSOR_IMAGE, &nwpixrect,
					 CURSOR_XHOT, 0, CURSOR_YHOT, 0,
					 0),
	       0);

    for ( ;; ) {
	n = window_read_event(win, &event);
	if ( n < 0 )
		continue;
	if ( event_is_ascii(&event) ) {
		if ( event_id(&event) == 'F' ) {
			r.r_left = 10;
			r.r_top = 10;
			r.r_width = 900;
			r.r_height = 900;
		}
		else {
			r.r_left = 542;
			r.r_top = 0;
			r.r_width = 540;
			r.r_height = 512;
		}
		goto getout;
	}
	if ( event_is_down(&event) && event_is_button(&event) )
		break;
    }

    right = left = event_x(&event);
    bottom = top = event_y(&event);

    window_set(win,
	       WIN_CURSOR, cursor_create(CURSOR_IMAGE, &sepixrect,
					 CURSOR_XHOT, 15, CURSOR_YHOT, 15,
					 0),
	       0);

    drawbox(pw, left, top, right, bottom);

    while(window_read_event(win, &event) == -1 ||
	  !event_is_up(&event) ||
	  !event_is_button(&event))
    {
	drawbox(pw, left, top, right, bottom);
	right = event_x(&event);
	bottom = event_y(&event);
	drawbox(pw, left, top, right, bottom);
    }

    drawbox(pw, left, top, right, bottom);

    if(right < left)
    {
	temp = right;
	right = left;
	left = temp;
    }
    if(bottom < top)
    {
	temp = bottom;
	bottom = top;
	top = temp;
    }
    r.r_left = left;
    r.r_top = top;
    r.r_width = (right-left);
    r.r_height = (bottom-top);
getout:
    fullscreen_destroy(fs);

    window_set(win, FRAME_NO_CONFIRM, TRUE, 0);
    window_destroy(win);
    return r;
}

drawbox(pw, left, top, right, bottom)
Pixwin *pw;
int left, top, right, bottom;
{
    fullscreen_pw_vector(pw, left, top, right, top, PIX_NOT(PIX_DST), 0);
    fullscreen_pw_vector(pw, right, top, right, bottom, PIX_NOT(PIX_DST), 0);
    fullscreen_pw_vector(pw, right, bottom, left, bottom, PIX_NOT(PIX_DST), 0);
    fullscreen_pw_vector(pw, left, bottom, left, top, PIX_NOT(PIX_DST), 0);
}

ttygets(buff,len)
char *buff;
{
	int x, y, n, key;
	char *p = buff;

	for ( n=0; n<(len-1); n++ ) {
		while ( (key=mouseorkey(&x,&y)) < 0 )
			;
		if ( key == '\r' )	/* just in case */
			key = '\n';
		*p++ = key;
		if ( key == '\n' || key == '\0' )
			break;
	}
	*p++ = '\0';
}

int mouseorkey(x,y)
int* x;
int* y;
{
	Event anevent;
	char c;
	int n;

	Key = -1;

	notify_do_dispatch();
	n = read(0,&c,1);
	notify_no_dispatch();
	if ( n == 1 ) {
		/* character was typed in text (original) window */
		/* ie. stdin */
		Key = c;
		*x = Mousex;
		*y = Mousey;
		xyunscale(x,y);
	}
	else if ( Key >= 0 ) {
		/* character was typed in graphics window */
		/* so it must be echoed. */
		putchar(Key);
		if ( Key == '\r' )
			putchar('\n');
		fflush(stdout);
		*x = Mousex;
		*y = Mousey;
		xyunscale(x,y);
	}
	return(Key);
}

interact()
{
	(void) notify_dispatch();
}

setcolormap()
{
	u_char red[CMAPSIZE], green[CMAPSIZE], blue[CMAPSIZE];
	int n;

	for(n=0;n<CMAPSIZE;n++) {
		red[n] = mycolors[n][0];
		green[n] = mycolors[n][1];
		blue[n] = mycolors[n][2];
	}
        pw_setcmsname(Pw,"showcolor");
        pw_putcolormap(Pw, 0, CMAPSIZE, red, green, blue);
}

/*ARGSUSED*/
wait_proc(window,event,arg)
Window window;
Event *event;
caddr_t arg;
{
	int id = event_id(event);

	if ( event_is_ascii(event) && id == 'q' )
		notify_stop(0);
}

om_close()
{
	window_set(Win, WIN_EVENT_PROC, wait_proc, 0);
	if ( fork() == 0 ) {
		close(0);
		close(1);
		close(2);
		/* This stuff doesn't seem to work.  I'm trying to */
		/* get the window to be able to repaint itself when */
		/* uncovered.  */
		sleep(1);
		window_main_loop(Mainframe);
		exit(0);
	}
}

space(x0,y0,x1,y1)
int x0, y0, x1, y1;
{
	int tx, ty;

	obotx = x0;
	oboty = y0;
	otopx = x1;
	otopy = y1;

        boty = 0;
        botx = 0;
        tx = (int) window_get(Win,WIN_WIDTH);
        ty = (int) window_get(Win,WIN_HEIGHT); 
        topx = tx;
        topy = ty;
        scx = (double)(topx-botx)/(otopx-obotx);
        scy = (double)(topy-boty)/(otopy-oboty);
}

#ifdef OLDSTUFF
xyscale(x, y)
int *x, *y;
{
        *x = (*x-obotx)*scx+botx;
        *y = (*y-oboty)*scy+boty;
}
#endif

xyunscale(x, y)
int *x, *y;
{
	/* map from device coordinates to space() coordinates */

	*x = ( (*x - botx)/scx + obotx );
	*y = ( (*y - boty)/scy + oboty );
}

wline(x1,y1,x2,y2)
int x1, y1, x2, y2;
{
	lastx = x2;
	lasty = y2;

	XYSCALE(x1, y1);
	XYSCALE(x2, y2);

	arawline(x1,y1,x2,y2);
}

wrect(x1,y1,x2,y2)
int x1, y1, x2, y2;
{
	lastx = x2;
	lasty = y2;

	XYSCALE(x1, y1);
	XYSCALE(x2, y2);

	arawbox(x1,y1,x2,y2);
}

arawbox(x1,y1,x2,y2)
int x1, y1, x2, y2;
{
	arawline(x1,y1,x2,y1);
	arawline(x2,y1,x2,y2);
	arawline(x2,y2,x1,y2);
	arawline(x1,y2,x1,y1);
}

arawline(x1,y1,x2,y2)
int x1, y1, x2, y2;
{
	int op, col;

	currentopcol(&op,&col);
/* fprintf(stderr,"calling pw_vector, %d,%d  %d,%d  currentop=%d  Colorval=%d  Pw=%ld\n",x1,y1,x2,y2,op,col,Pw); */
	pw_vector(Pw, (int)x1,(int)y1, (int)x2,(int)y2, op, col);
	interact();
}

currentopcol(aop,acol)
int *aop, *acol;
{
	if ( lmode == 1 && Colorval == S_WHITE ) {
		*aop = (PIX_NOT(PIX_SRC) & PIX_DST);
		*acol = S_BLACK;
	}
	else {
		*acol = Colorval;
		switch (lmode) {
		case 0:
			*aop = (PIX_NOT(PIX_SRC) & PIX_DST);
			break;
		case 1:
		case 2:
			/* *aop = (PIX_SRC | PIX_DST); */
			*aop = PIX_SRC;
			break;
		case 3:
			*aop = (PIX_SRC ^ PIX_DST);
			break;
		default:
			*aop = (PIX_SRC | PIX_DST);
			break;
		}
	}
}

wt(s,scl,left,top,right,bot)
char *s;
{
	int op, col;
/* fprintf(stderr,"wt() called, s=%s  lastxy=%d,%d  scl=%d  left-top=%d,%d\n",
s,left,top,scl,left,top); */
	currentopcol(&op,&col);
	XYSCALE(left, top);
	pw_ttext(Pw,(int)left,(int)top,op,NULL,s);
}

Sp *
set_font(n)
{
	static Sp chsz;
	struct pr_size prs;
	int x, y;

	prs = pf_textwidth(1,pf_default(),"x");
	x = prs.x;
	y = prs.y;
	xyunscale(&x,&y);
	chsz.x = ++x;
	chsz.y = y;
	return &chsz;
}

#ifdef OLDSTUFF
textwidth(s)
{
	struct pr_size prs;

	prs = pf_textwidth(bound,strlen(s),pf_default(),s);

	
	prs = pf_textwidth(1,pf_default(),"x");
	*ax = prs.x;
	*ay = prs.y;
	xyunscale(ax,ay);
}
#endif

amove(x,y)
int x,y;
{
	lastx = x;
	lasty = y;
}

cont(x,y)
int x,y;
{
	wline(lastx,lasty,x,y);
	/* last[xy] are then updated by line */
}


set_color(n)
int n;
{
	switch(n){
	case M_WHITE:
		n = S_WHITE; break;
	case M_PALE_GREY:
	case M_GREY_7:
		n = S_GREY; break;
	case M_BLACK:
		n = S_BLACK; break;
	case M_YELLOW_13:
	case M_YELLOW_11:
		n = S_YELLOW; break;
	case M_MAGENTA:
	case M_CYAN:
	case M_CYAN_14:
		n = S_AQUA; break;
	case M_GREEN:
	case M_GREEN_7:
		n = S_GREEN; break;
	case M_BLUE:
		n = S_BLUE; break;
	case M_RED:
		n = S_RED; break;
	default:
		fprintf(stderr,"Unknown color in set_color (%d)\n",n);
		n = S_WHITE;
		break;
	}
	Colorval = n;
/* fprintf(stderr,"set_color = (sun#) %d\n",n); */
}

linemod(s)
char *s;
{
	if ( strcmp(s,"erase")==0 )
		lmode = 0;
	else if ( strcmp(s,"dotted")==0 || strcmp(s,"hilight")==0 )
		lmode = 2;
	else if ( strcmp(s,"xor")==0 )
		lmode = 3;
	else { /* everything, including "solid" defaults to this */
		lmode = 1;
	}
}

aerase()
{
	pw_writebackground(Pw,0,0,(int)topx,(int)topy,PIX_SRC);
}

wfrect(x1,y1,x2,y2)
int x1, y1, x2, y2;
{
	int op, col;
	int t;

	XYSCALE(x1, y1);
	XYSCALE(x2, y2);

	currentopcol(&op,&col);

	if ( x1 > x2 ) {
		t = x1;
		x1 = x2;
		x2 = t;
	}
	if ( y1 > y2 ) {
		t = y1;
		y1 = y2;
		y2 = t;
	}
/* fprintf(stderr,"wfrect(%d,%d to %d,%d  lmode=%d op=%d col=%d)\n",
x1,y1,x2,y2,lmode,op,col); */
	for ( t=y1; t<=y2; t++ ) {
		pw_vector(Pw, x1,t, x2,t, op, col);
	}
	interact();
}

/*ARGSUSED*/
event_proc(window,event,arg)
Window window;
Event *event;
caddr_t arg;
{
	int id = event_id(event);

	if ( event_is_ascii(event) ) {
		Key = id;
		notify_stop(0);
		return;
	}
}

/* trim a Metheus X coordinate to fit on screen */
int M_trimX(x)
	int x;
{	if(x<0) return(0);
	else if(x>(topx-1)) return((topx-1));
	return(x);
	}

/* trim a Metheus Y coordinate to fit on screen */
int M_trimY(y)
	int y;
{	if(y<0) return(0);
	else if(y>(topy-1)) return((topy-1));
	return(y);
	}

/* show Sp (Metheus coordinates) on Metheus,
   enlarged to a `dot'-sided square */
sh_Mp(mpp,dot)
	Sp *mpp;
	int dot;
{	int half_dot;
	if(dot==1)
	   wfrect(mpp->x,mpp->y,mpp->x,mpp->y);
	else {
		half_dot=dot/2;
		if((dot%2)==0)
	   		wfrect( M_trimX(mpp->x-half_dot+1),
				M_trimY(mpp->y-half_dot+1),
				M_trimX(mpp->x+half_dot),
				M_trimY(mpp->y+half_dot) );
		else	wfrect( M_trimX(mpp->x-half_dot),
				M_trimY(mpp->y-half_dot),
				M_trimX(mpp->x+half_dot),
				M_trimY(mpp->y+half_dot) );
		};
	}


om_force(){}

/* write "thick" line, two pixels wide */
wtline(x1,y1,x2,y2)
{   int absdx, absdy;
	wline(x1,y1,x2,y2);
	absdx = (x1-x2)>=0 ? x1-x2 : x2-x1;
	absdy = (y1-y2)>=0 ? y1-y2 : y2-y1;
	if(absdx>absdy)
		/* more horizontal -- thicken vertically */
		wline(x1,M_trimY(y1+1),x2,M_trimY(y2+1));
	else
		/* more vertical -- thicken horizontally */
		wline(M_trimX(x1+1),y1,M_trimX(x2+1),y2);
}

/* write "fat" line, three pixels wide */
wfline(x1,y1,x2,y2)
{	register int absdx, absdy;

	wline(x1,y1,x2,y2);
	absdx = (x1-x2)>=0 ? x1-x2 : x2-x1;
	absdy = (y1-y2)>=0 ? y1-y2 : y2-y1;
	if(absdx>absdy) {
		/* more horizontal -- thicken vertically */
		wline(x1,M_trimY(y1+1),x2,M_trimY(y2+1));
		wline(x1,M_trimY(y1-1),x2,M_trimY(y2-1));
		}
	else	{
		/* more vertical -- thicken horizontally */
		wline(M_trimX(x1+1),y1,M_trimX(x2+1),y2);
		wline(M_trimX(x1-1),y1,M_trimX(x2-1),y2);
		};
}


om_wrpix()
{
        printf("om_wrpix called\n");
}

om_buffer(n) { }

rreset() { }
0707070035351136761006640007620000050000011476070476773366200001100000004314makefile# for all OS --
OPT = -O
PROF = -p
PI = -g

PRODUCTION =  $(OPT)
DEBUG = $(PROF) $(PI)

# -- for UNIX 9th Ed --
CFLAGS = $(PRODUCTION)
LIBS = -lY3610 -lY
PORTLIB = -lport
LDFLAGS = 
F77LIBS = $(LIBS)
MLIB =
REGEX =
FTW =
METLIB = mlib.o
RASTLIB =
POSTLIB =
GRAPHICLIBS = 

# -- For Sun OS 4.x --
##GRAPHICLIBS = -lsuntool -lsunwindow -lpixrect
##MLIB = -lm
##LIBS = $(GRAPHICLIBS) $(MLIB) 
##PORTLIB = /usr/lib/libport3.a
##F77LIBS = -lF77 -lI77 -lc $(MLIB) $(GRAPHICLIBS)
##REGEX = regexec.o regcomp.o regerror.o
##FTW = myftw.o
##LDFLAGS = $(PROF) -fswitch
##CFLAGS = $(PROF) -fswitch -Bstatic
##METLIB = sunlib.o
##RASTLIB = rastlib.o
##POSTLIB = postlib.o 

all:	bcp
	touch bcp
clean:
	rm -rf *.[cho15] bcp bcp.cpio *.srcs makefile

# the next three targets are for use in 1127 software distribution on bowell

install: /usr/bin/bcp
	cp bcp.1 /usr/man/man1

/usr/bin/bcp:	bcp
	strip bcp
	cp bcp /usr/bin

ship:	/usr/bin/bcp
	ship /usr/bin/bcp

# If you want to use UNIX FILE_TREEs:
Path.o:  Path.c CPU.h myftw.h Path.h
	cc $(CFLAGS) -c Path.c
FTREE=Path.o

# If you DON'T want to use FILE_TREEs:
##FTREE=

bcp:	bcp.o CCITT.o rlelib.o riclib.o Coord.o piclib.o jslr.o Text.o $(FTREE) $(POSTLIB) $(RASTLIB)
	cc $(CFLAGS) bcp.o CCITT.o rlelib.o riclib.o Coord.o piclib.o jslr.o Text.o $(FTREE) $(POSTLIB) $(RASTLIB) $(MLIB) $(GRAPHICLIBS) -o bcp
bcp.o:	bcp.c CPU.h stdocr.h rle.h CCITT.h bitio.h pic.h Path.h Bitmap.h Text.h abort.h
	cc $(CFLAGS) $(MLIB) $(GRAPHICLIBS) -c bcp.c

stdocr.h:  boole.h limits.h Units.h ric.h fioi.h
	touch stdocr.h
CCITT.o: CCITT.c CPU.h stdocr.h rle.h Bitmap.h CCITT.h bitio.h
	cc $(CFLAGS) -c CCITT.c
rlelib.o:  rlelib.c CPU.h stdocr.h rle.h ric.h
	cc $(CFLAGS) -c rlelib.c
riclib.o:  riclib.c CPU.h stdocr.h
	cc $(CFLAGS) -c riclib.c
Coord.o:  Coord.c CPU.h boole.h Units.h Coord.h
	cc $(CFLAGS) -c Coord.c
Text.o:  Text.c font.h Bfeats.h stdocr.h
	cc $(CFLAGS) -c Text.c
piclib.o:  piclib.c CPU.h boole.h limits.h Units.h Coord.h pic.h
	cc $(CFLAGS) -c piclib.c
jslr.o:	jslr.c
	cc $(CFLAGS) -c jslr.c
rastlib.o:  rastlib.c
	cc $(CFLAGS) $(MLIB) $(GRAPHICLIBS) -c rastlib.c
postlib.o:  postlib.c
	cc $(CFLAGS) -c postlib.c
sunlib.o: sunlib.c
	cc $(CFLAGS) -c sunlib.c
myftw.o: myftw.c myftw.h
	cc $(CFLAGS) -c myftw.c
0707070035350335411006640007620000050000010556240457561704600000700000001365READMECopy bcp.cpio.z into an empty directory, cd there, and...
	unpack bcp.cpio.z
	cpio -ic <bcp.cpio
If your cpu is not a VAX or your OS is not research UNIX:
	edit CPU.h to specify SUN, CRAY, 3B, etc (and specify OS too)
	edit makefile to enable SUN, CRAY, 3B, etc compilation options
Next, defeat the UNIX file-tree code (later, you may decide you want this; but
it seldom ports easily), by taking these steps:
	1)  in CPU.h, change this line to:
		#define FILE_TREE 0
	2)  in makefile, remove all references to Path.c Path.o (this is
	    spelled out in the comments).
Then say:
	make
and hope for the best, which is a working `bcp'.
Bcp.1 and picfile.5 are man pages; print them using `troff -man'.
More detailed documentation can be found in source bcp.c.
0707070035351136771006640007620000050000011476110476773366300000600000011432bcp.1.TH BCP 1 
.CT 1 graphics
.SH NAME
bcp \(mi reformat black-and-white picture files
.SH SYNOPSIS
.B bcp
[
.I option ...
]
[
.I file1
[
.I file2
]
]
.SH DESCRIPTION
.I Bcp
copies black-and-white (B&W) image
.I file1
to
.I file2,
optionally changing the file format and transforming the image.
If
.I file1
is a directory name,
then every leaf of its file tree is processed in turn; and, in this case,
if
.I file2
also is specified, it is made the root directory
of an isomorphic tree of output files.
If
.I file2
is not specified, all output is catenated to stdout.
.PP
.I Bcp
can copy among all the B&W
.IR picfile (5)
formats, and some others.
The default output format is 
.BR TYPE=ccitt-g4 .
Image transformations include trimming, translation, scaling, and rotation,
performed in that order (not in argument order).
.PP
Input files in
.IR picfile (5)
format must begin with an ASCII 
.BI TYPE= type
header line.
.I Types
supported both as input and output are:
.nr xx \w'\fLccitt-g4\ '
.TP \n(xxu
.B dump
One byte/pixel.
.B NCHAN=1
is required.
On input, the grey pixel values are thresholded
to B&W;
see option
.BR -T .
On output, black becomes 0 and white 255.
.TP
.B bitmap
One bit/pixel.
Essentially Sun rasterfile format, with a
.IR picfile (5)
header replacing the Sun binary header.
.TP
.B ccitt-g4
CCITT Group 4 FAX encoding, strongly compressive on printed text.
Also,
.B ccitt-g31
(Group 3, 1-dim)
and
.B ccitt-g32
(Group 3, 2-dim; see
.BR -k ).
.LP
Other supported
.I types
are:
.TP \n(xxu
.B binary
One bit/pixel encoding; obsolescent, but needed for old image archives.
Both input and output.
.TP
.B rle
Fast run-length encoding; obsolescent, but needed for old image archives.
Input or output, but not both.
.TP
.B pico
Same as
.BR dump .
Input only.
.TP
.B cdf
`Compound document format', used in AT&T FAX Connection product.
Input only.
Only the first of multiple pages is read.
.LP
Other formats not using a 
.BI TYPE= type
header, are:
.IR bitfile (9.5)
format;
PostScript bitmap format (output only); and
Sun rasterfile format (with the Sun binary header; output only).
.PP
The options are:
.TP \n(xxu
.B -B[io]
Read/write
.IR bitfile (9.5)
format (no 
.BI TYPE= type
header).
.TP
.B -M
Write 
.B TYPE=bitmap
format.
.TP
.B -P
Write Postscript bitmap format (Suns only).
.TP
.BI -R x , y
Force output resolutions to 
.I x,y
(pixels/inch).
If 
.BI , y
is missing, it is taken to be the same as
.I x.
Overrides
.BI -x x , y .
Requires a 
.BI RES= "x y
line in the header (but, see 
.BR -Z ).
.TP
.B -R=
Force the output resolution to be equal to the greater of
the input resolutions.
.TP
.B -S
Write Sun rasterfile format (no 
.BI TYPE= type
header; on Suns only).
.TP
.BI -T t
Threshold.
When reading 
.BR TYPE=dump ,
assign black to grey levels less than
.I t,
and white to others.
Default:
.BR -T128 .
.TP
.BI -Z x , y
Force input 
.BI RES= "x y.
.TP
.B -b
Write 
.B TYPE=binary
format.
.TP
.B -g4
.br
.ns
.TP
.B -4
Write 
.B TYPE=ccitt-g4
format.
Similarly, 
.B -g31
or
.B -31
and 
.B -g32
or
.BR -32 .
.TP
.BI -k n
Set the `k' for 
.B ccitt-g32
encoding on output (default
.BR -k4 ).
.TP
.BI -o x , y
Offset (translate) the image by 
.I x,y
pixels.
The width and height of the picture are not changed.
.TP
.B -p
Write 
.B TYPE=dump NCHAN=1
format.
Map black to 0, white to 255.
.TP
.B -r
Write 
.B TYPE=rle
format.
.TP
.B -tl
Rotate the image to bring the left edge of the page to the top.
Set top-left corner of the rotated
image at the top-left corner of the image.
.TP
.BI -t d
Rotate the image 
.I d
degrees counterclockwise about its center.
.I d
is a real number.
.TP
.BI -w l,t,r,b
Specify window (trim the image):
.I l,t
is the left-top corner and 
.I r,b
the right-bottom corner measured in pixels.
If the new margins are outside the original picture,
the new area is set to white.
An argument given as
.L %
leaves the edge unchanged.
.TP
.BI -x x , y
Expand/contract (scale) the image, by real factors 
.I x
and
.I y.
If
.BI , y
is missing,
.I y
is taken to be the same as
.I x.
May be overridden by 
.BI -R x , y.
Requires a 
.BI RES= "x y
line in the header (but, see 
.BR -Z ).
.SH SEE ALSO
.IR cscan (1),
.IR imscan (1),
.IR ocr (1),
.IR pico (1),
.IR picfile (5)
.br
CCITT facsimile coding standards Rec. T.4(1988) and T.6(1988).
.SH BUGS
Concatenated pages are supported, but only if each new page has a complete
header.
.br
Scaling is accomplished by naive replication/deletion of pixels.
.br
Rotation by small angles exhibits aliasing effects, and is slow.
.br
Rotations
.B -tr
and
.B -tb
are unfinished.
.br
CCITT FAX `uncompressed' (or, `transparent') mode is not implemented.
.br
Postscript output is useful only for small images.
.br
.BI WINDOW= "l t r b
where
.I l
or
.I t
is non-zero
may not be handled correctly for every combination of file types.
.br
.B TYPE=rle
can't be both input and output.
.br
Should be merged with T. Duff's
.I pcp.
0707070035351137001006640007620000050000010260120476773366300001200000006503picfile.5.TH PICFILE 5
.CT 1 inst_info graphics
.SH NAME
picfile \- raster graphic image format
.SH DESCRIPTION
Files in this format store images represented as two-dimensional
arrays of multiple-channel pixels.
A
.I picfile
consists of an
.SM ASCII
header followed by binary data encoding the pixels
in row-major order.
The header is a list of attribute/value pairs
separated by newlines, terminated by an
empty line.
Each header line has the form
.IB name = value.
The name may not contain an 
.SM ASCII NUL,
newline or
.LR = ;
the value may not contain null or newline.
The last line of a header is empty.
.PP
The standard attributes are described below; all but
.BR TYPE
and
.BR WINDOW
are optional.
.B TYPE
must come first; otherwise order is irrelevant.
As any unrecognised attribute is passed over uninterpreted by all standard software,
applications are welcome to include arbitrary annotations, like
.BR SHOESIZE=10 ,
if they wish.
.TP
.BI TYPE= type
How the pixels are encoded.
Standard types are
.PD 0
.RS
.TF runcode
.TP
.B runcode
A run-length encoding.
The data are a sequence of
.RI ( nchan +1)-byte
records each containing a count
.I k
and
.I nchan
bytes giving a pixel value to be repeated
.IR k +1
times.
A run may not span scanlines.
.TP
.B dump
A two-dimensional array of
.IR nchan -byte
records in row major order.
.TP
.B bitmap
One-bit pixels, packed into bytes high bit leftmost.
Zero bits are white, one bits are black.
Rows are padded with zeros to a multiple of 16 bits.
.TP
.B ccitt-g4
A black-and-white image under CCITT FAX Group 4 compression.
This format is highly compressive on images of text and line art.
Similarly,
.L ccitt-g31
and
.L ccitt-g32
for Group 3, 1-D and 2-D.
.TP
.B pico
A sequence of
.I nchan
two-dimensional arrays of single bytes.
.TP
.B ccir601
Pixels are in dump order, 2 bytes per pixel
encoded according to the IEEE digital component video standard.
.RE
.TP
.BI WINDOW= "x0 y0 x1 y1
The 
.I x,y
coordinates of the upper left corner and
the point just diagonally outside the lower right corner,
.I x
increasing to the right,
.I y
down.
.TP
.BI NCHAN= nchan
The number of channels, default 1.
.TP
.BI CHAN= value
The order of channels. 
.TP
.BI RES= "x y
The digitizing resolution horizontally and vertically, in pixels/inch.
.PD
.TP
.B CMAP=
(The value is empty.)
A color map, a 256\(mu3-byte translation table for
color values, follows the header.
In a full-color picture, each color-map row maps pixel
values of the corresponding channel.
In a monochrome picture, pixel values index
the color map to yield red, green and blue, like this:
.IP
.EX
unsigned char cmap[256][3];
red=cmap[pixel][0];
green=cmap[pixel][1];
blue=cmap[pixel][2];
.EE
.SH EXAMPLES
.TP
.B sed '/^$/q' image
Print a header.
A sample header follows.
.LP
.EX
TYPE=dump
WINDOW=0 0 512 512
NCHAN=1
CHAN=m
RES=300 300
CMAP=
COMMAND= antiquantize 'halftone CLASSIC' 512.halftone LIBERTY.anticlassic 
COMMAND=  halftone CLASSIC 512.liberty 512.halftone 1.75 512.halftone 
COMMAND=   transpose IN OUT 
COMMAND=    resample 512 IN OUT 
COMMAND=     transpose IN OUT 
COMMAND=      resample 512 IN OUT 
COMMAND=       clip 400 400 LIBERTY OUT
.EE
.SH "SEE ALSO"
.IR bcp (1),
.IR cscan (1),
.IR imscan (1),
.IR pico (1), 
.IR flicks (9.1), 
.IR mugs
in
.IR face (9.7), 
.IR rebecca (9.1),
.IR flickfile (9.5)
.br
T. Duff,
`The 10th Edition Raster Graphics System',
this manual, Volume\ 2
0707070035351137001006640007620000050000010260120476773366300001300000000000TRAILER!!!,
.IR flickfile (9.5)
.br
T. Duff,
`The 10th Edition Raster Graphics System',
this manual, Volume\ 2
0707070035351137001006640007620000050000010260120476773366300001300000000000TRAILER!!!,
.IR flickfile (9.5)
.br
T. Duff,
`The 10th Edition Raster Graphics System',
this manual, Volume\ 2
07070700353511370010066400076200000