/* This file is macfont.h
 *
 * Copyright (C) 1993 by Norman Walsh
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 ************************************************************************/

#include <stdio.h>
#include "mactypes.h"
#include "macio.h"
#include "mac2bdf.h"
#include "applestd.h"

#define PTRSIZE 4
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#define Vers "1.1"

extern char *optarg;
extern int optind, opterr;

int Mac_typeCount;
int POSTnum, FONDnum, NFNTnum;
RsrcHdrStruct Mac_header;
RsrcMapStruct Mac_map;
RsrcTypeStruct *Mac_types;
RsrcRefStruct  **Mac_refs;

FILE *input;
FILE *output;
int  rc;

char **style_names;
char **style_longnames;
char *familyname;

char *weight;
char *encoding_scheme;

int  debug = 0;

void dump_mac_header(RsrcHdrStruct h, RsrcMapStruct m)
{
  printf("Mac header:\t\tMac map:\n");
  printf("DataOffset (4): 0x%04x\tNextMap    (4) : 0x%04x\n", 
	 h.DataOffset, m.NextMap);
  printf("MapOffset  (4): 0x%04x\tFileRef    (2) :   %4d\n", 
	 h.MapOffset, m.FileRef);
  printf("DataLen    (4):   %4d\tFileAttr   (2) :   %4d\n", 
	 h.DataLen, m.FileAttr);
  printf("MapLen     (4):   %4d\tTypeOffset (2) :   %4d\n",
	 h.MapLen, m.TypeOffset);
  printf("\t\t\tNameOffset (2) :   %4d\n", 
	 m.NameOffset);
  printf("\n");
}

void dump_mac_info(RsrcTypeStruct t, RsrcRefStruct r)
{
  printf("Mac type:\t\tMac ref:\n");
  printf("Name      (4) :   %c%c%c%c\tIdent      (2) : %6d\n",
	 t.Name[0], t.Name[1], t.Name[2], t.Name[3], r.Ident);
  printf("Count     (2) :   %4d\tNameOffset (2) : 0x%04x\n",
	 t.Count, r.NameOffset);
  printf("RefOffset (2) : 0x%04x\tAttr       (1) : %d\n",
	 t.RefOffset, r.Attr);
  printf("\t\t\tDataOffset (2) : 0x%04x\n", 
	 r.DataOffset);
  printf("\n");
}

void dump_mac_info2(RsrcRefStruct r)
{
  printf("\t\t\tMac ref:\n");
  printf("\t\t\tIdent      (2) : %6d\n", r.Ident);
  printf("\t\t\tNameOffset (2) : 0x%04x\n", r.NameOffset);
  printf("\t\t\tAttr       (1) : %d\n", r.Attr);
  printf("\t\t\tDataOffset (2) : 0x%04x\n",  r.DataOffset);
  printf("\n");
}

void dump_mac_nfnt(RsrcNfntStruct n, int id)
{
  printf("Mac NFNT (%d)\n", id);
  printf("FontType    : %6d\n", n.FontType);
  printf("FirstChar   : %6d\n", n.FirstChar);
  printf("LastChar    : %6d\n", n.LastChar);
  printf("WidMax      : %6d\n", n.WidMax);
  printf("KernMax     : %6d\n", n.KernMax);
  printf("NDescent    : %6d\n", n.NDescent);
  printf("FRectWidth  : %6d\n", n.FRectWidth);
  printf("FRectHeight : %6d\n", n.FRectHeight);
  printf("OWTLoc      : 0x%04x\n", n.OWTLoc);
  printf("Ascent      : %6d\n", n.Ascent);
  printf("Descent     : %6d\n", n.Descent);
  printf("Leading     : %6d\n", n.Leading);
  printf("RowWords    : %6d\n\n", n.RowWords);
}

