#!/usr/local/bin/bash
######################################################################
#                               gff2ps                               #
######################################################################
#
#     Converting GFF files to PostScript.
#
#   Copyright (C) 1999/2008 - Josep Francesc ABRIL FERRANDO
#                                    Roderic GUIGO SERRA
#
# 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.
#
######################################################################
#
# Creation Date: 01.03.1999
# Last Update:
#         $Id: gff2ps,v 1.111 2008/08/27 13:37:35 lopep Exp lopep $
#
# Autor : Josep Francesc ABRIL FERRANDO
# e-mail: jabril@imim.es
#
# ( ./gff2ps -vC mygffcustomfile -- samples/data.gff > samples/.ps ) > & samples/report.
#
#
SECONDS=0; # For timing purposes

# Only for testing (only works in bash)
# set -o xtrace

if [ -z "$GAWK_DIR" ];
  then
    GAWK_DIR="/usr/bin";
  fi;
GAWK="$GAWK_DIR/gawk";

# Forcing LOCALE settings to define decimal separator as '.'
# (ie, instead of ','), which is required by the PostScript syntax
export LC_NUMERIC="C";

# Check SORT Version
if sort -k 1 </dev/null >/dev/null 2>&1;
  then
    POSIX_SORT=1;
  else
    POSIX_SORT=0;
  fi;

##############################################################
#################### PROGRAM DEFINITIONS #####################
#
# TT_start=`date +%T`;
CMDLine=$0" "$*;
PID=$$;
TEMP="/tmp";
if [ $GFF2PS_TMP ];
  then
    if [ -d "$GFF2PS_TMP" ];      ###### Environment variable for temporary files directory.
      then
        TEMP="$GFF2PS_TMP";
      fi;
  fi;
PSHEAD=$TEMP/HEADPS.$PID;
PSMAIN=$TEMP/MAINPS.$PID;
GWKPRG=$TEMP/GAWKCODE.$PID;
GWKOPT=$TEMP/GAWKOPTS.$PID;

#
# To delete temporary files if program breaks...
trap "rm -f $GWKPRG $GWKOPT $PSHEAD $PSMAIN 2>/dev/null; exit 1" 0 1 2 3 9 15 ;

#
# Defining Default Values...
RCSVERSION='$Id: gff2ps,v 1.111 2008/08/27 13:37:35 lopep Exp lopep $';
AAA=`echo $RCSVERSION | $GAWK '{ print substr($0,2,length($0)-2); }'`;
#
Defaults () {
  #
  # Constants:
  PROGRAM="gff2ps";
  GAWK_PROG="gff2ps.awk";
  VERSION="v0.98l";
  CREATIONDATE="1999/03/01"; # PSCREATION="1999/03/01"
  REVISION=`echo $RCSVERSION | $GAWK '{print $3}'`;
  DATERELEASE=`echo $RCSVERSION | $GAWK '{print $3,$4}'`;
  PSPROGRAM="PostScript Output from gff2ps";
  AUTHOR="Josep Francesc ABRIL FERRANDO";
  EMAIL="jabril@imim.es";
  USAGE=$PROGRAM" [-h] [ ...(See available options with -h)... ] -- gff_files";
  COLORS="       Basic Colors: black white
       Variable Colors: grey magenta violet blue skyblue cyan seagreen green limegreen yellow orange red brown
       You can get five color shades from Variable Colors with \"verydark\", \"dark\", \"light\" and \"verylight\" prefixes.
         An example: verydarkseagreen darkseagreen seagreen lightseagreen verylightseagreen";
  PAGES="       From A0 to A10, from B0 to B10, 10x14, executive, folio, ledger, legal, letter, quarto, statement and tabloid.";
  #
  # Default User-Defined Options:
  CFDIR=`pwd`;
  if [ $GFF2PS_CFDIR ];
    then
      if [ -d "$GFF2PS_CFDIR" ];      ###### Environment variable for custom file directory.
        then
          CFDIR="$GFF2PS_CFDIR";
        fi;
    fi;
  bgcolor="white";
  fgcolor="black";
  v01=0; n01="load_customfile";
  v02=""; n02="customfile_name";
  if [ $GFF2PS_CUSTOMFILE ];         ###### Environment variable for default custom file name.
    then
      v03="$CFDIR/$GFF2PS_CUSTOMFILE";
    else
      v03="$CFDIR/.gff2psrc";
    fi;
    n03="customfile_name_default";
  v04=0; n04="exist_default_customfile";
  v04_1=0; n04_1="create_default_customfile";
  v05=0; n05="print_report";
  v06="!!!???"; n06="page_orientation"; # "Landscape"
  v07="!!!???"; n07="page_size"; # "a4"
  v08="!!!???"; n08="page_number"; # 1
  v09="!!!???"; n09="blocks_x_page"; # 1
  v10="!!!???"; n10="nucleotides_x_line"; # 0
  v11="!!!???"; n11="show_blocks_top-bottom"; # 1
  v12="!!!???"; n12="page_bbox"; # "auto,0,0"
  v13="!!!???"; n13="major_tickmarks_num"; # 10
  v14="!!!???"; n14="major_tickmarks_nucleotides"; # -1
  v15="!!!???"; n15="minor_tickmarks_num"; # 10
  v16="!!!???"; n16="minor_tickmarks_nucleotides"; # -1
  v17="!!!???"; n17="show_positions"; # "false"
  v18_s='*'; v18_e='*'; n18="zoom_cmdln";
  v19="!!!???"; n19="foreground_color"; # "FGcolor"
  v20="!!!???"; n20="background_color"; # "BGcolor"
  v21="!!!???"; n21="header_style"; # "default"
  v22="!!!???"; n22="show_page_numbers"; # "on"
  v23="!!!???"; n23="show_date"; # "on"
  v24="!!!???"; n24="show_time"; # "on"
  v25="!!!???"; n25="title"; # "default"
  v26="!!!???"; n26="subtitle"; # "default"
  v27="!!!???"; n27="strand_show_forward"; # "on"
  v28="!!!???"; n28="strand_show_reverse"; # "on"
  v29="!!!???"; n29="strand_show_independent"; # "on"
  v30="!!!???"; n30="frame0_color"; # "blue"
  v31="!!!???"; n31="frame1_color"; # "red"
  v32="!!!???"; n32="frame2_color"; # "green"
  v33="!!!???"; n33="frame_unknown_color"; # "orange"
  v34=1; n34="quiet_mode";
  v35=1; n35="Show_Credits";
  v36="!!!???"; n36="page_bbox"; # "name,width,height"
  #
  CHOSFLG=0;
  CHOSFILE="none";
} # End of Defaults

#
# Default ColorDefinition:
#
colorDef () { # still not defined seagreen and limegreen (now same as green)
  cat <<'@@@COLORS@@@'
%
% COLORS.gff2ps,v 1.3 1999/12/14 09:20:05 jabril Exp jabril
%
% black+grey+white
black               0.00 0.00 0.00 1.00
greyd               0.00 0.00 0.00 0.90
verydarkgrey        0.00 0.00 0.00 0.80
greyc               0.00 0.00 0.00 0.70
darkgrey            0.00 0.00 0.00 0.60
greyb               0.00 0.00 0.00 0.50
grey                0.00 0.00 0.00 0.40
greya               0.00 0.00 0.00 0.30
lightgrey           0.00 0.00 0.00 0.20
verylightgrey       0.00 0.00 0.00 0.10
% lgrey             0.00 0.00 0.00 0.25
% vgrey             0.00 0.00 0.00 0.15
% vvgrey            0.00 0.00 0.00 0.05
white               0.00 0.00 0.00 0.00
% magenta
verydarkmagenta     0.00 1.00 0.00 0.30
darkmagenta         0.00 0.80 0.00 0.05
magenta             0.00 0.60 0.00 0.00
lightmagenta        0.00 0.40 0.00 0.00
verylightmagenta    0.00 0.20 0.00 0.00
% violet
verydarkviolet      0.45 0.85 0.00 0.00
darkviolet          0.30 0.65 0.00 0.00
violet              0.22 0.55 0.00 0.00
lightviolet         0.15 0.40 0.00 0.00
verylightviolet     0.10 0.20 0.00 0.00
% blue
verydarkblue        1.00 1.00 0.00 0.20
darkblue            0.90 0.90 0.00 0.00
blue                0.75 0.75 0.00 0.00
lightblue           0.50 0.50 0.00 0.00
verylightblue       0.30 0.30 0.00 0.00
% skyblue
verydarkskyblue     0.90 0.50 0.00 0.15
darkskyblue         0.75 0.45 0.00 0.00
skyblue             0.60 0.38 0.00 0.00
lightskyblue        0.45 0.25 0.00 0.00
verylightskyblue    0.30 0.15 0.00 0.00
% cyan
verydarkcyan        1.00 0.00 0.00 0.10
darkcyan            0.80 0.00 0.00 0.00
cyan                0.60 0.00 0.00 0.00
lightcyan           0.40 0.00 0.00 0.00
verylightcyan       0.20 0.00 0.00 0.00
% seagreen
verydarkseagreen    0.75 0.00 0.45 0.00
darkseagreen        0.62 0.00 0.38 0.00
seagreen            0.50 0.00 0.30 0.00
lightseagreen       0.38 0.00 0.22 0.00
verylightseagreen   0.25 0.00 0.15 0.00
% green
verydarkgreen       1.00 0.00 1.00 0.25
darkgreen           0.80 0.00 0.80 0.00
green               0.60 0.00 0.60 0.00
lightgreen          0.40 0.00 0.40 0.00
verylightgreen      0.20 0.00 0.20 0.00
% limegreen
verydarklimegreen   0.50 0.00 1.00 0.10
darklimegreen       0.40 0.00 0.95 0.00
limegreen           0.30 0.00 0.80 0.00
lightlimegreen      0.20 0.00 0.65 0.00
verylightlimegreen  0.10 0.00 0.50 0.00
% yellow
verydarkyellow      0.00 0.00 1.00 0.25
darkyellow          0.00 0.00 1.00 0.10
yellow              0.00 0.00 1.00 0.00
lightyellow         0.00 0.00 0.50 0.00
verylightyellow     0.00 0.00 0.25 0.00
% orange
verydarkorange      0.00 0.50 0.80 0.10
darkorange          0.00 0.40 0.80 0.00
orange              0.00 0.30 0.80 0.00
lightorange         0.00 0.20 0.75 0.00
verylightorange     0.00 0.15 0.70 0.00
% red
verydarkred         0.00 1.00 1.00 0.15
darkred             0.00 0.80 0.80 0.00
red                 0.00 0.60 0.60 0.00
lightred            0.00 0.40 0.40 0.00
verylightred        0.00 0.20 0.20 0.00
% brown
verydarkbrown       0.35 0.85 1.00 0.40
darkbrown           0.30 0.70 1.00 0.35
brown               0.25 0.75 1.00 0.25
lightbrown          0.20 0.60 0.70 0.15
verylightbrown      0.15 0.45 0.55 0.00
%
% ucsc chr color palette
vdubrown     0.00 0.33 1.00 0.67
dubrown      0.00 0.33 1.00 0.52
ubrown       0.00 0.33 1.00 0.40
lubrown      0.00 0.19 0.57 0.27
vlubrown     0.00 0.12 0.35 0.19
vdudolive    0.00 0.00 1.00 0.78
dudolive     0.00 0.00 1.00 0.68
udolive      0.00 0.00 1.00 0.60
ludolive     0.00 0.00 0.47 0.41
vludolive    0.00 0.00 0.26 0.28
vdulolive    0.00 0.00 0.80 0.67
dulolive     0.00 0.00 0.80 0.52
ulolive      0.00 0.00 0.80 0.40
lulolive     0.00 0.00 0.45 0.27
vlulolive    0.00 0.00 0.28 0.19
vdubrick     0.00 1.00 1.00 0.56
dubrick      0.00 1.00 1.00 0.36
ubrick       0.00 1.00 1.00 0.20
lubrick      0.00 0.64 0.64 0.14
vlubrick     0.00 0.42 0.42 0.09
vdured       0.00 1.00 1.00 0.45
dured        0.00 1.00 1.00 0.20
ured         0.00 1.00 1.00 0.00
lured        0.00 0.69 0.69 0.00
vlured       0.00 0.47 0.47 0.00
vdupink      0.00 1.00 0.20 0.45
dupink       0.00 1.00 0.20 0.20
upink        0.00 1.00 0.20 0.00
lupink       0.00 0.69 0.14 0.00
vlupink      0.00 0.47 0.09 0.00
vdusalmon    0.00 0.20 0.20 0.45
dusalmon     0.00 0.20 0.20 0.20
usalmon      0.00 0.20 0.20 0.00
lusalmon     0.00 0.14 0.14 0.00
vlusalmon    0.00 0.09 0.09 0.00
vdudorange   0.00 0.40 1.00 0.45
dudorange    0.00 0.40 1.00 0.20
udorange     0.00 0.40 1.00 0.00
ludorange    0.00 0.27 0.69 0.00
vludorange   0.00 0.19 0.47 0.00
vdulorange   0.00 0.20 1.00 0.45
dulorange    0.00 0.20 1.00 0.20
ulorange     0.00 0.20 1.00 0.00
lulorange    0.00 0.14 0.69 0.00
vlulorange   0.00 0.09 0.47 0.00
vduyellow    0.00 0.00 1.00 0.45
duyellow     0.00 0.00 1.00 0.20
uyellow      0.00 0.00 1.00 0.00
luyellow     0.00 0.00 0.69 0.00
vluyellow    0.00 0.00 0.47 0.00
vdulgreen    0.20 0.00 1.00 0.45
dulgreen     0.20 0.00 1.00 0.20
ulgreen      0.20 0.00 1.00 0.00
lulgreen     0.14 0.00 0.69 0.00
vlulgreen    0.09 0.00 0.47 0.00
vdugreen     1.00 0.00 1.00 0.45
dugreen      1.00 0.00 1.00 0.20
ugreen       1.00 0.00 1.00 0.00
lugreen      0.69 0.00 0.69 0.00
vlugreen     0.47 0.00 0.47 0.00
vdudgreen    0.59 0.00 1.00 0.72
dudgreen     0.59 0.00 1.00 0.60
udgreen      0.59 0.00 1.00 0.50
ludgreen     0.31 0.00 0.52 0.34
vludgreen    0.18 0.00 0.31 0.24
vdudblue     1.00 1.00 0.00 0.56
dudblue      1.00 1.00 0.00 0.36
udblue       1.00 1.00 0.00 0.20
ludblue      0.64 0.64 0.00 0.14
vludblue     0.42 0.42 0.00 0.09
vdumblue     0.60 0.40 0.00 0.45
dumblue      0.60 0.40 0.00 0.20
umblue       0.60 0.40 0.00 0.00
lumblue      0.41 0.27 0.00 0.00
vlumblue     0.28 0.19 0.00 0.00
vdulblue     0.40 0.20 0.00 0.45
dulblue      0.40 0.20 0.00 0.20
ulblue       0.40 0.20 0.00 0.00
lulblue      0.27 0.14 0.00 0.00
vlulblue     0.19 0.09 0.00 0.00
vdudcyan     1.00 0.00 0.00 0.45
dudcyan      1.00 0.00 0.00 0.20
udcyan       1.00 0.00 0.00 0.00
ludcyan      0.69 0.00 0.00 0.00
vludcyan     0.47 0.00 0.00 0.00
vdulcyan     0.20 0.00 0.00 0.45
dulcyan      0.20 0.00 0.00 0.20
ulcyan       0.20 0.00 0.00 0.00
lulcyan      0.14 0.00 0.00 0.00
vlulcyan     0.09 0.00 0.00 0.00
vdudpurple   0.25 1.00 0.00 0.56
dudpurple    0.25 1.00 0.00 0.36
udpurple     0.25 1.00 0.00 0.20
ludpurple    0.16 0.64 0.00 0.14
vludpurple   0.10 0.42 0.00 0.09
vdumpurple   0.20 0.80 0.00 0.45
dumpurple    0.20 0.80 0.00 0.20
umpurple     0.20 0.80 0.00 0.00
lumpurple    0.14 0.55 0.00 0.00
vlumpurple   0.09 0.38 0.00 0.00
vdulpurple   0.20 0.40 0.00 0.45
dulpurple    0.20 0.40 0.00 0.20
ulpurple     0.20 0.40 0.00 0.00
lulpurple    0.14 0.27 0.00 0.00
vlulpurple   0.09 0.19 0.00 0.00
vdudgrey     0.00 0.00 0.00 0.78
dudgrey      0.00 0.00 0.00 0.68
udgrey       0.00 0.00 0.00 0.60
ludgrey      0.00 0.00 0.00 0.41
vludgrey     0.00 0.00 0.00 0.28
vdumgrey     0.00 0.00 0.00 0.67
dumgrey      0.00 0.00 0.00 0.52
umgrey       0.00 0.00 0.00 0.40
lumgrey      0.00 0.00 0.00 0.27
vlumgrey     0.00 0.00 0.00 0.19
vdulgrey     0.00 0.00 0.00 0.56
dulgrey      0.00 0.00 0.00 0.36
ulgrey       0.00 0.00 0.00 0.20
lulgrey      0.00 0.00 0.00 0.14
vlulgrey     0.00 0.00 0.00 0.09
vdudyellow   0.00 0.00 0.25 0.56
dudyellow    0.00 0.00 0.25 0.36
udyellow     0.00 0.00 0.25 0.20
ludyellow    0.00 0.00 0.16 0.14
vludyellow   0.00 0.00 0.10 0.09
vdumgreen    0.41 0.00 0.70 0.56
dumgreen     0.41 0.00 0.70 0.36
umgreen      0.41 0.00 0.70 0.20
lumgreen     0.26 0.00 0.45 0.14
vlumgreen    0.17 0.00 0.29 0.09
%
@@@COLORS@@@
} # End of colorDef

##############################################################
################### SHELL MAIN FUNCTIONS #####################
#
# Defining Help...
Help () {
  # echo ""
  # echo "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
  # echo "         1         2         3         4         5         6         7         8"
  echo "";
  echo "NAME           $PROGRAM";
  echo "VERSION        $VERSION";
  echo "";
  echo "Creation DATE: $CREATIONDATE";
  echo "Last REVISION: $DATERELEASE";
  echo "";
  echo "SYNOPSIS";
  echo "";
  echo "      $USAGE";
  echo "";
  echo "DESCRIPTION";
  echo "";
  echo "       This program draws color-filled DotPlots";
  echo "       from files with gff-formatted data fields.";
  echo ""; echo "";
  echo "OPTIONS";
  echo "";
  echo "     -h  Shows this help.";
  echo "     -H <option> Shows only help for the especified option.";
  echo "     -V Verbose mode, a full report is sent to standard error (default only sends Warnings).";
  echo "     -v Silent mode: Disable all warnings, no messages sent to standard error.";
  echo "     -d Write (or rewrite if exists) default customfile \"$v03\".";
  echo "     -D <default_custom_filename> Create a new default customfile with the given filename.";
  echo "     -C <custom_filename>  Load given custom file and append to default custom file (.gff2psrc).";
  echo "     -s <page_size> Useful to modify page size (default is a4).";
  echo "     -p Switches page orientation to Portrait (default is Landscape).";
  echo "     -G <color_name> Sets color for FOREGROUND (default is black).";
  echo "     -g <color_name> Sets color for BACKGROUND (default is white).";
  echo "     -P <\#> Sets how many pages are needed to split your output (default is one).";
  echo "     -S <\#> Zoom first nucleotide (default is sequence origin).";
  echo "     -E <\#> Zoom last nucleotide (default is sequence length).";
  echo "     -B <\#> Sets blocks per page (default is one).";
  echo "     -N <\#> Sets nucleotides per line (default is the largest sequence position from input gff-files).";
  echo "     -b Blocks from left to right and from top to bottom (default is top to bottom first).";
  echo "     -L Switch off Header (Title area).";
  echo "     -T <title_string> Defining title (default is input gff filename).";
  echo "     -t <subtitle_string> Defining subtitle (default is none).";
  echo "     -l Does not show page numbering.";
  echo "     -O Does not show date.";
  echo "     -o Does not show time.";
  echo "     -M <\#> Number of major tickmarks per line (default 10).";
  echo "     -K <\#> Major tickmarks scale in nucleotides, default is nucleotide length for lines divided by major tickmarks number (see option -T).";
  echo "     -m <\#> Number of minor tickmarks between major tickmarks (default 10).";
  echo "     -k <\#> Minor tickmarks scale in nucleotides default is major tickmarks size divided by minor tickmarks number (see option -t).";
  echo "     -w or -f Switch off displaying forward-strand(Watson) elements.";
  echo "     -c or -r Switch off displaying reverse-strand(Crick) elements.";
  echo "     -i Switch off displaying strand-independent elements.";
  echo "     -0 <color_name> Sets color for frame \"0\" (default is blue).";
  echo "     -1 <color_name> Sets color for frame \"1\" (default is red).";
  echo "     -2 <color_name> Sets color for frame \"2\" (default is green).";
  echo "     -3 <color_name> Sets color for frame \".\" (default is orange).";
  echo "     -n Switch off labels for element positions.";
  echo "     -a Switch off CopyRight line on plot.";
  echo "";
  echo "ENVIRONMENT VARIABLES";
  echo "";
  echo "   There are three environmental variables that can be set by users to their preferences:";
  echo "   + You can specify the path where GFF2PS can find the default files with the shell variable \"GFF2PS_CFDIR\". Default value is path where you are running GFF2PS.";
  echo "   + You can also define the default custom filename you will like with the variable \"GFF2PS_CUSTOMFILE\", program default filename for custom file is \".gff2psrc\".";
  echo "   + GFF2PS needs to write few temporary files in a directory with permissions for current user to read and write. Default temporary directory path is set to \"/tmp/\" but you can assign a different temporary directory path using the variable \"GFF2PS_TMP\".";
  echo "   + Setting those vars in Bourne-shell and C-shell:";
  echo "     o Using a Bourne-Shell (e.g. bash):";
  echo "           export GFF2PS_CFDIR=\"path\"";
  echo "           export GFF2PS_CUSTOMFILE=\"file_name\"";
  echo "           export GFF2PS_TMP=\"path\"";
  echo "     o Using a C-Shell:";
  echo "           setenv GFF2PS_CFDIR \"path\"";
  echo "           setenv GFF2PS_CUSTOMFILE \"file_name\"";
  echo "           setenv GFF2PS_TMP \"path\"";
  echo "";
  echo "COMMENTS";
  echo "";
  echo "  * Colors defined are:";
  echo "";
  echo "$COLORS";
  echo "";
  echo "  * Page Sizes defined are:";
  echo "";
  echo "$PAGES";
  echo "";
  echo "BUGS";
  echo "";
  echo "  Please, report bugs to:";
  echo "       $AUTHOR";
  echo "       e-mail: $EMAIL";
  echo "";
  echo "  Copyright (C) 1999/2008 - J.F. ABRIL & R. GUIGO";
  echo "";
  return 0;
} # End of Help

ShowHelpLine () {
  Help | $GAWK 'BEGIN{
         IGNORECASE=1; flg=0;
         srch=ARGV[1]; ARGV[1]="";
         gsub("-","",srch); srch="\ -"srch"\ "; }
       { if ($0~srch) { print $0; flg=1; } }
    END{ if (!flg) printf "\n\tERROR: Option %s is not defined,\n\t\tmake sure which option you need help.\n\n",srch;
         }' $1 ;
  return 0;
} # End of ShowHelpLine

##############################################################
################# POSTSCRIPT MAIN FUNCTIONS ##################
#
# Printing PostScript Prolog (Constants,Variables and Functions)...
{
echo '%'; echo '%    *** '$AAA'***';
#
cat <<'@@@EndProlog@@@'
%
%
%      Converting GFF files to PostScript plots.
%
%      Copyright (C) 1999/2008 - Josep Francesc ABRIL FERRANDO
%                                       Roderic GUIGO SERRA
%
%    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.
%
% ------------------------------------------------------------------------
%
%%BeginProlog
%
%%BeginProcSet: ShortNames 1.0 0
/tflg false def % test flag
/D { def } bind def
/B { bind D } bind D
/X { exch D } B
/cm { 28.35 mul } B
/in { 72    mul } B
/mmod { 2 dict begin /y X /x X x x y div truncate y mul sub end } B
%%EndProcSet: ShortNames 1.0 0
%
%%BeginProcSet: Constants 1.0 0
% Printing Offset
/VUpOS 0.25 cm D  % offset defines non printable
/VDnOS 0.25 cm D  % paper area for pages (printer outlimits).
/HLtOS 0.25 cm D
/HRtOS 0.25 cm D
@@@EndProlog@@@
#
colorDef | $GAWK 'BEGIN{ i=0; }
 { if ($1!="%") { count[i++]=$1; C[$1]=$2; M[$1]=$3; Y[$1]=$4; K[$1]=$5; } }
 END {
   printf "%% Fixed Color Variables (CMYK)\n";
   printf "/colordict %s dict D colordict begin %% %s colors + 28 definitions\n", (i+28), i;
   for (j=0;j<i;j++) {
     n=count[j];
     printf "/%-20s { %-4s %-4s %-4s %-4s } D\n", n,C[n],M[n],Y[n],K[n];
   };
   printf "end %% colordict\n";
 }' -
#
} >$PSHEAD
#### End of MAINPSHEADER function ####

#
# Printing Main PostScript Routines...
cat <<'@@@MAINProcs@@@' >$PSMAIN
%%EndProcSet: Setting_Vars 1.0 0
%
%%BeginProcSet: Page_Layout 1.0 0
% checking if margins are within the defined offset
flglscape {
 UpM HLtOS lt { /UpM HRtOS D } if % Checking margins for flglscape mode
 DnM HRtOS lt { /DnM HLtOS D } if
 LtM VDnOS lt { /LtM VUpOS D } if
 RtM VUpOS lt { /RtM VDnOS D } if
 } {
  UpM VUpOS lt { /UpM VUpOS D } if % Checking margins for portrait mode
  DnM VDnOS lt { /DnM VDnOS D } if
  LtM HLtOS lt { /LtM HLtOS D } if
  RtM HRtOS lt { /RtM HRtOS D } if
  } ifelse
% defining pagelimits and X - Y scales (Xlim Ylim)
/pglim { Dpage pop LtM RtM add sub Dpage exch pop UpM DnM add sub } D
% Defining starting point on page.
/XORI flglscape { UpM } { LtM } ifelse D
/YORI flglscape { LtM } { UpM } ifelse D
% Defining page-elements layout.
/XSTitl pglim pop XOriTitl 2 mul sub D
/XSBlck pglim pop D
/FSF 4 D % Point size for Credits for A4
/CSF { pagedict begin pga4 pop end Dpage pop exch div dup
 1 cm gt { pop 1 cm } if dup FSF lt { pop FSF } if } B
/CYSF { pagedict begin pga4 exch pop end Dpage exch pop exch div dup
 1 cm gt { pop 1 cm } if dup FSF lt { pop FSF } if } B
%# /TYSF { pagedict begin pga4 end Dpage 3 2 roll div 3 1 roll exch div div mul } B
%# /YSTitl YSTitl TYSF dup 4 cm gt { pop 4 cm } if dup 0.5 cm lt { pop 0.5 cm } if Titlscl mul D
/YSTitl YSTitl dup 4 cm gt { pop 4 cm } if dup 0.5 cm lt { pop 0.5 cm } if Titlscl mul D
/XOriBlck 0 D
/XSPlot { XSBlck FLftLbl { XLftLbl sub } if FRgtLbl { XRgtLbl sub } if } D
/XOriPlot { XOriBlck FLftLbl { XLftLbl add } if } D
/Xscale XSPlot MaxNuclPage div D
/YOriBlck { FlgTitl { YSTitl BlckSp add } { 0 } ifelse } D
/adcrd { flgcrd { CYSF 2 mul FlgBkBx { 5 add } if sub } if } B
% is2tck == true if must plot two tickmark lines
/is2tck LnBth 0 gt LnFwd 0 gt LnRvs 0 gt and and FlgISU FlgISD and and D
/is1tck LnFwd 0 gt LnBth 0 gt and LnFwd 0 gt LnRvs 0 gt and or
        LnBth 0 gt LnRvs 0 gt and or is2tck or FlgISU FlgISD or and D
%
NBlck 0 eq {
  /YSBlck { pglim exch pop adcrd FlgTitl { YOriTitl YSTitl BlckSp add add sub } if } D
  /YS2Blck { pglim exch pop adcrd FlgTitl { YOriTitl YSTitl BlckSp add add sub } if
   FlgOSU { TkMrkW 1 TkMspc add mul sub } if FlgOSD { TkMrkW 1 TkMspc add mul sub } if } D
  /YSFwd LnFwd D
  /YSBth LnBth D
  /YSRvs LnRvs D
 } {
  /YSBlck { pglim exch pop adcrd FlgTitl { YOriTitl YSTitl add NBlck } { 0 NBlck 1 sub } ifelse
   BlckSp mul add sub NBlck div } D
  /YS2Blck { pglim exch pop adcrd FlgTitl { YOriTitl YSTitl add NBlck } { 0 NBlck 1 sub } ifelse
   BlckSp mul add sub NBlck div FlgOSU { TkMrkW 1 TkMspc add mul sub } if
   FlgOSD { TkMrkW 1 TkMspc add mul sub } if
   is1tck { TkMrkW 1 TkMspc add mul is2tck { TkMrkW 1 TkMspc add mul add } if sub } if } D
  /YSLine YS2Blck LnTot div D
  /tracksize tracksize YSLine mul D
  /spcrsize spcrsize YSLine mul D
  /YSFwd LnFwd YSLine mul D
  /YSBth LnBth YSLine mul D
  /YSRvs LnRvs YSLine mul D
} ifelse
%%EndProcSet: Page_Layout 1.0 0
%
%%BeginProcSet: functions 1.0 0
/msg { print (\n) print flush } B
/mst { print (\n) print flush counttomark 1 add dup { dup index 20 string cvs print ( )
 print 1 sub } repeat (\n) print pop flush } B
/F { scale } B
/T { translate } B
/S { gsave } B
/R { grestore } B
/m { moveto } B
/rm { rmoveto } B
/l { lineto } B
/rl { rlineto } B
/K { stroke } B
/scmyk { setcmykcolor } B
/slw { setlinewidth } B
%%EndProcSet: functions 1.0 0
%
%%BeginProcSet: text_functions 1.0 0
/sfont { findfont exch scalefont setfont } B
/chrh { S newpath 0 0 m false charpath flattenpath pathbbox exch pop 3 -1 roll pop R } B
/strh { 2 dict begin /lly 0.0 D /ury 0.0 D
 { ( ) dup 0 4 -1 roll put chrh dup ury gt { /ury X } { pop } ifelse
 dup lly lt { /lly X } { pop } ifelse } forall ury end } B
/stringheight  { S newpath 0 0 m (0) false charpath flattenpath
 pathbbox exch pop exch sub exch pop 0.95 mul R } B
