#!/usr/bin/perl

################################################################################
#                                                                              #
# LARGE BINOCULAR TELESCOPE OBSERVATORY                                        #
# --------------------------------------                                       #
#                                                                              #
# LUCIFER SCRIPT SYNTAX CHECKER / REVIEWER                                     #
#                                                                              #
# By Steve Allanson (LBTO)                                                     #
#                                                                              #
#                                                                              #
# DESCRIPTION:                                                                 #
# This script analyzes the acquisition, science, and calibration scripts,      #
# checks for errors, and outputs a summary of what it will do. A DSS image is  #
# displayed in ds9 showing the field, LUCIFER FOV, chosen guide star, and      #
# any jitter or offsets used.                                                  #
#                                                                              #
# ACKNOWLEDGMENTS:                                                             #
# Thanks to Dave Thompson (LBTO) for his ongoing help developing this program. #
# Thanks to Olga Kuhn (LBTO) for providing her LUCI FOV visualization tool.    #
# Thanks to Chris Wilmer (UofA) for help with the LUCI FOV fix at high DEC.    #
# Thanks to Jenny Power (NOAO) for many helpful and useful coding discussions. #
# Thanks to Jaron Kurk and Jochen Heidt for their suggestions and bug reports. #
#                                                                              #
# NOTES:                                                                       #
# - Remember that this is not a planning tool. We have attempted to cover      #
#   the most common (and some uncommon) errors that observers have made in the #
#   past. If you come across a reasonable setup that shows a warning or fail,  #
#   please let us know!                                                        #
# - comments in LUCI scripts MUST be done with #                               #
# - consider spectroscopic calibration as 'CAL'                                #
# - consider imaging calibration as 'IMG'                                      #
#                                                                              #
# TO EXECUTE:                                                                  #
#   perl lucichkX.Y.pl <scriptname>                                            #
#                                                                              #
# VERSION:                                                                     #
$scriptversion = 4.26; # November 27th 2012                                    #
#   4.18: - Added zJspec as an optional filter.                   DONE         #
#         - changed OrderSep to HKspec                            DONE         #
#         - add explicit failure for OrderSep NOTDONE: implied by filter check #
#         - changed minimum exposure and readout times:                        #
#           O2DCR is now 4sec, MER10 is now 12sec                 DONE, DONE   #
#         - change Target/guide coord to properly check decimal secs, DONE     #
#           need to fix 'pointing, dark' ra/dec checks            DONE         #
#         - fixed guide_coord output format                                    #
#         - added in some RA boundary condition checks for offsets             #
#    4.19 - added check for blank named masks, allowed only when not in use    #
#         - if mask specified, position must be specified                      #
#         - fixed FILTER check for improper format + comment non-fail issue    #
#         - added explicit check for no filter arguement fail                  #
#    4.20 - zJspec + 200_H+K standard combo, wavelength 0.87-1.197um,          #
#           standard=1.1                                                       #
#    4.21 - fixed cos(dec) error when using RADEC offsets                      #
#    4.22 - check for EOF if missing last end_setup line   DONE                #
#         - fix overhead times (apr13 email from dave)     DONE                #
#         - sex2deg subs mod for unforeseen non-digit passes                   #
#         - added startup splash screen to point out version# to user          #
#    4.23 - added autodetection of file extensions                             #
#    4.24 - changed screen spacing to compact/consolidate things               #
#    4.25 - added version check to lbto server, if new version available,      #
#           option available to update.                                        #
#         - changed flexurecomp to WARN if imaging script                      #
#         - changed default ds9 image catalog to NOMAD from USNO-A2            #
#    4.26 - changed warning about N3.75 on an ACQ script (post explosion)      #
#         - added fail if lamp time specified                                  #
#         - added reminder message for autodetected acq script (w/spec script) #
#           to check that script before proceeding to associate                #
#         - added message on lucichk header msg stating latest version in use  #
#                                                                              #
# TO DO:                                                                       #
#   - figure out math to calculate GS position relative to patrol field        #
#   - Warn when vignetting may occur                                           #
#   - IMPORTANT: FLAT,DARK - when used in the more complicated ways, I need    #
#                checks performed from the readout section to be applied       #
#                - verify filter combos on these                               #
#  - add NOCHECK flag to prevent version check for debugging                   #
#                                                                              #
################################################################################

####################################################
### Debug variables
$PRTCMD = 0;         # if set, prints out read script commands
#$NOCHECK = 0;

####################################################
### Some globals/packages

use Math::Trig;
use POSIX;
use Term::ANSIColor qw(:constants); $Term::ANSIColor::AUTORESET = 1;

$time = localtime();
$home = $ENV{HOME};
$flagFAIL = 0; $flagWARN = 0; 

@dither = 0; # Dither array and counter for DITHER subroutine and GS plotting
@ditheruse = 0;
@dithertemp = 0;
$idith = 0;  

# some times
$Tsave = 12; # approximate time to save each image
$Toffset = 14; # approximate time for each offset
$Tslew = 120; # very approximate slew time
$Tcoll = 135; # very approximate collimation time
$Texec = 0; $Texpo = 0;

####################################################
### Check script version
### vcheck = -1 => wrong version; 
###           0 => can't resolve newest version, proceed; 
###           1 => latest and greatest

$vcheck=0; $vnewest=0;
print "\nQuerying LBTO server for latest lucichk version:\n\n";
# start curl, timeout if there is an issue
eval{ local $SIG{ALRM} = sub {die "alarm\n"};
      alarm 5;
      `curl -O http://abell.as.arizona.edu/~lbtsci/Instruments/LUCIFER/Scripts/version`;
      alarm 0; };
# kill this process if timeout
if($@){ die unless $@ eq "alarm\n"; $vcheck = 0; print "\nTIMEOUT - Something went wrong.\n"; } # if it died
# compare versions, catch is theres a problem
else { $vnewest = `head -n 1 version`; chomp $vnewest;
       if($vnewest!~m/^\d+\.\d+$/){ $vcheck = 0; print "\nSomething went wrong with version check.\n"; }
       # old version
       elsif($vnewest>$scriptversion){ $vcheck = -1; print "\nNewer version available.\n"; }
       # current version
       else{ $vcheck = 1; print "\nYou are running the latest version.\n"; } }

if(-e "version"){ `rm version`; } # delete file if it exists (only exists if curl completed)
else{ $vcheck = 0; }              # else we don't have it, something went wrong


# Display startup splash
system "clear";   # clear screen

print "********************************************\n";
print "**  LBTO - LUCIFER SCRIPT CHECKER v$scriptversion   **\n";
print "********************************************\n";
if($vcheck==1){
    print "You are running the latest version.\n\n";
}
# new version available?
if($vcheck==-1){
    print RED "NEW VERSION AVAILABLE!!\n";
    while(1){
    print "Would you like to download version $vnewest to this directory? (y/n):\n";
    $vchoice = <STDIN>; chomp $vchoice;
    if($vchoice=~m/n/i || $vchoice=~m/no/i){ print "Please update to the latest version:\nhttp://abell.as.arizona.edu/~lbtsci/Instruments/LUCIFER/Scripts/scriptcheck.html\n\n"; goto newSKIP; }
    elsif($vchoice=~/y/i || $vchoice=~m/yes/i){ last; }
    else{ print "Please try again.\n"; }
    }

    print "Downloading lucichk$vnewest\.pl from LBTO server:\n\n";
    eval{ local $SIG{ALRM} = sub {die "alarm\n"};
	  alarm 5;
	  `curl -O http://abell.as.arizona.edu/~lbtsci/Instruments/LUCIFER/Scripts/lucichk$vnewest\.pl`;
	  alarm 0; };
    
    if($@){ die unless $@ eq "alarm\n"; print "\nTIMEOUT - Something went wrong. Please go to:\nhttp://abell.as.arizona.edu/~lbtsci/Instruments/LUCIFER/Scripts/scriptcheck.html\nto download the newest version.\n\n"; die "\n"; } # if it died
    unless(-e "lucichk$vnewest\.pl"){ die "\nSomething went wrong. Please go to:\nhttp://abell.as.arizona.edu/~lbtsci/Instruments/LUCIFER/Scripts/scriptcheck.html\nto download the newest version.\n\n"; }
    
    die "\nPlease run the latest version of lucichk with your script.\n\n"; 
}
# no info available... something went wrong with check
if($vcheck==0){
    print "Please verify that you are running the latest version:\n";
    print "http://abell.as.arizona.edu/~lbtsci/Instruments/LUCIFER/Scripts/scriptcheck.html\n\n"; }

newSKIP:

####################################################
### Check if specificed file exists

# identify file/type
if(!$ARGV[0])
{ die "You must specify a script to check! Exiting...\n\n"; }
elsif(-e "$ARGV[0]")
  { 
      $filescript = $ARGV[0]; print "Found $filescript... "; 
      open SCR, "<$filescript" or die "cannot open $filescript: $!";

      ### Type of script?
      $autoDETECT=0; $typeDETECT="";
      
      if($filescript=~m/^\S*\.acq$/i){ $autoDETECT=1; $typeDETECT="ACQUISITION"; $flagtype=0; }
      elsif($filescript=~m/^\S*\.img$/i){ $autoDETECT=1; $typeDETECT="IMAGING"; $flagtype=3; }
      elsif($filescript=~m/^\S*\.sci$/i || $filescript=~m/^\S*\.spec$/i){ $autoDETECT=1; $typeDETECT="SPECTROSCOPY"; $flagtype=1; }
      elsif($filescript=~m/^\S*\.cal$/i || $filescript=~m/^\S*\.arc$/i || $filescript=~m/^\S*\.flat$/i)
           { $autoDETECT=1; $typeDETECT="CALIBRATION"; $flagtype=2; }
      else{
	  while(1) {
	      print "\nType of script? ( acq | img | spec | cal ):\n";
#      print "acq\n"; $flagtype=0; ### FOR DEBUG PURPOSES
	      $intype = <STDIN>;
	      chomp $intype;
	      if($intype=~m/^acq$/i)
	      { $flagtype = 0; $typeDETECT = "ACQUSITION"; last; }
	      elsif($intype=~m/^spec$/i)
	      { $flagtype = 1; $typeDETECT = "SPECTROSCOPY"; last; }
	      elsif($intype=~m/^cal$/i)
	      { $flagtype = 2; $typeDETECT = "CALIBRATION"; last; }
	      elsif($intype=~m/^img$/i)
	      { $flagtype = 3; $typeDETECT = "IMAGING"; last; }
	      else{ print "Please try again."; } # system "clear";
	  } }
      # If type detected, extract root name. Used to autodetect acq script for sci script w/o telescope setup
      if($autoDETECT==1){ $filescript=~m/(\S+)\.\S+/; $rootDETECT=$1; }
  }
else{ die "Specified file $ARGV[0] does not exist! Exiting...\n\n"; }

print "Processing $typeDETECT script...\n"; # tell user what type of script

####################################################
### Define Filter Wheels
### filter wheels: 0=both; 1=wheel1; 2=wheel2

@wheelf = 0; @wheelw=0; $nfilters=0;
# FILTER NAME          # FILTER WHEEL
### define common filters
$wheelf[0]="blind";    $wheelw[0]=0;  
$wheelf[1]="clear";    $wheelw[1]=0;
$wheelf[2]="";         $wheelw[2]=0;
### define filter wheel 1
$wheelf[3]="z";        $wheelw[3]=1;
$wheelf[4]="J";        $wheelw[4]=1;
$wheelf[5]="H";        $wheelw[5]=1;
$wheelf[6]="K";        $wheelw[6]=1;
$wheelf[7]="Ks";       $wheelw[7]=1;
$wheelf[8]="HKspec";   $wheelw[8]=1;
$wheelf[9]="zJspec";   $wheelw[9]=1;
### define filter wheel 2
$wheelf[10]="Br_gam";  $wheelw[10]=2;
$wheelf[11]="FeII";    $wheelw[11]=2;
$wheelf[12]="H2";      $wheelw[12]=2;
$wheelf[13]="HeI";     $wheelw[13]=2;
$wheelf[14]="J_high";  $wheelw[14]=2;
$wheelf[15]="J_low";   $wheelw[15]=2;
$wheelf[16]="OH_1060"; $wheelw[16]=2;
$wheelf[17]="OH_1190"; $wheelw[17]=2;
$wheelf[18]="P_beta";  $wheelw[18]=2;
$wheelf[19]="P_gam";   $wheelw[19]=2;
$wheelf[20]="Y1";      $wheelw[20]=2;
$wheelf[21]="Y2";      $wheelw[21]=2;

$nfilters = @wheelf;

####################################################
### define start lines. each subroutine will look 
### for its own end after satisfying the required keywords

@blocks; $nblocks=5;
# checked flag      # name                                       # subroutine name
$blocks[0][1] = 2;  $blocks[0][0] = "START_ARCHIVE_INFORMATION"; $blocks[0][2] = ARCHIVE;
$blocks[1][1] = 0;  $blocks[1][0] = "START_INSTRUMENT_SETUP";    $blocks[1][2] = INSTRUMENT;
$blocks[2][1] = 0;  $blocks[2][0] = "START_TELESCOPE_SETUP";     $blocks[2][2] = TELESCOPE;
$blocks[3][1] = 0;  $blocks[3][0] = "START_READOUT_SETUP";       $blocks[3][2] = READOUT;
$blocks[4][1] = 0;  $blocks[4][0] = "START_OBSERVING_SETUP";     $blocks[4][2] = OBSERVING;
### flags: 0=notchecked; 1=checked; 2=optional; 3=donotuse!.

### define special cases based on type of script.
if($flagtype==0){ $blocks[2][1]=2; } # acq, telescope setup optional. warn if missing
if($flagtype==1){ $blocks[2][1]=3; } # sci, no telescope setup 
if($flagtype==2){ $blocks[2][1]=3; } # cal, no telescope setup 
if($flagtype==3){ $blocks[2][1]=2; } # img, telescope setup optional. warn if missing

### some flags and other iteratives
$flagblock = 0;
$flagin = 0;
$flagmatch = 0;
$n = 0;
$blockcount = 0;

####################################################
### Begin Syntax Check

#system "clear";   # clear screen

print "\n************ BEGIN SYNTAX CHECK ************\n\n";

### Begin read in of script

