CONST
  bufSize = 32768;
Type
  PTree = ^TTree;
  TTree = record
    info : byte;
    ti   : longint;
    Left : PTree;
    Right: PTree;
  end;
    ps  = ^el;
    el  = record
        data : PTree;
        prev : ps;
    end;

CONST
  fname  : string[13] = 'input.txt';
  fout   : string[13] = 'input.huf';

VAR
  INP,OUT	:  FILE;
  USED          :  set of byte;
  Nums          :  ps;
  THead         :  PTree;
{-----}
  Code          :  longint;
  CodeLen       :  byte;
{-----}
  GO,GNum       :  byte;
  done			: boolean;
  Size,Csize    : longint;
{---------------------------------}
var
{FReadBuf}
   RBBuf, RBread    : ^BYTE;
   RBcount          : word;
   RBsize           : word;
   RBFirst, RBLast  : boolean;
{FReadBuf}
Function FReadBuf(var F:FILE;var val:byte):boolean;
begin
  if RBFirst then
   begin
    RBfirst:=false;
    GetMem(RBBuf,BUFSize);
    RBcount:=0;
    RBSize:=0;
   end;
  if RBLast then
   begin
    RBLast:=false;
    FreeMem(RBBuf,BufSize);
    RBFirst:=true;
    exit;
   end;
  If RBcount=RBsize then
   begin
     BlockRead(F,RBBuf^,BufSize,RBsize);
    if Rbsize=0 then
      begin
        FReadBuf:=false;
        exit;
      end;
     RBcount:=0;
   end;
  RBread:=PTR(SeG(RBBUF^),Ofs(RBbuf^)+RBcount);
  inc(RBcount);
  val:=RBread^;
  FReadBuf:=true;
end; {FReadBuf}
{-----------------------------------------}
var
{FWriteBuf}
   WBBuf,WBwrt      : ^BYTE;
   WBcount          : word;
   WBFirst, WBLast  : boolean;
{FWritebuf}
Procedure FWriteBuf(var F:FILE;val:byte);
begin
  if WBFirst then
   begin
    WBfirst:=false;
    GetMem(WBBuf,BUFSize);
    WBcount:=0;
   end;
  if WBLast then
   begin
    WBLast:=false;
    BlockWrite(F,WBBuf^,WBcount);
    FreeMem(WBBuf,BufSize);
    WBFirst:=true;
    exit;
   end;
  WBwrt:=PTR(SeG(WBBUF^),Ofs(WBbuf^)+WBcount);
  inc(WBcount);
  WBwrt^:=val;
  If WBcount=BUFsize then
   begin
     BlockWrite(F,WBBuf^,WBcount);
     WBcount:=0;
   end;
end;{FWriteBuf}
{-----------------------------------------}
Procedure DelBranch(br:PTree);
begin
  if br^.left <> nil then DelBranch(br^.left);
  if br^.right <> nil then DelBranch(br^.right);
  Dispose(br);
end;{DelBranch}
{------------------------------------------}
Procedure AddItem(var HEAD:ps; VAL : PTree);
var
 c,NEWs : ps;
Begin
 c := HEAD;
 New(News);
 News^.data := VAL;
 News^.prev := nil;
 if c=nil then begin HEAD := NEWs; exit end;
 if val^.ti <= C^.DATA^.ti then begin News^.prev:=C; HEAD:=News; exit end;
 while (c^.prev <> nil) and
   (not ((val^.ti>C^.data^.ti) and (val^.ti<=C^.prev^.data^.ti))) do
     c:=c^.prev;
 News^.prev := c^.prev;
 C^.prev := News;
end;{AddItem}
{---------------------------------}
Procedure RemoveItem(var HEAD:ps; VAL : PTree);
var
 c,cur : ps;