/ct { S 0 T sfont scmyk dup stringwidth pop 2 div neg stringheight 2 div neg m show R } B
% X Y angle string valign halign fnt color ttxt
% valign : tv (top) cv (middle) bv (bottom) --- halign : lh (left) ch (center) rh (right)
/ttxt { S scmyk sfont 8 dict begin /h X /v X /lbl X /angle X
 /y X /x X /hs lbl stringwidth pop neg D /vs lbl strh neg D
 x y T angle rotate h (rh) eq { hs } { h (ch) eq { hs 2 div } { 0 } ifelse } ifelse
 v (tv) eq { vs } { v (cv) eq { vs 2 div } { 0 } ifelse } ifelse m lbl show end R } B
%%EndProcSet: text_functions 1.0 0
%
%%BeginProcSet: painting_functions 1.0 0
/solidline   { [] 0 setdash } D
/dotted      { [ 1 ] 0 setdash } D
/longdotted  { [ 1 ] 5 setdash } D
/shortdashed { [ 10 ] 10 setdash } D
/longdashed  { [ 20 ] 10 setdash } D
/bbox { 4 copy 3 1 roll exch 6 2 roll 8 -2 roll m l l l closepath } B
/scolor { colordict exch get exec scmyk } B
%
colordict begin % adding definitions and functions
 /lup { /ku X /yu X /mu X /cu X } B
 /lmd { /km X /ym X /mm X /cnm X } B
 /ldn { /kd X /yd X /md X /cd X } B
 /n (-) D
 /load2col { lup ldn /dk ku kd sub D /dy yu yd sub D
                     /dm mu md sub D /dc cu cd sub D } B
 /load3col { lup lmd ldn /uk ku km sub D /uy yu ym sub D
                         /um mu mm sub D /uc cu cnm sub D
                         /dk km kd sub D /dy ym yd sub D
                         /dm mm md sub D /dc cnm cd sub D } B
 /col2 { 2 dict begin /p X p n ne { /pcd { p mul add } B
  cd dc pcd md dm pcd yd dy pcd kd dk pcd } { BGcolor } ifelse scmyk end } B
 /col3 { 3 dict begin /p X p n ne { /pcd { p 2 mul mul add } B
  /pcu { p 0.5 sub 2 mul mul add } B p 0.5 le { cd dc pcd md dm pcd yd dy pcd kd dk pcd }
  { cnm uc pcu mm um pcu ym uy pcu km uk pcu } ifelse } { BGcolor } ifelse scmyk end } B
 /rainbow { 1 dict begin /p X p n ne { p 0.1 le { p 0.2 div 0.5 add 1 0 0 }
  { p 0.4 le { 1 1 p 0.1 sub 0.3 div sub 0 0 } { p 0.6 le { 1 0 p 0.4 sub 0.2 div 0 }
  { p 0.8 le { 1 p 0.6 sub 0.2 div sub 0 1 0 } { 0 p 0.8 sub 0.2 div 1 0
  } ifelse } ifelse } ifelse } ifelse scmyk } if end } B %# <ifelse> } { BGcolor } ifelse scmyk end } B
end % colordict
%%EndProcSet: painting_functions 1.0 0
%
%%BeginProcSet: header_functions 1.0 0
headerdict begin
 /ttfsz { YSTitl 0.50 mul } D
 /stfsz { YSTitl 0.25 mul } D
 /xtfsz { YSTitl 0.25 mul } D
 /sepsz { YSTitl 0.125 mul } D
 /ttfnt { ttfsz /Helvetica-Bold } D
 /stfnt { stfsz /Helvetica      } D
 /dtfnt { xtfsz /Times-Roman    } D
 /tmfnt { xtfsz /Times-Roman    } D
 /pgfnt { xtfsz /Times-Roman    } D
 /ttlong { S ttfnt sfont Title stringwidth pop stfnt sfont
  SubTitle stringwidth pop R 2 copy gt { pop } { exch pop } ifelse 2 div } B
 /Header { S XOriTitl YOriTitl YSTitl add T 1 -1 F ShwTBx { S 0 0 XSTitl YSTitl bbox
  0.125 slw fgcolor scmyk K R } if ShwTt Title () ne and { sepsz ttlong add YSTitl sepsz sub
  0 Title (tv) (ch) ttfnt fgcolor ttxt } if ShwST SubTitle () ne and { sepsz ttlong add sepsz
  0 SubTitle (bv) (ch) stfnt fgcolor ttxt } if ShwDate { XSTitl 4.5 sub xtfsz
  0 Sdate (tv) (rh) tmfnt fgcolor ttxt } if ShwTime { XSTitl 4.5 sub YSTitl 2 div
  0 Stime (cv) (rh) dtfnt fgcolor ttxt } if Shwp_num { XSTitl 4.5 sub YSTitl xtfsz sub
  0 PageNumber (bv) (rh) pgfnt fgcolor ttxt } if R } B
%
 /s_credits { S 1 dict begin /fs_cd CYSF D pglim fs_cd 0.5 mul sub T 1 -1 F 0 0 0
  (This plot has been obtained using gff2ps. The most recent version of gff2ps is freely available at \042http:\/\/genome.imim.es/software/gfftools/GFF2PS.html\042. Copyright      1999/2008 by Josep F. Abril & Roderic Guigo)
  (bv) (rh) fs_cd /Times-Roman fgcolor ttxt S fs_cd /Times-Roman sfont
  (   1999/2008 by Josep F. Abril & Roderic Guigo) stringwidth pop neg R
  0 0 (\343) (bv) (ch) fs_cd /Symbol fgcolor ttxt end R } B
end
%
%%EndProcSet: header_functions 1.0 0
%
%%BeginProcSet: tickmarks 1.5 0
% Rule.ps ---> rules and scales
/tmdct 30 dict D tmdct begin
 /ChkLimits { 3 copy pop 5 2 roll dup dup 5 1 roll 3 1 roll
  lt 3 1 roll gt or { pop false } { true } ifelse } B
 /ShowGrid 0 D % 0 - none : 1 - MinTicks : 2 - MaxTicks : 3 - Both
 /Gridup true D /Griddn true D /flgup true D
 /TkMrkDW TkMrkW 10 div D
 /TkFont { TkMrkHW /Helvetica } D
 /MaxWidthT { S MaxNuclPage 10 string cvs TkFont sfont stringwidth pop 2 mul R } B
 /CheckCloser { 3 copy pop MaxWidthT sub 3 1 roll MaxWidthT add 3 1 roll
  dup dup 5 1 roll 3 1 roll lt 3 1 roll gt or 4 1 roll 3 copy dup 3 1 roll ne 3 1 roll ne
  and 5 -1 roll and { pop false } { true } ifelse } B
 /ctextick { S TkFont sfont dup stringheight 2 div exch stringwidth pop
  2 Xscm div neg Xscm exch 2 copy neg T 2 mul exch 2 mul neg exch
  S 0 0 bbox bgcolor scmyk S tflg { fgcolor scmyk } if 0.75 slw K R
  fill R 0 0 m fgcolor scmyk show R } B
 /bltextick { S TkFont sfont dup stringwidth pop 2 Xscm div neg Xscm TkMrkHW 2 copy
  flgup { TkMrkDW add T } { 2 mul T 1 -1 F } ifelse exch 2 mul neg exch
  S 0 0 bbox bgcolor scmyk S tflg { fgcolor scmyk } if 0.75 slw K R
  fill R 0 0 m fgcolor scmyk show R } B
 /tonormtick { /go true D 2 copy pop 2100000000 gt { /go false D } if
  go { 0 eq { 2 { dup dup 0 ne { MinTick mod } if sub exch } repeat }
  { 2 { dup dup 0 ne { MaxTick mod } if sub exch } repeat } ifelse }
  { pop } ifelse } B %##% WARNING TEMPORARY HACK ON: tonormtick
 /Mkg { 0 0 m l fgcolor scmyk dotted K } B
 % Reset scale numbering
 /CHoffrsc { CHofflen 0 ge { dup CHnext ge { globaldict /CHcurrent globaldict
  /CHnext get put 0 1 CHofflen { CHoffsets exch get dup CHnext gt { globaldict /CHnext 3 -1 roll put exit }
  { pop } ifelse } for } if CHcurrent sub } if } D
 %# the following Mklb prints integer scales
 %# /Mklb { S CHoffrsc 3 dict begin TS 3 eq { 1000000 div round cvi /q exch 20 string cvs D
 %#  /y q length D /h y 2 add string D h 0 q putinterval h y (Mb) putinterval h }
 %#  { TS 2 eq { 1000 div round cvi /q exch 20 string cvs D /y q length D
 %#  /h y 2 add string D h 0 q putinterval h y (Kb) putinterval h }
 %#  { 10 string cvs } ifelse } ifelse end R } B
 % the following Mklb prints 1 decimal position scales
 /mkexp { TrS 0 ne { 10 TrS exp cvi div } if div round
  cvi TrS 0 ne { 10 TrS exp cvi div } if } B
 /Mklb { S CHoffrsc 3 dict begin TS 3 eq { 1000000 mkexp
  /q exch 20 string cvs D /y q length D /h y 2 add string D
  h 0 q putinterval h y (Mb) putinterval h } { TS 2 eq { 1000 mkexp
  /q exch 20 string cvs D /y q length D /h y 2 add string D
  h 0 q putinterval h y (Kb) putinterval h } { 10 string cvs } ifelse } ifelse end R } B
 %
 /MkVGrid { S slw Gridup flgup not { not } if { 0 up Mkg } if
  Griddn flgup not { not } if { 0 down neg Mkg } if  R } B
 /MkAtick { slw 0 TkMrkHW neg m 0 TkMrkHW l fgcolor scmyk K } B
 /MkBtick { S dup Xscm 0 T ShowGrid 2 eq ShowGrid 3 eq or { 0.25 MkVGrid } if
  1 MkAtick CheckCloser { Mklb ctextick } if R } B
 /MkCtick { slw 0 0 m 0 TkMrkHW 3 -1 roll { TkMrkDW sub } if l fgcolor scmyk K } B
 /MkDtick { S dup Xscm 0 T CheckCloser { Mklb bltextick } if
  ShowGrid 2 eq ShowGrid 3 eq or { 0.25 MkVGrid } if false 1 MkCtick R } B
 /baseline { S 2 setlinecap Xscm TkMrkDW 0.75 mul m Xscm TkMrkDW 0.75 mul l
  TkMrkDW 1.5 mul slw fgcolor scmyk K R } B % slw: 1.5 instead of 2
 /r { /Gridup true D /Griddn true D /flgup true D 0 exch TkMrkHW sub
  T S 0 T 1 -1 F 4 { 2 copy } repeat pop neg Xscm 0 T
  0 tonormtick MinTick exch { ChkLimits { S Xscm 0 T
  0.25 MkAtick ShowGrid 1 eq ShowGrid 3 eq or { 0 MkVGrid } if R } if } for
  1 tonormtick MaxTick exch { ChkLimits { MkBtick } if } for
  2 { dup dup 0 ne { MaxTick mmod } if 0 ne { MkBtick } { pop } ifelse } repeat pop pop R } B
 /x { 5 { 2 copy } repeat pop neg Xscm 0 T baseline
  0 tonormtick MinTick exch { ChkLimits { S Xscm 0 T true 0.25 MkCtick
  ShowGrid 1 eq ShowGrid 3 eq or { 0 MkVGrid } if R } if } for
  1 tonormtick MaxTick exch { ChkLimits { MkDtick } if } for
  2 { dup dup 0 ne { MaxTick mmod } if 0 ne { MkDtick } { pop } ifelse } repeat pop pop } B
 /s { /Gridup false D /Griddn true D /flgup true D 0 exch TkMrkW add T S 0 T 1 -1 F x R } B
 /z { /Gridup true D /Griddn false D /flgup false D 0 exch TkMrkW sub T S 0 T 1 1 F x R } B
 /g { /down X /up X S T 2 { 2 copy } repeat pop neg Xscm 0 T
  1 tonormtick MaxTick exch { ChkLimits { S Xscm 0 T 0.125 slw 0 down Mkg R } if } for R pop pop } B
end % tmdct
%%EndProcSet: tickmarks 1.5 0
%
%%BeginProcSet: objects 1.2 0
/shpdct 255 dict D shpdct begin
 /nucdif { 2 copy exch sub } B
 /mtrx matrix D
 /mrr false D
 /LY { Yscl FlgScRM { Flgspos { 0.45 } { 0.7 } ifelse mul } { 0.975 mul } ifelse } B
 /HLY { LY sc mul 2 div } B
 /rt { Yscl } B
 /vst 250 string D
 /clrselc { cvx exec dup 2 eq { pop load2col /clrproc /col2 load D }
  { dup 3 eq { pop load3col /clrproc /col3 load D }
  { dup 0 eq { pop white black load2col /clrproc /col2 load D }
  { dup 4 eq { 5 { pop } repeat /clrproc /rainbow load D }
  { 1 eq { white 8 4 roll load2col /clrproc /col2 load D
  } if } ifelse } ifelse } ifelse } ifelse } B
  % no end for closing dict because grdct must be closed by calling function
 /GetVtVar { /v_cmod X /v_ori X /v_end X
  /sc_ori X sc_ori v_ori gt { /v_ori sc_ori D } if } B
 %
 /doVg { S { currentfile vst readline pop { { token { cvx exec /vtcsc X
  runVl } { exit } ifelse } loop } stopped { exit } if } loop R end } B
 /doVl { /lvtcsc n D strnd (-) eq { 1 -1 F } if
  ScV 0 eq { 0 HLY neg T } if S { currentfile vst readline pop { { token
  { cvx exec /vtcsc exch dup n ne { LY mul ScV 0 ne { 2 mul } if } if D
  runVl } { exit } ifelse } loop } stopped { exit } if } loop R end } B
 %
 % score vector color gradient
 /v { vtcsc clrproc S v_v Xscm 0 T v_s 0 m v_e 0 l
      vtcsc n ne { K } { newpath } ifelse R /v_v v_v VStp add D } B
 /vt { S /VStp X /VWdw X GetVtVar
  colordict begin v_cmod clrselc rt slw
  v_ori 1 sub VWdw 2 div add Xscm 0 T
  /v_s VStp 2 div 1 add Xscm neg D /v_e VStp 2 add Xscm D
  /v_v 0 D /runVl { v } B doVg R } B
  %# (Score-Vector Loop finished...GRADIENT) msg
 %
 % score vector graph
 /vc { v_s Xscm lvtcsc n ne { solidline lvtcsc } { dotted 0 } ifelse
  m v_e Xscm vtcsc n ne { solidline vtcsc } { dotted 0 } ifelse l K
  /v_s v_e D /v_e v_s VStp add D /lvtcsc vtcsc D } B
 /vtc { S /VStp X /VWdw X GetVtVar
  colordict begin v_cmod cvx exec scmyk 0.25 slw
  v_ori 1 sub Xscm 0 T
  /v_s 0 D /v_e VWdw 2 div D /runVl { vc } B doVl R } B
  %# (Score-Vector Loop finished...LINE-PLOT) msg
 %
 % score vector bars
 /vb { vtcsc n ne { S v_v Xscm 0 T v_s 0 v_e vtcsc bbox S K R fill R } if
       /v_v v_v VStp add D } B
 /vtb { S /VStp X /VWdw X GetVtVar
  colordict begin v_cmod cvx exec scmyk 0.125 slw
  v_ori 1 sub VWdw 2 div add Xscm 0 T
  /v_s VStp 2 div 1 add Xscm neg D /v_e VStp 2 add Xscm D
  /v_v 0 D /runVl { vb } B doVl R } B
  %# (Score-Vector Loop finished...BAR-PLOT) msg
 %
 %# The following 3 functions must be revised as the v and vc functions were modified 
 /GetVtvar { /v_cmod X /v_end X /v_ori X } B
 % position-score vector
 /vp { S GetVtvar v_ori 0 T { currentfile vst readline pop { { token
  { cvx exec /v_s exch D /v_e v_s D
  /vtcsc exch dup n ne { LY mul ScV 0 ne { 2 mul } if } if D
  v } { exit } ifelse } loop } stopped { exit } if } loop R } B
  %# (Position-Vector Loop finished...) msg
 % segment-score vector
 /vg { S GetVtvar v_ori 0 T { currentfile vst readline pop { { token
  { cvx exec /v_e exch D /v_s exch D
  /vtcsc exch dup n ne { LY mul ScV 0 ne { 2 mul } if } if D
  v } { exit } ifelse } loop } stopped { exit } if } loop R } B
  %# (Segment-Vector Loop finished...) msg
 /vtg { S GetVtvar v_ori 0 T { currentfile vst readline pop { { token
  { cvx exec /v_e exch D /v_s exch D
  /vtcsc exch dup n ne { LY mul ScV 0 ne { 2 mul } if } if D
  vc } { exit } ifelse } loop } stopped { exit } if } loop R } B
  %# (Segment-Vector Loop finished...LINE-PLOT) msg
 % string vector
 /vw { S (String-Vector Loop finished...) msg R } B
 % Functions for Shapes......
 /getfrcol { dup (.) eq { pop frmN } { dup 0 eq { pop frm0 } {
  dup 1 eq { pop frm1 } { 2 eq { frm2 } if } ifelse } ifelse } ifelse } B
 /cmdln { HLY m sqdif 2 div neg 0 rl scmyk K } B % S - R removed to allow frame-remainder fill mode to work.
 /lnfill { S Yscl slw sqdif cmdln sqdif 2 div cmdln R } B
 /frmfill { frm getfrcol rmd getfrcol lnfill } B
 /rnbfill { sc rainbow fill } B
 %# this rbnfill produces a full rainbow gradient to fill a shape
 %# /rnbfill { 1 dict begin S /incr sqdif 100 div D 0 incr sqdif { dup dup incr add 0 exch 0 m l
 %#  dup 0 gt { sqdif div } if rainbow Yscl slw K } for R end } B
 /setcolmod { cmod cvx exec dup 1 eq { pop scmyk fill } { dup 2 eq { pop lnfill }
  { dup 5 eq { 5 { pop } repeat frmfill } { dup 4 eq { 5 { pop } repeat rnbfill }
  { pop } ifelse } ifelse } ifelse } ifelse } B
 /ShFsz { GpFsz 2 div pslbSC mul } B
 /ShFont { ShFsz /Helvetica } B
 %# /postk { S 0 0 m 0 LY ScV 0 eq { Flgspos { 0.65 } { 1 } ifelse } { 1.15 } ifelse
 %#  mul rl longdotted fgcolor scmyk 0.125 slw K R } B
 /postk { S 0 0 m 0 LY ScV 0 eq { 0.65 } { 1.15 } ifelse
  mul rl longdotted fgcolor scmyk 0.125 slw K R } B
 /shwpos { S Flgspos { seqori LY neg ScV 0 eq { 0.65 mul T } { 1 -1 F 1.15 mul T } ifelse
  sqend sqdif sqori 0 2 { S 0 T postk 10 string cvs 0 0 S ScV 1 eq { 1 -1 F } if
  strnd (-) eq { 1 -1 F 45 } { -45 } ifelse ScV 1 eq { neg } if 4 -1 roll
  strnd (-) eq { ScV 1 ne { (bv) } { (tv) } ifelse } { ScV 1 ne { (tv) } { (bv) } ifelse } ifelse
  (lh) ShFont fgcolor ttxt R R } repeat } if R } B
 % *V align:  0 center : 1 baseline : -1 reverse
 /frs { S strnd (-) eq { -1 1 F } if FtV 0 eq { 0 HLY neg T } if
  colordict begin p_s cvx exec newpath end R } B
 /GetVar { /ftlbl X /flblfg X /Flgspos X /FtV exch dup 2 eq { pop 0 /mrr true D }
  { /mrr false D } ifelse D /p_s X /cmod X /sc X /rmd X /frm X /sqend X
  /seqend sqend Xscm D /sqori X /seqori sqori Xscm D /sqdif sqend sqori sub Xscm D
  sqdif 0.1 lt { /sqdif 0.1 D } if /fflbl ftlbl () eq { false } { flblfg } ifelse D /p_strk true D pop } B
 /p { S GetVar shwpos strnd (-) eq { seqend } { seqori } ifelse 0 T frs R } B
 %
 % new shape for expand
 /trchg 0.20 D
 %
 /resize_xp { S 5 dict begin /nd_xp sqend D /end_xp seqend D /or_xp sqori D
  /ori_xp seqori D /df_xp sqdif D MSLen 0 gt { sqdif MSLen Xscm lt {
  strnd (-) eq { /sqori sqend MSLen sub D /seqori sqori Xscm D } {
  /sqend sqori MSLen add D /seqend sqend Xscm D } ifelse /sqdif sqend sqori sub Xscm D
  } if } if S 0 LY trchg mul 2 div T 1 1.35 F bline R /sqend nd_xp D
  /seqend end_xp D /sqori or_xp D /seqori ori_xp D /sqdif df_xp D end R } B
 %
 /xpVL { GetVar strnd (-) eq { seqend } { seqori } ifelse 0 T strnd (-) eq { -1 1 F } if
  FtV 0 eq { 0 HLY neg T } if mrr { 0 LY sc mul T 1 -1 F } if } B
 %
 /nxpshp { S xpVL 4 dict begin /hdif sqdif 2 div D /xdif sqdif xpnd mul D
  /hxdif xdif 2 div hdif xpnd mul sub hdif add D
  /vrtfct LY 4 div neg D /hvrtfct vrtfct 3 div D
  /xpndmv xpndmv Xscm D colordict begin gcmod
  token { exch pop cvx exec } { pop pop black } ifelse
  resize_xp seqori neg trchg neg T /LY vrtfct D
  S { currentfile token pop exec } loop R
  /Xscm { Xscale mul } B end end R } B
 %
 /lxpshp { S xpVL 4 dict begin /hdif sqdif 2 div D /xdif sqdif xpnd mul D
  /hxdif xdif 2 div hdif xpnd mul sub hdif add D
  /vrtfct LY 4 div neg D /hvrtfct vrtfct 3 div D
  /xpndmv xpndmv Xscm D colordict begin gcmod
  token { exch pop cvx exec } { pop pop black } ifelse
  S 1 LY sc mul F hdif trchg m hdif trchg neg l 0.025 LY div slw fgcolor scmyk K newpath R
  resize_xp seqori neg trchg neg T /LY vrtfct D
  S 0 hvrtfct T { currentfile token pop exec } loop R
  /Xscm { Xscale mul } B end end R } B
 %
 /xpbbx { S 0.2 0 T 0 0 4 2 roll bbox fgcolor scmyk 0.25 slw K newpath R } B
 % fgcolor scmyk 0.125 slw K newpath R } B
 %
 /xpshp { S xpVL 5 dict begin /hdif sqdif 2 div D /xdif sqdif xpnd mul D
  /vrtfct LY 4 div D /hvrtfct vrtfct 2 div D /xpndmv xpndmv Xscm D colordict begin gcmod
  token { exch pop cvx exec } { pop pop black } ifelse %to make boxed base features% xdif vrtfct xpbbx
  S 1 LY sc mul F 0.025 LY div slw 0 trchg 1.2 mul m 0 trchg 1.3 mul l
  hdif xdif 2 div sub xpndmv strnd (-) eq { sub } { add } ifelse
  dup 0.73 l 0.74 l fgcolor scmyk K newpath R resize_xp 1 LY sc mul F hdif xdif 2 div sub
  xpndmv strnd (-) eq { sub } { add } ifelse 0.745 T
  S 1 1 LY div F xdif vrtfct xpbbx R seqori xpnd mul neg 0 T
  1 1 LY div F 0.225 0 T /LY vrtfct D /Xscm { Xscale xpnd mul mul } B
  S /cgfnt { LY gplbSC mul /Helvetica } D /cgflg xdif cgfnt sfont grlbl stringwidth pop lt CLPgplbl and not D
  grlbl () ne glblfg and cgflg and { gp_st gp_nd gp_st sub 2 div add Xscm LY 1.3 mul T
  % strnd (-) eq { 1.3 } { 1.35 } ifelse mul T
  strnd (-) eq { -1 -1 F } if ScV -1 eq { 1 -1 F } if gp_nd gp_st sub MINshwLBLlen gt { 0 0 0 grlbl
  strnd (-) eq ScV -1 eq or { (tv) } { (bv) } ifelse (ch) cgfnt fgcolor ttxt } if } if R
  % S 0 %hvrtfct->0% T { currentfile token pop exec } loop
  S { currentfile token pop exec } loop
  /Xscm { Xscale mul } B R end end R } B
  %# S 0 0 xdif vrtfct bbox fgcolor scmyk 0.5 slw K newpath R
  %# sqdif trchg 1.2 mul m sqdif trchg 1.3 mul l hdif neg xpndmv add
  %# strnd (-) eq { neg } if dup 0.73 l 0.74 l % right line
 %gplbSC
 /uxpshp { S xpVL 5 dict begin /hdif sqdif 2 div D /xdif sqdif xpnd mul D
  /vrtfct LY 4 div D /hvrtfct vrtfct 2 div D /xpndmv xpndmv Xscm D colordict begin gcmod
  token { exch pop cvx exec } { pop pop black } ifelse % xdif vrtfct xpbbx
  S 1 LY sc mul F 0.025 LY div slw 0 trchg 1.2 mul m 0 trchg 1.3 mul l
  hdif xpndmv strnd (-) eq { sub } { add } ifelse
  dup 0.73 l 1.35 l fgcolor scmyk K newpath R resize_xp 1 LY sc mul F hdif xpndmv
  strnd (-) eq { sub } { add } ifelse 1.355 T
  S 1 1 LY div F xdif vrtfct xpbbx R seqori xpnd mul neg 0 T
  1 1 LY div F 0.225 0 T /LY vrtfct D /Xscm { Xscale xpnd mul mul } B
  S /cgfnt { LY gplbSC mul /Helvetica } D /cgflg xdif cgfnt sfont grlbl stringwidth pop lt CLPgplbl and not D
  grlbl () ne glblfg and cgflg and { gp_st gp_nd gp_st sub 2 div add Xscm LY 1.3 mul T
  % strnd (-) eq { 1.3 } { 1.35 } ifelse mul T
  strnd (-) eq { -1 -1 F } if ScV -1 eq { 1 -1 F } if gp_nd gp_st sub MINshwLBLlen gt { 0 0 0 grlbl
  strnd (-) eq ScV -1 eq or { (tv) } { (bv) } ifelse (ch) cgfnt fgcolor ttxt } if } if R
  % S 0 %hvrtfct->0% T { currentfile token pop exec } loop
  S { currentfile token pop exec } loop
  /Xscm { Xscale mul } B R end end R } B
  %# S 0 0 xdif vrtfct bbox fgcolor scmyk 0.125 slw K newpath R
  %# sqdif trchg 1.2 mul m sqdif trchg 1.3 mul l hdif neg xpndmv add
  %# strnd (-) eq { neg } if dup 0.73 l 1.35 l % right line %# xdif 2 div sub 1.35 T
 %
 % Shapes......
 /HLFcrt { ScV 0 ne { 1 2 F } if } B
 /CkMR { mrr { 0 LY sc mul T 1 -1 F } if } B
 /PMX { 1 dict begin /svmtrix mtrx currentmatrix D CkMR } B
 /PMK { svmtrix setmatrix end } B
 /KCFmod { 0.25 slw scmyk S clip setcolmod R K } B  %##%ALSO MODIFIED
 /cpt { PMX sqdif LY sc mul F m { l } repeat closepath PMK KCFmod } B
 /cptc { sqdif LY sc mul F arc closepath PMK KCFmod } B
 /lft { sqdif 0 T -1 1 F } B
 /no_shp { 4 { pop } repeat } B
 /line   { PMX sqdif LY sc mul F 0 0.5 m 1 0.5 l PMK 2 slw scmyk K } B % 1 slw
 /tline  { PMX sqdif LY sc mul F 0 0.5 m 1 0.5 l PMK 1.6 slw scmyk K } B % 1 slw
 %# /bline  { LY trchg mul dup 0 exch 0.77 mul T PMX sqdif LY sc mul F 0 0 m 1 0 l PMK slw scmyk K } B % 1 slw
 %# /bline  { LY trchg mul dup 0 exch 0.77 mul T PMX sqdif exch sc mul F
 %#  1.0 -0.5 1.0 0.5 0.0 0.5 3 0.0 -0.5 m { l } repeat closepath PMK KCFmod } B % 1 slw
 /bline  { LY trchg mul PMX sqdif exch sc mul F 1.0 0.0 1.0 0.5 0.0 0.5 3 0.0 0.0
  m { l } repeat closepath PMK KCFmod } B % 1 slw
 /scline { PMX sqdif LY sc mul F 0 0.5 m 1 0.5 l PMK LY sc mul slw scmyk K } B
 /box    { 1.0 0.0 1.0 1.0 0.0 1.0 3 0.0 0.0 cpt } B
 /hbox   { ScV 0 ne { 1.0 0.0 1.0 0.5 0.0 0.5 3 0.0 0.0 }
  { 1.0 0.5 1.0 1.0 0.0 1.0 3 0.0 0.5 } ifelse cpt } B
 /gtgb   { PMX 1.0 0.0 1.0 1.0 0.0 1.0 3 0.0 0.0 sqdif LY sc mul F m { l } repeat closepath
  PMK 0.25 slw scmyk S BGcolor scmyk fill R K grlbl () ne { S sqdif 2 div LY 2 div dup sc mul
  0 grlbl (cv) (ch) 6 -1 roll /Helvetica FGcolor ttxt R } if } B %# S clip BGcolor scmyk fill R
 /fcir   { PMX 0.5 0.5 0.5 0 360 cptc } B
 /hcir   { PMX ScV 0 ne { 1 2 F 0.5 0.0 } { 0.5 0.5 } ifelse 0.5 0 180 cptc } B
 /frhead { 0.75 0.0 0.75 -0.1 0.755 -0.1 1.0 0.5 0.755 1.1 0.75 1.1 0.75 1.0 0.0 1.0 8 0.0 0.0 cpt } B
 /flhead { lft frhead } B
 /hrhead { ScV 0 ne { 1.0 0.0 0.755 1.1 0.75 1.1 0.75 1.0 0.0 1.0 5 0.0 0.0 }
  { 1.0 0.5 0.755 1.1 0.75 1.1 0.75 1.0 0.0 1.0 5 0.0 0.5 } ifelse cpt } B
 /hlhead { lft hrhead } B
 /frend  { 1.0 0.0 1.0 1.0 0.0 1.0 0.0 0.995 0.25 0.5 0.0 0.005 6 0.0 0.0 cpt } B
 /flend  { lft frend } B
 /hrend  { ScV 0 ne { 1.0 0.0 1.0 1.0 0.0 1.0 0.0 0.995 4 0.25 0.0 }
  { 1.0 0.5 1.0 1.0 0.0 1.0 0.0 0.995 4 0.25 0.5 } ifelse cpt } B
 /hlend  { lft hrend } B
 /frsgl  { 0.75 0.0 0.75 -0.1 0.755 -0.1 1.0 0.5 0.755 1.1 0.75 1.1 0.75
  1.0 0.0 1.0 0.0 0.995 0.25 0.5 0.0 0.005 11 0.0 0.0 cpt } B
 /flsgl  { lft frsgl } B
 /hrsgl  { ScV 0 ne { 1.0 0.0 0.755 1.1 0.75 1.1 0.75 1.0 0.0 1.0 0.0 0.995 6 0.25 0.0 }
  { 1.0 0.5 0.755 1.1 0.75 1.1 0.75 1.0 0.0 1.0 0.0 0.995 6 0.25 0.5 } ifelse cpt } B
 /hlsgl  { lft hrsgl } B
 /frtgl  { 0.0 0.0 0.0 1.0 1.0 0.505 3 1.0 0.495 cpt } B
 /fltgl  { lft frtgl } B
 /hrtgl  { ScV 0 ne { 0.0 0.0 0.0 1.0 2 1.0 0.0 }
  { 0.0 0.5 0.0 1.0 2 1.0 0.5 } ifelse cpt } B
 /hltgl  { lft hrtgl } B
 /fdmd   { 0.0 0.5 0.5 1.0 1.0 0.5 3 0.5 0.0 cpt } B
 /hdmd   { ScV 0 ne { ScV 1 eq { 1.0 0.0 0.5 1.0 2 0.0 0.0 } { 0.0 1.0 1.0 1.0 2 0.5 0.0 } ifelse }
  { mrr { 1.0 0.5 0.5 1.0 2 0.0 0.5 } { 1.0 0.5 0.5 1.0 2 0.0 0.5 } ifelse } ifelse cpt } B
 /fdtgl  { ScV 0 ne { ScV 1 eq { 0.0 1.0 1.0 1.0 2 0.5 0.0 } { 1.0 0.0 0.5 1.0 2 0.0 0.0 } ifelse }
  { mrr { 0.0 1.0 1.0 1.0 2 0.5 0.5 } { 0.0 1.0 1.0 1.0 2 0.5 0.5 } ifelse } ifelse cpt } B
 /f2tgl { 1.0 0.0 0.0 1.0 1.0 1.0 3 0.0 0.0 cpt } B
 /fast  { scmyk PMX sqdif LY sc mul F 0.5 0.5 T 0.025 slw
  10 { -0.5 0 m 0.5 0 l K 18 rotate } repeat PMK } B
 /fstar { PMX sqdif LY sc mul F 0 0.5 T 22.5 rotate 0 0 m 8 { 0.925 0 rlineto 225 rotate } repeat
  closepath PMK 0.75 slw scmyk S K R clip setcolmod } B
 % gap shape definition begin
 /gbbx { 1.1 -0.5 1.1 1.5 -0.1 1.5 3 -0.1 -0.5 m { l } repeat closepath } B
 /gfna { 0.60 1.50 0.0 0.5 0.50 0.5 -0.10 -0.50 m 3 { l } repeat } B
 /gfnb { 1 LY sc mul F gfna reversepath sqdif 0.50 sub 0 T gfna } B
 /gfnc { 0.0 0.0 0.0 1.0 1.0 1.0 3 1.0 0.0 m { l } repeat closepath } B
 /gap { PMX gfnb S 0.10 0 T sqdif 0.68 sub neg 1 F gbbx clippath newpath gfnc PMK
  0.1 slw 4 copy scmyk S dotted K R clip setcolmod R S scmyk 0.36 slw K R S BGcolor scmyk 0.12 slw K R } B
 % New shapes
 /loop { PMX sqdif LY sc mul F 0.5 0.5 T -0.05 0 m -0.05 0.4 l -0.6 0.4 -0.6 1.0 0 1.0 curveto
  0.6 1.0 0.6 0.4 0.05 0.4 curveto 0.05 0 l closepath PMK 0.75 slw scmyk S K R clip setcolmod } B
 % New CELERA Feature SHAPES X - Y
 /langl { PMX sqdif LY FlgScRM { 2.35 } { sc 1.10 mul } ifelse
  mul F 1.0 0.0 m 0.0 1.0 l PMK 0.175 slw scmyk K } B
 /rangl { PMX sqdif LY FlgScRM { 2.35 } { sc 1.10 mul }
  ifelse mul F 0.0 0.0 m 1.0 1.0 l PMK 0.175 slw scmyk K } B
 %# /hstar { PMX ScV 0 ne { 1 2 F 0.0 0.5 } { 0.0 -0.5 } ifelse T sqdif LY sc mul F newpath
 %#  -0.1 -0.1 1.1 0.5 bbox newpath 22.5 rotate 0 0 m 8 { 0.925 0 rlineto 225 rotate } repeat closepath PMK
 %#  0.75 slw scmyk S K R S eoclip setcolmod R newpath 0 0.5 m sqdif 0.5 l K } B
 % ......Shapes
 % Group functions...
 /g_score 1 D % /g_score 1.1 D % /g_score 0.5 D
 %# /GpFsz { Yscl 0.15 mul dup 8 gt { pop 8 } if gplbSC mul } D
 /GpFsz { Yscl 0.15 mul gplbSC mul } D
 /GpFont { GpFsz /Helvetica } B
 /gshp { S 0 gp_st gp_nd 0 0 g_score gcmod g_shape GpV Flgrpspos Flgglbl grlbl p R } B
 /gp_no { 4 { pop } repeat } B
 /gp_ln { scmyk 0.25 slw 0 0 m grdif 0 l K } B
 /gp_dt { dotted gp_ln } B
 /gp_lt { longdotted  gp_ln } B
 /gp_sh { shortdashed gp_ln } B
 /gp_lh { longdashed  gp_ln } B
 /gp_bk { scmyk 0.125 slw 2 dict begin /tl GpFsz 0.05 mul D /ol GpFsz 0.05 mul D
  0 0 m S 0 ol neg rl K R tl 0 rl S 0 ol rl K R tl 0 rl S 0 ol neg rl K R K end } B
 /gp_raw { scmyk 0.125 slw strnd (-) eq { grdif 0 T -1 1 F } if 2 dict begin /tl GpFsz 0.05 mul D
  /ol GpFsz 0.1 mul D tl 0 m tl neg dup S ol rl K R S ol neg rl K R
  grdif 0 l S tl neg ol rl 0 -2 ol mul rl tl ol rl S fill R K R K end } B
 /gp_law { grdif 0 T -1 1 F gp_raw } B
 /CkGPL { dup GpFsz 2 div lt { pop GpFsz 0.55 mul } if } B
 /gln { S colordict begin g_line cvx exec end R } B
 %# /shgl { S grori Yscl ScV 0 eq { 0.2875 mul } { 0.775 mul } ifelse T gln
 %#  S grdif 2 div Yscl 0.25 mul 2 div CkGPL 2 div T strnd (-) eq { 1 -1 F } if
 %#  ScV -1 eq { 1 -1 F } if Flgglbl { 0 0 0 grlbl strnd (-) eq { ScV -1 eq { (bv) } { (tv) } ifelse }
 %#  { ScV -1 eq { (tv) } { (bv) } ifelse } ifelse (ch) GpFont fgcolor ttxt } if R R } B
 %# /GetGVar { /gplbSC X /grlbl X /glblfg X /Flgrpspos X /g_line X /GpV X
 %#  /g_shape X /gcmod X /gp_nd X /grend gp_nd Xscm D /gp_st X /grori gp_st Xscm D
 %#  /grdif gp_nd gp_st sub Xscm D /Flgglbl grlbl () eq { false } { glblfg } ifelse D } B
 /shgl { /tScV ScV swplfg { neg } if D /tstrnd strnd swplfg { (-) ne { (-) } { (+) } ifelse } if D
  /.gswp swplfg D /.str tstrnd (-) eq D /.Szr tScV 0 eq D /.Sng tScV -1 eq D
  /glms S GpFont sfont grlbl stringwidth R pop D S grori Yscl .Szr { 0.2875 mul } { 0.775 mul } ifelse
  .gswp { neg } if T gln S gra 0 eq { grdif 2 div } { gra cos glms mul .str { neg } if } ifelse
  Yscl 0.25 mul 2 div CkGPL 2 div gra 0 ne { gra sin glms mul .str { neg } if add } if T
  .str { 1 -1 F } if .Sng { 1 -1 F } if .gswp { 1 -1 F } if Flgglbl { 0 0 gra grlbl
  .str { .Sng { (bv) } { (tv) } ifelse } { .Sng { (tv) } { (bv) } ifelse } ifelse
  gra 0 eq { (ch) } { .str not { (rh) } { (lh) } ifelse } ifelse GpFont fgcolor ttxt } if R R } B
 /GetGVar { /gplbSC X /grlbl X /gra X /swplfg X /glblfg X /Flgrpspos X /g_line X
  /GpV X /g_shape X /gcmod X /gp_nd X /grend gp_nd Xscm D /gp_st X /grori gp_st Xscm D
  /grdif gp_nd gp_st sub Xscm D % pending to add clipping by label length
  /Flgglbl grlbl () eq MINshwLBLlen gp_nd gp_st sub gt or { false } { glblfg } ifelse D } B
 /gx { exit } B
