#!/usr/bin/env expect

##################################################################################
#
#  Copyright (C) 2008-2012 Craig Miller
#
#  Copyright (C) 2005-2007 Freescale Semiconductor, Inc. 
#
#  See the file "COPYING" for information on usage and redistribution
#  of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#  Distributed under BSD-Style License
#
##################################################################################
#
#
# Expect-lite 
# Script logs into Remote-host, sends command file, while validating commands
#	fails if validation fails, returns code 1 (0=passed)
#
# by Craig Miller cvmiller@gmail.com	19 Jan 2005
#
# Command Arguments:
#	<Remote-Host|IP>
#	<command_file>
#	<user_directory>
#	[additional constants, see usage]
#
#
# Requires Expect version supported 5.42.1 and later (although earlier versions may work)
#
#
#
#

##################################################################################
#	
#	The user may want to customize the following variables & procs to suite one's needs
#
#

# Encapsulate expect-lite variables in a namespace to prevent collisions with other apps
namespace eval expectlite {

	# echo version in usage
	variable version "4.6.2"

	#set starting expect timeout 
	set ::timeout 10 

	# EL_LIBRARY when set, places expect-lite in library mode,
	# used for TCL programming calling expect-lite functions directly
	# see documentation for more info
	# Normally, this would be UNSET (or commented out)
	#set EL_LIBRARY 1

	# infinite_loop protection - Max number of looping permitted
	#	Protects against infinite loops by decrementing this number
	#	when value is Zero, _el_buffer_search will return 'not found' (-1)
	# typically this should be set in the range of 5000-10000
	variable _el_infinite_loop 5000


	# hardcoded login values - only used for telnet, and ssh logins
	variable user "root"
	variable pass ""
	# User is now used by ssh_key method as well. If user is blank then the default
	#	user will be used (the user running the script). However if $user is defined
	#	then ssh_key will use the following command: ssh $user@$host
	variable user ""


	# Print Warnings to stdout (when set to 1 = TRUE, 0 = FALSE)
	variable WARN 1

	# Print Info messages to stdout (when set to 1 = TRUE, 0 = FALSE)
	variable INFO 1

	# Print Expect Info messages to stdout (when set to 1 = TRUE, 0 = FALSE)
	variable EXP_INFO 0

	# Select remote shell to spawn after logging into remote host 
	variable remote_shell "bash"
	variable remote_shell ""

	# Delay (in ms) to wait for host in Not Expect, and Dynamic Var Capture
	# 100 ms is a good value for a local LAN, 200 ms if running across high speed internet
	variable delay_wait_for_host 100

	# connects to login host, and logs in as $USER
	#
	#	Choose one login method here
	#	
	#set connect_method "telnet" 
	#set connect_method "ssh" 
	#set connect_method "ssh_key" 
	variable connect_method "none" 

	# Accept SSH host keys
	variable connect_ssh_accept_host_key "-o StrictHostKeyChecking=no"
	variable connect_ssh_accept_host_key ""


	# Path to telnet (helps in cygwin environments)
	variable _el_telnet "/usr/bin/telnet"

	# set the user configurable prompt to something sane
	set ::expectlite::_el(prompt) ".*\$ $"

	# set global color for comment ; or ;; lines
	# select one of the following: none, blue, ltblue, gray, ltgray, cyan, black, pink, purple
	variable _el_comment_color ltblue

	# End of Line Sequence (eols) - typically \n or \r\n
	# some devices must have a CRLF at the end of line in order to respond
	# This is also controlled by directive *EOLS LF|CRLF
	variable _el_eols "\n"


	####################################################################################
	#	
	#	Vars & Procs below here should not require customization
	#
	#


	#
	#	Provide info for library mode
	#
	package provide expect-lite 4.0