void dump_mac_fond(RsrcFondStruct f, int id)
{
  int count;

  printf("Mac FOND (%d)\n", id);
  printf("Flag          : %6d\n", f.Flag);
  printf("FamilyId      : %6d\n", f.FamilyId);
  printf("FirstChar     : %6d\n", f.FirstChar);
  printf("LastChar      : %6d\n", f.LastChar);
  printf("Ascent        : %6d\n", f.Ascent);
  printf("Descent       : %6d\n", f.Descent);
  printf("Leading       : %6d\n", f.Leading);
  printf("WidMax        : %6d\n", f.WidMax);
  printf("WidTblOfs (4) : 0x%04x\n", f.WidTblOfs);
  printf("KrnTblOfs (4) : 0x%04x\n", f.KrnTblOfs);
  printf("StyTblOfs (4) : 0x%04x\n", f.StyTblOfs);

  for (count = 0; count < 9; count++)
      printf("  FamStyProp %d: %6d\n", count, f.FamStyProp[count]);

  printf("Intrnatnl (4) : %6d\n", f.Intrnatnl);
  printf("FontVers      : %6d\n", f.FontVers); 

  for (count = 0; count < f.NumFonts; count++)
    {
       printf("  ResourceId  : %6d\n", f.AssocTable[count].ResourceNumber);
       printf("  StyleCode   : %6d\n", f.AssocTable[count].StyleCode);
       printf("  PointSize   : %6d\n", f.AssocTable[count].PointSize);
     }

  printf("\n");
}

void write_post(int count, int offset)
{
  int datalen,post_type,filler;
  int place,hexplace,rowlen,newplace;
  unsigned char *buffer, *newbuf;
  char hexdigits[16] = "0123456789ABCDEF";

  fseek (input, offset, 0);
  datalen = read_macint() - 2;
  post_type = read_macchar();
  filler = read_macchar();
  while (count > 0 && post_type != 5) 
    {
      buffer = (char *) malloc(datalen);
      fread (buffer, 1, datalen, input);

      switch (post_type)
	{
	case 0: /* comment */
	  break;
	case 1: /* ASCII text */
	  newbuf = (char *) malloc(2*datalen); /* 2 is a guesstimate */
	  for (place = 0, newplace=0; place < datalen; place++)
	    {
	      switch (buffer[place])
		{
		case 13:
		  newbuf[newplace++] = 10;
		  break;
		case 0251:
		  newbuf[newplace++] = '(';
		  newbuf[newplace++] = 'C';
		  newbuf[newplace++] = ')';
		  break;
		default:
		  newbuf[newplace++] = buffer[place];
		  break;
		}
	    }
	  fwrite (newbuf, 1, newplace, output);
	  free(newbuf);
	  break;
	case 2: /* hexidecimal data */
	  newbuf = (char *) malloc(3*datalen); /* 3 is overkill */
	  for (place = 0, hexplace = 0, rowlen = 0;
	       place < datalen;
	       place++)
	    {
	      newbuf[hexplace++] = hexdigits[(buffer[place] >> 4) & 0x0F];
	      newbuf[hexplace++] = hexdigits[buffer[place] & 0x0F];
	      rowlen += 2;
	      if (rowlen > 63)
		{
		  newbuf[hexplace++] = 10;
		  rowlen = 0;
		}
	    }
	  if (rowlen != 0)
	    newbuf[hexplace++] = 10;
	  fwrite(newbuf, 1, hexplace, output);
	  free(newbuf);
	  break;
	case 3: /* end-of-file marker */
	  break;
	case 4: /* font program is in data fork */
	  printf("Can't handle POST resources in the data fork.\n");
	  exit(1);
	  break;
	case 5: /* end of font program */
	  break;
	}
	  
      free (buffer);
      datalen = read_macint() - 2;
      post_type = read_macchar();
      filler = read_macchar();
      count--;
    }
}

float frac2real(int W)
{
  float R;
  int   I;

  R = (W & 0x0FFF);
  R = R / 4096.0;

  W = (W >> 12) & 0x0F;
  if (W >= 0x08)
    {
      W = W ^ 0xFFFF;
      W = (W + 1) & 0x0F;
      I = -W;
    }
  else 
    I = W;

  R = R + I;
  
  return R;
}

