text: """Contains all the core ShutIt methods and functionality, and public interface
  off to internal objects such as shutit_pexpect.
  """
  
  # The MIT License (MIT)
  #
  # Copyright (C) 2014 OpenBet Limited
  #
  # Permission is hereby granted, free of charge, to any person obtaining a copy of
  # this software and associated documentation files (the "Software"), to deal in
  # the Software without restriction, including without limitation the rights to
  # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  # of the Software, and to permit persons to whom the Software is furnished to do
  # so, subject to the following conditions:
  #
  # The above copyright notice and this permission notice shall be included in all
  # copies or substantial portions of the Software.
  #
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  # ITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  # SOFTWARE.
  
  import sys
  import os
  import socket
  import time
  import getpass
  import datetime
  import logging
  import fcntl
  import pwd
  import re
  import termios
  import signal
  import struct
  import threading
  from distutils.dir_util import mkpath
  import curtsies
  #from curtsies.fmtfuncs import black, yellow, magenta, cyan, gray, blue, red, green, on_black, on_dark, on_red, on_green, on_yellow, on_blue, on_magenta, on_cyan, on_gray, bold, dark, underline, blink, invert, plain
  from curtsies.fmtfuncs import blue, cyan, invert
  from shutit_session_setup import vagrant
  import shutit_threads
  
  if sys.version_info[0] >= 3:
  	unicode = str
  
  class ShutItGlobal(object):
  	"""Single object to store all the separate ShutIt sessions, and information
  	that is global to all sessions.
  	"""
  
  	only_one = None
  	def __init__(self):
  		"""Constructor.
  		"""
  		self.shutit_objects = []
  		# Primitive singleton enforcer.
  		assert self.only_one is None, shutit_util.print_debug()
  		self.only_one                = True
  
  		# Capture the original working directory.
  		self.owd                     = os.getcwd()
  
  		# Python version.
  		self.ispy3                   = (sys.version_info[0] >= 3)
  
  		# Threading.
  		self.global_thread_lock      = threading.Lock()
  		# Acquire the lock by default.
  		self.global_thread_lock.acquire()
  
  		# Secret words.
  		self.secret_words_set        = set()
  
  		# Logging.
  		# global logstream is written to by logger in each shutit_class.py object.
  		self.logstream               = None
  		self.logstream_size          = 1000000
  		self.log_trace_when_idle     = False
  		self.signal_id               = None
  		self.window_size_max         = 65535
  		self.username                = os.environ.get('LOGNAME', '')
  		self.default_timeout         = 3600
  		self.delaybeforesend         = 0
  		self.default_encoding        = 'utf-8'
  
  		# Panes.
  		self.managed_panes           = False
  		self.pane_manager            = None
  		self.lower_pane_rotate_count = 0
  
  		# Errors.
  		self.stacktrace_lines_arr    = []
  
  		# Prompts and shell.
  		self.bash_startup_command    = "bash --noprofile --rcfile <(sleep .05||sleep 1)"
  		# Quotes here are intentional. Some versions of sleep don't support fractional seconds.
  		# True is called to take up the time require
  		self.prompt_command          = "'sleep .05||sleep 1'"
  		# It's important that this has '.*' at the start, so the matched data is reliably 'after' in the
  		# child object. Use these where possible to make things more consistent.
  		# Attempt to capture any starting prompt (when starting) with this regexp.
  		# The '>' is for AIX and explains why we use '2>/dev/null' in some other parts
  		# of the code (ie to avoid matching initialiser commands).
  		self.base_prompt      = '\n.*[@#$] '
  		# There is a problem with lines roughly around this length + the length of the prompt (?3k?)
  		self.line_limit          = 3000
  		# Terminal size
  		def terminal_size():
  			h, w, _, _ = struct.unpack('HHHH', fcntl.ioctl(0, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)))
  			return int(h), int(w)
  		try:
  			self.root_window_size = terminal_size()
  		except IOError:
  			# If no terminal exists, set to default.
  			self.root_window_size = (24,80)
  		# Just override to the max possible
  		self.pexpect_window_size = (self.window_size_max,self.window_size_max)
  		self.interactive         = 1 # Default to true until we know otherwise
  
  		# Session environments.
  		# Environments are kept globally, as different sessions may re-connect to them.
  		self.shutit_pexpect_session_environments = set()
  
  		# Real username.
  		if self.username == '':
  			try:
  				if os.getlogin() != '':
  					self.username = os.getlogin()
  			except Exception:
  				self.username = getpass.getuser()
  			if self.username == '':
  				self.handle_exit(msg='LOGNAME not set in the environment, ' + 'and login unavailable in python; ' + 'please set to your username.', exit_code=1)
  		self.real_user        = os.environ.get('SUDO_USER', self.username)
  		self.real_user_id     = pwd.getpwnam(self.real_user).pw_uid
  
  		# ShutIt build ID.
  		self.build_id         = (socket.gethostname() + '_' + self.real_user + '_' + str(time.time()) + '.' + str(datetime.datetime.now().microsecond))
  		# ShutIt state directory.
  		shutit_state_dir_base  = '/tmp/shutit_' + self.username
  		if not os.access(shutit_state_dir_base,os.F_OK):
  			mkpath(shutit_state_dir_base,mode=0o777)
  		self.shutit_state_dir       = shutit_state_dir_base + '/' + self.build_id
  		os.chmod(shutit_state_dir_base,0o777)
  		if not os.access(self.shutit_state_dir,os.F_OK):
  			mkpath(self.shutit_state_dir,mode=0o777)
  		os.chmod(self.shutit_state_dir,0o777)
  		self.shutit_state_dir_build_db_dir = self.shutit_state_dir + '/build_db'
  
  		# Allowed delivery methods.
  		self.allowed_delivery_methods = ['ssh','dockerfile','bash','docker','vagrant']
  
  	def __str__(self):
  		str_repr = '\n====== SHUTIT_GLOBAL_OBJECT BEGIN ====='
  		str_repr += '\tself.signal_id='          + str(self.signal_id)
  		str_repr += '\tself.window_size_max='    + str(self.window_size_max)
  		str_repr += '\tself.username='           + str(self.username)
  		str_repr += '\tbase_prompt='             + str(self.base_prompt)
  		str_repr += '\treal_user='               + str(self.real_user)
  		str_repr += '\treal_user_id='            + str(self.real_user_id)
  		str_repr += '\tbuild_id='                + str(self.build_id)
  		str_repr += '\tdelaybeforesend='         + str(self.delaybeforesend)
  		str_repr += '\tprompt_command='          + str(self.prompt_command)
  		str_repr += '\tself.default_encoding='   + str(self.default_encoding)
  		for shutit_object in self.shutit_objects:
  			str_repr += str(shutit_object)
  		str_repr += '\n====== SHUTIT_GLOBAL_OBJECT DONE ====='
  		return str_repr
  
  
  
  	def create_session(self,
  	                   session_type='bash',
  	                   docker_image=None,
  	                   rm=None,
  	                   echo=False,
  	                   walkthrough=False,
  	                   walkthrough_wait=-1,
  	                   nocolor=False,
  	                   loglevel='WARNING'):
  		assert isinstance(session_type, str), shutit_util.print_debug()
  		new_shutit = ShutIt(standalone=True, session_type=session_type)
  		self.shutit_objects.append(new_shutit)
  		if session_type == 'bash':
  			new_shutit.process_args(ShutItInit('build',
  			                                   delivery='bash',
  			                                   echo=echo,
  			                                   walkthrough=walkthrough,
  			                                   walkthrough_wait=walkthrough_wait,
  			                                   loglevel=loglevel))
  			new_shutit.load_configs()
  			new_shutit.setup_host_child_environment()
  			return new_shutit
  		elif session_type == 'docker':
  			new_shutit.process_args(ShutItInit('build',
  			                                   delivery='docker',
  			                                   base_image=docker_image,
  			                                   echo=echo,
  			                                   walkthrough=walkthrough,
  			                                   walkthrough_wait=walkthrough_wait,
  			                                   loglevel=loglevel))
  			new_shutit.target['rm'] = rm
  			target_child = new_shutit.conn_docker_start_container('target_child')
  			new_shutit.setup_host_child_environment()
  			new_shutit.setup_target_child_environment(target_child)
  			return new_shutit
  		new_shutit.fail('unhandled session type: ' + session_type)
  		return new_shutit
  
  
  	def create_session_vagrant(self,
  	                           session_name,
  	                           num_machines,
  	                           vagrant_image,
  	                           vagrant_provider,
  	                           gui,
  	                           memory,
  	                           swapsize,
  	                           echo,
  	                           walkthrough,
  	                           walkthrough_wait,
  	                           nocolor,
  	                           vagrant_version,
  	                           virt_method,
  	                           root_folder,
  	                           cpu,
  	                           loglevel):
  		new_shutit = ShutIt(standalone=True, session_type='vagrant')
  		self.shutit_objects.append(new_shutit)
  		# Vagrant is: delivery over bash, but running the vagrant scripts first.
  		new_shutit.process_args(ShutItInit('build',
  		                                   delivery='bash',
  		                                   echo=echo,
  		                                   walkthrough=walkthrough,
  		                                   walkthrough_wait=walkthrough_wait,
  		                                   nocolor=nocolor,
  		                                   loglevel=loglevel))
  		new_shutit.load_configs()
  		new_shutit.setup_host_child_environment()
  		# Run vagrant setup now
  		vagrant.pre_build(shutit=new_shutit,
  		                  vagrant_version=vagrant_version,
  		                  virt_method=virt_method)
  		machines = vagrant.setup_machines(new_shutit,
  		                                  vagrant_image,
  		                                  virt_method,
  		                                  gui,
  		                                  memory,
  		                                  root_folder,
  		                                  session_name,
  		                                  swapsize,
  		                                  num_machines,
  		                                  cpu)
  		new_shutit.vagrant_machines = machines
  		return new_shutit
  
  
  	def determine_interactive(self):
  		"""Determine whether we're in an interactive shell.
  		Sets interactivity off if appropriate.
  		cf http://stackoverflow.com/questions/24861351/how-to-detect-if-python-script-is-being-run-as-a-background-process
  		"""
  		try:
  			if not sys.stdout.isatty() or os.getpgrp() != os.tcgetpgrp(sys.stdout.fileno()):
  				self.interactive = 0
  				return False
  		except Exception:
  			self.interactive = 0
  			return False
  		if self.interactive == 0:
  			return False
  		return True
  
  
  	def setup_panes(self, action=None):
  		assert not self.managed_panes or (self.managed_panes and self.logstream)
  		assert action is not None
  		# TODO: managed_panes and echo are incompatible
  		if self.managed_panes:
  			self.pane_manager     = PaneManager(self)
  			shutit_threads.track_main_thread()
  		else:
  			if action == 'build':
  				shutit_threads.track_main_thread_simple()
  
  
  	def yield_to_draw(self):
  		# Release the lock to allow the screen to be drawn, then acquire again.
  		# Only ever yield if there are any sessions to draw.
  		if len(get_shutit_pexpect_sessions()) > 0:
  			self.global_thread_lock.release()
  			# Allow a _little_ time for others to get a look in
  			time.sleep(0.001)
  			self.global_thread_lock.acquire()
  
  
  	def handle_exit(self,
  	                exit_code=0,
  	                msg=None):
  		if not msg:
  			msg = '\r\nExiting with error code: ' + str(exit_code)
  			msg += '\r\nInvoking command was: ' + sys.executable
  			for arg in sys.argv:
  				msg += ' ' + arg
  		if exit_code != 0:
  			self.shutit_print('\r\nExiting with error code: ' + str(exit_code))
  			self.shutit_print(msg)
  			self.shutit_print('\r\nResetting terminal')
  			shutit_util.sanitize_terminal()
  			shutit_util.exit_cleanup()
  		sys.exit(exit_code)
  
  
  	def shutit_print(self, msg):
  		"""Handles simple printing of a msg at the global level.
  		"""
  		if self.pane_manager is None:
  			print(msg)
  
  
  # shutit_global.shutit_objects have the pexpect sessions in their shutit_pexpect_sessions variable.
  class PaneManager(object):
  	only_one = None
  	def __init__(self, shutit_global_object):
  		"""
  
  		only_one             - singleton insurance
  		"""
  		assert self.only_one is None
  		self.only_one is True
  		# Keep it simple for now by creating four panes
  		self.shutit_global             = shutit_global_object
  		self.top_left_session_pane     = SessionPane('top_left')
  		self.top_right_session_pane    = SessionPane('top_right')
  		self.bottom_left_session_pane  = SessionPane('bottom_left')
  		self.bottom_right_session_pane = SessionPane('bottom_right')
  		self.window                    = None
  		self.screen_arr                = None
  		self.wheight                   = None
  		self.wwidth                    = None
  		# Whether to actually draw the screen - defaults to 'True'
  		self.do_render                 = True
  		# Refresh the window
  		self.refresh_window()
  
  
  	def refresh_window(self):
  		self.window               = curtsies.FullscreenWindow(hide_cursor=True)
  		self.wheight              = self.window.height
  		self.wwidth               = self.window.width
  		self.screen_arr           = None
  		# Divide the screen up into two, to keep it simple for now
  		self.wheight_top_end      = int(self.wheight / 2)
  		self.wheight_bottom_start = int(self.wheight / 2)
  		self.wwidth_left_end      = int(self.wwidth / 2)
  		self.wwidth_right_start   = int(self.wwidth / 2)
  		assert self.wheight >= 24, 'Terminal not tall enough: ' + str(self.wheight) + ' < 24'
  		assert self.wwidth >= 80, 'Terminal not wide enough: ' + str(self.wwidth) + ' < 80'
  
  
  	def draw_screen(self, draw_type='default', quick_help=None):
  		if quick_help is None:
  			quick_help = 'Help: (r)otate shutit sessions | re(d)raw screen | (1,2,3,4) zoom pane in/out | (q)uit'
  		assert draw_type in ('default','clearscreen','zoomed1','zoomed2','zoomed3','zoomed4')
  		# Header
  		header_text = u'  <= Shutit'
  		self.screen_arr           = curtsies.FSArray(self.wheight, self.wwidth)
  		self.screen_arr[0:1,0:len(header_text)] = [blue(header_text)]
  		# Footer
  		space = (self.wwidth - len(quick_help))*' '
  		footer_text = space + quick_help
  		if not self.shutit_global.ispy3:
  			footer_text = footer_text.decode('utf-8')
  		self.screen_arr[self.wheight-1:self.wheight,0:len(footer_text)] = [invert(blue(footer_text))]
  		if draw_type in ('default','zoomed3','zoomed4'):
  			# get sessions - for each ShutIt object in shutit_global
  			sessions = list(get_shutit_pexpect_sessions())
  			# reverse sessions as we're more likely to be interested in later ones.
  			sessions.reverse()
  			# Update the lower_pane_rotate_count so that it doesn't exceed the length of sessions.
  			self.shutit_global.lower_pane_rotate_count = self.shutit_global.lower_pane_rotate_count % len(sessions)
  			sessions = sessions[-self.shutit_global.lower_pane_rotate_count:] + sessions[:-self.shutit_global.lower_pane_rotate_count]
  		# Truncate logstream if it gets too big.
  		if self.shutit_global.logstream.getvalue() > self.shutit_global.logstream_size:
  			self.shutit_global.logstream.truncate(self.shutit_global.logstream_size)
  		if draw_type == 'default':
  			# Draw the sessions.
  			self.do_layout_default()
  			logstream_lines = []
  			logstream_string_lines_list = self.shutit_global.logstream.getvalue().split('\n')
  			for line in logstream_string_lines_list:
  				logstream_lines.append(SessionPaneLine(line,time.time(),'log'))
  			self.write_out_lines_to_fit_pane(self.top_left_session_pane, logstream_lines, u'Logs')
  			self.write_out_lines_to_fit_pane(self.top_right_session_pane, self.shutit_global.stacktrace_lines_arr, u'Code Context')
  			# Count two sessions
  			count = 0
  			for shutit_pexpect_session in sessions:
  				count += 1
  				if count == 2:
  					self.write_out_lines_to_fit_pane(self.bottom_left_session_pane,
  					                                 shutit_pexpect_session.session_output_lines,
  					                                 u'Shutit Session: ' + str(shutit_pexpect_session.pexpect_session_number) + '/' + str(len(sessions)))
  				elif count == 1:
  					self.write_out_lines_to_fit_pane(self.bottom_right_session_pane,
  					                                 shutit_pexpect_session.session_output_lines,
  					                                 u'ShutIt Session: ' + str(shutit_pexpect_session.pexpect_session_number) + '/' + str(len(sessions)))
  				else:
  					break
  		elif draw_type == 'zoomed1':
  			self.do_layout_zoomed(zoom_number=1)
  			logstream_lines = []
  			logstream_string_lines_list = self.shutit_global.logstream.getvalue().split('\n')
  			for line in logstream_string_lines_list:
  				logstream_lines.append(SessionPaneLine(line,time.time(),'log'))
  			self.write_out_lines_to_fit_pane(self.top_left_session_pane, logstream_lines, u'Logs')
  		elif draw_type == 'zoomed2':
  			self.do_layout_zoomed(zoom_number=2)
  			self.write_out_lines_to_fit_pane(self.top_left_session_pane, self.shutit_global.stacktrace_lines_arr, u'Code Context')
  		elif draw_type == 'zoomed3':
  			self.do_layout_zoomed(zoom_number=3)
  			# Get first session
  			count = 0
  			for shutit_pexpect_session in sessions:
  				count += 1
  				if count == 2:
  					self.write_out_lines_to_fit_pane(self.top_left_session_pane,
  					                                 shutit_pexpect_session.session_output_lines,
  					                                 u'Shutit Session: ' + str(shutit_pexpect_session.pexpect_session_number) + '/' + str(len(sessions)))
  				elif count > 2:
  					break
  		elif draw_type == 'zoomed4':
  			self.do_layout_zoomed(zoom_number=4)
  			# Get second session
  			for shutit_pexpect_session in sessions:
  				self.write_out_lines_to_fit_pane(self.top_left_session_pane,
  					                                 shutit_pexpect_session.session_output_lines,
  					                                 u'ShutIt Session: ' + str(shutit_pexpect_session.pexpect_session_number) + '/' + str(len(sessions)))
  				break
  		elif draw_type == 'clearscreen':
  			for y in range(0,self.wheight):
  				line = u' '*self.wwidth
  				self.screen_arr[y:y+1,0:len(line)] = [line]
  		else:
  			assert False, 'Layout not handled: ' + draw_type
  		if self.do_render:
  			self.window.render_to_terminal(self.screen_arr, cursor_pos=(0,0))
  
  
  	def write_out_lines_to_fit_pane(self, pane, p_lines, title):
  		assert pane is not None
  		assert isinstance(pane, SessionPane)
  		assert isinstance(title, unicode)
  		pane_width  = pane.get_width()
  		pane_height = pane.get_height()
  		assert pane_width > 39
  		assert pane_height > 19
  		# We reserve one row at the end as a pane status line
  		available_pane_height   = pane.get_height() - 1
  		lines_in_pane_str_arr   = []
  		p_lines_str = []
  		for session_pane_line in p_lines:
  			assert isinstance(session_pane_line, SessionPaneLine)
  			p_lines_str.append(session_pane_line.line_str)
  		p_lines = p_lines_str
  		p_lines_str = None
  		# Scrub any ansi escape sequences.
  		ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]')
  		if not self.shutit_global.ispy3:
  			lines = [ ansi_escape.sub('', line).strip().decode('utf-8') for line in p_lines ]
  		else:
  			lines = [ ansi_escape.sub('', line).strip() for line in p_lines ]
  		# If the last line is blank we can just skip it.
  		if len(lines) > 0 and lines[-1] == '':
  			lines = lines[:-1]
  		for line in lines:
  			# Take the next line in the stream. If it's greater than the pane_width,
  			# Then parcel over multiple lines
  			while len(line) > pane_width-1 and len(line) > 0:
  				lines_in_pane_str_arr.append(line[:pane_width-1])
  				line = line[pane_width-1:]
  			lines_in_pane_str_arr.append(line)
  		# Status line:
  		lines_in_pane_str_arr.append(title)
  		top_y                                      = pane.top_left_y
  		bottom_y                                   = pane.bottom_right_y
  		for i, line in zip(reversed(range(top_y,bottom_y)), reversed(lines_in_pane_str_arr)):
  			# Status on bottom line
  			# If    this is on the top, and height + top_y value == i (ie this is the last line of the pane)
  			#    OR this is on the bottom (ie top_y is not 1), and height + top_y == i
  			# One or both of these help prevent glitches on the screen. Don't know why. Maybe replace with more standard list TODO
  			if (top_y == 1 and available_pane_height + top_y == i) or (top_y != 1 and available_pane_height + top_y == i):
  				self.screen_arr[i:i+1, pane.top_left_x:pane.top_left_x+len(line)] = [cyan(invert(line))]
  			else:
  				self.screen_arr[i:i+1, pane.top_left_x:pane.top_left_x+len(line)] = [line]
  
  
  
  	def do_layout_zoomed(self, zoom_number):
  		# Only one window - the top left.
  		self.top_left_session_pane.set_position    (top_left_x=0,
  		                                            top_left_y=1,
  		                                            bottom_right_x=self.wwidth,
  		                                            bottom_right_y=self.wheight-1)
  
  
  	def do_layout_default(self):
  		self.top_left_session_pane.set_position    (top_left_x=0,
  		                                            top_left_y=1,
  		                                            bottom_right_x=self.wwidth_left_end,
  		                                            bottom_right_y=self.wheight_bottom_start)
  		self.top_right_session_pane.set_position   (top_left_x=self.wwidth_right_start,
  		                                            top_left_y=1,
  		                                            bottom_right_x=self.wwidth,
  		                                            bottom_right_y=self.wheight_bottom_start)
  		self.bottom_right_session_pane.set_position(top_left_x=self.wwidth_right_start,
  		                                            top_left_y=self.wheight_bottom_start,
  		                                            bottom_right_x=self.wwidth,
  		                                            bottom_right_y=self.wheight-1)
  		self.bottom_left_session_pane.set_position (top_left_x=0,
  		                                            top_left_y=self.wheight_bottom_start,
  		                                            bottom_right_x=self.wwidth_left_end,
  		                                            bottom_right_y=self.wheight-1)
  
  
  # Represents a window pane with no concept of context or content.
  class SessionPane(object):
  
  	def __init__(self, name):
  		self.name                 = name
  		self.top_left_x           = -1
  		self.top_left_y           = -1
  		self.bottom_right_x       = -1
  		self.bottom_right_y       = -1
  		self.line_buffer_size     = 1000
  		assert self.name in ('top_left','bottom_left','top_right','bottom_right')
  
  	def __str__(self):
  		string =  '\n============= SESSION PANE OBJECT BEGIN ==================='
  		string += '\nname: '           + str(self.name)
  		string += '\ntop_left_x: '     + str(self.top_left_x)
  		string += '\ntop_left_y: '     + str(self.top_left_y)
  		string += '\nbottom_right_x: ' + str(self.bottom_right_x)
  		string += '\nbottom_right_y: ' + str(self.bottom_right_y)
  		string += '\nwidth: '          + str(self.get_width())
  		string += '\nheight: '         + str(self.get_width())
  		string += '\n============= SESSION PANE OBJECT END   ==================='
  		return string
  
  	def set_position(self, top_left_x, top_left_y, bottom_right_x, bottom_right_y):
  		self.top_left_x     = top_left_x
  		self.top_left_y     = top_left_y
  		self.bottom_right_x = bottom_right_x
  		self.bottom_right_y = bottom_right_y
  
  	def get_width(self):
  		return self.bottom_right_x - self.top_left_x
  
  	def get_height(self):
  		return self.bottom_right_y - self.top_left_y
  
  
  # Represents a line in the array of output
  class SessionPaneLine(object):
  
  	def __init__(self, line_str, time_seen, line_type):
  		assert line_type in ('log','output')
  		self.line_str        = line_str
  		if isinstance(line_str, bytes):
  			line_str = line_str.decode('utf-8')
  		assert isinstance(line_str, unicode), 'line_str type: ' + str(type(line_str))
  		self.time_seen       = time_seen
  		self.time_seen       = time_seen
  
  	def __str__(self):
  		return self.line_str
  
  
  def setup_signals():
  	"""Set up the signal handlers.
  	"""
  	signal.signal(signal.SIGINT, shutit_util.ctrl_c_signal_handler)
  	signal.signal(signal.SIGQUIT, shutit_util.ctrl_quit_signal_handler)
  
  
  def get_shutit_pexpect_sessions():
  	"""Returns all the shutit_pexpect sessions in existence.
  	"""
  	sessions = []
  	for shutit_object in shutit_global_object.shutit_objects:
  		for key in shutit_object.shutit_pexpect_sessions:
  			sessions.append(shutit_object.shutit_pexpect_sessions[key])
  	return sessions
  
  shutit_global_object = ShutItGlobal()
  
  # Only at this point can we import other modules, otherwise we get race failures.
  from shutit_class import ShutIt, ShutItInit
  import shutit_util
  
  # Create default shutit object. TODO: do we need this?
  shutit_global_object.shutit_objects.append(ShutIt(standalone=False, session_type='bash'))
  