	#
	#	Initialization of Global Variables
	#
	proc _el_init_globals { } {

		#set ::expectlite::_el_timeout to hold value of timeout (used to preserve value of timeout)
		variable _el_timeout $::timeout

		#set ::expectlite::the expect Match Buffer really large
		match_max -d 10000

		#Create Debug Log output == 1, no log ==0
		variable DEBUG_LOG 0

		# declare array user_namespace (for user vars)
		set ::expectlite::user_namespace(0) 0

		# declare array cli_namespace (for cli passed constants)
		set ::expectlite::cli_namespace(#) " "

		# declare array cli_namespace (for cli passed constants)
		set ::expectlite::cli_namespace(EL_CONNECT_METHOD) "none"

		# declare global array _el (for internal expect-lite vars)
		set ::expectlite::_el(0) 0

		# clear NOFAIL flag 1=test should have failed
		set ::expectlite::_el(test_failed) 0 

		# clear native expect lines list
		set ::expectlite::_el(_el_lines) {}

		# clear ide paste lines flag
		set ::expectlite::_el(ide_paste_lines) 0
		
		# initialize the command file name
		set ::expectlite::_el(cmd_file) ""
		
		# debugging aid: turn on to display match string and expect buffer
		variable DEBUG 0

		# timestamp on send: turn on to display timestamp when sending > or >>
		variable TIMESTAMP 0

		# keep script running to end: turn on to never fail test
		variable NOFAIL 0

		# clear NOINTERACT flag 0=allow interact, >0 skip interact
		variable NOINTERACT 0

		# clear NOINCLUDE flag 0=allow include files, >0 skip include files
		# this is backward compatibility option for 4.1 library behaviour
		variable NOINCLUDE 0

		# clear LOG flag 0=no log, 1 logging
		variable LOG 0

		# global constant for timeout_multiplier mode
		variable timeout_multiplier "timeout_multiplier"

		# global constant for script name aka arg0
		variable arg0 "arg0"
		
		# global flag show_help - displays help if set
		variable SHOW_HELP 0

		# set ::expectlite::global fork count (for multiple sessions) to 0
		set ::expectlite::_el(fork_count) 0

		# set ::expectlite::global fork stack to blank
		set ::expectlite::_el_fork_stack {}

		# set ::expectlite::global fork id list to blank
		set ::expectlite::_el_fork_id_list { }

		# set ::expectlite::default FORK session
		set ::expectlite::_el(fork_current) "default"

		# set ::expectlite::current FORK session
		variable _el_current_session ""

		# set ::expectlite::default fork_context to default end-of-line-sequence (eols)
		set ::expectlite::_el_fork(default,eols) $::expectlite::_el_eols

		#
		# Scripts (aka Command files) are kept in buffers for random access, and looping
		# Buffers are global, and are referenced by a "stack" number, the stack number allows multiple buffers to exist
		#
		# stack which contains list of valid buffers
		set ::expectlite::_el_buf(stack) "0"
		# buffer which contains  help text
		set ::expectlite::_el_buf(help) {}
		# buf pointer - contains line number of buffer
		set ::expectlite::_el_buf(0,ptr) "0"
		# block line stack. used when reading into buffer blocks of lines
		set ::expectlite::_el_buf_block_stack {}

		# expect-lite key characters (first char in expect-lite script)
		variable _out ">"
		variable _out_nowait ">>"
		variable _in "<"
		variable _in_noregex "<<"
		variable _not_in "-<"
		variable _timeout "@"
		variable _exec "!"
		variable _stdout_comment ";"
		variable _stdout_comment_nobuf ";;"
		variable _include "~"
		variable _include_fail "\\\*~"
		variable _setvar "+"
		variable _var "\$"
		variable _cond_regex "\\\?"
		variable _cond "?"
		variable _cond_else "::"
		variable _label "%"
		variable _incr_var "\\\+\\\$"
		variable _decr_var "\\-\\\$"

		# cli Parameter Initialization
		variable remote_host "none"
		variable cmd_file ""
		variable user_dir ""
		# default logging extension
		variable el_log_ext ".log"

		# set ::expectlite::the default user configurable prompt to something sane
		set ::expectlite::_el(default_prompt) ".*\$ $"

		# set ::expectlite::ANSI colors for colored output
		set ::expectlite::el_color(red) "\033\[1;31m"
		set ::expectlite::el_color(blue) "\033\[0;34m"
		set ::expectlite::el_color(ltblue) "\033\[1;34m"
		set ::expectlite::el_color(black) "\033\[0;30m"
		set ::expectlite::el_color(cyan) "\033\[0;36m"
		set ::expectlite::el_color(gray) "\033\[1;30m"
		set ::expectlite::el_color(ltgray) "\033\[0;37m"
		set ::expectlite::el_color(green) "\033\[0;32m"
		set ::expectlite::el_color(yellow) "\033\[0;33m"
		set ::expectlite::el_color(purple) "\033\[0;35m"
		set ::expectlite::el_color(pink) "\033\[1;35m"
		set ::expectlite::el_color(nocolor) "\033\[0m"
		set ::expectlite::el_color(left_angle) "<"
		set ::expectlite::el_color(none) ""

		# set ::expectlite::INFO color
		variable _el_info_color green
		# set ::expectlite::WARN color
		variable _el_warn_color yellow
		# set ::expectlite::ERROR color
		variable _el_err_color red
		# set ::expectlite::debug color
		variable _el_debug_color gray

		# el_exec vars
		variable comment_line ""
		variable timeout_line ""
		
		# 
		#	Expect Signal Handler, which checks for broken stdout pipe
		#	Default signal is SIGPIPE
		#
		#
		trap {
			catch { puts stderr "\nERROR:Broken Pipe\n" }
			exit 2
		} SIGPIPE


		# 
		#	Expect Signal Handler, checks ^C and exits except inside an IDE paste
		#	Default signal is SIGINT
		#
		#
		trap {
			if { $expectlite::_el(ide_paste_lines) } {
				catch { puts stderr "\nPress ^\\ to interupt... returning to instant-interact\n" }
				# flush the paste buffer
				catch { expectlite::_el_buffer_stack_clear $expectlite::_el_buf(stack) } error
				expectlite::instant_interact_sig
			} else {
				catch { puts stderr "\nexpect-lite: Interrupt received, exiting...\n" }
				exit 2
			}
		} SIGINT
		# 
		#	Expect Signal Handler, which places user into instant-interactive(tm) session
		#	Default signal is SIGQUIT or ^\
		#
		#
		trap {
			# check if app has output redirected using istty()
			if {[catch {fconfigure stdout -mode}]} {
    			puts stderr "expect-lite: Warning: Output is redirected from tty.\n The script quit unexpectantly.\n"
			} 

			if { $expectlite::_el(ide_paste_lines) } {
				catch { puts stderr "\nreturning to instant-interact...\n" }
				# flush the paste buffer
				catch { expectlite::_el_buffer_stack_clear $expectlite::_el_buf(stack) } error
			}
			expectlite::instant_interact_sig
		} SIGQUIT

	}

	#
	#	Removes colour if terminal type is not xterm, vt100, cygwin
	#	
	#
	proc check_term_type { } {
		global  env
		upvar expectlite::_el_comment_color 		_el_comment_color
		upvar expectlite::el_color 					el_color
		upvar expectlite::_el_info_color			_el_info_color
		upvar expectlite::_el_warn_color			_el_warn_color
		upvar expectlite::_el_err_color 			_el_err_color

		#disable global comment color if unknown
		if { [lsearch [array names el_color] $_el_comment_color] == -1 } {
			set _el_comment_color none
		}
		
		if { [catch { switch -glob -- $env(TERM) {
			"xterm"		-
			"xterm-color"		-
			"vt100"		-
			"vt220"		-
			"ansi"		-
			"cygwin"	{ 
				# keep colors as set globally
				set el_color(left_angle) "<"
			 }
			 "www"		-
			 "web"		-
			 "WEB"		-
			 "Web"		{
			 	# set colors to HTML values
				set el_color(red) "<span style=\"color:red\">"
				set el_color(blue) "<span style=\"color:blue\">"
				set el_color(ltblue) "<span style=\"color:aqua\">"
				set el_color(black) "<span style=\"color:black\">"
				set el_color(cyan) "<span style=\"color:#00FFFF\">"
				set el_color(gray) "<span style=\"color:gray\">"
				set el_color(ltgray) "<span style=\"color:silver\">"
				set el_color(green) "<span style=\"color:green\">"
				set el_color(yellow) "<span style=\"color:yellow\">"
				set el_color(purple) "<span style=\"color:purple\">"
				set el_color(pink) "<span style=\"color:#FF69B4\">"
				set el_color(nocolor) "</span>"
				set el_color(left_angle) "&#60;"
			 }
			 default {
				# set INFO color
				set _el_info_color none
				# set WARN color
				set _el_warn_color none
				# set ERROR color
				set _el_err_color none
				# set global color
				set _el_comment_color none		 	
			 }
		} } \
		error ] } {
			puts "Warning: No Terminal Type defined: $error"
			# set INFO color
			set _el_info_color none
			# set WARN color
			set _el_warn_color none
			# set ERROR color
			set _el_err_color none
			# set global color
			set _el_comment_color none		 	
			set el_color(left_angle) "<"

		}
	}

	#
	#	Wraps puts in selected global colour 
	#	
	#
	proc cputs { str  {l_color ""} {newline ""}} {
		upvar expectlite::el_color 					el_color
		upvar expectlite::_el_info_color			_el_info_color
		upvar expectlite::_el_warn_color			_el_warn_color
		upvar expectlite::_el_err_color 			_el_err_color
		upvar expectlite::_el_comment_color 		_el_comment_color
		upvar expectlite::LOG 						LOG

		proc protect_puts { str } {
			upvar LOG 	LOG
			upvar newline NL
			
			if {$NL != "-nonewline"} {			
				# catch stdout errors and quit
				if { [catch { puts $str } error] } {
					puts stderr "ERROR:$error"
					exit 1
				}
				# Log to file
				if { $LOG } {send_log "$str\n"}
			} else {
				# catch stdout errors and quit
				if { [catch { puts -nonewline $str } error] } {
					puts stderr "ERROR:$error"
					exit 1
				}
				if { $LOG } {send_log "$str"}
			}
		}


		if {$_el_comment_color == "none"} {
			# use no color
			protect_puts $str	
		} elseif { $l_color != "" } {	
			# use supplied color
			protect_puts "$el_color($l_color)$str$el_color(nocolor)"
		} elseif {$_el_comment_color != "none"} {
			# use global color
			protect_puts "$el_color($_el_comment_color)$str$el_color(nocolor)"
		} 

	}


	# 
	#	Interact help
	#	
	#
	#
	proc interact_help { } {
		send_user "\n"
		send_user "IDE: Help\n"
		send_user "  Key          Action\n"
		send_user "  ----        ------\n"
		send_user "  <esc>s      Step\n"
		send_user "  <esc>k      sKip next step\n"
		send_user "  <esc>c      Continue\n"
		send_user "  <esc>v      show Vars\n"
		send_user "  <esc>0to9   Show N next lines of script\n"
		send_user "  <esc>-1to-9 Show N previous lines of script\n"
		send_user "  ctrl+D      Quit & Exit expect-lite\n"
		send_user "  <esc>h      this Help\n"
		#send_user "\n"
		return
	}



	# 
	# 
	#	Actual Signal Handler, which places user into instant-interactive(tm) session
	#	Default signal is SIGQUIT or ^\
	#	This function is also called by *INTERACT, providing similar functionality
	#
	proc instant_interact_sig {} {
		global expect_out errorInfo
		upvar expectlite::remote_host		remote_host
		upvar expectlite::_el				_el
		upvar expectlite::DEBUG 			DEBUG
		upvar expectlite::NOFAIL			NOFAIL
		upvar expectlite::_el_info_color	_el_info_color
		upvar expectlite::_el_eols			_el_eols
		upvar expectlite::_el_buf			_el_buf
		upvar expectlite::_el_warn_color	_el_warn_color
		upvar expectlite::_el_err_color	_el_err_color


		# return if called during a IDE paste
		if {$_el(ide_paste_lines)} {
			return
		}

		# change user message depending on how the function is called
		if { $_el(line) != "*INTERACT" } {
			# called by user 
			cputs  "\n\n Press '+++' to end instant-interact & return to script \n\n" $_el_info_color
		} else {
			# called by script *INTERACT
			cputs  "\n\n Press '+++' to end interact session & return to script \n\n" $_el_info_color
		}
		# do not allow script to fail during IDE
		incr NOFAIL
		protected_send "$_el_eols"
		# preserve script fork session
		push_session_id $_el(fork_current)
		set restart_interact 1
		# restart interact if *FORK is called to set to new spawn_id

		# Check that expect version is supported, if not issue warning
		if { [exp_version] < "5.42.0" } {
			cputs "Warning: Paste feature requires Expect version 5.42 or later (but using [exp_version])" $_el_err_color
			cputs "  See Cygwin documentation on http://expect-lite.sf.net/ on upgrading expect\n" $_el_err_color
			protected_send "$_el_eols"
		}

		while {$restart_interact} {
			# Interact session connects user to remote session, and also:
			#	Interprets expect-lite commands and directives (as of 4.0)
			# reset paste lines flag
			set _el(ide_paste_lines) 0
			if { [catch { interact {
				-re {\+\+\+|^\x1b\x63|^`c} { #DEBUGGER '+++' or .c to exit interact session, continue script
					set restart_interact 0
					set _el(ide_paste_lines) 0
					return 
					}
				\004	{ # ^D exit interact and expect-lite
					puts "\nExiting interact & expect-lite.\n"
					exit 
					}
				-reset \007	{ # ^G show lines with meta-data
					puts "Current Stack---->$_el_buf(stack)"
					_el_buffer_show 20 $_el_buf(stack) 1
					send "\n"
					#puts "Infinite loop count: $expectlite::_el_infinite_loop"
					return 
					}
				-re {(^\x1b|`)(s|k)}	{ #DEBUGGER .s=Next Step, k=skip step
					# determine next or skip step
					set param "s" ; # set default to step
					catch { set param "$interact_out(2,string)" } error 

					# increment buffer line pointer 
					incr _el_buf($_el_buf(stack),ptr)
					# read line from buffer
					set line  [ _el_buffer_read  $_el_buf($_el_buf(stack),ptr) $_el_buf(stack) ]
					set line_meta  [ _el_buffer_read  $_el_buf($_el_buf(stack),ptr) $_el_buf(stack) 1]
					#puts "==BUF====>$_el_buf($_el_buf(stack),ptr)|$line|$line_meta\n"

					switch -regexp -- $line { 
						{^\*INT}	{ 
								# skip interact lines
								cputs "$line"  $_el_info_color
								protected_send "$_el_eols"
							}
						{^\*FORK}	{ 
								# Allow interact to return, since it hangs onto old session
								if { $param == "k" } {
									cputs "Skipping:$line"  $_el_info_color
									protected_send "$_el_eols"
								} else {
									cputs "$line" $_el_info_color
									_el_script_exec "\|$line"  $_el_buf(stack)
									# allow interact to return, for new/changed session
									return
								}
							}
						^\!	{	# Send prompt after native expect lines
								if { $param == "k" } {
									cputs "Skipping:$line"  $_el_info_color
									protected_send "$_el_eols"
								} else {
									cputs "$line" $_el_info_color
									_el_script_exec "\|$line"  $_el_buf(stack)
									# kick the prompt
									protected_send "$_el_eols"

								}
							}
						^\>	{	# send line out and clump any following lines with < or +$
								# clear clump list
								set cli_list ""
								# add lines to clump
								while {$line!=-1} {
									lappend cli_list $line 
									incr _el_buf($_el_buf(stack),ptr)
									# read line from buffer
									set line  [ _el_buffer_read  $_el_buf($_el_buf(stack),ptr) $_el_buf(stack) ]
									#puts "===L==>$line"
									# is line part of clump: expect, dynvar, not-expect
									if {[regexp {^\<|^\+\$|^\-\<} $line] == 0} {
										#No more clump, roll back pointer
										incr _el_buf($_el_buf(stack),ptr) -1
										set line -1
									}
								}					
								# send clump to _el_script_exec
								#send_user "=====>$cli_list||$_el_buf(stack)"
								foreach item $cli_list {
									if { $item != "" } {
										if { $param == "k" } {
											cputs "Skipping:$item"  $_el_info_color
											protected_send "$_el_eols"
										} else {
											# execute next step
											cputs "$item"  $_el_info_color
											_el_script_exec "\|$item" $_el_buf(stack)
										}
									}
								}

								# end clump send
							}
						^\~	{	# include a file
								if { $param == "k" } {
									cputs "Skipping:$line"  $_el_info_color
									protected_send "$_el_eols"
								} else {
									cputs "$line"  $_el_info_color
									# kick the prompt
									protected_send "$_el_eols"
									_el_script_exec "\|$line"
								}
							}
						{^\?.+\?}	{  # if with code block
								#{^\?.+\?.+\[}
								if { $param == "k" } {
									cputs "Skipping:$line"  $_el_info_color
									protected_send "$_el_eols"
								} else {
									cputs "$line"  $_el_info_color
									# kick the prompt
									protected_send "$_el_eols"
									# does this line have a jump-to-label?
									# run if statement with $_el_buf(stack) context
									set retcode [_el_script_exec "\|$line"  $_el_buf(stack)]
									#puts "=====>$retcode|$line|$line_meta"
									# retcode 1 = result true, 0 = result false
									# jump past code block
									if {$retcode == 1 } {
										# else action
										if {[regexp {^\?.+\?.+::[ ]*\[} $line ]} {
											_el_buffer_goto [expr $line_meta ] $_el_buf(stack)
										}
									} else {
										# action
										if {[regexp {^\?.+\?[^:]*\[} $line ]} {
											_el_buffer_goto [expr $line_meta ] $_el_buf(stack)
										}
									}
									# kick the prompt
									protected_send "$_el_eols"
								}
							
							}
						^\\\[	{	# begining while block
								if { $param == "k" } {
									cputs "Skipping:$line"  $_el_info_color
									protected_send "$_el_eols"
								} else {
									cputs "$line"  $_el_info_color
									# kick the prompt
									protected_send "$_el_eols"
									set retcode [ _el_script_exec "\|$line" ]
									# retcode 1 = result true, 0 = result false
									if {$retcode == 1 } {
										# continue the loop
										#set _el_buf($_el_buf(stack),ptr) [expr $line_meta - 1]
									} else {
										# make the jump passed while loop
										_el_buffer_goto [expr $line_meta ] $_el_buf(stack)
									
									}
									# kick the prompt
									protected_send "$_el_eols"
								}
							}
						^\\\]	{	# end while block
								if { $param == "k" } {
									cputs "Skipping:$line"  $_el_info_color
									protected_send "$_el_eols"
								} else {
									cputs "$line"  $_el_info_color
									# make the jump
									_el_buffer_goto [expr $line_meta - 1 ] $_el_buf(stack)
									# kick the prompt
									protected_send "$_el_eols"
								}
							}
						"-1" {
								cputs "End of File" $_el_warn_color
							}
						default {
								if { $param == "k" } {
									cputs "Skipping:$line"  $_el_info_color
									protected_send "$_el_eols"
								} else {
									cputs "$line" $_el_info_color
									#puts "---->$::spawn_id"
									set _el_result [ _el_script_exec "\|$line"  $_el_buf(stack)]
									
									
									if {$_el_result == 1 } {
										# step failed? kick the prompt
										protected_send "$_el_eols"
									}
								}


							}
						}
					}
				-re {^(\x1b|`)([-]?[0-9])} {	#DEBUGGER .-1to9 Show next or last 1-9 lines
						# .1to9 or .-1to9
						#send_user "=====>[scan $interact_out(0,string) %c]|$interact_out(0,string)"
						#catch { set param "$interact_out(1,string)" } error 
						catch { set param "$interact_out(2,string)" } error 

						_el_buffer_show $param $_el_buf(stack)
						protected_send "$_el_eols"
					}
				-re {^\x1bv|`v} {	#DEBUGGER .v Show Vars
						show_vars
						protected_send "$_el_eols"
					}
				-re {\x1bh|`h} {	#DEBUGGER .h Show help
						interact_help
						protected_send "$_el_eols"
					}
				-echo -re  {^(>[a-zA-Z0-9/$.]|\?[iI][fF]|\$[a-zA-Z0-9]|~[a-zA-Z0-9]|;|\*[A-Z]|\+\$|=\$|%[A-Z]|\[ )(.+)\r|(^@[0-9]+\r)|(\]\r)} {
						#### Support for EL commands in Interact
						#### Permits pasting of multiple commands into Interact session
						#### test for expect version - 5.26 does not paste
						# create list of multiple pasted commands
						set cli_list [split $interact_out(0,string) "\r"]
						
						# OS identification - .dll or "" = Cygwin, .so=Linux, .dylib=MacOS X
						set os_id [info sharedlibextension]
						if { $os_id == ".dll" || $os_id == "" } {
							# Special expect to pick up Cygwin Pasted lines, which come one at a time
							while 1 {
								expect_user {
									-re {(.+)\r} {
										# strip newlines and add to cli_list
										regsub {\n|\r|\r\n} $expect_out(1,string) "" cli_item
										lappend cli_list $cli_item
										} 
									-timeout 1 timeout { break }
									-re \003 {puts "\nAck!\n"; exit 1}
									}
								}
								# end while
						}
						# remove extraneous end of lines (paste into putty from windows)
						regsub {\n|\r|\r\n} $cli_list "" cli_list
						#end if os_id
						# clear line of pasted text
						send_user "                                                                      \r"
						# signal to paste lines outside of interact loop
						set _el(ide_paste_lines) 1
						return
					}
				} }  \
			 error] } {
				puts stderr "CONNECT ERROR: lost connection to $remote_host \n   $error \n $errorInfo"
				# Fail script?
				exit 1
			}
			if {$_el(ide_paste_lines)} {
				if {$DEBUG} {
					send_user "\nDEBUG: Evaluating:\n"
					foreach d_item $cli_list {
						send_user "\t$d_item\n"
					}
				}
				#send_user "\n=====>$cli_list\n"

				# special case of one line: if jump to label
				set _buf_ptr [lsearch -regexp $cli_list {\?.+\?.*%} ]
				if { $_buf_ptr == 0} {
					# get line from paste input, and execute if-jump-to-label in main script
					set _line [lindex $cli_list $_buf_ptr]
					_el_script_exec "\|$_line"  $_el_buf(stack)
				} else {
					# multiple lines pasted, treat as small script
					# pasted lines operate in own paste buffer, 
					# and can not access lines (via jumping) in main script

					# assign meta-data to list
					set i 0
					# clear the block stack
					_el_buffer_block_clear

					set paste_buf_ptr [ _el_buffer "" $cli_list ]

					protected_send "$_el_eols"
					# call el script exec
					set rtncode [ _el_script_exec "" $paste_buf_ptr ]
					
					if { $paste_buf_ptr == $_el_buf(stack) } {
						# clear list in buffer stack and pop stack number if not popped
						_el_buffer_stack_clear $expectlite::_el_buf(stack)
					}
				}; #endif
			
			}; #endif paste lines
			protected_send "$_el_eols"
		}; #end while
		
		# restore script session
		session_id_manager [ pop_session_id ]
		set _el(success) 1
		protected_send "$_el_eols"
		# restore NOFAIL
		incr NOFAIL -1

	}


	#
	#	Prompts are always a problem, this should _not_ require customization with the
	#	addition of User Defined Prompts '*/some_regex/' as of version 3.1.5
	#	These prompt regexs are setup to take just about any non-color prompt: >#%$
	#
	#
	proc wait_for_prompt { } {
		global timeout expect_out
		upvar expectlite::_el_warn_color		_el_warn_color
		upvar expectlite::_el_debug_color		_el_debug_color
		upvar expectlite::WARN					WARN
		upvar expectlite::DEBUG					DEBUG
		upvar expectlite::_el					_el
		
		#Accept '>' '#' '%' or '$' prompt
		if { $timeout == 0 } {
			# delay in ms
			after 50
		}
		set TIMEOUT_RETURN 0
		# User Defined prompt is $_el(prompt)
		if {[catch { expect { 
			-re "$_el(prompt)" { } 
			-re ".*> $" { } 
			-re ".*# $" { } 
			-re ".*% $" { } 
			-re {.*\$ $} { } 
			timeout { 
				if {$WARN} { cputs "Warning:Prompt Timed Out!" $_el_warn_color} 
				set TIMEOUT_RETURN 1
				# is user defined prompt being used?
				if { $_el(default_prompt) != $_el(prompt)} {
					if {$DEBUG} {
						# gobble as much return text as possible
						expect -notransfer -re ".*\n+" { }
						# print out debug info to help user 
						cputs "DEBUG: User Defined Prompt:<<$_el(prompt)>>" $_el_debug_color
						cputs "  Not Found in<<$expect_out(buffer)>>" $_el_debug_color
					}
				}

				} } } \
			error ] } {
				puts "\nERROR: $error: Bad User Defined Prompt: $_el(prompt)"
				# Quit expect-lite
				exit 1
		}
		if {$TIMEOUT_RETURN} { return 1 } else { return 0 }

	}




	#
	#	Print Usage
	#	
	#
	proc usage {} {
		upvar expectlite::version version
		puts " "
		puts "usage: expect-lite -c <command_file> \[ -r <remote_host_IP>\] \[-d <user_dir>\] \\ "
		puts "              \[const1=value1\] \[*DIRECTIVE\]"
		puts "   eg. ./expect-lite -c pm_alt.elt -r host8 -d /home/sw myvar=myvalue *NOFAIL"
		puts " "
		puts "   additional login options: -u <username>  -p <password>"
		puts "   eg. ./expect-lite -c pm_alternation.elt -r host-008 -u superuser -p mysecret"
		puts " "
		puts "   additional logging options: -V|-v|-vv|-vvv"
		puts "        -V    prints \'expected\' lines   (i.e lines beginning with < & << )"
		puts "        -v    prints info and warnings  (i.e. conditionals,dynamic vars)"
		puts "        -vv   prints warnings and debug (i.e. expect match info) "
		puts "        -vvv  prints info, warnings and debug "
		puts "   eg. ./expect-lite -vv -r host8  -c pm_alt.elt "
		puts " "
		puts "If set, environment variables starting with EL_ will be used "
		puts "   See man page or documentation for full list of env vars"
		puts " "
		puts "   Version $version by Craig Miller"
		exit 0
	}


	#
	#	Initializes Library function of expect-lite
	#	Pass in values for Constants and Directives (cli_str)
	#	Set library_mode, and connect to bash
	#
	proc _el_init_library { {cli_str ""} } {

		# script will core dump if libexpect is wrong version
		#puts "tclsh version:[info patchlevel]|[info tclversion]"

		if { [ catch {[package present Expect] } error ]} {
			#puts $error
			if { [info tclversion ] != "8.5" } {
				# check tclsh version before loading libexpect 
				puts "ERROR:tclsh version mismatch with libexpect, expected version 8.5, using tclversion:[info tclversion ]" 
				exit 1
			}
			package require Expect
		} 

		# test expect extensions
		if {[ catch { send_user "libexpect loaded\n"}  error ]} {
			puts "ERROR: libexpect not loaded \n$error\n"
			exit 1
		}

		# load el globals
		_el_init_globals

		# set el library mode
		set ::EL_LIBRARY 1
		# ignore *INTERACT directive
		set expectlite::NOINTERACT 10


		# Read arguments to el_lib and call el_read_args
		# count words on cli_str
		set argc [llength [split $cli_str " "]]
		_el_read_args $argc $cli_str

		# spawn to bash for now
		#_el_connect_localhost ""
	}


	#
	#	Imports expect-lite constants into expect-lite
	#	Pass in values for Constants and Directives (cli_str)
	#	Can be called multiple times, values are additive
	#
	proc _el_import_const { {cli_str ""} } {

		# Read arguments to el_lib and call el_read_args
		# count words on cli_str
		set argc [llength [split $cli_str " "]]
		_el_read_args $argc $cli_str

	}


	#
	#	Takes full command path+file, and returns just the file name minus path
	#	
	#
	proc parse_cmd_file_nopath { cmd_file } {
		# Is there a path component?
		if {[regexp {/} $cmd_file] == 1 } {
			set temp_list [split $cmd_file '/']
			set len [expr [llength $temp_list] - 1 ]
			return [lindex $temp_list $len]
		} else {
			return $cmd_file
		}
	}

	#
	#	Assign cli arguments to the variable names
	#	Requires that $remote_host and $cmd_file are passed in via cli or
	#	that shell enviroment vars be set prior to running
	#		EL_REMOTE_HOST
	#		EL_CMD_FILE
	#		EL_USER_DIR
	#		EL_CONNECT_METHOD
	#		EL_CONNECT_USER
	#		EL_CONNECT_PASS
	#		EL_LOG_EXT
	#		EL_INFINITE_LOOP
	#		EL_DELAY_WAIT_FOR_HOST
	#		EL_SHELL
	#
	proc _el_read_args { argc argv } {
		global env
		upvar expectlite::remote_host			remote_host
		upvar expectlite::cmd_file				cmd_file
		upvar expectlite::user_dir				user_dir
		upvar expectlite::connect_method		connect_method
		upvar expectlite::user					user
		upvar expectlite::pass					pass
		upvar expectlite::delay_wait_for_host 	delay_wait_for_host
		upvar expectlite::_el_infinite_loop 	_el_infinite_loop
		upvar expectlite::remote_shell 			remote_shell
		upvar expectlite::cli_namespace			cli_namespace
		upvar expectlite::timeout_multiplier	timeout_multiplier
		upvar expectlite::arg0					arg0
		upvar expectlite::INFO					INFO
		upvar expectlite::WARN					WARN
		upvar expectlite::DEBUG					DEBUG
		upvar expectlite::LOG					LOG
		upvar expectlite::EXP_INFO				EXP_INFO
		upvar expectlite::_el_warn_color		_el_warn_color
		upvar expectlite::_el_err_color			_el_err_color
		upvar expectlite::_el_debug_color		_el_debug_color
		upvar expectlite::SHOW_HELP				SHOW_HELP
		upvar expectlite::el_log_ext			el_log_ext

		# default timeout_multiplier multiplier to 1
		set cli_namespace($timeout_multiplier) 1

		# command file (aka script name) counter
		set cmd_file_counter 0

		# If needed read parameters from Env Vars
		catch { set remote_host $env(EL_REMOTE_HOST)}
		if { $remote_host == "" } { set remote_host "none" }

		if { $cmd_file=="" } { catch { set cmd_file $env(EL_CMD_FILE)} }
		if { $user_dir=="" } { catch { set user_dir $env(EL_USER_DIR)} }

		if { [info exist env(EL_LOG_EXT) ]} { catch { set el_log_ext $env(EL_LOG_EXT)} }
		# check for empty el_log_ext string
		if { $el_log_ext == "" } {
			cputs "expect-lte: ERROR: Environment var EL_LOG_EXT is blank, which could overwrite script file.\nSetting extension to \".log\"" $_el_err_color
			set el_log_ext ".log"
		}
		
		# preset local var
		set infinite_loop $_el_infinite_loop
		if { [info exist env(EL_INFINITE_LOOP) ]} { catch { set infinite_loop $env(EL_INFINITE_LOOP)} }
		# check for number el_infinite_loop string
		if { [string is integer -strict $infinite_loop] } {
			set _el_infinite_loop $infinite_loop
		} else {
			cputs "expect-lte: ERROR: Environment var EL_INFINITE_LOOP is blank or not a number.\nSetting INFINITE_LOOP to: $_el_infinite_loop" $_el_err_color
		}
		if { $user=="" } { catch { set user $env(EL_CONNECT_USER)} }
		if { $pass=="" } { catch { set pass $env(EL_CONNECT_PASS)} }
		if { [info exists env(EL_CONNECT_METHOD)] } { catch { set connect_method $env(EL_CONNECT_METHOD)} }
		if { [regexp {none|telnet|ssh|ssh_key} $connect_method] == 0 } { set connect_method "none" }

		if { [info exists env(EL_DELAY_WAIT_FOR_HOST)] } { catch { set delay_wait_for_host $env(EL_DELAY_WAIT_FOR_HOST)} }
		if { $delay_wait_for_host == "" } { set delay_wait_for_host "100" }
		if { [info exists env(EL_SHELL)] } { catch { set remote_shell $env(EL_SHELL)} }

		# ensure arg list is separated by spaces - removed in 4.2.0
# 		set argvstr [ join $argv ]
# 		set argv [split $argvstr ]
# 		set argc [ llength $argv ]

		if { $argc >= 1 ||  $cmd_file!="" }  {
			# Walk thru additional args (should be cli constants)
			for { set x  0 } { $x < $argc} { incr x } {
				set optarg [ lindex $argv $x ]
				catch {set optargval [ lindex $argv [expr $x + 1]]}
				if { $optargval == "" } { 
					# no optargval, set to a sane value
					set optargval "--"
				}
				#puts "=====>$x|$optarg|$optargval|"
				# Check that last parameter is command file name
				# script name cannot have '=', which would be interpretted as a constant
				if {  [regexp {^[-*]|[=]}  $optarg ] == 0 && [regexp {^[-*]|[=]} $optargval] == 1 } {
					if { [regexp "$el_log_ext$" $optarg] == 0 } {
						#puts ">>>$optarg>>>$optargval"
						set cmd_file $optarg
						set cli_namespace($arg0) [parse_cmd_file_nopath  $cmd_file]
						incr cmd_file_counter
					}
				}
				# look for help & debug options which overide script options
				# added -r and -c for remote_host & cmd_file respectively
				if { [catch { switch -glob -- $optarg {
					-h		-
					--help	{ set SHOW_HELP 1 }
					-v		{set WARN 10; set INFO 10}
					-vv		-
					--verbose	{set WARN 10; set DEBUG 10}
					-vvv		{set INFO 10; set WARN 10; set DEBUG 10}
					-V		-
					--verify	{set EXP_INFO 10; set INFO 10}
					-r		{ set remote_host $optargval; incr x  }
					-c		{ set cmd_file $optargval; set cli_namespace($arg0) [parse_cmd_file_nopath  $cmd_file] ; incr x }
					-d		{ set user_dir $optargval; incr x  }
					-u		{ set user $optargval; incr x  }
					-p		{ set pass $optargval; incr x }
				} } \
				error ] } {
					puts "Warning: Bad input option: $error"
				}
				#general vars
				if [ regexp {.+=.*} $optarg ] {
					# detect and parse args in format "var=value"
					set user_var [string range $optarg 0 [expr [string first "=" $optarg] -1 ]]
					set user_value [string range $optarg [expr [string first "=" $optarg] +1 ] [string length $optarg]]
					#puts "->$user_var $user_value"
					# populate required cli parameters and cli_constants
					switch -glob -- $user_var {
						remote_host -
						r 		{ set remote_host $user_value }
						cmd_file	-
						c	 	{ set cmd_file $user_value 
								# set script constant arg0 with script name
								set cli_namespace($arg0) [parse_cmd_file_nopath  $cmd_file]
							}
						user_dir	-
						d		{set user_dir $user_value }
						user_name	-
						u		{set user $user_value }
						user_password	-
						p		{set pass $user_value }
						default {
							set cli_namespace($user_var) $user_value
							puts "Const: $user_var = $cli_namespace($user_var)"
							}
					} 

				}
			} ; # for loop
			
			# walk though CLI options again and check for *DIRECTIVES
			for { set x  0 } { $x < $argc} { incr x } {
				set optarg [ lindex $argv $x ]
				catch {set optargval [ lindex $argv [expr $x + 1]]}
				if { $optargval == "" } { 
					# no optargval, set to a sane value
					set optargval "--"
				}
				#puts "=====>$x|$optarg|$optargval|"
				#cli-based directives (in form *DIRECTIVE)
				if [ regexp {\*[A-Z_]+} $optarg] {

					# check if optargval is just a word
					set chk_word ""
					#regsub {[a-zA-Z./]+} $optargval {} chk_word
					regsub {(^[-*]|[^*=]+)} $optargval {} chk_word
					#puts "===>got $optarg|$optargval|$el_log_ext|$chk_word|"
					
					if { [string length $chk_word] != 0 } {
						# just *LOG on the cli
						_el_global_directive $optarg 
					} elseif { [regexp {^[-*]|[=]}  $optargval ] } {
						# next arg is -,*DIR, or var=value
						_el_global_directive $optarg
					} elseif { [string match "*$el_log_ext" $optargval ] } {
						# next arg is *LOG <filename>
						_el_global_directive "$optarg $optargval"
						# increment loop to skip optargval
						incr x
					} elseif {[string match "*$el_log_ext" $optargval ] == 0} {
						# check again to see that second item doesn't end in .log
						# just *LOG on the cli
						_el_global_directive $optarg 
					
					} ; # end if
						
				}
			} ; # for loop
			
			
			
			# assign over riding directives
			if { $LOG } { set LOG 10 }
			if { $LOG < 0 } { set LOG -10 }
			if { $INFO > 1 } { set INFO 10 }
			if { $WARN } { set WARN 10 }
			if { $DEBUG } { set DEBUG 10 }
			if { $EXP_INFO } { set EXP_INFO 10 }

			#puts "->$remote_host|$cmd_file|$user_dir"

			# check that require paremeters are present
			if { $remote_host=="" } { 
				cputs "Error: Missing remote_host" $_el_err_color
				usage
				}
			if { [info exists ::EL_LIBRARY] != 1 && $remote_host=="none" || $remote_host=="NONE" } { 
				if {$WARN} { cputs "Warning: Remote Host=none, using Localhost" $_el_warn_color }
				# don't use remote login method but use localhost	
				set connect_method "none"
				}
			if { $cmd_file=="" && [info exists ::EL_LIBRARY] != 1} { 
				cputs "Error: Missing cmd_file"  $_el_err_color
				usage
				}
			# check that only 1 script name was on the CLI
			#puts "========>$cmd_file_counter|$LOG|$cmd_file"
			if { $cmd_file_counter > 1  &&  $LOG != 0} {
				puts stderr "Error: Can't determine cmd_file name with *LOG, please use log file with extension:$el_log_ext" 
				exit 1
			}
			
		}

		# Assign any Environment Variables starting with 'EL_' to Constants
		# only show in Debug and not Library mode
		if { $DEBUG && [info exists ::EL_LIBRARY] != 1} {
			cputs "expect-lite version $expectlite::version" $_el_debug_color
			cputs "Env Vars -> Constants:" $_el_debug_color
		}
		foreach key [array names env] {
			if {[regexp {^EL_} $key] == 1 } {
				if { $DEBUG && [info exists ::EL_LIBRARY] != 1} {
					cputs "$key=$env($key)" $_el_debug_color
				}
				set cli_namespace($key) $env($key)
			}
		}
		# validate ENV Vars
		switch -glob -- $cli_namespace(EL_CONNECT_METHOD) {
			none -
			ssh -
			ssh_key -
			telnet { # do nothing }
			default {
				cputs "ERROR: EL_CONNECT_METHOD set incorrect! Set to: $cli_namespace(EL_CONNECT_METHOD)" $_el_err_color
				cputs "Please set to one of: none, telnet, ssh, ssh_key" $_el_err_color
				cputs "export EL_CONNECT_METHOD=telnet" $_el_err_color
				exit 1
				}
		}

		if {[info exists ::EL_LIBRARY] != 1} {
			# show help if command file (script) is not given on command line			
			if { $argc < 1 && $cmd_file=="" }  {
				usage
			}
		}
	}


	#
	#	Takes full command path+file, and returns just the path to command file minus the filename
	#	This is used in including files
	#
	proc parse_cmd_file_path { cmd_file } {
		# Is there a path component?
		if {[regexp {/} $cmd_file] == 1 } {
			set temp_list [split $cmd_file '/']
			set len [expr [llength $temp_list] - 1 ]
			regsub [lindex $temp_list $len] $cmd_file "" temp_path

			return $temp_path
		} else {
			return ""
		}
	}

	#
	#	Reads in main command file, and if show_help is true, shows help and exits
	#	
	#
	proc read_cmd_file { } {
		upvar expectlite::cmd_file				cmd_file
		upvar expectlite::INFO					INFO
		upvar expectlite::_el_info_color			_el_info_color
		upvar expectlite::SHOW_HELP				SHOW_HELP
		upvar expectlite::arg0					arg0
		upvar expectlite::_el_buf				_el_buf
		upvar expectlite::_include				_include
		upvar expectlite::_el_err_color 			_el_err_color
		upvar expectlite::_el_debug_color		_el_debug_color
		upvar expectlite::DEBUG 					DEBUG
		upvar expectlite::_el 					_el

		# read this file as el script, reference by buf_stack pointer
		set cmd_list_ptr [expectlite::_el_buffer $cmd_file]

		# preserve cmd_file for later use 
		set _el(cmd_file) $cmd_file
						
		# validate include files
		set missing_include 0
		set inc_files [_el_buffer_get_obj $cmd_list_ptr ~]
		foreach line $inc_files {
			set _include_file [_el_strip_char $line $_include]
			# get only the first word as include file
			set _include_file [lindex [split $_include_file " " ] 0]
			
			# is include file a variable, skip validation
			if { [ regexp {^\$} $_include_file ] == 0 } {
				# absolute path to include file?
				set _slash "/"
				if { [string index $_include_file 0] == $_slash} {
					set include_path_file "$_include_file"
				} else {
					set include_path_file "[parse_cmd_file_path $cmd_file]$_include_file"
				}
				# validate include file
				if { $DEBUG } {
					cputs "Checking include file exists: $include_path_file" $_el_debug_color
				}
				if {[file exists $include_path_file] == 0} {
					cputs "$include_path_file   not found!" $_el_err_color
					incr missing_include
				}
			}		
		}; #foreach
		
		# if needed show help and exit
		if { $SHOW_HELP } {
			cputs "Help for: $cmd_file" $_el_info_color

			_el_buffer_show_help $cmd_list_ptr
			cputs "Displaying assigned variables, which can be overridden with \na Constant on command line e.g var=value" $_el_info_color
			set var_list [_el_buffer_get_obj $cmd_list_ptr]

			set var_list [ lsort -unique $var_list ]
			foreach line $var_list {
				# remove $ from help lines
				regsub {\$} $line {} line
				puts "\t$line"
			}
			usage
			exit 1
		}
		if { $missing_include } {
			cputs "\nMissing required include files, exiting..." $_el_err_color
			# exit with abend code
			exit 2
		}
		
		# return the pointer to the buffer	
		return $cmd_list_ptr
	}

	#
	#	Login Method which uses user and password via Telnet to log into hosts
	#	If this is not your access method use one of the other login methods
	#
	proc connect_telnet_host {remote_host {optional_suppress_stdout "no"}} {
		global spawn_id 
		upvar expectlite::DEBUG					DEBUG
		upvar expectlite::_el_timeout			_el_timeout
		upvar expectlite::_el_telnet			_el_telnet
		upvar expectlite::user					user
		upvar expectlite::pass					pass
		
		
		
		#This spawns the telnet program - auto generates spawn_id var
		set timeout 5
		if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} {
			# turn off stdout - suppress login banners - show with -vv
			log_user 0
		}
		if { [catch { spawn $_el_telnet $remote_host  } error] } {
			puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n   $error"
			# Fail script?
			exit 1
		}
		#The script expects login
		expect "ogin:"

		#The script sends the user variable
		if { [catch { send -- "$user\r"   } error] } {
			puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n   $error\n    $errorInfo"
			# Fail script?
			exit 1
		}
		#The script expects Password
		expect "assword:" 

		#The script sends the password variable
		# do not log password
		set log_user 0
		send -- "$pass\r" 
		set log_user 1
		#wait_for_prompt
		set timeout $_el_timeout
		# turn on stdout
		log_user 1
	}

	#
	#	Subroutine used by ssh user/password method
	#	If this is not your access method use one of the other login methods
	#
	proc zlogin { {pass ""} {login_attempts 2} } {
		upvar expectlite::remote_host		remote_host
		upvar expectlite::_el_warn_color			_el_warn_color
		upvar expectlite::_el_eols			_el_eols
		upvar expectlite::WARN					WARN
		
		set timeout 2
		set MAXLOGINATTEMPT 10
		#set login_attempts 0
		while { $login_attempts < $MAXLOGINATTEMPT} {
			#puts "loop: $login_attempts"
			expect {
				-re "assword:"	{
					# do not log password
					set log_user 0
					send -- "$pass$_el_eols" 
					set log_user 1
					#puts "send pass"
					}
				-re "Are you sure you want to continue connecting" {
					send -- "yes$_el_eols"
					#zlogin $pass $login_attempts
					}
				-re "Warning: Permanently added .* to the list of known hosts" {
					if {$WARN} { cputs "Expect-lite: Warning: ssh added host key to known hosts" $_el_warn_color }
					
					}
				-re "Last login" { return }
				-re {.*[>#%$] $} { return }
				-re {.+\n} { #expect connected  }

			 }
			 incr login_attempts
			 #puts "here"
		 }
		 if { $login_attempts >= $MAXLOGINATTEMPT} {
			puts stderr "\nCONNECT ERROR:Unable to login to $remote_host \n "
			exit 1
		 }
	}

	#
	#	Login Method which uses user and password via ssh to log into hosts
	#	If this is not your access method use one of the other login methods
	#
	proc connect_ssh_host {remote_host {optional_suppress_stdout "no"}} {
		global spawn_id env
		upvar expectlite::user					user
		upvar expectlite::pass					pass
		upvar expectlite::_el_timeout			_el_timeout
		upvar expectlite::DEBUG					DEBUG
		upvar expectlite::connect_ssh_accept_host_key	connect_ssh_accept_host_key	
		
		
		# work around for older versions of expect
		#This spawns the ssh program - auto generates spawn_id var
		#spawn ssh -l $user $remote_host
		set timeout 15
		if { $user == "" } {
			# user username from environment
			set user $env(USER)
		}
		# suppress stdout during login
		if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} {
			# turn off stdout - suppress login banners - show with -vv
			log_user 0
		}
		
		# create ssh command line
		set connect_cmd [concat ssh $connect_ssh_accept_host_key -l $user $remote_host]
		
		#This spawns the ssh program - auto generates spawn_id var
		if { [catch "spawn $connect_cmd" error] } {
			puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n   $error"
			# Fail script?
			exit 1
		}
		# debug help
		#exp_internal 1

		set login_attempt 0
		#better way of logging in (and catch any errors)
		if { [ catch {zlogin $pass $login_attempt} error] } {
			puts stderr "CONNECTION ERROR to $remote_host \n   $error"
			exit 1
		}
		# turn off the debugging
		#exp_internal 0
		set timeout $_el_timeout
		# turn on stdout
		log_user 1

	}

	#
	#	Login Method which assumes ssh keys are configured for login hosts
	#	If this is not your access method use one of the other login methods
	#
	proc connect_ssh_key_host {remote_host {optional_suppress_stdout "no"}} {
		global spawn_id timeout
		upvar expectlite::user					user
		upvar expectlite::pass					pass
		upvar expectlite::DEBUG					DEBUG
		upvar expectlite::delay_wait_for_host	delay_wait_for_host
		upvar expectlite::_el_eols				_el_eols
		upvar expectlite::connect_ssh_accept_host_key		connect_ssh_accept_host_key	
		upvar expectlite::_el_timeout				_el_timeout
		
		
		# work around for older versions of expect
		# Enable use of an alternet user for ssh_key method
		# if $user is not blank, then use the alternet user
		set timeout 30
		if { $user != "" } { 
			set login_user "$user@"
		} else {
			set login_user ""
		}
		# suppress stdout during login
		if { ($optional_suppress_stdout == "suppress_stdout") && ($DEBUG != 1)} {
			# turn off stdout - suppress login banners - show with -vv
			log_user 0
		}
		#This spawns the ssh program - auto generates spawn_id var
		set connect_cmd [concat ssh $connect_ssh_accept_host_key $login_user$remote_host]
		if { [catch  "spawn $connect_cmd" error] } {
			puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n   $error"
			# Fail script?
			exit 1
		}
		# TODO:Auto update ~/.ssh/known_hosts if needed
		#better way of logging in (and catch any errors)
		if { [ catch {zlogin} error] } {
			puts stderr "CONNECTION ERROR to $remote_host \n   $error"
			exit 1
		}
	
		# Test the connection by sending a return
		if { [catch { send -- "$_el_eols"   } error] } {
			puts stderr "CONNECT ERROR: Unable to connect to $remote_host \n   $error"
			# Fail script?
			exit 1
		}
		# allow time for remote banner (if present) to echo
		#after [expr $delay_wait_for_host * 2]

		# answer quetion if given, else take any response as "connected"
		set timeout 5
		expect {
			-re "Are you sure you want to continue connecting" {
			send -- "yes$_el_eols"
			}
			-re {.+} { #puts "expect-lite: Connected" }
			timeout { }
		}
		# debug help
		#exp_internal 1

		# turn off the debugging
		#exp_internal 0
		set timeout $_el_timeout
		# turn on stdout
		log_user 1

	}

	#
	#	Login Method connects to localhost (no telnet or ssh)
	#	If this is not your access method use one of the other login methods
	#
	proc _el_connect_localhost {remote_host} {
		# this proc just spawns a connection to a shell
		# all other functions are handled by remote_host_init

		global  spawn_id timeout
		upvar expectlite::remote_shell			remote_shell
		upvar expectlite::_el_eols				_el_eols
		
		# OS identification - .dll or "" = Cygwin, .so=Linux, .dylib=MacOS X
		set os_id [info sharedlibextension]
		if { $os_id == ".dll" || $os_id == "" } {
			set timeout 30
		}
		
		# protect against empty remote_shell
		if { $remote_shell == "" } { set remote_shell "bash" }
		# spawn a local shell for localhost
		if { [catch { spawn $remote_shell  } error] } {
			puts stderr "CONNECT ERROR: Unable to connect to localhost \n   $error"
			# Fail script?
			exit 1
		}
		send -- " $_el_eols"
		set timeout 10
	}

	#
	#	Reads configuration directives, prior to command file execution
	#	Sets global variables
	#	This function will eventually replace all user defined globals at top of script
	#
	proc read_set_config_directives { buf_stack } {
		upvar expectlite::remote_shell			remote_shell
		upvar expectlite::_el_buf				_el_buf

		# search for shell configuration directive (**SHELL=...)
		#set _search "^\\\*\*SHELL=.*"
		set _search "\{\\\*\*SHELL=.*"

		# search buffer _el_buf($buf_stack) with $_search  
		#set _buf_ptr [lsearch -regexp -index 0 $_el_buf($buf_stack) "$_search"]
		set _buf_ptr [lsearch -regexp  $_el_buf($buf_stack) "$_search"]
		
		set _line [_el_buffer_read $_buf_ptr $buf_stack]	
		#puts "shell_line-------->$_line|$_buf_ptr"
		if { $_buf_ptr != -1 } {
			set _line_list [split $_line "="]
			if { [llength $_line_list ] == 2 } {
				set remote_shell [lindex $_line_list 1]
			}
			puts "expect-lite directive: Shell is: $remote_shell"
		}
	}

	#
	#	Wraps expect send command in catch, reports error if connection is lost
	#	Error condition terminates script
	#
	proc protected_send { str } {
		upvar expectlite::remote_host			remote_host

		if { [catch { send -- "$str"   } error] } {
			puts stderr "CONNECT ERROR: Unable to connect to remote_host: $remote_host \n   $error"
			# Fail script?
			exit 1
		}
	}

	#
	#	After logged into remote host, does house keeping activities before starting expect-lite script
	#		starts shell on remote host, sets sane prompt, and cd's to user directory (aka user_dir) if needed
	#	
	proc remote_host_init { user_dir  } {
		global spawn_id timeout expect_out
		upvar expectlite::remote_host			remote_host
		upvar expectlite::remote_shell			remote_shell
		upvar expectlite::DEBUG					DEBUG
		upvar expectlite::_el_timeout			_el_timeout
		upvar expectlite::connect_method		connect_method
		upvar expectlite::delay_wait_for_host	delay_wait_for_host
		upvar expectlite::_el_debug_color		_el_debug_color
		upvar expectlite::_el_eols				_el_eols
		
		set timeout 5
		
		#set an initial sane value
		set detected_prompt "$ "
		
		# suppress stdout during login for *FORK
		if { $DEBUG > 0 } {
			# turn off stdout - suppress login banners - show with -vv
			log_user 0
		}

		# ensure we are using user's desired shell, and check connection
		if {$connect_method != "none" } {
			# handle real remote host invocation of shell
			protected_send "$remote_shell$_el_eols"

			# wait for echo to appear when starting a shell
			if { $remote_shell != "" } {
				expect {
					-re ".+\[%>#$\] $remote_shell.+" { if {$DEBUG} { cputs "DEBUG: Starting Shell: $remote_shell\n" $_el_debug_color} }
					timeout { if {$DEBUG} { cputs "DEBUG: Unable to detect Shell Start\n"  $_el_debug_color} }
				}
			}
		}

		# attempt to detect shell by prompt
		protected_send "$_el_eols"
		expect -re {([%>#$]) $} {
			if {$DEBUG} { cputs "<<$expect_out(0,string)>>"  $_el_debug_color}
			#puts "<<$expect_out(buffer)>>" 
			set detected_prompt $expect_out(0,string)
		}
		# set sane prompt
		
		switch -glob -- $remote_shell {
			csh -
			tcsh 	{ set _prompt "%c02 %# %L"
						protected_send "set prompt = \"$_prompt\"$_el_eols" 
						expect -re {.+prompt.+} { }
					}
			sh -
			ksh -
			bash		{ set _prompt "\"\[\\u@\\h:\\w\]\\$ \"" 
						protected_send "export PS1=$_prompt$_el_eols" 
						expect -re {.+PS1.+} { }
					}
			default 	{ switch -glob -- $detected_prompt {
						"# " -
						"$ " { 	set _prompt "\$ " 
								protected_send "export PS1=\'$_prompt\'$_el_eols" 
								if {$DEBUG} { cputs "DEBUG: Setting sh prompt. \n"  $_el_debug_color}
							}
						"% " -
						"> " {	set _prompt "\$ " 
								protected_send "set prompt = \"$_prompt\"$_el_eols" 
								if {$DEBUG} { cputs "DEBUG: Setting csh prompt. \n"  $_el_debug_color} 
							}
						}
					}
		}
		# clear expect_out(buffer)
		#expect -re {.+} {}

		# turn on stdout
		log_user 1

		#only change directory if user_dir was passed as an arg, otherwise, user will set it in expect-lite script
		if { $user_dir != "" } {
			protected_send "cd $user_dir$_el_eols"
			wait_for_prompt
		}
		set timeout $_el_timeout
	}
	
	#
	#	initialize session and remote host
	#
	#
	proc session_init { cmd_file_ptr } {
		upvar expectlite::user_dir					user_dir
		upvar expectlite::_el_fork					_el_fork
		upvar expectlite::_el_eols				_el_eols
	
		# is main script name equal to command file (script) name 
		# or Is this an include file, then don't do remote_host_init
		read_set_config_directives $cmd_file_ptr
		# init prompt for first (default) session
		remote_host_init $user_dir
		# kick the prompt
		protected_send "$_el_eols"
		
		# set default fork session if it doesn't already exist
		if { [info exists _el_fork(default,session)] != 1 } {
			if { [catch { set _el_fork(default,session) $::spawn_id  } error] } {
				puts stderr "BUG: Expect-lite: Bug in _el_script_exec init code while setting default FORK session \n   $error"
				# Fail script?
				exit 1
			}
		}
	
	}

	#
	#	Control spawn_id sessions on host
	#
	#
	proc session_id_manager { fork_id } {
		global spawn_id timeout
		upvar expectlite::_el				_el
		upvar expectlite::_el_fork			_el_fork
		upvar expectlite::_el_fork_id_list	_el_fork_id_list
		upvar expectlite::INFO				INFO
		upvar expectlite::connect_method	connect_method
		upvar expectlite::remote_host		remote_host
		upvar expectlite::DEBUG 			DEBUG
		upvar expectlite::user_dir			user_dir
		upvar expectlite::_el_info_color	_el_info_color
		upvar expectlite::_el_warn_color	_el_warn_color
		upvar expectlite::_el_debug_color	_el_debug_color
		upvar expectlite::_el_eols			_el_eols

		
		if { $fork_id == "default" } {
			# set fork session back to default if count > 0
			if { $_el(fork_count) > 0 } {
				set spawn_id  $_el_fork(default,session)
			}
		} elseif { $fork_id != "" } {
			# request for new fork session

			if {[info exists _el_fork($fork_id,session) ]} {
				# connect to existing session
				set spawn_id $_el_fork($fork_id,session)
			} else {
				# save current timeout
				set current_timeout $timeout
				# start new session on remote_host
				# Use selected (at top of this file) connect_method
				switch $connect_method {
					telnet	{connect_telnet_host $remote_host "suppress_stdout" }
					ssh		{connect_ssh_host 	$remote_host "suppress_stdout" }
					ssh_key	{connect_ssh_key_host $remote_host "suppress_stdout"}
					none		{_el_connect_localhost $remote_host }
				}
				# set a sane prompt for additional sessions
				remote_host_init $user_dir
				# restore current timeout
				set timeout $current_timeout 
				set _el_fork($fork_id,session) $spawn_id
				incr _el(fork_count)
				# update list of fork_id's
				lappend _el_fork_id_list $fork_id
				# set default eols for this session
				set _el_fork($fork_id,eols) $_el_eols
			}
			# end if		
		} elseif {$fork_id == "" } {
			# Show current session name
			if { [info exists _el(fork_current)] } {
				set fork_id $_el(fork_current)
			} else {
				set fork_id "default"
			}
		}
		# clear and regenerate fork id list and count
		set _el_fork_id_list { }
		set _el(fork_count) 0
		foreach keyitem [array names _el_fork] {
			#filter out eols from session printout
			if { [string match "*,session" $keyitem] } {
				# retrieve session name, drop ',session' from keyitem
				set session_name [lindex [split $keyitem ,] 0]
				lappend _el_fork_id_list $session_name
				incr _el(fork_count)
				#puts "=====>$keyitem|$session_name|$_el_fork_id_list|$_el(fork_count)"
			}
		}

		if {$INFO && !$DEBUG} {
			cputs "\n\nINFO: FORK session is: $fork_id,	Active sessions are: $_el_fork_id_list\n" $_el_info_color
		} elseif { $DEBUG } {
			cputs "\n\nDEBUG: FORK session is: $fork_id, Spawn_id=$spawn_id, fork_count:$_el(fork_count), active sessions:$_el_fork_id_list\n" $_el_debug_color
		}
		set _el(fork_current) $fork_id
		return $fork_id
	}

	#
	#	el_lib: import session names and spawn_ids
	#	Enables external app to spawn sessions, and feed list to EL
	#
	proc _el_import_session_ids { session_list } {
		global spawn_id 
		upvar expectlite::_el				_el
		upvar expectlite::_el_fork			_el_fork
		upvar expectlite::_el_fork_id_list	_el_fork_id_list
		upvar expectlite::INFO				INFO
		upvar expectlite::DEBUG 			DEBUG
		upvar expectlite::_el_info_color	_el_info_color
		upvar expectlite::_el_debug_color		_el_debug_color
		upvar expectlite::_el_err_color		_el_err_color
		upvar expectlite::_el_eols			_el_eols

		puts  "SL>$session_list|[llength $session_list]"
		if { [ catch { array set import_fork  $session_list} error ]} {
			cputs "ERROR: Invalid array:$session_list:\n$error\n" $_el_err_color
		}

		# set current fork_id to current spawn_id
		foreach keyitem [array names import_fork] {
			#filter out eols from keyitems
			puts "SL>$keyitem"
			# set current fork_id to current spawn_id
			puts "SL2>$keyitem"
			if { [info exists spawn_id ] && $import_fork($keyitem,session) == $spawn_id } {
				set _el(fork_current) $keyitem
				set _el_fork(fork_current,eols) $_el_eols
			}
			# set default eol context 
			set _el_fork($keyitem,eols) $_el_eols
		}
		# set spawn_id to default, if not currently set
		if { [info exists spawn_id ] != 1 && [ info exists import_fork(default)] } {
			set spawn_id $import_fork(default)
		} else {
			cputs "ERROR: Import Sessions: no 'default' session found\n    Sessions imported: [array names import_fork]" $_el_err_color 
			exit 1
		}
		# convert imported session array to el_fork array
		foreach keyitem [array names import_fork] {
			set _el_fork($keyitem,session) $import_fork($keyitem)
		}

		# show array
		if { $DEBUG } {
			cputs "Printing session ids:" $_el_debug_color
			foreach keyitem [array names _el_fork] {
				#filter out eols from session printout
				if { [string match "*session*" $keyitem] == 1 } {
					set session_name [lindex [split $keyitem ,] 0]
					cputs "	$session_name=$_el_fork($keyitem)" $_el_debug_color
				}
			}
		}; #endif DEBUG
	}


	#
	#	push spawn_id sessions on fork_id stack
	#	used by interact
	#
	proc push_session_id { fork_id } {
		global spawn_id 
		upvar expectlite::_el				_el
		upvar expectlite::_el_fork			_el_fork
		upvar expectlite::_el_fork_stack	_el_fork_stack
		upvar expectlite::INFO				INFO
		upvar expectlite::DEBUG 			DEBUG

		# remove any \n or \r's
		regsub -all {[ \n\r]+} $fork_id "" fork_id
		if { [string length $fork_id ] > 0 } {
			# push new session_id on stack
			lappend _el_fork_stack $_el(fork_current)
		}
		set len [llength $_el_fork_stack]
	}

	#
	#	pop spawn_id sessions from fork_id stack
	#	used by interact, to set proper *FORK session when continuing the expect-lite script
	#
	proc pop_session_id { } {
		global spawn_id 
		upvar expectlite::_el				_el
		upvar expectlite::_el_fork			_el_fork
		upvar expectlite::_el_fork_stack	_el_fork_stack
		upvar expectlite::INFO				INFO
		upvar expectlite::DEBUG 			DEBUG

		if {[info exists _el_fork_stack ]} {
			set len [llength $_el_fork_stack]
			if { $len > 0 } {
				# get last value on stack
				set fork_id [lindex $_el_fork_stack [expr $len -1 ]]
				# delete last item in stack
				set _el_fork_stack [lreplace $_el_fork_stack end end]
				# return last value of fork_id from stack
				return $fork_id
			}	
		}
		return ""
	}

	#
	#	Subroutine to remove first char from string and return substring
	#
	#
	proc _el_strip_char { string char } {
		#puts "s->$string||$char||"

		regsub -- $char $string "" stringb
		#puts "s->$stringb||$char||"
		return $stringb
	}



	#
	#	Find a color in a comment line
	#	
	#
	proc find_color { str } {
		upvar expectlite::el_color		el_color

		set fcolor ""
		# detect first word of comment, if it is a color, then so use it
		set l_str [split $str]
		set first_word [lindex $l_str 0 ]
		#puts "------------------>$l_str|$first_word|[lsearch [array names el_color] $first_word ]|"
		if {[lsearch [array names el_color] $first_word ] != -1} {
			set fcolor $first_word
		}
		return $fcolor
	}


	#
	#	Proc to allow passing of arguments to Include file as constants
	#		preserves any constants already defined, and restores them 
	#		after include file returns
	#
	#	preserve const var=value and return preserved values as list {{var} {value}...}
	#
	proc _el_preserve_const { varvalue_list } {
		upvar expectlite::cli_namespace			cli_namespace
		
		set out_list {}
		# tease apart in list
		foreach x $varvalue_list {
			# pull values off of list
			set var [lindex $x 0]
			set value [lindex $x 1]
			# is there a constant with this name?
			if { [info exists cli_namespace($var) ] } {
				#preserve value of constant
				lappend out_list "{$var} {$cli_namespace($var)}"
				set cli_namespace($var) $value
			} else {
				# put empty value on list
				lappend out_list "{$var} {}"
				set cli_namespace($var) $value

			}
		}; #foreach
		#puts "pppppp>$out_list"
		return $out_list
	}

	#
	#	restore const var=value from list {{var} {value}...}
	#
	proc _el_restore_const { varvalue_list } {
		upvar expectlite::cli_namespace			cli_namespace
		
		# tease apart in list
		foreach x $varvalue_list {
			# pull values off of list
			set var [lindex $x 0]
			set value [lindex $x 1]
			# is there a constant with this name?
			if { [info exists cli_namespace($var) ] } {
				#restore value of constant
				if { $value != {} } { 
					set cli_namespace($var) $value
				} else {
					unset cli_namespace($var)
				}
			}
		}; #foreach
	}
	
	
	#
	#	Parse arg string for var=value in list {{var} {value}...}
	#
	proc _el_parse_var_value { varvalue_list } {
		set out_list {}
		# create new list
		set in_list {}
		set val_str ""
		# Parse list to be var-value and directives pairs
		# append to list in format {var=} {value with spaces}
		foreach x $varvalue_list {
			#puts "==x>$x, $val_str"
			if {  [regexp {[a-zA-Z0-9_]+[=]}  $x ] == 1 } {
				if { $val_str != ""} {
					lappend in_list [string trimright $val_str " "]
					set val_str ""
				}
				set y [ split $x "=" ]
				#puts "==y>$y"
				set val_str [lindex $y 1]
				lappend in_list "[lindex $y 0]="
			} elseif { [regexp {[*][A-Z0-9_]+}  $x ] == 1 } {
				if { $val_str != ""} {
					lappend in_list [string trimright $val_str " "]
					set val_str ""
				}
				lappend in_list $x
				lappend in_list {}
			} else {
				set val_str "$val_str $x "
			}
		}
		# append last value part
		if { $val_str != ""} {
			lappend in_list [string trimright $val_str " "]
		}
		#puts "==in_list>$in_list"
		# walk through list creating {{var} {value}}
		set i 0
		if { [llength $in_list] > 0 } {
			foreach x $in_list {
				# is passed value in format 'var='
				if {  [regexp {[a-zA-Z0-9_]+[=]}  $x ] == 1 } {
					set var_value_l [split $x "=" ]
					set var [lindex $var_value_l 0]
					set value [lindex $in_list [expr $i + 1]]
					#set value [lindex $var_value_l 1]
					lappend out_list "{$var} {$value}"
					#puts ">>>$x>>$var=$value"
				}
				incr i
			}; #foreach
		}
		# walk through list to format directives as {{*DIRECTIVE} {}}
			# TODO implement directive processing in the future
		if { [llength $out_list ] > 0 } {
			return $out_list
		} else {
			return {}
		}
	}; #proc


	#
	#	Prints a comment line (begins with a ';')
	#	
	#
	proc print_comment_line { } {
		upvar expectlite::el_color			el_color
		upvar expectlite::_el_info_color	_el_info_color
		upvar expectlite::_el_comment_color	_el_comment_color
		upvar expectlite::timeout_line		timeout_line
		upvar expectlite::comment_line		comment_line
		upvar expectlite::INFO				INFO


		# initialize font color
		if { $comment_line != "" } {
			set fcolor [find_color $comment_line]
			if { $fcolor != "" } {
				# remove first word
				regsub "$fcolor" $comment_line "" comment_line
			}
		}

		# print ';' printable comment
		if { $comment_line != "" } {
			#puts "\n$comment_line\n"
			cputs "\n$comment_line\n" $fcolor
			set comment_line ""
			} 
		# print new expect timeout value (if needed)
		if { $timeout_line != "" } {
			if {$INFO} { cputs "\n$timeout_line\n" $_el_info_color }
			set timeout_line ""
			} 

	}


	#
	#	Prints all user vars and constants
	#	Called by *SHOW VARS & IDE <esc>v
	#
	proc show_vars { } {
		upvar expectlite::user_namespace		user_namespace
		upvar expectlite::cli_namespace			cli_namespace
		upvar expectlite::arg0					arg0

		set blank "                    "
		set blank_len [string length $blank]
		set var_list [array names user_namespace]
		set var_list_sorted [lsort $var_list]

		cputs "DEBUG Info: Printing all expect-lite variables" "none"
		# print internal vars
		if { [ info exists cli_namespace($arg0) ] } { 
			set ii_len [string length $arg0]
			set ii_blank [string range $blank 1 [expr $blank_len - $ii_len]]
			cputs "Var:arg0 $ii_blank Value:$cli_namespace($arg0)" "none"
		}
		foreach ii $var_list_sorted {
			# create aligned columns
			set ii_len [string length $ii]
			set ii_blank [string range $blank 1 [expr $blank_len - $ii_len]]
			# is a constant overiding the var?
			if { [info exists cli_namespace($ii) ] } {
				set iii_len [string length $cli_namespace($ii)]
				set iii_blank [string range $blank 1 [expr $blank_len - $iii_len]]
			}
			# don't print array initialization var (zero)
			if { $ii != 0 } {
				if { [info exists cli_namespace($ii) ] } { 
					# print var, value, Const
					cputs "Var:$ii $ii_blank Value:$user_namespace($ii) $iii_blank Const:$cli_namespace($ii)" none
				} else {
					# print var, value
					cputs "Var:$ii $ii_blank Value:$user_namespace($ii)" none

				}
			}
		}
	}

	#
	#	Resolves user vars to values, only if there isn't a Constant with the same name
	#	Constants are always given preference over user vars (defined in the script)
	#	returns value of var if known, or replaces $var format (for shell vars)
	#
	proc resolve_var_sub var {
		upvar expectlite::user_namespace		user_namespace
		upvar expectlite::cli_namespace			cli_namespace
		upvar expectlite::_el_info_color		_el_info_color
		upvar expectlite::INFO					INFO
		upvar expectlite::WARN					WARN
		upvar expectlite::DEBUG					DEBUG

		if { $var != "" } {
			set append_value 1
			# we have the var
			set user_var $var

			#puts "var>$user_var"

			# Give priority over Constants, only assign Vars if Constant not present
			if { [catch {set user_value $cli_namespace($user_var)}]  } {
				if { [catch {set user_value $user_namespace($user_var)}] } {
					# go quietly into the night
					#puts stderr "VAR NOT FOUND: |$user_var|"
					# unknown var
					set append_value 0
				}

			} else {
				# Show all constant substitutions if in DEBUG
				if {$DEBUG} {
					cputs  "INFO: CONST FOUND: $user_var = $cli_namespace($user_var)" $_el_info_color
				}
				# Show non ENV constant substitutions in INFO
				if { $INFO==1 && [regexp {^EL_} $user_var]!=1 } {

					cputs  "INFO: CONST FOUND: $user_var = $cli_namespace($user_var)" $_el_info_color
				}
			}
			if { $append_value } {
				#puts "u_v>$var=$user_value"
				# only append valid vars
				return $user_value
			} else {
				# if unknown var, be sure to put it back on line with a '$' in front for shell vars
				return "\$$var"
			}
		} else {
			return ""
		}

	}

	#
	#	A rather complicated subroutine (sorry) which parses out user vars in the script
	#	The sep_list defines what chars are _not_ in vars
	#	returns value of var, or $var if shell var
	#
	#	This function uses a two stage TCL command "split" to parse the expect-lite variables
	#		For example, the following line requires parsing: "mount$this$that#other"
	#			1) The first stage split will split on '$' resulting in "mount this that#other"
	#			2) "mount" will be discarded, since it is the first part, and not preceeded with a '$'
	#			3) The remaining line segments (in a TCL list) will go to the second split stage which
	#				cycles thru a known list of characters signaling the end of a variable name (sep_list)
	#			4) "this" passes the second stage, and is passed to proc resolve_var_sub for resolution
	#			5) "that#other" will be split again into "that other" in the second split stage
	#			6) Only the first line segment after the second stage split is sent to proc resolve_var_sub 
	#				for resolution (of key value pairs)
	#				In this example it would be "that" which is sent for resolution
	#			7) The entire line is reassembled after var resolution, and returned
	#
	proc parse_var { var sep } {
		# parses the string passed, separating out the Vars and passing them to resolve_var_sub to be resolved
		# List of Chars which define the end of a Var
		set sep_list { ! @ # % & * / { } \\ ( ) . [ ] = ? \" : - , | }
		#puts "v>$var|s>$sep"
		set resolved_line ""

		set var_list [ split $var $sep]
		#puts "vl>$var_list|sep>$sep"
		# If only 1 var on the line
		if { [llength $var_list] == 1 } {
			if { $sep == "$" } {
				#puts "one only"
				# return first chunk which is NOT a var in var_list
				append resolved_line $var
			} else {

				append resolved_line [resolve_var_sub $var]
			}
		} else {
			# First time in (no recursion) 
			if { $sep == "$" } {
				append resolved_line [lindex $var_list 0]
			} else {
				# Dereferences Vars on First time through the var_list
				#puts "look here"
				append resolved_line [resolve_var_sub [lindex $var_list 0]]
			}
			#puts "vl>$var_list"
			for {set j 1} {$j<[llength $var_list]} {incr j} {
				set var_only 1
				# are there other strange chars in the var?
				# use low_water_marker to find closest one
				# FIXME: limits var length to less that 255
				set low_water_marker 255
				foreach k $sep_list {
					set odd_char_pos [string first $k [lindex $var_list $j]]
					if { $odd_char_pos > -1 } { 
						if { $odd_char_pos < $low_water_marker } { 
							set low_water_marker $odd_char_pos
							set s $k
						}
						set var_only 0
					}
					#puts "k>[string first $k [lindex $var_list $j]]]"
				}
				if { $var_only } {
					# "var only" no other strange chars found
					if { $sep == "$" } {
						#puts "vo>[lindex $var_list $j]|j>$j"
						append resolved_line [resolve_var_sub [lindex $var_list $j]]
					} else {
						#puts "j>$j|sep>$sep"
						# add literals back to the line (in a recursed call)
						append resolved_line $sep[lindex $var_list $j]
					}
				} else {
					#puts "j>$j|recurse!"
					# Recursion Call with smaller chunck - splits known var with "extra" chars
					# and make sure the var length isn't zero
					if { ($sep == "$") && ($low_water_marker != 0) } {
						append resolved_line [parse_var [lindex $var_list $j] $s]
					} else {
						append resolved_line $sep[lindex $var_list $j]
					}
				}
				#puts "j>$j|val>$resolved_line"
			}
		}
		#puts "r>$resolved_line"
		return $resolved_line
	} 
	# end of parse_var



	#
	#	Buffer management functions
	#	A buffer is used to permit random access to the command script
	#		This enables looping, but setting the buffer pointer to a 
	#		previous line in the script
	#	The conditional/jump mechanism will use this method for looping
	#

	#
	#	Opens command script and reads into buffer (tcl list)
	#	Returns buffer
	#
	proc _el_buffer {{cmd_file ""} {in_list ""}} {
		upvar expectlite::_el_buf					_el_buf

		
		# generic get next proc to get from file or list
		proc get_next_line {} {
			upvar cmd_file cmd_file
			upvar infile 	infile
			upvar in_list	in_list
			upvar listptr	listptr
			upvar buf_line	buf_line
			
			if {$cmd_file != ""} {
				set rtncode [gets $infile buf_line]
				return $rtncode
			}
			if {$in_list != ""} {
				if { $listptr <= [llength $in_list] } {
					# read line off of in_list
					set buf_line [ lindex $in_list $listptr ]
					incr listptr
					set rtncode 1
				} else {
					set rtncode -1
				}
				return $rtncode
			}
			# should not make it here, but if so, stop
			return -1
		
		}; #end proc

		# sets line buffer to start at line 1, rather than 0, helps pasting lines in IDE		
		set line_buffer {#}
		set help_buffer {}
		set listptr 0
		# read help flag
		set read_help 0
		
		if {$cmd_file != ""} {
			# Protect against no file to read
			if { [ catch { set infile [open $cmd_file r ] } error] } {
				puts stderr "Unable to open cmd/include_file \n   $error"
					exit 1
			}
		}
		
		
		while { -1 != [ get_next_line ]} {

			# meta_line used to hold additional info about line, for line blocks 
			set meta_line -1
			
			# remove leading white space on line (permitting indentation
			regsub {^[ \t]+} $buf_line {} buf_line

			#trim white space at end of labels
			if { [ regexp {^%} $buf_line ] } {
				# remove leading white space on line (permitting indentation
				regsub {[ \t]+$} $buf_line {} buf_line
			}
			# pad back slash at end of line - do not escape curly list item
			if { [ regexp {\\$} $buf_line ] } {
				# remove leading white space on line (permitting indentation
				regsub {\\$} $buf_line {\\ } buf_line
			}
			
			# process block lines ] pop
			if { [regexp {^[\]]} $buf_line ] } {
				set meta_line_blob [join [_el_buffer_block_pop ]]
				# poor man's lassign (8.5 feature) - unpack list into vars
				foreach {meta_line meta_line_type} $meta_line_blob {break}
				
				# update meta-line of '[' line
				# preserve line-data
				set t_line_data [lindex $line_buffer $meta_line 0]
				#puts "======>$buf_line | $meta_line | $t_line_data | $meta_line_type"
				# update [ line meta-data with valid line number (read: not -1)
				if { $meta_line > 0 } {
					lset line_buffer $meta_line "{$t_line_data} {[llength $line_buffer]}"
				}
				# is the popped line an if statement?
				if { $meta_line_type == "if" } {
					set meta_line [expr [llength $line_buffer] + 1]
					
					# if block lines is "else" ]::[  then push
					if { [regexp {^\][ ]*::[ ]*\[[ \t]*$} $buf_line ]} {
						# then push "else"
						_el_buffer_block_push [concat "[llength $line_buffer] $meta_line_type"]
					}
				}; #if meta-if
			}

			
			# process block lines [ push
			if { [regexp {^[\[]} $buf_line ] } {
				_el_buffer_block_push [concat "[llength $line_buffer] \"while\" "]
			}
			# process ?if block lines [ push
			if { [regexp {^\?.+\?[ ]*\[} $buf_line ] ||[regexp {^\?.+\?.*::[ ]*\[} $buf_line ]} {
				_el_buffer_block_push [concat "[llength $line_buffer] \"if\" "]
			}

			# check if help lines are in file
			if { [ regexp {^;;;} $buf_line ] && $read_help == 1 } {
				set read_help 0
				# stip three semi-colons
				regsub {;;;} $buf_line {} buf_line
				# add last line of help
				lappend help_buffer  "$buf_line"
			} elseif { [ regexp {^;;;} $buf_line ] && $read_help == 0 } {
				set read_help 1
			} 

			# add line to buffer
			if { $read_help == 1 } {
				# place help lines into help_buffer
				# stip three semi-colons
				regsub {;;;} $buf_line {} buf_line
				#puts "==add help line==>[llength $line_buffer] | {$buf_line} {$meta_line}"
				lappend help_buffer  "$buf_line"
			} elseif { [regexp {^[$%*+:-@!~'\[\]-]} $buf_line ] } {
				# don't read in blank lines - make sure to include all needed lines [><?+*-~;@$=!%]
				# escape curly braces
				regsub -all {([{}])} $buf_line {\\\1} buf_line
				#puts "==add line==>[llength $line_buffer] | {$buf_line} {$meta_line}"
				lappend line_buffer  "{$buf_line} {$meta_line}"
			} 

		}
		if {$cmd_file != "" } {
			close $infile
		}
		#puts "-> $line_buffer|[llength $line_buffer] "

		# push new buffer stack
		incr _el_buf(stack)
		# save the buffer
		set _el_buf($_el_buf(stack)) $line_buffer
		
		# save the help buffer
		set _el_buf(help) $help_buffer
		
		# initialize the buffer pointer - points to the line no in the buffer
		set _el_buf($_el_buf(stack),ptr) 0

		# clear the block stack
		_el_buffer_block_clear
		
		# return the stack ID of this buffer
		return $_el_buf(stack)
	}
	
	#
	#	Clears buffer but retains stack pointer
	#	
	#
	proc _el_buffer_stack_clear { stack_number } {
		upvar expectlite::_el_buf					_el_buf

		# set buffer to empty list
		if { [info exists _el_buf($stack_number) ] } {
			set _el_buf($stack_number) {}
			# pop  buffer stack
			incr _el_buf(stack) -1
			
		}
	}
	
	#
	#	Reads buffer as if it were a file, returning a line from the buffer
	#	
	#
	proc _el_buffer_read { line_no buf_stack {line_info_field 0} {debug 0}} {
		upvar expectlite::_el_buf					_el_buf
		# line_info
		#set line_info_field 0
		
		if { $line_info_field == 0 } {
			#puts " $line_no | $buf_stack | $_el_buf($buf_stack,ptr) | [lindex $_el_buf($buf_stack) $line_no ] "
		}

		# Do not read past end of buffer
		if { $line_no < [llength $_el_buf($buf_stack)] } {
			# use lindex to return first field in line_no
			set buf_line [lindex $_el_buf($buf_stack) $line_no $line_info_field]
			# remove escaped braces
			regsub -all {\\([{}])} $buf_line {\1} buf_line
			if {$debug} {
				# show debug info, line number, line & meta-data
				set buf_line "$line_no | $buf_stack | [lindex $_el_buf($buf_stack) $line_no ] "
			}
			return $buf_line
		} else {
			return -1
		}
	}


	#
	#	Reads buffer, prints n lines
	#	
	#
	proc _el_buffer_show { num_of_lines buf_stack {debug 0}} {
		upvar expectlite::_el_buf			_el_buf
		upvar expectlite::_el_info_color		_el_info_color


		#puts " $num_of_lines | $buf_stack | $_el_buf($buf_stack,ptr) | [expr  $_el_buf($buf_stack,ptr) + $num_of_lines] "

		# don't print lines which are not in the buffer (have -1)
		proc print_line { line } {
			#global _el_info_color
			upvar  expectlite::_el_info_color		_el_info_color
			
			if { $line != -1 } {
				cputs "$line" $_el_info_color
			}
		} 
		# end print_line

		if {$num_of_lines > 0} {
			cputs "Printing next $num_of_lines line(s) of script:" $_el_info_color
			set num_of_lines [expr $num_of_lines + 1 ]
			for {set n [expr $_el_buf($buf_stack,ptr) +1]} {$n<[expr $num_of_lines + $_el_buf($buf_stack,ptr)]} {incr n} {
				print_line [ _el_buffer_read $n $buf_stack 0 $debug ]
			}
		} elseif {$num_of_lines < 0} {
			cputs "Printing last [expr {abs($num_of_lines)}] line(s) of script:" $_el_info_color
			for {set n [expr  $_el_buf($buf_stack,ptr) + $num_of_lines]  } {$n <  $_el_buf($buf_stack,ptr)} {incr n } {
				print_line [ _el_buffer_read $n $buf_stack 0 $debug ]
			}
		} else {
			# print current line
			cputs "Printing current line of script:" $_el_info_color
				print_line [ _el_buffer_read $_el_buf($buf_stack,ptr) $buf_stack ]

		}
	}
	
	#
	#	Reads buffer, returns list of items maching $obj
	#	
	#
	proc _el_buffer_get_obj { buf_stack {obj "\\\$"}} {
		upvar expectlite::_el_buf			_el_buf
		upvar expectlite::_el_info_color		_el_info_color

		set out_list {}
		#puts "obj>>>$obj|"
		foreach line $_el_buf($buf_stack) {
			if { [ regexp "^$obj" [lindex $line 0 ] ] } {
				lappend out_list [lindex $line 0]
			}
			#puts "ddd>$line"
		}
		#puts "out_list>$out_list"
		return $out_list
	}
	
	#
	#	Reads buffer, prints contigous help lines
	#	
	#
	proc _el_buffer_show_help { buf_stack {obj {^;;;} }} {
		upvar expectlite::_el_buf			_el_buf
		upvar expectlite::_el_info_color		_el_info_color
		upvar expectlite::WARN					WARN

		set out_list {}
		#puts "obj>>>$_el_buf(help)|"
		
		#check that there is text in the help buffer
		if { $_el_buf(help) != {} } {
			set i 0
			# display text in help buffer
			while { $i < [llength $_el_buf(help)] } {
				set buf_line [lindex $_el_buf(help)  $i]
				puts "\t$buf_line"
				incr i
			} ;#end while
		}


	}; #end proc

	#
	#	Goto buffer line number
	#	
	#
	proc _el_buffer_goto { line_no buf_stack } {
		upvar expectlite::_el_buf					_el_buf
		
		# Do not set past end of buffer
		if { $line_no >= 0 && $line_no <= [llength $_el_buf($buf_stack)] } {
			set _el_buf($_el_buf(stack),ptr) $line_no
		}
	}
	#
	#	clears block stack 
	#	
	#
	proc _el_buffer_block_clear { } {
		upvar expectlite::_el_buf_block_stack		stack

		set stack {}
	}

	#
	#	Pushes '[' line in buffer 
	#	
	#
	proc _el_buffer_block_push { meta_blob} {
		upvar expectlite::_el_buf_block_stack		stack

		#puts "=====>$line_no | $type | $stack "
		# meta_blob is line_no + type
		lappend stack $meta_blob
	}

	#
	#	pops '[' line in buffer and returns line number + type
	#	
	#
	proc _el_buffer_block_pop { } {
		upvar expectlite::_el_buf_block_stack		stack

		if { [llength $stack ] != 0 } {
			set meta_blob [lindex $stack end]
			#puts "====stack==>$stack | $meta_blob"
			# delete last item (most recent) in stack
			set stack [lreplace $stack end end]
			#puts "====stack==>$stack"
			return  $meta_blob
		} else {
			return -1
		}
	}

	#
	#	Buffer Search
	#	Searches buffer from line_ptr down to end of buffer
	#	If search fails, search will 'wrap' and continue from beginning of buffer
	#	This allows duplicate search items in the buffer, finding the first succeding one
	#		However search items used as looping labels should be unique!
	#
	proc _el_buffer_search {line_ptr line_search buf_stack} {
		upvar expectlite::_el_infinite_loop		_el_infinite_loop
		upvar expectlite::el_color				el_color
		upvar expectlite::INFO					INFO
		upvar expectlite::WARN					WARN
		upvar expectlite::DEBUG					DEBUG
		upvar expectlite::EXP_INFO				EXP_INFO
		upvar expectlite::_el_info_color		_el_info_color
		upvar expectlite::_el_warn_color			_el_warn_color
		upvar expectlite::_el_err_color			_el_err_color
		upvar expectlite::_el_comment_color		_el_comment_color
		upvar expectlite::_el_buf				_el_buf



		# search down first
		if {$INFO} {
			# start INFO color
			if {$_el_comment_color == "none"} {
				puts  -nonewline $el_color($_el_info_color)
			}
			puts -nonewline "\nJumping to label"

		}
		
		
		# get a list of pointers which match search of first field (line-data)
		if { [exp_version] >= "5.44.0" } {
			set _ptr_list [lsearch -all -index 0 $_el_buf($buf_stack) "$line_search"]
		} else {
			# TCL 8.4 does not support lsearh -index 
			set line_search_glob "\{$line_search*"
			set _ptr_list [lsearch -all $_el_buf($buf_stack) "$line_search_glob"]
		}
		
		if { $_ptr_list == {} } {
			if {$WARN} {
				puts -nonewline "\n\nWARNING: Label not found" 
			}
			# signal label not found
			set _ptr -1
		} else {
			# give preference to search backwards
			set i -1
			foreach ptr $_ptr_list {
				if { $ptr < $line_ptr } { incr i }
			}
			if { $i == -1} {
				# not found then search forwards
				foreach ptr $_ptr_list {
					if { $ptr > $line_ptr } { incr i ; break }
				}
			}
			set _ptr [lindex $_ptr_list $i]

			# decrement infinite loop detector 
			incr _el_infinite_loop -1
			if { $_el_infinite_loop < 1 } {
				# return search not found
				cputs ":$line_search\n\n\nERROR: Infinite Loop Detected!!\n\n" $_el_err_color
				return -2
			}
		}
		
		# put final field on info line
		if {$INFO} {
			cputs ":$line_search\n" $_el_info_color
		}
		#puts "|$line_search|$line_ptr|$_ptr_list|$_ptr|[lindex $_el_buf($buf_stack) 152]|"
		return $_ptr
	}
	#
	#	End of Buffer management functions
	#
	
	#
	#	Infinite loop detection
	#	
	#
	proc _el_check_infinite_loop { } {
		upvar expectlite::_el_infinite_loop		_el_infinite_loop
		upvar expectlite::_el_err_color			_el_err_color
		
		#cputs "=======>infinite_loop=$_el_infinite_loop" $_el_err_color
		# decrement infinite loop detector 
		incr _el_infinite_loop -1
		if { $_el_infinite_loop < 0 } {
			# return search not found
			cputs "\n\nERROR: Infinite Loop Detected!\n\n" $_el_err_color
			return -2
		}
		return 0
		
	}


	#
	#	Set Global expect-lite Directives
	#	
	#
	proc _el_global_directive { g_dir_str } {
		global timeout
		upvar expectlite::INFO					INFO
		upvar expectlite::EXP_INFO				EXP_INFO
		upvar expectlite::WARN					WARN
		upvar expectlite::DEBUG 				DEBUG
		upvar expectlite::_el_info_color		_el_info_color
		upvar expectlite::_el_warn_color		_el_warn_color
		upvar expectlite::_el_err_color 		_el_err_color
		upvar expectlite::_el_comment_color 	_el_comment_color
		upvar expectlite::_el_debug_color		_el_debug_color
		upvar expectlite::_el_eols				_el_eols
		upvar expectlite::_el_fork				_el_fork
		upvar expectlite::_el_current_session	_el_current_session
		upvar expectlite::_el_infinite_loop 	_el_infinite_loop
		upvar expectlite::NOFAIL				NOFAIL
		upvar expectlite::_el					_el
		upvar expectlite::TIMESTAMP 			TIMESTAMP
		upvar expectlite::NOINTERACT			NOINTERACT
		upvar expectlite::NOINCLUDE				NOINCLUDE
		upvar expectlite::LOG					LOG
		upvar expectlite::arg0					arg0
		upvar expectlite::cli_namespace			cli_namespace
		upvar expectlite::el_log_ext			el_log_ext
		upvar expectlite::SHOW_HELP				SHOW_HELP



		switch -glob $g_dir_str {	
			"\\*INFO"	{	# Turn on INFO logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				incr INFO
			}
			"\\*EXP_INFO"	{	# Turn on Expect INFO logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				set EXP_INFO 1
			}
			"\\*WARN"	{	# Turn on WARN logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				set WARN 1
			}
			"\\*DEBUG"	{	# Turn on DEBUG logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				set DEBUG 1
			}
			"\\*LOG*"	{	# Turn on LOG logging
				# set default log file name to script name+.log (e.g. $el_log_ext)
				if { [info exist cli_namespace($arg0)] } {
					set fname "$cli_namespace($arg0)$el_log_ext"
				} else {
					# use a default name
					set fname "expect-lite$el_log_ext"
				}
				
				# remove excess spaces in log string
				regsub {[ ]+} $g_dir_str " " g_dir_str
				set log_list [split $g_dir_str]
				
				if { [llength $log_list] > 2 } {
					if {$WARN} {
						cputs "\n\nWarning: LOG: Too Many Parameters: $g_dir_str\n" $_el_warn_color
					}
					# invalid *LOG command, exit this function
					return 1
				} elseif {[llength $log_list] == 2 } {
					#if { $LOG == 0 } { set LOG 1 }
					# get log filename
					set fname [lindex $log_list 1]
					# check for *LOGAPPEND
					if { [regexp {LOGA} [lindex $log_list 0]] == 1 } {
						set LOG -1
						# close any running log
						log_file
					}
				} elseif {[llength $log_list] == 1 } {
					set LOG 1
					if { [regexp {LOGA} [lindex $log_list 0]] == 1 } {
						set LOG -1
						# close any running log
						log_file
					}
				}				
				if { $SHOW_HELP } {
					# don't do any thing with the LOG
					set LOG -10
				}
				
				switch -- $LOG {
					1 -
					0	{ # open log file
						# check of log file exists, and issue warning
						if {[file exists $fname] == 1} {
							if {$WARN} {
							cputs "expect-lite: Warning: Overwriting $fname " $_el_warn_color
							}
						}
					
						# close running log
						log_file
						# make sure log file is writable
						if {[ catch { log_file; log_file -noappend "$fname"}  error ]} {
							cputs "expect-lite: ERROR: $error\n" $_el_err_color
							return -1
						}
						set LOG 1
					}
					-1	{ # Log was already open, so just append to log file
						if {[ catch { log_file -a "$fname"}  error ]} {
							cputs "expect-lite: ERROR: $error\n" $_el_err_color
							return -1
						}
						set LOG 1
						if {$INFO} {
							cputs "\nexpect-lite: Appending to log file: $fname" $_el_info_color
						}
					}
					10	{ #do nothing, overiden at CLI
					}
					-10	{ #do nothing, overiden at CLI
					}
				} ; # end switch
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				
			}
			"\\*NOLOG"	{	# Turn off LOG logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				# do not disable if CLI has enabled
				if {$LOG != 10 && $LOG != -10 } { 
					set LOG -1
					# turn off log file
					log_file
				}
			}
			"\\*NOINFO"	{	# Turn off INFO logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				# do not disable if CLI has enabled
				if {$INFO != 10 } { set INFO 0 }

			}
			"\\*NOEXP_INFO"	{	# Turn off Expect INFO logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				if {$EXP_INFO != 10 } { set EXP_INFO 0 }
			}
			"\\*NOWARN"	{	# Turn off WARN logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				# do not disable if CLI has enabled
				if {$WARN != 10 } { set WARN 0 }

			}
			"\\*NODEBUG"	{	# Turn off DEBUG logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				# do not disable if CLI has enabled
				if {$DEBUG != 10 } { set DEBUG 0 }

			}
			"\\*NOCOLOR"	-
			"\\*NOCOLOUR"	{	# Turn off Color logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				# set INFO color
				set _el_info_color none
				# set WARN color
				set _el_warn_color none
				# set ERROR color
				set _el_err_color none
				# set global color
				set _el_comment_color none		 	
			}
			"\\*NOTIMESTAMP"	{	# Turn off TIMESTAMP logging
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				# do not disable if CLI has enabled
				if {$TIMESTAMP != 10 } { set TIMESTAMP 0 }
			}
			"\\*PASS" -
			"\\*TERM"	{	# Terminate but Pass Test
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				### Terminate the test with a pass
				if {$INFO} {cputs "\n\n##Overall Result: PASS \n\n" $_el_info_color }
				exit 0
				
			}
			"\\*FAIL"	{	# Terminate and Fail Test
				cputs "\nexpect-lite directive: $g_dir_str " $_el_err_color
				if { $NOFAIL } {
					# set test to fail
					return 0
				} else {
					# NOFAIL not set, fail right now
					return 2
				}
			}
			"\\*EOLS LF"	{	# Set End of Line Sequence to LF
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				set _el_eols "\n"
			}
			"\\*EOLS CRLF"	{	# Set End of Line Sequence to CRLF
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				set _el_eols "\r\n"
			}
			"\\*SHOW VARS"	{	# Show expect-lite variables
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				show_vars
			}
			"\\*INTERACT"	{	# place into expect interact mode
				# Skip interact if in Library mode
				# Jump to interact
				if { $NOINTERACT == 0 } {
					cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
					instant_interact_sig
				} elseif {$NOINTERACT > 0} {
					cputs "\nSkipping expect-lite directive: $g_dir_str " $_el_info_color
				}
			}
			"\\*FORK*"	{	# Spawn/Switch to a new session
				set fork_list [split $g_dir_str]

				if { [llength $fork_list] > 2 } {
					if {$WARN} {
						cputs "\n\nWarning: FORK: Too Many Names: $g_dir_str\n" $_el_warn_color
					}
					# invalid *FORK command, exit this function
					return 1
				} elseif {[llength $fork_list] == 2 } {
					# set the fork_id to the passed value
					set fork_id [lindex $fork_list 1]
					# store current eols in current session fork_context
					set _el_fork($_el_current_session,eols) $_el_eols

				} elseif {[llength $fork_list] == 1 } {
					# no arguments to *FORK, then display current session name
					set fork_id $_el_current_session
				}
				# spawn/switch to fork_id session
				set _el_current_session [session_id_manager $fork_id]
				# set eols from new fork_id_context
				set _el_eols $_el_fork($_el_current_session,eols)
				#kick the prompt
				protected_send "$_el_eols"

			}
			"\\*NOFAIL"	{	# Never fail the test
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				incr NOFAIL
			}
		
			"\\*NOINTERACT"	{	# Never stop at *INTERACT (good for regression)
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				incr NOINTERACT
			}
			"\\*NOINCLUDE"	{	# Do not include files -- backward compatiblity with 4.1 behaviour
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				incr NOINCLUDE
			}
		}
		# end switch glob

		# set values with a parameter (using regex)
		switch -regexp $g_dir_str {	
			"\\*INFINITE_LOOP [0-9]+"	{	# expect-lite infinite loop value
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				set varlist [split $g_dir_str ]
				set _el_infinite_loop [lindex $varlist 1]
			}
			"\\*TCL .+" { #native TCL command for library use
				if { [info exist ::EL_LIBRARY] } {
					set ::_el_tcl_cmd [string trim $g_dir_str "*TCL "]
					# preserve timeout
					set el_timeout $::timeout
					# disable timeout during function call
					set timeout 0
					if { $DEBUG } {
						cputs "EL TCL CMD>$::_el_tcl_cmd" $_el_debug_color
					}
					# provide catch protection, and run tcl_cmd
					if {[ catch { uplevel #0 {eval $::_el_tcl_cmd }}  error ]} {
						cputs "ERROR: Expect: \'\n$::_el_tcl_cmd\' \n$error\n" $_el_err_color
					}
					# restore timeout
					set timeout $el_timeout
				}
			}
			"\\*TIMESTAMP" { #Issue Time Stamps with each > or >>
				cputs "\nexpect-lite directive: $g_dir_str " $_el_info_color
				set ts_list [split $g_dir_str]
				if { [llength $ts_list] > 2 } {
					if {$WARN} {
						cputs "\n\nWarning: TIMESTAMP: Too Many Parameters: $g_dir_str\n" $_el_warn_color
					}
					# invalid *TIMESTAMP command, exit this function
					return 1
				} elseif {[llength $ts_list] == 2 } {
					# set timestamp on & format string
					set TIMESTAMP 1
					set ts_format [lindex $ts_list 1]
					switch -glob $ts_format {
						"YMD"	-
						"ISO"    { set _el(ts_fmt) "\n\[ %Y-%m-%d %T \] " }
						"MDY"	 { set _el(ts_fmt) "\n\[ %D %T \] " }
						"DMY"	 { set _el(ts_fmt) "\n\[ %d-%m-%Y %T \] " }
						default { # set a ISO as default
									if {$WARN} { cputs "\n\nWarning: unknown format, using YMD" $_el_warn_color }
									set _el(ts_fmt) "\n\[ %Y-%m-%d %T \] " 
								}
					}

				} elseif {[llength $ts_list] == 1 } {
					# no arguments to *TIMESTAMP, default to ISO
					set TIMESTAMP 1
					# use YMD format as default
					set _el(ts_fmt) "\n\[ %Y-%m-%d %T \] "
				}

			} ; #timestamp

		}
		# end switch regex
		return 1
	}

	#
	#	Heart of expect-lite, reads through script file, and takes appropriate action (based on switch statement)
	#	
	#
	proc _el_script_exec {{cmd_file ""} {buf_stack ""}} {
		# default parameters: cmd_file is "" in library mode
		#	buf_stack is used when el_script is called recursively (e.g. include)

		global expect_out timeout spawn_id

		upvar expectlite::remote_host				remote_host
		upvar expectlite::_out						_out
		upvar expectlite::_out_nowait				_out_nowait
		upvar expectlite::_in						_in
		upvar expectlite::_in_noregex				_in_noregex
		upvar expectlite::_not_in					_not_in
		upvar expectlite::_timeout					_timeout
		upvar expectlite::_var						_var
		upvar expectlite::_cond 					_cond
		upvar expectlite::_cond_regex				_cond_regex
		upvar expectlite::_cond_else				_cond_else
		upvar expectlite::_label					_label
		upvar expectlite::_el						_el
		upvar expectlite::_el_buf					_el_buf
		upvar expectlite::_exec 					_exec
		upvar expectlite::_stdout_comment			_stdout_comment
		upvar expectlite::_stdout_comment_nobuf 	_stdout_comment_nobuf
		upvar expectlite::_include					_include
		upvar expectlite::_include_fail 			_include_fail
		upvar expectlite::comment_line				comment_line
		upvar expectlite::timeout_line				timeout_line
		upvar expectlite::timeout_multiplier		timeout_multiplier
		upvar expectlite::WARN						WARN
		upvar expectlite::delay_wait_for_host		delay_wait_for_host
		upvar expectlite::cli_namespace 			cli_namespace
		upvar expectlite::user_namespace			user_namespace
		upvar expectlite::user_dir					user_dir
		upvar expectlite::_el_infinite_loop 		_el_infinite_loop
		upvar expectlite::_incr_var 				_incr_var
		upvar expectlite::_decr_var 				_decr_var
		upvar expectlite::connect_method			connect_method
		upvar expectlite::_el_fork					_el_fork
		upvar expectlite::DEBUG 					DEBUG
		upvar expectlite::INFO						INFO
		upvar expectlite::arg0						arg0
		upvar expectlite::_el_comment_color 		_el_comment_color
		upvar expectlite::_el_info_color			_el_info_color
		upvar expectlite::_el_warn_color			_el_warn_color
		upvar expectlite::_el_err_color 			_el_err_color
		upvar expectlite::_el_debug_color			_el_debug_color
		upvar expectlite::_el_eols					_el_eols
		upvar expectlite::el_color					el_color
		upvar expectlite::EXP_INFO					EXP_INFO
		upvar expectlite::_el_current_session		_el_current_session
		upvar expectlite::NOFAIL					NOFAIL
		upvar expectlite::NOINCLUDE					NOINCLUDE
		upvar expectlite::TIMESTAMP 				TIMESTAMP



		set prev_line ""
		set comment_line ""
		set timeout_line ""
		set _el_fail_script ""
		set teststr ""

		array set _foreach {}
				
		# used in if and while lines
		set _test_result 0
		
		# clear expect lines list
		set _el_cont_lines ""

		# set default session (aka fork)
		set _el_current_session $_el(fork_current)
		#fork_id

		#
		# Dereference Vars if needed in $_el(line) as read from cmd file	
		#	
		proc _el_deref_line {} {
			#global _el _var _cond
			upvar expectlite::_el					_el
			upvar expectlite::_var					_var
			upvar expectlite::_cond					_cond
			
			if { [regexp {.*\$[A-Za-z0-9]+.*} $_el(line) ] } {
				# Detect the use of a user_var
				#puts "l0>$_el(line)"
				switch -regexp -- $_el(line) {
					{^\[[ ]*\$[a-zA-Z0-9_]+[ ]?[=][ a-zA-Z0-9$]+.*} -
					{^\$.*} -				
					{^\+\$.*} { # repeat variable line, variable line, dyn var line
						# this is a dyn var definition line - remove leading '+'
						if { [regexp -line {^\+\$.*} $_el(line)] == 1} {
							set prepend "+"
							# remove leading '+'
							regsub {^\+} $_el(line) {} _el(line)

							} else {set prepend ""}
						# this is a var definition line - don't dereference first var (it is being set)
						set parse_list1 [split $_el(line) "="]
						#puts "===PL>$parse_list1, [llength $parse_list1]"
						# check that this is an assignment, and not an increment var command
						if { [llength $parse_list1] >= 2 } {
							# check if there are other variables on left side of equals assignment
							set _left_vars [lindex $parse_list1 0]
							set _el_var_list [split $_left_vars "$"]
							#puts "========>$_el_var_list"
							# is there more than one var on the left-side of the assignment?
							if { [llength $_el_var_list] > 2 } {
								set _left_vars [join [lrange $_el_var_list 1 end ] "$"]
								# dereference left-side vars except first one
								set _left_vars [parse_var $_left_vars $_var]
								set _left_vars "\$[lindex $_el_var_list 0]$_left_vars"
								# detect illegal chars in var name?
								#regsub {[^A-Za-z0-9_$]} $_left_vars {} _left_vars
							}
							# 1st pass of dereferncing assignment variables
							set _right_value [join [lrange $parse_list1 1 end] "="]
							#set _el_assignment [parse_var [lindex $parse_list1 1] $_var]
							#puts "====RV>$_right_value"
							set _el_assignment [parse_var $_right_value $_var]
							# 2nd pass of dereferencing assignment variables
							set _el(line) "$_left_vars=[parse_var $_el_assignment $_var]"
						}
						# place '+' back on front when needed
						set _el(line) "$prepend$_el(line)"
						#puts "l2>$_el_assignment|"
						#puts "l2>$_el(line)"
					} 
					{^\-\$.*} {
						# this is a decr var line - don't touch it
					}	
					{^\*[A-Z]+.*} - 
					{^\=\$.*} {
						# this is used to dereference a *DIRECTIVE $var line as well as math var line.
						# this is a math var definition line - don't dereference first var (it is being set)
						# separate var from rest of line with space
						regsub {^(=\$[A-Za-z0-9_]+)}  $_el(line) {\1 } _el(line)
						set parse_list1 [split $_el(line) " "]
						set _math_var [lindex $parse_list1 0]
						# remove math variable from list
						set parse_list1 [lreplace $parse_list1 0 0]
						set _parse_line [ join $parse_list1 " " ]
						#puts "l2.1>$_parse_line"
						# first pass at dereferencing variables
						set _parse_line [parse_var $_parse_line $_var]
						# extra space "  " prevents arrays from being supported
						set _el(line) "$_math_var  [parse_var $_parse_line $_var]"

						#puts "l2>$_el(line)"
					} 
					{^\#.*} { 
						# this is a comment line - don't touch it
					} 
					{^\?.+\?.+} {
						# This is a conditional line, only dereference Vars in Conditional part
						# remove "if" if present
						regsub {^\?[iI]?[fF]?} $_el(line) "?" _el(line)
						# insert spaces around conditional operator to permit proper resolving of variables
						# Only act on conditional part of the line (between the ?'s)
						#regsub {([<>][^^][=]?)} $_el(line) { \1 } _el(line)
						regsub {\?(.+)([<>][=]?)(.+)\?(.+)} $_el(line) {? \1 \2 \3 ?\4} _el(line)
						#puts "PL0>$_el(line)"
						# parse cond from action
						#set parse_list1 [split $_el(line) "?"]

						set parse_list1 ""
						# remove first '?' on conditional line
						regsub {^[ \t]*[?]} $_el(line) {} _el(line)
						# parse cond from action
						lappend parse_list1 [string range $_el(line) 0 [expr [string first $_cond $_el(line)] - 1]]
						lappend parse_list1  [string range $_el(line) [expr [string first $_cond $_el(line)] + [string length $_cond] ] [string length $_el(line)]]

						#puts "PL1>$parse_list1|[llength $parse_list1]"
						if { [llength $parse_list1] >= 2 } {
							# rebuild _el_line: ?cond?$action_str
							# build action assigment and else_action without dereferencing
							set action_str " [join [lrange $parse_list1 1 [llength $parse_list1] ] ""]"
							# first pass dereferencing
							set _parse_line [parse_var [lindex $parse_list1 0] $_var ]
							set _el(line) "?[parse_var $_parse_line $_var]? $action_str"
						}
						#puts "EL_LINE_COND>$_el(line)"

					}
					default {
						#puts "EL_LINE1>$_el(line)"
						# Process Line resolving vars if needed
						set parse_list1 [split $_el(line) ]
						#puts "p1>$parse_list1"
						set plist2 {}
						foreach i $parse_list1 {
							lappend plist2 [ parse_var $i $_var ]
						}
						set _el(line2) [join $plist2 " "]
						set _el(line) $_el(line2)
						# are there still vars to be dereferenced, if so, to a second pass
						if { [regexp {.*\$[A-Za-z0-9]+.*} $_el(line) ] } {
							# Process Line resolving vars if needed
							set parse_list1 [split $_el(line) ]
							#puts "p1>$parse_list1"
							set plist2 {}
							foreach i $parse_list1 {
								lappend plist2 [ parse_var $i $_var ]
							}
							set _el(line2) [join $plist2 " "]
							set _el(line) $_el(line2)
						}
						#puts "EL_LINE2>$_el(line)"

					} 
				} 
				#switch
			} 
			#if
		} 
		#proc _el_deref_line


		#
		#	Execute expect lines buffered in list variable _el_lines 
		#
		#
		proc _el_exec_expect {} {
			#Allow embedded Expect access to only the following internal vars
			#global cli_namespace user_namespace timeout remote_host user_dir 
			global errorInfo 
			upvar expectlite::_el_debug_color		_el_debug_color
			upvar expectlite::_el_err_color		_el_err_color
			upvar  expectlite::DEBUG 					DEBUG

			upvar _el(_el_lines) __el_lines _el_cont_lines __el_cont_lines 

			#puts "=>[llength _el_lines]:$_el_lines:"
			if {  $__el_lines != {} } {

				# join Expect lines		
				set __el_cont_lines [join $__el_lines " ; "]
				if {$DEBUG} {cputs "EL-Expect: $__el_cont_lines \n" $_el_debug_color}

				if {[ catch { uplevel {eval $_el_cont_lines }}  error ]} {
					regsub -all " ; " $__el_cont_lines "\n" __el_cont_lines
					cputs "ERROR: Expect: \'\n$__el_cont_lines\' \n$errorInfo\n" $_el_err_color
				}

				# clear cont lines
				set __el_lines {}
				# re-derefence variables in $_el(line)
				#	required when embedded expect changes user_namespace(variable) values
				_el_deref_line
			}	
		} 
		# end of _el_exec_expect


		# idea: if $cmd_file begins with '|' then process as a _el(line) rather than a file
		# 	Used for conditional actions, which are a recursive call to _el_script_exec
		#	Also used by interact to execute lines of expect-lite script
		# initialize vars
		set _one_line 0

		if { $cmd_file == "" } {
			# use pre-read _el_buf(stack)
			# read first line of buffer
			set _el(line) [_el_buffer_read  $_el_buf($buf_stack,ptr) $buf_stack]
			set _el(line_meta) [_el_buffer_read  $_el_buf($buf_stack,ptr) $buf_stack 1]
			
		} elseif { [ regexp {^\|} $cmd_file ] == 0} {
			#puts "zzz>$cmd_file|[ regexp {^\|} $cmd_file ]"
			# read in cmd_file to buffer - no longer used
			cputs "\nError: Calling el_script_exec <filename> has been deprecated\n as of v4.3.0" $_el_err_color
			#HALT
			exit 2
			

		} else {
			# cmd_file is string to evaluate (trim leading spaces if needed)
			regsub {\|[ ]*(.*)} $cmd_file {\1} _el(line)
			set _one_line 1
		}
		# set test up for success
		set _el(success) 1
		while { -1 != $_el(line) } {
			# deref line
			_el_deref_line


			#puts "el(line):$_el(line)"


			switch -regexp -- $_el(line) {
				^\#	{	# Don't send lines that start with a '#' which are commented

						print_comment_line

					}
				{(^>|^>>)\^[A-\]a-z]}	{
						# Don't wait for prompt, Generalized routine to send control chars

						# get ascii value of char
						scan [string index $_el(line) [expr [string length $_el(line)] -1]] %c control_char_ascii
						# parse char from passed string
						set control_char [string index $_el(line) [expr [string length $_el(line)] -1]]
						# print timestamp
						if { $TIMESTAMP } {
							cputs  [timestamp -format $_el(ts_fmt)] "none" "-nonewline"
						}
						# Check if passed char is lower case
						if {[expr $control_char_ascii - 96] > 0 } {
							# Send lower case control char
							send -- [format %c [expr $control_char_ascii - 96]]
						} else {
							# Send upper case control char
							send -- [format %c [expr $control_char_ascii - 64]]
						}
						#puts "=>$control_char_ascii"
						# notify user
						puts "sending ^$control_char\n"
						set prev_line $_el(line)
					}
				^\>>	{	# Don't wait for Prompt just send the line

						print_comment_line
						# execute expect lines if present
						_el_exec_expect

						# delay to give remote-host a little time (in ms)
						after 10
						# print timestamp
						if { $TIMESTAMP } {
							cputs  [timestamp -format $_el(ts_fmt)] "none" "-nonewline"
						}
						# Check of remote_host is still connected before sending string
						if { [catch { send  -- "[_el_strip_char $_el(line) $_out_nowait]$_el_eols"  } error] } {
							cputs "CONNECT ERROR: Lost connection to $remote_host \n   $error \nExiting..." $_el_err_color
							# Fail script
							exit 1
						}
						set prev_line $_el(line)
						# clear expect buffer
						expect -re {.*} {}

					}
				^\>	{	# Wait for Prompt and send the line

						# do not wait for prompt if only one_line
						if { $_one_line == 0 } {
							wait_for_prompt
						}
						print_comment_line
						# execute expect lines if present
						_el_exec_expect

						# Set test up for success
						set _el(success) 1
						# print timestamp
						if { $TIMESTAMP } {
							cputs  [timestamp -format $_el(ts_fmt)] "none" "-nonewline"
						}

						# Check of remote_host is still connected before sending string
						if { [catch { send  -- "[_el_strip_char $_el(line) $_out]$_el_eols"  } error] } {
							puts stderr "CONNECT ERROR: Lost connection to $remote_host \n   $error \nExiting..."
							# Fail script
							exit 1
						}
						set prev_line $_el(line)
						# clear expect_out buffer
						expect -re {.*} {}
						#set expect_out(buffer) ""
						if {$connect_method == "none"} {
							# delay in ms - slow down the host, give the target time to respond
							after [expr $delay_wait_for_host * 2]
						}	
					}
				^\<\<	{ 	# Expect teststr without regex or set success to 0 and fail test		'<<'=no regex
						set _el(success) 0
						print_comment_line
						# execute expect lines if present
						_el_exec_expect
						set teststr [_el_strip_char $_el(line) $_in_noregex]

						# catch expect, just in case
						if {[catch {expect -ex "$teststr" { set _el(success) 1 } } error  ] } {
							if {$WARN} {
								cputs "\nExpect error: Expect-lite: $error\n" $_el_err_color
							}
						}

						# look at the expect_out(buffer) for debugging
						if { $DEBUG } {
							cputs "\nfind<<$teststr>>" $_el_debug_color
							cputs "  in<<$expect_out(buffer)>>" $_el_debug_color
							#puts "  found_in<<$expect_out(0,string)>>"
							cputs "\n" $_el_debug_color
						}
						# show expect found string
						if { $EXP_INFO && $DEBUG==0 && $_el(success)==1 } {
							cputs "$el_color(left_angle)$el_color(left_angle)$expect_out(0,string)" $_el_info_color
						}
					}
				^\<	{ 	# Expect teststr or set success to 0 and fail test	'<'=use regex
						set _el(success) 0
						print_comment_line
						# execute expect lines if present
						_el_exec_expect
						set teststr [_el_strip_char $_el(line) $_in]

						# test for single num expect string
						if {([string length $teststr]==1) && ([regexp \[0-9\] $teststr])} {
					    	expect {
								 -re \n$teststr\r { 
					 		    	#puts "\nGood=[_el_strip_char $_el(line) $_in]\n" 
							    	set _el(success) 1
							    	}
								 -re $teststr {
								 	set _el(success) 1
								 	}
						    	}
						} else {
							# test for multi-char expect strings
							# catch expect, just in case
							if {[catch {expect -re "$teststr" { set _el(success) 1 } } error  ] } {
								if {$WARN} {
									cputs "\nWarning: Expect-lite: $error: Attempting to fix\n" $_el_warn_color
								}
								# escape parens or square brackets
								regsub {([^\\])[(]} $teststr {\1\(} teststr
								regsub {([^\\])[)]} $teststr {\1\)} teststr
								# fix potential unbalanced square brackets
								regsub {([^\\])[[]} $teststr {\1\[} teststr
								regsub {([^\\])[]]} $teststr {\1\]} teststr
								# escape braces
								regsub {([^\\])[\{]} $teststr {\1\{} teststr
								regsub {([^\\])[\}]} $teststr {\1\}} teststr
								#puts "+>$teststr"
								if {[catch {expect -re "$teststr" { set _el(success) 1 } } error  ] } {
									puts "\nBUG: Expect-lite: $error\n Fix Failed\n"
								}
							}
					 		#puts "\nGood=[_el_strip_char $_el(line) $_in]\n" 
						}
						# look at the expect_out(buffer) for debugging
						if { $DEBUG } {
							cputs "\nfind<<$teststr>>" $_el_debug_color
							cputs "  in<<$expect_out(buffer)>>" $_el_debug_color
							#puts "  found_in<<$expect_out(0,string)>>"
							cputs "\n" $_el_debug_color
						}
						# show expect found string
						if { $EXP_INFO && $DEBUG==0 && $_el(success)==1} {
							regsub ".*($teststr)" $expect_out(buffer) {\1} foundstr
							cputs "$el_color(left_angle)$foundstr" $_el_info_color
						}

					}
				^\-<	{ 	# NOT Expect teststr and If it is found then set success to 0 and fail test
						set _el(success) 0
						print_comment_line
						# execute expect lines if present
						_el_exec_expect
						set teststr [_el_strip_char $_el(line) $_not_in]

						# delay in ms - slow down the host, give the target time to respond
						after $delay_wait_for_host	

						# wait for something in expect_out buffer if using localhost
						if {$connect_method == "none"} {
							expect {
								-timeout 1 -notransfer -re {\n.+\n} {}
								}
						}

						# search all text in expect in buffer -- using -notransfer to keep data in expect input buffer
						# Reverse logic, if the NOT match string is found, then set _el(success) to 0 and fail test
						expect {
							-timeout 0 -notransfer -re  $teststr {set _el(success) 0} 
							default {set _el(success) 1}
							}
						# look at the expect_out(buffer) for debugging
						if { $DEBUG } {
							cputs "\nNOT find<<$teststr>>" $_el_debug_color
							cputs "  in>>$expect_out(buffer)<<" $_el_debug_color
							cputs "\n" $_el_debug_color
						}

					}
				^\@ 	{ 	# Update the timeout value
						
						# validate that the timeout value is a number
						print_comment_line
						# execute expect lines if present
						_el_exec_expect
						if {([regexp \[^0-9\ \]+ [_el_strip_char $_el(line) $_timeout]])} {
							if {$WARN} {
								cputs "WARN: Bad Timeout Value: [_el_strip_char $_el(line) $_timeout] " $_el_warn_color
							}
							#send "quit$_el_eols"
							# Stop the script Now! - removed in 4.4.0
							#exit 1
						} else {
							#puts "\nSetting Expect Timeout to: [_el_strip_char $_el(line) $_timeout] \n"
							set timeout_int [_el_strip_char $_el(line) $_timeout]

							if { $cli_namespace($timeout_multiplier) != 1 } {
								# user has changed timeout_multiplier to something other than 1, use the value
								set timeout [expr $timeout_int * $cli_namespace($timeout_multiplier)]
								set timeout_line "\nTimeout Multiplier mode: Setting Expect Timeout to: $timeout \n"
							} else {
								set t_timeout $timeout_int
								set timeout_line "\nSetting Expect Timeout to: $t_timeout \n"
								set timeout $t_timeout
							}
						}
						# print new timeout value if one_line is set (e.g. from IDE)
						if { $_one_line == 1 } {
							if {$INFO} {
								cputs $timeout_line $_el_info_color
							}
						}
					}
				^\\\?[iI]?[fF]?	{	# Conditional processing - ?cond?action::else_action

						# execute expect lines if present
						_el_exec_expect

						print_comment_line

						set _cond_line [_el_strip_char $_el(line) $_cond_regex]
						#puts "\n##>[_el_strip_char $_el(line) $_cond_regex]\n"
						# remove optional 'if' or 'IF'
						regsub {^[iI]?[fF]?} $_cond_line "" _cond_line

						#parse conditional and action (and else_action if needed)
						set _else_action ""
						set _action [string range $_cond_line [expr [string first $_cond $_cond_line] + [string length $_cond] ] [string length $_cond_line]]
						#puts "\n##ACT>$_cond_line|$_action|[string first $_cond $_cond_line]|[string length $_cond]|[string length $_cond_line]"
						# check for else action - defined by ::
						
						if { [regexp $_cond_else $_action] } {
							# add spaces to else separator
							regsub {([^0-9a-f])::([^0-9a-f])} $_action "\\1 $_cond_else \\2" _action
							#regsub {::} $_action " $_cond_else " _action
							
							# parse action into action::else_action
							#set _else_action [string range $_action [expr [string first $_cond_else $_action] + [string length $_cond_else] ] [string length $_action]]
							#set _action [string range $_action 0 [expr [string first $_cond_else $_action] - [string length $_cond_else] ]]
							
							regsub {^(.+) :: (.+)$} $_action "\\2" _else_action
							regsub {^(.+) :: (.+)$} $_action "\\1" _action
							# trim trailing spaces
							set _action [string trimright $_action]
							#puts "#2#>then$_action|else$_else_action|"
						}
						set _conditional [string range $_cond_line 0 [expr [string first $_cond $_cond_line] - [string length $_cond] ]]

						# define list of supported conditional operators
						set _cond_oper_list { == != <= >= < > }

						# find conditional operator
						set _cond_oper "@"
						foreach k $_cond_oper_list {
							if { [regexp $k $_conditional] } {
								set _cond_oper $k
								break
							}
						}
						 # parse around conditional operator
						set _cond_arg1 [string range $_conditional 0 [expr [string first $_cond_oper $_conditional] - 1]]
						set _cond_arg2 [string range $_conditional [expr [string first $_cond_oper $_conditional] + [string length $_cond_oper] ] [string length $_conditional]]
						#puts "\n#@@|$_cond_oper|$_conditional|$_cond_arg1|$_cond_arg2|"

						# remove leading and trailing spaces from conditional arguments
						# count the number of non-space chars in condition
						if {[string length [regexp -inline {[^ ]+} $_cond_arg1]] > 1 } {
							# condition larger then 1 byte
							regsub -all {([ ]*)([^ ].*[^ ])([ ]*)} $_cond_arg1 {\2} _cond_arg1
						} else {
							# condition only 1 byte in size
							regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg1 {\2} _cond_arg1
						}
						
						if { [string length [regexp -inline {[^ ]+} $_cond_arg2]] > 1 } {
							# condition larger then 1 byte
							regsub -all {([ ]*)([^ ].*[^ ])([ ]*)} $_cond_arg2 {\2} _cond_arg2
							#puts ">$_cond_arg2<"
						} else {
							# condition only 1 byte in size
							regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg2 {\2} _cond_arg2
							#puts ">$_cond_arg2<"
						}

						# preserve buffer pointer - if not one_line
						if { $_one_line != 1 } {
							set _tmp_buf_ptr $_el_buf($buf_stack,ptr)
						}

						# validate comparison and if true, send to _el_script_exec (recursive call)

						# check for unresolved Var
						# Var is defined as in the set [a-zA-Z0-9_]
						if { [regexp {\$[a-zA-Z0-9_]+} $_conditional] } {
							if {$DEBUG} { cputs "EL:Unresolved Var:$_conditional" $_el_debug_color}
							# replace all unresolved vars with ""
							regsub -all {\$[a-zA-Z0-9_]+} $_cond_arg1 {} _cond_arg1
							regsub -all {\$[a-zA-Z0-9_]+} $_cond_arg2 {} _cond_arg2							
						} 
						# build test line
						set _test " expr { \"$_cond_arg1\" $_cond_oper \"$_cond_arg2\" } "
						# check for syntax errors and evaluate result of test line
						if {[catch { eval  $_test  } error ] } {
							if {$WARN} {
								cputs "\nWarning: Expect-lite: $error: Unable to detect conditional operator\n" $_el_warn_color
								cputs "	Evaluating line:$_test|$_action|$_else_action" $_el_warn_color
							}
						} else {
							# Show user the if statement, action and result
							set _test_result [eval  $_test ]
							if {$_test_result} {
								set _test_result "TRUE"
								# code block, else_action is false
								if { [ regexp {^[ \t]*\[} $_else_action ] } {
									#puts "=====going to>$_el(line_meta)|$_el_buf(stack)"
									_el_buffer_goto [expr $_el(line_meta) ] $_el_buf(stack)
								}
							} else {
								set _test_result "FALSE"
								
								# code block, action is false
								if { [ regexp {^[ \t]*\[} $_action ] || [ regexp {\?.+\?.*\[} $_action ] } {
									#puts "=====going to>$_action|$_el(line_meta)|$_el_buf(stack)"
									_el_buffer_goto [expr $_el(line_meta) ] $_el_buf(stack)
								}
							}
							if {$INFO} {
								if { $_else_action == ""} {
									cputs "\nIf:$_test|then$_action|result=$_test_result\n" $_el_info_color
									#puts "======buf stack>$_el_buf(stack)"
								} else {
									cputs "\nIf:$_test|then$_action|else$_else_action|result=$_test_result\n" $_el_info_color
								}
							};#if INFO
							# issue warning if both then & else actions are code blocks
							if { [regexp {^[ \t]*\[} $_action ] && [regexp {^[ \t]*\[} $_else_action ] } {
								if { $WARN } {
									cputs "\nWarning: Expect-lite: Code Blocks not supported in both then & else actions\n" $_el_warn_color
								}
							}
								
							# no syntax error, go ahead and eval the conditional action or else action
							# skip to label if present in action or else_action
							if { [eval  $_test ] } {
								# remove any leading space and trailing from action
								regsub {^[ \t]+} $_action {} _action
								regsub {[ \t]+$} $_action {} _action
								# Is there a jump to a label in action?
								if { [ regexp "^$_label" $_action ] } {
									_el_buffer_goto [_el_buffer_search $_el_buf($buf_stack,ptr) $_action $buf_stack] $_el_buf(stack)
								} elseif { [ regexp {^\[} $_action ] } {
									# code block NOP
								} else {
									# Interpret action with recursive call to _el_script_exec
									_el_script_exec "\|$_action" $buf_stack
								}
							} elseif { $_else_action != "" } {
								# remove any leading and trailing space from else_action
								regsub {^[ \t]+} $_else_action {} _else_action
								regsub {[ \t]+$} $_else_action {} _else_action
								# Is there a jump to a label in else_action?
								if { [ regexp "^$_label" $_else_action ] } {
									_el_buffer_goto [_el_buffer_search $_el_buf($buf_stack,ptr) $_else_action $buf_stack] $_el_buf(stack)
								} elseif { [ regexp {^\[} $_else_action ] } {
									# code block NOP
								} else {
									# Interpret else_action with recursive call to _el_script_exec
									_el_script_exec "\|$_else_action" $buf_stack
								}
							}
						}
						if { $_one_line != 1 } {					
							# label not found
							if { $_el_buf($buf_stack,ptr) == -1 } {
								# label search failed (-1), restore buf_ptr, allow script to continue
								#set _el_buf($buf_stack,ptr) $_tmp_buf_ptr
								_el_buffer_goto $_tmp_buf_ptr $_el_buf(stack)
							}

							# infinite loop detected!
							if { $_el_buf($buf_stack,ptr) == -2 } {
								# label search failed (-2), restore buf_ptr, allow script to continue
								#set _el_buf($buf_stack,ptr) $_tmp_buf_ptr
								_el_buffer_goto $_tmp_buf_ptr $_el_buf(stack)
								# signal to fail script - something is wrong
								set _el(success) 0
								# tell the user why this failed
								set prev_line "Infinite Loop Detected!"
							}
							#puts "++++++ptr>$_el_buf($buf_stack,ptr)"
						}
					}
				^\;;[^;]	{	# Send "comment" to stdout unbuffered

						# execute expect lines if present
						_el_exec_expect

						# Find color at beginning of comment line and use it, if not, use default comment color
						set unbuf_comment [_el_strip_char $_el(line) $_stdout_comment_nobuf]
						set unbuf_color [find_color $unbuf_comment] 
						if { $unbuf_color != "" } {
							# remove first word
							regsub "$unbuf_color" $unbuf_comment "" unbuf_comment
							# use custom color
							cputs $unbuf_comment $unbuf_color
						} else {
							# use default comment color
							cputs $unbuf_comment $_el_comment_color
						}

					}
				^\;[^;]	{	# Send "comment" to stdout buffered

						# execute expect lines if present
						_el_exec_expect

						print_comment_line

						set comment_line [_el_strip_char $_el(line) $_stdout_comment]
						# print comment if one_line is set
						if {$_one_line} { print_comment_line }

					}
				^\~ 	{	# include file from same location at cmd_file
						# Uses recursion to interpret included file

						# execute expect lines if present
						_el_exec_expect

						print_comment_line

							
						set _include_file [_el_strip_char $_el(line) $_include]
						#puts "==========> $_include_file"

						# set up passed values
						set _var_value [split $_include_file " "]
						set _include_file_str $_include_file
						# get only the first word as include file
						set _include_file [lindex [split $_include_file " " ] 0]

						# This was 4.1 EL_LIBRARY behavior
						if { $NOINCLUDE == 0 } {
							# don't include file if name is set to __NO_STRING_CAPTURED__ (which is a blank dynamic/capture variable)
							if { $_include_file != "__NO_STRING_CAPTURED__" } {
								# absolute path to include file?
								set _slash "/"
								if { [string index $_include_file 0] == $_slash} {
									set include_path_file "$_include_file"
								} else {
									set include_path_file "[parse_cmd_file_path $_el(cmd_file)]$_include_file"
								}
								#puts "->$include_path_file"
								if {$INFO} {
									cputs "\nIncluding: $_include_file_str\n" $_el_info_color
								}
								# Make Recursive Call in stand alone mode

								# parse passed constants on include line
								set _pass_var_values [ _el_parse_var_value $_var_value ]
								#puts "==========> $_pass_var_values"

								# preserve constants going into include
								set _keep_var_values [ _el_preserve_const $_pass_var_values ]

								# read in cmd_file to buffer
 								set buf_stack [_el_buffer $include_path_file]

								# preserve test_failed going into include file
								set _preserve_test_result $_el(test_failed)
								set _el(test_failed) 0

								set result [_el_script_exec "" $buf_stack]
								# don't report false include failure, set test_failed
								switch -- $result {
									0 { # pass
										set _el(success) 1
										set _el(test_failed) $_preserve_test_result
										}
									1 { # fail
										set _el(success) 0
										# no need to restore, it failed
										set _el(test_failed) 1

										cputs "\n##Include Result: FAILED: $include_path_file\n" $_el_err_color
										}
									2 { # fail right now!
										# return result code to caller, stop now
										return $result
										}
								}; #switch
								# pop _el_buf(stack)
								_el_buffer_stack_clear $buf_stack
								incr buf_stack -1
								# sync with global value, for INTERACT/IDE
								set _el_buf(stack) $buf_stack
								# restore constants
								_el_restore_const $_keep_var_values
							}; # if include file not __NO_STRING_CAPTURED__
						} else {
							cputs "\nWarning: *NOINCLUDE: Skipping include file:$_include_file\n" $_el_warn_color

						}; #if

					}
				^\\+\\$[A-Za-z0-9_]+[=]	{ 	# Setup Dynamic Var using Expect Capture
						# execute expect lines if present
						_el_exec_expect

						print_comment_line
						# delay in ms - slow down the host, give the target time to respond
						after $delay_wait_for_host
						# parse $_el(line) to pull out var and expect parts
						#puts "\n->$_el(line)"
						set user_var [string range $_el(line) 1 [expr [string first "=" $_el(line)] -1 ]]
						set user_value [string range $_el(line) [expr [string first "=" $_el(line)] +1 ] [string length $_el(line)]]
						#puts "\n->$user_var=$user_value"
						# remove '$' in front of the Var
						regsub {\$} $user_var "" user_var

						#set teststr [_el_strip_char $_el(line) $_setvar]
						set capture_val "__NO_STRING_CAPTURED__"
						set _el(var_capture_begin) [ clock seconds ]
						expect {
							-notransfer -re "\n$_el(prompt)|\n.*\\\$ $|\n.*# $|\n.*> $|\n.*% $" {

								# Do capture in expect buffer
								if { [catch {regexp -line "$user_value" $expect_out(buffer) match_val capture_val}]  } {
									set capture_val "__NO_STRING_CAPTURED__"
									set match_val ""
								}
								# remove newlines from capture value
								# add spaces to make foreach lists easier
								regsub -all {[\n\r]+} $capture_val " " capture_val
								
								if { $DEBUG } {
									cputs "\nvar_found<<$capture_val>>" $_el_debug_color
									cputs "\nvar_in<<$expect_out(buffer)>>" $_el_debug_color
								}
								if { $INFO } {
									#puts "\nAssigned Var:$user_var=|$capture_val|\n"
									cputs "\nAssigned Var:$user_var=$capture_val\n" $_el_info_color
								}
								# Trigger a new prompt - commented out cvm 10/2/10
								#protected_send "$_el_eols"
								}
							# expect should never timeout, but just in case
							timeout {
								set _el(var_capture_end)	[ clock seconds ]
								set _el(var_capture_duration) [ expr $_el(var_capture_end) - $_el(var_capture_begin)]
								if { $timeout != $_el(var_capture_duration)} {
									puts "BUG: Expect-lite: Var Capture Timed Out!\n"
									puts "Debugging Info: \n\tEL_Line:$_el(line)\n\texpect timeout=$timeout secs \n\tDuration of capture:$_el(var_capture_duration) secs \n\n"
									show_vars
								} elseif {$WARN} {
									cputs "Warning: Expect-lite: Var Capture Timed Out! Recommend lengthening timeout, current timeout is: $timeout secs\n" $_el_warn_color
									if { $DEBUG } {
										cputs "\nfound<<$capture_val>>" $_el_debug_color
										cputs "\nin<<$expect_out(buffer)>>" $_el_debug_color
									}

								}
							}
						}
						# set var (similar to below)
						set user_namespace($user_var) $capture_val
					}
				{^\$[A-Za-z0-9_]+[=]([ ]?|[~\$\[/A-Za-z0-9_.-]+)} {
						# allow a single space or blank as a value in addition to the normal assignment

						# execute expect lines if present
						_el_exec_expect

						# Set a user variable 

						set user_var [string range $_el(line) 1 [expr [string first "=" $_el(line)] -1 ]]
						set user_value [string range $_el(line) [expr [string first "=" $_el(line)] +1 ] [string length $_el(line)]]

						# remove '$' in front of the Var
						regsub {\$} $user_var "" user_var

						# Assign the Var
						set user_namespace($user_var) $user_value

						# Used for debugging
						#puts "->$user_var $user_value"
						#parray user_namespace
						}
				^\\+\\$[A-Za-z0-9_]+	{ 	# increment Var, decimal 
						# execute expect lines if present
						_el_exec_expect

						print_comment_line

						set _tmp_var [_el_strip_char $_el(line) $_incr_var]
						#remove traling space
						regsub {[ \t]+$} $_tmp_var {} _tmp_var
						#increment decimal number if possible
						catch { incr user_namespace($_tmp_var)}

						# else, pass string value back without incrementing					
					}
				^\-\\$[A-Za-z0-9_]+	{ 	# decrement Var 
						# execute expect lines if present
						_el_exec_expect
						print_comment_line

						set _tmp_var [_el_strip_char $_el(line) $_decr_var]
						#remove traling space
						regsub {[ \t]+$} $_tmp_var {} _tmp_var

						# decrement variable
						catch { incr user_namespace($_tmp_var) -1 }
						#puts "->$_el(line) $_decr_var $_tmp_var"

					}
				{^=\$[A-Za-z0-9_]+}	{ 	# math variable
						# execute expect lines if present
						_el_exec_expect
						print_comment_line

						# strip math_var symbol from beginning of line
						regsub {^=\$} $_el(line) "" _tmp_var
						# normalize spaces
						regsub -all {[ ]+} $_tmp_var " " _tmp_var
						set _el_parse_list [split $_tmp_var " "]
						set var [lindex $_el_parse_list 0]
						# remove $var from list
						set _el_parse_list [lreplace $_el_parse_list 0 0]
						set _el_predicate [join $_el_parse_list " "]
						
						# check if math variable exists
						if { [info exists user_namespace($var)] == 0 } {
							# if not, set to blank
							set user_namespace($var) 0
						}
						if { [string is integer $user_namespace($var) ] || [string is double $user_namespace($var) ]} {
							#$var is a number
							# supports oper: << >> & | ^ + = * / % pow(x,y)
							if { [catch { set user_namespace($var) [expr $user_namespace($var)$_el_predicate] } error]} {
								if {$WARN} {
									cputs "\nWarning: Expect-lite: Unable to interpret $_el(line) \n	$error" $_el_warn_color
								}
							}
						} else {
							#$var is a string 
							# get operator. % + / ; // ;; -
							regsub {([%+/;-]|[/;][/;]).*} $_el_predicate {\1} _operator
							
							#puts "===strmath==>$_operator#$_el_parse_list#"
							
							set show_error 0
							switch -re $_operator {
								"%"	{ # slice/ordinal e.g. % 5-9
										# pop operator off front
										set _el_parse_list [lreplace $_el_parse_list 0 0]
										set _el_predicate [join $_el_parse_list " "]
										set _el_parse_list [split $_el_predicate "-"]
										foreach {start end} $_el_parse_list {break}
										#puts "===strmath1==>$start#$end#$_el_parse_list"
										
										# decrement range to zero-base
										catch {incr start -1; incr end -1}
										if { [catch { set user_namespace($var) [string range $user_namespace($var) $start $end] } error]} {
											set show_error 1 
										}
									}
								{[+]}	{ # concat e.g. + string

										# pop operator off front
										if { [llength $_el_parse_list ] > 1 } {
											set _el_parse_list [lreplace $_el_parse_list 0 0]
										} else {
											set _el_parse_list [string trimleft $_el_parse_list "+"]
										}
										#puts "===strmath2==>$_el_parse_list#"
										if { [catch { set user_namespace($var)  "$user_namespace($var)$_el_parse_list" } error]} {
											set show_error 2 
										}
									}
								 {^[/;][/;]}	{ # search/replace - no regex
								 		# determine parsing char
								 		regsub {([/;]).*} $_operator {\1} splitchar 
										set replacelist [ split $_el_predicate "$splitchar" ]
										#puts "===strmath3==>$replacelist#$_el_predicate#"
										# resulting list is: null search replace null

										# remove nulls in list
										regsub  -all "{}" $replacelist "" replacelist
										
										#regsub -all $search $user_namespace($var) $replace user_namespace($var)
										if { [catch { set user_namespace($var) [string map $replacelist $user_namespace($var) ]} error]} {
											set show_error 3
										}
									}
								 {^[;/]}	{ # regex search/replace 
								 		# determine parsing char
								 		regsub {([/;]).*} $_operator {\1} splitchar 
										set replacelist [ split $_el_predicate "$splitchar" ]
										#puts "===strmath4==>$replacelist#$_el_predicate#"
										# resulting list is: null search replace null
										# remove nulls in list
										regsub  -all "{}" $replacelist "" replacelist
										foreach {search replace} $replacelist {break}
										
										#regsub -all $search $user_namespace($var) $replace user_namespace($var)
										if { [catch { regsub -all -- $search $user_namespace($var) $replace user_namespace($var)} error]} {
											set show_error 4
										}
								 	
										#regsub -all $search $user_namespace($var) $replace user_namespace($var)
									}
								{[-]}	{ # subtract or remove e.g. - string
										# remove leading white space
										regsub {([-])[ ]+(.+)} $_el_parse_list {\1\2} _el_parse_list
										#reparse parse_list
										set _el_predicate [join $_el_parse_list " "]
										set _el_parse_list [split $_el_predicate "-"]
										# pop operator off front
										set _el_parse_list [lreplace $_el_parse_list 0 0]
										# create replace_map
										set replacelist [list $_el_parse_list {} ]
										#puts "===strmath5==>$_el_predicate#$_el_parse_list#"
										if { [catch { set user_namespace($var) [string map $replacelist $user_namespace($var) ]} error]} {
											set show_error 5
										}

									}
								default {
										set show_error 9 
									}
							}; #swicth
							if { $show_error } {
								if {$DEBUG} {
									cputs "\nWarning:$show_error Expect-lite: Unable to interpret $_el(line) \n	$error" $_el_debug_color
								} elseif {$WARN} {
									cputs "\nWarning:$show_error Expect-lite: Unable to interpret $_el(line)" $_el_warn_color
								} 
								
							}
						
						}; #else
					}
				^\!	{	# Run an Embedded Expect Line(s) (limited support)

						# don't add Expect comment lines (hint they start with '!#'
						if { [regexp -line {^![ \t]*#} $_el(line) ] == 0  } {
							# add Expect Lines to _el(_el_lines) list
							lappend _el(_el_lines) [_el_strip_char $_el(line) $_exec] 
							#puts "+>[llength $_el(_el_lines)]:$_el(_el_lines):"

						}
					}
				^\\*~ 	{	# include file of failure script - called when test fails
							# Uses recursion to interpret included file
							# expect-lite directive

						# execute expect lines if present
						_el_exec_expect
						
						print_comment_line

						if { $_one_line == 0 } {
							set _el_fail_script [_el_strip_char $_el(line) $_include_fail]
						} else {
							# we are inside a recursive call
							uplevel {set _el_fail_script [_el_strip_char $_el(line) $_include_fail]}
						}
						# don't include file if name is set to __NO_STRING_CAPTURED__ (which is a blank dynamic/capture variable)
						if { $_el_fail_script == "__NO_STRING_CAPTURED__" } {
							# don't set fail_script
							set _el_fail_script ""
						}
						if { $_one_line == 0 } {
							if {$INFO} {
								cputs "\nFail Include Script: $_el_fail_script\n" $_el_info_color
							}
						} else {
							# we are inside a recursive call
							if {$INFO} {
								uplevel {cputs "\nFail Include Script: $_el_fail_script\n" $_el_info_color}
							}
						}

					}
				^\\*/.*/$	{	# Set a user defined prompt
							# expect-lite directive

						# execute expect lines if present
						_el_exec_expect

						# strip leading and trailing slashes
						regsub {^\*/} $_el(line) {} el_u_prompt
						regsub {/$} $el_u_prompt {} _el(prompt)
						#  Set empty prompt to something sane, the default prompt
						if { $_el(prompt) == "" } {
							set _el(prompt) $_el(default_prompt)
						}

						if $INFO {
							if { $_el(prompt) == $_el(default_prompt) } {
								cputs "INFO: User Defined Prompt is now default: $_el(prompt)" $_el_info_color
							} else {
								cputs "INFO: User Defined Prompt: $_el(prompt)" $_el_info_color
							}
						}

					}
				^\\*[a-zA-Z]	{	# Process expect-lite run-time directives
								# expect-lite directives

						print_comment_line

						# execute expect lines if present
						_el_exec_expect
						print_comment_line
						# trim off white space
						set _el(line) [string trimright $_el(line)]
						# remove any multiple spaces
						regsub -all {[ ]+} $_el(line) " " _el(line)
						# Process the directive - return 0 to fail
						set _el(success) [_el_global_directive $_el(line)]

					}						
				^\\\[	{	# start block of lines

						# execute expect lines if present
						_el_exec_expect

						print_comment_line

						set _cond_line [string trimleft $_el(line) '\[']
						#puts "====>start block lines|$_cond_line|$_el(line_meta)"
						
						set _conditional [string trimright $_cond_line]

						if { [regexp {^\[[ ]*\$[a-zA-Z0-9_]+[ ]?[=]} $_el(line)] } {
							### foreach loop
							
							set _cond_oper "="

							# parse around conditional operator
							set _cond_arg1 [string range $_conditional 0 [expr [string first $_cond_oper $_conditional] - 1]]
							set _cond_arg2 [string range $_conditional [expr [string first $_cond_oper $_conditional] + [string length $_cond_oper] ] [string length $_conditional]]
							# clean up white space
							regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg1 {\2} _cond_arg1
							#regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg2 {\2} _cond_arg2

							set user_var $_cond_arg1
							# remove '$' in front of the Var
							regsub {\$} $user_var "" user_var

							# create foreach list
							set line_meta $_el(line_meta)
							if { [info exists _foreach($line_meta,$user_var)] == 0 } {
								# clean up white space
								regsub -all {[ ]+} $_cond_arg2 " " _cond_arg2
								set _cond_arg2 [string trimleft $_cond_arg2 ]
								set _cond_arg2 [string trimright $_cond_arg2 ]
								
								set _foreach_list [split $_cond_arg2]
								if {$INFO} {
									cputs "\nForeach: $_cond_arg1=$_cond_arg2" $_el_info_color
								};#if INFO
								# add extra item to allow last user item to be executed
								lappend _foreach_list "END"
							} else {
								# restore list - hashed based on meta line and var name
								set _foreach_list $_foreach($line_meta,$user_var)
							}
							# set value from first item in foreach list
							set user_value [lindex $_foreach_list 0]

							#puts "====>repeat lines|$_foreach_list|[llength $_foreach_list]|$user_var|$user_value"

							# delete first item in list
							set _foreach_list [ lreplace $_foreach_list 0 0]
							# is list empty, then stop loop
							if { [llength $_foreach_list] == 0 } {
								set _foreach_list ""
								# clear foreach info, to allow re-run of this foreach loop
								unset -nocomplain _foreach($line_meta,$user_var)
								if { $_el(line_meta) != -1 } {
									# stop loop, jump to bottom of loop + 1
									_el_buffer_goto [expr $_el(line_meta) + 0] $_el_buf(stack)
								}
							} else {
								#List not empty, Loop back
								# save list info
								set _foreach($line_meta,$user_var) $_foreach_list
								# Assign the Var
								set user_namespace($user_var) $user_value
								if {$INFO} {
									cputs "\nForeach: \$$user_var=$user_value\n" $_el_info_color
								};#if INFO
							}

						} else {
							### While Loop

							# define list of supported conditional operators
							set _cond_oper_list { == != <= >= < > }

							# find conditional operator
							set _cond_oper "@"
							foreach k $_cond_oper_list {
								if { [regexp $k $_conditional] } {
									set _cond_oper $k
									break
								}
							}

							 # parse around conditional operator
							set _cond_arg1 [string range $_conditional 0 [expr [string first $_cond_oper $_conditional] - 1]]
							set _cond_arg2 [string range $_conditional [expr [string first $_cond_oper $_conditional] + [string length $_cond_oper] ] [string length $_conditional]]
							# clean up white space
							regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg1 {\2} _cond_arg1
							regsub -all {([ ]*)([^ ]*)([ ]*)} $_cond_arg2 {\2} _cond_arg2

							#puts "\n#@@|$_cond_oper|$_conditional|$_cond_arg1|$_cond_arg2|"

							# Var is defined as in the set [a-zA-Z0-9_]
							if { [regexp {\$[a-zA-Z0-9_]+} $_conditional] } {
								if {$DEBUG} { cputs "EL:Unresolved Var:$_conditional" $_el_debug_color}
								# replace all unresolved vars with ""
								regsub -all {\$[a-zA-Z0-9_]+} $_cond_arg1 {} _cond_arg1
								regsub -all {\$[a-zA-Z0-9_]+} $_cond_arg2 {} _cond_arg2							
							} 

							# allow _cond_arg2 to be blank, test against blank
							if {( $_cond_oper == "==" || $_cond_oper == "!=" ) && ($_cond_arg2 == "" ) } {
								# build special test line against blank arg2
								set _test " expr { \"$_cond_arg1\" $_cond_oper \"\" } "
							} else {
								# build test line
								if { $_cond_arg1 == "" || $_cond_arg2 == "" } {
									# something is wrong, one of the conditions is blank break the eval
									set _test " expr { $_cond_arg1 $_cond_oper $_cond_arg2 } "
								} else {
									set _test " expr { \"$_cond_arg1\" $_cond_oper \"$_cond_arg2\" } "
								}
							}

							# check for syntax errors and evaluate result of test line
							if {[catch { eval  $_test  } error ] } {
								if {$WARN} {
									cputs "\nWarning: Expect-lite: $error: Unable to detect conditional operator\n" $_el_warn_color
									cputs "	Evaluating line:$_test" $_el_warn_color
								}
								#skip block lines, don't jump if bad line-meta value
								if { $_el(line_meta) != -1 } {
									#set _el_buf($buf_stack,ptr) [expr $_el(line_meta) + 1]
									_el_buffer_goto [expr $_el(line_meta) + 1] $_el_buf(stack)
								}

							} else {
								# Show user the if statement, action and result
								set _test_result [eval  $_test ]
								if {$_test_result} {
									set _test_result "TRUE"
								} else {
									set _test_result "FALSE"
								}
								if {$INFO} {
									cputs "\nWhile:$_test|result=$_test_result\n" $_el_info_color
								};#if INFO

								# no syntax error, go ahead and eval the conditional action or else action
								# skip to label if present in action or else_action
								if { [eval  $_test ] } {
									# continue loop

									# test for infinite loop
									set retcode [_el_check_infinite_loop]
									if { $retcode == -2 } {
										# infinite loop failed (-2)
										# signal to fail script - something is wrong
										set _el(success) 0
										# tell the user why this failed
										set prev_line "Infinite Loop Detected!"
										set _test_result -2
									}							

								} elseif { $_el(line_meta) != -1 } {
									# stop loop, jump to bottom of loop + 1
									_el_buffer_goto [expr $_el(line_meta)] $_el_buf(stack)
								}

							};#if Catch
						}; #else While loop
					}
				^\\\]	{	# end block of lines

						# execute expect lines if present
						_el_exec_expect

						print_comment_line

						#puts "====>end block lines|$_el(line_meta)"
						if { $_one_line == 0 } {
							# jump back to top of block lines
							_el_buffer_goto [expr $_el(line_meta) - 1 ] $_el_buf(stack)
						}
						
					}
				default {	# blank lines are allowed

			 		}
			}

			#puts "line_ptr->$_el_buf($buf_stack,ptr)|$_el(success)"
			
			# Fail the test if Expect fails
			if {$_el(success) != 1 && [regexp "^$_in" $_el(line)]==1  } {
				cputs "\n\n FAILED COMMAND:[_el_strip_char $prev_line $_out] \n" $_el_err_color
				cputs "    Expect Failed:$teststr\n" $_el_err_color
				if { $_el_current_session != "default" } {
					cputs "    Current Fork Session: $_el_current_session \n\n" $_el_err_color
				}
			}
			# Fail the test if NOT Expect fails
			if {$_el(success) != 1 && [regexp "^$_not_in" $_el(line)]==1  } {
				cputs "\n\n FAILED COMMAND:[_el_strip_char $prev_line $_out] \n" $_el_err_color
				cputs "    Expect Found:$teststr\n\n" $_el_err_color
				if { $_el_current_session != "default" } {
					cputs "    Current Fork Session: $_el_current_session \n\n" $_el_err_color
				}
			}
			# Fail the test, and invoke Fail_script
			if {$_el(success) != 1 } {
				if { $_el_fail_script != "" } {
					# run fail script to clean up
					# absolute path to fail include file?
					set _slash "/"
					if { [string index $_el_fail_script 0] == $_slash} {
						set include_path_file "$_el_fail_script"
					} else {
						set include_path_file "[parse_cmd_file_path $_el(cmd_file)]$_el_fail_script"
					}
					#puts "->$include_path_file"
					if {$INFO} {
						cputs "\nIncluding Fail Script: $_el_fail_script\n" $_el_info_color
					}
					# set fail_script up for success
					set _el(success) 1

					# Make Recursive Call
					# read in cmd_file (fail script) to buffer
					set buf_stack [_el_buffer $include_path_file]
					_el_script_exec "" $buf_stack
					# pop _el_buf(stack)
					_el_buffer_stack_clear $buf_stack
					incr buf_stack -1
					# sync with global value, for INTERACT/IDE
					set _el_buf(stack) $buf_stack
					
					# special short cut to allow main script to continue
					if { [info exists _el(continue)] == 1 } {
						if { $_el(continue) == 1 } { set _el(success) 1 }
						set _el(continue) 0
					} else {
						# no backdoor to continue script, fail script
						set _el(success) 0
					}
					#puts "success->$_el(success)"
					#puts "FS>$_el_fail_script"
				}
				# last chance to let script continue, even though it should fail
				if {$NOFAIL} {
					set _el(success) 1
					set _el(test_failed) 1
				} 			
				if { $_el(success) != 1 } {
					# allow fail script to set success, and continue if need be
					#protected_send "quit$_el_eols"
					#exit 1
					# FATAL
					return 2
				}
			}

			# ensure we stop at end of file/buffer
			if { $_one_line == 0 } {
				if { $_el_buf($buf_stack,ptr) >= [llength $_el_buf($buf_stack)] } {
					# exit the while loop
					set _el(line) -1
				}
				if {$_el_buf($buf_stack,ptr) < 0 } {
					# last chance to return unknown
					return -1
				}
			}
			# Get next line in buffer
			# Or return if in one_line mode
			if { $_one_line == 0 } {
				# not in one line, normal processing
				# read next line from buffer
				incr _el_buf($buf_stack,ptr)
				set _el(line) [_el_buffer_read $_el_buf($buf_stack,ptr) $buf_stack]
				# read meta-data for line
				set _el(line_meta) [_el_buffer_read $_el_buf($buf_stack,ptr) $buf_stack 1]
				# remove leading white space on line (permitting indentation)
				regsub {^[ \t]+} $_el(line) {} _el(line)
			} else {
				# one_line is true (which means invoked by a conditional)
				# 	or invoked from IDE
				# Done processing one line, and handling failures
				# so just return from this recursive call
				switch -regex -- $_test_result {
					"TRUE"	{ return 1 }
					"FALSE"	{ return 0 }
					[-0-9]+	{ return $_test_result }
					default	{ return "test_result_error" }
				}
			}; #endif not one_line

		}
		# set result code
		if { $_el(test_failed) == 1} {
			# FAIL
			return 1
		} else {
			# PASS
			return 0
		}

	} 
	# end of _el_script_exec


	# ############# MAIN ######################
	#
	#	Main Program starts here
	#	
	#
	proc main { } {
		upvar expectlite::connect_method		connect_method
		upvar expectlite::remote_host			remote_host
		upvar expectlite::_el_info_color		_el_info_color
		upvar expectlite::_el_warn_color		_el_warn_color
		upvar expectlite::_el_err_color 		_el_err_color
		upvar expectlite::delay_wait_for_host	delay_wait_for_host
		upvar expectlite::WARN					WARN
		upvar expectlite::INFO					INFO
		upvar expectlite::_el_eols				_el_eols
		upvar expectlite::_el					_el
		upvar expectlite::DEBUG_LOG 			DEBUG_LOG
		upvar expectlite::cmd_file				cmd_file


		_el_init_globals

		# check terminal type for use of colors
		check_term_type 
		
		_el_read_args $::argc $::argv

		# Check Expect Version, warn if old
		# if { [exp_version] < "5.42.0" } {
		# 	puts "Warning: older version of expect\n"
		# }
		if [catch { exp_version 5.42.0 } msg ] {
			cputs "\nWarning: $msg\n" $_el_err_color
		}
		
		# read in cmd file and return handle to buffer
		set cmd_file_ptr [ read_cmd_file ]

		# Use selected (at top of file) connect_method
		switch $connect_method {
			telnet	{connect_telnet_host $remote_host }
			ssh		{connect_ssh_host 	$remote_host }
			ssh_key	{connect_ssh_key_host $remote_host }
			none		{_el_connect_localhost $remote_host }
		}

		# initialize remote_host_init, fork session
		session_init $cmd_file_ptr
		
		#if { $DEBUG_LOG==1 } { log_file -noappend debug_output.txt } - removed in v4.4.0


		# Send commands to remote host, and validate response
		set _el_result [ _el_script_exec "" $cmd_file_ptr ]


		after [expr 5 * $delay_wait_for_host]
		#To show the very end of the test, wait for that very last prompt
		# clear expect buffer
		expect -re {.*} {}

		# exit local or remote shell
		if { [catch {  send "exit $_el_eols" } error] } {
			if {$WARN} {cputs  "Warning: Lost connection to $remote_host \n  $error\n  $errorInfo " $_el_warn_color}
		}

		wait_for_prompt

		# Print result of test
		switch -- $_el_result {
			0 { # PASS
				if {$INFO} {cputs "\n\n##Overall Result: PASS \n\n" $_el_info_color }
			}
			1 { # FAIL
				if {$INFO} {cputs "\n\n##Overall Result: FAILED (*NOFAIL on)\n\n" $_el_err_color }
				exit 1
			}
			2 { # FATAL
				if {$INFO} {cputs "\n\n##Overall Result: FAILED \n\n" $_el_err_color }
				exit 1
			}
			-1 { # UNKNOWN
				if {$INFO} {cputs "\n\n##Overall Result: UNKNOWN \n\n" $_el_err_color }
				exit 1
			}
		}


		#if { $DEBUG_LOG==1 } { log_file }

		# exit with 0 to indicate that test passed
		exit 0
	}
}; #end namespace expect-lite

# run the main program (in standalone) when run with expect
#if { [info exist ::EL_LIBRARY]  != 1} { main }
if { [string match "*expect*" [info nameofexecutable]] } { expectlite::main }