void get_style_names (int offset, int num_styles)
{
  int count, place, actual, strcnt, namecnt;
  unsigned char SNT[4096];
  unsigned short int SNPos[64];
  char *SPtr;
  char *EncStr;
  unsigned short int Class;
  int EncTblOfs;
  unsigned char StyIdxTbl[48];
  char **strings;
  
  fseek (input, offset, 0);
  count = read_macint();
  Class = read_macshortint();
  EncTblOfs = read_macint();
  read_macint(); /* skip the reserved word */
  for (count = 0; count < 48; count++)
    StyIdxTbl[count] = read_macchar() - 1;

  if (EncTblOfs != 0)
    {
      printf("Info: This file contains an encoding table...\n");
    }

  strcnt = read_macshortint();
  fread (SNT+2, 1, 126, input);
  place = 2;
  SNPos[0] = place;
  for (count = 1; count < 64; count++)
    {
      place = place + SNT[SNPos[count-1]] + 1;
      SNPos[count] = place;
    }

  strings = (char **) malloc (strcnt * PTRSIZE);

  for (count = 0; count < strcnt; count++)
    {
      int slen;
      char *sptr;

      slen = SNT[SNPos[count]];
      sptr = (char *) malloc(slen+1);
      strncpy(sptr,&SNT[SNPos[count]+1],slen);
      *(sptr+slen) = 0;

      strings[count] = sptr;
    }

  familyname = strings[0];
  style_names = (char **) malloc((num_styles+1) * PTRSIZE);
  style_longnames = (char **) malloc((num_styles+1) * PTRSIZE);

  for (count = 0; count < num_styles; count++)
    {
      int slen;
      char *sptr,*strnum;
      char *nptr,*lnptr;

      sptr = strings[0];
      slen = strlen(sptr);

      if (strcnt > 1) 
	{
	  strnum = strings[StyIdxTbl[count]];
	  while (*strnum) 
	    {
	      sptr = strings[*strnum-1];
	      slen += strlen(sptr);
	      strnum++;
	    }
	}

      style_names[count] = (char *) malloc(slen+1);
      style_longnames[count] = (char *) malloc(slen+1);

      nptr = style_names[count];
      lnptr = style_longnames[count];

      sptr = strings[0];
      slen = strlen(sptr);

      strncpy (nptr, sptr, MIN(slen,5));
      nptr += MIN(slen,5);
      *nptr = 0;

      strcpy (lnptr, sptr);
      lnptr += slen;
      *lnptr = 0;

      if (strcnt > 1) 
	{
	  strnum = strings[StyIdxTbl[count]];
	  while (*strnum) 
	    {
	      sptr = strings[*strnum-1];
	      slen = strlen(sptr);

	      strncpy (nptr, sptr, MIN(slen,3));
	      nptr += MIN(slen,3);
	      *nptr = 0;

	      strcpy (lnptr, sptr);
	      lnptr += slen;
	      *lnptr = 0;

	      strnum++;
	    }
	}
    }

  style_names[num_styles] = 0;
  style_longnames[num_styles] = 0;
}

void write_kerns(int offset, FILE *afm)
{
  int NumKernTbls, StyleCode, NumKernPairs;
  int count;
  unsigned char L1, L2;
  int Frac;

  fseek(input, offset, 0);

  read_macint(); /* skip length, or something? */

  NumKernTbls  = read_macshortint();
  StyleCode    = read_macshortint();
  NumKernPairs = read_macshortint();

  fprintf(afm, "StartKernData\n");
  fprintf(afm, "StartKernPairs %d\n", NumKernPairs);

  for (count = 0; count < NumKernPairs; count++)
    {
      L1 = read_macchar();
      L2 = read_macchar();
      Frac = read_macshortint();

      if (encoding[L1] != 0 && encoding[L2] != 0)
	fprintf(afm, "KPX %s %s %d\n",
		encoding[L1],
		encoding[L2],
		(int) (frac2real(Frac)*1000));
    }

  fprintf(afm, "EndKernPairs\n");
  fprintf(afm, "EndKernData\n");
}

void write_nfnt(int offset, 
		FontEntryFormat font_entry, 
		char *name,int id,
		int sequential)
{
  RsrcNfntStruct Nfnt;
  int datalen;
  unsigned char *buf;

  fseek (input, offset, 0);
  datalen = read_macint();

  Nfnt = read_mac_nfnt();

  if (debug)
    dump_mac_nfnt(Nfnt, id);

  fseek (input, offset, 0);
  datalen = read_macint();

  buf = (char *) malloc (datalen);
  fread (buf, 1, datalen, input);

  if (sequential) 
    name = "mf";

  FontDump(buf, name, font_entry.StyleCode, font_entry.PointSize);

  free(buf);

  return;
}

