def exception_logger(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        try:
            res = fun(*args, **kwargs)
            if isinstance(res, defer.Deferred):
                @res
                def on_error(failure):
                    log.msg("Got unhandled exception: %s" % failure.getErrorMessage(), system='debug')
                    if get_config().getboolean('debug', 'print_exceptions'):
                        log.err(failure, system='debug')
            return res
        except Exception:
            if get_config().getboolean('debug', 'print_exceptions'):
                log.err(system='debug')
            raise
    return wrapper def find_nth(haystack, needle, n, start_boundary=None):
    start = haystack.find(needle, start_boundary)
    while start >= 0 and n > 1:
        start = haystack.find(needle, start + len(needle))
        n -= 1
    return start CTRL_A = '\x01' CTRL_C = '\x03' CTRL_E = '\x05' CTRL_K = '\x0b' CTRL_X = '\x18' CTRL_Y = '\x19' CTRL_S = '\x13' CTRL_G = '\x07' CTRL_L = '\x0c' CTRL_W = '\x17' DARK_RED = '\x1b[0;31m' RESET_COLOR = '\x1b[0m'
import os
        import string
from contextlib import closing
from copy import copy
from twisted.internet import defer
from twisted.conch.insults import insults
from twisted.python import log
from opennode.oms.util import exception_logger, find_nth
from opennode.oms.endpoint.ssh.terminal import CTRL_A, CTRL_C, CTRL_E, CTRL_K, CTRL_X, CTRL_Y, CTRL_S, CTRL_G, CTRL_L, CTRL_W, DARK_RED, RESET_COLOR
        self.reset_scrolling_region()
        self.parent.setInsertMode()
        self.terminal.termSize.y -= 2

        if self.tracing:
            self.enable_tracing()

        try:
            self.redraw_buffer()
            self.terminal.cursorHome()

            if self.tracing:
                self.replay_recorded()

            yield self.wait_for_exit()
        finally:
            self.terminal.termSize.y += 2
            self.terminal.write('\x1b[?7h')  # re-enable auto wrap
            self.parent.exit_full_screen()

            if self.tracing:
                self.finalize_tracing()

        defer.returnValue(self.saved)

    def replay_recorded(self):
        """Debug utility useful for repeating difficult to reproduce sessions that show some bug"""
        replay_file = '/tmp/key.sim'
        if os.path.exists(replay_file):
            arrows = {'[UP_ARROW]': self.terminal.UP_ARROW,
                      '[DOWN_ARROW]': self.terminal.DOWN_ARROW,
                      '[LEFT_ARROW]': self.terminal.LEFT_ARROW,
                      '[RIGHT_ARROW]': self.terminal.RIGHT_ARROW,
                      }
            for i in open(replay_file):
                if '#' not in i:
                    self.keystrokeReceived(arrows[i.strip()], None)

    def enable_tracing(self):
        self.tracing = True
        self.key_log = open('/tmp/key.log', 'w')

    def finalize_tracing(self):
        self.key_log.close()

    def trace_keystroke(self, keyID, mod):
        if self.tracing:
            print >>self.key_log, keyID
            self.key_log.flush()

    def wait_for_exit(self):
        self.exit = defer.Deferred()
        return self.exit

    def redraw_buffer(self):
        self.terminal.saveCursor()

        self.terminal.eraseDisplay()
        self.draw_modeline('--:-- test     0 %  (0,0)      (Fundamental)')
        self.terminal.cursorHome()

        self.write('\n'.join(self.buffer.split('\n')[0:self.parent.height - 2]))

        self.terminal.restoreCursor()

    def draw_modeline(self, text):
        self.terminal.cursorPosition(0, self.parent.height - 2)
        self.terminal.selectGraphicRendition(str(insults.REVERSE_VIDEO))
        self.terminal.write(text.ljust(self.parent.width))
        self.terminal.selectGraphicRendition()

    def refresh_modline(self):
        if self.has_quit:
            return

        self.terminal.saveCursor()
        self.terminal.selectGraphicRendition(str(insults.REVERSE_VIDEO))
        self.parent.setTypeoverMode()

        if self.dirty != self.old_dirty:
            self.old_dirty = self.dirty
            self.terminal.cursorPosition(3, self.parent.height - 2)
            if self.dirty:
                self.terminal.write('**')
            else:
                self.terminal.write('--')

        self.terminal.cursorPosition(20, self.parent.height - 2)
        self.terminal.write('(%s,%s)   ' % (self.current_line, self.current_column))

        self.parent.setInsertMode()
        self.terminal.selectGraphicRendition()
        self.terminal.restoreCursor()

    def draw_status(self, text):
        text = text.replace('\n', '^J')

        if text == self.status_line:
            return
        self.status_line = text

        self.terminal.saveCursor()
        self.terminal.cursorPosition(0, self.parent.height - 1)
        self.terminal.eraseLine()
        self.terminal.write(text)
        self.terminal.restoreCursor()

    def abort(self):
        self.prefix = ""
        self.draw_status("Quit")

    def char_at(self, pos):
        return self.buffer[pos] if pos < len(self.buffer) else '\x00'

    def write(self, text):
        for line in text.splitlines(True):
            if line.startswith('#'):
                self.terminal.write(self.COMMENT_COLOR)
            self.terminal.write(line)
            if line.startswith('#'):

                self.terminal.write(RESET_COLOR)