Begin
 c := HEAD;
 if c=nil then exit;
 if c^.data = val then begin HEAD:=C^.prev; Dispose(C); exit end;
 while (c^.prev <> nil) and (C^.prev^.data <> val) do c:=c^.prev;
 if c^.prev^.data <> val then exit;
 cur := c^.prev;
 C^.prev := cur^.prev;
 Dispose(cur);
end;{RemoveItem}
{---------------------------------}
Procedure DeleteAll(var HEAD:ps);
var
 c:ps;
begin
  while HEAD <> nil do
   begin
     c:=HEAD^.prev;
     Dispose(HEAD);
     HEAD := C;
   end;
end;{DeleteAll}
{---------------------------------}
Procedure GetCode(VAL:Byte;BRA:PTree;cur:longint;len:byte);
begin
  if (Bra^.left=nil) and (Bra^.right=nil) and (BRA^.info = VAL) then
   begin
      Code := cur;
      CodeLen:=len;
   end;
  if (Bra^.left<>nil) then begin
   GetCode(val,Bra^.left,(cur shl 1) + 1,len+1);
   GetCode(val,Bra^.right,(cur shl 1),len+1)
  end;
end;{GetCode}
{---------------------------------}
Function GetByte(cur:string):byte;
var ret:byte;
begin
  ret:=0;
  while length(cur)>0 do
   begin
    ret:=ret shl 1 + ord(cur[1])-ord('0');
    delete(cur,1,1);
   end;
   GetByte:=ret;
end;{GetByte}
{---------------------------------}
Procedure IfNeedWrite(var gg:longint;var F:FILE);
var
  FFF : byte;
begin
   FFF := gg and $0FF;
   FWriteBuf(F,Fff);
end;{IfNeedWrite}
{---------------------------------}
Function GetBit(var F:File):boolean;
begin
  if GNum = 0 then
   begin
     GNum:=8;
     inc(CSize);
     done:=FReadBuf(F,GO);
     if not done then
      begin
       RBLast:=true;
       FReadBuf(F,GO);
       WBLast:=true;
       FWriteBuf(OUT,0);
       close(INP);
       Close(OUT);
       Halt(0);
      end;
     if csize=Size-1 then done:=FReadBuf(F,GNum);
   end;
  Dec(GNum);
  GetBit := (GO and 128) = 128;
  Go := GO shl 1;
end;{GetBit}
{---------------------------------}
VAR
  CURCODE       : longint;
  curlen        : byte;
  CUR           : byte;
  i             : byte;
  Ctr           : Ptree;
BEGIN
  if (ParamCount<1) then
   begin
     WriteLn('Usage: HUF.exe <FILENAME.EXT> [OUTNAME.ext]');
     Halt(10);
   end;
  Fname := ParamStr(1);
  for size := 1 to Length(Fname) do
   fname[size] := UpCase(fname[size]);
  if pos('.HUF',fname) = 0 then
  begin
   if Paramcount = 2 then fout := ParamStr(2) else
   fout := Copy(Fname,1,pos('.',Fname)) + 'HUF';
   Assign(INP,Fname);
   Reset(INP,1);
   Size:=FileSize(INP);
   Assign(OUT,Fout);
   Rewrite(OUT,1);
   BlockWrite(OUT,Fname,14);
   curcode:=0;
   curlen:=0;
   csize:=0;
   RBFirst:=true;
   RBLast:=false;
   WBFirst:=true;
   WBLast:=false;
   while FReadBuf(INP,CUR) do
    begin
     inc(csize);
     if cur in USED then
      begin
        AddItem(HEAD)
      end
     else
      begin

      end;
     Write(#13'Complete: ',round((csize/size)*100),'%');
    end;
   if (curlen <> 0) then
    begin
      curcode := curcode shl (7-curlen);
      ifNeedWrite(curcode,OUT);
    end
   else
   curlen:=7;
   FWriteBuf(OUT,curlen);
   RBLast:=true;
   FReadBuf(INP,cur);
   WBLast:=true;
   FWriteBuf(OUT,0);
   Close(OUT);
   Close(INP);
  end
 else
  begin
  end;
END.