void write_fond(int offset, int id, int afmopt, int bdfopt, int sequential)
{
  int fonddatalen,datalen,count,tblcount;
  unsigned char *buffer;
  RsrcFondStruct Fond;
  unsigned short int TableCount, Style, Width;
  unsigned short int **Widths;
  unsigned short int *curWidths;
  FILE *afm;

  fseek (input, offset, 0);
  fonddatalen = read_macint();
  
  Fond = read_mac_fond();

  if (debug)
    dump_mac_fond(Fond, id);

  fseek (input, offset+Fond.WidTblOfs, 0);
  
  datalen = read_macshortint();
  datalen = read_macshortint();
  
  TableCount = read_macshortint()+1;
  
  Widths = (unsigned short int **) malloc (TableCount * PTRSIZE);
  
  for (tblcount = 0; tblcount < TableCount; tblcount++)
    {
      Style = read_macshortint();
      
      Widths[tblcount] = (unsigned short int *) malloc(256 * 2);
      curWidths = Widths[tblcount];
      
      for (count = 0; count < 256; count++)
	{
	  Width = read_macshortint();
	  curWidths[count] = (frac2real(Width) * 1000);
	}
      
      read_macshortint();	/* discard unused word */
      count = read_macshortint();
      
      if (count != 0)
	printf("Warning: table doesn't conform to spec.\n");
    }
  
  get_style_names (offset + Fond.StyTblOfs, TableCount);
  
  for (tblcount = 0; afmopt && tblcount < TableCount; tblcount++)
    {
      char *filename;
      char *ch;
      
      if (sequential)
	{
	  filename = (char *) malloc(12);
	  sprintf(filename, "macfont.%d", sequential++);
	}
      else
	{
	  filename = (char *) malloc(strlen(style_names[tblcount])+5);
	  strcpy(filename, style_names[tblcount]);
	  strcpy(filename+strlen(style_names[tblcount]),".afm");
	  
	  for (ch = filename;
	       *ch;
	       ch++)
	    if (*ch < 32 || *ch > 126)
	      *ch = '-';
	}
      
      fprintf (stderr, "Writing AFM file to %s.\n", filename);
      afm = fopen(filename, "w");

      fprintf (afm, "StartFontMetrics 3.0\n");
      fprintf (afm, "Comment Created by MacFont vers %s.\n", Vers);
      fprintf (afm, "Comment MacFont Copyright (C) 1993 by Norman Walsh\n");
      fprintf (afm, "Comment Free software.  No warranty.\n");
      fprintf (afm, "FontName %s\n", style_names[tblcount]);
      fprintf (afm, "FullName %s\n", style_longnames[tblcount]);
      fprintf (afm, "FamilyName %s\n", familyname);
      fprintf (afm, "Weight %s\n", weight);
      fprintf (afm, "FontBBox 0 %d %d %d\n",
	       (int) (frac2real(Fond.Descent)*1000),
	       (int) (frac2real(Fond.WidMax)*1000),
	       (int) (frac2real(Fond.Ascent)*1000));
      fprintf (afm, "EncodingScheme %s\n", encoding_scheme);

      fprintf (afm, "StartCharMetrics %d\n",
	       Fond.LastChar-Fond.FirstChar+1);
      
      curWidths = Widths[tblcount];
      for (count = Fond.FirstChar; count <= Fond.LastChar; count++)
	{
	  fprintf(afm,"C %3d ; WX %d ; N %s ; B 0 %d %d %d ;\n", 
		  count,
		  curWidths[count],
		  encoding[count],
		  (int) (frac2real(Fond.Descent) * 1000),
		  curWidths[count],
		  (int) (frac2real(Fond.Ascent) * 1000));
	}

      fprintf (afm, "EndCharMetrics\n");

      if (Fond.KrnTblOfs == 0)
	{
	  fprintf(afm, "StartKernData\n");
	  fprintf(afm, "StartKernPairs 0\n");
	  fprintf(afm, "EndKernPairs\n");
	  fprintf(afm, "EndKernData\n");
	}
      else
	write_kerns(offset+Fond.KrnTblOfs,afm);

      fprintf(afm, "EndFontMetrics\n");
      fclose(afm);
    }

  if (bdfopt)
    {
      RsrcRefStruct *curRef;
      int refcount;

      for (count = 0; count < Fond.NumFonts; count++)
	{
	  curRef = Mac_refs[NFNTnum];
	  for (refcount = 0; refcount < Mac_types[NFNTnum].Count; refcount++)
	    {
	      if (curRef->Ident == Fond.AssocTable[count].ResourceNumber)
		write_nfnt(Mac_header.DataOffset + curRef->DataOffset,
			   Fond.AssocTable[count], 
			   style_names[Fond.AssocTable[count].StyleCode], 
			   curRef->Ident,
			   sequential);
	      curRef++;
	    }
	}
    }
}

