|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T f
Length: 20760 (0x5118)
Types: TextFile
Names: »fonts.c«
└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
└─⟦this⟧ »./DVIware/crt-viewers/others/fonts.c«
/*
* dvipage: DVI Previewer Program for Suns
*
* Neil Hunt (hunt@spar.slb.com)
*
* This program is based, in part, upon the program dvisun,
* distributed by the UnixTeX group, extensively modified by
* Neil Hunt at the Schlumberger Palo Alto Research Laboratories
* of Schlumberger Technologies, Inc.
*
* Copyright (c) 1988 Schlumberger Technologies, Inc 1988.
* Anyone can use this software in any manner they choose,
* including modification and redistribution, provided they make
* no charge for it, and these conditions remain unchanged.
*
* This program is distributed as is, with all faults (if any), and
* without any warranty. No author or distributor accepts responsibility
* to anyone for the consequences of using it, or for whether it serves any
* particular purpose at all, or any other reason.
*
* $Log: fonts.c,v $
* Revision 1.1 88/11/28 18:40:54 hunt
* Initial revision
*
* Stripped out of dvipage 1.4,
* with additions from mitdrivers from TeX 1988 distribution tape.
*/
#include <stdio.h>
#include <sys/param.h> /* For MAXPATHLEN */
#include <fcntl.h>
#include <suntool/sunview.h>
#include "dvipage.h"
#include "dvi.h"
forward FILE * open_font_file();
forward bool init_font_file();
forward bool read_font_char();
static int nopen = 0; /* number of open FNT files */
/*
* get_font_def:
* Read the font definitions as they are in the postamble of the DVI file.
* Returns TRUE unless the document can not be processed further.
*/
bool
get_font_def()
{
char *calloc ();
unsigned char byte;
while(((byte = get_unsigned(dvifp, 1)) >= FNT_DEF1) &&
(byte <= FNT_DEF4))
{
switch (byte)
{
case FNT_DEF1:
if(! read_font_def(get_unsigned(dvifp, 1)))
return FALSE;
break;
case FNT_DEF2:
if(! read_font_def(get_unsigned(dvifp, 2)))
return FALSE;
break;
case FNT_DEF3:
if(! read_font_def(get_unsigned(dvifp, 3)))
return FALSE;
break;
case FNT_DEF4:
if(! read_font_def(get_unsigned(dvifp, 4)))
return FALSE;
break;
default:
message(
"%s: Bad dvi file: bad font specification.", filename);
return FALSE;
}
}
if(byte != POST_POST)
{
message(
"%s: Bad dvi file: no postpostamble after fontdefs.", filename);
return FALSE;
}
return TRUE;
}
/*
* skip_font_def:
* Ignore font definition when fonts have been read from the postamble.
*/
/* ARGSUSED */
void
skip_font_def(k)
int k;
{
int a, l;
(void)get_unsigned(dvifp, 4);
(void)get_unsigned(dvifp, 4);
(void)get_unsigned(dvifp, 4);
a = get_unsigned(dvifp, 1);
l = get_unsigned(dvifp, 1);
fseek(dvifp, (long)a+l, 1);
}
/*
* read_font_def:
* Reads font def, and attempts to open font file and read data.
* Returns TRUE unless a fatal error has occurred so that
* document processing cannot proceed.
*/
bool
read_font_def(k)
int k;
{
int i;
struct char_entry *tcharptr;
FILE *font_fp;
/*
* Allocate and link new font entry.
*/
if((fontptr =
(struct font_entry *)calloc(1, sizeof(struct font_entry))) == NULL)
{
message(
"Out of memory for font entries; try a larger machine.");
return FALSE;
}
fontptr->next = hfontptr;
hfontptr = fontptr;
/*
* Fill in new font entry.
*/
fontptr->font_file_fd = NULL;
fontptr->k = k;
fontptr->c = get_unsigned(dvifp, 4); /* checksum */
fontptr->s = get_unsigned(dvifp, 4); /* space size */
fontptr->d = get_unsigned(dvifp, 4); /* design size */
fontptr->a = get_unsigned(dvifp, 1); /* area length for font name */
fontptr->l = get_unsigned(dvifp, 1); /* device length */
fread(fontptr->n, 1, fontptr->a+fontptr->l, dvifp);
fontptr->n[fontptr->a+fontptr->l] = '\0';
fontptr->font_space = fontptr->s/6; /* never used */
fontptr->font_gf_mag = (int)((actual_factor((int)(((float)fontptr->s/
(float)fontptr->d)*1000.0 + 0.5)) *
#ifdef USEGLOBALMAG
actual_factor(mag) *
#endif
(float)resolution) + 0.5);
fontptr->font_pxl_mag = (int)((actual_factor((int)(((float)fontptr->s/
(float)fontptr->d)*1000.0 + 0.5)) *
#ifdef USEGLOBALMAG
actual_factor(mag) *
#endif
(float)resolution * 5.0) + 0.5);
/*
* Try to find the font file to match.
*/
if(! find_font_file(font_path, fontptr) ||
(font_fp = open_font_file(fontptr)) == NO_FILE)
{
message("Cant find or open font file \"%s\" .%dgf or .%dpxl",
fontptr->n, fontptr->font_gf_mag, fontptr->font_pxl_mag);
if(verbose & DEBUG_FONTS)
fprintf(stderr,
"Cant find font file %s %s .%dgf or .%dpxl\n",
font_path, fontptr->n,
fontptr->font_gf_mag, fontptr->font_pxl_mag);
fontptr->font_file_fd = NO_FILE;
fontptr->magnification = 0;
fontptr->designsize = 0;
for(i = 0; i < NFNTCHARS; i++)
{
tcharptr = &(fontptr->ch[i]);
tcharptr->width = 0;
tcharptr->height = 0;
tcharptr->xOffset = 0;
tcharptr->yOffset = 0;
tcharptr->where.isloaded = FALSE;
tcharptr->where.address.fileOffset = NONEXISTENT;
tcharptr->tfmw = 0;
}
return TRUE;
}
else
return init_font_file(font_fp, fontptr);
}
/*
* open_font_file:
* Called with fontptr; opens a file for this font.
* May have to close another to do it.
* Returns a FILE * pointer, or NO_FILE.
*/
FILE *
open_font_file(fontptr)
struct font_entry *fontptr;
{
register struct font_entry *tfontptr, *lufontptr;
register int used;
if(nopen >= MAXOPEN)
{
used = MAXINT;
lufontptr = NULL;
for(tfontptr = hfontptr; tfontptr; tfontptr = tfontptr->next)
{
if(tfontptr->font_file_fd == NO_FILE ||
tfontptr->font_file_fd == NULL ||
tfontptr == fontptr)
continue;
if(tfontptr->use_count < used)
{
used = tfontptr->use_count;
lufontptr = tfontptr;
}
}
if(lufontptr == NULL)
{
fprintf(stderr, "Cant have no least used font\n");
exit(1);
}
if(verbose & DEBUG_FONTS)
fprintf(stderr, "Closing (%x) font '%s'\n",
lufontptr->font_file_fd, lufontptr->name);
fclose(lufontptr->font_file_fd);
lufontptr->font_file_fd = NULL;
--nopen;
}
/*
* Open the file; close-on-exec.
*/
if((fontptr->font_file_fd = fopen(fontptr->name, "r")) == NULL)
{
message("Cant open font file %s", fontptr->name);
fontptr->font_file_fd = NO_FILE;
}
else
{
if(verbose & DEBUG_FONTS)
fprintf(stderr, "Opened (%x) font '%s'\n",
fontptr->font_file_fd, fontptr->name);
fcntl(fileno(fontptr->font_file_fd), F_SETFD, 1);
nopen++;
}
return fontptr->font_file_fd;
}
/*
* close_fonts:
* Closes all the font files, and frees up all the memory.
*/
void
close_fonts()
{
register struct font_entry *pf, *next;
register struct pixrect *pr;
register int i;
for(pf = hfontptr; pf; pf = next)
{
if(verbose & DEBUG_FONTS)
fprintf(stderr, "Freeing font %s\n", pf->name);
/*
* Close the file if still open.
*/
if(pf->font_file_fd != NO_FILE && pf->font_file_fd != NULL)
{
fclose(pf->font_file_fd);
--nopen;
}
pf->font_file_fd = NULL;
/*
* Free the pixrects.
*/
for(i = 0; i < NFNTCHARS; i++)
{
if(pf->ch[i].where.isloaded == TRUE)
{
if(pr = pf->ch[i].where.address.pixrectptr)
pr_destroy(pr);
}
}
/*
* Get the next.
*/
next = pf->next;
free(pf);
}
hfontptr = NULL;
fontptr = NULL;
if(nopen != 0)
{
fprintf(stderr, "Mislaid some font files; cant happen\n");
exit(1);
}
}
/*
* load_char:
* Reads in a character from the font file.
* Returns TRUE unless document cannot be processed.
*/
bool
load_char(fontptr, ptr)
struct font_entry *fontptr;
struct char_entry *ptr;
{
register FILE *font_fp;
if(verbose & DEBUG_CHARS)
fprintf(stderr, "Load char %d of font %s at offset %d\n",
(ptr - &fontptr->ch[0]), fontptr->name,
ptr->where.address.fileOffset);
/*
* If the font file is currently unopen, then open it.
*/
if((font_fp = fontptr->font_file_fd) == NULL)
font_fp = open_font_file(fontptr);
/*
* If the font file is unavailable, forget it.
*/
if(font_fp == NO_FILE)
{
ptr->where.isloaded = TRUE;
return TRUE;
}
/*
* Read the font character.
*/
return read_font_char(font_fp, fontptr, ptr);
}
/*
* Generic Font reading functions.
* ==============================
*/
forward bool init_gf_font_file();
forward bool init_pxl_font_file();
forward bool read_gf_font_char();
forward bool read_pxl_font_char();
/*
* init_font_file:
* Reads general data from font file.
* Returns TRUE unless processing cannot continue.
*/
bool
init_font_file(font_fp, fontptr)
FILE *font_fp;
struct font_entry *fontptr;
{
switch(fontptr->type)
{
case TYPE_GF:
return init_gf_font_file(font_fp, fontptr);
case TYPE_PXL:
return init_pxl_font_file(font_fp, fontptr);
default:
fprintf(stderr, "Unknown type of font file; cant happen\n");
exit(1);
}
}
/*
* read_font_char:
* Reads character from font file.
* Returns TRUE unless document cannot be processed.
*/
bool
read_font_char(font_fp, fontptr, ptr)
FILE *font_fp;
struct font_entry *fontptr;
struct char_entry *ptr;
{
switch(fontptr->type)
{
case TYPE_GF:
return read_gf_font_char(font_fp, fontptr, ptr);
case TYPE_PXL:
return read_pxl_font_char(font_fp, fontptr, ptr);
default:
fprintf(stderr, "Unknown type of font file; cant happen\n");
exit(1);
}
}
/*
* GF font reading functions.
* ==========================
*/
#define false 0
#define true 1
/* The following macros describe gf file format */
#define paint_0 0
#define last_paint 63
#define paint1 64
#define paint2 65
#define paint3 66
#define boc 67
#define boc1 68
#define eoc 69
#define skip0 70
#define skip1 71
#define skip2 72
#define skip3 73
#define new_row_0 74
#define last_new_row 238
#define xxx1 239
#define xxx2 240
#define xxx3 241
#define xxx4 242
#define yyy 243
#define no_op 244
#define char_loc 245
#define char_loc0 246
#define pre 247
#define post 248
#define postpost 249
#define undefined_cases 250: case 251: case 252: case 253: case 254: case 255
#define gf_version 131
/*
* init_gf_font_file:
* Reads font data from file.
* If the file is unavailable, its fp is set to NO_FILE.
* Returns TRUE unless processing cannot continue.
*/
bool
init_gf_font_file(font_fp, fontptr)
FILE *font_fp;
struct font_entry *fontptr;
{
register int b, c;
register struct char_entry *tcharptr;
long checksum; /* should match TFM file and DVI file */
long hppp, vppp; /* horizontal and vertical pixels/point scaled
* 1<<16 */
int font_min_m, font_max_m, font_min_n, font_max_n;
int char_wd; /* character width in pixels, rounded if
* necessary */
/*
* Seek to the postamble part of the GF file.
*/
fseek(font_fp, -5L, 2); /* skip four 223's */
do
{
c = get_unsigned(font_fp, 1);
fseek(font_fp, -2L, 1);
} while(c == 223);
if(c != gf_version)
{
message("Bad GF font version number (%d) in %s.",
c, fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
}
fseek(font_fp, -3L, 1); /* back up to the pointer */
if(fseek(font_fp, (long)get_unsigned(font_fp, 4), 0) < 0 ||
get_unsigned(font_fp, 1) != post)
{
message("Bad GF font file format in %s.", fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
}
(void)get_unsigned(font_fp, 4); /* ignore back pointer to font-wide xxx
* commands */
fontptr->designsize = get_unsigned(font_fp, 4);
checksum = get_unsigned(font_fp, 4);
hppp = get_unsigned(font_fp, 4);
vppp = get_unsigned(font_fp, 4);
font_min_m = get_unsigned(font_fp, 4);
font_max_m = get_unsigned(font_fp, 4);
font_min_n = get_unsigned(font_fp, 4);
font_max_n = get_unsigned(font_fp, 4);
if(verbose & DEBUG_FONTS)
fprintf(stderr, "Initialising font %s\n", fontptr->name);
for(tcharptr = &fontptr->ch[0]; tcharptr < &fontptr->ch[NFNTCHARS];
tcharptr++)
{
tcharptr->where.isloaded = FALSE;
tcharptr->where.address.fileOffset = -1;
tcharptr->tfmw = 0;
}
for(;;)
{
b = get_unsigned(font_fp, 1);
c = get_unsigned(font_fp, 1);
if(verbose & DEBUG_CHARS)
fprintf(stderr, "Finding char %d type %d\n", c, b);
if(b == char_loc0)
char_wd = get_unsigned(font_fp, 1);
else if(b == char_loc)
{
char_wd = (get_unsigned(font_fp, 4) + 0100000) >> 16;
get_unsigned(font_fp, 4); /* skip dy */
}
else
break;
tcharptr = &(fontptr->ch[c % NFNTCHARS]);
tcharptr->tfmw =
((float)get_unsigned(font_fp, 4) * (float)fontptr->s) /
(float)(1 << 20);
tcharptr->where.address.fileOffset = get_unsigned(font_fp, 4);
}
if((fontptr->c != 0) && (checksum != 0) && (fontptr->c != checksum))
message("Bad font checksum %d != %d, font %s.",
checksum, fontptr->c, fontptr->name);
/*
* Return leaving font file open for use.
*/
return TRUE;
}
/*
* read_font_char:
* Reads character from font file.
* Returns TRUE unless document cannot be processed.
*/
bool
read_gf_font_char(font_fp, fontptr, ptr)
FILE *font_fp;
struct font_entry *fontptr;
register struct char_entry *ptr;
{
register int i, b, c;
register int x, y;
register struct pixrect *pr;
int min_m, max_m, min_n, max_n;
int bytes, lines, paint_switch;
long backpointer;
long charfam;
if(verbose & DEBUG_CHARS)
fprintf(stderr, "Reading char %d of font %s\n",
(ptr - &fontptr->ch[0]), fontptr->name);
/*
* Seek to start of char.
*/
fseek(font_fp, (long)ptr->where.address.fileOffset, 0);
/*
* Sync with char
*/
do
{
switch(i = get_unsigned(font_fp, 1))
{
case yyy:
(void)get_unsigned(font_fp, 1);
/* FALLTHROUGH */
case paint3:
case skip3:
(void)get_unsigned(font_fp, 1);
/* FALLTHROUGH */
case paint2:
case skip2:
(void)get_unsigned(font_fp, 1);
/* FALLTHROUGH */
case paint1:
case skip1:
(void)get_unsigned(font_fp, 1);
break;
case boc:
case boc1:
break;
case pre:
if((c = get_unsigned(font_fp, 1)) != gf_version)
{
message(
"Bad GF font version number (%d); font %s.",
c, fontptr->name);
return TRUE;
}
fseek(font_fp, (long)get_unsigned(font_fp, 1), 1);
break;
case xxx1:
fseek(font_fp, (long)get_unsigned(font_fp, 1), 1);
break;
case xxx2:
fseek(font_fp, (long)get_unsigned(font_fp, 2), 1);
break;
case xxx3:
fseek(font_fp, (long)get_unsigned(font_fp, 3), 1);
break;
case xxx4:
fseek(font_fp, (long)get_unsigned(font_fp, 4), 1);
break;
case post:
if(verbose & DEBUG_FONTS)
fprintf(stderr, "gettochar: found POST\n");
return TRUE;
case char_loc:
case char_loc0:
case postpost:
case undefined_cases:
message(
"Bad GF font file format (%d); font %s.",
i, fontptr->name);
return TRUE;
default: /* do nothing */ ;
break;
}
if(i != boc && i != boc1 &&
verbose & DEBUG_FONTS)
fprintf(stderr, "gettochar iterates with %d\n", i);
}
while(i != boc && i != boc1);
/*
* Read character code and raster sizes.
*/
switch(i)
{
case boc:
c = get_unsigned(font_fp, 4);
backpointer = get_unsigned(font_fp, 4);
min_m = get_unsigned(font_fp, 4);
max_m = get_unsigned(font_fp, 4);
min_n = get_unsigned(font_fp, 4);
max_n = get_unsigned(font_fp, 4);
charfam = c < 0 ? -((-c) >> 8) : c >> 8;
break;
case boc1:
c = get_unsigned(font_fp, 1);
x = get_unsigned(font_fp, 1); /* del_m */
max_m = get_unsigned(font_fp, 1);
min_m = max_m - x;
x = get_unsigned(font_fp, 1); /* del_n */
max_n = get_unsigned(font_fp, 1);
min_n = max_n - x;
break;
default:
fprintf(stderr,
"Font BOC code has corrupted in memory; cant happen.\n");
exit(1);
}
ptr->width = max_m - min_m + 1;
ptr->height = max_n - min_n + 1;
ptr->xOffset = -min_m;
ptr->yOffset = max_n;
/*
* Create Pixrect for char.
* Clear to zero.
*/
pr = mem_create(ptr->width, ptr->height, 1);
ptr->where.address.pixrectptr = pr;
pr_rop(pr, 0, 0, ptr->width, ptr->height, PIX_SRC | PIX_COLOR(0),
NULL, 0, 0);
#ifdef NEVER
pr_rop(pr, 0, 0, ptr->width, ptr->height, PIX_SRC | PIX_COLOR(1),
NULL, 0, 0);
pr_rop(pr, 1, 1, ptr->width-2, ptr->height-2, PIX_SRC | PIX_COLOR(0),
NULL, 0, 0);
#endif NEVER
x = 0;
y = 0;
paint_switch = 0;
for(;;)
{
switch(b = get_unsigned(font_fp, 1))
{
case paint1:
bytes = get_unsigned(font_fp, 1);
goto paint;
case paint2:
bytes = get_unsigned(font_fp, 2);
goto paint;
case paint3:
bytes = get_unsigned(font_fp, 3);
goto paint;
case skip0:
lines = 0;
goto skip;
case skip1:
lines = get_unsigned(font_fp, 1);
goto skip;
case skip2:
lines = get_unsigned(font_fp, 2);
goto skip;
case skip3:
lines = get_unsigned(font_fp, 3);
goto skip;
case xxx1:
fseek(font_fp, (long)get_unsigned(font_fp, 1), 1);
continue;
case xxx2:
fseek(font_fp, (long)get_unsigned(font_fp, 2), 1);
continue;
case xxx3:
fseek(font_fp, (long)get_unsigned(font_fp, 3), 1);
continue;
case xxx4:
fseek(font_fp, (long)get_unsigned(font_fp, 4), 1);
continue;
case yyy:
get_unsigned(font_fp, 4);
continue;
case no_op:
continue;
case eoc:
ptr->where.isloaded = TRUE;
return TRUE;
default:
if(b >= paint_0 && b <= last_paint)
{
bytes = b - paint_0;
paint:; /*
* Paint the specified number of bytes black
* or white.
* Toggle the paint colour.
* Advance the current position.
*/
if(verbose & DEBUG_CHARS)
fprintf(stderr,
" Paint %d line %d, %d for %d\n", paint_switch, y, x, bytes);
if(bytes > 0 && paint_switch)
pr_rop(pr, x, y, bytes, 1,
PIX_SRC | PIX_COLOR(1), NULL, 0, 0);
paint_switch = ! paint_switch;
x += bytes;
continue;
}
else if(b >= new_row_0 && b <= last_new_row)
{
/*
* Special shortcut; skip to new row,
* and paint some white bytes.
* Leave switch ready for next black bytes.
*/
y++;
x = b - new_row_0;
paint_switch = 1;
if(verbose & DEBUG_CHARS)
fprintf(stderr,
" Jump to line %d, paint white to %d\n", y, x);
continue;
}
else
{
message(
"Bad GF file format code %d; char %d font %s.",
b, (ptr - &fontptr->ch[0]), fontptr->name);
return TRUE;
}
skip:; /*
* Skip to the start of the line.th next line.
* Start at beginnning of line, ready to paint white.
*/
y += lines + 1;
x = 0;
paint_switch = 0;
if(verbose & DEBUG_CHARS)
fprintf(stderr,
" Jump to line %d at start\n", y);
continue;
}
}
}
/*
* PXL font reading functions.
* ==========================
*/
#define NPXLCHARS 128
/*
* init_pxl_font_file:
* Reads font data from file.
* If the file is unavailable, its fp is set to NO_FILE.
* Returns TRUE unless processing cannot continue.
*/
bool
init_pxl_font_file(font_fp, fontptr)
FILE *font_fp;
struct font_entry *fontptr;
{
int t, i;
register struct char_entry *tcharptr;
/*
* Read the PXL file
*/
if((t = get_unsigned(font_fp, 4)) != PXLID)
{
message("Bad font file version %d; font %s.",
t, fontptr->name);
fclose(fontptr->font_file_fd);
fontptr->font_file_fd = NO_FILE;
return TRUE;
}
fseek(font_fp, -20L, 2);
t = get_unsigned(font_fp, 4);
if((fontptr->c != 0) && (t != 0) && (fontptr->c != t))
message("Bad font checksum %d != %d; font %s.",
t, fontptr->c, fontptr->name);
fontptr->magnification = get_unsigned(font_fp, 4);
fontptr->designsize = get_unsigned(font_fp, 4);
fseek(font_fp, (long)get_unsigned(font_fp, 4) * 4, 0);
for(i = 0; i < NPXLCHARS; i++)
{
tcharptr = &(fontptr->ch[i]);
tcharptr->width = get_unsigned(font_fp, 2);
tcharptr->height = get_unsigned(font_fp, 2);
tcharptr->xOffset= get_signed(font_fp, 2);
tcharptr->yOffset = get_signed(font_fp, 2);
tcharptr->where.isloaded = FALSE;
tcharptr->where.address.fileOffset =
get_unsigned(font_fp, 4) * 4;
tcharptr->tfmw =
((float)get_unsigned(font_fp, 4)*(float)fontptr->s) /
(float)(1<<20);
}
/*
* Return leaving font file open for access.
*/
return TRUE;
}
/*
* read_font_char:
* Reads character from font file.
* Returns TRUE unless document cannot be processed.
*/
/* ARGSUSED */
bool
read_pxl_font_char(font_fp, fontptr, ptr)
FILE *font_fp;
struct font_entry *fontptr;
register struct char_entry *ptr;
{
register struct pixrect *pr;
register int nshorts, i, col, nints;
register short *dp, *sp;
int buf[8];
/*
* Seek to start of char.
*/
fseek(font_fp, (long)ptr->where.address.fileOffset, 0);
/*
* Create a mem pixrect.
* Read the char.
*/
pr = mem_create(ptr->width, ptr->height, 1);
nshorts = mpr_mdlinebytes(pr) >> 1;
nints = (ptr->width + 31) >> 5;
dp = mpr_d(pr)->md_image;
for(col = 0; col < ptr->height; col++)
{
fread(buf, 4, nints, font_fp);
sp = (short *) &buf[0];
for(i = nshorts; i > 0; i--)
*dp++ = *sp++;
}
ptr->where.address.pixrectptr = pr;
ptr->where.isloaded = TRUE;
return TRUE;
}