end % shpdct
%%EndProcSet: objects 1.2 0
%
%%BeginProcSet: blocks 1.1 0
/blckdct 80 dict D blckdct begin
 /Xscm { Xscale mul } B /Xscme { Xscm exch } B
 /gst 250 string D
 /XLL { blckori MaxTick sub } B
 /XLR { blckend MaxTick add } B
 /CKL { 2 { dup XLL lt { pop XLL } { dup XLR gt { pop XLR } if } ifelse exch } repeat } B
 % Group Functions
 /gp { S shpdct begin GetGVar shgl gshp { currentfile token pop exec } loop end R } B
 % EXPAND group function
 /xp { S shpdct begin /xpnlvl X /xpndmv X /xpnd X GetGVar /xpdsv save D
  /xpdmat matrix currentmatrix D XPDLvl 2 eq { 1 0.7 scale } if S 0 gp_st gp_nd 0 0 g_score gcmod g_shape GpV Flgrpspos Flgglbl grlbl
  xpnlvl 2 eq { uxpshp } { xpnlvl 1 eq { xpshp } { xpnlvl -1 eq { lxpshp } { nxpshp } ifelse } ifelse } ifelse R
  xpdmat setmatrix xpdsv restore end R } B
 % Source Functions.
 /ScFsz { Yscl 0.75 mul dup 10 gt { pop 10 } if sclbSC mul } D
 /ScFont { ScFsz /Courier } B
 /sc_no { 4 { pop } repeat } B
 /sc_ln { scmyk 0.25 slw 0 0 m XSPlot 0 l K } B
 /sc_dt { dotted      sc_ln } B
 /sc_lt { longdotted  sc_ln } B
 /sc_sh { shortdashed sc_ln } B
 /sc_lh { longdashed  sc_ln } B
 /sln { S colordict begin s_line cvx exec end R } B
 %
 /obmsflg true D
 /obms { /obmsflg false D /obmsYs exch tracksize mul D /obmsYo Y D } B %# /obmsYo Y obmsYs 0.25 mul add D
 /cbms { S /kk obmsYs 0.25 mul D /ku obmsYs 0.75 mul D /kd obmsYs 0.25 mul D
  /obmsYe Y obmsYs 0.25 mul sub D /obmsY obmsYe obmsYo sub 2 div obmsYo add D /sclbSC X
  /srcrgtlbl X /srclftlbl X /srgtlblfg X /slftlblfg X XOriPlot
  0 T bshsrl bshsll R /obmsflg true D } B
 /bshsll { S FLftLbl Flgslftlbl and { S -25 obmsY T strnd (-) ne { 1 -1 F } if
  0 0 0 srclftlbl sclbva (rh) ScFont fgcolor ttxt R S -5 obmsYo m -15 obmsYo 10 add l
  -15 obmsYe 10 sub l -5 obmsYe l 2 slw -15 obmsY m -22 obmsY l K R } if R } B
 /bshsrl { S FRgtLbl Flgsrgtlbl and { XSPlot 0 T S 25 obmsY T strnd (-) ne { 1 -1 F } if
  0 0 0 srcrgtlbl sclbva (lh) ScFont fgcolor ttxt R S 5 obmsYo m 15 obmsYo 10 add l
  15 obmsYe 10 sub l 5 obmsYe l 2 slw 15 obmsY m 22 obmsY l K R } if R } B
 %
 %# /sbc { -10 Yscl 2 mul neg XSPlot 10 add Yscl 1.5 mul bbox clip newpath } B
 /sbb { -4 Yscl neg XSPlot 4 add Yscl 3 mul bbox clip newpath FlgScBx {
  0 0 XSPlot Yscl bbox 0.25 slw fgcolor scmyk K newpath 0.125 0.125
  XSPlot 0.125 sub Yscl 0.125 sub bbox clip newpath } if } B
 /shsll { S FLftLbl Flgslftlbl and { SLA { -25 } { XLftLbl 2 div neg } ifelse
  Yscl 2 div T strnd (-) ne { 1 -1 F } if 0 0 0 srclftlbl sclbva
  SLA { (rh) } { (ch) } ifelse ScFont fgcolor ttxt } if R } B
 /shsrl { S FRgtLbl Flgsrgtlbl and { XSPlot SLA { 25 } { XRgtLbl 2 div } ifelse add
  Yscl 2 div T strnd (-) ne { 1 -1 F } if 0 0 0 srcrgtlbl sclbva
  SLA { (lh) } { (ch) } ifelse ScFont fgcolor ttxt } if R } B
 /GetSVar { /XPDLvl X /sclbva X /sclbSC X /srcrgtlbl X /srclftlbl X /srgtlblfg X /slftlblfg X
  /s_line X /strnd X /FlgScRM X /FlgScBx X /spacer exch spcrsize mul D /Yscl exch tracksize mul D
  /ScV exch dup 2 eq { pop 0 } if D /Flgsrgtlbl srcrgtlbl () eq { false } { srgtlblfg } ifelse D
  /Flgslftlbl srclftlbl () eq { false } { slftlblfg } ifelse D
  strnd (.) eq { /Y Y spacer 2 div add D } { strnd (-) eq { /Y Y Yscl spacer add add D } if } ifelse } B
 /source { S GetSVar XOriPlot Y T strnd (-) eq { 1 -1 F } if obmsflg { shsrl shsll } if
  sbb S ScV 0 eq { 0 Yscl 2 div T 1 -1 F } { ScV 1 eq { 0 Yscl T 1 -1 F } if } ifelse
  sln S blckori Xscm neg 0 T } B
 /s_end { R R R strnd (.) eq { /Y Y Yscl add spacer 2 div add D }
  { strnd (+) eq { /Y Y Yscl spacer add add D } if } ifelse } B
 % Block Functions.
 /GetBVar { /blcknum exch 1 sub D /blckend X /blckori X
  /Y FlgOSU { TkMrkW 1 TkMspc add mul } { 0 } ifelse D
  /YB YOriBlck YSBlck blcknum mul add BlckSp blcknum mul add D } B
 /kbb { XOriBlck 5 sub -2 XSBlck 10 add YSBlck 2 add bbox
  FlgBkBx { S 1 slw fgcolor scmyk K R } { newpath } ifelse } B
 % tickmark calls
 /tm { S tmdct begin /ShowGrid X exec end R } B
 /shwgrd { FlgGrd { blckori blckend XOriPlot FlgOSU { TkMrkW } { 0 } ifelse
  0 YSBlck FlgOSU { TkMrkW sub } if FlgOSD { TkMrkW sub } if {g} 0 tm } if } B
 /shwtck { shwgrd FlgOSU { blckori blckend XOriPlot 0 {s} 0 tm } if
  FlgOSD { blckori blckend XOriPlot YSBlck {z} 0 tm } if } B
 /chgtst { FlgISU FlgISD or is2tck not is1tck and and FlgISU is2tck and or is2tck FlgISD and or } B
 /uptck { shwgrd FlgOSU { blckori blckend XOriPlot 0 {s} 0 tm } if } B
 /dntck { FlgOSD { blckori blckend XOriPlot Y TkMrkW 1 TkMspc add mul add {z} 0 tm } if } B
 /nxtblck { dup dup (.) eq { pop YSFwd 0 gt { YSBth } { 0 } ifelse } {
  (-) eq { YSFwd 0 gt YSBth 0 gt or { YSRvs } { 0 } ifelse } { 0 } ifelse } ifelse } B
 /Strand { nxtblck 0 gt { /Y Y chgtst { TkMrkW 1 TkMspc add mul 2 div add } if D
  dup (-) eq { pop is1tck FlgISU FlgISD or is2tck not and FlgISU is2tck and or and {
  blckori blckend XOriPlot TkMrkW FlgOSU { 2 TkMspc 1.5 mul add mul } { 1 TkMspc 0.5 mul add mul } ifelse
  YSFwd 0 gt { YSFwd add } { YSBth add } ifelse {r} 0 tm } if } { (.) eq { is2tck FlgISD and {
  blckori blckend XOriPlot TkMrkW FlgOSU { 3 TkMspc 2.5 mul add mul } { 2 TkMspc 1.5 mul add mul } ifelse
  YSFwd add YSBth add {r} 0 tm } if } if } ifelse
  /Y Y chgtst { TkMrkW 1 TkMspc add mul 2 div add } if D } { pop } ifelse } B
 /b_end { R end } B
 /vb_end { dntck R end } B
 % BG block fill functs
 %# /bgtsz { TkMrkHW 1.25 mul /Helvetica-bold } D
 /bgtsp 5 D % /bgtsp { BlckSp 0.25 mul } D
 /bgtsz { bgtsp mul /Helvetica } B
 %
 /bgb { S /blbx X /blbl X /cmod X /gp_nd exch dup blckend gt { pop blckend } if D
  /grend gp_nd Xscm D /gp_st exch dup blckori lt { pop blckori } if D /grori gp_st Xscm D
  /sqdif gp_nd gp_st sub Xscm D grori 0 T colordict begin S PMX sqdif YY F
  0 0 1 1 bbox PMK setcolmod fill end R blbx bgtsz sfont /ttt blbl stringwidth pop D sqdif
  ttt gt { /hpos sqdif 2 div D /haln (ch) D } { /hpos gp_st blckori ge { 0 } { sqdif } ifelse D
  /haln gp_nd blckori ge { (lh) } { (rh) } ifelse D } ifelse sqdif 10 mul
  ttt gt { hpos YY 1.025 mul T 1 -1 F 0 0 0 blbl (tv) haln blbx bgtsz fgcolor ttxt } if R } B
 %
 /bgw { S /blbx X /blbl X /cmod X /gp_nd exch dup blckend gt { pop blckend } if D
  /grend gp_nd Xscm D /gp_st exch dup blckori lt { pop blckori } if D /grori gp_st Xscm D
  /sqdif gp_nd gp_st sub Xscm D grori 0 T colordict begin S PMX sqdif YY F 0 0 1 1 bbox PMK 0.5 slw
  S dotted K R setcolmod fill end R blbx bgtsz sfont /ttt blbl stringwidth pop D sqdif ttt gt {
  /hpos sqdif 2 div D /haln (ch) D } { /hpos gp_st blckori ge { 0 } { sqdif } ifelse D
  /haln gp_nd blckori ge { (lh) } { (rh) } ifelse D } ifelse sqdif 10 mul
  ttt gt { hpos YY 1.025 mul T 1 -1 F 0 0 0 blbl (tv) haln blbx bgtsz fgcolor ttxt } if R } B
 %
 /oim { S /blbx X /blbl X /cmod X /gp_nd exch dup blckend gt { pop blckend } if D
  /grend gp_nd Xscm D /gp_st exch dup blckori lt { pop blckori } if D /grori gp_st Xscm D
  /sqdif gp_nd gp_st sub Xscm D /sqh sqdif 2 div D /ttt blbx bgtsz sfont blbl stringwidth pop D
  grori sqh add YY dup 3 1 roll T 1 -1 F colordict begin S -1 2 1 4 -1 roll bbox 0 -2 T
  S ttt neg 0 m ttt ttt 0.8 mul 2 copy rl neg rl closepath bgcolor scmyk fill R % 0.0125 slw K R
  ttt 0.9 mul dup neg 0.4 sub 0 m 2.5 1.75 rl 0 -3.5 rl closepath 0.5 add 0 m -2.5 1.75 rl 0 -3.5 rl closepath
  S fgcolor scmyk 0.0125 slw K R clip setcolmod R end 0 -2 0 blbl (cv) (ch) blbx bgtsz fgcolor ttxt R } B
 % BG block features
 /orm { S /blbx X /blbl X /cmod X /gp_nd exch dup blckend gt { pop blckend } if D /grend gp_nd Xscm D
  /gp_st exch dup blckori lt { pop blckori } if D /grori gp_st Xscm D /sqdif gp_nd gp_st sub Xscm D
  /sqdH sqdif 2 div D grori sqdH add 0 T /dwcdcol { colordict begin cmod cvx exec pop end } D
  /dwcdln 0.25 D colordict begin S PMX sqdif TkMrkW neg F -0.5 0.15 m 0.5 0.15 l 0 1.25 l closepath PMK
  0.125 slw fgcolor scmyk S K R clip setcolmod end R blbl () ne { 90 rotate TkMrkW 1.85 mul neg 0 T 1 -1 F
  bgtsp blbx bgtsz sfont blbl stringwidth pop 0.85 mul blbl 1.4 drawcard } if R } B
  %# TkMrkW 1.60 mul neg %# bgtsp 1.20 mul %# 0.95 mul blbl
 %
 /backft { S 2 dict begin /xtrhg TkMrkW TkMspc mul D
  /YY YSBlck FlgOSU { TkMrkW sub xtrhg add } if FlgOSD { TkMrkW sub xtrhg add } if D
  XOriPlot blckori Xscm sub FlgOSU { TkMrkW } { 0 } ifelse T /FlgScRM false D
  shpdct begin { currentfile token pop exec } loop end end R } B % exit the loop with "gx" function from shpdct
 % Block Vertical LABELS
 /drawcard { S 5 dict begin /dclblsc X /dclbl X /height X /width X /Hwidth width 2 div D
  newpath 0 height 2 div neg T Hwidth 0 m width 0 width height Hwidth arcto width height 0 height Hwidth arcto
  0 height 0 0 Hwidth arcto 0 0 width 0 Hwidth arcto closepath 16 { pop } repeat S dwcdcol scmyk fill R
  fgcolor scmyk dwcdln slw K  Hwidth height 2 div 90 dclbl (cv) (ch) Hwidth dclblsc mul
  /Helvetica-Bold fgcolor ttxt end R } B
 %
 /TMadd { TkMrkW TkMspc mul add } B
 /split_ruler { S XOriPlot blckori MinTick 2 div sub Xscm sub TkMrkW 1.35 div neg T
  /YY YSBlck FlgOSU { TMadd } if FlgOSD { TMadd } if D
  /FlgScRM false D shpdct begin /cmod (bgcolor 1) D /srlbl X /gp_nd X /grend gp_nd Xscm D
  /gp_st X /grori gp_st Xscm D /sqdif gp_nd gp_st sub Xscm D grori % 2500 Xscm add
  YSBlck FlgOSU { TkMrkW TMadd add } if T 1 -1 F /dwcdcol { colordict begin Blblcol end } D
  /dwcdln 1 D colordict begin FlgOSU { 0 TkMrkW 3 div neg T } if 1.0 0.0 1.0 1.0 0.0 1.0 3 0.0 0.0 PMX
  sqdif MinTick Xscm sub YY F m { l } repeat closepath PMK setcolmod
  srlbl () ne { sqdif YY 2 div T sqdif 4 div blklblsc mul dup -1.5 mul 0 T YY srlbl 1 drawcard } if end end R } B
 %
end % blockdict
%%EndProcSet: blocks 1.0 0
%
%%BeginProcSet: main_function_calls 1.0 0
/block { blckdct begin GetBVar S 0 YB T kbb shwtck } B
/vblock { blckdct begin GetBVar S 0 YB T kbb uptck } B
%%EndProcSet: main_function_calls 1.0 0
%
%%EndProlog
%
%%BeginSetup
% initgraphics
% true setpacking
true setstrokeadjust
0.125 slw
0 setlinejoin
0 setlinecap
% mark % Only for error-tracking purposes
%%EndSetup
%
@@@MAINProcs@@@
#
#### End of MAINPSPROCS function

##############################################################
##################### SHELL FUNCTIONS ########################
#
# Testing parameters passed by User: Colors.
CheckColor () {
  $GAWK 'BEGIN{
    color=ARGV[1];
    if (tolower(color)!~/^((b|f)g(color)?|black|white|(very)?(light|dark)?(grey[abcd]?|(sea|lime)?green|(sky)?blue|cyan|violet|magenta|red|orange|yellow|brown))$/) {
      if (ARGV[4]) {
        printf "\n<<<<ERROR>>>> \"%s\" is not a defined color.\n", color | "cat 1>&2";
        printf "              Default \"" ARGV[2] "\" is asigned to this option.\n" | "cat 1>&2";
        printf "              You can choose one of this colors:\n" | "cat 1>&2";
        print ARGV[3] | "cat 1>&2";
        print "" | "cat 1>&2";
      }
      color=ARGV[2];
    } # if color
    print color;
    ARGV[1]=ARGV[2]=ARGV[3]=ARGV[4]="";
  }' $1 $2 "$COLORS" $v34;
  return 0;
} # End of CheckColor

#
# Testing parameters passed by User: Integer Numbers.
CheckInt () {
  if [ `expr $1 : '[-]?[0-9]*'` -eq `expr $1 : '[-]?.*'` ];
    then
      echo "1"; return 0;
    elif [ $v34 -eq 1 ];
      then
        { echo "<<<<ERROR>>>> \" $1 \" is not an integer value.";
          echo "              You must especify an integer value to -$W_OPTION";
          echo "              Program will take value from defaults..."; echo "";
        } 1>&2 ;
        echo "0"; return 1;
    else
      return 1;
    fi
} # End of CheckInt

#
# Testing if files exist.
ExistFile () {
  if [ ! -f "$1" ];
    then
      echo "0";
      if [ $v34 -eq 1 ];
        then
          echo "INPUT FILE: File \"$1\" is empty or does not exist... Not Loaded!" 1>&2;
        fi;
      return 1;
    else
      echo "1"; # exist_file
      if [ $v34 -eq 1 ];
        then
          echo "INPUT FILE: File \"$1\" exist, included as GFF-file." 1>&2;
        fi;
      return 0;
    fi;
} # End of ExistFile

ExistCustomfile () {
  if [ ! -f "$1" ];
    then
      echo "0";
      if [ $v34 -eq 1 ];
        then
          printf "CUSTOM FILE: Default Custom File does not exist... Not Loaded!\n\n" 1>&2;
        fi;
      return 0;
    else
      echo "1"; # exist_default_customfile
      if [ $v34 -eq 1 ];
        then
          { printf "CUSTOM FILE: Default Custom File exist.\n\n";
            printf "             Filename: \"$1\"\n\n"; } 1>&2;
        fi;
      return 1;
    fi;
} # End of ExistCustomfile

XtrCustomExist () {
  if [ ! -f "$1" -a ! -f "$CFDIR/$1"  -a ! -f "./$1" ];    # load_customfile customfile_name
    then
      v01=0;
      if [ $v34 -eq 1 ];
        then
          printf "CUSTOM FILE: Custom File \"$1\" does not exist... Not Loaded!\n\n" 1>&2;
        fi;
      return 1;
    else
      v01=1;
      if [ -f "$1" ];
        then
          v02="$1";
        else
          if [ -f "$CFDIR/$1" ];
            then
              v02="$CFDIR/$1";
            else
              if [ -f "./$1" ];
                then
                  v02="./$1";
                fi;
            fi;
        fi;
      if [ $v34 -eq 1 ];
        then
          { printf "CUSTOM FILE: Adding User-Defined Custom File to defaults:\n\n";
            printf "             Filename: \"$v02\"\n\n"; } 1>&2;
        fi;
      return 0;
    fi;
} # XtrCustomExist

###################################################################
################## MAIN GFF2PS SHELL SCRIPT #######################
###################################################################
############### CONVERTING GFF TO POSTSCRIPT ######################
###################################################################

Defaults

#
# When no options, no parameters and
#  no inputstream are given, print USAGE.
npar=$#;
if [ $npar -eq 0 ];
  then
    printf "\n$USAGE\n"; exit 1;
  fi;

#
# Asking for Help, output it to screen.
case $1 in
  -h) (Help | more); exit 2;;
  -H) printf "\n$PROGRAM : Option Definition Help.\n\n";
      if [ $npar -gt 1 ];
        then shift; fi;
      for temp in $@;
        do ShowHelpLine $temp; done;
      exit 2;;
  esac;

#
# Processing all options and parameters passed to program.
while getopts :HhVvdD:C:z:Z:s:pG:g:P:S:E:B:N:bLT:t:lOoM:K:m:k:wfcri0:1:2:3:na W_OPTION;
  do {
    case $W_OPTION in
      H|h) (Help | more); exit 2;;
      V) v05=1;v34=1;;                # print_report
      v) v34=0;;                      # quiet_mode
      d) v04_1=1;;                    # create_default_customfile (.gff2psrc) or rewrite
      D) v04_1=1;                     # create_default_customfile or rename_it if exist
         v03="$CFDIR/$OPTARG";;
      C) cftmp=$OPTARG;;
      s) v07=$OPTARG;;                # page_bbox
         # v12=`chkpagesize $v07`;;
      p) v06="Portrait";;             # page_orientation
      G) v19=`CheckColor $OPTARG $v19`;;  # foreground_color
      g) v20=`CheckColor $OPTARG $v20`;;  # background_color
      P) if [ `CheckInt $OPTARG` ];
           then
             v08=$OPTARG;
           fi;;               # page_number
      S) if [ `CheckInt $OPTARG` ];
           then
             v18_s=$OPTARG;
           fi;;               # zoom_begin
      E) if [ `CheckInt $OPTARG` ];
           then
             v18_e=$OPTARG;
           fi;;               # zoom_end
      B) if [ `CheckInt $OPTARG` ];
           then
             v09=$OPTARG;
           fi;;               # blocks_x_page
      N) if [ `CheckInt $OPTARG` ];
           then
             v10=$OPTARG;
           fi;;               # nucleotides_x_line
      b) v11=0;;              # show_blocks_top-bottom
      L) v21="none";;         # header_style
      T) v25=$OPTARG;;        # title
      t) v26=$OPTARG;;        # subtitle
      l) v22="off";;          # show_page_numbers
      O) v23="off";;          # show_date
      o) v24="off";;          # show_time
      M) if [ `CheckInt $OPTARG` ];
           then
             v13=$OPTARG;
           fi;;               # major_tickmarks_num
      K) if [ `CheckInt $OPTARG` ];
           then
             v14=$OPTARG;
           fi;;               # major_tickmarks_nucleotides
      m) if [ `CheckInt $OPTARG` ];
           then
             v15=$OPTARG;
           fi;;               # minor_tickmarks_num
      k) if [ `CheckInt $OPTARG` ];
           then
             v16=$OPTARG;
           fi;;               # minor_tickmarks_nucleotides
      w|f) v27="off";;        # strand_show_forward
      c|r) v28="off";;        # strand_show_reverse
      i) v29="off";;          # strand_show_independent
      0) v30=`CheckColor $OPTARG $fgcolor`;;  # frame0_color
      1) v31=`CheckColor $OPTARG $fgcolor`;;  # frame1_color
      2) v32=`CheckColor $OPTARG $fgcolor`;;  # frame2_color
      3) v33=`CheckColor $OPTARG $fgcolor`;;  # frame_unknown_color
      n) v17="true";;         # show_positions
      a) v35=0;;              # Show_Credits
      Z) v36=$OPTARG;;        # page_bbox
      z) CHOSFLG=1; CHOSFILE=$OPTARG;; # offsets file
       :) ShowHelpLine $1; exit 2;;
      \?) ShowHelpLine $1; exit 2;;
    esac;  # case $W_OPTION
  }; done; # while getopts