int main (int argc, char **argv)
{
  int dump_input = 1;
  int Mac_typeCount;
  int count;
  char outputname[80];
  int outputcount = 1;
  FILE *encinput;

  char opt;
  char *optstring = "ap:e:E:dsw:b";
  char *pfafile   = 0;
  char *encfile   = 0;
  char *rsrcfile  = 0;
  int  pfaopt     = 0;
  int  afmopt     = 0;
  int  bdfopt     = 0;
  int  encopt     = 0;
  int  sequential = 0;

  fprintf (stderr,"MacFont vers %s.  Copyright (C) 1993 by Norman Walsh.\n",
	   Vers);
  fprintf (stderr,"Portions Copyright (C) 1992, 1993, Metis Technology, Inc.\n");

  /* ********************************************************************** */
  /* Read the command line arguments.  This is really crudely done!         */

  weight = 0;

  opterr = 0;
  while ((opt = getopt (argc, argv, optstring)) != EOF) 
    {
      switch (opt)
	{
	case '?':
	  fprintf(stderr,"Invalid option.\n");
	  exit(1);
	  break;

	case 'a':
	  afmopt = 1;
	  break;

	case 'b':
	  bdfopt = 1;
	  break;

	case 's':
	  sequential = 1;
	  break;

	case 'p':
	  pfaopt = 1;
	  pfafile = optarg;
	  break;

	case 'e':
	  encopt = 1;
	  encfile = optarg;
	  break;

	case 'E':
	  encoding_scheme = optarg;
	  break;

	case 'w':
	  weight = optarg;
	  break;

	case 'd':
	  debug = 1;
	  break;
	}
    }

  rsrcfile = argv[optind];

  if (!rsrcfile) 
    {
      fprintf(stderr, "You must supply a resource file.\n");
      fprintf(stderr, "\nUsage  : %s <opts> macfile\n", argv[0]);
      fprintf(stderr, "Where  : macfile is a Macintosh resource fork.\n");
      fprintf(stderr, "Options: -a      = extract AFM file from FOND.\n");
      fprintf(stderr, "         -b      = extract BDF bitmap fonts from NFNT.\n");
      fprintf(stderr, "         -p file = extract PFA file from POST into `file'.\n");
      fprintf(stderr, "         -d      = dump resource data (debugging).\n");
      fprintf(stderr, "         -e file = load encoding vector from `file'.\n");
      fprintf(stderr, "         -E name = change EncodingScheme name in AFM.\n");
      fprintf(stderr, "         -s      = extract AFM files with sequential names.\n");
      fprintf(stderr, "         -w wght = change Weight to `wght' in AFM.\n");
      exit(1);
    }

  if (!weight)
    weight = "Normal";

  input = fopen(rsrcfile,"r");
  if (!input)
    {
      fprintf (stderr, "Can't open resource file: %s\n", rsrcfile);
      exit(1);
    }

  if (encopt && encfile)
    {
      char line[80];

      if (!encoding_scheme)
	encoding_scheme = "FontSpecific";

      encinput = fopen(encfile,"r");
      if (!encinput)
	{
	  fprintf (stderr, "Can't open encoding file: %s\n", encfile);
	  exit(1);
	}

      for (count = 0; count < 256; count++)
	{
	  fgets(line, 80, encinput);
	  line[strlen(line)-1] = 0;

	  if (strncmp(line, ".notdef", 7) == 0)
	    encoding[count] = NULL;
	  else
	    {
	      encoding[count] = (char *) malloc(strlen(line)+1);
	      strcpy(encoding[count], line);
	    }
	}

      if (debug)
	{
	  printf("Encoding:\n");
	  for (count = 0; count < 256; count++)
	    if (encoding[count])
	      printf("\t%3d `%s'\n", count, encoding[count]);
	    else
	      printf("\t%3d `.notdef'\n", count);
	}
    }

  if (!encoding_scheme)
    encoding_scheme = "AppleStandard";

  /* ********************************************************************** */
  /* Read the Mac resource file ...                                         */

  Mac_header = read_mac_header();

  fseek(input, Mac_header.MapOffset, 0);

  Mac_map = read_mac_map();

  if (debug)
    dump_mac_header(Mac_header, Mac_map);

  fseek(input, Mac_header.MapOffset + Mac_map.TypeOffset, 0);

  Mac_typeCount = read_macshortint()+1;
  Mac_types = (RsrcTypeStruct *) malloc (Mac_typeCount*sizeof(RsrcTypeStruct));
  Mac_refs = (RsrcRefStruct **) malloc (Mac_typeCount*sizeof(RsrcRefStruct));

  POSTnum = -1;
  FONDnum = -1;
  NFNTnum = -1;
  for (count = 0; count < Mac_typeCount; count++)
    {
      Mac_types[count] = read_mac_type();
      if (strncmp (Mac_types[count].Name, "POST", 4) == 0)
	POSTnum = count;
      if (strncmp (Mac_types[count].Name, "FOND", 4) == 0)
	FONDnum = count;
      if (strncmp (Mac_types[count].Name, "NFNT", 4) == 0)
	NFNTnum = count;
    }

  for (count = 0; count < Mac_typeCount; count++)
    {
      RsrcRefStruct *curRef;
      int ref_count;

      curRef = (RsrcRefStruct *) malloc(Mac_types[count].Count
					* sizeof(RsrcRefStruct));

      Mac_refs[count] = curRef;

      fseek(input,
            Mac_header.MapOffset
            + Mac_map.TypeOffset
            + Mac_types[count].RefOffset,
            0);

      for (ref_count = 0; ref_count < Mac_types[count].Count; ref_count++)
	{
	  *curRef = read_mac_ref();
	  curRef++;
	}
    }

  if (debug)
    for (count = 0; count < Mac_typeCount; count++)
      {
	RsrcRefStruct *curRef;
	int ref_count;
	
	curRef = Mac_refs[count];
	dump_mac_info(Mac_types[count], *curRef++);
	for (ref_count = 1; ref_count < Mac_types[count].Count; ref_count++)
	  dump_mac_info2(*curRef++);
      }

  /* ********************************************************************** */
  /* Dump out the POST and FOND resources, as requested                     */

  if (pfaopt)
    {
      if (POSTnum >= 0) 
	{
	  RsrcRefStruct *curRef = Mac_refs[POSTnum];

	  fprintf (stderr, "Writing PFA file to %s.\n", pfafile);
	  sprintf(outputname, pfafile);
	  output = fopen(outputname, "w");
	  write_post(Mac_types[POSTnum].Count,
		     Mac_header.DataOffset + curRef->DataOffset);
	  fclose(output);
	}
      else
	fprintf (stderr, "No POST found in %s.\n", rsrcfile);
    }

  if (afmopt || bdfopt)
    {
      if (FONDnum >= 0) 
	{
	  RsrcRefStruct *curRef = Mac_refs[FONDnum];
	  int refcount;

	  for (refcount = 0; refcount < Mac_types[FONDnum].Count; refcount++)
	    {
	      write_fond(Mac_header.DataOffset + curRef->DataOffset,
			 curRef->Ident,
			 afmopt, bdfopt,
			 sequential);
	      curRef++;
	    }
	}
      else
	fprintf (stderr, "No metrics or bitmaps found in %s.\n", rsrcfile);
    }

  exit (0);
}