while($line=<SCR>)
{
    if($line=~m/^\s*\#.*/ || $line=~m/^\s*$/)
      { goto skipit; }                                        # skip commented lines
    
    if($flagblock==0)
      { $flagblock=1; }                                       # first non commented line    
    chomp $line;                                              # remove carriage return
    
    if($line=~m/^[\{,\(].*/)                                  # check for bad brackets
      { print RED "\n"; die "*FAIL* You began this line: $line with a { or (.\n\n"; }
    elsif($line!~m/^\[STA.*/i && $flagblock==1)               # check if its a proper START line
      { print RED "\n"; die "*FAIL* The line in the script: $line was not a START to a section.\n\n"; }
    else                                                      # we are in a block
    {
	$flagin = 1;                                          # in!

	### match $blocks names, check if it has been checked.
	for($n=0; $n<$nblocks; $n=$n+1)
	{
	    if($line=~m/^\[$blocks[$n][0]\]\s*(\#.*|\s*)$/i)    # check against known block names(\#.*|\s*)
	      { 
		  if($blocks[$n][1]==1)                       # die if already checked
		  { print RED "\n"; die "*FAIL* The section $line has already been defined!\n\n"; }
		  elsif($blocks[$n][1]==3)                    # die if should be ignored
		    { print RED "\n*FAIL*"; print " The section $line should NOT be defined!\n";
		      print RED "******"; print " (comment out, or delete)\n\n"; $flagFAIL=$flagFAIL+1;}
		  $flagmatch = 1;                             # match!
		  \&{$blocks[$n][2]}(\@wheelf, \@wheelw);     # call specific subroutine and feed it filterwheel info
		  $blocks[$n][1] = 1;                         # flag section as 'checked'
		  $blockcount = $blockcount + 1;              # count it
		  last;                                       # jump out
	      }
	}   
	if($n==$nblocks && $flagmatch==0)                     # if we went through all of them, die
	{ print RED "\n"; die "*FAIL* The line $line did not match a valid block.\n\n"; }	
	else
	{ $flagmatch=0; }                                     # we made it out!            
    }
    
    $flagin = 0;                                             # out of a block now
    $flagmatch = 0;                                          # out of a block
    $flagblock = 0;                                          # can now consider commented/whitespace 
                                                             # lines only until the next blockcheck
  skipit:                                                    # label to skip commented/whitespace lines
    
}

### Check if all sections have been checked
for($i=0;$i<$blockcount;$i=$i+1)
{
    if($blocks[$i][1]==3){ print "MISSING $blocks[$i][2] BLOCK as expected.\n"; }    
    elsif($blocks[$i][1]==0){ print YELLOW "\n   *WARN*"; print " You did not define section $blocks[$i][2]\n"; }
}

### End syntax check report

print                   "\n********************************************\n";
if($flagFAIL==0){ print   "* YOUR SCRIPT HAS PASSED THE SYNTAX CHECK  *\n"; }
else{             print   "* YOUR SCRIPT HAS FAILED THE SYNTAX CHECK  *\n"; 
                  print   "************ WITH $flagFAIL FAILURE(S) *************\n"; }
print "\n";
#print                     "************ END SYNTAX CHECK **************\n\n";
if($flagFAIL==0){ print "Review the results, then hit return to continue.\n";
    #print "Please review the results of the syntax check,\nthen hit return to move on to the script review.\n";
		  <STDIN>; } #system "clear"; }
else{ die "Please correct these errors and rerun this check\nto move on to the script review and guide star check.\n\n"; }


####################################################
### Begin sanity check

print   "*********** BEGIN SCRIPT REVIEW ************\n\n";
$flagWARN = 0; $flagFAIL = 0;  # reset globals here to start new counts
# flagtype: 0=acq; 1=spec; 2=cal; 3=img

### ARCHIVE BLOCK
ARCHIVE_REVIEW();
### INSTRUMENT SETUP BLOCK
INSTRUMENT_REVIEW();
### TELESCOPE SETUP BLOCK
TELESCOPE_REVIEW();
### READOUT SETUP BLOCK
READOUT_REVIEW();
### OBSERVING BLOCK
OBSERVING_REVIEW();

### END
if($flagFAIL>0 || $flagWARN>0){ print "\n"; }
                   print   "********************************************\n";
if($flagFAIL==0){  print     "*    YOUR SCRIPT HAS PASSED THE REVIEW     *\n"; }
else{              print     "*    YOUR SCRIPT HAS FAILED THE REVIEW     *\n"; 
                   print     "************ WITH $flagFAIL FAILURE(S) *************\n"; }
if($flagWARN>0){   print     "************ WITH $flagWARN WARNING(S) *************\n"; }

### Print summary
$TexecM = sprintf("%.0f", $Texec/60); #Texec in mins.
$PctOS = sprintf("%.0f", 100 * $Texpo / ($Texec + $Tslew + $Tcoll + $flagFLUSH_DETECTOR*11*60)); # very approximate percentage of time on sky.

if($flagNOCALC==0){ print "\nApproximate total execution time: $Texec sec.\nApproximate percentage of time on sky: $PctOS\%.\n\n"; }
else{               print "\nUnable to calculate total execution time due to unsufficient information.\n\n"; }

#                    print   "************ END SCRIPT REVIEW *************\n\n"; 
#print "\n";


####################################################
### GUIDESTAR / DITHER POSITION VISUAL CHECK

### notes for myself: GS selection will only occur if:
###                   - telescope_setup is defined. If not, and a dither exists, request a setup script.
###                   - telescope_mode is not track, static, or adaptive (for now)
###                   - rot_mode is not parallactic
###                   - target coord, guide coord, and posangle are defined

@dithertemp = @dither;     # transfer dither array to new array for use in printing
@dither=(); $idith = 0;  # clear original for future use.

if($blocks[2][1]==1 && $TELESCOPE_MODE!~m/track/i && $TELESCOPE_MODE!~m/static/i && $TELESCOPE_MODE!~m/adaptive/i && $ROT_MODE!~m/parallactic/i && $flagTARGET_COORD==1 && $flagGUIDE_COORD==1 && $flagPOSANGLE==1){ 
    $gscheck = 1; 
    print "Review the results, then hit return to continue.\n";
    #print "Please review the results of the script review,\nthen hit return to move on to the guide-star and dither-position check.\n";
    <STDIN>; } #system "clear"; }

### If TELESCOPE_SETUP is missing, see if setup script is available to check guidestar.

close SCR;  # need to reuse this label

if($blocks[2][1]!=1 && ($flagACQUISITION!=0 || $flagOFFSET!=0 || $flagJITTER!=0)) #TELESCOPE_SETUP not defined, offsets found
{
    print "Review the results, then hit return to continue.\n";
    #print "Please review the results of the script review,\nthen hit return to move on to the guide-star and dither-position check.\n";
    <STDIN>; #system "clear";

    $flagSETUPTELESCOPE = 0;
    $flagFAIL = 0; # reset fails

    # check if associated .acq file exists (if script type autodetected), otherwise ask
    if($autoDETECT==1 && (-e "$rootDETECT\.acq")){ 
	$setupfile="$rootDETECT\.acq"; print "Found associated ACQUISITION script $setupfile...\n";
	print BOLD "Please ensure this ACQ script has passed through lucichk before proceeding.\n"; print "Hit return to continue, or CTRL+C to abort.\n";
	<STDIN>;
	open SCR, "<$setupfile" or die "cannot open $setupfile: $!"; goto acqSKIP; }
    else{
	print "This script does not have a defined TELESCOPE_SETUP block.\nIf you would like to specify an associated setup script which defines this block\n("; print BOLD "and has already passed through lucichk"; print"), a guide-star and dither-position\ncheck can be performed.\n\nPlease specify the file here, or hit return to quit:\n";	
	while(1){                                        # check if it exists, try again if not.
	    $setupfile = <STDIN>; chomp $setupfile;	
	    if(-e "$setupfile"){  
		print "\nFound $setupfile...\n"; 
		open SCR, "<$setupfile" or die "cannot open $setupfile: $!";
		last; }
	    elsif($setupfile =~ m/^$/){ die "\n"; }     # quit if they just hit enter
	    else{ print "\nSpecified file $setupfile does not exist! Please try again:\n"; } }
    }
  acqSKIP:

    $flagtype = 0;   # reassign script type to acqusition for review purposes.
    while($line = <SCR>){
	if($line =~ m/^\s*\[START_TELESCOPE_SETUP\]\s*[\#]*.*/i){ 
	    $flagSETUPTELESCOPE = 1;
	    TELESCOPE(\@wheelf, \@wheelw);
	    TELESCOPE_REVIEW();
	    last; } }

    if($flagSETUPTELESCOPE==1){  # check for offsets!
	while($line = <SCR>){
	    if($line =~ m/^\s*\[START_OBSERVING_SETUP\]\s*[\#]*.*/i){ 
		OBSERVING(\@wheelf, \@wheelw);
		OBSERVING_REVIEW();
		last; } } }
    
    print "\n";

    if($flagSETUPTELESCOPE==0){ print RED "\n*FAIL*"; print " No TELESCOPE_SETUP block found.\n"; 
				print RED "******"; print " Please run $setupfile through this check/review.\n"; die "\n"; }
    if($flagFAIL>0){ print RED "*FAIL*"; print " Errors were found.\n"; 
		     print RED "******"; print " Please run $setupfile through this check/review.\n"; die "\n"; }
    
    $blocks[2][1]=1; # define TELESCOPE block as checked
    if($blocks[2][1]==1 && $TELESCOPE_MODE!~m/track/i && $TELESCOPE_MODE!~m/static/i && $TELESCOPE_MODE!~m/adaptive/i 
       && $ROT_MODE!~m/parallactic/i && $flagTARGET_COORD==1 && $flagGUIDE_COORD==1 && $flagPOSANGLE==1){ $gscheck = 1; }  #GS check ready
    else{ die "More information / different config required for guidestar/dither position check\n\n"; }
}

### Check Guide Star as required

if($gscheck==1){ 

    #system "clear"; 

    ### Begin Guide Star check
    print "********** BEGIN GUIDE STAR CHECK **********\n\n";

    GSVIEW($Trh, $Trm, $Trs, $Tdd, $Tdm, $Tds, $Grh, $Grm, $Grs, $Gdd, $Gdm, $Gds, $POSANGLE);
    while(1)
    {
	print "Are the chosen guidestar (highlighted in"; print RED " red"; print "), and corresponding offsets \n(highlighted in"; print CYAN " cyan"; print ") suitable and within the patrol field? (y/n):\n"; 
	$gsgood = <STDIN>; chomp $gsgood;
	if($gsgood=~m/y/i)
	{ last; }
	elsif($gsgood=~m/n/i)
	{ 
	    print "\nIn the ds9 window:\n - Click on a suitable guidestar (with a "; print GREEN "green"; print " circle inside the patrol field)\n - Chosen star is now highlighted in the catalog tool\n - Click the line a few times to make sure it is "; print BOLD "active"; print " and "; print CYAN "highlighted"; print "\n - CTRL+C (or COMMAND+C on a mac) to copy the line\n - Paste the line here, I will format the GUIDE_COORD line for you:\n";
	    while(1){
		$newGS = <STDIN>; chomp $newGS;
		if($newGS=~m/^\{(\S+)\s+(\S+)\s+\S+\s+\S+\s+\S+\s+.*/){
		    $degRA = $1; $degDEC = $2;
		    $newGSRAsex = DEGtoSEXAGESIMALRA($degRA);
		    $newGSRAsex=~m/(\d{2})\:(\d{2})\:(\d{2}.*)/; $newGSRAsex = "$1 $2 $3";
		    $newGSDECsex = DEGtoSEXAGESIMALDEC($degDEC);
		    $newGSDECsex=~m/([+-]{1}\d{2})\:(\d{2})\:(\d{2}.*)/; $newGSDECsex = "$1 $2 $3";
		    print "\n GUIDE_COORD = $newGSRAsex $newGSDECsex\n";
		    print "\n - VERIFY this makes sense from the DS9 image\n - MODIFY your script\n - RE-RUN this check\n";
		    last; }
		else{ print "\nPlease try again, this appears to be the wrong format:\n"; } }
	    last; }
	else{ system "clear";  print "Please try again.\n"; } }
    
    ### End Guide Star check
    print "\n*********** END GUIDE STAR CHECK ***********\n\n";
    
    ### delete regions file
    system "rm $regfile";    
}

### Otherwise die.

else{ die "\n"; }  




















################################################################################
################################################################################
################################################################################
### SUBROUTINES

##################################################
##################################################
sub ARCHIVE {
    if($PRTCMD==1){ print "\n"; }
    print "PARSING ARCHIVE BLOCK......";
    if($PRTCMD==1){ print "\n"; }
    
    ### define/clear some variables
    $flagPARTNER=0; $flagPI_NAME=0; $flagPROP_ID=0; @PARTNER=0; $PI_NAME=0; $PROP_ID=0; $flagARCHIVE=0;
    @namestring=0; @tempstring=0;
    my $i=0; my $j=0;

    while(1)
    {
	$line = <SCR>; chomp $line;

	### EOF?       vv needed if no newline at end
	if(eof(SCR) && $line=~m/^$/){ print RED "\n*FAIL* "; print "Reached EOF before end of ARCHIVE section.\n"; die "\n"; }

	elsif($line=~m/^\s*\#.*/ || $line=~m/^\s*$/)
	{ goto skipARCHIVE; }                                    # skip commented lines

	### PARTNER
	$matchPARTNER=0;
	@partnerlist = ("OSURC","LBTB","INAF","AZ","LBTO","COMMISSIONING","CALIBRATION","LBTSDT","NOPARTNER");
	if($line =~ m/^\s*PARTNER\s*=\s*(.*)$/i){ 
	    @tempstring = split('\#', $1);              # take all before comment
	    $tempstring[0]=~m/(\S+)\s*$/;               # strip off any trailing whitespace
	    @namestring = split(',', $1);  # parse it by comma
	    for($i=0;$i<@namestring;$i=$i+1){
		$matchPARTNER=0;
		for($k=0;$k<@partnerlist;$k=$k+1){
		    if($namestring[$i]=~m/$partnerlist[$k]$/)
		    { $PARTNER[$j]=$namestring[$i]; $j=$j+1; $matchPARTNER=1; last;} }
	    if($k==@partnerlist && $matchPARTNER==0)
	      { print RED "\n   *FAIL*"; print " A partner listed is invalid,\n   "; 
		print RED "******"; print " or you have not comma separated them on line:\n   "; print RED "******"; print " $line\n";
				  $flagFAIL = $flagFAIL+1; $flagARCHIVE = $flagARCHIVE+1; } }
	    $flagPARTNER = 1;
	    if($PRTCMD==1){
		print "   PARTNER(s)          = ";
		for($i=0;$i<@PARTNER;$i=$i+1){ 
		    if($i!=@PARTNER-1){ print "$PARTNER[$i],"; }
		    if($i==@PARTNER-1){ print "$PARTNER[$i]\n"; } } }
	}
	
	### PI_NAME
	elsif($line =~ m/^\s*PI\_NAME\s*=\s*(.*)/i){ 
	    @namestring=0; @namestring = split('#', $1);      # Should allow anything before a #
	    $PI_NAME = $namestring[0]; $flagPI_NAME = 1;
	    if($PRTCMD==1){ print "   PI_NAME             = $PI_NAME\n"; }
	}

	### PROP_ID
	elsif($line =~ m/^\s*PROP_ID\s*=\s*(.*)/i){ 
	    @namestring=0; @namestring = split('#', $1);      # Should allow anything before a #
	    $PROP_ID = $namestring[0]; $flagPROP_ID = 1;
	    if($PRTCMD==1){ print "   PROP_ID             = $PROP_ID\n"; }
	}

	### END OF BLOCK?
	elsif($line =~ m/^\s*\[END_ARCHIVE_INFORMATION\]\s*(\#.*|\s*)$/i){ last; }

	### MISSED END?
	elsif($line=~m/\[STA.*/i){ print RED "\n*FAIL* "; print "Could not find end to ARCHIVE section.\n"; die "\n"; }

	### FAILED TO FIND KEYWORD       
	else{ print RED "\n   *FAIL*"; print " There is a problem with line: $line\n"; 
	      print RED "******"; print " The keyword is invalid, or you did not use an '=' sign.\n\n"; 
	      $flagFAIL = $flagFAIL+1; $flagARCHIVE = $flagARCHIVE+1; }

      skipARCHIVE:
    }
### all required keywords accounted for? OK or not OK?
    if($flagARCHIVE==0){ print GREEN " OK!\n"; }
    else{ print RED "\n NOT OK!"; print " ($flagARCHIVE failures)\n\n"; }
}


##################################################
##################################################
sub ARCHIVE_REVIEW {
    if($blocks[0][1]==2){ print YELLOW "*WARN*"; print " ARCHIVE_INFORMATION block undefined.\n"; $flagWARN = $flagWARN+1; } 
                                                                    # if eq 2, optional but not present.
    elsif($blocks[0][1]==1){                                        # if eq 1, block is present, warn if keywords not defined
	if($flagPARTNER==0){ print RED "*FAIL*"; print " No PARTNER specified.\n"; $flagFAIL = $flagFAIL+1; }
	if($flagPI_NAME==0){ print YELLOW "*WARN*"; print " No PI_NAME specified.\n"; $flagWARN = $flagWARN+1; } 
	if($flagPROP_ID==0){ print YELLOW "*WARN*"; print " No PROP_ID specified.\n"; $flagWARN = $flagWARN+1; } }    
}


##################################################
##################################################
sub INSTRUMENT {
    if($PRTCMD==1){ print "\n"; }
    print "PARSING INSTRUMENT BLOCK...";
    if($PRTCMD==1){ print "\n"; }

    ### Construct 2D wheels array from passed 1D arrays.
    my (@array1, @array2) = @_;
    my @wheels = (@array1, @array2);

    ### define/clear some variables
    @FILTER=0; $GRATING_UNIT=0; $MASK=0; $MASK_POSITION=0; 
    $tempf1=0; $tempf2=0; $tempwave=0; $flagCAMERA=0; $flagFILTER=0; $flagGRATING_UNIT=0; 
    $flagCENTRAL_WAVELENGTH=0; $flagMASK=0; $flagMASK_POSITION=0; $flagINSTRUMENT=0;
    $flagf1=-1; $flagf2=-1; my $i=0;


    ### begin parsing keywords and analyzing the values
    while(1)
    {
	$line = <SCR>; chomp $line;

	### EOF?       vv needed if no newline at end
	if(eof(SCR) && $line=~m/^$/){ print RED "\n*FAIL* "; print "Reached EOF before end of INSTRUMENT section.\n"; die "\n"; }

	elsif($line=~m/^\s*\#.*/ || $line=~m/^\s*$/)
	{ goto skipINSTRUMENT; }                                    # skip commented lines
        
        ### CAMERA
	if($line =~ m/^\s*CAMERA\s*=\s*(.*)$/i){     # CAMERA
	    if($1 =~ m/(N3\.75|N1\.8|N30)\s*(\#.*|\s*)$/i)
	      { $CAMERA = $1; $flagCAMERA = 1; 
		if($PRTCMD==1){ print "   CAMERA              = $CAMERA\n"; } } 
	    else{ print RED "\n   *FAIL*"; print " Chosen camera is invalid or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
	          $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; } }
	
	### FILTER
	elsif($line =~ m/^\s*FILTER\s*=\s*(.*)$/i){
	    $1 =~ m/^(\w+)(\s+|\s*\#.*)(\w*|\#.*)\s*(\#.*|\s*)$/;
	    $tempf1 = $1; $tempf2 = $3; #print "\n\"$1\"\t\"$3\"\n";
	    ### Check for filter 1
	    for($i=0;$i<$nfilters;$i=$i+1){           
		if($tempf1 =~ m/^$wheels[0][$i]$/i){
		    $flagf1 = $wheels[1][$i]; $FILTER[0]=$wheels[0][$i]; last; } }
	    ### Check for filter 2
	    for($i=0;$i<$nfilters;$i=$i+1){                      
		if($tempf2 =~ m/^\s*$wheels[0][$i]$/i){
		    $flagf2 = $wheels[1][$i]; $FILTER[1]=$wheels[0][$i]; last; } }
	    ### If either didn't match, fail.
	    if(($flagf1==-1 || $flagf2==-1) || ($FILTER[0]=~m/^$/ && $FILTER[1]=~m/^$/))                       
	    { print RED "\n   *FAIL*"; print " A specified filter is invalid,\n   "; print RED "******"; print " or the request is improperly formatted on line:\n   "; print RED "******"; print " $line\n"; 
	      $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; }
	    ### If they're on the same wheel, fail.
	    elsif($flagf1==$flagf2 && $flagf1!=0 && $flagf2!=0)     
	    { print RED "\n   *FAIL*"; print " Multiple filters chosen from same wheel on line:\n   "; print RED "******"; print " $line\n"; 
	      $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; }
	    ### If they're identical (and not common to both wheels), fail.
	    elsif($FILTER[0]=~m/^$FILTER[1]$/i && $flagf1!=0 && $flagf2!=0)
	    { print RED "\n   *FAIL*"; print " Identical filters chosen on line:\n   "; print RED "******"; print " $line\n"; 
	      $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; }
	    else{ if($PRTCMD==1){ print  "   FILTER(S)           = $FILTER[0] $FILTER[1]\n"; } $flagFILTER = 1; }
	}

	### GRATING_UNIT
	elsif($line =~ m/^\s*GRATING_UNIT\s*=\s*(.*)$/i){   
	    if($1 =~ m/(mirror|210_zJHK|200_H\+K|150_Ks)\s*(\#.*|\s*)$/i)
	      { $GRATING_UNIT = $1; $flagGRATING_UNIT = 1; 
		if($PRTCMD==1){ print "   GRATING_UNIT        = $GRATING_UNIT\n"; } } 
	    else{ print RED "\n   *FAIL*"; print " Chosen grating unit is invalid or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; } }	

	### CENTRAL_WAVELENGTH
	elsif($line =~ m/^\s*CENTRAL_WAVELENGTH\s*=\s*(.*)$/i){   
	    $tempwave = $1;
	    if($tempwave =~ m/^(\d+|\d+\.\d+|\d+\.|\.\d+)\s*(\#.*|\s*)$/)
	      { $CENTRAL_WAVELENGTH = $1; $flagCENTRAL_WAVELENGTH = 1; 
		if($PRTCMD==1){ print "   CENTRAL_WAVELENGTH  = $CENTRAL_WAVELENGTH\n"; } } 
	    elsif($tempwave =~ m/^\s*(\#.*|\s*)$/)
	      { $CENTRAL_WAVELENGTH = ""; $flagCENTRAL_WAVELENGTH = 1; 
		if($PRTCMD==1){ print "   CENTRAL_WAVELENGTH  = $CENTRAL_WAVELENGTH\n"; } } 
	    else{ print RED "\n   *FAIL*"; print " Chosen central wavelength is invalid or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; } }	

	### MASK
	elsif($line =~ m/^\s*MASK\s*=\s*(.*)$/i){   
	    if($1 =~ m/^(ID\d{6}|NB\d+|\s*)\s*(\#.*|\s*)$/i)
	      { $MASK = $1; $flagMASK = 1; 
		if($PRTCMD==1){ print "   MASK                = $MASK\n"; } } 
	    else{ print RED "\n   *FAIL*"; print " Chosen mask is invalid or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; } }

	### MASK_POSITION
	elsif($line =~ m/^\s*MASK_POSITION\s*=\s*(.*)$/i){   
	    if($1 =~ m/^(mask_in_fpu|mask_in_turnout|no_mask_in_use)\s*(\#.*|\s*)$/i)
	      { $MASK_POSITION = $1; $flagMASK_POSITION = 1; 
		if($PRTCMD==1){ print "   MASK_POSITION       = $MASK_POSITION\n"; } } 
	    else{ print RED "\n   *FAIL*"; print " Chosen mask position is invalid or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; } }

	### FLEXURE_COMP
	elsif($line =~ m/^\s*FLEXURE_COMP\s*=\s*(.*)$/i){   
	    if($1 =~ m/^(on|off)\s*(\#.*|\s*)$/i)
	      { $FLEXURE_COMP = $1; $flagFLEXURE_COMP = 1; 
		if($PRTCMD==1){ print "   FLEXURE_COMP        = $FLEXURE_COMP\n"; } } 
	    else{ print RED "\n   *FAIL*"; print " Chosen flexure comp is invalid or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; } }

	### END OF BLOCK?
	elsif($line =~ m/^\s*\[END_INSTRUMENT_SETUP\]\s*(\#.*|\s*)$/i){ last; }

	### MISSED END?
	elsif($line=~m/\[STA.*/i){ print RED "\n*FAIL* "; print "Could not find end to INSTRUMENT section.\n"; die "\n"; }

	### FAILED TO FIND KEYWORD
	else{ print RED "\n   *FAIL*"; print " There is a problem with line: $line\n   "; 
	      print RED "******"; print " The keyword is invalid, or you did not use an '=' sign.\n"; 
	      $flagFAIL = $flagFAIL+1; $flagINSTRUMENT = $flagINSTRUMENT+1; }       # 1 if passed
	  
      skipINSTRUMENT:
    }
    ### check if all flags are passed. OK or not OK?
    if($flagINSTRUMENT==0){ print GREEN " OK!\n"; }
    else{ print RED "\n NOT OK!"; print " ($flagINSTRUMENT failures)\n\n"; }
} 


##################################################
##################################################
sub INSTRUMENT_REVIEW { 
    if($flagtype==3 && $CAMERA!~m/N3\.75/i)       # ACQ or IMG, camera!=N3.75, fail.
      { print YELLOW "*WARN*"; print " CAMERA!=N3.75 in this IMG script.\n"; $flagWARN = $flagWARN+1; }
    if(($flagtype==3 || $flagtype==0) && $GRATING_UNIT!~m/mirror/i) # ACQ or IMG, grating!=mirror, fail.
      { print RED "*FAIL*"; print " GRATING_UNIT!=mirror in this ACQ or IMG script.\n"; $flagFAIL = $flagFAIL+1; }
    if($FILTER[0]=~m/blind/i || $FILTER[1]=~m/blind/i || $FILTERflat[0]=~m/blind/i || $FILTERflat[1]=~m/blind/i)
      { print YELLOW "*WARN*"; print " Blind filter chosen.\n"; $flagWARN = $flagWARN+1; }  #Blind filter chosen, also checks FLAT         
    # Spec or cal script, must specify a grating and a central wavelength, fail.
    if(($flagtype==1 || $flagtype==2) && ($flagGRATING_UNIT!=1 || $flagCENTRAL_WAVELENGTH!=1))
      { print YELLOW "*WARN*"; print " Must specify a GRATING_UNIT *AND* CENTRAL_WAVELENGTH in this SPEC or CAL script.\n"; $flagWARN = $flagWARN+1; }
    if(($flagtype==1 || $flagtype==2) && $GRATING_UNIT=~m/mirror/i)  # spec/cal script with mirror, fail.
      { print RED "*FAIL*"; print " GRATING_UNIT cannot be set to \'mirror\' in this SPEC or CAL script.\n"; $flagFAIL = $flagFAIL+1; }
    # Spec or cal script, mask must be in the focal plane
    if(($flagtype==1 || $flagtype==2) && ($MASK_POSITION=~m/mask_in_turnout/i || $MASK_POSITION=~m/no_mask_in_use/i))
      { print RED "*FAIL*"; print " MASK_POSITION must be in focal plane in this SPEC or CAL script.\n"; $flagFAIL = $flagFAIL+1; }
    if((($flagMASK==1 && $MASK=~m/^\s*$/) || $flagMASK==0) && ($flagMASK_POSITION==1 && $MASK_POSITION!~m/no_mask_in_use/i))
      { print RED "*FAIL*"; print " No mask specified, and mask is in use.\n"; $flagFAIL = $flagFAIL+1; }
    if($flagMASK==1 && $flagMASK_POSITION==0)
      { print RED "*FAIL*"; print " No mask position specified.\n"; $flagFAIL = $flagFAIL+1; }
    if(($flagtype==0 || $flagtype==1 || $flagtype==2) && ($MASK=~m/^NB3$/i || $MASK=~m/^ID990031$/i))  # Blind mask chosen. fail.
      { print RED "*FAIL*"; print " MASK NB3/ID99031 is a blind mask.\n"; $flagFAIL = $flagFAIL+1; }  
    if(($flagtype==0 || $flagtype==1 || $flagtype==2) && ($MASK=~m/^NB0$/i || $MASK=~m/^ID990001$/i))  # spectro sieve, warn.
      { print YELLOW "*WARN*"; print " MASK NB0/ID990001 is the spectro sieve, normally used for engineering.\n"; $flagWARN = $flagWARN+1; }  
    if(($flagtype==0 || $flagtype==1 || $flagtype==2) && ($MASK=~m/^NB1$/i || $MASK=~m/^ID990063$/i))  # optic sieve, warn.
      { print YELLOW "*WARN*"; print " MASK NB1/ID990063 is the optic sieve, normally used for engineering.\n"; $flagWARN = $flagWARN+1; }  
    if(($flagtype==0 || $flagtype==1 || $flagtype==2) && $MASK=~m/^NB\d+/i)  # NB used, prefer ID's, warn.
      { print RED "*FAIL*"; print " Mask NB# used, we prefer you use the ID#.\n"; $flagFAIL = $flagFAIL+1; }  
    if(($flagtype==0 || $flagtype==1 || $flagtype==2) && $CAMERA!~m/N1\.8/i)  # ACQ Spec or Cal, not using N1.8 camera, warn.
      { print YELLOW "*WARN*"; print " CAMERA!=N1.8 in this ACQ, SPEC or CAL script\n"; $flagWARN = $flagWARN+1; } 
    if($flagFLEXURE_COMP==0){ print YELLOW "*WARN*"; print " FLEXURE_COMP undefined (turn on).\n"; $flagWARN = $flagWARN+1; } #flexure comp 
    if($flagtype==3 && $FLEXURE_COMP=~m/off/i){ print YELLOW "*WARN*"; print " FLEXURE_COMP should be ON at this time.\n"; $flagWARN = $flagWARN+1; }
    elsif($FLEXURE_COMP=~m/off/i){ print RED "*FAIL*"; print " FLEXURE_COMP should be ON at this time.\n"; $flagFAIL = $flagFAIL+1; } #flexure comp
    if($flagtype==1 && ($flagf1==2 || $flagf2==2 || $flagf1o==2 || $flagf2o==2))
      { print YELLOW "*WARN*"; print " Narrowband filter chosen for this SPEC script.\n"; $flagWARN = $flagWARN+1; } # Narrowband (filter wheel 2), spec, warn.

# Check if central wavelength choice is non center, and if grating/filter combo is non standard, and if wavelength outside limits.
# 200_H+K
    if(($flagtype==1 || $flagtype==2) && $GRATING_UNIT=~m/200_H\+K/i){
	#if($CENTRAL_WAVELENGTH<1.49 || $CENTRAL_WAVELENGTH>2.4)
	if(($CENTRAL_WAVELENGTH<1.49 || $CENTRAL_WAVELENGTH>2.4) && ($CENTRAL_WAVELENGTH<0.87 || $CENTRAL_WAVELENGTH>1.197))
	{ print RED "*FAIL*"; print " central wavelength outside physical limits.\n"; $flagFAIL = $flagFAIL+1; }
	if(($FILTER[0]=~m/HKspec/i || $FILTER[1]=~m/HKspec/i) &&  #should be xor but syntax check takes care of it
	   ($FILTER[0]=~m/^$/ || $FILTER[1]=~m/^$/ || $FILTER[0]=~m/clear/i || $FILTER[1]=~m/clear/i)){ 
	    if($CENTRAL_WAVELENGTH != 1.93){ print YELLOW "*WARN*"; print " Non-standard central wavelength.\n"; $flagWARN = $flagWARN+1; } }
	elsif(($FILTER[0]=~m/zJspec/i || $FILTER[1]=~m/zJspec/i) && 
	      ($FILTER[0]=~m/^$/ || $FILTER[1]=~m/^$/ || $FILTER[0]=~m/clear/i || $FILTER[1]=~m/clear/i)){ 
	    if($CENTRAL_WAVELENGTH != 1.10){ print YELLOW "*WARN*"; print " Non-standard central wavelength.\n"; $flagWARN = $flagWARN+1; } }
	else{ print YELLOW "*WARN*"; print " Non-standard Grating-Filter combination (VERIFY - see manual).\n"; $flagWARN = $flagWARN+1; } }
# 150_Ks
    if(($flagtype==1 || $flagtype==2) && $GRATING_UNIT=~m/150_Ks/i){
	if($CENTRAL_WAVELENGTH<1.89 || $CENTRAL_WAVELENGTH>2.423)
	{ print RED "*FAIL*"; print " central wavelength outside physical limits.\n"; $flagFAIL = $flagFAIL+1; }
	if(($FILTER[0]=~m/Ks/i || $FILTER[1]=~m/Ks/i) &&  #should be xor but syntax check takes care of it
	   ($FILTER[0]=~m/^$/ || $FILTER[1]=~m/^$/ || $FILTER[0]=~m/clear/i || $FILTER[1]=~m/clear/i)){ 
	    if($CENTRAL_WAVELENGTH != 2.17){ print YELLOW "*WARN*"; print " Non-standard central wavelength.\n"; $flagWARN = $flagWARN+1; } } 
	else{ print YELLOW "*WARN*"; print " Non-standard Grating-Filter combination (VERIFY - See manual).\n"; $flagWARN = $flagWARN+1; } } 
# 210_zJHK
    if(($flagtype==1 || $flagtype==2) && $GRATING_UNIT=~m/210_zJHK/i){
	if( ($CENTRAL_WAVELENGTH<0.841 || $CENTRAL_WAVELENGTH>1.068) &&     # central wavelength can be anywhere 
	    ($CENTRAL_WAVELENGTH<1.10 || $CENTRAL_WAVELENGTH>1.322) &&     # between these values
	    ($CENTRAL_WAVELENGTH<1.5 || $CENTRAL_WAVELENGTH>1.75) && 
	    ($CENTRAL_WAVELENGTH<2.099 || $CENTRAL_WAVELENGTH>2.4) )
	{ print RED "*FAIL*"; print " central wavelength outside physical limits.\n"; $flagFAIL = $flagFAIL+1; }
	if(($FILTER[0]=~m/^z$/i || $FILTER[1]=~m/^z$/i) &&  #should be xor but syntax check takes care of it
	   ($FILTER[0]=~m/^$/ || $FILTER[1]=~m/^$/ || $FILTER[0]=~m/clear/i || $FILTER[1]=~m/clear/i)){ 
	    if($CENTRAL_WAVELENGTH != 0.96){ 
		if($CENTRAL_WAVELENGTH<0.841 || $CENTRAL_WAVELENGTH>1.068)
		{ print RED "*FAIL*"; print " Mismatch between filter and central wavelength.\n"; $flagFAIL = $flagFAIL+1; }
		else{ print YELLOW "*WARN*"; print " Non-standard central wavelength.\n"; $flagWARN = $flagWARN+1; } } }
	elsif(($FILTER[0]=~m/^J$/i || $FILTER[1]=~m/^J$/i) &&  #should be xor but syntax check takes care of it
	      ($FILTER[0]=~m/^$/ || $FILTER[1]=~m/^$/ || $FILTER[0]=~m/clear/i || $FILTER[1]=~m/clear/i)){ 
	    if($CENTRAL_WAVELENGTH != 1.25){ 
		if($CENTRAL_WAVELENGTH<1.10 || $CENTRAL_WAVELENGTH>1.322)
		{ print RED "*FAIL*"; print " Mismatch between filter and central wavelength.\n"; $flagFAIL = $flagFAIL+1; }
		else{ print YELLOW "*WARN*"; print " Non-standard central wavelength.\n"; $flagWARN = $flagWARN+1; } } }
	elsif(($FILTER[0]=~m/^H$/i || $FILTER[1]=~m/^H$/i) &&  #should be xor but syntax check takes care of it
	      ($FILTER[0]=~m/^$/ || $FILTER[1]=~m/^$/ || $FILTER[0]=~m/clear/i || $FILTER[1]=~m/clear/i)){ 
	    if($CENTRAL_WAVELENGTH != 1.65){ 
		if($CENTRAL_WAVELENGTH<1.5 || $CENTRAL_WAVELENGTH>1.75)
		{ print RED "*FAIL*"; print " Mismatch between filter and central wavelength.\n"; $flagFAIL = $flagFAIL+1; }
		else{ print YELLOW "*WARN*"; print " Non-standard central wavelength.\n"; $flagWARN = $flagWARN+1; } } }
	elsif(($FILTER[0]=~m/^K$/i || $FILTER[1]=~m/^K$/i) &&  #should be xor but syntax check takes care of it
	      ($FILTER[0]=~m/^$/ || $FILTER[1]=~m/^$/ || $FILTER[0]=~m/clear/i || $FILTER[1]=~m/clear/i)){ 
	    if($CENTRAL_WAVELENGTH != 2.2){ 
		if($CENTRAL_WAVELENGTH<2.099 || $CENTRAL_WAVELENGTH>2.4)
		{ print RED "*FAIL*"; print " Mismatch between filter and central wavelength.\n"; $flagFAIL = $flagFAIL+1; }
		else{ print YELLOW "*WARN*"; print " Non-standard central wavelength.\n"; $flagWARN = $flagWARN+1; } } }
	else{ print YELLOW "*WARN*"; print " Non-standard Grating-Filter combination (VERIFY - see manual).\n"; $flagWARN = $flagWARN+1; } }
}


##################################################
##################################################
sub TELESCOPE {
    if($PRTCMD==1){ print "\n"; }
    print "PARSING TELESCOPE BLOCK....";
    if($PRTCMD==1){ print "\n"; }

    ### define/clear some variables
    $flagTARGET_NAME=0; $flagTARGET_COORD=0; $flagGUIDE_NAME=0; $flagGUIDE_COORD=0;
    $flagPOSANGLE=0; $flagROT_MODE=0; $flagTELESCOPE_MODE=0; 
    $TARGET_NAME=0; $GUIDE_NAME=0; $TARGET_COORD=0; $GUIDE_COORD=0; $POSANGLE=0; $ROTMODE=0;
    $TELESCOPE_MODE=0; $flagTELESCOPE=0; 
    @namestring=0;

    while(1)
    {
	$line = <SCR>; chomp $line;

	### EOF?       vv needed if no newline at end
	if(eof(SCR) && $line=~m/^$/){ print RED "\n*FAIL* "; print "Reached EOF before end of TELESCOPE section.\n"; die "\n"; }

	elsif($line=~m/^\s*\#.*/ || $line=~m/^\s*$/)
	{ goto skipTELESCOPE; }                                    # skip commented lines

	### TARGET_NAME
	if($line =~ m/^\s*TARGET_NAME\s*=\s*(.*)/i){ 
	    @namestring = split('#', $1);               # Should allow anything before a #
	    $TARGET_NAME = $namestring[0]; $flagTARGET_NAME = 1;
	    if($PRTCMD==1){ print "   TARGET_NAME         = $TARGET_NAME\n"; }  }
	
	### TARGET_COORD
	# future: check for validity of values
	elsif($line =~ m/^\s*TARGET_COORD\s*=\s*(.*)$/i){
	    if($1 =~ m/^(\d{2})\s+(\d{2})\s+(\d{2}\.\d+|\d{2}\.|\d{2})\s+([+-]?\d{2})\s+(\d{2})\s+(\d{2}\.\d+|\d{2}\.|\d{2})\s*(\#.*|\s*)$/)
	    {   $TARGET_COORD = "$1 $2 $3 $4 $5 $6";
		$Trh = $1; $Trm = $2; $Trs = $3; $Tdd = $4; $Tdm = $5; $Tds = $6; 
		if(SEXCHECK_RA("$Trh $Trm $Trs")>0 && SEXCHECK_DEC("$Tdd $Tdm $Tds")>0 ){ 
		    $flagTARGET_COORD = 1;  if($PRTCMD==1){ print "   TARGET_COORD        = $TARGET_COORD\n"; } } 
		else{ print RED "\n   *FAIL*"; print " Chosen target coords are invalid, improperly parsed,\n   "; 
		      print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		      $flagFAIL = $flagFAIL+1; $flagTELESCOPE = $flagTELESCOPE+1; } }
	    else{ print RED "\n   *FAIL*"; print " Chosen target coords are invalid, improperly parsed,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagTELESCOPE = $flagTELESCOPE+1; } }

	### GUIDE_NAME
	elsif($line =~ m/^\s*GUIDE_NAME\s*=\s*(.*)/i){ 
	    @namestring = split('#', $1);               # Should allow anything before a #
	    $GUIDE_NAME = $namestring[0]; $flagGUIDE_NAME = 1;
	    if($PRTCMD==1){ print "   GUIDE_NAME          = $GUIDE_NAME\n"; }   }

	### GUIDE_COORD
	elsif($line =~ m/^\s*GUIDE_COORD\s*=\s*(.*)$/i){
	    if($1 =~ m/^(\d{2})\s+(\d{2})\s+(\d{2}\.\d+|\d{2}\.|\d{2})\s+([+-]?\d{2})\s+(\d{2})\s+(\d{2}\.\d+|\d{2}\.|\d{2})\s*(\#.*|\s*)$/)
	      { $GUIDE_COORD = "$1 $2 $3 $4 $5 $6"; 
		$Grh = $1; $Grm = $2; $Grs = $3; $Gdd = $4; $Gdm = $5; $Gds = $6;
		if(SEXCHECK_RA("$Grh $Grm $Grs")>0 && SEXCHECK_DEC("$Gdd $Gdm $Gds")>0 ){ 
		    $flagGUIDE_COORD = 1;  if($PRTCMD==1){ print "   GUIDE_COORD         = $GUIDE_COORD\n"; } }
		else{ print RED "\n   *FAIL*"; print " Chosen guide coords are invalid, improperly parsed,\n   "; 
		      print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		      $flagFAIL = $flagFAIL+1; $flagTELESCOPE = $flagTELESCOPE+1; } }
	    else{ print RED "\n   *FAIL*"; print " Chosen guide coords are invalid, improperly parsed,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagTELESCOPE = $flagTELESCOPE+1; } }	

	### POSANGLE
	elsif($line =~ m/^\s*POSANGLE\s*=\s*(.*)$/i){ 
	    if($1 =~ m/^([+-]?\d+|[+-]?\d+\.\d+|[+-]?\d+\.|[+-]?\.\d+)\s*(\#.*|\s*)$/)
	      { $POSANGLE = $1; $flagPOSANGLE = 1;
		if($PRTCMD==1){ print "   POSANGLE            = $POSANGLE\n"; }   }
	    else{ print RED "\n   *FAIL*"; print " Chosen position angle is invalid, or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagTELESCOPE = $flagTELESCOPE+1; } }

	### ROT_MODE
	elsif($line =~ m/^\s*ROT_MODE\s*=\s*(.*)$/i){ 
	    if($1 =~ m/^(position|parallactic)\s*(\#.*|\s*)$/i)
	      { $ROT_MODE = $1; $flagROT_MODE = 1;
		if($PRTCMD==1){ print "   ROT_MODE            = $ROT_MODE\n"; }  }
	    else{ print RED "\n   *FAIL*"; print " Chosen rotator mode is invalid, or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagTELESCOPE = $flagTELESCOPE+1; } }

	### TELESCOPE_MODE
	elsif($line =~ m/^\s*TELESCOPE_MODE\s*=\s*(.*)$/i){ 
	    if($1 =~ m/^(active|guide|track|static|adaptive)\s*(\#.*|\s*)$/i)
	      { $TELESCOPE_MODE = $1; $flagTELESCOPE_MODE = 1;
		if($PRTCMD==1){ print "   TELESCOPE_MODE      = $TELESCOPE_MODE\n"; }  }
	    else{ print RED "\n   *FAIL*"; print " Chosen telescope mode is invalid, or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagTELESCOPE = $flagTELESCOPE+1; } }

	### END OF BLOCK?
	elsif($line =~ m/^\s*\[END_TELESCOPE_SETUP\]\s*(\#.*|\s*)$/i){ last; }

	### MISSED END?
	elsif($line=~m/\[STA.*/i){ print RED "\n*FAIL* "; print "Could not find end to TELESCOPE section.\n"; die "\n"; }

	### FAILED TO FIND KEYWORD
	else{ print RED "\n   *FAIL*"; print " There is a problem with line: $line\n   "; 
	      print RED "******"; print " The keyword is invalid, or you did not use an '=' sign.\n"; 
	      $flagFAIL = $flagFAIL+1; $flagTELESCOPE = $flagTELESCOPE+1; }       

      skipTELESCOPE:
    }

### all required keywords accounted for? OK or not OK?
    if($flagTELESCOPE==0){ print GREEN " OK!\n"; }
    else{ print RED "\n NOT OK!"; print " ($flagTELESCOPE failures)\n\n"; }
}


##################################################
##################################################
sub TELESCOPE_REVIEW {
    if(($flagtype==3 || $flagtype==0) && $blocks[2][1]==2)  #ACQ or IMG, optional TELESCOPE_SETUP is not defined
      { print YELLOW "*WARN*"; print " TELESCOPE_SETUP block undefined in this ACQ or IMG script.\n"; $flagWARN = $flagWARN+1; }
    elsif(($flagtype==3 || $flagtype==0) && $blocks[2][1]==1){
	if($ROT_MODE!~m/position/i){ print YELLOW "*WARN*"; print " ROT_MODE!=position in this ACQ or IMG script.\n"; $flagWARN = $flagWARN+1; }
	if($TELESCOPE_MODE!~m/active/i){ print YELLOW "*WARN*"; print " TELESCOPE_MODE!=active in this ACQ or IMG script.\n"; $flagWARN = $flagWARN+1; } }
    if($blocks[2][1]==1){
	if($flagPOSANGLE==0){ print RED "*FAIL*"; print " POSANGLE is undefined.\n"; $flagFAIL = $flagFAIL+1; }
	if($flagTARGET_COORD==0){ print RED "*FAIL*"; print " TARGET_COORD must be defined.\n"; $flagFAIL = $flagFAIL+1; }
	if($flagGUIDE_COORD==0 && ($TELESCOPE_MODE!~m/track/i && $TELESCOPE_MODE!~m/static/i)){ print RED "*FAIL*"; print " GUIDE_COORD must be defined.\n"; 
												$flagFAIL = $flagFAIL+1; } }
    if($TELESCOPE_MODE=~m/static/i){ print YELLOW "*WARN*"; print " TELESCOPE_MODE=static.\n"; $flagWARN = $flagWARN+1; }
    if($TELESCOPE_MODE=~m/adaptive/i){ print YELLOW "*WARN*"; print " TELESCOPE_MODE=adaptive is not fully developed yet. GS won't be checked.\n"; 
				       $flagWARN = $flagWARN+1; }
    if($blocks[2][1]==1 && ($POSANGLE<-360 || $POSANGLE>360))
      { print YELLOW "*WARN*"; print " POSANGLE is beyond +/-360deg. Please verify.\n"; $flagWARN = $flagWARN+1; }
}


##################################################
##################################################
sub READOUT {
    if($PRTCMD==1){ print "\n"; }
    print "PARSING READOUT BLOCK......";
    if($PRTCMD==1){ print "\n"; }

    ### define/clear some variables
    $DIT=0; $NDIT=0; $NEXPO=0; $ROE_MODE=0; $SAVE_MODE=0;
    $flagDIT=0; $flagNDIT=0; $flagNEXPO=0; $flagROE_MODE=0; $flagSAVE_MODE=0;
    $tempDIT=0; $tempNDIT=0; $tempNEXPO=0; $flagREADOUT=0;

    while(1)
    {
	$line = <SCR>; chomp $line;

	### EOF?       vv needed if no newline at end
	if(eof(SCR) && $line=~m/^$/){ print RED "\n*FAIL* "; print "Reached EOF before end of READOUT section.\n"; die "\n"; }

	elsif($line=~m/^\s*\#.*/ || $line=~m/^\s*$/)
	{ goto skipREADOUT; }                                    # skip commented lines

	### DIT
	if($line =~ m/^\s*DIT\s*=\s*(.*)/i){ 
	    $tempDIT=$1;
	    if($tempDIT =~ m/^(\d+|\d+\.\d+|\d+\.|\.\d+)\s*(\#.*|\s*)$/ && $tempDIT>0)
	      { $DIT = $1; $flagDIT = 1;
		if($PRTCMD==1){ print "   DIT                 = $DIT\n"; }  } 
	    else{ print RED "\n   *FAIL*"; print " Chosen detector integration time is invalid,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagREADOUT = $flagREADOUT+1; } }

	### NDIT
	elsif($line =~ m/^\s*NDIT\s*=\s*(.*)/i){ 
	    $tempNDIT=$1;
	    if($tempNDIT =~ m/^(\d+)\s*(\#.*|\s*)$/ && $tempNDIT>0)
	      { $NDIT = $1; $flagNDIT = 1;
		if($PRTCMD==1){ print "   NDIT                = $NDIT\n"; }  } 
	    else{ print RED "\n   *FAIL*"; print " Chosen number of DITs is invalid,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagREADOUT = $flagREADOUT+1; } }
  
	### NEXPO
	elsif($line =~ m/^\s*NEXPO\s*=\s*(.*)/i){ 
	    $tempNEXPO=$1;
	    if($tempNEXPO =~ m/^(\d+)\s*(\#.*|\s*)$/ && $tempNEXPO>0)
	      { $NEXPO = $1; $flagNEXPO = 1;
		if($PRTCMD==1){ print "   NEXPO               = $NEXPO\n"; }  } 
	    else{ print RED "\n   *FAIL*"; print " Chosen number of exposures is invalid,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagREADOUT = $flagREADOUT+1; } }

	### ROE_MODE
	elsif($line =~ m/^\s*ROE_MODE\s*=\s*(.*)$/i){ 
	    if($1 =~ m/^(o2dcr|mer)\s*(\#.*|\s*)$/i)
	      { $ROE_MODE = $1; $flagROE_MODE = 1;
		if($PRTCMD==1){ print "   ROE_MODE            = $ROE_MODE\n"; }  }
	    else{ print RED "\n   *FAIL*"; print " Chosen readout mode is invalid, or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagREADOUT = $flagREADOUT+1; } }

	### SAVE_MODE
	elsif($line =~ m/^\s*SAVE_MODE\s*=\s*(.*)$/i){ 
	    if($1 =~ m/^(integrated|cube|normal)\s*(\#.*|\s*)$/i)
	      { $SAVE_MODE = $1; $flagSAVE_MODE = 1;
		if($PRTCMD==1){ print "   SAVE_MODE           = $SAVE_MODE\n"; }  }
	    else{ print RED "\n   *FAIL*"; print " Chosen readout mode is invalid, or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagREADOUT = $flagREADOUT+1; } }

	### SAVE_PATH
	elsif($line =~ m/^\s*SAVE_PATH\s*=\s*(.*)$/i){
	    print RED "\n   *FAIL*"; print " You are requested not to specify a save path. Line:\n   "; 
	    print RED "******"; print " $line\n"; 
	    $flagFAIL = $flagFAIL+1; $flagREADOUT = $flagREADOUT+1; }

	### FILENAME
	elsif($line =~ m/^\s*FILENAME\s*=\s*(.*)$/i){ 
	    print RED "\n   *FAIL*"; print " You are requested not to specify a filename. Line:\n   "; 
	    print RED "******"; print " $line\n"; 
	    $flagFAIL = $flagFAIL+1; $flagREADOUT = $flagREADOUT+1; }

	### END OF BLOCK?
	elsif($line =~ m/^\s*\[END_READOUT_SETUP\]\s*(\#.*|\s*)$/i){ last; }

	### MISSED END?
	elsif($line=~m/\[STA.*/i){ print RED "\n*FAIL* "; print "Could not find end to READOUT section.\n"; die "\n"; }

	### FAILED TO FIND KEYWORD
	else{ print RED "\n   *FAIL*"; print " There is a problem with line: $line\n   "; 
	      print RED "******"; print " The keyword is invalid, or you did not use an '=' sign.\n"; 
	      $flagFAIL = $flagFAIL+1; $flagREADOUT = $flagREADOUT+1; }       

      skipREADOUT:
    }
### all required keywords accounted for?  OK or not OK?
    if($flagREADOUT==0){ print GREEN " OK!\n"; }
    else{ print RED "\n NOT OK!"; print " ($flagREADOUT failures)\n\n"; }
}


##################################################
##################################################
sub READOUT_REVIEW {
# initialize
    $Tdwell=0; $Tro=0; $flagTIMES=0; $PctOS=0; $Ndither=0; $flagNOCALC=0;
    if($flagROE_MODE==0 && ($defFLAT==0 && $defDARK==0) && ($flagOFFSET>0 || $flagACQUISITION>0 || $flagJITTER>0))
      { print YELLOW "*WARN*"; print " ROE_MODE is undefined (do not depend on defaults).\n"; $flagWARN = $flagWARN+1; $flagNOCALC=$flagNOCALC+1; } 
    # check if ROE_MODE, DIT, NDIT, NEXPO are defined.
    if($flagDIT==0 && ($defFLAT==0 && $defDARK==0) && ($flagOFFSET>0 || $flagACQUISITION>0 || $flagJITTER>0))
      { print YELLOW "*WARN*"; print " DIT is undefined (do not depend on defaults).\n"; $flagWARN = $flagWARN+1; $flagNOCALC=$flagNOCALC+1; }
    if($flagNDIT==0 && ($defFLAT==0 && $defDARK==0) && ($flagOFFSET>0 || $flagACQUISITION>0 || $flagJITTER>0))
      { print YELLOW "*WARN*"; print " NDIT is undefined (do not depend on defaults).\n"; $flagWARN = $flagWARN+1; $flagNOCALC=$flagNOCALC+1; }
    if($flagNEXPO==0 && ($defFLAT==0 && $defDARK==0) && ($flagOFFSET>0 || $flagACQUISITION>0 || $flagJITTER>0))
      { print YELLOW "*WARN*"; print " NEXPO is undefined (do not depend on defaults).\n"; $flagWARN = $flagWARN+1; $flagNOCALC=$flagNOCALC+1; }
    
    if($flagROE_MODE==1 && $flagDIT==1 && $flagNDIT==1 && $flagNEXPO==1){
	if($ROE_MODE=~m/o2dcr/i){ $Tro = 4; } if($ROE_MODE=~m/mer/i){ $Tro = 12; }  # readout times
	
	$flagTIMES = 1; # set a flag that we are calculating times
	$Tdwell = $NEXPO*($NDIT*($DIT+$Tro));  # time for each image
	$Ndither = $flagOFFSET+$flagACQUISITION+$NJITTER+$Nflat+$Ndark; #print "$NJITTER\n";  # number of images taken
	$Tslew = $Tslew + 30*$flagPOINTING; # very approximate slew time, plus time for each new pointing command
	$Tcoll = $Tcoll + 30*$flagPOINTING; # very approximate collimation time
	$Texec = $Texec + $Ndither*($Tdwell + $Tsave + $Toffset); # approximate execution time
	$Texpo = $Texpo + $Ndither*$NEXPO*$NDIT*$DIT; # approximate total exposure time
	if($Tdwell<60 && $flagtype!=2){print YELLOW "*WARN*"; print " Estimated dwell time is less than 60s ($Tdwell).\n"; $flagWARN = $flagWARN+1; }
	if($Tdwell>312 && $flagtype!=2){print YELLOW "*WARN*"; print " Estimated dwell time is greater than 312s ($Tdwell).\n"; $flagWARN = $flagWARN+1; } }
    
    if($ROE_MODE=~m/o2dcr/i && $DIT<4){ print RED "*FAIL*"; print " DIT<4s with ROE_MODE=o2dcr.\n"; $flagFAIL = $flagFAIL+1; }
    if($ROE_MODE=~m/mer/i && $DIT<12){ print RED "*FAIL*"; print " DIT<12s with ROE_MODE=mer.\n"; $flagFAIL = $flagFAIL+1; }
    if(($flagtype==3 || $flagtype==0) && $ROE_MODE!~m/o2dcr/i)
      { print YELLOW "*WARN*"; print " ROE_MODE!=o2dcr in this ACQ or IMG script.\n"; $flagWARN = $flagWARN+1; }
    if($flagtype==1 && $ROE_MODE!~m/mer/i){ print YELLOW "*WARN*"; print " ROE_MODE!=mer in this SPEC script.\n"; $flagWARN = $flagWARN+1; }
    if($ROE_MODE=~m/o2dcr/i){
	if($NDIT>1 && $SAVE_MODE!~m/integrated/i)
	{ print YELLOW "*WARN*"; print " SAVE_MODE!=integrated with NDIT>1 and ROE_MODE=o2dcr.\n"; $flagWARN = $flagWARN+1; }
	if($NDIT==1 && $SAVE_MODE!~m/normal/i)
	{ print YELLOW "*WARN*"; print " SAVE_MODE!=normal with NDIT=1 and ROE_MODE=o2dcr.\n"; $flagWARN = $flagWARN+1; } }
    if($ROE_MODE=~m/mer/i){ 
	if($NDIT==1 && $SAVE_MODE!~m/normal/i)
	{ print YELLOW "*WARN*"; print " SAVE_MODE!=normal with NDIT=1 and ROE_MODE=mer.\n"; $flagWARN = $flagWARN+1; } }
}


##################################################
##################################################
sub OBSERVING {
    if($PRTCMD==1){ print "\n"; }
    print "PARSING OBSERVING BLOCK....";
    if($PRTCMD==1){ print "\n"; }

    ### Construct 2D wheels array from passed 1D arrays.
    my (@array1, @array2) = @_;
    my @wheels = (@array1, @array2);

    ### define/clear some variables
    $COORD_SYS=0; $OFFSET_TYPE=0; $JITTER=0; $OFFSET=0; $POINTING=0; $FLAT=0; $DARK=0; $Nflat=0; $Ndark=0; 
    $FLUSH_DETECTOR=0; $LAMP=0; @FILTERflat=0;
    $flagCOORD_SYS=0; $flagJITTER=0; $flagOFFSET=0; $flagPOINTING=0; $flagFLAT=0; $flagACQUISITION=0; $defFLAT=0; $defDARK=0;
    $flagDARK=0; $flagFUSH_DETECTOR=0; $flagLAMP=0; $flagf1o=-1; $flagf2o=-1; $flagOBSERVING=0; $NJITTER=0;
    $tempFLAT=0; $tempFLAT2=0; $tempDARK=0;

    while(1)
    {
	$line = <SCR>; chomp $line; 

	### EOF?       vv needed if no newline at end
	if(eof(SCR) && $line=~m/^$/){ print RED "\n*FAIL* "; print "Reached EOF before end of OBSERVING section.\n"; die "\n"; }

	elsif($line=~m/^\s*\#.*/ || $line=~m/^\s*$/)
	{ goto skipOBSERVING; }                                    # skip commented lines


	### COORD_SYS
	if($line =~ m/^\s*COORD_SYS\s*=\s*(.*)$/i){ 
	    if($1 =~ m/^(DETXY|RADEC)\s*(\#.*|\s*)$/i)
	      { $COORD_SYS = $1; $flagCOORD_SYS = 1;
		if($PRTCMD==1){ print "   COORD_SYS           = $COORD_SYS\n"; }  }
	    else{ print RED "\n   *FAIL*"; print " Chosen coordinate system is invalid, or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } }

	### OFFSET_TYPE
	elsif($line =~ m/^\s*OFFSET_TYPE\s*=\s*(.*)$/i){ 
	    if($1 =~ m/^(relative|absolute)\s*(\#.*|\s*)$/i)
	      { $OFFSET_TYPE = $1; $flagOFFSET_TYPE = 1;
		if($PRTCMD==1){ print "   OFFSET_TYPE         = $OFFSET_TYPE\n"; }  }
	    else{ print RED "\n   *FAIL*"; print " Chosen offset type is invalid, or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } }

	### ACQUISITION
	# check if '+' sign here is valid!
	elsif($line =~ m/^\s*ACQUISITION\s*=\s*(.*)/i){ 
	    if($1 =~ m/^([+-]?\d+|[+-]?\d+\.\d+|[+-]?\d+\.|[+-]?\.\d+)\s+([+-]?\d+|[+-]?\d+\.\d+|[+-]?\d+\.|[+-]?\.\d+)\s*(\#.*|\s*)$/)
	      { $ACQUISITION = "$1 $2"; $flagACQUISITION = $flagACQUISITION + 1;
		if($PRTCMD==1){ print "   ACQUISITION         = $ACQUISITION\n"; }  } 
	    else{ print RED "\n   *FAIL*"; print " Chosen acquisition syntax is invalid,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } 

	    DITHER("ACQUISITION",$COORD_SYS,$OFFSET_TYPE,$1,$2);
	}

	### JITTER
	elsif($line =~ m/^\s*JITTER\s*=\s*(.*)/i){ 
	    if($1 =~ m/^(\d+)\s+(\d+|\d+\.\d+|\d+\.|\.\d+)\s*(\#.*|\s*)$/)
	    { $JITTER = "$1 $2"; $flagJITTER = $flagJITTER + 1; $NJITTER = $NJITTER + $1; #total number of jitters
		if($PRTCMD==1){ print "   JITTER              = $JITTER\n"; }  } 
	    else{ print RED "\n   *FAIL*"; print " Chosen jitter syntax is invalid,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } 

	    DITHER("JITTER",$COORD_SYS,$OFFSET_TYPE,$1,$2);
	}

	### OFFSET
	# check if '+' sign here is valid!
	elsif($line =~ m/^\s*OFFSET\s*=\s*(.*)/i){ #print "$line\n";
	    if($1 =~ m/^(([+-]?\d+|[+-]?\d+\.\d+|[+-]?\d+\.|[+-]?\.\d+)\s+([+-]?\d+|[+-]?\d+\.\d+|[+-]?\d+\.|[+-]?\.\d+)|([+-]?\d+|[+-]?\d+\.\d+|[+-]?\d+\.|[+-]?\.\d+)\s+([+-]?\d+|[+-]?\d+\.\d+|[+-]?\d+\.|[+-]?\.\d+)\s+([+-]?\d+|[+-]?\d+\.\d+|[+-]?\d+\.|[+-]?\.\d+))\s*(\#.*|\s*)$/)
	      { $OFFSET = "$1"; $flagOFFSET = $flagOFFSET + 1;
		if($PRTCMD==1){ print "   OFFSET              = $OFFSET\n"; }  } 
	    else{ print RED "\n   *FAIL*"; print " Chosen offset syntax is invalid,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } 

	    $OFFSET =~ m/(\S+)\s+(\S+)\s*(\S*)/;
	    DITHER("OFFSET",$COORD_SYS,$OFFSET_TYPE,$1,$2,$3);
	}

	### POINTING
	# future: check for validity of values
	elsif($line =~ m/^\s*POINTING\s*=\s*(.*)$/i){
	    if($1 =~ m/^(\d+)\s+(\d+)\s+(\d+\.\d+|\d+\.|\.\d+|\d+)\s+([+-]?\d+)\s+(\d+)\s+(\d+\.\d+|\d+\.|\.\d+|\d+)\s+(\d+)\s+(\d+)\s+(\d+\.\d+|\d+\.|\.\d+|\d+)\s+([+-]?\d+)\s+(\d+)\s+(\d+|\d+\.\d+|\d+\.|\.\d+)\s*(\#.*|\s*)$/)
	      { $POINTING = "$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12"; $flagPOINTING = $flagPOINTING+1;
		if($PRTCMD==1){ print "   POINTING            = $POINTING\n"; } }
	    else{ print RED "\n   *FAIL*"; print " Chosen pointing syntax is invalid, improperly parsed,\n   "; 
		  print RED "******"; print " or missing '#' to comment on line:\n   "; print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } }	

	### FLAT
	elsif($line =~ m/^\s*FLAT\s*(.*)$/i){
	    $tempFLAT = $1;
	    if($tempFLAT =~ m/^\s*(\#.*|\s*)$/)      # blank?
	      { $FLAT = ""; $flagFLAT = 1; $Nflat=$Nflat+1; if($PRTCMD==1){ print "   FLAT\n"; } }
	    elsif($tempFLAT =~ m/\s*=\s*((mer|o2dcr)\s+(\d+\.\d+|\d+\.|\.\d+|\d+)\s+\d+\s+\d+)\s*(\#.*|\s*)$/i)     # included ROE/DIT/NDIT/NEXPO?
	      { $FLAT = $1; $flagFLAT = 1; $defFLAT = $defFLAT+1; if($PRTCMD==1){ print "   FLAT                = $FLAT\n"; } } 
	    elsif($tempFLAT =~ m/\s*=\s*(mer|o2dcr)\s+(\d+\.\d+|\d+\.|\.\d+|\d+)\s+(\d+)\s+(\d+)\s+(\w+)\s+(\w+)\s+(N1.8|N3.75|N30)\s*(\#.*|\s*)$/i)      
                                                                                                              # included ROE/DIT/NDIT/NEXPO/filt/filt/CAM?
	      {
		  $tempFLAT2 = "$1 $2 $3 $4 $5 $6 $7";
		  #check the filters!
		  $tempf1 = $5; $tempf2 = $6;		
		  ### Check for filter 1
		  for($i=0;$i<$nfilters;$i=$i+1){           
		      if($tempf1 =~ m/^$wheels[0][$i]$/i){
			  $flagf1o = $wheels[1][$i]; $FILTERflat[0]=$wheels[0][$i]; last; } }
		  ### Check for filter 2
		  for($i=0;$i<$nfilters;$i=$i+1){                      
		      if($tempf2 =~ m/^\s*$wheels[0][$i]$/i){
			  $flagf2o = $wheels[1][$i]; $FILTERflat[1]=$wheels[0][$i]; last; } }
		  ### If either didn't match, fail.
		  if($flagf1o==-1 || $flagf2o==-1)                       
		  { print RED "\n   *FAIL*"; print " A specified filter is invalid on line:\n   "; 
		    print RED "******"; print " $line\n"; 
		    $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; }
		  ### If they're on the same wheel, fail.
		  elsif($flagf1o==$flagf2o && $flagf1o!=0 && $flagf2o!=0)     
		  { print RED "\n   *FAIL*"; print " Multiple filters chosen from same wheel on line:\n   "; 
		    print RED "******"; print " $line\n"; 
		    $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; }
		  ### If they're identical (and not common to both wheels), fail.
		  elsif($FILTERflat[0]=~m/^$FILTERflat[1]$/i && $flagf1o!=0 && $flagf2o!=0)
		  { print RED "\n   *FAIL*"; print " Identical filters chosen on line:\n   "; 
		    print RED "******"; print " $line\n"; 
		    $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; }
		  else
		  { $FLAT = $tempFLAT2; if($PRTCMD==1){ print  "   FLAT                = $FLAT\n"; } $flagFLAT = 1; $defFLAT = $defFLAT+1; }  
	      }
	    else{ print RED "\n   *FAIL*"; print " Syntax error in FLAT command on line:\n   "; 
		  print RED "******"; print " $line\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } 

	    ### add Texec Texpo here
	    if($defFLAT>0){
		@spFLAT = split(' ',$FLAT);
		if($spFLAT[0]=~m/o2dcr/i){ $Tro=4; } elsif($spFLAT[0]=~m/mer/i){ $Tro=12; }
		$Texec = $Texec + ($spFLAT[3]*($spFLAT[2]*($spFLAT[1]+$Tro)) + $Tsave + $Toffset); # approximate execution time
		$Texpo = $Texpo + $spFLAT[3]*$spFLAT[2]*$spFLAT[1]; }# approximate total exposure time
	}

	### DARK
	elsif($line =~ m/^\s*DARK\s*(.*)$/i){
	    $tempDARK = $1;
	    if($tempDARK =~ m/^\s*(\#.*|\s*)$/)      # blank?
	      { $DARK = ""; $flagDARK = 1; $Ndark=$Ndark+1; if($PRTCMD==1){ print "   DARK\n"; } }
	    elsif($tempDARK =~ m/\s*=\s*((mer|o2dcr)\s+(\d+\.\d+|\d+\.|\.\d+|\d+)\s+\d+\s+\d+)\s*(\#.*|\s*)$/i)  # included ROE/DIT/NDIT/NEXPO?
	      { $DARK = $1; $flagDARK = 1; $defDARK = $defDARK+1; 
		if($PRTCMD==1){ print "   DARK                = $DARK\n"; } } 
	    else{ print RED "\n   *FAIL*"; print " Syntax error in DARK command on line:\n   "; 
		  print RED "******"; print " $line\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } 

	    ### add Texec Texpo here
	    if($defDARK>0){
		@spDARK = split(' ',$DARK);
		if($spDARK[0]=~m/o2dcr/i){ $Tro=4; } elsif($spDARK[0]=~m/mer/i){ $Tro=12; }
		$Texec = $Texec + ($spDARK[3]*($spDARK[2]*($spDARK[1]+$Tro)) + $Tsave + $Toffset); # approximate execution time
		$Texpo = $Texpo + $spDARK[3]*$spDARK[2]*$spDARK[1]; }# approximate total exposure time
	}

	### FLUSH_DETECTOR
	elsif($line =~ m/^\s*FLUSH_DETECTOR\s*(.*)$/i){ 
	    if($1 =~ m/^\s*(\#.*|\s*)$/)
	      { $flagFLUSH_DETECTOR = $flagFLUSH_DETECTOR+1; if($PRTCMD==1){ print "   FLUSH_DETECTOR\n"; } } 
	    else{ print RED "\n   *FAIL*"; print " FLUSH_DETECTOR has no arguments or '='. Line:\n   "; 
		  print RED "******"; print " $line\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } }

	### LAMP
	elsif($line =~ m/^\s*LAMP\s*=\s*(.*)$/i){ 
	    if($1 =~ m/^((Ar|Xe|Ne|Halo1|Halo2|Halo3))\s*(\#.*|\s*)$/i) # no time good
	      { $LAMP = $1; $flagLAMP = 1; if($PRTCMD==1){ print "   LAMP                = $LAMP\n"; }  }
	    elsif($1 =~ m/^((Ar|Xe|Ne|Halo1|Halo2|Halo3)\s+(\d+|\d+\.\d+|\d+\.|\.\d+))\s*(\#.*|\s*)$/i) # with time fail
	      { print RED "\n   *FAIL*"; print " Do not specify LAMP time (done automatically by LUCI) on line:\n   "; 
		print RED "******"; print " $line.\n"; 
		$flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; }
	    else{ print RED "\n   *FAIL*"; print " Chosen lamp (or syntax) is invalid, or missing '#' to comment on line:\n   "; 
		  print RED "******"; print " $line.\n"; 
		  $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; } }

	### END OF BLOCK?
	elsif($line =~ m/^\s*\[END_OBSERVING_SETUP\]\s*(\#.*|\s*)$/i){ last; }

	### MISSED END?
	elsif($line=~m/\[STA.*/i){ print RED "\n*FAIL* "; print "Could not find end to OBSERVING section.\n"; die "\n"; }

	### FAILED TO FIND KEYWORD
	else{ print RED "\n   *FAIL*"; print " There is a problem with line: $line\n   "; 
	      print RED "******"; print " The keyword is invalid, or you did not use an '=' sign.\n"; 
	      $flagFAIL = $flagFAIL+1; $flagOBSERVING = $flagOBSERVING+1; }       

      skipOBSERVING:
    }
### all required keywords/required-combinations accounted for?  OK or not OK?
    if($flagOBSERVING==0){ print GREEN " OK!\n"; }
    else{ print RED "\n NOT OK!"; print " ($flagOBSERVING failures)\n\n"; }
}


##################################################
##################################################
sub OBSERVING_REVIEW {
    $caltemp=0;
    if($flagtype==3 && $flagJITTER>0 && $OFFSET_TYPE!~m/absolute/i) # IMG, !abs offset with jitter, fail.
      { print RED "*FAIL*"; print " OFFSET_TYPE must be ABSOLUTE when using the JITTER command.\n"; $flagFAIL = $flagFAIL+1; }
    if($flagtype!=3 && $flagJITTER>0) # IMG, !abs offset with jitter, fail.
      { print RED "*FAIL*"; print " No reason to use JITTER in a SPEC, CAL, or ACQ script.\n"; $flagFAIL = $flagFAIL+1; }
    if($flagtype==3 && $flagACQUISITION!=0){ print YELLOW "*WARN*"; print " ACQUISITION command within an IMG script.\n"; $flagWARN = $flagWARN+1; }
    if($flagtype==3 && $flagJITTER==0 && $flagOFFSET==0)
      { print YELLOW "*WARN*"; print " Should have at least one OFFSET in this IMG script $flagOFFSET.\n"; $flagWARN = $flagWARN+1; }
    if($flagtype==1 && $OFFSET_TYPE!~m/relative/i)
      { print RED "*FAIL*"; print " OFFSET_TYPE!=relative in this SPEC script (absolute will undo alignment).\n"; $flagFAIL = $flagFAIL + 1; } 
    if($flagtype==1 && $COORD_SYS!~m/DETXY/i)
      { print YELLOW "*WARN*"; print " COORD_SYS!=DETXY in this SPEC script (easier to dither on slit).\n"; $flagWARN = $flagWARN + 1; }
    $OFFSET=~m/(\S+)\s+.*/; $dX = $1;
    if($flagtype==1 && abs($dX)!=0.0)
      { print YELLOW "*WARN*"; print " OFFSET dX!=0 in this SPEC script (will dither off slit).\n"; $flagWARN = $flagWARN + 1; }
    if($flagFLUSH_DETECTOR!=0){ print YELLOW "*WARN*"; print " FLUSH_DETECTOR: are you sure? (takes 11 mins to complete).\n"; $flagWARN = $flagWARN + 1; }
    if($flagPOINTING!=0){ print YELLOW "*WARN*"; print " POINTING is valid, but is not reccommended. GS will not be checked.\n"; $flagWARN = $flagWARN + 1; }
    if($flagtype==2){
	if(($flagLAMP+$flagDARK+$flagFLAT)==0)
	{ print RED "*FAIL*"; print " One of LAMP, DARK, or FLAT is required in this CAL script.\n"; $flagFAIL = $flagFAIL+1; }
	elsif(($flagLAMP+$flagDARK+$flagFLAT)>1){ 
	    if($flagLAMP>0){ $caltemp++; } if($flagDARK>0){ $caltemp++; } if($flagFLAT>0){ $caltemp++; }
	    if($caltemp>1){ print RED "*FAIL*"; print " LAMP, DARK, and FLAT are mutually exculsive in this CAL script.\n"; $flagFAIL = $flagFAIL+1; } }
	elsif($flagDARK==1){
	    if(($MASK!~m/^NB3$/i && $MASK!~m/^ID990031$/i) || $MASK_POSITION!~m/^mask_in_fpu$/i || ($FILTER[0]!~m/^blind$/i || $FILTER[1]!~m/^blind$/i))
	    { print YELLOW "*WARN*"; print " The blind mask and filters must be used with DARK in this CAL script.\n"; $flagWARN = $flagWARN+1; } }
	elsif($flagFLAT==1){
	    if($flagMASK!=0 || $GRATING_UNIT!~m/^mirror$/i || $MASK_POSITION=~m/^mask_in_fpu$/i)
	    { print RED "*FAIL*"; print " FLAT must be setup for imaging (mirror, no mask, etc) in this CAL script.\n"; $flagFAIL = $flagFAIL+1; } } }
    if(($flagLAMP+$flagDARK+$flagFLAT)==1){
	if($tempstring[0]=~m/LBTB/ && $tempstring[0]=~m/INAF/ && $tempstring[0]=~m/OSURC/ && $tempstring[0]=~m/AZ/ && $tempstring[0]=~m/LBTO/
	   && $PROP_ID=~m/Calibration/i){ }
	else{ print YELLOW "*WARN*"; print " For a LAMP, DARK or FLAT, please include all partners in PARTNER string:\n"; 
	      print YELLOW "******"; print " (LBTB,INAF,OSURC,AZ,LBTO) and set PROP_ID to Calibration,\n"; 
	      print YELLOW "******"; print " to help distribute calibration files to everyone.\n"; $flagWARN = $flagWARN+1; } }
    $caltemp=0;
}


##################################################
##################################################

sub GSVIEW {
# This is a copy/paste/edit of OKuhn's 'luciguide.pl' dated June 17th 2010.
# EDIT: this includes the fix for high DEC in Olga's internal distribution of 'lcw.pl' dated Jan 27th 2011.
#       I also added dither plots to region file.
# note that now we include the Math::Trig module, and so i replaced some def's of pi with the pi function

#Syntax: luciguide.pl hh mm ss dd mm ss posangle

# Current caveats from Olga:
#This is still a "work-in-progress". In particular, the line segments are drawn "by-eye" 

my $x0;
my $y0;
my $xp0;
my $yp0;
my $xnew;
my $ynew;
my $x2new;
my $y2new;
my $x3new;
my $y3new;
my $xpnew;
my $angle;
my $pa = 0;
#my $infile;
$regfile;
my $ra_hh;
my $ra_mm;
my $ra_ss;
my $dec_dd;
my $dec_mm;
my $dec_ss;
my $deltxrc = 0.0;
my $deltyrc = 0.0;
#
#box1 = the 4' x 4' LUCIFER FOV
my $b1x0 = 0.; my $b1y0 = 0.; my $b1a0 = 240.; my $b1b0 = 240.; my $b1ang = 359.906;
#
#box2 = the 1' rim around the top portion of the LUCIFER FOV; appears as a box, but disregard the bottom half
my $b2x0 = 0.; my $b2y0 = 0.; my $b2a0 = 360.; my $b2b0 = 360.; my $b2ang = 359.906;
#
#box3 (was line1) = the horizontal line through the LUCIFER FOV. Only consider regions above this.
my $b3x0 = 0; my $b3y0 = 0.0; my $b3a0 = 720; my $b3b0 = 0.0; my $b3ang = 359.906;
#
#line2 = demarcates the AGw r-theta stage theta limit (approximate!)
my $l2x0 = -0.07451246; my $l2y0 = 0.052647868; my $l2x1 = -0.086382723; my $l2y1 = 0.012760314;
#
#line3 = demarcates the AGw r-theta stage theta limit (approximate!)
my $l3x0 = 0.08; my $l3y0 = 0.012288064; my $l3x1 = 0.065; my $l3y1 = 0.065199892;
#
#circle1 = Gregorian Focal Plane 11' diameter
my $c1x = 0.0; my $c1y = 0.0; my $c1r = 330;
#circle2 = AGw r-theta stage radial limit. 
# Circle with center of rotation 612.5mm (1020.8333 arcsec=612.5mm/0.6mm/arcsec) above
# center of LUCIFER detector. Center (0,1028.833) and radius = 1020.8333
my $c2x = 0.0; my $c2y = 0.2835648148; my $c2r = 1020.83333333;

$counter = 0;
$ra_hh = $_[0];
$ra_mm = $_[1];
$ra_ss = $_[2];
$dec_dd = $_[3];
$dec_mm = $_[4];
$dec_ss = $_[5];
$Gra_hh = $_[6];
$Gra_mm = $_[7];
$Gra_ss = $_[8];
$Gdec_dd = $_[9];
$Gdec_mm = $_[10];
$Gdec_ss = $_[11];
$pa= $_[12];

$regfile = "r" . $ra_hh . $ra_mm . $ra_ss . "d" . $dec_dd . $dec_mm . $dec_ss . "PA_" . $pa . ".reg";
open (OUT, ">$regfile") || die "cannot open file $regfile for writing: $!";

#TARGET
$tmp = reverse($dec_dd);
$sign = chop $tmp;
if ($sign eq "-") {
	$decdeg = $dec_dd + ((-1.*$dec_mm + (-1.*$dec_ss/60.))/60.); }
else {  $decdeg = $dec_dd + (($dec_mm + ($dec_ss/60.))/60.); }
$radeg = 15.*($ra_hh + (($ra_mm + ($ra_ss/60.))/60.));
$decrad = $decdeg*pi/180.;

#GUIDE STAR
$Gtmp = reverse($Gdec_dd);
$Gsign = chop $Gtmp;
if ($Gsign eq "-") {
	$Gdecdeg = $Gdec_dd + ((-1.*$Gdec_mm + (-1.*$Gdec_ss/60.))/60.); }
else {  $Gdecdeg = $Gdec_dd + (($Gdec_mm + ($Gdec_ss/60.))/60.); }
$Gradeg = 15.*($Gra_hh + (($Gra_mm + ($Gra_ss/60.))/60.));
$Gdecrad = $Gdecdeg*pi/180.;

printf OUT "# Region file format: DS9 version 4.1\n";
printf OUT "global dashlist=8 3 width=3 font=\"helvetica 10 normal\" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1\n";
#printf OUT "global color=green dashlist=8 3 width=1 font=\"helvetica 10 normal\" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1\n";
printf OUT "fk5\n";
printf OUT "# composite(0,0,0) || composite=1\n";

$newpa = $pa;
$q = pi/180;
$newparad = $newpa*$q; 

# recompute boxes 
# box1 - inner box
$b1xnew = -1*$b1x0 - $deltxrc;
$b1ynew = $b1y0 - $deltyrc;
$b1x2new = cos(-1.*$newparad)*$b1xnew + sin(-1.*$newparad)*$b1ynew;
$b1y2new = -sin(-1.*$newparad)*$b1xnew + cos(-1.*$newparad)*$b1ynew;
$b1x3new = $radeg + -1.*$b1x2new/cos($decrad);
$b1y3new = $decdeg + ($b1y2new);
printf OUT "box(%10.6f,%10.6f,%10.6f\",%10.6f\",%10.6f) # color = cyan\n", $b1x3new, $b1y3new, $b1a0, $b1b0, $newpa;
#
# box2 - warning box
$b2xnew = -1*$b2x0 - $deltxrc;
$b2ynew = $b2y0 - $deltyrc;
$b2x2new = cos(-1.*$newparad)*$b2xnew + sin(-1.*$newparad)*$b2ynew;
$b2y2new = -sin(-1.*$newparad)*$b2xnew + cos(-1.*$newparad)*$b2ynew;
$b2x3new = $radeg + -1.*$b2x2new/cos($decrad);
$b2y3new = $decdeg + ($b2y2new);
printf OUT "box(%10.6f,%10.6f,%10.6f\",%10.6f\",%10.6f) # color = yellow\n", $b2x3new, $b2y3new, $b2a0, $b2b0, $newpa;

# box3 - center cut
$b3xnew = -1*$b3x0 - $deltxrc;
$b3ynew = $b3y0 - $deltyrc;
$b3x2new = cos(-1.*$newparad)*$b3xnew + sin(-1.*$newparad)*$b3ynew;
$b3y2new = -sin(-1.*$newparad)*$b3xnew + cos(-1.*$newparad)*$b3ynew;
$b3x3new = $radeg + -1.*$b3x2new/cos($decrad);
$b3y3new = $decdeg + ($b3y2new);
printf OUT "box(%10.6f,%10.6f,%10.6f\",%10.6f\",%10.6f) # color = white\n", $b3x3new, $b3y3new, ($b3a0/3)*0.94, ($b3b0/3)*0.94, ($newpa+90);

# line 1; assume same pa as for boxes
$l3xnew = -1*$l3x0 - $deltxrc;
$l3ynew = $l3y0 - $deltyrc;
$l3x2new = cos(-1*$newparad)*$l3xnew + sin(-1.*$newparad)*$l3ynew;
$l3y2new = -sin(-1*$newparad)*$l3xnew + cos(-1.*$newparad)*$l3ynew;
$l3x3new = $radeg + -1*$l3x2new/cos($decrad);
$l3y3new = $decdeg + ($l3y2new);
$l3xnew1 = -1*$l3x1 - $deltxrc;
$l3ynew1 = $l3y1 - $deltyrc;
$l3x2new1 = cos(-1*$newparad)*$l3xnew1 + sin(-1.*$newparad)*$l3ynew1;
$l3y2new1 = -sin(-1*$newparad)*$l3xnew1 + cos(-1.*$newparad)*$l3ynew1;
$l3x3new1 = $radeg + -1*$l3x2new1/cos($decrad);
$l3y3new1 = $decdeg + ($l3y2new1);
printf OUT "line(%10.6f,%10.6f,%10.6f,%10.6f) # color = red\n", $l3x3new, $l3y3new, $l3x3new1, $l3y3new1;
#
# line 2; assume same pa as for boxes
$l2xnew = -1*$l2x0 - $deltxrc;
$l2ynew = $l2y0 - $deltyrc;
$l2x2new = cos(-1*$newparad)*$l2xnew + sin(-1.*$newparad)*$l2ynew;
$l2y2new = -sin(-1*$newparad)*$l2xnew + cos(-1.*$newparad)*$l2ynew;
$l2x3new = $radeg + -1*$l2x2new/cos($decrad);
$l2y3new = $decdeg + ($l2y2new);
$l2xnew1 = -1*$l2x1 - $deltxrc;
$l2ynew1 = $l2y1 - $deltyrc;
$l2x2new1 = cos(-1*$newparad)*$l2xnew1 + sin(-1.*$newparad)*$l2ynew1;
$l2y2new1 = -sin(-1*$newparad)*$l2xnew1 + cos(-1.*$newparad)*$l2ynew1;
$l2x3new1 = $radeg + -1*$l2x2new1/cos($decrad);
$l2y3new1 = $decdeg + ($l2y2new1);
printf OUT "line(%10.6f,%10.6f,%10.6f,%10.6f) # color = red\n", $l2x3new, $l2y3new, $l2x3new1, $l2y3new1;
#

# circle 1
$c1xnew = -1*$c1x - $deltxrc;
$c1ynew = $c1y - $deltyrc;
$c1x2new = cos(-1*$newparad)*$c1xnew + sin(-1.*$newparad)*$c1ynew;
$c1y2new = -sin(-1*$newparad)*$c1xnew + cos(-1.*$newparad)*$c1ynew;
$c1x3new = $radeg + -1*$c1x2new/cos($decrad);
$c1y3new = $decdeg + ($c1y2new);
printf OUT "circle(%10.6f,%10.6f,%10.6f\") # color = red\n", $c1x3new, $c1y3new, $c1r;

# circle 2 Chris Willmer's algorithm
$mdeg = 18.5;
$nstep = 2*$mdeg*100;
for ($i = 0; $i <= $nstep ; $i++) {
    $k = -$mdeg+$i/100;
    $angle = ($newpa + $k/100) * $q ;        
    $dxmax = ($c2r/3600) * sin($k*$q);
    $dymax = ($c2r/3600) * (1.0-cos($k*$q));
    ($dra,$ddec) = convert_dx_dy_dra_ddec($dxmax, $dymax, $newpa);
    $rra = $radeg + $dra/cos($decdeg*$q);
    $dde = $decdeg + $ddec;        
    $sline = 'fk5;point('.$rra.','. $dde.') # point=circle 1 color=red';
    print OUT $sline,"\n";
 }

# circle 3 - guide star
print OUT "fk5; circle $Gra_hh:$Gra_mm:$Gra_ss $Gdec_dd:$Gdec_mm:$Gdec_ss 8\"  # color = red width = 5\n";


### DITHER MOVEMENT

$idith=0;
$dithRAsex = "$Gra_hh:$Gra_mm:$Gra_ss"; 
$dithRAdeg = $Gradeg;  #dithered positions
$dithDECsex = "$Gdec_dd:$Gdec_mm:$Gdec_ss";
$dithDECdeg = $Gdecdeg;
$origRAdeg = $Gradeg; #original positions for moves
$origDECdeg = $Gdecdeg;
$startRAdeg = $Gradeg;
$startDECdeg = $Gdecdeg;
$origRAsex = $dithRAsex;
$origDECsex = $dithDECsex;
$detRA = 0; $detDEC = 0;
$jitrad = 0;

# remember, absolute movements are based from original GS coords. relative, are from these dith coords.
# @dither: {movekeyword; coordsys; offsettype; param1; param2; param3}
# offset parameters are in arcseconds

$runsetup = 1; # some poorly written trickery to see if we need to add the offsets from the setup script FIRST.
$runoffset=0;          # runsetup=0 means do acq first. otherwise 1
if($flagSETUPTELESCOPE == 1){ $runsetup = 0; }

#print "$dither[0][0] $dithertemp[0][0]\n";

for($runoffset=$runsetup; $runoffset<2; $runoffset=$runoffset+1){
    @ditheruse = ();                                # clear the array
    if($runoffset==0){ @ditheruse = @dither; }
		       #for($shit=0;$shit<6;$shit++){ print "$dither[0][$shit]\n"; } }     # use current setup script values
    if($runoffset==1){ @ditheruse = @dithertemp; }
    #for($shit=0;$shit<6;$shit++){ print "$dithertemp[0][$shit]\n"; } } # use saved sci script values
 
    for($idith=0;$idith<@ditheruse;$idith=$idith+1){

# ACQUISITION
	if($ditheruse[$idith][0] =~ m/ACQUISITION/i){
	    #if($runoffset!=0){  # because we're not interested in this motion for the setup script	    
		# RADEC
		if($ditheruse[$idith][1] =~ m/RADEC/i){ 
		    if($ditheruse[$idith][2] =~ m/absolute/i){ $origRAdeg = $startRAdeg; $origDECdeg = $startDECdeg; }   # absolute
		    else{ $origRAdeg = $dithRAdeg; $origDECdeg = $dithDECdeg; }                               # relative
		    $dithRAdeg = ($origRAdeg*3600 - $ditheruse[$idith][3]/cos($origDECdeg*$q))/3600;  
		    $dithDECdeg = ($origDECdeg*3600 - $ditheruse[$idith][4])/3600;
		    if($runoffset==1){ print OUT "fk5; circle $dithRAdeg $dithDECdeg 3\"  # color = cyan width = 4\n"; }
		}
		# DETXY
		else{
		    if($ditheruse[$idith][2] =~ m/absolute/i){ $origRAdeg = $startRAdeg; $origDECdeg = $startDECdeg; }   # absolute
		    else{ $origRAdeg = $dithRAdeg; $origDECdeg = $dithDECdeg; }                               # relative		  
		    ($detRA,$detDEC) = convert_dx_dy_dra_ddec($ditheruse[$idith][3]/3600, $ditheruse[$idith][4]/3600, $newpa);
		    $dithRAdeg = $origRAdeg + $detRA/cos($origDECdeg*$q);  $dithDECdeg = $origDECdeg + $detDEC; 		   
		    if($runoffset==1){ #print "ACQ $dithRAdeg $dithDECdeg\n";
				       print OUT "fk5; circle $dithRAdeg $dithDECdeg 3\"  # color = cyan width = 4\n"; }
		} } #}
# JITTER
	elsif($ditheruse[$idith][0] =~ m/JITTER/i){ 
	    #if($runoffset!=0){ # because we're not interested in this motion for the setup script
		# RADEC
		if($ditheruse[$idith][1] =~ m/RADEC/i){ 
		    if($ditheruse[$idith][2] =~ m/absolute/i){ $origRAdeg = $startRAdeg; $origDECdeg = $startDECdeg;      # absolute
							       $jitrad = $ditheruse[$idith][4];
							       if($runoffset==1){ 
								   print OUT "fk5; circle $origRAdeg $origDECdeg $jitrad\" # color = cyan width = 2\n"; } }
		    else{ print "*NOTE* JITTER radius has been omitted from this plot (!absolute).\n"; } } 
		# DETXY
		else{
		    if($ditheruse[$idith][2] =~ m/absolute/i){ $origRAdeg = $startRAdeg; $origDECdeg = $startDECdeg;    # absolute 
							       ($detRA,$detDEC) = convert_dx_dy_dra_ddec($ditheruse[$idith][4]/3600, 0, $newpa);            
							       # trick it to say dRADEC is a pure dx motion.
							       $dithRAdeg = $origRAdeg + $detRA/cos($origDECdeg*$q);  $dithDECdeg = $origDECdeg + $detDEC;   
							       $jitrad = (acos(cos(pi/2-$origDECdeg*pi/180)*cos(pi/2-$dithDECdeg*pi/180) 
									       + sin(pi/2-$origDECdeg*pi/180)*sin(pi/2-$dithDECdeg*pi/180)
									       *cos($origRAdeg*pi/180-$dithRAdeg*pi/180))*180/pi)*3600;  
							       # spherical trig separation of pos.
							       if($runoffset==1){ 
								   print OUT "fk5; circle $origRAdeg $origDECdeg $jitrad\"  # color = cyan width = 2\n"; } }
		    else{ print "*NOTE* JITTER radius has been omitted from this plot (!absolute).\n"; } }
	    } #}
# OFFSET
	elsif($ditheruse[$idith][0] =~ m/OFFSET/i){ 
	    if($ditheruse[$idith][5]==0 || $ditheruse[$idith][5]=~m/^$/){  # IGNORE ROTATIONAL OFFSETS FOR NOW
		# RADEC
		if($ditheruse[$idith][1] =~ m/RADEC/i){ 
		    if($ditheruse[$idith][2] =~ m/absolute/i){ $origRAdeg = $startRAdeg; $origDECdeg = $startDECdeg; }   # absolute
		    else{ $origRAdeg = $dithRAdeg; $origDECdeg = $dithDECdeg; }                               # relative
		    $dithRAdeg = ($origRAdeg*3600 - $ditheruse[$idith][3]/cos($origDECdeg*$q))/3600;  
		    $dithDECdeg = ($origDECdeg*3600 - $ditheruse[$idith][4])/3600;
		   if($runoffset==1){ print OUT "fk5; circle $dithRAdeg $dithDECdeg 3\"  # color = cyan width = 4\n"; }
		}
		# DETXY
		else{
		    if($ditheruse[$idith][2] =~ m/absolute/i){ $origRAdeg = $startRAdeg; $origDECdeg = $startDECdeg; }   # absolute
		    else{ $origRAdeg = $dithRAdeg; $origDECdeg = $dithDECdeg; }                               # relative		  
		    ($detRA,$detDEC) = convert_dx_dy_dra_ddec($ditheruse[$idith][3]/3600, $ditheruse[$idith][4]/3600, $newpa);
		    $dithRAdeg = $origRAdeg + $detRA/cos($origDECdeg*$q);  $dithDECdeg = $origDECdeg + $detDEC;    		    
		    if($runoffset==1){ #print "OFF $dithRAdeg $dithDECdeg $ditheruse[$idith][3] $ditheruse[$idith][4]\n";
				       print OUT "fk5; circle $dithRAdeg $dithDECdeg 3\"  # color = cyan width = 4\n"; }
	        }
	    }  
	    else{ print "*NOTE* Offsets with rotational components have been omitted from this plot.\n"; }
	}    
    }
    if($runoffset==0){ $startRAdeg = $dithRAdeg; $startDECdeg = $dithDECdeg; } # new start position for science script
}
close(OUT);

# now launch ds9 and load USNO-A2 catalog
# dds9 rhh rmm rss ddd dmm dss
$filthi = '\$Rmag>12';
$filtlo = '\$Rmag<16';
system "ds9 -dsssao size 12 12 arcmin -dsssao coord $ra_hh:$ra_mm:$ra_ss $dec_dd:$dec_mm:$dec_ss sexagesimal -catalog nomad -catalog filter \"$filtlo && $filthi\" -catalog size 12 12 arcmin -mode catalog -regions load $regfile &";

}

##################################################
##################################################
### Create array of regionfile entries for dithers

sub DITHER { # movement array for plotting: {movekeyword; coordsys; offsettype; param1; param2; param3}
             # movekeyword = { Acquisition, Jitter, Offset }, with corresponding params
             # acquisition: DX, DY (or DRA, DDEC);  jitter: Nexpo, Radius;  offset: DX, DY, DRot (or DRA, DDEC, RRot)
 
    $dither[$idith][0] = $_[0];
    $dither[$idith][1] = $_[1];
    $dither[$idith][2] = $_[2];
    $dither[$idith][3] = $_[3];
    $dither[$idith][4] = $_[4];
    $dither[$idith][5] = $_[5]; 
    $idith = $idith + 1;

}

##################################################
##################################################
### Convert dX, dY to dRA, dDEC

sub convert_dx_dy_dra_ddec {
   my( $dx, $dy, $pa) = @_ ;
   my( $q)  = pi/180.0;
   my( $dra, $ddec, $cosa, $sina) ;
   $cosa = cos($pa * $q);
   $sina = sin($pa * $q);
   $dra  =  $dx * $cosa + $dy * $sina;
   $ddec = -$dx * $sina + $dy * $cosa;
   return $dra, $ddec ;
  }



##################################################
##################################################
### Convert dec given in degrees to sexagesimal

sub DEGtoSEXAGESIMALDEC{
    my $DECd = 0; my $DECm = 0; my $DECs = 0;
    if ($_[0]=~m/^-.*/){ 
	$DECd = sprintf("%03d",ceil($_[0])); if($DECd=~m/^000$/){ $DECd="\-00"; }
	$DECm = sprintf("%02d",abs(ceil(($_[0]-$DECd)*60)));
	$DECs = sprintf("%05.02f",(((abs($_[0]-$DECd)*60)-$DECm)*60)); }
    else {
	$DECd = sprintf("+%02d",floor($_[0]));
	$DECm = sprintf("%02d",floor(($_[0]-$DECd)*60));
	$DECs = sprintf("%05.02f",(((($_[0]-$DECd)*60)-$DECm)*60)); }
    if($DECs==60){ $DECs=sprintf("%05.02f",0); $DECm = sprintf("%02d",$DECm+1); }
    if($DECm==60){ $DECm=sprintf("%02d",0); 
		   if($DECd<0){ $DECd = sprintf("%02d",$DECd-1); }
		   else{ $DECd = sprintf("+%02d",$DECd+1); }  }    
    return  "$DECd\:$DECm\:$DECs";
}

##################################################
##################################################
### Convert RA given in degrees to sexigesimal

sub DEGtoSEXAGESIMALRA {
    my $DEGin = $_[0];
    if($DEGin<0){ $DEGin =  $DEGin + 360; }
    elsif($DEGin>360){ $DEGin = $DEGin - 360; }
    my $RAh = 0; my $RAm = 0; my $RAs = 0;
    $RAh = sprintf("%02d",floor($DEGin/15));
    $RAm = sprintf("%02d",floor(($DEGin/15-$RAh)*60));
    $RAs = sprintf("%05.02f",(($DEGin/15-$RAh)*60-$RAm)*60);
    if($RAs==60){ $RAs=sprintf("%05.02f",0); $RAm = sprintf("%02d",$RAm+1); }
    if($RAm==60){ $RAm=sprintf("%02d",0); $RAh = sprintf("%02d",$RAh+1); }  
    return  "$RAh\:$RAm\:$RAs";
}








##################################################
##################################################
### check sexegesimal format

sub SEXCHECK_DEC{
    my $dd, $mm, $ss, $deg;
    if($_[0] =~ m/^([+-]?\d{2})(\s+|\:)(\d{2})(\s+|\:)(\d{2}|\d{2}\.\d+|\d{2}\.)$/){
	$dd = $1; $mm = $3; $ss = $5;
	$deg = SEXAGESIMALtoDEGDEC("$dd $mm $ss");
	if($deg<-90.0 || $deg>90.0){ return -1; }
	if($dd<-90.0 || $dd>90.0)  { return -2; }
	if($mm<0.0 || $mm>60.0)    { return -3; }
	if($ss<0.0 || $ss>60.0)    { return -4; }
	else{ return 1; } }
    else{ return -5; } }

sub SEXCHECK_RA{
    my $hh, $mm, $ss, $deg;
    if($_[0] =~ m/^(\d{2})(\s+|\:)(\d{2})(\s+|\:)(\d{2}|\d{2}\.\d+|\d{2}\.)$/){
	$hh = $1; $mm = $3; $ss = $5;
	$deg = SEXAGESIMALtoDEGRA("$hh $mm $ss");
	if($deg<0.0 || $deg>360.0){ return -1; }
	if($hh<0.0 || $hh>24.0)  { return -2; }
	if($mm<0.0 || $mm>60.0)    { return -3; }
	if($ss<0.0 || $ss>60.0)    { return -4; }
	else{ return 1; } }
    else{ return -5; }
}

##################################################
##################################################
### Convert RA given in sexagesimal to degrees

sub SEXAGESIMALtoDEGRA{
    if($_[0] =~ m/(^\d{2}) (\d{2}) (\d{2}\.\d+$|\d{2}\.$|\d{2}$)/ ){
	return $1 * 15 + $2 * 0.25 + $3 / 240; }
    elsif($_[0] =~ m/(^\d{2}):(\d{2}):(\d{2}\.\d+$|\d{2}\.$|\d{2}$)/){
	return $1 * 15 + $2 * 0.25 + $3 / 240; }
    elsif($_[0] =~ m/(^\d{2})h(\d{2})m(\d{2}\.\d+$|\d{2}\.$|\d{2})s$/ ){
	return $1 * 15 + $2 * 0.25 + $3 / 240; }
    else{ return -1; }
}


##################################################
##################################################
### Convert DEC given in sexagesimal to degrees

sub SEXAGESIMALtoDEGDEC{
    my $out;
    if($_[0] =~ m/(^[+-]?\d{2}) (\d{2}) (\d{2}\.\d+$|\d{2}\.$|\d{2}$)/ ){
	$out = abs($1)  + $2/60 + $3/3600; 
	if($1=~m/^-.*/){ return  -$out; }
	elsif($1 >= 0){ return  $out; } }
    elsif($_[0] =~ m/(^[+-]?\d{2})\:(\d{2})\:(\d{2}\.\d+$|\d{2}\.$|\d{2}$)/){	
	$out = abs($1)  + $2/60 + $3/3600; 
	if($1=~m/^-.*/){ return  -$out; }
	elsif($1 >= 0){ return  $out; } }
    elsif($_[0] =~ m/(^[+-]?\d{2})d(^\d{2})m(\d{2}\.\d+$|\d{2}\.$|\d{2})s$/ ){
	$out = abs($1)  + $2/60 + $3/3600; 
	if($1=~m/^-.*/){ return  -$out; }
	elsif($1 >= 0){ return  $out; } }
    else{ return -1; }
}

##################################################
##################################################