# Done GetOpts
v18="$v18_s..$v18_e";

#
# Shifting all options tested before,
# without removing files passed to shell...
incr=1;
while [ $OPTIND -gt $incr ]; do shift; incr=`expr $incr + 1`; done;

#
# Report Command Line
if [ $v34 -eq 1 ];
  then
   { printf "************** Begin Report ****************\n\n";
       echo "********************************************";
       echo "*  Running $PROGRAM $VERSION [$DATERELEASE] ";
     printf "********************************************\n\n";
     printf "Report: You have typed the following command line:\n\n$CMDLine\n\n";
     if [ -n "$GFF2PS_CFDIR" -o -n "$GFF2PS_CUSTOMFILE" -o -n "$GFF2PS_TMP" -o -n "$GAWK_DIR" ];
       then
         printf "Report: You have defined the following $PROGRAM Shell-Vars:\n\n";
         if [ $GFF2PS_CFDIR ];
           then echo "        \$GFF2PS_CFDIR      = \"$GFF2PS_CFDIR\""; fi;
         if [ $GFF2PS_CUSTOMFILE ];
           then echo "        \$GFF2PS_CUSTOMFILE = \"$GFF2PS_CUSTOMFILE\""; fi;
         if [ $GFF2PS_TMP ];
           then echo "        \$GFF2PS_TMP        = \"$GFF2PS_TMP\""; fi;
         if [ $GAWK_DIR ];
           then echo "        \$GAWK_DIR          = \"$GAWK_DIR\""; fi;
         echo "";
       fi; } 1>&2;
  fi;

#
# Checking files
if [ $v34 -eq 1 ];
  then
   { echo "********************************************";
     echo "*  Checking input filenames given by user";
     echo "********************************************";
     echo ""; } 1>&2;
  fi;

GFF_INPUT_FILES=""; ck=0; hmf=0; rd_std=1;
if [ $npar -ge $OPTIND ];
   then
     for files in $@;
       do {
         if [ $files = "-" ];
           then
             if [ $ck -eq 1 ];
               then
                 GFF_INPUT_FILES=$GFF_INPUT_FILES" ";
               fi		
             GFF_INPUT_FILES=$GFF_INPUT_FILES$files;
             shift; ck=1;
             hmf=`expr $hmf + 1`;
             rd_std=1;
             if [ $v34 -eq 1 ];
               then
                 printf "\nINPUT DATA: Standard-input is going to be included with input files...\n\n" 1>&2;
               fi;
           else
             if [ `ExistFile $files` -eq 1 ];  # Checks any kind of input files (*, ./*, path/*).
               then
                 if [ $ck -eq 1 ];
                   then
                     GFF_INPUT_FILES=$GFF_INPUT_FILES" ";
                   fi
                 GFF_INPUT_FILES=$GFF_INPUT_FILES$files;
                 shift; ck=1;
                 hmf=`expr $hmf + 1`;
               fi;
           fi;
       }; done;
     if [ $v34 -eq 1 ];
       then
         printf "\nINPUT DATA: $GFF_INPUT_FILES\n\n" 1>&2;
       fi;
   fi;
if [ $hmf -eq 0 ];
   then
     GFF_INPUT_FILES="-";
     if [ $v34 -eq 1 ];
       then
         printf "INPUT DATA: Redirecting from standard-input...\n\n" 1>&2;
       fi;
   fi;

#
# Checking for custom files...

v04=`ExistCustomfile "$v03"`;

XtrCustomExist $cftmp;

#
# Printing GAWK OPTIONS.
cat <<@@@EndOfOptions@@@ > $GWKOPT
BG_COLOR:=$bgcolor::FG_COLOR:=$fgcolor::$n04_1:=$v04_1
$n01:=$v01::$n02:=$v02::$n03:=$v03::$n04:=$v04::$n05:=$v05
$n06:=$v06::$n07:=$v07::$n08:=$v08::$n09:=$v09::$n10:=$v10
$n11:=$v11::$n12:=$v12::$n13:=$v13::$n14:=$v14::$n15:=$v15
$n16:=$v16::$n17:=$v17::$n18:=$v18::$n19:=$v19::$n20:=$v20
$n21:=$v21::$n22:=$v22::$n23:=$v23::$n24:=$v24::$n25:=$v25
$n26:=$v26::$n27:=$v27::$n28:=$v28::$n29:=$v29::$n30:=$v30
$n31:=$v31::$n32:=$v32::$n33:=$v33::$n34:=$v34::$n35:=$v35::$n36:=$v36
PID:=$PID::InputFNs:=$GFF_INPUT_FILES::PS_Header_FN:=$PSHEAD::PS_Main_FN:=$PSMAIN
PROGRAM:=$PROGRAM::VERSION:=$VERSION::AUTHOR:=$AUTHOR::EMAIL:=$EMAIL::PSPROGRAM:=$PSPROGRAM
CHOSFLAG:=$CHOSFLG::CHOSFILE:=$CHOSFILE::POSIX_SORT:=$POSIX_SORT
@@@EndOfOptions@@@

#
# Main GFF2APLOT GNU AWK PROGRAM
#
cat << '@@@EndPROGRAM@@@' >> $GWKPRG # Shell file
BEGIN{ ######### INITIALITATION ###############
  OFS="\t";
  #
  # Loading Default Variables...
  GFF_FORMAT_DEFS();
  ARY_VARIABLES();
  PageSizesDEF();
  #
  # Find actual date...
  "date +%Y/%m/%d" | getline date; close("date +%Y/%m/%d");
  "date +%T" | getline time; close("date +%T");
  #
  # Finding logged user...
  "whoami" | getline usr; close("whoami");
  #
  # Defining pre-variables by CommandLine
  READ_CL();
  #
  # Initialization for some vars.
  BigLINE="********************************************";
  MINSCORE=0.10; MAXSCORE=1.00;
  MINV_SCO=0.00; MAXV_SCO=1.00;
  FIRST_POS=0;
  LAST_POS=0;
  nordcnt=ordcnt=0;
  src_nordcnt=src_ordcnt=0;
  seq_nordcnt=seq_ordcnt=0;
  grouped_=1;ungrouped_=0;
  gff_NR=0;
  TITLE_FN="";
  CHOffSet[0]=0; CHOSblnk=0;
  #
  # Color REGEXP
  V_COLORS="((fg|foreground)(color)?|black|white|(very)?(light|dark)?(grey[abcd]?|(sea|lime)?green|(sky)?blue|cyan|violet|magenta|red|orange|yellow|brown)|v?(d|l)?u(brown|(d|l)olive|brick|red|pink|salmon|(d|l)orange|(d)?yellow|(d|m|l)?green|(d|m|l)blue|(d|l)cyan|(d|m|l)purple|(d|m|l)grey))";
  Valid_Colors="^("V_COLORS"(\\.\\."V_COLORS"(\\.\\."V_COLORS")?)?)$";
  #
  PrintWRN(sprintf("%s\n*  GFF2PS Inizialization DONE !!!\n%s\n\n",BigLINE,BigLINE));
  PrintWRN(sprintf("%s\n*  Processing GFF Records...\n*\n",BigLINE));
}
########## INITIALITATION Finished ##########
#
############ READING .GFF FILES  ############
{ is_EOF=0;
  #
  # skips those comment lines (starting with "#") or empty lines
  # also checking if input line is gff_formated.
  while (!ChkInput()) {
    PrintWRN(sprintf(">>> %10s :: Not Read :: <%s>\n", NR, ChkCharIF($0)));
    if (getline<=0) { is_EOF=1; break };
  } # while
  if (!is_EOF) {
    #
    # Printing Input Lines
    if (NF>10) PrintRPT(sprintf("OK: %10s :: GFF v.%s  :: <%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s (...)>\n", NR, GFF_V, $1,$2,$3,$4,$5,$6,$7,$8,$9,$10));
    else PrintRPT(sprintf("OK: %10s :: GFF v.%s  :: <%s>\n", NR, GFF_V, $0));
    #
    # Reading gff-line elements.
    ReadElements();
  } # if (!is_EOF)
}
########### .GFF FILES WERE READ ############
#
########### MAIN PROGRAM PROCESSES ##########
END{
  PrintWRN(sprintf("*\n*  ...GFF Records READ\n%s\n\n",BigLINE));
  #
  OFS=" ";
  #
  # Defining Object Properties.
  SET_VARS();
  #
  # Defining New Order array combining src and seq oredrings
  # (allows multiple seqs by src or srcs by seq).
  SET_ORDER();
  #
  # Sorting groups
  SortGroups();
  #
  # Making Lines...
  MakeGroupLines();
  #
  # # Printing groups and elements sorted
  # PrtSorted();
  #
  # Defining Page variables.
  SET_PAGE_VARS();
  #
  # Writing PS Header...
  PSheader();
  #
  # PostScript Variables Setup.
  defPSvars();
  #
  # Pages MAIN LOOP.
  MAIN_PAGE_LOOP();
  #
  # Closing PostScript document.
  PSTrailer();
  #
  # If not exist, create custom file (.gff2psrc)
  CREATECUSTOM();
}
############ MAIN PROCESSES DONE ############
#
#################### MAIN ###################
############ FUNCTIONS DEFINITION ###########
#
function GFF_FORMAT_DEFS() {
  #
  PrintRPT("*  GFF Format Definitions...\n");
  #
  # gff BASIC data-structure
  seqname = 1 ; REseqname = "[^\\# ]+" ;
  source  = 2 ; REsource  = "[^\\# ]+"  ;
  feature = 3 ; REfeature = "[^\\# ]+"  ;
  # now allowing any kind of numbers, not just integers
  start   = 4 ; REstart   = "([+-]?[0-9]*[.]?[0-9]*([Ee][+-]?[0-9]+)?)" ;
  end     = 5 ; REend     = "([+-]?[0-9]*[.]?[0-9]*([Ee][+-]?[0-9]+)?)" ;
  score   = 6 ; REscore   = "([+-]?[0-9]*[.]?[0-9]*([Ee][+-]?[0-9]+)?)" ;
  strand  = 7 ; REstrand  = "[+.-]"  ; # to ensure that works on all systems
  frame   = 8 ; REframe   = "[.012]" ;
  group   = 9 ;
  #
  # gff2ps extra data-structure
  gpname=1; gpstart=2; gpend=3; is_grouped=4; gplabel=5;
  vector=10; v_window=11; v_step=12; v_scmin=13; v_scmax=14; v_DATA=15; v_NUM=16; v_CLASS=0;
  VctSPLIT="[\\t ]+[Vv][Ee][Cc][Tt][Oo][Rr][\\t ]+";
  expand="::x"; xpnd_zoom="::z"; xpnd_delta="::d"; xpnd_level="::l"; xpnd_frame="::f";
  XpndSPLIT="[\\t ]+[Ee][Xx][Pp][Aa][Nn][Dd][\\t ]+";
  #
  ### GFF FORMAT - Tag-Value definition ###
  REST="^";
  REND="$";
  REtag= "[A-Za-z][A-Za-z0-9_]*" ;
  REval= "\\\"[^\\\"\\#]+\\\"(;)?" ;
  #
  ### GFF FORMAT - Version 1 - Record Definition ###
  REfs1     = "[\\t ]+" ;
  REtagval  = REtag REfs1 REval ; # "([\\t ]*;)?"
  PlainGP   = "[^\\\"\\# ]+" ;
  REtail1   = ".*" ;     # ".*" ;
  REgroupV1 = "(" PlainGP "|" REval "|" REtagval REtail1 ")" ;
  CKgroupV1 = "(" PlainGP "|" REval ")" ;
  REGV1     = "(" REfs1 "(" REgroupV1 REtail1 ")?)?" ;
  #    Version1 : ..$1.......FS.....$2......FS.....$3.......FS.....$4.....FS.....$5...FS.....$6.....FS.....$7......FS.....$8.....FS.....$9.....
  gff_format_V1 = REST REseqname REfs1 REsource REfs1 REfeature REfs1 REstart REfs1 REend REfs1 REscore REfs1 REstrand REfs1 REframe REGV1 REND ;
  #
  ### GFF FORMAT - Version 2 - Record Definition ###
  # In version 2 gff-format field separator is \t.
  REfs2     = "[\\t]+" ;
  REgroupV2 = REtagval ; # REtag REfs1 REval ;
  REtail2   = ".*" ;
  REGV2     = "(" REfs2 "(" REgroupV2 REtail2 ")?)?" ; # "([^\\#]+)*";
  #    Version2 : ..$1.......FS.....$2......FS.....$3.......FS.....$4.....FS.....$5...FS.....$6.....FS.....$7......FS.....$8.....FS.....$9.....
  gff_format_V2 = REST REseqname REfs2 REsource REfs2 REfeature REfs2 REstart REfs2 REend REfs2 REscore REfs2 REstrand REfs2 REframe REGV2 REND ;
} # End of GFF_FORMAT_DEFS
#
function ARY_VARIABLES() {
  #
  PrintRPT("*  Default Settings...\n");
  #
  ############################################## LAYOUT
  # Page Layout
  Default["page_size"]="a4";               # Var["page_size"]
  Default["page_bbox"]="auto,0,0";         # Var["page_bbox"]
  Default["page_orientation"]="Landscape"; # Var["page_orientation"] : Landscape (default), Portrait.
  Default["margin_left"]="1cm";            # cm, in, pt
  Default["margin_right"]="1cm";           #
  Default["margin_upper"]="1cm";           #
  Default["margin_lower"]="1cm";           #
  Default["foreground_color"]="FGcolor";   #
  Default["background_color"]="BGcolor";   #
  Default["page_number"]=1;                # Var["page_number"] : Default=1
  Default["zoom_cmdln"]="*..*";            # retrieving zoom from custom file
  Default["zoom"]="*..*";                  # "*..*", "*..end", "start..*", "start..end"
  Default["blocks_x_page"]=1;              # Var["blocks_x_page"] : Default=1 # if ==0 then multiple vertical pages.
  Default["nucleotides_x_line"]=0;         # Var["nucleotides_x_line"] : Default=0,gets the seqlenght from data
  Default["block_style"]="default";        # default, boxed
  Default["default_block_spacing_width"]="0.25cm"; #
  Default["show_blocks_top-bottom"]=1;     # Var["show_blocks_top-bottom"] : 1->TopBottom, 2->LeftRight.
  Default["show_page_limits"]="off";
  # Title Area
  Default["header_style"]="default"; # none, default, boxed
  Default["header_scale"]=1;
  Default["title"]="default";        # none, default, "user def"
  Default["subtitle"]="default";     # none, default, "user def"
  Default["show_page_numbers"]="on"; #
  Default["show_date"]="on";         #
  Default["show_time"]="on";         #
  # Tick Marks
  Default["major_tickmarks_num"]=10;         #
  Default["major_tickmarks_nucleotides"]=-1; #
  Default["minor_tickmarks_num"]=10;         #
  Default["minor_tickmarks_nucleotides"]=-1; #
  Default["show_grid"]=1;                    #
  Default["show_inner_scale"]="both";        # both(default)/none/top/bottom
  Default["show_outer_scale"]="both";        #
  Default["default_scale_width"]="0.25cm";   #
  Default["default_scale_spacing_width"]=1;  # Only for outer scale. Units in rule_widths
  Default["nucleotide_scale"]="default";     #
# Blocks Layout
# Default["strand_show_mixed"]="off";
  Default["strand_show_forward"]="on";       #
  Default["strand_show_reverse"]="on";       #
  Default["strand_show_independent"]="on";   #
  Default["show_left_source_label"]="true";  #
  Default["left_source_label_width"]="2cm";  #
  Default["show_right_source_label"]="false"; #
  Default["right_source_label_width"]="2cm"; #
  Default["source_label_align"]="off"; # default centering labels
  Default["default_track_width"]="1cm";      #
  Default["default_track_spacing_width"]="0.25cm"; #
  Default["sort_tracks_by_sequence"]="on";   # on : by sequence - off : by source
# Default["default_track_scale"]=1;
# Default["default_track_spacing_scale"]=0.25;
  Default["block_label_scale"]=1;
  # General Properties
  Default["frame_unknown_color"]="orange"; #
  Default["frame0_color"]="blue";         #
  Default["frame1_color"]="red";          #
  Default["frame2_color"]="green";        #
  Default["block_label_fill_color"]="verylightred"; #
  Default["show_positions"]="false";      #
  Default["group_label_scale"]=1;
  Default["position_label_scale"]=1;
  Default["minimum_single_length"]=0; # minimum length for those elements that have a single component.
  Default["show_label_min_gene_length"]=-1; # shortest gene length to show its label (-1 show all labels)
  Default["hide_label_larger_gene_length"]=0; # hide those gene labels that are larger than gene plot length
  Default["min_group_separation"]=10; # minimum nucleotide distance between two groups to avoid overlapping.
  #
  ############################################## GFF-FEATURES
  FT_PROP["feature_color"]="default";    # default,1color(color),2color(color..color),3color(color..color..color)
  FT_PROP["feature_stroke_color"]="default"; #
  FT_PROP["shape"]="box";                # box, arrow, end_arrow, circle # still not implemented: vector, spike, block
  FT_PROP["fill_shape_mode"]="default";  # none(BGcolor), default(FGcolor 1color), 1_color, 2_color, frame-remainder, rainbow
  FT_PROP["vector_shape"]="default";     # line_plot, gradient
  FT_PROP["fill_vector_mode"]="default"; # none(0 BGcolor grad), default(0 black grad), rainbow(1), 1_color(BGcolor color 2), 2_color(color1 color2 2), 3_color(col1 col2 col3 2)
  FT_PROP["vert_align"]="default";       # center,baseline # still not implemented: reverse
  FT_PROP["layer"]=0;                    # now is implemented, first sorting for feature lines is made on FT_PROP["layer"]
  FT_PROP["label"]="++default++";        # ++none++ , ++default++ , "user-def"
  FT_PROP["label_scale"]=1;
  FT_PROP["show_feature"]="on";          #
  FT_PROP["show_feature_positions"]="false"; #
  #
  ############################################## GROUPS
  GR_PROP["feature_color"]="default";      #
  GR_PROP["feature_stroke_color"]="default"; #
  GR_PROP["group_color"]="default";        #
  GR_PROP["group_stroke_color"]="default"; #
  GR_PROP["group_shape"]="none";           # default (none) , ...
  GR_PROP["fill_shape_mode"]="default";    # none(BGcolor), default(FGcolor 1color), 1_color, 2_color, frame-remainder, rainbow
  GR_PROP["fill_vector_mode"]="default";   # none(0 BGcolor grad), default(0 black grad), rainbow(1), 1_color(BGcolor color 2), 2_color(color1 color2 2), 3_color(col1 col2 col3 2)
  GR_PROP["group_line"]="default";         # none , default (black line)
  GR_PROP["group_line_color"]="default";   #
  GR_PROP["vert_align"]="default";         # center or baseline
  GR_PROP["label"]="++default++";          # ++none++ , ++default++ , "user-def"
  GR_PROP["group_label_angle"]=0;          #
  GR_PROP["group_label_swap"]="false";     #
  GR_PROP["show_group"]="on";              #
  GR_PROP["group_label_scale"]="default";  # LAYOUT variable rules over this one
  GR_PROP["show_group"]="on";              #
  GR_PROP["show_group_positions"]="false"; #
  #
  ############################################## METHODS/SOURCES
  SO_PROP["feature_color"]="default";        #
  SO_PROP["feature_stroke_color"]="default"; #
  SO_PROP["group_color"]="default";          #
  SO_PROP["group_stroke_color"]="default";   #
  SO_PROP["group_label_angle"]=0;            #
  SO_PROP["group_label_swap"]="false";       #
  SO_PROP["left_label"]="++default++";  # ++none++ , ++default++ , ++sequence++, ++source++ , ++both++ , ++info++ , "user-def"
  SO_PROP["show_left_label"]="on";      #
  SO_PROP["right_label"]="++default++"; # ++none++ , ++default++ , ++sequence++, ++source++ , ++both++ , ++info++ , "user-def"
  SO_PROP["show_right_label"]="on";     #
  SO_PROP["single_source_label"]="off";
  SO_PROP["source_label_scale"]=1;
  SO_PROP["source_label_vert_align"]="center";
  SO_PROP["source_style"]="default";    # default, boxed
  SO_PROP["source_line"]="default";     # none , default (black line), line, dotted, longdotted, shortdashed, longdashed
  SO_PROP["source_line_color"]="verydarkred"; #
  # SO_PROP["source_fill_shape_mode"]="none"; # none(BGcolor), 1_color
  # SO_PROP["source_fill_color"]="default"; # none(BGcolor), 1_color
  SO_PROP["vert_align"]="default";      # default,center,baseline(down),
  SO_PROP["range"]="default";           # range of lower-upper scores (none, default, "#user_def number#")
  SO_PROP["show_source_positions"]="false";   #
  SO_PROP["keep_feature_label_space"]="true"; # on/off
  SO_PROP["track_scale"]=1;                   #
  SO_PROP["track_spacing_scale"]=0.25;        #
  SO_PROP["last_track_spacing_scale"]="default"; #
  SO_PROP["unfold_grouped_ungrouped"]="off";  # on/off
  SO_PROP["unfold_grouped_line"]="on";        # on/off
  SO_PROP["unfold_ungrouped_line"]="on";      # on/off
  SO_PROP["unfold_revert"]="off";             # on/off
  SO_PROP["fit_block_height"]="off";
#
# Not defined yet:
#
#  Default["text_color"]=Default["foreground_color"];
#
#  FT_PROP["join"]="on";
#
#  GR_PROP["join_align"]="center";
#  GR_PROP["join_color"]=Default["foreground_color"];
#  GR_PROP["join_linetype"]="solid";
#  GR_PROP["join_show"]="off";
#
#  SO_PROP["bbox_color"]=Default["foreground_color"];
#
#  ?_PROP["rule_scale"]="nucleotide";
#  ?_PROP["rule_rel"]="none";
#  ?_PROP["rule_abs"]="none";
#
  #
  ############################################## PRE-DEFINED PARAMETERS
  # gff2ps strand-frame codification
  strands["+"]=strands["."]=strands["-"]=1;
  wstr[1]="+";wstr[2]=".";wstr[3]="-";
  Frames["."]=Frames["0"]=Frames["1"]=Frames["2"]=1;
  #
  # vector classes
  VT["sco"]=VT["score"]=VT["0pos-sco"]= 0;                            # only scores
  VT["pos"]=VT["position"]=VT["1pos-sco"]=VT["def"]=VT["default"]= 1; # position-score pairs
  VT["seg"]=VT["segment"]=VT["2pos-sco"]= 2;                          # position-position-score triplets
  VT["str"]=VT["string"]=VT["sequence"]= 3;                           # position-position-score triplets
  shpVT["default"]=shpVT["gradient"]="vt";
  shpVT["line_plot"]=shpVT["line"]="vtc";
  shpVT["bar_plot"]=shpVT["bars"]="vtb";
  #
  # Coding shape-names
  shpnm["none"]="no_shp";
  shpnm["default"]=shpnm["line"]="line";
  shpnm["base_line"]="bline";
  shpnm["thick_line"]="tline";
  shpnm["weighted_line"]="scline";
  shpnm["box"]="box";
  shpnm["half_box"]="hbox";
  shpnm["circle"]="fcir";
  shpnm["half_circle"]="hcir";
  shpnm["arrow_head"]=shpnm["right_arrow_head"]="frhead";
  shpnm["half_arrow_head"]=shpnm["half_right_arrow_head"]="hrhead";
  shpnm["left_arrow_head"]="flhead";
  shpnm["half_left_arrow_head"]="hlhead";
  shpnm["arrow_end"]=shpnm["right_arrow_end"]="frend";
  shpnm["half_arrow_end"]=shpnm["half_right_arrow_end"]="hrend";
  shpnm["left_arrow_end"]="flend";
  shpnm["half_left_arrow_end"]="hlend";
  shpnm["single"]=shpnm["right_single"]=shpnm["arrow"]=shpnm["right_arrow"]="frsgl";
  shpnm["half_single"]=shpnm["half_arrow"]=shpnm["half_right_arrow"]="hrsgl";
  shpnm["left_single"]=shpnm["left_arrow"]="flsgl";
  shpnm["half_left_single"]=shpnm["half_left_arrow"]="hlsgl";
  shpnm["right_triangle"]="frtgl";
  shpnm["half_right_triangle"]="hrtgl";
  shpnm["left_triangle"]="fltgl";
  shpnm["half_left_triangle"]="hltgl";
  shpnm["diamond"]="fdmd";
  shpnm["half_diamond"]=shpnm["up_triangle"]="hdmd";
  shpnm["down_triangle"]="fdtgl";
  shpnm["sand_clock"]="f2tgl";
  shpnm["asterisk"]="fast";
  shpnm["star"]="fstar";
  shpnm["gap"]="gap";
  shpnm["group_tag_box"]="gtgb";
  shpnm["right_angle"]="rangl";
  shpnm["left_angle"]="langl";
  shpnm["loop"]="loop";
  # BG features
  shpnm["background_box"]="bgb";
  shpnm["background_boundary"]="bgw";
  shpnm["on_interval"]="oim";
  shpnm["on_ruler_mark"]="orm";
  # shpnm["half_star"]="hstar";
  #
  # Coding baseline alignment
  shpal["baseline"]=shpal["bottom"]=1;
  shpal["default"]=shpal["center"]=0;
  shpal["mirror"]=2;
  shpal["reverse"]=shpal["top"]=-1;
  #
  # Label Valign
  shplv["default"]=shplv["center"]="(cv)";
  shplv["top"]="(tv)";
  shplv["bottom"]="(bv)";
  #
  # Coding line-types
  lnnm["none"]="no";
  lnnm["default"]=lnnm["line"]="ln";
  lnnm["dotted"]=lnnm["dotted_line"]="dt";
  lnnm["long_dotted"]="lt";
  lnnm["short_dashed"]="sh";
  lnnm["long_dashed"]="lh";
  lnnm["bracket"]="bk";
  lnnm["arrow"]=lnnm["right_arrow"]="raw";
  lnnm["left_arrow"]="law";
} # ARY_VARIABLES
#
function PageSizesDEF() { # Default PageSizes:
  #
  PrintRPT("*  Default Page Formats...\n");
  #
  PsizeX["a0"]=2384; PsizeY["a0"]=3370;
  PsizeX["a1"]=1684; PsizeY["a1"]=2384;
  PsizeX["a2"]=1190; PsizeY["a2"]=1684;
  PsizeX["a3"]=842; PsizeY["a3"]=1190;
  PsizeX["a4"]=595; PsizeY["a4"]=842;
  PsizeX["a5"]=420; PsizeY["a5"]=595;
  PsizeX["a6"]=297; PsizeY["a6"]=420;
  PsizeX["a7"]=210; PsizeY["a7"]=297;
  PsizeX["a8"]=148; PsizeY["a8"]=210;
  PsizeX["a9"]=105; PsizeY["a9"]=148;
  PsizeX["a10"]=73; PsizeY["a10"]=105;
  PsizeX["b0"]=2920; PsizeY["b0"]=4127;
  PsizeX["b1"]=2064; PsizeY["b1"]=2920;
  PsizeX["b2"]=1460; PsizeY["b2"]=2064;
  PsizeX["b3"]=1032; PsizeY["b3"]=1460;
  PsizeX["b4"]=729; PsizeY["b4"]=1032;
  PsizeX["b5"]=516; PsizeY["b5"]=729;
  PsizeX["b6"]=363; PsizeY["b6"]=516;
  PsizeX["b7"]=258; PsizeY["b7"]=363;
  PsizeX["b8"]=181; PsizeY["b8"]=258;
  PsizeX["b9"]=127; PsizeY["b9"]=181;
  PsizeX["b10"]=91; PsizeY["b10"]=127;
  PsizeX["10x14"]=720; PsizeY["10x14"]=1008;
  PsizeX["executive"]=540; PsizeY["executive"]=720;
  PsizeX["folio"]=612; PsizeY["folio"]=936;
  PsizeX["ledger"]=1224; PsizeY["ledger"]=792;
  PsizeX["legal"]=612; PsizeY["legal"]=1008;
  PsizeX["letter"]=612; PsizeY["letter"]=792;
  PsizeX["quarto"]=610; PsizeY["quarto"]=780;
  PsizeX["statement"]=396; PsizeY["statement"]=612;
  PsizeX["tabloid"]=792; PsizeY["tabloid"]=1224;
  PsizeX["userdefined"]=595; PsizeY["userdefined"]=2384;
  NumPGSZ=34; # 32 fixed + 2 variable
} # PageSizesDEF
#
function READ_CL() {
  #
  PrintRPT("*  Processing Comman-Line Options...\n");
  #
  while ( ( getline < ARGV[1] ) > 0 ) {
    npar=split($0,parm,"::");
    for (r=1;r<=npar;r++) {
      split(parm[r],elem,":=");
      if (elem[1]~/COLOR$/) {
        ecolor=elem[2];
        if (!ChkColor(ecolor)) elem[2]=BG_COLOR;
        else if (tolower(ecolor)~/^fg(color)?$/) elem[2]=FG_COLOR;
      } # if elem[1]
      if (elem[2]!="!!!???") Var[elem[1]]=elem[2];
    } # for
  } # while
  ARGV[1]="";
} # READ_CL
#
function ChkInput() { # some changes will be made on input line if some defaults were present.
  f=split($0,ln,/[\t ]*[\#]/);
  if (ln[1]!="") {
    $0=""; $0=ln[1]; for (s=1;s<=f;s++) { delete ln[s] };
    if (!($frame in Frames) && NF>=8) {
      PrintWRN(sprintf("*** WARNING ***  Unknown frame \"%s\" (replaced by \".\") in [%s]:\n", $frame, NR)); #  ***  <%s>\n", $frame, NR, $0));
      $frame=".";
    } # if frame not exist
    if (!($strand in strands) && NF>=8) {
      PrintWRN(sprintf("*** WARNING ***  Unknown strand \"%s\" (replaced by \".\") in [%s]:\n", $strand, NR)); #  ***  <%s>\n", $strand, NR, $0));
      $strand=".";
    } # if strand not exist
    if ($start>$end && NF>=8) {
      kk=$start; $start=$end; $end=kk;
      # "[%s]: <%s>\n" <===> NR, $0
      PrintWRN(sprintf("*** WARNING ******  Non-standard gff-formatted input line [%s].\n            ***  REMEMBER that START(%s) must be lower or equal than END(%s): Swapping their values.\n", NR, $start, $end));
    } # if start>end
    if ($0~gff_format_V2) {
      GFF_V=2;
      return 1;
    } else { # if gff-line Version 2 KO
      if ($0~gff_format_V1) {
        GFF_V=1;
        return 1;
      } else { # if gff-line Version 1 KO
        if ($0!~/^[\t ]*$/) {
          if (NF<8) {
            PrintWRN(sprintf("*** WARNING ***  Non-standard gff-formatted input line [%s]: <%s>\n            ***  There are %s fields left: Standard gff lines need a minimum of 8 fields.\n", NR, $0, 8-NF));
          } else { # if NF>8		
            PrintWRN(sprintf("*** WARNING ******  GARBAGE!: Non-standard gff-formatted input line [%s]:\n            ***  <%s>\n", NR, $0));
	  }; # else if NF>8
        } else {
          PrintWRN(sprintf(">>> %10s :: Empty line... <%s>\n", NR, $0));
        };
        return 0;
      }; # else gff-line WRONG
    }; # else gff-line NON-Standard
  } else { # else empty line
    if ($0~/^[\t ]*[\#].*/)
      PrintWRN(sprintf(">>> %10s :: Comment Line: <%s>\n", NR, ChkCharIF($0)));
    else
      PrintWRN(sprintf(">>> %10s :: Empty line... <%s>\n", NR, $0));
    return 0;
  }; # if not comment
} # ChkInput
#
function scan_quotes(Vscn) {
  while ($Vscn!~/^.*[^\"]\"(\;)?$/ && Vscn<NF) { Gtv=Gtv" "$Vscn; $Vscn=""; Vscn++ };
  if ($Vscn~/^.*[^\"]\"(\;)?$/)
    Gtv=Gtv" "$Vscn; # solving '"<label>";' issue
  else
    Gtv=Gtv" "$Vscn"\"";
  gsub(/\;$/,"",Gtv);
  $Vscn="";
} # scan_quotes
#
function LOAD_Quoted(GFN,    mm) {
  if ($GFN~"^"REgroupV2"$") { # if tag-value single single
    split($GFN,mm,/\"/);
    gp_tag=mm[1];
    Gtv=mm[2];
    Vscn=GFN+1;
    gp_TYPE="Tag-Value (Single)";
  # printf "***GFFV*** %s *** %s ***Tag*** %s ***Val*** %s ***Vscn*** %s\n", GFF_V, gp_TYPE, gp_tag, Gtv, Vscn | "cat 1>&2";
  } else {
    if ($GFN~"^"REtag"$" && $(GFN+1)~"^"REval"$") { # if tag-value single double
      gp_tag=$GFN;
      Gtv=$(GFN+1);
      Vscn=GFN+1;
      gp_TYPE="Tag-Value (Double)";
    # printf "***GFFV*** %s *** %s ***Tag*** %s ***Val*** %s ***Vscn*** %s\n", GFF_V, gp_TYPE, gp_tag, Gtv, Vscn | "cat 1>&2";
    } else {
      if ($GFN~"^"REtag"$" && $(GFN+1)~/^\".*[^\"]$/) { # if tag-value multiple
        gp_tag=$GFN;
        Gtv=$(GFN+1);
        Vscn=GFN+2;
        scan_quotes(Vscn);
        gp_TYPE="Tag-Value (Multiple)";
      # printf "***GFFV*** %s *** %s ***Tag*** %s ***Val*** %s ***Vscn*** %s\n", GFF_V, gp_TYPE, gp_tag, Gtv, Vscn | "cat 1>&2";
      } else {
        if ($GFN~"^"CKgroupV1"$") { # if value single
          Gtv=$GFN;
          gp_TYPE="Value (Single)";
          # printf "***GFFV*** %s *** %s ***Tag*** %s ***Val*** %s\n", GFF_V, gp_TYPE, gp_tag, Gtv | "cat 1>&2";
        } else {
          if ($GFN~/^\".*[^\"]$/) { # if value multiple
            Gtv=$GFN;
            Vscn=GFN+1;
            scan_quotes(Vscn);
            gp_TYPE="Value (Multiple)";
          # printf "***GFFV*** %s *** %s ***Tag*** %s ***Val*** %s\n", GFF_V, gp_TYPE, gp_tag, Gtv | "cat 1>&2";
          };
        }; # else value multiple
      }; # else value single
    }; # else tag-value multiple
  }; # else tag-value single double
} # LOAD_Quoted
#
function LOAD_Groups(    pnt,lbgp_tmp) {
  # Obtaining group string values.
  gptv=1;
  gp_tag=".";
  Gtv=".";
  if (NF>8 && $group!=".") {
    LOAD_Quoted(group);
    gsub("\"","",Gtv); # removing quotes from group name.
    gsub(/\;$/,"",Gtv); # solving '"<label>";' issue
    lbgp_tmp=Gtv;
    Gtv=$seqname $source $strand Gtv;
    label_group[Gtv]=lbgp_tmp;
    flg_grp=1;
  } else {
    Gtv=NR $seqname $source $strand;   # empty group defined as default (none==".")
    label_group[Gtv]="";
    gp_TYPE="Ungrouped";
    flg_grp=0;
  }; # if NF==8 and group=="." or group==""
} # LOAD_Groups
#
function LOAD_Vectors(    v_nm,K,k,W,w,vs,vv,va,v_,stp,lsco,usco,nsc,vtsc,equal) {
  # PrintRPT("Parsing Vector: "NF" == "Vscn" ?");
  if (NF==Vscn) {  # Loading multi-record vectors.
    v_nm=vct_element[$feature,iG2];
    # loading VECTOR elements.
    element[iG2,v_nm,start]    = min(element[iG2,N[iG2],start],$start);
    element[iG2,v_nm,end]      = max(element[iG2,N[iG2],end],$end);
    element[iG2,v_nm,v_window] = "NONE";
    element[iG2,v_nm,v_step]   = "NONE";
    if ($score!=".") {
      element[iG2,v_nm,v_scmin]  = min(element[iG2,v_nm,v_scmin],$score);
      element[iG2,v_nm,v_scmax]  = max(element[iG2,v_nm,v_scmax],$score);
    };
    element[iG2,v_nm,v_DATA]   = element[iG2,v_nm,v_DATA]""sprintf(" %5.3f %s %s",$score,$start,$end);
    element[iG2,v_nm,v_NUM]++;
    # removing FEATURE elements.
    if (element[iG2,v_nm,v_NUM]>1) { # if multi-record vectors
      element[iG2,v_nm,v_CLASS]=VT["segment"];
      delete element[iG2,N[iG2],feature];
      delete element[iG2,N[iG2],start];
      delete element[iG2,N[iG2],end];
      delete element[iG2,N[iG2],frame];
      delete element[iG2,N[iG2],score];
      N[iG2]--;
      sources[iS]--; # field 2 (source) record-counter
      FT_ary[iF]--;  # field 3 (gff-feature) record-counter
      GP_ary[Gtv]--; # field 9 (group) record-counter
    };
  } else { # Loading single-record vectors. (Vector: sco sco ... sco)
    v_nm=N[iG2];
    element[iG2,v_nm,v_window] = 0; # if none then paired data.
    element[iG2,v_nm,v_step]   = 0; # if none then paired data.
    element[iG2,v_nm,v_scmin]  = 0; # score defined?
    element[iG2,v_nm,v_scmax]  = 0; # score defined?
    # PrintRPT(sprintf("GPName: %s\nMAIN: %s\nVECTOR: %s\n",VctSPLIT,vs[1],vs[2]));
    split($0,vs,VctSPLIT);
    # PrintRPT(sprintf("GPName: %s\nMAIN: %s\nVECTOR: %s\n",VctSPLIT,vs[1],vs[2]));
    K=split(vs[2],vv,/[ \t]*;[ \t]+/);
    # K=split(yoyoba,vv,/[ \t]*;[ \t]+/);
    # gsub(/[ \t]*/,"",vv[1]);
    if (tolower(vv[1]) in VT)
      element[iG2,v_nm,v_CLASS]=VT[vv[1]]; # vector class: score position(default) segment
    else
      element[iG2,v_nm,v_CLASS]=VT["default"]; # set as position-score
    lsco=usco=0;
    for (k=2;k<=K;k++) {
      W=split(vv[k],va,/[ \t]+/);
      v_=tolower(va[1]);
      # PrintRPT(sprintf("V-TAG: %s \tV-DATA: %s\n",va[1],va[2]));
      if (v_~/^window/ && va[2]~/[0-9]+/)
        element[iG2,v_nm,v_window] = va[2];
      else
        if (v_~/^step/ && va[2]~/[0-9]+/)
          element[iG2,v_nm,v_step]   = va[2];
        else
          if (v_~/^minval/ && va[2]~REscore) {
            element[iG2,v_nm,v_scmin] = va[2];
            lsco=1;
          } else
            if (v_~/^maxval/ && va[2]~REscore) {
              element[iG2,v_nm,v_scmax] = va[2];
              usco=1;
            } else
              if (v_~/^scores/) {
                stp=element[iG2,v_nm,v_CLASS]+1;
                vtsc=""; equal=0;
                for (w=2;w<=W;w+=stp) {
                  if (element[iG2,v_nm,v_CLASS]==0) {
                    vtsc=vtsc""va[w]" ";
                    nsc=va[w];
                  } else
                    if (element[iG2,v_nm,v_CLASS]==1) {
                      vtsc=vtsc""va[w]" "va[w+1]" ";
                      nsc=va[w+1];
                    } else
                      if (element[iG2,v_nm,v_CLASS]==2) {
                        vtsc=vtsc""va[w]" "va[w+1]" "va[w+2]" ";
                        nsc=va[w+2];
                      };
                    if (equal) {
                      if (nsc!="-") {
                        if (!lsco)
                          element[iG2,v_nm,v_scmin] = min(element[iG2,v_nm,v_scmin],nsc);
                        if (!usco)
                          element[iG2,v_nm,v_scmax] = max(element[iG2,v_nm,v_scmax],nsc);
                      };
                    } else {
                      if (nsc!="-") {
                        element[iG2,v_nm,v_scmin]=element[iG2,v_nm,v_scmax]=nsc;
                        equal=1;
                      };
                    }; # else equal==0
                }; # for w
                element[iG2,v_nm,v_DATA]=vtsc;
                for (w=1;w<=W;w++) delete va[w];
              }; # if scores
    }; # for
    if (element[iG2,v_nm,v_step]==0) {
      element[iG2,v_nm,v_step]=element[iG2,v_nm,v_window];
    };
    for (k=2;k<=K;k++) delete vv[k];
    delete vs[1];
    delete vs[2];
  };  # else single-record
  #
  element[iG2,v_nm,vector] = 1;
} # LOAD_Vectors
#
function ReadElements() { # read gff element within source, strand, and group
  sp_feat=0;
  # GFF format compliant record-counter
  gff_NR++;
  #
  $feature=tolower($feature);
  # Defining some indexes.
  iS=$source;  # iS=$seqname SUBSEP $source;
  iF=$feature; # iF=$seqname SUBSEP $feature;
  II=$seqname SUBSEP iS;
  # getting sequence order from file...
  if (!($seqname in seqs)) {
    TITLE_FN=TITLE_FN""$seqname" ";
  }
  if ($strand~/[+-]/) {
    STR_PMT=1;
    Nss[II]++; # Valid Sequence-Source Combinations (Strand)
  } else {
    STR_PMT=0;
    Nsn[II]++; # Valid Sequence-Source Combinations (No-Strand)
  };
  if (SQ_ORD[$seqname,STR_PMT]!="Y") {
    if (STR_PMT) seq_order["strand",seq_ordcnt++]=$seqname;
    else seq_order["none",seq_nordcnt++]=$seqname;
    SQ_ORD[$seqname,STR_PMT]="Y";
  };
  # getting source order from file...
  if (!(iS in sources)) {
    sc_score["MIN",iS] = 0;
    sc_score["MAX",iS] = $score;
  };
  if (SC_ORD[$seqname,iS,STR_PMT]!="Y") {
    if (STR_PMT) src_order["strand",src_ordcnt++]=$source;
    else src_order["none",src_nordcnt++]=$source;
    SC_ORD[$seqname,iS,STR_PMT]="Y";
  };
  # Defining some counters.
  seqs[$seqname]++;
  sources[iS]++; # field 2 (source) record-counter (Nsources for no-strand)
  FT_ary[iF]++ ; # field 3 (gff-feature) record-counter
  # Defining groups.
  LOAD_Groups();
  GP_ary[Gtv]++; # field 9 (group) record-counter
  # Creating group arrays.
  iG1=$seqname SUBSEP $source SUBSEP $strand;
  iG2=iG1 SUBSEP Gtv;
  if (!(iG2 in N)) {
    G[iG1]++;
    gp[iG1,G[iG1],gpname]     = Gtv;
    gp[iG1,G[iG1],gplabel]    = label_group[Gtv];
    gp[iG1,G[iG1],gpstart]    = $start;
    gp[iG1,G[iG1],gpend]      = $end;
    gp[iG1,G[iG1],is_grouped] = flg_grp;
    gp_cnt[Gtv]               = G[iG1];
  # PrintRPT(sprintf("***** %s {%s} *** Creating Group DataSet on %s\n",Gtv,G[iG1],iG1));
  # PrintRPT(sprintf("***** %s {%s} *** Is grouped? %s *** Group Class \"%s\"\n",Gtv,G[iG1],TxtBool(gp[iG1,G[iG1],is_grouped]),gp_TYPE));
  }; # if tmp in N
  N[iG2]++;
  # PrintRPT("#######FILE###START#" $start "##END#" $end "##\n");
  element[iG2,N[iG2],feature] = $feature;
  element[iG2,N[iG2],start]   = $start;
  element[iG2,N[iG2],end]     = $end;
  element[iG2,N[iG2],frame]   = $frame;
  element[iG2,N[iG2],score]   = $score; # element[iG2,N[iG2],group] = $group;
  # PrintRPT("#######ELEM###START#" element[iG2,N[iG2],start] "##END#" element[iG2,N[iG2],end] "##\n");
  # Defining vectors if present.
  if (!vct_element[$feature,iG2]) vct_element[$feature,iG2]=N[iG2];
  if (tolower(gp_tag)=="vector") {
    LOAD_Vectors();
    gp[iG1,G[iG1],is_grouped] = 0;
    gp[iG1,G[iG1],gplabel]    = "";
  } else element[iG2,N[iG2],vector]=0;
  # Defining expands if present
  if (!vct_expand[Gtv,iG2]) {
    gpx[Gtv,xpnd_zoom] = gpx[Gtv,xpnd_delta] = 0;
    vct_expand[Gtv,iG2]++;
  };
  if (!iS""SUBSEP":"SUBSEP"this_source_expand" in PLOT_FT) {
    PLOT_FT[iS,":","this_source_expand"] = 0;
  };
  txflg = 0;
  if (tolower(gp_tag)=="expand") {
    expand_ct++;
    gpx[Gtv,expand] = 1;
    gsub(";","",$12);
    gsub(";","",$14);
    gpx[Gtv,xpnd_zoom] = $12;
    gpx[Gtv,xpnd_delta] = $14;
    if ($16=="2") gpx[Gtv,xpnd_level] = "2";
    else if ($16=="1") gpx[Gtv,xpnd_level] = "1";
    else if ($16=="-1") gpx[Gtv,xpnd_level] = "-1";
    else gpx[Gtv,xpnd_level] = "0";
    txflg = gpx[Gtv,xpnd_level];
    gpx[Gtv,xpnd_frame] = $8; # frame
    PrintRPT("###############Found EXPAND Z:"gpx[Gtv,xpnd_zoom]" D:"gpx[Gtv,xpnd_delta]" L:"gpx[Gtv,xpnd_level]"\n");
  };
  PLOT_FT[iS,":","this_source_expand"] = max(txflg,PLOT_FT[iS,":","this_source_expand"]);
  # Defaults for sequence start and end.
  if (FIRST_POS>$start) FIRST_POS = $start;
  if (LAST_POS<$end)    LAST_POS  = $end;
  # start-end for each group-sc-strand
  gp[iG1,gp_cnt[Gtv],gpstart] = min(gp[iG1,gp_cnt[Gtv],gpstart],$start);
  # PrintRPT("##############MIN#" gp[iG1,gp_cnt[Gtv],gpstart] "##" min(gp[iG1,gp_cnt[Gtv],gpstart],$start) "##\n");
  gp[iG1,gp_cnt[Gtv],gpend]   = max(gp[iG1,gp_cnt[Gtv],gpend],$end);
  # PrintRPT("##############MAX#" gp[iG1,gp_cnt[Gtv],gpend] "##" max(gp[iG1,gp_cnt[Gtv],gpend],$end) "##\n");
  # getting score - boundaries
  sc_score["MIN",iS]=min($score,sc_score["MIN",iS]);
  sc_score["MAX",iS]=max($score,sc_score["MAX",iS]);
  # place gff element in sort array by acceptor position
  NS=N[iG2]-1;
  while ($start < element[iG2,S[iG2,NS],start] && NS>0) {
    S[iG2,NS+1]=S[iG2,NS]; NS--;
  }; # while
  S[iG2,NS+1]=N[iG2];
} # ReadElements
#
function SET_VARS() {
  #
  PrintWRN(sprintf("%s\n*  Processing User-Defined Options...\n%s\n\n",BigLINE,BigLINE));
  #
  # Variable definition hierarchy:
  # Program Defaults < Default Custom File < Custom File < Command Line.
  CreateProps(0);
  if (Var["exist_default_customfile"]) { # Modifying Defaults with default custom file
    PrintWRN(sprintf("\n%s\n*  Reading Default Custom File:\n*  \"%s\"\n*\n",BigLINE,Var["customfile_name_default"]));
    RCFile(Var["customfile_name_default"]);
  } # if exist_default_customfile
  else PrintWRN(sprintf("\n%s\n*  Default Custom File not loaded.\n%s\n",BigLINE,BigLINE));
  if (Var["load_customfile"]) { # Modifying Defaults with custom file
    PrintWRN(sprintf("\n%s\n*  Reading User Custom File:\n*  \"%s\"\n*\n",BigLINE,Var["customfile_name"]));
    RCFile(Var["customfile_name"]);
  } # if load_customfile
  else PrintWRN(sprintf("\n%s\n*  User Custom File not loaded.\n%s\n",BigLINE,BigLINE));
  PrintWRN(sprintf("\n%s\n*  Command-Line Options\n*\n",BigLINE));
  for (lytdef in Default) {
    dft=Default[lytdef];
    if (PLOT_LY[lytdef]!="") Default[lytdef]=PLOT_LY[lytdef];
    if (lytdef in Var) {
      if (Default[lytdef]!=Var[lytdef] && Var[lytdef]!="") Default[lytdef]=Var[lytdef];
    } # if lytdef in var
    else Var[lytdef]="\"NOT_DEF\"";
    if (PLOT_LY[lytdef]=="") PLOT_LY[lytdef]="\"NOT_DEF\"";
    if (Var["print_report"])
      printf "%s *** Default Value=%s : Custom File=%s : Command-Line=%s *** Using=%s\n",
             lytdef,dft,PLOT_LY[lytdef],Var[lytdef],Default[lytdef] | "sort 1>&2";
  }; # for lytdef
  if (Var["print_report"]) close("sort 1>&2");
  PrintWRN(sprintf("*\n* ........................................................ DONE\n*\n%s\n",BigLINE));
  # forcing page_size if page_bbox is provided in custom-files with its format.
  split(Default["page_bbox"],bbm,",");
  bbpgsz=tolower(bbm[1]); bbx=bbm[2]; bby=bbm[3];
  if (bbpgsz=="auto" || (bbx==0 || bby==0)) {
    bbpgsz=tolower(Default["page_size"]);
    if (!chkps(bbpgsz)) {
      bbx=PsizeX["a4"]; bby=PsizeY["a4"];
    } else {
      bbx=PsizeX[bbpgsz]; bby=PsizeY[bbpgsz];
    };
  } else {
    Default["page_size"]=bbpgsz;
    PsizeX[bbpgsz]=bbx; PsizeY[bbpgsz]=bby;
    NumPGSZ++;
  };
  # Title definition...
  # TITLE_FN=TITLE_SEQNAME # TITLE_FN=Var["InputFNs"];
  if (Default["title"]=="none") {
    flgt="false"; title="";
  } else {
    flgt="true";
    if (Default["title"]=="default") title=TITLE_FN;
    else title=Default["title"];
  };
  title=substr(title,1,100);
  # First and last position, zoom option checking...
  t_ori=Nuc_round(FIRST_POS,0); # floor
  t_end=Nuc_round(LAST_POS,1);  # ceiling
  #
  split(Default["zoom"],poszm,/\.\./);
  split(Default["zoom_cmdln"],poszmc,/\.\./);
  if (poszmc[1]!="*") poszm[1]=poszmc[1];
  if (poszmc[2]!="*") poszm[2]=poszmc[2];
  if (poszm[1]=="*") PORI=t_ori; else PORI=poszm[1];
  if (poszm[2]=="*") PEND=t_end; else PEND=poszm[2];
  #
  if (gff_NR==0) { ## Here can be included a checking for no strand drawn??
    PORI=0; PEND=1000;
    title="Empty PLOT";
    PrintWRN("\n***************\n*** WARNING *** There were no gff-records from input-files.\n*** WARNING *** You are going to obtain an empty page...\n***************\n");
  };
  if (PORI!=0) PDIF=PEND-PORI; # if PDIF=PEND-PORI+1 then plot with an "extra" nucleotide position.
  else PDIF=PEND;
  MGS=Default["min_group_separation"];
  # switching for tickmarks (none,both/default,top,bottom)
  FlgSwISUp=0; FlgSwISDn=0; TmTt=chktmk(Default["show_inner_scale"]);
  if (TmTt=="both") { FlgSwISUp=1; FlgSwISDn=1; }
  else {
    if (TmTt=="top") FlgSwISUp=1;
    else
      if (TmTt=="bottom") FlgSwISDn=1;
  };
  FlgSwOSUp=0; FlgSwOSDn=0; TmTt=chktmk(Default["show_outer_scale"]);
  if (TmTt=="both") { FlgSwOSUp=1; FlgSwOSDn=1; }
  else {
    if (TmTt=="top") FlgSwOSUp=1;
    else
      if (TmTt=="bottom") FlgSwOSDn=1;
  };
  #
  # Defining Multi-Chromosome Display Offsets.
  #   File format: offset/blank start end label(blanks as underscore)
  if (OnOff(Var["CHOSFLAG"])) {
    PrintRPT("\n"BigLINE"\nReading New OFFSET Line from file: "Var["CHOSFILE"]"\n"BigLINE"\n");
    while ((getline < Var["CHOSFILE"]) > 0 ) {
      if (tolower($1)=="offset") {
        CHOffSet[0]++;
        CHOffSet[CHOffSet[0]] = $2;
        CHOffSetend[CHOffSet[0]] = $3;
        gsub("_"," ",$4);
        CHOSlabel[CHOffSet[0]] = $4;
        PrintRPT("OFFSET "CHOffSet[0]" : "$0"\n");
      } else {
        CHOSblnk++;
        CHOSblnkori[CHOSblnk] = $2;
        CHOSblnkend[CHOSblnk] = $3;
        PrintRPT("BLANK "CHOSblnk" : "$0"\n");
      };
    }; # while CHOSFILE
    close(Var["CHOSFILE"]);
  }; # if CHOSFLAG
  #
} # SET_VARS
#
function SET_ORDER(    Q,S,lseq,lsrc,seso_rd) { # for swapping order for seqs or srcs.
  PrintWRN(sprintf("\n%s\n*  SORTING TRACKS and SEQUENCES\n*\n",BigLINE));
  #
  if (OnOff(Default["sort_tracks_by_sequence"])) {
    PrintWRN("*  Sorting by SEQUENCES then by SOURCES (Comparing Sources)\n*\n");
    lseq=seq_ordcnt; lsrc=src_ordcnt;   # strand(+/-) counter
    for (Q=0;Q<lseq;Q++) {   # sequence ordering ary loop
      for (S=0;S<lsrc;S++) { # source ordering ary loop
        seso_rd=seq_order["strand",Q] SUBSEP src_order["strand",S];
        if ((seso_rd in Nss) && !(seso_rd in CHKs)) {
          order["strand",ordcnt++]=seso_rd;
          PrintRPT(sprintf("***+++***STRAND***Order[%s]::%s::***K1::%s::***K2::%s::***CTRL::%s\n", (ordcnt-1), order["strand",(ordcnt-1)], seq_order["strand",Q], src_order["strand",S], CHKs[seso_rd]));
        }; # if seso_rd
        CHKs[seso_rd]++;
      }; # for S
    }; # for Q
    lseq=seq_nordcnt; lsrc=src_nordcnt; # no-strand counter
    for (Q=0;Q<lseq;Q++) {   # sequence ordering ary loop
      for (S=0;S<lsrc;S++) { # source ordering ary loop
        seso_rd=seq_order["none",Q] SUBSEP src_order["none",S];
        if ((seso_rd in Nsn) && !(seso_rd in CHKn)) {
          order["none",nordcnt++]=seso_rd;
          PrintRPT(sprintf("***+++***NO-STR***Order[%s]::%s::***K1::%s::***K2::%s::***CTRL::%s\n", (nordcnt-1), order["none",(nordcnt-1)], seq_order["none",Q], src_order["none",S], CHKn[seso_rd]));
        }; # if seso_rd
        CHKn[seso_rd]++;
      }; # for S
    }; # for Q
  } else {
    PrintWRN("*  Sorting by SOURCES then by SEQUENCES (Comparing Sequences)\n*\n");
    lseq=seq_ordcnt; lsrc=src_ordcnt;   # strand(+/-) counter
    for (S=0;S<lsrc;S++) {   # source ordering ary loop
      for (Q=0;Q<lseq;Q++) { # sequence ordering ary loop
        seso_rd=seq_order["strand",Q] SUBSEP src_order["strand",S];
        if ((seso_rd in Nss) && !(seso_rd in CHKs)) {
          order["strand",ordcnt++]=seso_rd;
          PrintRPT(sprintf("***+++***STRAND***Order[%s]::%s::***K1::%s::***K2::%s::***CTRL::%s\n", (ordcnt-1), order["strand",(ordcnt-1)], seq_order["strand",Q], src_order["strand",S], CHKs[seso_rd]));
        }; # if seso_rd
        CHKs[seso_rd]++;
      }; # for Q
    }; # for S
    lseq=seq_nordcnt; lsrc=src_nordcnt; # no-strand counter
    for (S=0;S<lsrc;S++) {   # source ordering ary loop
      for (Q=0;Q<lseq;Q++) { # sequence ordering ary loop
        seso_rd=seq_order["none",Q] SUBSEP src_order["none",S];
        if ((seso_rd in Nsn) && !(seso_rd in CHKn)) {
          order["none",nordcnt++]=seso_rd;
          PrintRPT(sprintf("***+++***NO-STR***Order[%s]::%s::***K1::%s::***K2::%s::***CTRL::%s\n", (nordcnt-1), order["none",(nordcnt-1)], seq_order["none",Q], src_order["none",S], CHKn[seso_rd]));
        }; # if seso_rd
        CHKn[seso_rd]++;
      }; # for Q	
    }; # for S
  };
  #
  PrintWRN(sprintf("* ........................................................ DONE\n*\n%s\n",BigLINE));
} # SET_ORDER
#
function SortGroups(    g) {
  PrintWRN(sprintf("\n%s\n*  SORTING GROUPS\n*\n",BigLINE));
  #
  for (sq in seqs) {
    for (sc in sources) {
      for (s in strands) {
        g=sq SUBSEP sc SUBSEP s;
        if (G[g]>0) {
          for (t=1;t<=G[g];t++) {
            gs=t-1;
            if (s!="-") { # sorting forward and no-strand by acceptors
              gpstrt_=gp[g,t,gpstart];
            # PrintRPT(sprintf("------- %s : (%s) #%s# #%s#\n",t,gp[g,t,gpname],gpstrt_,gp[g,t,gpend]));
              while (gpstrt_ < gp[g,SG[g,gs],gpstart] && gs>0) {
            # PrintRPT(sprintf("------- %s < %s\n",gp[g,t,gpstart],gp[g,SG[g,gs],gpstart]));
                SG[g,gs+1]=SG[g,gs]; gs--;
              }; # while
            } else { # sorting reverse by acceptors
              gpstrt_=gp[g,t,gpend];
            # PrintRPT(sprintf("------- %s : (%s) #%s# #%s#\n",t,gp[g,t,gpname],gpstrt_,gp[g,t,gpend]));
              while (gpstrt_ > gp[g,SG[g,gs],gpend] && gs>0) {
            # PrintRPT(sprintf("------- %s > %s\n",gp[g,t,gpend],gp[g,SG[g,gs],gpend]));
                SG[g,gs+1]=SG[g,gs]; gs--;
              }; # while
            };
            SG[g,gs+1]=t;
          }; # for t
          for (t=1;t<=G[g];t++)
            PrintRPT(sprintf("*** Re-Sorting groups : {%s} %s %s %s %s ( %s %s )\n",t,sq,sc,s,gp[g,SG[g,t],gpname],gp[g,SG[g,t],gpstart],gp[g,SG[g,t],gpend]));
        }; # if G[g]
      }; # for strands
    }; # for sources
  }; # for seqs
  #
  PrintWRN(sprintf("*\n* ........................................................ DONE\n*\n%s\n",BigLINE));
} # End of SortGroups
#
function Aux_LINES(sq,sc,s,   g,lg,pg,fldGxU,fldGln,fldUln,LN,c) {
  lg=sq SUBSEP sc SUBSEP s;
  fldGxU=OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"]);
  fldGln=OnOff(PLOT_FT[sc,":","unfold_grouped_line"]);
  fldUln=OnOff(PLOT_FT[sc,":","unfold_ungrouped_line"]);
  #if (!fldGxU) { c=(fldGln||fldUln); fldGln=fldUln=c }
  if (G[lg]>0) {
    if (s!="-") lastpos[lg,grouped_,1]=lastpos[lg,ungrouped_,1]=t_ori-1; # PORI;
    else lastpos[lg,grouped_,1]=lastpos[lg,ungrouped_,1]=t_end+1; # PEND;
    lines[lg,grouped_]=lines[lg,ungrouped_]=1;
    for (pg=1;pg<=G[lg];pg++) {
      g=SG[lg,pg];
      gp_nm =gp[lg,g,gpname];
      gp_ori=gp[lg,g,gpstart];
      gp_end=gp[lg,g,gpend];
      c=gp[lg,g,is_grouped];
      if (fldGxU) gp_gpd=c
      else gp_gpd=1; # 1 (grouped_) or 0 (ungrouped_)
      PrintRPT(sprintf(">>>>>>>%s %s %s %s (%s %s) G %s SG %s\n",sq,sc,s,gp_nm,gp_ori,gp_end,G[lg],g));
      LN=1;
      ttt=lg SUBSEP gp_gpd SUBSEP LN;
      if ((fldGln && c) || (fldUln && !c)) {
        PrintRPT(sprintf("A........%s : %s (%s) G %s SG %s %s %s %s %s \n",LN,lastpos[lg,gp_gpd,LN],gp_ori,G[lg],g,sq,sc,s,gp_nm));
        if (gp_end>PORI && gp_ori<PEND) {
          if (s!="-") {
            gpo=gp_ori;
            while (lastpos[ttt] >= gpo) { # && gp_ori<=gpo
              LN++;
              ttt=lg SUBSEP gp_gpd SUBSEP LN;
              if (!(ttt in lastpos)) {
                lastpos[ttt]=gp_end + MGS;
                break;
              };
              PrintRPT(sprintf("a(%s).........%s : %s : %s (%s:%s..%s)\n",s,LN,ttt,lastpos[ttt],gp_ori,gpo,gp_end));
            }; # while lastpos
            lastpos[lg,gp_gpd,LN]=gp_end + MGS;
          } else {
            gpe=gp_end;
            while (lastpos[ttt] <= gpe) { # && gpe>=gp_end
              LN++;
              ttt=lg SUBSEP gp_gpd SUBSEP LN;
              if (!(ttt in lastpos)) {
                lastpos[ttt]=gp_ori - MGS;
                break;
              };
              PrintRPT(sprintf("a(%s).........%s : %s : %s (%s:%s..%s)\n",s,LN,ttt,lastpos[ttt],gp_end,gp_ori,gpe));
            }; # while lastpos
            lastpos[lg,gp_gpd,LN]=gp_ori - MGS;
          };
        }; # if checklimits
        PrintRPT(sprintf("B........%s : %s (%s %s) G %s SG %s\n",LN,lastpos[lg,gp_gpd,LN],gp_ori,gp_end,G[lg],g));
        PrintRPT(sprintf(">>>>>>> Line %s : LastPos %s : ID <%s><%s><%s><%s> (%s %s) #G %s #SG %s\n",LN,lastpos[lg,gp_gpd,LN],sq,sc,s,gp_nm,gp_ori,gp_end,G[lg],g));
      }; # if checking
      lines[lg,gp_gpd]=max(lines[lg,gp_gpd],LN);
      LE[lg,gp_gpd,LN]++;
      LNelem[lg,gp_gpd,LN,LE[lg,gp_gpd,LN]]=g;
    }; # for g(SG)
  }; # if G>0
} # Aux_LINES
#
function MakeGroupLines(    lg,c) {
  PrintWRN(sprintf("\n%s\n*  Minimizing Lines for Overlapping Groups.\n%s\n",BigLINE,BigLINE));
  for (stp=1;stp<=3;stp++) { # for s in strand
    s=wstr[stp];
    if (OnOff(Default["sort_tracks_by_sequence"])) {
      for (sq in seqs) {
        for (sc in sources) {
          Aux_LINES(sq,sc,s);
        }; # for sources
      }; # for seqs
    } else {
      for (sc in sources) {
        for (sq in seqs) {
          Aux_LINES(sq,sc,s);
        }; # for seqs
      }; # for sources
    };
  }; # for strands
} # End of MakeGroupLines
#
function SET_PAGE_VARS() {  # Calculating Page Number, Blocks and NucxLine
  # header flags
  if (Default["header_style"]=="boxed") {
    shtt="true"; shbt="true";
  } else {
    if (Default["header_style"]=="default") {
      shtt="true"; shbt="false";
    } else {
      shtt="false"; shbt="false";
    };
  };
  HDRheight="1cm";
  #
  P=Default["page_number"];
  B=Default["blocks_x_page"];
  if (B>0) {
    if (Default["nucleotides_x_line"]==0) {
      if (B>1 || P>1) NOFFSET=Nuc_round((PDIF/(B*P)),1);
      else NOFFSET=PDIF;
    } else NOFFSET=Default["nucleotides_x_line"];
    # if (NOFFSET>PDIF) NOFFSET=PDIF; # necessary if it is defined a Zoom.
      B1= PDIF%NOFFSET!=0 ? ((PDIF-(PDIF%NOFFSET))/NOFFSET)+1 : ((PDIF-(PDIF%NOFFSET))/NOFFSET);
      P = B1%B!=0 ? ((B1-(B1%B))/B)+1 : ((B1-(B1%B))/B);
      if (OnOff(Default["show_blocks_top-bottom"])) {
        BOFFSET=NOFFSET; POFFSET=B*NOFFSET;
      } else {
        BOFFSET=P*NOFFSET; POFFSET=NOFFSET;
      };
      PrintWRN(sprintf("\n%s\n*  PostScript Page Definitions\n%s\n\n",BigLINE,BigLINE));
      PrintRPT(sprintf("page_number %s\nblocks_x_page %s\nnucleotides_x_line %s\nshow_blocks_top-bottom %s\n\n",P,B,NOFFSET,OnOff(Default["show_blocks_top-bottom"])));
    # PrintRPT(sprintf("\nPORI %s\nPEND %s\nP %s\nB %s\nNOFFSET %s\nBOFFSET %s\n\n",PORI,PEND,P,B,NOFFSET,BOFFSET));
  } else { # B==0
    if (Default["nucleotides_x_line"]==0) {
      if (P>1) NOFFSET=Nuc_round((PDIF/P),1);
      else NOFFSET=PDIF;
    } else NOFFSET=Default["nucleotides_x_line"];
    # if (NOFFSET>PDIF) NOFFSET=PDIF; # necessary if it is defined a Zoom.
    P = PDIF%NOFFSET!=0 ? ((PDIF-(PDIF%NOFFSET))/NOFFSET)+1 : ((PDIF-(PDIF%NOFFSET))/NOFFSET);
    POFFSET=BOFFSET=NOFFSET;
    PrintWRN(sprintf("\n%s\n*  PostScript Page Definitions\n%s\n\n",BigLINE,BigLINE));
    PrintRPT(sprintf("page_number %s\nblocks_x_page %s\nnucleotides_x_line %s\nshow_blocks_top-bottom %s\n\n",P,B,NOFFSET,OnOff(Default["show_blocks_top-bottom"])));
  }; # else B==0
  # Calculating Block scale factor.
  StrSize=0; NStSize=0; # for strands...
  aS=calcpt(Default["default_track_width"]);
  bS=calcpt(Default["default_track_spacing_width"]);
  for (ws in order) {
    split(ws,wsb,SUBSEP);
    split(order[ws],K,SUBSEP);
    # PrintRPT(sprintf("***+++***WS::%s::***wsb1::%s::***wsb2::%s::\n", ws, wsb[1], wsb[2]));
    # PrintRPT(sprintf("***+++***Order[ws]::%s::***K1::%s::***K2::%s::\n", order[ws], K[1], K[2]));
   # PrintRPT(sprintf("***+++***Order[ws]::%s::***ws::%s::***wsb1::%s::***wsb2::%s::\n", order[ws], ws, wsb[1], wsb[2]));
    # PrintRPT(sprintf("***+++***Order[ws]::%s::***K1::%s::***K2::%s::\n", order[ws], K[1], K[2]));
    # k=order[ws]; #K[2];
    k=order[ws]; #K[2];
    q=K[2];
    if (wsb[1]=="strand") {
      if (!OnOff(PLOT_FT[q,":","unfold_grouped_ungrouped"]) && !OnOff(PLOT_FT[q,":","unfold_grouped_line"]) && !OnOff(PLOT_FT[q,":","unfold_ungrouped_line"]))
        cl=1;
      else {
        if (DoUnFoldMixed(q) && !OnOff(PLOT_FT[q,":","unfold_grouped_ungrouped"]))
          cl=max(lines[k,"+",grouped_],lines[k,"-",grouped_]);
        else
          cl=max(lines[k,"+",grouped_],lines[k,"-",grouped_])+max(lines[k,"+",ungrouped_],lines[k,"-",ungrouped_]);
      };
      if (cl > 1 && PLOT_FT[q,":","last_track_spacing_scale"] != "default") {
        StrSize=StrSize+((cl*aS*PLOT_FT[q,":","track_scale"])+((cl - 1)*bS*PLOT_FT[q,":","track_spacing_scale"])+(bS*PLOT_FT[q,":","last_track_spacing_scale"]));
      } else {
        StrSize=StrSize+(cl*((aS*PLOT_FT[q,":","track_scale"])+(bS*PLOT_FT[q,":","track_spacing_scale"])));
      };
      # PrintRPT(sprintf("   +++***StrSize::%s::***cl::%s::***aS::%s::***bS::%s::\n", StrSize, cl, aS, bS));
    } else {
      if (wsb[1]=="none") {
        if (!OnOff(PLOT_FT[q,":","unfold_grouped_ungrouped"]) && !OnOff(PLOT_FT[q,":","unfold_grouped_line"]) && !OnOff(PLOT_FT[q,":","unfold_ungrouped_line"]))
          cl=1;
        else {
          if (DoUnFoldMixed(q) && !OnOff(PLOT_FT[q,":","unfold_grouped_ungrouped"]))
            cl=lines[k,".",grouped_];
          else
            cl=lines[k,".",grouped_]+lines[k,".",ungrouped_];
        };
        if (cl > 1 && PLOT_FT[q,":","last_track_spacing_scale"] != "default") {
          NStSize=NStSize+((cl*aS*PLOT_FT[q,":","track_scale"])+((cl - 1)*bS*PLOT_FT[q,":","track_spacing_scale"])+(bS*PLOT_FT[q,":","last_track_spacing_scale"]));
        } else {
          NStSize=NStSize+cl*((aS*PLOT_FT[q,":","track_scale"])+(bS*PLOT_FT[q,":","track_spacing_scale"]));
        };
      # PrintRPT(sprintf("   +++***NStSize::%s::***cl::%s::***aS::%s::***bS::%s::\n", NStSize, cl, aS, bS));
      }; # if wsb==none
    }; # else if wsb
  }; # for order
  if (OnOff(Default["strand_show_forward"])) StrSizeFwd=StrSize; else StrSizeFwd=0;
  if (OnOff(Default["strand_show_reverse"])) StrSizeRvs=StrSize; else StrSizeRvs=0;
  if (!OnOff(Default["strand_show_independent"])) NStSize=0;
  if (gff_NR==0) { StrSizeFwd=0.33; StrSizeRvs=0.33; NStSize=0.33 }
  BSize=StrSizeFwd+StrSizeRvs+NStSize; # +xtra; # +SclSize (points)
  # PrintRPT(sprintf("\n***+++***StrSizeFwd::%s::***StrSizeRvs::%s::***NStSize::%s::***BSize::%s::\n", StrSizeFwd, StrSizeRvs, NStSize, BSize));
  if (B>0) VP=1;
  else {
    Sw=calcpt(Default["default_scale_width"]);
    if (StrSizeFwd>0 && (NStSize>0 || StrSizeRvs>0) && (OnOff(FlgSwISDn) || OnOff(FlgSwISUp))) BSize=BSize+Sw;
    if (NStSize>0 && StrSizeRvs>0 && (OnOff(FlgSwISDn) || OnOff(FlgSwISUp))) BSize=BSize+Sw;
    if (Default["page_orientation"]=="Landscape") ttbby=bbx; else ttbby=bby;
    if (OnOff(shtt)) {
      tthdr=calcpt(HDRheight)*(bbx/PsizeX["a4"]);
      tthdr=(tthdr>calcpt("4cm"))?calcpt("4cm"):tthdr;
      tthdr=tthdr+calcpt(Default["default_block_spacing_width"]);
    } else tthdr=0; # +(4*calcpt(Default["default_scale_width"]))
    if (OnOff(Var["Show_Credits"])) {
      crdt=calcpt("2.5pt")*(bbx/PsizeX["a4"]);
      crdt=(crdt>calcpt("1cm"))?calcpt("1cm"):crdt;
      crdt=2*crdt;
    } else crdt=0;
    if (OnOff(FlgSwOSUp)) TSwu=(1+Default["default_scale_spacing_width"])*Sw; else TSwu=0;
    if (OnOff(FlgSwOSDn)) TSwd=(1+Default["default_scale_spacing_width"])*Sw; else TSwd=0;
    TSw=TSwu+TSwd;
    Tsize=ttbby-(tthdr+calcpt(Default["margin_upper"])+calcpt(Default["margin_lower"])+TSw+crdt);
    VP=(BSize/Tsize);
    if (int(VP)<VP) VP=int(VP)+1;
    PrintRPT(sprintf("\n*********\n**** Page Vsize = %s cm \n**** Title Vsize = %s cm \n**** Block Tsize = %s cm \n**** Credit Vsize = %s cm \n***************\n\n",ttbby/28.35,tthdr/28.35,Tsize/28.35,crdt/28.35));
  }; # else B==0
  # Major Minor Tickmarks ratio
  if (Default["major_tickmarks_nucleotides"]>NOFFSET) {
    Default["major_tickmarks_nucleotides"]=int(NOFFSET/10); 
  };
  if (Default["major_tickmarks_nucleotides"]==-1 || NOFFSET<Default["major_tickmarks_nucleotides"]) {
    kt=NOFFSET/Default["major_tickmarks_num"];
    Default["major_tickmarks_nucleotides"]=kt<1000?kt:Nuc_round(kt,0);
  };
  if (Default["minor_tickmarks_nucleotides"]==-1 || Default["major_tickmarks_nucleotides"]<Default["minor_tickmarks_nucleotides"]) {
    Default["minor_tickmarks_nucleotides"]=Default["major_tickmarks_nucleotides"]/Default["minor_tickmarks_num"];
  };
} # SET_PAGE_VARS
#
function MAIN_PAGE_LOOP() { # MAIN LOOP: Start
  if (OnOff(FlgSwISUp)) VSwu=Sw; else VSwu=0;
  if (OnOff(FlgSwISDn)) VSwd=Sw; else VSwd=0; # for PRINTTRACKS function only
  VSw=VSwu+VSwd;
  for (pages=1;pages<=P;pages++) {
    Vpages=1;
    BORI=PORI;
    startPSpage(pages,P,Vpages,VP);  # PostSCript PageSetup.
    if (B>0) {
      for (blocks=1;blocks<=B;blocks++) {
        BEND=BORI+NOFFSET;
        # make groups. assumes elements sorted by increasing acceptor position
        # PostScript Drawing strands, sources, groups, features
        # make plotlines. Put non-overlapping groups into the same plotting line.
        printf "%%##%% BLOCK %s - PAGE %s\n",blocks,pages;
        printf "%s %s %s block\n", BORI, BEND, blocks;
        PrintWRN(sprintf("*  Page: %s - Block: %s - Nuc_Ori: %s - Nuc_End: %s\n",pages,blocks,BORI,BEND));
        #
        PRINTblockBG();
        PRINTSOURCES();
        # if (Var["print_report"]) close("sort +6 1>&2"); # sort -k 7 1>&2
        # Closing Pages MAIN LOOP.
        if (OnOff(Var["CHOSFLAG"])) {
          PrintRPT(sprintf("   * Sequence: %-25s Source: %-25s Strand: %s *** Printing block offsets labels...\n", sq, sc, s));
          printf "%%##%% BLABELS\n";
          if (Default["major_tickmarks_nucleotides"]==-1) theta=1000;
          else theta=Default["major_tickmarks_nucleotides"];
          # if (theta>NOFFSET) { theta=Nuc_round(theta,0); };
          for (lzd=1;lzd<=CHOffSet[0];lzd++) {
            if (CHOffSet[lzd]>=BORI && CHOffSet[lzd]<BEND) {
              kukoo = CHOffSet[lzd] - theta;
              printf "%d %d (%s) split_ruler\n", kukoo, CHOffSet[lzd], CHOSlabel[lzd];
            }; # if
          }; # for CHOffSet
          for (lzd=1;lzd<=CHOSblnk;lzd++) {
            if (CHOSblnkori[lzd]>=BORI && CHOSblnkori[lzd]<BEND) {
              printf "%d %d () split_ruler\n", CHOSblnkori[lzd], CHOSblnkend[lzd];
            }; # if
          }; # for CHOSblnk
        }; # if CHOSFLAG
        printf "b_end %%##%% Closing BLOCK\n";
        BORI+=BOFFSET;
      }; # for blocks
      # PostSCript Page Trailer.
      endPSpage(pages);
    } else { # if B==0
      BEND=BORI+NOFFSET;
      # Converting to PostScript all plot elements.
      printf "%%\n%% Block Num: - Page: %s.%s\n%%\n",pages,Vpages;
      printf "%s %s 1 vblock\n", BORI, BEND;
      PrintWRN(sprintf("\n*  Page: %sH.%sV\nNuc_Ori: %s - Nuc_End: %s\n",pages,Vpages,BORI,BEND));
      #
      PRINTTRACKS(); # VP=(BSize/Tsize)
      # Closing Pages MAIN LOOP.
      printf "vb_end\n";
      endPSpage(pages,Vpages);
    }; # else B==0
    PORI+=POFFSET;
  }; # for pages
} # MAIN_PAGE_LOOP # MAIN LOOP: End
#
function PlotElement(kokoinc,peft,peng,pesc,fso,    shwpst,KEKE,mycece,ftcolor,tmpstr) {
  shwpst=TxtBool(OnOff(Default["show_positions"]) || OnOff(PLOT_FT[peft,":","show_feature_positions"]) || OnOff(PLOT_FT[peng,":","show_group_positions"]) || OnOff(PLOT_FT[pesc,":","show_source_positions"]));
  start_=element[PE,start]; # peng -> ng
  end_=element[PE,end];
  if (PLOT_FT[sc,":","range"]=="default") {
    scmin_=element[PE,v_scmin];
    scmax_=element[PE,v_scmax];
  } else {
    scmin_=lower_sc;
    scmax_=upper_sc;
  };
  ##
  if (rscaled_gp==1) { end_=start_ + Default["minimum_single_length"]; };
  ##
  # PrintRPT(sprintf("Element %s : %s : %s - %s\n",el,sel,start_,end_));
  # PrintRPT(sprintf("Positions for %s: Start %s - BORI %s : End %s - BEND %s\n",el,start_,BORI,end_,BEND));
  KEKE=ChkLimits(start_,BORI,end_,BEND);
  # if (!gpx[ng_,expand]) { KEKE=ChkLimits(start_,BORI,end_,BEND); mycece=0 }
  # else {
  #   mycece=(gpx[ng_,xpnd_delta]*gpx[ng_,xpnd_zoom]);
  #   KOKO=ChkLimits(min(sg_,(sg_ + mycoco - ((eg_ - sg_) * gpx[ng_,xpnd_zoom]))),BORI,max(eg_,(eg_ + mycoco + ((eg_ - sg_) * gpx[ng_,xpnd_zoom]))),BEND);
  #   KEKE=ChkLimits(min(start_,(sg_ + mycece - ((eg_ - sg_) * gpx[ng_,xpnd_zoom]))),BORI,max(end_,(eg_ + mycece + ((eg_ - sg_) * gpx[ng_,xpnd_zoom]))),BEND);
  #   # KEKE=ChkLimits((start_ - mycoco),BORI,(end_ - mycoco),BEND) || ChkLimits((start_ + mycoco),BORI,(end_ + mycoco),BEND);
  # };
  if (KEKE || gpx[peng,expand]) {
    elem_sc=element[PE,score];
    # PrintRPT(sprintf("Scores for %s: score %s (Min:%s - Max:%s)\n",el,elem_sc,lower_sc,upper_sc));
    if (sco_lm) score_=1; else score_=GetScore(elem_sc,scmin_,scmax_);
    # for gene mode. try to recompute relative frame and remainder
    if (element[PE,frame]!=".") {
      frame_=element[PE,frame];
      remainder_=(3-(end_-(start_+frame_)+1)%3)%3;
      frcfrm=1;
    } else { frame_="(.)"; remainder_="(.)"; frcfrm=0 }
    if (PLOT_FT[peft,":","label"]=="++none++") flflg="false";
    else flflg="true";
    ftcolor=Set_feat_Clr(peft,peng,pesc,0,frcfrm);
    if (gpx[peng,expand]) {
      if (gpx[peng,xpnd_level]>0) {
        if (peft ~ /^transcript/) PLOT_FT[peft,":","layer"]--;
        # if (peft_ !~ "^transcript") ftcolor="fgcolor 1";
      };
    };
    if (gpx[peng,expand]==0 || gpx[peng,xpnd_level] != 0) {
      # expand==0 does not show features... print features otherwise
      printf "%s %d %d %s %s %4.2f (%s) (%s) %s %s %s (%s) p\n", PLOT_FT[peft,":","layer"], start_, end_, frame_ , remainder_, score_, ftcolor, Set_feat_Shape(peft,peng,pesc), VertPos(3,pesc,peng,peft), shwpst, flflg, Plot_Lbl(peft) | fso;
    };
  }; # if element checklimits
} # PlotElement
#
function PlotVector(endgp_,    lnct,step_,window_,scmin_,scmax_,start_,end_,WK,w,pos_,cmmnd,cmmnt,vct_there) {
  start_=element[PE,start];
  end_=element[PE,end];
  step_=element[PE,v_step];
  window_=element[PE,v_window];
  if (step_=="NONE") step_=1;
  if (PLOT_FT[sc,":","range"]=="default") {
    scmin_=element[PE,v_scmin];
    scmax_=element[PE,v_scmax];
  } else {
    scmin_=lower_sc;
    scmax_=upper_sc;
  };
  PrintRPT(sprintf("     Vector : %s : %s - %s : Window %s Step %s : Min %s Max %s\n",feature_,start_,end_,window_,step_,scmin_,scmax_));
  gsub(/[ \t]+$/,"",element[PE,v_DATA]);
  WK=split(element[PE,v_DATA],V_ary,/[ \t]+/);
  lnct=0;
  if (WK>0) {
    if (window_!="NONE") {
      #
      #   # score vectors
      #
      cmmnt=tolower(PLOT_FT[feature_,":","vector_shape"]);
      cmmnd=shpVT[cmmnt];
      if (cmmnd!~/vt|vtc/) cmmnd="vt";
      pos_=start_+((window_/2));
      vct_there=0;
      for (w=1;w<=WK;w++) {
        if (pos_>=BORI && pos_<=BEND && pos_<=endgp_) { # pos_ is always taken as mid_position.
          if (vct_there==0) {
            vct_there=1;
            if (cmmnd=="vt") {
              printf "%s %s %s (%s) %s %s vt\n", BORI, BEND, start_, Set_feat_Clr(feature_,ng_,sc,1), window_, step_;
            } else {
              printf "%s %s %s (%s) %s %s %s\n", BORI, BEND, start_, PLOT_FT[feature_,":","feature_color"], window_, step_, cmmnd; # vt/vtc/vtb
            };
          };
          lnct++;
          if (lnct>1) printf " ";
          if (V_ary[w]!="-") {
            if (sco_lm) score_=1;
            else score_=GetScore(V_ary[w],scmin_,scmax_);
            printf "%5.3f", score_;
          } else printf "n"; # inorder to save memory, we reduce the empty spaces
        }; # if frame is on page
        if (lnct==20 || (lnct>0 && w==WK)) { printf "\n"; lnct=0 }
        pos_=pos_+step_;
      }; # for fixed steps...
      # if step_ for fixed values.
      #
      #   # position-score vectors
      #
    } else {
      #
      #   # segment-score vectors
      #
      cmmnt=tolower(PLOT_FT[feature_,":","vector_shape"]);
      cmmnd=shpVT[cmmnt];
      if (cmmnd!~/vt|vtc/) cmmnd="vt";
      vct_there=0;
      if (element[PE,v_CLASS] == 2) { # segment/2pos-sco
        for (w=1;w<=(WK-1);w+=3) {
          posO_=V_ary[w+1];
          posE_=V_ary[w+2];
          if (posE_>=BORI && posO_<=BEND) { # pos_ is always taken as mid_positio
            if (vct_there==0) {
              vct_there=1;
              if (cmmnd=="vt") {
                 printf "%s %s (%s) vg\n", start_, end_, Set_feat_Clr(feature_,ng_,sc,1);
              } else {
                 printf "%s %s (%s) vtg\n", start_, end_, Set_feat_Clr(feature_,ng_,sc,1);
              };
            };
            lnct++;
            if (sco_lm) score_=1;
            else score_=GetScore(V_ary[w],scmin_,scmax_);
            printf "%5.3f %s %s ", score_, posO_, posE_;
          };
          if (lnct==10 || w==WK-1) { printf "\n"; lnct=0; };
        };
      } else {
        if (element[PE,v_CLASS] == 1) { # position/1pos-sco
          for (w=1;w<=(WK-1);w+=2) {
            pos_=V_ary[w];
            if (pos_>=BORI && pos_<=BEND) { # pos_ is always taken as mid_position.
              if (vct_there==0) {
                vct_there=1;
                printf "%s %s (%s) vp\n", start_, end_, Set_feat_Clr(feature_,ng_,sc,1);
              };
              lnct++;
              if (sco_lm) score_=1;
              else score_=GetScore(V_ary[w+1],scmin_,scmax_);
              printf "%5.3f %s ", score_, pos_;
            }; # if frame is on page
            if (lnct==10 || w==WK-1) { printf "\n"; lnct=0; };
          };
        };
      }; # for position score pairs...
      #
      #   # string vector
      #
    }; # if step_ for position score pairs.
    if (vct_there==1) printf "(stop)\n";
  }; # if WK>0
} # PlotVector
#
function PRINT_ELEMENTS(    KOKO,lbl,lbltmp,K_k,glsvr) {
  for (gl=1;gl<=LE[SSS,i,l];gl++) {
    g=LNelem[SSS,i,l,gl];
    ng_=gp[SSS,g,gpname];
    if (OnOff(PLOT_FT[ng_,":","show_group"])) {
      rscaled_gp=0;
      sg_=gp[SSS,g,gpstart];
      eg_=gp[SSS,g,gpend];
      ##
      # length hack
      K_k=eg_ - sg_;
      if ((N[SSS,ng_]==1 && Default["minimum_single_length"]>0) && (K_k<Default["minimum_single_length"])) {
        eg_=sg_ + Default["minimum_single_length"];
        rscaled_gp=1;
      };
      ##
      if (!gpx[ng_,expand]) {
        mycoco=0; xpco=0;
        KOKO=ChkLimits(sg_,BORI,eg_,BEND);
      } else {

        mycoco=(gpx[ng_,xpnd_delta]*gpx[ng_,xpnd_zoom]);
        KOKO=ChkLimits(min(sg_,(sg_ + mycoco - ((eg_ - sg_) * gpx[ng_,xpnd_zoom]))),BORI,max(eg_,(eg_ + mycoco + ((eg_ - sg_) * gpx[ng_,xpnd_zoom]))),BEND);
        xpco=gpx[ng_,expand];
      };
      # if (!gpx[ng_,expand]) { KOKO=ChkLimits(sg_,BORI,eg_,BEND);
      #                         mycoco=0; xpco=0; }
      # else {
      #    mycoco=(gpx[ng_,xpnd_delta]*gpx[ng_,xpnd_zoom]);
      #    # FWD : (END or XEND)>BORI, (ORI or XORI)<BEND
      #    # RVS :
      #    KOKO=ChkLimits(min(sg_,(sg_ + mycoco - ((eg_ - sg_) * gpx[ng_,xpnd_zoom]))),BORI,max(eg_,(eg_ + mycoco + ((eg_ - sg_) * gpx[ng_,xpnd_zoom]))),BEND);
      #    xpco=gpx[ng_,expand];
      # };
      if (KOKO) {
        # plot group in file
        shwgrpst=TxtBool(OnOff(Default["show_positions"]) || OnOff(PLOT_FT[ng_,":","show_group_positions"]) || OnOff(PLOT_FT[sc,":","show_source_positions"]));
        if (PLOT_FT[ng_,":","label"]=="++none++") glflg="false";
        else glflg="true";
        #
        if (PLOT_FT[ng_,":","group_label_scale"]=="default" || PLOT_FT[ng_,":","group_label_scale"] !~ /[0-9]*[.]?[0-9]*/) {
           glsvr=Default["group_label_scale"];
        } else {
           glsvr=PLOT_FT[ng_,":","group_label_scale"];
        };
        swpgflg = TxtBool(OnOff(PLOT_FT[sc,":","group_label_swap"]) || OnOff(PLOT_FT[ng_,":","group_label_swap"]));
        if (PLOT_FT[sc,":","group_label_angle"] ~ /[0-9]*[.]?[0-9]*/ && PLOT_FT[sc,":","group_label_angle"] != 0) {
           gpangle=PLOT_FT[sc,":","group_label_angle"];
        } else {
           if (PLOT_FT[ng_,":","group_label_angle"] !~ /[0-9]*[.]?[0-9]*/) {
              gpangle=0;
           } else {
              gpangle=PLOT_FT[ng_,":","group_label_angle"];
           };
        };
        if (!gpx[ng_,expand]) {
           if (expand_ct>0) glflg="false"; # CELERA's HACK
           printf "%s %s (%s) (%s) %s (%s) %s %s %s %s (%s) %s gp\n", sg_, eg_, Set_group_Clr(ng_,sc), Set_group_Shape(ng_,sc), VertPos(2,sc,ng_), Set_Line(ng_,"gp_"), shwgrpst, glflg, swpgflg, gpangle, Plot_Lbl(ng_,sq,sc,s),glsvr;
        #  printf "%s %s (%s) (%s) %s (%s) %s %s (%s) %s gp\n", sg_, eg_, Set_group_Clr(ng_,sc), Set_group_Shape(ng_,sc), VertPos(2,sc,ng_), Set_Line(ng_,"gp_"), shwgrpst, glflg, Plot_Lbl(ng_,sq,sc,s),glsvr; }
        } else {
          # maybe someday include a charlength cutoff for labels...
          # if (length(gp[sq,sc,s,gp_cnt[ng_],gplabel])<=7) {
          lbl=Plot_Lbl(ng_,sq,sc,s);
          glflg="true";
          # } else { glflg="false" }; # lbl="";
          ncl=gpx[ng_,xpnd_frame];
          if (ncl==0)
            ncl=Default["frame0_color"]; # darkgreen
          else if (ncl==1)
            ncl=Default["frame1_color"]; # skyblue
          else if (ncl==2)
            ncl=Default["frame2_color"]; # darkred
          else # ncl==2
            ncl=Default["frame_unknown_color"]; # black
          zm=gpx[ng_,xpnd_zoom];
          dt=gpx[ng_,xpnd_delta];
          lv=gpx[ng_,xpnd_level];
        # printf "%s %s (%s 1) (%s) %s (%s) %s %s (%s) %s %s xp\n", sg_, eg_, PLOT_FT[ng_,":","group_color"], Set_group_Shape(ng_,sc), VertPos(2,sc,ng_), Set_Line(ng_,"gp_"), shwgrpst, glflg, Plot_Lbl(ng_,sq,sc,s), gpx[ng_,xpnd_zoom], gpx[ng_,xpnd_delta]; }; ## tolower(PLOT_FT[ng_,":","group_color"]) Set_group_Shape(ng_,sc)
        # print sg_ " " eg_ " (" Set_Color("1_color",ncl) ") (" ncl " box) " VertPos(2,sc,ng_) " (" Set_Line(ng_,"gp_") ") " shwgrpst " " glflg " (" lbl ") " zm " " dt " xp";
          printf "%s %s (%s) (%s box) %s (%s) %s %s %s %s (%s) %s %s %s %s xp\n", sg_, eg_, Set_Color("1_color",ncl), ncl, VertPos(2,sc,ng_), Set_Line(ng_,"gp_"), shwgrpst, glflg, swpgflg, gpangle, lbl, glsvr, zm, dt, lv;
        }; # else print expand group
        #
        # fsort = (s=="-") ? "sort -bn +0 -1 +1 -2 +2r -3 +5r -6" : "sort -bn +0 -1 +2 -3 +1 -2 +5 -6";
        fsort = (Var["POSIX_SORT"] == 1 ? "sort -k 1bn -k 2bn -k 3bnr -k 6bnr" : "sort +0bn +1bn +2bnr -3 +5bnr -6");
        for (el=1;el<=N[SSS,ng_];el++) {
          sel=S[SSS,ng_,el];
          PE=sq SUBSEP sc SUBSEP s SUBSEP ng_ SUBSEP sel;
          feature_=element[PE,feature];
          IS_VECT=element[PE,vector];
          if (OnOff(PLOT_FT[feature_,":","show_feature"])) {
            if (!IS_VECT) {
              PlotElement(mycoco,feature_,ng_,sc,fsort);
            } else { # if vector
              PlotVector(eg_);
            }; # if vector
          }; # if show feature
        }; # for elements in group
        if (!IS_VECT) close(fsort);
        printf "gx\n";
      }; # if group checklimits
    }; # if show group
  }; # for LE
} # PRINT_ELEMENTS
#
function PRINTblockBG(    do_prt,blckSTR,tmpSTR,myolof,olofstr,rlabel,cmmnd) { # do_brk,
  # do_brk=0;
  for (stp=1;stp<=3;stp++) { # for s in strand
    # if (do_brk) break;
    do_prt=0;
    sbg=wstr[stp];
    if (s~/[+-]/) lastcnt=ordcnt;
    else lastcnt=nordcnt;
    for (srcord=0;srcord<lastcnt;srcord++) { # for sc in sources
      if (sbg=="-") {
        ngcnt=(lastcnt-1)-srcord;
        split(order["strand",ngcnt],SQC,SUBSEP);
      } else {
        if (sbg=="+") split(order["strand",srcord],SQC,SUBSEP);
        else split(order["none",srcord],SQC,SUBSEP); # (s==".")
      };
      sq=SQC[1];
      sc=SQC[2];
      SSS=sq SUBSEP sc SUBSEP sbg;
      if (!OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"])) ungp=grouped_;
      else ungp=ungrouped_;
      for (pd=grouped_;pd>=ungp;pd--) {
        if (s=="-" && OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"])) i=!pd;
        else i=pd;
        if (s!=".") m_lines=max(lines[sq,sc,"+",i],lines[sq,sc,"-",i]);
        else m_lines=lines[sq,sc,".",i];
        for (pl=1;pl<=m_lines;pl++) {
          if (s=="-") l=m_lines-pl+1;
          else l=pl;
          if (OnOff(PLOT_FT[sc,":","fit_block_height"])) {
            tmpSTR = "";
            blckSTR = "%%##%% BGFEAT\nbackft \n";
            for (gl=1;gl<=LE[SSS,i,l];gl++) {
              ngbg=gp[SSS,LNelem[SSS,i,l,gl],gpname];
              # if (ChkLimits(sg_,BORI,eg_,BEND)) {
              for (el=1;el<=N[SSS,ngbg];el++) {
                PE=sq SUBSEP sc SUBSEP sbg SUBSEP ngbg SUBSEP S[SSS,ngbg,el];
                featurebg=element[PE,feature];
                if (OnOff(PLOT_FT[featurebg,":","show_feature"])) {
                  startbg=element[PE,start];
                  endbg=element[PE,end];
                  if (ChkLimits(startbg,BORI,endbg,BEND)) {
                    # PrintRPT(">>>>>L>>>>" sq "<<>>" sc "<<>>" gl "<<<<<<\n");
                    myolof = Set_feat_Clr(featurebg,ngbg,sc,0,frcfrm);
                    rlabel = Plot_Lbl(ngbg,sq,sc,sbg);
                    cmmnd = shpnm[PLOT_FT[featurebg,":","shape"]];
                    rlblscale = PLOT_FT[featurebg,":","label_scale"];
                    if (cmmnd!~/bg[bw]|o[ri]m/) cmmnd="bgb";
                    olofstr = sprintf("%d %d (%s) (%s) %s %s\n", startbg, endbg, myolof, rlabel, rlblscale, cmmnd);
                    if (cmmnd ~ /o[ri]m/) tmpSTR =tmpSTR "" olofstr;
                    else blckSTR = blckSTR "" olofstr;
                    do_prt = 1;
                  }; # checklimits
                }; # if show feature
              }; # for elements
              ##  } # checklimits
            }; # for groups
            if (do_prt) {
              PrintRPT(sprintf("   * Sequence: %-25s Source: %-25s Strand: %s *** Printing background features...\n", sq, sc, s));
              printf blckSTR "" tmpSTR "gx %%##%% Closing BGFEAT\n";
            }; # do_[rt
            # do_brk=1;
	  }; # fit_block_height
        }; # for pl
      }; # for pd
    }; # for scord in sources
  }; # for s in strands
} # PRINTblockBG
function PRINTSOURCES() { # print groups PlotSeqComp-like.
  notyet=1;
  for (stp=1;stp<=3;stp++) { # for s in strand
    s=wstr[stp];
    printf "%%##%% STRAND %s\n(%s) Strand\n", s, s;
    if ((s=="+" && OnOff(Default["strand_show_forward"])) || (s=="." && OnOff(Default["strand_show_independent"])) || (s=="-" && OnOff(Default["strand_show_reverse"]))) {
      if (s~/[+-]/) lastcnt=ordcnt;
      else lastcnt=nordcnt;
      for (srcord=0;srcord<lastcnt;srcord++) { # for sc in sources
        if (s=="-") {
          ngcnt=(lastcnt-1)-srcord; split(order["strand",ngcnt],SQC,SUBSEP);
        } else {
          if (s=="+") split(order["strand",srcord],SQC,SUBSEP);
          else split(order["none",srcord],SQC,SUBSEP);      # (s==".")
        };
        sq=SQC[1];
        sc=SQC[2];
        SSS=sq SUBSEP sc SUBSEP s;
        if (!OnOff(PLOT_FT[sc,":","fit_block_height"])) {
          PrintRPT(sprintf("   * Sequence: %-25s Source: %-25s Strand: %s\n", sq, sc, s));
          if (!OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"])) ungp=grouped_;
          else ungp=ungrouped_;
          for (pd=grouped_;pd>=ungp;pd--) {
            if (s=="-" && OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"])) i=!pd;
            else i=pd;
            if (s!=".") m_lines=max(lines[sq,sc,"+",i],lines[sq,sc,"-",i]);
            else m_lines=lines[sq,sc,".",i];
            for (pl=1;pl<=m_lines;pl++) {
              if (s=="-" || OnOff(PLOT_FT[sc,":","unfold_revert"])) l=m_lines-pl+1;
              else l=pl;
              if (DoUnFoldMixed(sc) || (!OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"]) && !OnOff(PLOT_FT[sc,":","unfold_grouped_line"]) && !OnOff(PLOT_FT[sc,":","unfold_ungrouped_line"]))) fl_gp="M";
              else { if (i) fl_gp="G"; else fl_gp="U"; };
              sco_lm=ScoreLimits();
              if (PLOT_FT[sc,":","source_style"]=="boxed") shscbx="true";
              else shscbx="false";
              if (!OnOff(PLOT_FT[sc,":","show_left_label"])) lftflb="false";
              else lftflb="true";
              if (!OnOff(PLOT_FT[sc,":","show_right_label"])) rgtflb="false";
              else rgtflb="true";
              if (PLOT_FT[sc,":","left_label"]=="++none++") lftflb="false";
              if (PLOT_FT[sc,":","right_label"]=="++none++") rgtflb="false";
              if (tolower(PLOT_FT[sc,":","source_label_vert_align"])~/default|center|top|bottom/)
                sr_v_al=shplv[PLOT_FT[sc,":","source_label_vert_align"]];
              else sr_v_al=shplv["default"];
              printf "%%##%% SOURCE %s\n",sc;
              if (OnOff(PLOT_FT[sc,":","single_source_label"]) && m_lines > 1 && pl == 1) {
                printf "%s obms\n", PLOT_FT[sc,":","track_scale"]; # open bracket multiline source
              };
              if (m_lines > 1 && pl == m_lines && PLOT_FT[sc,":","last_track_spacing_scale"] != "default") {
                tss=PLOT_FT[sc,":","last_track_spacing_scale"];
              } else {
                tss=PLOT_FT[sc,":","track_spacing_scale"];
              };
              if (PLOT_FT[sc,":","this_source_expand"] != 0) PLOT_FT[sc,":","range"]="none";
              printf "%s %s %s %s %s (%s) (%s) %s %s %s %s %s %s source\n", VertPos(1,sc), PLOT_FT[sc,":","track_scale"],tss,shscbx,TxtBool(OnOff(PLOT_FT[sc,":","keep_feature_label_space"])),s,Set_Line(sc,"sc_"),lftflb,rgtflb,Source_Lbl(sq,sc,s,fl_gp),PLOT_FT[sc,":","source_label_scale"],sr_v_al,PLOT_FT[sc,":","this_source_expand"];  # (lines[sq,sc,s,grouped_]+lines[sq,sc,s,ungrouped_])
              #
              # Plotting all elements for that source
              PRINT_ELEMENTS();
              #
              printf "s_end  %%##%% Closing SOURCE %s\n",sc;
              if (OnOff(PLOT_FT[sc,":","single_source_label"]) && m_lines > 1 && pl == m_lines) {
                printf "%s %s %s %s cbms\n", lftflb,rgtflb,Source_Lbl(sq,sc,s,fl_gp),PLOT_FT[sc,":","source_label_scale"];
              };
            }; # for lines
          }; # for grpd
        }; # !fit_block_height
      }; # for scord(source_ordering)
    }; # if strand_show
  # printf "%%##%% END of STRAND %s\n",s;
  };     # for strands(stp)
} # PRINTSOURCES
#
function ChangePage(ttt,ooo) {
  if (ttt>=Tsize) {
    printf "vb_end\n";
    endPSpage(pages,Vpages);
    Vpages++;
    startPSpage(pages,P,Vpages,VP);
    printf "%%\n%% Block Num: - Page: %s.%s\n%%\n",pages,Vpages;
    printf "%s %s 1 vblock\n", BORI, BEND;
    PrintWRN(sprintf("*  Page: %sH.%sV\nNuc_Ori: %s - Nuc_End: %s\n",pages,Vpages,BORI,BEND));
    return ooo;
  } else return ttt; # if up>Tsize
} # ChangePage
#
function PRINTTRACKS(    up_,tmpup,dflt_up) {
  up_=0; # 4*Sw+crdt;
  laststrand="+"; notyet=1;
  for (stp=1;stp<=3;stp++) { # for s in strand
    s=wstr[stp];
    printf "(%s) Strand %% ------------------ Strand(%s) Begin\n", s, s;
    if ((s=="+" && OnOff(Default["strand_show_forward"])) || (s=="." && OnOff(Default["strand_show_independent"])) || (s=="-" && OnOff(Default["strand_show_reverse"]))) {
      if (s=="+" || s=="-") lastcnt=ordcnt;
      else lastcnt=nordcnt;
      if (laststrand=="." && NStSize>0) {
        dflt_up=VSw;
        tmpup=up_+dflt_up;
        up_=ChangePage(tmpup,dflt_up);
      }; # if changestrand
      for (srcord=0;srcord<lastcnt;srcord++) { # for sc in sources
        if (s=="-") {
          ngcnt=(lastcnt-1)-srcord; split(order["strand",ngcnt],SQC,SUBSEP);
        } else {
          if (s=="+") split(order["strand",srcord],SQC,SUBSEP);
          else split(order["none",srcord],SQC,SUBSEP);      # (s==".")
        };
        sq=SQC[1];
        sc=SQC[2];
        SSS=sq SUBSEP sc SUBSEP s;
        PrintRPT(sprintf("   * Sequence: %-25s Source: %-25s Strand: %s\n", sq, sc, s));
        if (!OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"])) ungp=grouped_;
        else ungp=ungrouped_;
        for (pd=grouped_;pd>=ungp;pd--) {
          if (s=="-" && OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"])) i=!pd;
          else i=pd;
          if (s!=".") m_lines=max(lines[sq,sc,"+",i],lines[sq,sc,"-",i]);
          else m_lines=lines[sq,sc,".",i];
          for (pl=1;pl<=m_lines;pl++) {
            # Computing if next line fits on current page
            dflt_up=(aS*PLOT_FT[sc,":","track_scale"])+(bS*PLOT_FT[sc,":","track_spacing_scale"]);
            tmpup=up_+dflt_up;
            up_=ChangePage(tmpup,dflt_up);
            #
            if (s=="-" || OnOff(PLOT_FT[sc,":","unfold_revert"])) l=m_lines-pl+1;
            else l=pl;
            if (DoUnFoldMixed(sc) || (!OnOff(PLOT_FT[sc,":","unfold_grouped_ungrouped"]) && !OnOff(PLOT_FT[sc,":","unfold_grouped_line"]) && !OnOff(PLOT_FT[sc,":","unfold_ungrouped_line"]))) fl_gp="M";
            else { if (i) fl_gp="G"; else fl_gp="U"; };
            sco_lm=ScoreLimits();
            if (PLOT_FT[sc,":","source_style"]=="boxed") shscbx="true";
            else shscbx="false";
            if (!OnOff(PLOT_FT[sc,":","show_left_label"])) lftflb="false";
            else lftflb="true";
            if (!OnOff(PLOT_FT[sc,":","show_right_label"])) rgtflb="false";
            else rgtflb="true";
            if (PLOT_FT[sc,":","left_label"]=="++none++") lftflb="false";
            if (PLOT_FT[sc,":","right_label"]=="++none++") rgtflb="false";
            if (tolower(PLOT_FT[sc,":","source_label_vert_align"])~/default|center|top|bottom/)
              sr_v_al=shplv[PLOT_FT[sc,":","source_label_vert_align"]];
            else sr_v_al=shplv["default"];
            printf "%%##%% SOURCE %s\n",sc;
            if (m_lines > 1 && pl == m_lines && PLOT_FT[sc,":","last_track_spacing_scale"] != "default") {
              tss=PLOT_FT[sc,":","last_track_spacing_scale"];
            } else {
              tss=PLOT_FT[sc,":","track_spacing_scale"];
            };
            printf "%s %s %s %s %s (%s) (%s) %s %s %s %s %s %s source\n", VertPos(1,sc), PLOT_FT[sc,":","track_scale"],tss,shscbx,TxtBool(OnOff(PLOT_FT[sc,":","keep_feature_label_space"])),s,Set_Line(sc,"sc_"),lftflb,rgtflb,Source_Lbl(sq,sc,s,fl_gp),PLOT_FT[sc,":","source_label_scale"],sr_v_al,PLOT_FT[sc,":","this_source_expand"];  # (lines[sq,sc,s,grouped_]+lines[sq,sc,s,ungrouped_])
            #
            # Plotting all elements for that source
            PRINT_ELEMENTS();
            # Closing source
            printf "s_end  %%##%% Closing SOURCE %s\n",sc;
          }; # for pl(m_lines)
        }; # for pd
      }; # for scord
    }; # if show_strand
    if (laststrand=="+" && StrSizeFwd>0 && notyet ) {
      notyet=0;
      dflt_up=VSw;
      tmpup=up_+dflt_up;
      up_=ChangePage(tmpup,dflt_up);
    }; # if changestrand
    laststrand=s;
    printf "%% ------------------------------ Strand(%s) End\n",s;
  }; # for stp
} # PRINTTRACKS
#
function CREATECUSTOM() {
  if (Var["create_default_customfile"]) {
    PrintWRN(sprintf("\n%s\n*\n*  Custom File:\n*  %s\n*\n%s\n\n", BigLINE, Var["customfile_name_default"], BigLINE));
    if (Var["exist_default_customfile"]) {
      PrintWRN(sprintf("Warning: I am going to rewrite your Default Custom File.\n"));
      PrintWRN(sprintf("         Moving last Default Custom File to:\n           %s.old.%s\n",Var["customfile_name_default"],Var["PID"]));
      system("cp "Var["customfile_name_default"]" "Var["customfile_name_default"]".old."Var["PID"]);
    } else {
      PrintWRN(sprintf("Warning: Writing Default Custom File %s.\n",Var["customfile_name_default"]));
    };
    CreateProps(2);
  } else {
    NTC="%s\n* Warning: Defaults were taken from program defaults,\n";
    NTC=NTC"*          but current variable definitions are not saved.\n";
    NTC=NTC"*          If you want to force program to write default file,\n";
    NTC=NTC"*          you must pass the command-line option -d to the program.\n";
    NTC=NTC"*          Default custom-file name: %s\n*\n";
    NTC=NTC"*          ...See help for -d and -D <filename> options...\n*\n";
    PrintWRN(sprintf(NTC,BigLINE,Var["customfile_name_default"]));
  }; # else !created
  # Object Properties Report...
  CreateProps(1);
} # CREATECUSTOM
#
function CreateProps(flag,    STRING,prop,dffeat,feat,gpfeat,sofeat) {
  ############ Create Properties Index for Objects ############
  STRING="#\n# L ######PAGE LAYOUT & PROGRAM OPTIONS######\n#\n";
  if (flag==0) {
    PrintWRN(sprintf("%s\n*  Default Values to Variables\n*  for ALL GFF-Elements Read from INPUT:\n*\n",BigLINE));
  };
  if (flag==1) {
    PrintWRN(sprintf("%s\n*  Variables Defined for Default Custom File:\n*  \"%s\"\n*\n",BigLINE,Var["customfile_name_default"]));
    # for (dffeat in Default)
    #   printf "%s=%s\n", dffeat, Default[dffeat] | "sort 1>&2";
    # close("sort 1>&2");
  } else if (flag==2) {
    PrintWRN(sprintf("%s\n*\n*  Writing Default Custom File:\n*  \"%s\"\n*\n%s\n",BigLINE,Var["customfile_name_default"],BigLINE));
    CF_HEAD=       "########################################\n";
    CF_HEAD=CF_HEAD"##   DEFAULT CUSTOM FILE FOR GFF2PS   ##\n";
    CF_HEAD=CF_HEAD"########################################\n";
    CF_HEAD=CF_HEAD"##\n## User Name: %s\n##   Created: %s at %s\n##\n";
    printf CF_HEAD,usr,date,time > Var["customfile_name_default"];
    printf STRING > Var["customfile_name_default"];
    for (dffeat in Default)
      printf "%s=%s\n", dffeat, Default[dffeat] > Var["customfile_name_default"];
  }; # if flag==2
  STRING="#\n# F ############GENOMIC FEATURES############\n#\n";
  PrintWRN(STRING);
  if (flag==2) {
    printf STRING > Var["customfile_name_default"];
  };
  for (feat in FT_ary) {
    for (prop in FT_PROP) {
      if (flag==0) PLOT_FT[feat,":",prop]=FT_PROP[prop];
      else {
        if (PLOT_FT[feat,":",prop]=="") PLOT_FT[feat,":",prop]=FT_PROP[prop];
        if (flag==2)
          printf "%s::%s=%s\n", feat, prop, PLOT_FT[feat,":",prop] > Var["customfile_name_default"];
      };
    }; # for prop
    if (flag==1) {
      # close("sort 1>&2");
      PrintRPT(sprintf("# %s::%s=%s\n", feat, "feature_counter", FT_ary[feat]));
    };
  }; # for feat
  STRING="#\n# G ############GROUP FEATURES##############\n#\n";
  PrintWRN("*\n* ........................................................ DONE\n"STRING);
  if (flag==2) {
    printf STRING > Var["customfile_name_default"];
  };
  for (gpfeat in GP_ary) {
    for (prop in GR_PROP) {
      if (flag==0) PLOT_FT[gpfeat,":",prop]=GR_PROP[prop];
      else {
        if (PLOT_FT[gpfeat,":",prop]=="") PLOT_FT[gpfeat,":",prop]=GR_PROP[prop];
        # if (flag==1)
        #   printf "%s::%s=%s\n", gpfeat, prop, PLOT_FT[gpfeat,":",prop] | "sort 1>&2";
        # else
        if (flag==2)
          printf "%s::%s=%s\n", gpfeat, prop, PLOT_FT[gpfeat,":",prop] > Var["customfile_name_default"];
      };
    }; # for prop
    if (flag==1) {
      # close("sort 1>&2");
      PrintRPT(sprintf("# %s::%s=%s\n#\n", gpfeat, "group_elements_counter", GP_ary[gpfeat]));
    };
  }; # for gfeat
  STRING="#\n# S ############SOURCE FEATURES#############\n#\n";
  PrintWRN("*\n* ........................................................ DONE\n"STRING);
  if (flag==2) {
    printf STRING > Var["customfile_name_default"];
  };
  for (sofeat in sources) {
    for (prop in SO_PROP) {
      if (flag==0) PLOT_FT[sofeat,":",prop]=SO_PROP[prop];
      else {
        if (PLOT_FT[sofeat,":",prop]=="") PLOT_FT[sofeat,":",prop]=SO_PROP[prop];
        # if (flag==1)
        # printf "%s::%s=%s\n", sofeat, prop, PLOT_FT[sofeat,":",prop] | "sort 1>&2";
        # else
        if (flag==2)
          printf "%s::%s=%s\n", sofeat, prop, PLOT_FT[sofeat,":",prop] > Var["customfile_name_default"];
      };
    }; # for prop
    if (flag==1) {
      # close("sort 1>&2");
      PrintRPT(sprintf("# %s::%s=%s\n#\n", sofeat, "source_groups_counter", sources[sofeat]));
    };
  }; # for sofeat
  if (flag==2) close(Var["customfile_name_default"]);
  PrintWRN(sprintf("*\n* ........................................................ DONE\n*\n%s\n",BigLINE));
} # End of CreateProps
#
function chkGlobal(feat,gffirst,re,np,    go_on) {
  ChkCharRG(feat);
  if (!re) ChkCharRG(gffirst);
  # else gffirst="/"gffirst"/"
  if (np) { if (match(feat,gffirst)) go_on=0; else go_on=1;
  } else {
    if (re) { if (match(feat,gffirst)) go_on=1; else go_on=0;
    } else {
      if (feat==gffirst) go_on=1;
      else go_on=0;
    }; # else !exp_reg
  }; # else !neg_ptrn
  return go_on;
} # chkGlobal
#
function RCFile(file,    MATCH_T,MATCH_F,nothere,first,gffirst,second,ft_type,feat,lytdef,dft,exp_reg,neg_ptrn,df_,eq_,type_sel) { # Read CustomFile
  # PrintRPT(sprintf("\n%s\n*  Reading Custom File:\n%s\n\n*  %s\n*\n", BigLINE,BigLINE,file));
  MATCH_T="*** %s *** Feature %s - Match between: %s & %s : %s=%s\n";
  MATCH_F="********* Feature %s - No Match found : %s=%s\n";
  type_sel=0;
  while ((getline < file) > 0 ) {
    gsub(/^[ \t]+/,"",$0);
    if ( $0~/^[^\#]/ && $0!~/^( )*$/ && type_sel ) {
      # PrintRPT("\n>>> "ft_type" <<< "$0"\n");
      gsub(/[ \t]+([\#].*)?$/,"",$0)
      # PrintRPT("*** Removing Comments ***["$0"]***\n");
      nothere=global=exp_reg=neg_ptrn=0;
      df_="!=";eq_="==";
      if (ft_type!="L") {
        split($0,defs,"::");
        first=defs[1];
        split(defs[2],nwfeat,"=");
      } else {
        split($0,nwfeat,"=");
        first=nwfeat[1];
      };
      if (first~/^\*$/) first="/.*/";
      if (first~/^(\!)?\//) exp_reg=1; else exp_reg=0;
      if (exp_reg) {
        if (first~/^\!/) {
          neg_ptrn=1; df_="=="; eq_="!=";
        } else neg_ptrn=0;
        #gsub(/^!/,"",first);
        gsub(/^(!)?\//,"",first);
        gsub(/\/$/,"",first);
      } else neg_ptrn=0;
      second=nwfeat[1];
      PrintRPT("***:"$0":***:"first":***:"second":***:"nwfeat[2]":***REGEXP:"exp_reg"\n");
      if (ft_type=="F") { # F
        gffirst=tolower(first);
        if (second in FT_PROP) {
          for (feat in FT_ary) {
            go_on=chkGlobal(feat,gffirst,exp_reg,neg_ptrn);
            if (go_on) {
              PLOT_FT[feat,":",second]=nwfeat[2];
              PrintRPT(" +++ "ft_type" +++ Match found: "feat" "eq_" "gffirst" +++ <"nwfeat[2]">\n");
            }; # if go_on
            # else PrintRPT(" +++ "go_on" +++ No Match found: "feat" "df_" "gffirst" \n");
          }; # for feat
          if (!exp_reg && !(gffirst in FT_ary)) {
            for (pro_ in FT_PROP) {
              PLOT_FT[gffirst,":",pro_]=FT_PROP[pro_];
              # PrintRPT("********* PLOT_FT["gffirst":"pro_"]="PLOT_FT[gffirst,":",pro_]"\n");
            };
            FT_ary[gffirst]++;
            PLOT_FT[gffirst,":",second]=nwfeat[2];
            # PrintRPT(sprintf(MATCH_F,gffirst,(gffirst":"second),nwfeat[2]));
          }; # if !go_on
        # if varname exist
        } else PrintWRN(sprintf("*** VAR NAME NOT DEFINED on FEATURE SECTION *** "MATCH_F,first,second,nwfeat[2]));
      # if type="F"
      } else {
        if (ft_type=="G") { # G
          gffirst=first;
          if (second in GR_PROP) {
            for (feat in GP_ary) {
              go_on=chkGlobal(feat,gffirst,exp_reg,neg_ptrn);
              if (go_on) {
                PLOT_FT[feat,":",second]=nwfeat[2];
                PrintRPT(" +++ "ft_type" +++ Match found: "feat" "eq_" "gffirst" +++ <"nwfeat[2]">\n");
              }; # if go_on
              # else PrintRPT(" +++ "go_on" +++ No Match found: "feat" "df_" "gffirst" \n");
            }; # for
            if (!exp_reg && !(gffirst in GP_ary)) {
              for (pro_ in GP_PROP) {
                PLOT_FT[gffirst,":",pro_]=GP_PROP[pro_];
                # PrintRPT("********* PLOT_FT["gffirst":"pro_"]="PLOT_FT[gffirst,":",pro_]"\n");
              }; # for
              GP_ary[gffirst]++;
              PLOT_FT[gffirst,":",second]=nwfeat[2];
              # PrintRPT(sprintf(MATCH_F,gffirst,(gffirst":"second),nwfeat[2]));
            }; # if !go_on
          # if varname exist
          } else PrintWRN(sprintf("*** VAR NAME NOT DEFINED on GROUP SECTION *** "MATCH_F,first,second,nwfeat[2]));
        # if type="G"
        } else {
          if (ft_type=="S") { # S
            gffirst=first;
            if (second in SO_PROP) {
              for (feat in sources) {
                go_on=chkGlobal(feat,gffirst,exp_reg,neg_ptrn);
                if (go_on) {
                  PLOT_FT[feat,":",second]=nwfeat[2];
                  PrintRPT(" +++ "ft_type" +++ Match found: "feat" "eq_" "gffirst" +++ <"nwfeat[2]">\n");
                }; # if go_on
                # else PrintRPT(" +++ "go_on" +++ No Match found: "feat" "df_" "gffirst" \n");
              }; # for
              if (!exp_reg && !(gffirst in sources)) {
                for (pro_ in SO_PROP) {
                  PLOT_FT[gffirst,":",pro_]=SO_PROP[pro_];
                # PrintRPT("********* PLOT_FT["gffirst":"pro_"]="PLOT_FT[gffirst,":",pro_]"\n");
                };
                sources[gffirst]++;
                PLOT_FT[gffirst,":",second]=nwfeat[2];
                # PrintRPT(sprintf(MATCH_F,gffirst,(gffirst":"second),nwfeat[2]));
              }; # if !go_on
            # if varname exist
            } else PrintWRN(sprintf("*** VAR NAME NOT DEFINED on SOURCE SECTION *** "MATCH_F,first,second,nwfeat[2]));
          # if type="S"
          } else { # L
            if (ft_type=="L") {
              if (first in Default) {
                PLOT_LY[first]=nwfeat[2];
                PrintRPT(sprintf(" +++ %s +++ Match found: %s & %s : <%s>\n",ft_type,first,first,nwfeat[2]));
            # PrintRPT(sprintf(MATCH_T,ft_type,first,first,first,first,nwfeat[2]));
              } else PrintWRN(sprintf("*** VAR NAME NOT DEFINED on LAYOUT SECTION *** "MATCH_F,first,first,nwfeat[2]));
            }; # if type="L"
          }; # else ! "S"
        }; # else ! "G"
      }; # else ! "F"
    # if not empty or comment line
    } else {
      if ( $0~/^(\# )[LFGS]( \#)/ ) {
      # PrintRPT("*B*******"$0"\n");
        type_sel=1;
        split($0,cfo," ");
        ft_type=cfo[2];
      # PrintRPT("\n>>> "ft_type" <<< "$0"\n")
      } else {
        if ( $0~/^[^\#]/ && $0!~/^( )*$/ && !type_sel )
          PrintWRN("*** BLOCK TYPE NOT DEFINED *** <"$0">\n");
        # else
        #   PrintRPT("\n************\n* NOT READ * "$0"\n************\n");
      };
    }; # else change ft_type
  }; # while getline
  close(file);
  PrintWRN(sprintf("*\n* ........................................................ DONE\n*\n%s\n",BigLINE));
} # End of RCFile
#
########################################
######## Secondary Functions ###########
#
function PrintRPT(STRNG) { if (Var["print_report"]) printf STRNG | "cat 1>&2"; }
function PrintWRN(STRNG) { if (Var["quiet_mode"]) printf STRNG | "cat 1>&2"; }
#
## function lcase(string,    chr) { for (chr in CM) gsub(chr,CM[chr],string); return string; }
function OnOff(v) { if (tolower(v)~/^1$|^on$|^y(es)?$|^t(rue)?$/) return 1; else return 0; }
function TxtBool(n) { if (n) return "true"; else return "false"; }
#
function min(a,b) { if (a!~REscore) a=1; if (b!~REscore) b=1; if(a<=b) return a; else return b; }
function max(a,b) { if (a!~REscore) a=1; if (b!~REscore) b=1; if(a>=b) return a; else return b; }
function ChkLimits(o,O,e,E) { if (e<=O || o>=E) return 0; else return 1; } # start_,BORI,end_,BEND
function ChkLimitsXPND(o,xo,O,e,xe,E) { if (e<=O || o>=E) return 0; else return 1; } # start_,BORI,end_,BEND
#
function DoUnFoldMixed(SC) {
  if (!OnOff(PLOT_FT[SC,":","unfold_grouped_ungrouped"])&&((OnOff(PLOT_FT[SC,":","unfold_grouped_line"]) || OnOff(PLOT_FT[SC,":","unfold_ungrouped_line"]))))
    return 1;
  else return 0; } # DoUnFoldMixed
#
function ChkColor(ncolor) {
  # { PrintRPT(sprintf(" +++ Checking COLOR_NAMES: %s :: %s\n",ncolor,TxtBool(tolower(ncolor)~Valid_Colors))); return 1; }
  if (tolower(ncolor)~Valid_Colors) return 1;
  else return 0;
} # also when ncolor == ^BG$|(##DEFAULT##)
#
function checklbl(chain) {
  if (chain=="") return "";
  else {
    gsub(/[\\]/,"\\134",chain); gsub(/[\(]/,"\\050",chain); gsub(/[\)]/,"\\051",chain);
    return chain;
  };
} # checklbl
#
function chktmk(tk,    t) {
  t=tolower(tk);
  if (t~/both|top|bottom|none/) return t;
  else return "both";
}
#
function ChkCharIF(chain) { # Avoiding problems with config file variable names for elements.
  if (chain=="") return "";
  else { gsub(/[%]/,"%%",chain); return chain; };
} # ChkCharIF
#
function ChkCharRG(chain) { # Avoiding problems with config file variable names for elements.
  if (chain=="") return "";
  else { # gsub(/[ \t]/,"",chain);
    gsub(/[\\]/,"\\\\",chain); gsub(/[\(]/,"\\(",chain); gsub(/[\)]/,"\\)",chain);
    gsub(/[\[]/,"\\[",chain);  gsub(/[\]]/,"\\]",chain); gsub(/[\|]/,"\\|",chain);
    gsub(/[\{]/,"\\{",chain);  gsub(/[\}]/,"\\}",chain); gsub(/[\/]/,"\\/",chain);
    gsub(/[\^]/,"\\^",chain);  gsub(/[\$]/,"\\$",chain); gsub(/[\.]/,"\\.",chain);
    gsub(/[\?]/,"\\?",chain);  gsub(/[\+]/,"\\+",chain); gsub(/[\*]/,"\\*",chain);
    return chain;
  };
} # ChkCharRG
#
function chkpo(v) { if (tolower(v)=="portrait") return "false"; else return "true" }
function cktxpo(v) { if (tolower(v)=="portrait") return "Portrait"; else return "Landscape" }
function chkps(v) {
  if (v~/^(a|b)([0-9]|10)$|^10x14$|^(executive|folio|(le)(tter|gal|dger)|quarto|statement|tabloid|userdefined)$/)
    return 1;
  else return 0;
} # chkps
#
function chkun(st,    t,p) {
  t=tolower(st);
  if (gsub(/cm(s)?/,"",t)>0) {
    p=t" cm"; return p;
  } else {
    if (gsub(/in(ch)?(s)?/,"",t)>0) {
      p=t" in"; return p;
    } else {
      if (gsub(/pt(s)?/,"",t)>0) return t;
      else return "1 cm";
    };
  };
} # chkun
#
function calcpt(st,    t,p) { # return points
  t=tolower(st);
  if (gsub(/cm(s)?/,"",t)>0) {
    p=t*28.35; return p;
  } else {
    if (gsub(/in(ch)?(s)?/,"",t)>0) {
      p=t*72; return p;
    } else {
      if (gsub(/pt(s)?/,"",t)>0) return t;
      else return 0;
    };
  };
} # calcpt
#
function Nuc_round(nm,flg,    sign,nmp,i,mlt,smm,t) { # flg=0 then floor; flg=1 then ceiling.
  sign=nm<0?-1:1;
  if (sign==-1) { nm=-nm; flg=!(flg) }
  nmp=nm; for (i=1;nmp>10;i++) { nmp=nmp/10 };
  if (nm>=1000) mlt=2; else mlt=1;
  if (flg) {
    if (nm>0) {
      if (nm%10^(i-mlt)==0) smm=0; else smm=1;
      t=nm>=100?sign*((int(nmp*10^(mlt-1))+smm)*10^(i-mlt)):sign*100;
    } else t=0;
  } else {
    if (nm>0) t=nm>=100?sign*((int(nmp*10^(mlt-1)))*10^(i-mlt)):0; else t=0;
  };
  return t;
} # End of Nuc_round
#
function Nuc_Scale(st,    ts) {
  ts=tolower(st);
  if (ts~/^m(ega)?(b(ases)?)?/) return 3;
  else if (ts~/^k(ilo)?(b(ases)?)?/) return 2;
  else return 1; # (ts~/^b(ases)?|default/);
}
#
function showelemGS(sq,s,p,g,q,  string) {
  string=" : ";
  string=string" "element[sq,s,p,g,q,feature]" ";
  string=string" "element[sq,s,p,g,q,start]" ";
  string=string" "element[sq,s,p,g,q,end]" ";
  string=string" "element[sq,s,p,g,q,frame]" ";
  string=string" "element[sq,s,p,g,q,group];
  return string;
} # End of showelemS
#
function Plot_Lbl(gff_feat,    sq,sc,s,lbl,vn) {
  vn=PLOT_FT[gff_feat,":","label"];
  if (vn=="++default++" || vn=="++none++") {
    lbl=gff_feat;
    if (gff_feat in GP_ary) lbl=gp[sq,sc,s,gp_cnt[gff_feat],gplabel];
  } else lbl=vn;
  return checklbl(lbl);
} # Plot_Lbl
#
function SRC_LBL(sl,sq,sc,s,flg    ,lbl) {
  if (sl=="++default++" || sl=="++none++") {  # is not wrong, when sorting by sequence, source label is source else seqname
    if (OnOff(Default["sort_tracks_by_sequence"])) lbl=sc; else lbl=sq;
  } else {
    if (sl=="++strand++") {
      if (s=="+") lbl="FWD";
      else
        if (s=="-") lbl="REV";
        else lbl=" ";
    } else {
       if (sl=="++sequence++") lbl=sq;
       else
         if (sl=="++source++") lbl=sc;
         else
           if (sl=="++both++" || sl=="++info++") {
             if (OnOff(Default["sort_tracks_by_sequence"])) lbl=sq" ("sc")";
             else lbl=sc" ("sq")";
             if (sl=="++info++") lbl=lbl" ["flg""s"]";
           } else lbl=sl;
    };
  };
  return checklbl(lbl);
}
#
function Source_Lbl(sq,sc,s,flg,    lftlbl,rgtlbl,tlb) {
  lftlbl=SRC_LBL(PLOT_FT[sc,":","left_label"],sq,sc,s,flg);
  rgtlbl=SRC_LBL(PLOT_FT[sc,":","right_label"],sq,sc,s,flg);
  tlb="("lftlbl") ("rgtlbl")";
  return tlb;
} # Plot_Lbl
#
function Set_Color(sv,clst,fc,fv    ,clrmode,color1,color2,color3,clm,k,tmp) {
  clrmode=0; color2=""; color3=""; # "none" or not defined
  #PrintRPT(sprintf("*** FEATURE COLORS ::%s:: FILLSHAPE MODE ::%s::\n",clst,sv));
  if (clst=="default" || clst=="") {
    clm[1]="fgcolor"; k=1;
  } else {
    k=split(clst,clm,/\.\./);
    if (!ChkColor(clm[1])) clm[1]="bgcolor";
  };
  color1=clm[1];
  if (sv=="none") { clrmode=0; color1=""; }
  else if (sv=="bgcolor") { clrmode=1; color1="bgcolor"; }
  else if (sv=="fgcolor") { clrmode=1; color1="fgcolor"; }
  else if (sv=="default" && !fv) {
    if (fc) clrmode=5; # if frame is present in feature default shows frame-remainder fill shape.
    else clrmode=1; # else default fill-mode.
  } else if (sv=="default" && fv) {
      clrmode=4;
    } else if (sv=="1_color") {
        clrmode=1;
      } else if (sv=="2_color") {
          clrmode=2;
          if (k>1 && ChkColor(clm[2])) color2=clm[2];
          else color2="fgcolor";
        } else if (sv=="3_color" && fv ) {
            clrmode=3;
            if (color1=="bgcolor") color3="fgcolor";
            else if (color1=="fgcolor") color3="bgcolor";
            if (k>1 && ChkColor(clm[2])) color2=clm[2];
            else if (color1=="bgcolor" || color1=="fgcolor") color2="grey";
                 else color2="bgcolor";
            if (k>2 && ChkColor(clm[3])) color3=clm[3];
          } else if (sv=="rainbow") { clrmode=4; }
              else if (sv=="frame-remainder") { clrmode=5; };
  if (color1!="") color1=color1" ";
  if (color2!="") color2=color2" ";
  if (color3!="") color3=color3" ";
  tmp=color1""color2""color3""clrmode;
  return tmp;
} # Set_Color
#
function Set_feat_Clr(gff_feat,gp,sc,is_vector,fcf,    vn,stcl,a1,a2,a3) { # remaining to add vector definition colors.
  a1=PLOT_FT[gff_feat,":","feature_color"];
  a2=PLOT_FT[gp,":","feature_color"];
  a3=PLOT_FT[sc,":","feature_color"];
  if (a2!~/^(default|[ \t]*)$/) a1=a2;
  if (a3!~/^(default|[ \t]*)$/) a1=a3;
  if (ChkColor(a1)) stcl=a1;
  else stcl="fgcolor";
  if (is_vector) vn=PLOT_FT[gff_feat,":","fill_vector_mode"];
  else vn=PLOT_FT[gff_feat,":","fill_shape_mode"];
  return Set_Color(tolower(vn),tolower(stcl),fcf,is_vector);
} # Set_feat_Clr
#
function Set_feat_Shape(gff_feat,grp,src    ,shp,tmp,vn,cl,a1,a2,a3) {
  a1=PLOT_FT[gff_feat,":","feature_stroke_color"];
  a2=PLOT_FT[grp,":","feature_stroke_color"];
  a3=PLOT_FT[src,":","feature_stroke_color"];
  if (a2!~/^(default|[ \t]*)$/) a1=a2;
  if (a3!~/^(default|[ \t]*)$/) a1=a3;
  if (ChkColor(a1)) cl=a1;
  else cl="fgcolor";
  vn=PLOT_FT[gff_feat,":","shape"];
  if (vn in shpnm) shp=shpnm[vn];
  else shp=shpnm["none"];  # (vn==" vector, spike, block ")
  tmp=tolower(cl)" "shp; return tmp;
} # Set_feat_Shape
#
function Set_group_Clr(grp,src,    vn,stcl,a1,a2) {
  a1=PLOT_FT[grp,":","group_color"];
  a2=PLOT_FT[src,":","group_color"];
  if (a2!~/^(default|[ \t]*)$/) a1=a2;
  if (ChkColor(a1)) stcl=a1;
  else stcl="fgcolor";
  vn=PLOT_FT[grp,":","fill_shape_mode"];
  if (vn~/default/) vn="1_color";
  return Set_Color(tolower(vn),tolower(stcl),0,0);
} # Set_group_Clr
#
function Set_group_Shape(grp,src,    shp,ln,tmp,vn,clg,a1,a2) {
  a1=PLOT_FT[grp,":","group_stroke_color"];
  a2=PLOT_FT[src,":","group_stroke_color"];
  if (a2!~/^(default|[ \t]*)$/) a1=a2;
  if (ChkColor(a1)) clg=a1;
  else clg="fgcolor";
  vn=PLOT_FT[grp,":","group_shape"];
  if (vn in shpnm) shp=shpnm[vn];
  else shp=shpnm["none"];
  tmp=tolower(clg)" "shp; return tmp;
} # Set_group_Shape
#
function Set_Line(nm,ext,    vn,cl,ln,fl,c,tmp) {
  if (ext=="gp_") {
    cl=PLOT_FT[nm,":","group_line_color"];
    vn=PLOT_FT[nm,":","group_line"];
    fl=gp[sq,sc,s,gp_cnt[nm],is_grouped];
    if ((vn in lnnm) && fl) ln=lnnm[vn];
    else ln=lnnm["none"];
  } else {
    cl=PLOT_FT[nm,":","source_line_color"];
    vn=PLOT_FT[nm,":","source_line"];
    if (vn~/none|default|(long_|short_)?dashed|(long_)?dotted|(dotted_)?line/) ln=lnnm[vn];
    else ln=lnnm["none"];
  };
  if (ChkColor(cl)) c=cl;
  else {
    if (cl=="default" || cl=="fgcolor") c="fgcolor";
    else c="bgcolor";
  };
  tmp=tolower(c)" "ext""ln; return tmp;
} # Set_Line
#
function ChkVT(tt) {
  if (tt in shpal) return tt;
  else return "default";
} # ChkVT
#
function VertPos(lv,Vsc,Vgp,Vfg,   ps1,ps2,ps3) {
  ps1="default"; ps2="default"; ps3="default";
  if (lv>=1) {
    ps1=ChkVT(tolower(PLOT_FT[Vsc,":","vert_align"]));
    #PrintRPT(sprintf("*******>>> Vertical ALIGN  SC(%s) GP(%s) FT(%s)\n",ps1,ps2,ps3))
  }
  if (lv>=2) {
    ps2=ChkVT(tolower(PLOT_FT[Vgp,":","vert_align"]));
    if (ps2~/default|center|mirror/ && ps1~/default/) ps1=ps2;
    #PrintRPT(sprintf("*******>>> Vertical ALIGN  SC(%s) GP(%s) FT(%s)\n",ps1,ps2,ps3))
  }
  if (lv>=3) {
    ps3=ChkVT(tolower(PLOT_FT[Vfg,":","vert_align"]));
    if (ps3~/default|center|mirror/ && ps2~/default/ && ps1~/default/) ps1=ps3;
    #PrintRPT(sprintf("*******>>> Vertical ALIGN  SC(%s) GP(%s) FT(%s)\n",ps1,ps2,ps3))
  }
    #PrintRPT(sprintf("*******>>> Vertical ALIGN  SC(%s) GP(%s) FT(%s) ---> %s\n",ps1,ps2,ps3,shpal[ps1]))
  return shpal[ps1];
} # VertPos
#
function ScoreLimits(    no_score,tt,scmt) {
  if (PLOT_FT[sc,":","range"]=="none") no_score=1;
  else {
    no_score=0;
    if (PLOT_FT[sc,":","range"]=="default") {
      lower_sc=sc_score["MIN",sc];
      upper_sc=sc_score["MAX",sc];
    } else {
      split(PLOT_FT[sc,":","range"],scmt,/\.\./);
      if (scmt[1]=="*") scmt[1]=sc_score["MIN",sc];
      if (scmt[2]=="*") scmt[2]=sc_score["MAX",sc];
      if (scmt[1]>scmt[2]) { tt=scmt[1]; scmt[1]=scmt[2]; scmt[2]=tt; };
      lower_sc=scmt[1];
      upper_sc=scmt[2];
    };
  };
  return no_score;
} # ScoreLimits
#
function GetScore(sco,lwr,upr,   tmp) {
  if (sco<lwr) sco=lwr;
  else if (sco>upr) { sco=upr; };
  a=upr-lwr;
  if (a<1e-15) a=IS_VECT?MINV_SCO:MINSCORE;
  if (sco!~/^\.$/) {
    if (IS_VECT) tmp=(((MAXV_SCO-MINV_SCO)/a)*(sco-lwr))+MINV_SCO;
    else tmp=(((MAXSCORE-MINSCORE)/a)*(sco-lwr))+MINSCORE;
    return tmp;
  } else return 1;
} # GetScore
#
#############################################
######## PostScript Code DEFINITION #########
#
function PSheader() {
  PrintWRN("*  Writting PostScript Header.\n");
  # Printing PostScript Header...
  printf "%%!PS-Adobe-3.0\n";
  printf "%%%%Title: %s\n", title;
  printf "%%%%Creator: %s\n", Var["PROGRAM"];
  printf "%%%%Version: %s\n", Var["VERSION"];
  printf "%%%%CreationDate: %s\n", date" "time;
  printf "%%%%For: %s\n", usr;
  printf "%%%%Pages: %s\n", "(atend)";
  printf "%%%%Orientation: Portrait\n";
  printf "%%%%BoundingBox: 0 0 %s %s\n", PsizeX[bbpgsz], PsizeY[bbpgsz];
  printf "%%%%EndComments\n%%\n";
  printf "%%    Author : %s\n", Var["AUTHOR"];
  printf "%%    e-mail :        %s\n%%\n", Var["EMAIL"];
  printf "%% ------------------------------------------------------------------------\n";
  printf "%%                     %s\n", Var["PSPROGRAM"];
  printf "%% ------------------------------------------------------------------------\n";
  # Writing PostScript Header...
  system("cat "Var["PS_Header_FN"]);
  close("cat "Var["PS_Header_FN"]);
  # Generating Page-sizes table...
  printf "%%  Paper Sizes  (in points)\n";
  printf "/pagedict %s dict D pagedict begin %% %s+2 sizes defined\n", NumPGSZ, NumPGSZ-2;
  for (pasize in PsizeX)
    printf "/pg%-12s { %4s %4s } D\n", pasize, PsizeX[pasize], PsizeY[pasize] | "sort" ;
  close("sort");
  # printf "/pg%-12s { %4s %4s } D\n", bbpgsz, bbx, bby;
  printf "end %% pagedict\n%%%%EndProcSet: Constants 1.0 0\n%%\n%%%%BeginProcSet: Setting_Vars 1.0 0\n";
} # PSheader
#
function defPSvars(    flgst,subtitle,shbx,fixed,dfgc,dbgc) {
  PrintWRN("*  Writting PostScript Variables.\n");
  printf "%% BG & FG colors\n";
  dbgc=tolower(Default["background_color"]); if (!ChkColor(dbgc)) dbgc="bg";
  if (dbgc~/(bg|background)(color)?/) dbgc=Var["BG_COLOR"];
  printf "/BGcolor { colordict begin %s end } D /bgcolor { BGcolor } B\n", dbgc;
  dfgc=tolower(Default["foreground_color"]); if (!ChkColor(dfgc)) dfgc="fg";
  if (dfgc~/(fg|foreground)(color)?/) dfgc=Var["FG_COLOR"];
  printf "/FGcolor { colordict begin %s end } D /fgcolor { FGcolor } B\n", dfgc;
  printf "/frmN { colordict begin %s end } D\n", Default["frame_unknown_color"];
  printf "/frm0 { colordict begin %s end } D\n", Default["frame0_color"];
  printf "/frm1 { colordict begin %s end } D\n", Default["frame1_color"];
  printf "/frm2 { colordict begin %s end } D\n", Default["frame2_color"];
  printf "/Blblcol { colordict begin %s end } D\n", Default["block_label_fill_color"];
  printf "%% page orientation flag\n";
  printf "/flglscape %s D\n", chkpo(Default["page_orientation"]);
  printf "%% page size in points used for plot % pgA4 == 595  842\n";
  printf "/pglimflg %s D\n",TxtBool(OnOff(Default["show_page_limits"]));
  printf "/Dpage { pagedict begin pg%s flglscape { exch } if end } B\n", bbpgsz;
  printf "%% margins (1 cm) (Up Down Left Right - margins are XY independent)\n";
  printf "/UpM %s D\n", chkun(Default["margin_upper"]);
  printf "/DnM %s D\n", chkun(Default["margin_lower"]);
  printf "/LtM %s D\n", chkun(Default["margin_left"]);
  printf "/RtM %s D\n%%\n", chkun(Default["margin_right"]);
  printf "/TkMrkW %s D %% Defining tickmark-width.\n/TkMrkHW TkMrkW 2 div D\n", chkun(Default["default_scale_width"]);
  printf "/TkMspc %s D\n", Default["default_scale_spacing_width"];
  printf "/BlckSp %s D %% Defining blocks-spacing\n%%\n", chkun(Default["default_block_spacing_width"]);
  printf "/SeqLen %s D\n", PDIF;
  printf "/XNucOffSet %s D\n", PORI;
  printf "/NPages %s D\n", P;
  printf "/NBlck %s D\n", B;
  printf "/MaxNuclPage %s D\n", NOFFSET;
  printf "/MSLen %s D\n", Default["minimum_single_length"];
  printf "/MINshwLBLlen %s D %% minimum gene length to show gene label on expands\n", Default["show_label_min_gene_length"];
  printf "/CLPgplbl %s D\n",TxtBool(OnOff(Default["hide_label_larger_gene_length"]));
  if (Default["block_style"]=="boxed") shbx="true";
  else shbx="false";
  printf "/FlgBkBx %s D\n", shbx;
  printf "/FlgOSU %s D\n",TxtBool(OnOff(FlgSwOSUp));
  printf "/FlgOSD %s D\n",TxtBool(OnOff(FlgSwOSDn));
  printf "/FlgISU %s D\n",TxtBool(OnOff(FlgSwISUp));
  printf "/FlgISD %s D\n",TxtBool(OnOff(FlgSwISDn));
  my_nuc=Nuc_Scale(Default["nucleotide_scale"]);
  my_mjtk=Default["major_tickmarks_nucleotides"];
##
  my_exp=0;
  if ((my_nuc == 3) && (my_mjtk % 1000000 != 0)) my_exp=1
  else if ((my_nuc == 2) && (my_mjtk % 1000 != 0)) my_exp=1;
##
  printf "/TS %s D\n", my_nuc;
  printf "/TrS %s D\n", my_exp;
  printf "/FlgGrd %s D\n",TxtBool(OnOff(Default["show_grid"]));
  printf "/MaxTick %s D\n", my_mjtk;
  printf "/MinTick %s D\n%%\n", Default["minor_tickmarks_nucleotides"];
  printf "/tracksize %s D\n", chkun(Default["default_track_width"]);
  printf "/spcrsize  %s D\n", chkun(Default["default_track_spacing_width"]);
  printf "/LnTot  %s D\n", BSize;    # size in points (size is relative here)
  printf "/LnFwd %s D\n", StrSizeFwd; # if they are 0 then not showed
  printf "/LnRvs %s D\n", StrSizeRvs;
  printf "/LnBth %s D\n", NStSize;
  printf "/blklblsc %s D\n", Default["block_label_scale"];
  printf "/vectoffset 10 D\n%%\n";
  printf "/XLftLbl %s D\n", chkun(Default["left_source_label_width"]);
  printf "/FLftLbl %s D\n", TxtBool(OnOff(Default["show_left_source_label"])); #
  printf "/XRgtLbl %s D\n", chkun(Default["right_source_label_width"]);
  printf "/FRgtLbl %s D\n%%\n", TxtBool(OnOff(Default["show_right_source_label"])); #
  printf "/SLA %s D\n%%\n", TxtBool(OnOff(Default["source_label_align"]));
  printf "/XOriTitl 0 cm D\n";
  printf "/YOriTitl 0 cm D\n";
  printf "/YSTitl %s D\n", chkun(HDRheight);
  printf "/Titlscl %s D\n", Default["header_scale"];
  printf "/flgcrd %s D %% credits flag\n", TxtBool(OnOff(Var["Show_Credits"]));
  printf "/FlgTitl %s D\n", shtt;
  printf "/headerdict 25 dict D headerdict begin\n";
  printf " /ShwTBx %s D\n", shbt;
  printf " /ShwTt %s D\n", flgt;
  printf " /Title (%s) D\n", checklbl(title);
  if (Default["subtitle"]=="none" || Default["subtitle"]=="default") { flgst="false"; subtitle="" }
  else { flgst="true"; subtitle=Default["subtitle"] }
  printf " /ShwST %s D\n", flgst;
  printf " /SubTitle (%s) D\n", checklbl(subtitle);
  printf " /ShwDate %s D\n", TxtBool(OnOff(Default["show_date"]));
  printf " /Sdate (%s) D\n", checklbl(date);
  printf " /ShwTime %s D\n", TxtBool(OnOff(Default["show_time"]));
  printf " /Stime (%s) D\n", checklbl(time);
  printf " /Shwp_num %s D\n", TxtBool(OnOff(Default["show_page_numbers"]));
  printf "end %% headerdict \n";
  # printf "/gplbSC %s D\n", Default["group_label_scale"];
  printf "/pslbSC %s D\n", Default["position_label_scale"];
  printf "/sclbSC 1 D\n%%\n";
  #
  if (CHOffSet[0]>0) lstCHos = CHOffSet[1]
  else lstCHos = 0;
  printf "globaldict /CHcurrent %d put\n", lstCHos;
  if (CHOffSet[0]>1) lstCHos = CHOffSet[2]
  else lstCHos = P * B * NOFFSET;
  printf "globaldict /CHnext %d put\n", lstCHos; # 12000000
  printf "/CHoffsets [ "; # 26000000 36000000 56000000 501000000
  for (z=3;z<=CHOffSet[0];z++) { printf "%d ", CHOffSet[z]; };
  # printf "%d ] D\n%%\n", lstCHos ;
  if (CHOffSet[0]==2) {
    if (Default["major_tickmarks_nucleotides"]==-1) lstCHos = (P * B * NOFFSET) + 1000
    else lstCHos = (P * B * NOFFSET) + Default["major_tickmarks_nucleotides"];
    printf "%d ", lstCHos;
    };
  printf " ] D\n/CHofflen CHoffsets length 1 sub D%%\n";
  #
  # PostScript Main Procs.
  PrintWRN("*  Writting PostScript Prolog.\n");
  system("cat "Var["PS_Main_FN"]);
  close("cat "Var["PS_Main_FN"]);
} # defPSvars
#
function startPSpage(num,tot,vpg,vtot) {
  # PrintWRN("*  Opening PostScript Page.\n");
  if (B>0) printf "%%%%Page: %s %s\n",num,num;
  else printf "%%%%Page: %s.%s %s\n",num,vpg,++BPC;
  printf "%%%%BeginPageSetup\n%%\n";
  printf "%% Saving current page settings\n";
  printf "/pgsave save D\n";
  printf "%% Setting BGcolor for sheet \n";
  printf "Dpage flglscape { exch } if 0 0 bbox S bgcolor scmyk fill R\npglimflg { S shortdashed K R } if clip newpath\n";
  printf "%% Only for testing pagelimits\n% S XORI YORI T pglim flglscape { exch } if 0 0 bbox FGcolor scmyk longdashed K R\n";
  printf "%% setting coordinate axes for page orientation\n";
  printf "flglscape\n";
  printf " { XORI YORI T 90 rotate 1 -1 F }                  %% (0,0) - Ori for landscape pages\n";
  printf " { XORI Dpage exch pop YORI sub T 1 -1 F } ifelse  %% (0,0) - Ori for portrait pages\n";
  printf "%% Printing Header\n";
  printf "headerdict begin\n";
  if (B>0) printf " /PageNumber (Page %s of %s) D\n",num,tot;
  else printf " /PageNumber (Page %s.%s of %s.%s) D\n",num,vpg,tot,vtot;
  printf " FlgTitl { Header } if\n";
  printf "end\n";
  printf "%%%%EndPageSetup\n";
  printf "%%\n";
} # startPSpage
#
function endPSpage(p,vp) {
  # PrintWRN("*  Closing PostScript Page.\n");
  printf "%%##%% SHOWPAGE\nflgcrd { headerdict begin s_credits end } if\ngrestoreall\npgsave restore\n";
  printf "%%##%%LEGEND%%##%%\nshowpage\n";
  if (B>0) printf "%%\n%% PageEND: %s %s\n%%\n",p,p;
  else printf "%%\n%% PageEND: %s.%s %s\n%%\n",p,vp,BPC;
} # endPSpage
#
function PSTrailer() {
  PrintWRN(sprintf("*  Closing PostScript File.\n\n%s\n\n",BigLINE));
  printf "%%%%Trailer\n%%\n";
  if (B>0) printf "%%%%Pages: %s\n", P;
  else printf "%%%%Pages: %s\n", BPC;
  #--> this is already defined in the header and some programs complain when finding twice
  # printf "%%%%Orientation: Portrait\n";
  # printf "%%%%BoundingBox: 0 0 %s %s\n", PsizeX[bbpgsz], PsizeY[bbpgsz];
  printf "%%%%EOF\n";
} # PSTrailer
@@@EndPROGRAM@@@
#
# End of MAIN gff2ps gawk-script

######################################################
####            MAIN GFF2PS PROGRAM               ####
# Processing gff files and converting to PostScript. #

    $GAWK -f $GWKPRG $GWKOPT $GFF_INPUT_FILES ;      #

#                                                    #
####     Main GFF2PS GNU awk Program :  DONE      ####
######################################################

#
# Removing all temporal files...
rm -f $GWKPRG $GWKOPT $PSHEAD $PSMAIN 2>/dev/null;

#
# Timing gff2ps...
# TT_end=`date +%T`;
if [ $v34 -eq 1 ];
 then
perl -e '        $r = shift @ARGV;
  $s = $r % 60;  $r = ($r - $s) / 60;
  $m = $r % 60;  $r = ($r - $m) / 60;
  $h = $r % 24;
  ($s,$m,$h) = (&fill_left($s,2,"0"),&fill_left($m,2,"0"),&fill_left($h,2,"0"));
print STDERR <<EOF;
**
********************************************
**  GFF2PS Execution Time:  $h:$m:$s
********************************************
EOF
sub fill_left { ($_[2] x ($_[1] - length($_[0]))).$_[0] }
' $SECONDS;
 fi;

#
##################### EOF #####################
exit 0
