diff --git a/jlog/urls.py b/jlog/urls.py index f813c1afe..25eeb6a02 100644 --- a/jlog/urls.py +++ b/jlog/urls.py @@ -8,4 +8,5 @@ urlpatterns = patterns('', url(r'^history/$', log_history), url(r'^log_kill/', log_kill), url(r'^record/$', log_record), + url(r'web_terminal/$', web_terminal), ) \ No newline at end of file diff --git a/jlog/views.py b/jlog/views.py index 9b20a6602..14b27a70c 100644 --- a/jlog/views.py +++ b/jlog/views.py @@ -105,4 +105,6 @@ def log_record(request): return HttpResponse('无日志记录, 请查看日志处理脚本是否开启!') +def web_terminal(request): + return render_to_response('jlog/web_terminal.html', locals()) diff --git a/run_log_watch.py b/run_log_watch.py index 12fb83a14..209a42453 100644 --- a/run_log_watch.py +++ b/run_log_watch.py @@ -16,7 +16,30 @@ import tornado.gen from tornado.websocket import WebSocketClosedError from tornado.options import define, options -from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE, IN_MODIFY, AsyncNotifier, TornadoAsyncNotifier, ThreadedNotifier +from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE, IN_MODIFY + +from gevent import monkey +monkey.patch_all() + +import gevent +from gevent.socket import wait_read, wait_write +from gevent.select import select +from gevent.event import Event + +import paramiko +from paramiko import PasswordRequiredException +from paramiko.dsskey import DSSKey +from paramiko.rsakey import RSAKey +from paramiko.ssh_exception import SSHException + +import socket + +try: + import simplejson as json +except ImportError: + import json + +from StringIO import StringIO define("port", default=8080, help="run on the given port", type=int) define("host", default='0.0.0.0', help="run port on", type=str) @@ -80,6 +103,7 @@ class Application(tornado.web.Application): handlers = [ (r'/', MainHandler), (r'/monitor', MonitorHandler), + (r'/terminal', WebTerminalHandler), ] setting = { @@ -145,6 +169,68 @@ class MainHandler(tornado.web.RequestHandler): self.render('log_watch.html') +class WebTerminalHandler(tornado.websocket.WebSocketHandler): + tasks = [] + + def __init__(self, *args, **kwargs): + self.chan = None + self.ssh = None + super(WebTerminalHandler, self).__init__(*args, **kwargs) + + def check_origin(self, origin): + return True + + def open(self): + self.ssh = paramiko.SSHClient() + self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + try: + self.ssh.connect('127.0.0.1', 22, 'root', 'redhat') + except: + self.write_message(json.loads({'data': 'Connect server Error'})) + self.close() + + self.chan = self.ssh.invoke_shell(term='xterm') + WebTerminalHandler.tasks.append(threading.Thread(target=self._forward_outbound)) + + for t in WebTerminalHandler.tasks: + if t.is_alive(): + continue + t.setDaemon(True) + t.start() + + def on_message(self, message): + data = json.loads(message) + if not data: + return + if 'resize' in data: + self.chan.resize_pty( + data['resize'].get('width', 80), + data['resize'].get('height', 24)) + if 'data' in data: + self.chan.send(data['data']) + + def on_close(self): + self.write_message(json.dumps({'data': 'close websocket'})) + + def _forward_outbound(self): + """ Forward outbound traffic (ssh -> websockets) """ + try: + data = '' + while True: + wait_read(self.chan.fileno()) + recv = self.chan.recv(1024) + if not len(recv): + return + data += recv + try: + self.write_message(json.dumps({'data': data})) + data = '' + except UnicodeDecodeError: + pass + finally: + self.close() + + if __name__ == '__main__': tornado.options.parse_command_line() app = Application() diff --git a/run_tornado.py b/run_tornado.py new file mode 100644 index 000000000..0a3438306 --- /dev/null +++ b/run_tornado.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python +__author__ = 'liuzheng' + +import sys +import os +import re +from tornado.options import options, define, parse_command_line +import tornado.wsgi +import tornado.web +import tornado.httpserver +import tornado.ioloop +import tornado.web +import tornado.ioloop +import tornado.websocket +import pty +import io +import struct +import string +import random +import fcntl +import termios +import tornado.process +import tornado.options +import signal +import utils +import getpass +from connect import Jtty + +define('port', type=int, default=8000) + +ioloop = tornado.ioloop.IOLoop.instance() + +class Terminal(tornado.websocket.WebSocketHandler): + terminals = set() + + def pty(self): + # Make a "unique" id in 4 bytes + self.uid = ''.join( + random.choice( + string.ascii_lowercase + string.ascii_uppercase + + string.digits) + for _ in range(4)) + + self.pid, self.fd = pty.fork() + # print "pid:",self.pid,"fd",self.fd,"uid",self.uid + if self.pid == 0: + # print "Login as", self.user + os.execv("/usr/bin/ssh", [self.user, "localhost"]) + # self.callee = utils.User(name=self.user) + # self.determine_user() + self.shell() + else: + self.communicate() + + def determine_user(self): + if self.callee is None: + # If callee is now known and we have unsecure connection + user = self.user + + try: + self.callee = utils.User(name=user) + except Exception: + # self.log.debug("Can't switch to user %s" % user, exc_info=True) + self.callee = utils.User(name='nobody') + + assert self.callee is not None + + def shell(self): + try: + os.chdir(self.path or self.callee.dir) + except Exception: + pass + env = os.environ + # If local and local user is the same as login user + # We set the env of the user from the browser + # Usefull when running as root + if self.caller == self.callee: + env.update(self.socket.env) + env["TERM"] = "xterm-256color" + env["COLORTERM"] = "butterfly" + env["HOME"] = self.callee.dir + # print(self.callee.dir) + env["LOCATION"] = "http%s://%s:%d/" % ( + "s" if not True else "", + "localhost", 8001) + env["PATH"] = '%s:%s' % (os.path.abspath(os.path.join( + os.path.dirname(__file__), 'bin')), env.get("PATH")) + + try: + tty = os.ttyname(0).replace('/dev/', '') + except Exception: + tty = '' + + if self.caller != self.callee: + try: + os.chown(os.ttyname(0), self.callee.uid, -1) + except Exception: + pass + + utils.add_user_info( + self.uid, + tty, os.getpid(), + self.callee.name, self.request.headers['Host']) + + if os.path.exists('/usr/bin/su'): + args = ['/usr/bin/su'] + else: + args = ['/bin/su'] + + if sys.platform == 'linux': + args.append('-p') + if tornado.options.options.shell: + args.append('-s') + args.append(tornado.options.options.shell) + args.append(self.callee.name) + os.execvpe(args[0], args, env) + + def communicate(self): + fcntl.fcntl(self.fd, fcntl.F_SETFL, os.O_NONBLOCK) + + self.reader = io.open( + self.fd, + 'rb', + buffering=0, + closefd=False + ) + self.writer = io.open( + self.fd, + 'wt', + encoding='utf-8', + closefd=False + ) + ioloop.add_handler( + self.fd, self.shellHandle, ioloop.READ | ioloop.ERROR) + + def allow_draft76(self): + # for iOS 5.0 Safari + return True + + def check_origin(self, origin): + return True + + def open(self): + print "term socket open" + self.fd = None + self.closed = False + self.socket = utils.Socket(self.ws_connection.stream.socket) + self.set_nodelay(True) + self.path = None + self.user = getpass.getuser() + self.caller = self.callee = None + # self.user = "liuzheng" + self.callee = None + + Terminal.terminals.add(self) + + self.pty() + print self.fd + + def on_message(self, msg): + print "on_message ", msg + if not hasattr(self, 'writer'): + self.on_close() + self.close() + return + if msg[0] == 'C': # Change screen + c, r = map(int, msg[1:].split(',')) + s = struct.pack("HHHH", r, c, 0, 0) + fcntl.ioctl(self.fd, termios.TIOCSWINSZ, s) + elif msg[0] == 'R': # Run shell + self.writer.write(msg[1:]) + self.writer.flush() + + def shellHandle(self, f, events): + if events & ioloop.READ: + try: + read = self.reader.read() + except IOError: + read = '' + + if read and len(read) != 0 and self.ws_connection: + self.write_message(read.decode('utf-8', 'replace')) + else: + events = ioloop.ERROR + + if events & ioloop.ERROR: + self.on_close() + self.close() + + def on_close(self): + print "term close", self.uid + if self.closed: + return + self.closed = True + + if getattr(self, 'pid', 0) == 0: + return + + utils.rm_user_info(self.uid, self.pid) + + try: + ioloop.remove_handler(self.fd) + except Exception: + pass + + try: + os.close(self.fd) + except Exception: + pass + try: + os.kill(self.pid, signal.SIGKILL) + os.waitpid(self.pid, 0) + except Exception: + pass + Terminal.terminals.remove(self) + + +class Index(tornado.web.RequestHandler): + def get(self): + self.render('templates/terminal.html') + + +def main(): + sys.path.append('./jumpserver') # path to your project if needed + + parse_command_line() + + tornado_app = tornado.web.Application( + [ + ('/ws/terminal', Terminal), + ('/ws/Terminal', Index), + ]) + + server = tornado.httpserver.HTTPServer(tornado_app) + server.listen(options.port) + + tornado.ioloop.IOLoop.instance().start() + + +if __name__ == '__main__': + main() diff --git a/static/css/plugins/bootstrap.min.css b/static/css/plugins/bootstrap.min.css new file mode 100644 index 000000000..c95146773 --- /dev/null +++ b/static/css/plugins/bootstrap.min.css @@ -0,0 +1,689 @@ +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} +audio:not([controls]){display:none;} +html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} +a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +a:hover,a:active{outline:0;} +sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} +sup{top:-0.5em;} +sub{bottom:-0.25em;} +img{height:auto;border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;} +button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} +button,input{*overflow:visible;line-height:normal;} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} +button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} +input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;} +input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} +textarea{overflow:auto;vertical-align:top;} +.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";} +.clearfix:after{clear:both;} +.hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;} +.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} +body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;} +a{color:#0088cc;text-decoration:none;} +a:hover{color:#005580;text-decoration:underline;} +.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} +.row:after{clear:both;} +[class*="span"]{float:left;margin-left:20px;} +.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.span12{width:940px;} +.span11{width:860px;} +.span10{width:780px;} +.span9{width:700px;} +.span8{width:620px;} +.span7{width:540px;} +.span6{width:460px;} +.span5{width:380px;} +.span4{width:300px;} +.span3{width:220px;} +.span2{width:140px;} +.span1{width:60px;} +.offset12{margin-left:980px;} +.offset11{margin-left:900px;} +.offset10{margin-left:820px;} +.offset9{margin-left:740px;} +.offset8{margin-left:660px;} +.offset7{margin-left:580px;} +.offset6{margin-left:500px;} +.offset5{margin-left:420px;} +.offset4{margin-left:340px;} +.offset3{margin-left:260px;} +.offset2{margin-left:180px;} +.offset1{margin-left:100px;} +.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} +.row-fluid:after{clear:both;} +.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;} +.row-fluid>[class*="span"]:first-child{margin-left:0;} +.row-fluid > .span12{width:99.99999998999999%;} +.row-fluid > .span11{width:91.489361693%;} +.row-fluid > .span10{width:82.97872339599999%;} +.row-fluid > .span9{width:74.468085099%;} +.row-fluid > .span8{width:65.95744680199999%;} +.row-fluid > .span7{width:57.446808505%;} +.row-fluid > .span6{width:48.93617020799999%;} +.row-fluid > .span5{width:40.425531911%;} +.row-fluid > .span4{width:31.914893614%;} +.row-fluid > .span3{width:23.404255317%;} +.row-fluid > .span2{width:14.89361702%;} +.row-fluid > .span1{width:6.382978723%;} +.container{margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";} +.container:after{clear:both;} +.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";} +.container-fluid:after{clear:both;} +p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;} +.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;} +h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;} +h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;} +h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;} +h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;} +h4,h5,h6{line-height:18px;} +h4{font-size:14px;}h4 small{font-size:12px;} +h5{font-size:12px;} +h6{font-size:11px;color:#999999;text-transform:uppercase;} +.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;} +.page-header h1{line-height:1;} +ul,ol{padding:0;margin:0 0 9px 25px;} +ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} +ul{list-style:disc;} +ol{list-style:decimal;} +li{line-height:18px;} +ul.unstyled,ol.unstyled{margin-left:0;list-style:none;} +dl{margin-bottom:18px;} +dt,dd{line-height:18px;} +dt{font-weight:bold;line-height:17px;} +dd{margin-left:9px;} +.dl-horizontal dt{float:left;clear:left;width:120px;text-align:right;} +.dl-horizontal dd{margin-left:130px;} +hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;} +strong{font-weight:bold;} +em{font-style:italic;} +.muted{color:#999999;} +abbr[title]{border-bottom:1px dotted #ddd;cursor:help;} +abbr.initialism{font-size:90%;text-transform:uppercase;} +blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;} +blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} +blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} +q:before,q:after,blockquote:before,blockquote:after{content:"";} +address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;} +small{font-size:100%;} +cite{font-style:normal;} +code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} +pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;word-wrap:break-word;}pre.prettyprint{margin-bottom:18px;} +pre code{padding:0;color:inherit;background-color:transparent;border:0;} +.pre-scrollable{max-height:340px;overflow-y:scroll;} +form{margin:0 0 18px;} +fieldset{padding:0;margin:0;border:0;} +legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}legend small{font-size:13.5px;color:#999999;} +label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;} +input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;} +label{display:block;margin-bottom:5px;color:#333333;} +input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #cccccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.uneditable-textarea{width:auto;height:auto;} +label input,label textarea,label select{display:block;} +input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0 \9;} +input[type="image"]{border:0;} +input[type="file"]{width:auto;padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;} +select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;} +input[type="file"]{line-height:18px \9;} +select{width:220px;background-color:#ffffff;} +select[multiple],select[size]{height:auto;} +input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +textarea{height:auto;} +input[type="hidden"]{display:none;} +.radio,.checkbox{padding-left:18px;} +.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;} +.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} +.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;} +.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} +input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;} +input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;} +input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.input-mini{width:60px;} +.input-small{width:90px;} +.input-medium{width:150px;} +.input-large{width:210px;} +.input-xlarge{width:270px;} +.input-xxlarge{width:530px;} +input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;} +input,textarea,.uneditable-input{margin-left:0;} +input.span12, textarea.span12, .uneditable-input.span12{width:930px;} +input.span11, textarea.span11, .uneditable-input.span11{width:850px;} +input.span10, textarea.span10, .uneditable-input.span10{width:770px;} +input.span9, textarea.span9, .uneditable-input.span9{width:690px;} +input.span8, textarea.span8, .uneditable-input.span8{width:610px;} +input.span7, textarea.span7, .uneditable-input.span7{width:530px;} +input.span6, textarea.span6, .uneditable-input.span6{width:450px;} +input.span5, textarea.span5, .uneditable-input.span5{width:370px;} +input.span4, textarea.span4, .uneditable-input.span4{width:290px;} +input.span3, textarea.span3, .uneditable-input.span3{width:210px;} +input.span2, textarea.span2, .uneditable-input.span2{width:130px;} +input.span1, textarea.span1, .uneditable-input.span1{width:50px;} +input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#eeeeee;border-color:#ddd;cursor:not-allowed;} +.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} +.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;} +.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} +.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} +.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;} +.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} +.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} +.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;} +.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} +input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} +.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#eeeeee;border-top:1px solid #ddd;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";} +.form-actions:after{clear:both;} +.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} +:-moz-placeholder{color:#999999;} +::-webkit-input-placeholder{color:#999999;} +.help-block,.help-inline{color:#555555;} +.help-block{display:block;margin-bottom:9px;} +.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;} +.input-prepend,.input-append{margin-bottom:5px;}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{*margin-left:0;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;} +.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;} +.input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;min-width:16px;height:18px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #ffffff;vertical-align:middle;background-color:#eeeeee;border:1px solid #ccc;} +.input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;} +.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;} +.input-append input,.input-append select .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-append .uneditable-input{border-left-color:#eee;border-right-color:#ccc;} +.input-append .add-on,.input-append .btn{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;} +.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;margin-bottom:0;} +.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;} +.form-search label,.form-inline label{display:inline-block;} +.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;} +.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;} +.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-left:0;margin-right:3px;} +.control-group{margin-bottom:9px;} +legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;} +.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";} +.form-horizontal .control-group:after{clear:both;} +.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;} +.form-horizontal .controls{margin-left:160px;*display:inline-block;*margin-left:0;*padding-left:20px;} +.form-horizontal .help-block{margin-top:9px;margin-bottom:0;} +.form-horizontal .form-actions{padding-left:160px;} +table{max-width:100%;border-collapse:collapse;border-spacing:0;background-color:transparent;} +.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;} +.table th{font-weight:bold;} +.table thead th{vertical-align:bottom;} +.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;} +.table tbody+tbody{border-top:2px solid #dddddd;} +.table-condensed th,.table-condensed td{padding:4px 5px;} +.table-bordered{border:1px solid #dddddd;border-left:0;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;} +.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} +.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;} +.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;} +.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;} +.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;} +.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} +.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;} +table .span1{float:none;width:44px;margin-left:0;} +table .span2{float:none;width:124px;margin-left:0;} +table .span3{float:none;width:204px;margin-left:0;} +table .span4{float:none;width:284px;margin-left:0;} +table .span5{float:none;width:364px;margin-left:0;} +table .span6{float:none;width:444px;margin-left:0;} +table .span7{float:none;width:524px;margin-left:0;} +table .span8{float:none;width:604px;margin-left:0;} +table .span9{float:none;width:684px;margin-left:0;} +table .span10{float:none;width:764px;margin-left:0;} +table .span11{float:none;width:844px;margin-left:0;} +table .span12{float:none;width:924px;margin-left:0;} +table .span13{float:none;width:1004px;margin-left:0;} +table .span14{float:none;width:1084px;margin-left:0;} +table .span15{float:none;width:1164px;margin-left:0;} +table .span16{float:none;width:1244px;margin-left:0;} +table .span17{float:none;width:1324px;margin-left:0;} +table .span18{float:none;width:1404px;margin-left:0;} +table .span19{float:none;width:1484px;margin-left:0;} +table .span20{float:none;width:1564px;margin-left:0;} +table .span21{float:none;width:1644px;margin-left:0;} +table .span22{float:none;width:1724px;margin-left:0;} +table .span23{float:none;width:1804px;margin-left:0;} +table .span24{float:none;width:1884px;margin-left:0;} +[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0;} +.icon-white{background-image:url("../img/glyphicons-halflings-white.png");} +.icon-glass{background-position:0 0;} +.icon-music{background-position:-24px 0;} +.icon-search{background-position:-48px 0;} +.icon-envelope{background-position:-72px 0;} +.icon-heart{background-position:-96px 0;} +.icon-star{background-position:-120px 0;} +.icon-star-empty{background-position:-144px 0;} +.icon-user{background-position:-168px 0;} +.icon-film{background-position:-192px 0;} +.icon-th-large{background-position:-216px 0;} +.icon-th{background-position:-240px 0;} +.icon-th-list{background-position:-264px 0;} +.icon-ok{background-position:-288px 0;} +.icon-remove{background-position:-312px 0;} +.icon-zoom-in{background-position:-336px 0;} +.icon-zoom-out{background-position:-360px 0;} +.icon-off{background-position:-384px 0;} +.icon-signal{background-position:-408px 0;} +.icon-cog{background-position:-432px 0;} +.icon-trash{background-position:-456px 0;} +.icon-home{background-position:0 -24px;} +.icon-file{background-position:-24px -24px;} +.icon-time{background-position:-48px -24px;} +.icon-road{background-position:-72px -24px;} +.icon-download-alt{background-position:-96px -24px;} +.icon-download{background-position:-120px -24px;} +.icon-upload{background-position:-144px -24px;} +.icon-inbox{background-position:-168px -24px;} +.icon-play-circle{background-position:-192px -24px;} +.icon-repeat{background-position:-216px -24px;} +.icon-refresh{background-position:-240px -24px;} +.icon-list-alt{background-position:-264px -24px;} +.icon-lock{background-position:-287px -24px;} +.icon-flag{background-position:-312px -24px;} +.icon-headphones{background-position:-336px -24px;} +.icon-volume-off{background-position:-360px -24px;} +.icon-volume-down{background-position:-384px -24px;} +.icon-volume-up{background-position:-408px -24px;} +.icon-qrcode{background-position:-432px -24px;} +.icon-barcode{background-position:-456px -24px;} +.icon-tag{background-position:0 -48px;} +.icon-tags{background-position:-25px -48px;} +.icon-book{background-position:-48px -48px;} +.icon-bookmark{background-position:-72px -48px;} +.icon-print{background-position:-96px -48px;} +.icon-camera{background-position:-120px -48px;} +.icon-font{background-position:-144px -48px;} +.icon-bold{background-position:-167px -48px;} +.icon-italic{background-position:-192px -48px;} +.icon-text-height{background-position:-216px -48px;} +.icon-text-width{background-position:-240px -48px;} +.icon-align-left{background-position:-264px -48px;} +.icon-align-center{background-position:-288px -48px;} +.icon-align-right{background-position:-312px -48px;} +.icon-align-justify{background-position:-336px -48px;} +.icon-list{background-position:-360px -48px;} +.icon-indent-left{background-position:-384px -48px;} +.icon-indent-right{background-position:-408px -48px;} +.icon-facetime-video{background-position:-432px -48px;} +.icon-picture{background-position:-456px -48px;} +.icon-pencil{background-position:0 -72px;} +.icon-map-marker{background-position:-24px -72px;} +.icon-adjust{background-position:-48px -72px;} +.icon-tint{background-position:-72px -72px;} +.icon-edit{background-position:-96px -72px;} +.icon-share{background-position:-120px -72px;} +.icon-check{background-position:-144px -72px;} +.icon-move{background-position:-168px -72px;} +.icon-step-backward{background-position:-192px -72px;} +.icon-fast-backward{background-position:-216px -72px;} +.icon-backward{background-position:-240px -72px;} +.icon-play{background-position:-264px -72px;} +.icon-pause{background-position:-288px -72px;} +.icon-stop{background-position:-312px -72px;} +.icon-forward{background-position:-336px -72px;} +.icon-fast-forward{background-position:-360px -72px;} +.icon-step-forward{background-position:-384px -72px;} +.icon-eject{background-position:-408px -72px;} +.icon-chevron-left{background-position:-432px -72px;} +.icon-chevron-right{background-position:-456px -72px;} +.icon-plus-sign{background-position:0 -96px;} +.icon-minus-sign{background-position:-24px -96px;} +.icon-remove-sign{background-position:-48px -96px;} +.icon-ok-sign{background-position:-72px -96px;} +.icon-question-sign{background-position:-96px -96px;} +.icon-info-sign{background-position:-120px -96px;} +.icon-screenshot{background-position:-144px -96px;} +.icon-remove-circle{background-position:-168px -96px;} +.icon-ok-circle{background-position:-192px -96px;} +.icon-ban-circle{background-position:-216px -96px;} +.icon-arrow-left{background-position:-240px -96px;} +.icon-arrow-right{background-position:-264px -96px;} +.icon-arrow-up{background-position:-289px -96px;} +.icon-arrow-down{background-position:-312px -96px;} +.icon-share-alt{background-position:-336px -96px;} +.icon-resize-full{background-position:-360px -96px;} +.icon-resize-small{background-position:-384px -96px;} +.icon-plus{background-position:-408px -96px;} +.icon-minus{background-position:-433px -96px;} +.icon-asterisk{background-position:-456px -96px;} +.icon-exclamation-sign{background-position:0 -120px;} +.icon-gift{background-position:-24px -120px;} +.icon-leaf{background-position:-48px -120px;} +.icon-fire{background-position:-72px -120px;} +.icon-eye-open{background-position:-96px -120px;} +.icon-eye-close{background-position:-120px -120px;} +.icon-warning-sign{background-position:-144px -120px;} +.icon-plane{background-position:-168px -120px;} +.icon-calendar{background-position:-192px -120px;} +.icon-random{background-position:-216px -120px;} +.icon-comment{background-position:-240px -120px;} +.icon-magnet{background-position:-264px -120px;} +.icon-chevron-up{background-position:-288px -120px;} +.icon-chevron-down{background-position:-313px -119px;} +.icon-retweet{background-position:-336px -120px;} +.icon-shopping-cart{background-position:-360px -120px;} +.icon-folder-close{background-position:-384px -120px;} +.icon-folder-open{background-position:-408px -120px;} +.icon-resize-vertical{background-position:-432px -119px;} +.icon-resize-horizontal{background-position:-456px -118px;} +.dropdown{position:relative;} +.dropdown-toggle{*margin-bottom:-3px;} +.dropdown-toggle:active,.open .dropdown-toggle{outline:0;} +.caret{display:inline-block;width:0;height:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"";} +.dropdown .caret{margin-top:8px;margin-left:2px;} +.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.pull-right{right:0;left:auto;} +.dropdown-menu .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;} +.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333333;white-space:nowrap;} +.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;} +.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);} +.dropdown.open .dropdown-menu{display:block;} +.pull-right .dropdown-menu{left:auto;right:0;} +.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"\2191";} +.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;} +.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} +.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;} +.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;} +.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;} +.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);border:1px solid #cccccc;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;} +.btn:active,.btn.active{background-color:#cccccc \9;} +.btn:first-child{*margin-left:0;} +.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;outline:0;} +.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.btn-large [class^="icon-"]{margin-top:1px;} +.btn-small{padding:5px 9px;font-size:11px;line-height:16px;} +.btn-small [class^="icon-"]{margin-top:-1px;} +.btn-mini{padding:2px 6px;font-size:11px;line-height:14px;} +.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;} +.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);} +.btn-primary{background-color:#0074cc;background-image:-moz-linear-gradient(top, #0088cc, #0055cc);background-image:-ms-linear-gradient(top, #0088cc, #0055cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));background-image:-webkit-linear-gradient(top, #0088cc, #0055cc);background-image:-o-linear-gradient(top, #0088cc, #0055cc);background-image:linear-gradient(top, #0088cc, #0055cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);border-color:#0055cc #0055cc #003580;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0055cc;} +.btn-primary:active,.btn-primary.active{background-color:#004099 \9;} +.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;} +.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} +.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;} +.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} +.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;} +.btn-success:active,.btn-success.active{background-color:#408140 \9;} +.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;} +.btn-info:active,.btn-info.active{background-color:#24748c \9;} +.btn-inverse{background-color:#414141;background-image:-moz-linear-gradient(top, #555555, #222222);background-image:-ms-linear-gradient(top, #555555, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));background-image:-webkit-linear-gradient(top, #555555, #222222);background-image:-o-linear-gradient(top, #555555, #222222);background-image:linear-gradient(top, #555555, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222222;} +.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;} +button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} +button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;} +button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;} +button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;} +.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";} +.btn-group:after{clear:both;} +.btn-group:first-child{*margin-left:0;} +.btn-group+.btn-group{margin-left:5px;} +.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;} +.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;} +.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} +.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:3px;*padding-bottom:3px;} +.btn-group .btn-mini.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:1px;*padding-bottom:1px;} +.btn-group .btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px;} +.btn-group .btn-large.dropdown-toggle{padding-left:12px;padding-right:12px;} +.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);} +.btn .caret{margin-top:7px;margin-left:0;} +.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);} +.btn-mini .caret{margin-top:5px;} +.btn-small .caret{margin-top:6px;} +.btn-large .caret{margin-top:6px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);} +.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;} +.alert-heading{color:inherit;} +.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;} +.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;} +.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;} +.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;} +.alert-block{padding-top:14px;padding-bottom:14px;} +.alert-block>p,.alert-block>ul{margin-bottom:0;} +.alert-block p+p{margin-top:5px;} +.nav{margin-left:0;margin-bottom:18px;list-style:none;} +.nav>li>a{display:block;} +.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;} +.nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} +.nav li+.nav-header{margin-top:9px;} +.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;} +.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} +.nav-list>li>a{padding:3px 15px;} +.nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} +.nav-list [class^="icon-"]{margin-right:2px;} +.nav-list .divider{height:1px;margin:8px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;} +.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";} +.nav-tabs:after,.nav-pills:after{clear:both;} +.nav-tabs>li,.nav-pills>li{float:left;} +.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} +.nav-tabs{border-bottom:1px solid #ddd;} +.nav-tabs>li{margin-bottom:-1px;} +.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;} +.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} +.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;} +.nav-stacked>li{float:none;} +.nav-stacked>li>a{margin-right:0;} +.nav-tabs.nav-stacked{border-bottom:0;} +.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} +.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} +.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;} +.nav-pills.nav-stacked>li>a{margin-bottom:3px;} +.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} +.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;} +.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;} +.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;} +.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;border-bottom-color:#333333;} +.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;} +.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;} +.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);} +.tabs-stacked .open>a:hover{border-color:#999999;} +.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";} +.tabbable:after{clear:both;} +.tab-content{display:table;width:100%;} +.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;} +.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} +.tab-content>.active,.pill-content>.active{display:block;} +.tabs-below .nav-tabs{border-top:1px solid #ddd;} +.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;} +.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;} +.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;} +.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;} +.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} +.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} +.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} +.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} +.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} +.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} +.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} +.navbar{*position:relative;*z-index:2;overflow:visible;margin-bottom:18px;} +.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);} +.navbar .container{width:auto;} +.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;} +.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;} +.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} +.btn-navbar .icon-bar+.icon-bar{margin-top:3px;} +.nav-collapse.collapse{height:auto;} +.navbar{color:#999999;}.navbar .brand:hover{text-decoration:none;} +.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;} +.navbar .navbar-text{margin-bottom:0;line-height:40px;} +.navbar .btn,.navbar .btn-group{margin-top:5px;} +.navbar .btn-group .btn{margin-top:0;} +.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";} +.navbar-form:after{clear:both;} +.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} +.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0;} +.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} +.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;} +.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;background-color:#626262;border:1px solid #151515;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query:-moz-placeholder{color:#cccccc;} +.navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;} +.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} +.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;} +.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.navbar-fixed-top{top:0;} +.navbar-fixed-bottom{bottom:0;} +.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} +.navbar .nav.pull-right{float:right;} +.navbar .nav>li{display:block;float:left;} +.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} +.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;} +.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;} +.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;} +.navbar .nav.pull-right{margin-left:10px;margin-right:0;} +.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} +.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} +.navbar-fixed-bottom .dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;} +.navbar-fixed-bottom .dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;} +.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);} +.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;} +.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;} +.navbar .nav.pull-right .dropdown-menu,.navbar .nav .dropdown-menu.pull-right{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before,.navbar .nav .dropdown-menu.pull-right:before{left:auto;right:12px;} +.navbar .nav.pull-right .dropdown-menu:after,.navbar .nav .dropdown-menu.pull-right:after{left:auto;right:13px;} +.breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;} +.breadcrumb .divider{padding:0 5px;color:#999999;} +.breadcrumb .active a{color:#333333;} +.pagination{height:36px;margin:18px 0;} +.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} +.pagination li{display:inline;} +.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;} +.pagination a:hover,.pagination .active a{background-color:#f5f5f5;} +.pagination .active a{color:#999999;cursor:default;} +.pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;} +.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} +.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} +.pagination-centered{text-align:center;} +.pagination-right{text-align:right;} +.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";} +.pager:after{clear:both;} +.pager li{display:inline;} +.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.pager a:hover{text-decoration:none;background-color:#f5f5f5;} +.pager .next a{float:right;} +.pager .previous a{float:left;} +.pager .disabled a,.pager .disabled a:hover{color:#999999;background-color:#fff;cursor:default;} +.modal-open .dropdown-menu{z-index:2050;} +.modal-open .dropdown.open{*z-index:2050;} +.modal-open .popover{z-index:2060;} +.modal-open .tooltip{z-index:2070;} +.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} +.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} +.modal{position:fixed;top:50%;left:50%;z-index:1050;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} +.modal.fade.in{top:50%;} +.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} +.modal-body{overflow-y:auto;max-height:400px;padding:15px;} +.modal-form{margin-bottom:0;} +.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";} +.modal-footer:after{clear:both;} +.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;} +.modal-footer .btn-group .btn+.btn{margin-left:-1px;} +.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} +.tooltip.top{margin-top:-2px;} +.tooltip.right{margin-left:2px;} +.tooltip.bottom{margin-top:2px;} +.tooltip.left{margin-left:-2px;} +.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} +.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} +.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} +.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.tooltip-arrow{position:absolute;width:0;height:0;} +.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;} +.popover.right{margin-left:5px;} +.popover.bottom{margin-top:5px;} +.popover.left{margin-left:-5px;} +.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} +.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} +.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} +.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} +.popover .arrow{position:absolute;width:0;height:0;} +.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} +.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;} +.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;} +.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";} +.thumbnails:after{clear:both;} +.thumbnails>li{float:left;margin:0 0 18px 20px;} +.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);} +a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} +.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} +.thumbnail .caption{padding:9px;} +.label{padding:1px 4px 2px;font-size:10.998px;font-weight:bold;line-height:13px;color:#ffffff;vertical-align:middle;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.label:hover{color:#ffffff;text-decoration:none;} +.label-important{background-color:#b94a48;} +.label-important:hover{background-color:#953b39;} +.label-warning{background-color:#f89406;} +.label-warning:hover{background-color:#c67605;} +.label-success{background-color:#468847;} +.label-success:hover{background-color:#356635;} +.label-info{background-color:#3a87ad;} +.label-info:hover{background-color:#2d6987;} +.label-inverse{background-color:#333333;} +.label-inverse:hover{background-color:#1a1a1a;} +.badge{padding:1px 9px 2px;font-size:12.025px;font-weight:bold;white-space:nowrap;color:#ffffff;background-color:#999999;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;} +.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;} +.badge-error{background-color:#b94a48;} +.badge-error:hover{background-color:#953b39;} +.badge-warning{background-color:#f89406;} +.badge-warning:hover{background-color:#c67605;} +.badge-success{background-color:#468847;} +.badge-success:hover{background-color:#356635;} +.badge-info{background-color:#3a87ad;} +.badge-info:hover{background-color:#2d6987;} +.badge-inverse{background-color:#333333;} +.badge-inverse:hover{background-color:#1a1a1a;} +@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} +.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} +.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} +.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);} +.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);} +.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);} +.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);} +.progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.accordion{margin-bottom:18px;} +.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion-heading{border-bottom:0;} +.accordion-heading .accordion-toggle{display:block;padding:8px 15px;} +.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} +.carousel{position:relative;margin-bottom:18px;line-height:1;} +.carousel-inner{overflow:hidden;width:100%;position:relative;} +.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;} +.carousel .item>img{display:block;line-height:1;} +.carousel .active,.carousel .next,.carousel .prev{display:block;} +.carousel .active{left:0;} +.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;} +.carousel .next{left:100%;} +.carousel .prev{left:-100%;} +.carousel .next.left,.carousel .prev.right{left:0;} +.carousel .active.left{left:-100%;} +.carousel .active.right{left:100%;} +.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} +.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} +.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);} +.carousel-caption h4,.carousel-caption p{color:#ffffff;} +.hero-unit{padding:60px;margin-bottom:30px;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;} +.hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit;} +.pull-right{float:right;} +.pull-left{float:left;} +.hide{display:none;} +.show{display:block;} +.invisible{visibility:hidden;} diff --git a/static/js/term.js b/static/js/term.js new file mode 100644 index 000000000..dc8f9fc5c --- /dev/null +++ b/static/js/term.js @@ -0,0 +1,4182 @@ +/** + * tty.js - an xterm emulator + * Christopher Jeffrey (https://github.com/chjj/tty.js) + * + * Originally forked from (with the author's permission): + * + * Fabrice Bellard's javascript vt100 for jslinux: + * http://bellard.org/jslinux/ + * Copyright (c) 2011 Fabrice Bellard + * (Redistribution or commercial use is prohibited + * without the author's permission.) + * + * The original design remains. The terminal itself + * has been extended to include xterm CSI codes, among + * other features. +*/ + +;(function() { + +/** + * Terminal Emulation References: + * http://vt100.net/ + * http://invisible-island.net/xterm/ctlseqs/ctlseqs.txt + * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + * http://invisible-island.net/vttest/ + * http://www.inwap.com/pdp10/ansicode.txt + * http://linux.die.net/man/4/console_codes + * http://linux.die.net/man/7/urxvt + */ + +'use strict'; + +/** + * Shared + */ + +var window = this + , document = this.document; + +/** + * EventEmitter + */ + +function EventEmitter() { + this._events = {}; +} + +EventEmitter.prototype.addListener = function(type, listener) { + this._events[type] = this._events[type] || []; + this._events[type].push(listener); +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.removeListener = function(type, listener) { + if (!this._events[type]) return; + + var obj = this._events[type] + , i = obj.length; + + while (i--) { + if (obj[i] === listener || obj[i].listener === listener) { + obj.splice(i, 1); + return; + } + } +}; + +EventEmitter.prototype.off = EventEmitter.prototype.removeListener; + +EventEmitter.prototype.removeAllListeners = function(type) { + if (this._events[type]) delete this._events[type]; +}; + +EventEmitter.prototype.once = function(type, listener) { + function on() { + var args = Array.prototype.slice.call(arguments); + this.removeListener(type, on); + return listener.apply(this, args); + } + on.listener = listener; + return this.on(type, on); +}; + +EventEmitter.prototype.emit = function(type) { + if (!this._events[type]) return; + + var args = Array.prototype.slice.call(arguments, 1) + , obj = this._events[type] + , l = obj.length + , i = 0; + + for (; i < l; i++) { + obj[i].apply(this, args); + } +}; + +EventEmitter.prototype.listeners = function(type) { + return this._events[type] = this._events[type] || []; +}; + +/** + * States + */ + +var normal = 0 + , escaped = 1 + , csi = 2 + , osc = 3 + , charset = 4 + , dcs = 5 + , ignore = 6; + +/** + * Terminal + */ + +function Terminal(cols, rows, handler) { + EventEmitter.call(this); + + var options; + if (typeof cols === 'object') { + options = cols; + cols = options.cols; + rows = options.rows; + handler = options.handler; + } + this._options = options || {}; + + this.cols = cols || Terminal.geometry[0]; + this.rows = rows || Terminal.geometry[1]; + + //if (handler) { + // this.on('data', handler); + //} + this.handler = handler; + if (this.handler){ + this.on('data', this.handler); + } + + this.ybase = 0; + this.ydisp = 0; + this.x = 0; + this.y = 0; + this.cursorState = 0; + this.cursorHidden = false; + this.convertEol = false; + this.state = 0; + this.queue = ''; + this.scrollTop = 0; + this.scrollBottom = this.rows - 1; + + // modes + this.applicationKeypad = false; + this.originMode = false; + this.insertMode = false; + this.wraparoundMode = false; + this.normal = null; + + // charset + this.charset = null; + this.gcharset = null; + this.glevel = 0; + this.charsets = [null]; + + // mouse properties + this.decLocator; + this.x10Mouse; + this.vt200Mouse; + this.vt300Mouse; + this.normalMouse; + this.mouseEvents; + this.sendFocus; + this.utfMouse; + this.sgrMouse; + this.urxvtMouse; + + // misc + this.element; + this.children; + this.refreshStart; + this.refreshEnd; + this.savedX; + this.savedY; + this.savedCols; + + // stream + this.readable = true; + this.writable = true; + + this.defAttr = (257 << 9) | 256; + this.curAttr = this.defAttr; + + this.params = []; + this.currentParam = 0; + this.prefix = ''; + this.postfix = ''; + + this.lines = []; + var i = this.rows; + while (i--) { + this.lines.push(this.blankLine()); + } + + this.tabs; + this.setupStops(); +} + +inherits(Terminal, EventEmitter); + +/** + * Colors + */ + +// Colors 0-15 +Terminal.colors = [ + // dark: + '#2e3436', + '#cc0000', + '#4e9a06', + '#c4a000', + '#3465a4', + '#75507b', + '#06989a', + '#d3d7cf', + // bright: + '#555753', + '#ef2929', + '#8ae234', + '#fce94f', + '#729fcf', + '#ad7fa8', + '#34e2e2', + '#eeeeec' +]; + +// Colors 16-255 +// Much thanks to TooTallNate for writing this. +Terminal.colors = (function() { + var colors = Terminal.colors + , r = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff] + , i; + + // 16-231 + i = 0; + for (; i < 216; i++) { + out(r[(i / 36) % 6 | 0], r[(i / 6) % 6 | 0], r[i % 6]); + } + + // 232-255 (grey) + i = 0; + for (; i < 24; i++) { + r = 8 + i * 10; + out(r, r, r); + } + + function out(r, g, b) { + colors.push('#' + hex(r) + hex(g) + hex(b)); + } + + function hex(c) { + c = c.toString(16); + return c.length < 2 ? '0' + c : c; + } + + return colors; +})(); + +// Default BG/FG +Terminal.defaultColors = { + bg: '#000000', + fg: '#f0f0f0' +}; + +Terminal.colors[256] = Terminal.defaultColors.bg; +Terminal.colors[257] = Terminal.defaultColors.fg; + +/** + * Options + */ + +Terminal.termName = 'xterm'; +Terminal.geometry = [80, 30]; +Terminal.cursorBlink = true; +Terminal.visualBell = false; +Terminal.popOnBell = false; +Terminal.scrollback = 1000; +Terminal.screenKeys = false; +Terminal.programFeatures = false; +Terminal.debug = false; + +/** + * Focused Terminal + */ + +Terminal.focus = null; + +Terminal.prototype.focus = function() { + if (Terminal.focus === this) return; + if (Terminal.focus) { + Terminal.focus.cursorState = 0; + Terminal.focus.refresh(Terminal.focus.y, Terminal.focus.y); + if (Terminal.focus.sendFocus) Terminal.focus.send('\x1b[O'); + } + Terminal.focus = this; + if (this.sendFocus) this.send('\x1b[I'); + this.showCursor(); +}; + +/** + * Global Events for key handling + */ + +Terminal.bindKeys = function() { + if (Terminal.focus) return; + + // We could put an "if (Terminal.focus)" check + // here, but it shouldn't be necessary. + on(document, 'keydown', function(ev) { + return Terminal.focus.keyDown(ev); + }, true); + + on(document, 'keypress', function(ev) { + return Terminal.focus.keyPress(ev); + }, true); +}; + +/** + * Open Terminal + */ + +Terminal.prototype.open = function() { + var self = this + , i = 0 + , div; + + this.element = document.createElement('div'); + this.element.className = 'terminal'; + this.children = []; + + for (; i < this.rows; i++) { + div = document.createElement('div'); + this.element.appendChild(div); + this.children.push(div); + } + + document.body.appendChild(this.element); + + this.refresh(0, this.rows - 1); + + Terminal.bindKeys(); + this.focus(); + + this.startBlink(); + + on(this.element, 'mousedown', function() { + self.focus(); + }); + + // This probably shouldn't work, + // ... but it does. Firefox's paste + // event seems to only work for textareas? + on(this.element, 'mousedown', function(ev) { + var button = ev.button != null + ? +ev.button + : ev.which != null + ? ev.which - 1 + : null; + + // Does IE9 do this? + if (~navigator.userAgent.indexOf('MSIE')) { + button = button === 1 ? 0 : button === 4 ? 1 : button; + } + + if (button !== 2) return; + + self.element.contentEditable = 'true'; + setTimeout(function() { + self.element.contentEditable = 'inherit'; // 'false'; + }, 1); + }, true); + + on(this.element, 'paste', function(ev) { + if (ev.clipboardData) { + self.send(ev.clipboardData.getData('text/plain')); + } else if (window.clipboardData) { + self.send(window.clipboardData.getData('Text')); + } + // Not necessary. Do it anyway for good measure. + self.element.contentEditable = 'inherit'; + return cancel(ev); + }); + + this.bindMouse(); + + // XXX - hack, move this somewhere else. + if (Terminal.brokenBold == null) { + Terminal.brokenBold = isBoldBroken(); + } + + // sync default bg/fg colors + this.element.style.backgroundColor = Terminal.defaultColors.bg; + this.element.style.color = Terminal.defaultColors.fg; + + //this.emit('open'); +}; + +// XTerm mouse events +// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking +// To better understand these +// the xterm code is very helpful: +// Relevant files: +// button.c, charproc.c, misc.c +// Relevant functions in xterm/button.c: +// BtnCode, EmitButtonCode, EditorButton, SendMousePosition +Terminal.prototype.bindMouse = function() { + var el = this.element + , self = this + , pressed = 32; + + var wheelEvent = 'onmousewheel' in window + ? 'mousewheel' + : 'DOMMouseScroll'; + + // mouseup, mousedown, mousewheel + // left click: ^[[M 3<^[[M#3< + // mousewheel up: ^[[M`3> + function sendButton(ev) { + var button + , pos; + + // get the xterm-style button + button = getButton(ev); + + // get mouse coordinates + pos = getCoords(ev); + if (!pos) return; + + sendEvent(button, pos); + + switch (ev.type) { + case 'mousedown': + pressed = button; + break; + case 'mouseup': + // keep it at the left + // button, just in case. + pressed = 32; + break; + case wheelEvent: + // nothing. don't + // interfere with + // `pressed`. + break; + } + } + + // motion example of a left click: + // ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7< + function sendMove(ev) { + var button = pressed + , pos; + + pos = getCoords(ev); + if (!pos) return; + + // buttons marked as motions + // are incremented by 32 + button += 32; + + sendEvent(button, pos); + } + + // encode button and + // position to characters + function encode(data, ch) { + if (!self.utfMouse) { + if (ch === 255) return data.push(0); + if (ch > 127) ch = 127; + data.push(ch); + } else { + if (ch === 2047) return data.push(0); + if (ch < 127) { + data.push(ch); + } else { + if (ch > 2047) ch = 2047; + data.push(0xC0 | (ch >> 6)); + data.push(0x80 | (ch & 0x3F)); + } + } + } + + // send a mouse event: + // regular/utf8: ^[[M Cb Cx Cy + // urxvt: ^[[ Cb ; Cx ; Cy M + // sgr: ^[[ Cb ; Cx ; Cy M/m + // vt300: ^[[ 24(1/3/5)~ [ Cx , Cy ] \r + // locator: CSI P e ; P b ; P r ; P c ; P p & w + function sendEvent(button, pos) { + // self.emit('mouse', { + // x: pos.x - 32, + // y: pos.x - 32, + // button: button + // }); + + if (self.vt300Mouse) { + // NOTE: Unstable. + // http://www.vt100.net/docs/vt3xx-gp/chapter15.html + button &= 3; + pos.x -= 32; + pos.y -= 32; + var data = '\x1b[24'; + if (button === 0) data += '1'; + else if (button === 1) data += '3'; + else if (button === 2) data += '5'; + else if (button === 3) return; + else data += '0'; + data += '~[' + pos.x + ',' + pos.y + ']\r'; + self.send(data); + return; + } + + if (self.decLocator) { + // NOTE: Unstable. + button &= 3; + pos.x -= 32; + pos.y -= 32; + if (button === 0) button = 2; + else if (button === 1) button = 4; + else if (button === 2) button = 6; + else if (button === 3) button = 3; + self.send('\x1b[' + + button + + ';' + + (button === 3 ? 4 : 0) + + ';' + + pos.y + + ';' + + pos.x + + ';' + + (pos.page || 0) + + '&w'); + return; + } + + if (self.urxvtMouse) { + pos.x -= 32; + pos.y -= 32; + pos.x++; + pos.y++; + self.send('\x1b[' + button + ';' + pos.x + ';' + pos.y + 'M'); + return; + } + + if (self.sgrMouse) { + pos.x -= 32; + pos.y -= 32; + self.send('\x1b[<' + + ((button & 3) === 3 ? button & ~3 : button) + + ';' + + pos.x + + ';' + + pos.y + + ((button & 3) === 3 ? 'm' : 'M')); + return; + } + + var data = []; + + encode(data, button); + encode(data, pos.x); + encode(data, pos.y); + + self.send('\x1b[M' + String.fromCharCode.apply(String, data)); + } + + function getButton(ev) { + var button + , shift + , meta + , ctrl + , mod; + + // two low bits: + // 0 = left + // 1 = middle + // 2 = right + // 3 = release + // wheel up/down: + // 1, and 2 - with 64 added + switch (ev.type) { + case 'mousedown': + button = ev.button != null + ? +ev.button + : ev.which != null + ? ev.which - 1 + : null; + + if (~navigator.userAgent.indexOf('MSIE')) { + button = button === 1 ? 0 : button === 4 ? 1 : button; + } + break; + case 'mouseup': + button = 3; + break; + case 'DOMMouseScroll': + button = ev.detail < 0 + ? 64 + : 65; + break; + case 'mousewheel': + button = ev.wheelDeltaY > 0 + ? 64 + : 65; + break; + } + + // next three bits are the modifiers: + // 4 = shift, 8 = meta, 16 = control + shift = ev.shiftKey ? 4 : 0; + meta = ev.metaKey ? 8 : 0; + ctrl = ev.ctrlKey ? 16 : 0; + mod = shift | meta | ctrl; + + // no mods + if (self.vt200Mouse) { + // ctrl only + mod &= ctrl; + } else if (!self.normalMouse) { + mod = 0; + } + + // increment to SP + button = (32 + (mod << 2)) + button; + + return button; + } + + // mouse coordinates measured in cols/rows + function getCoords(ev) { + var x, y, w, h, el; + + // ignore browsers without pageX for now + if (ev.pageX == null) return; + + x = ev.pageX; + y = ev.pageY; + el = self.element; + + // should probably check offsetParent + // but this is more portable + while (el !== document.documentElement) { + x -= el.offsetLeft; + y -= el.offsetTop; + el = el.parentNode; + } + + // convert to cols/rows + w = self.element.clientWidth; + h = self.element.clientHeight; + x = ((x / w) * self.cols) | 0; + y = ((y / h) * self.rows) | 0; + + // be sure to avoid sending + // bad positions to the program + if (x < 0) x = 0; + if (x > self.cols) x = self.cols; + if (y < 0) y = 0; + if (y > self.rows) y = self.rows; + + // xterm sends raw bytes and + // starts at 32 (SP) for each. + x += 32; + y += 32; + + return { + x: x, + y: y, + down: ev.type === 'mousedown', + up: ev.type === 'mouseup', + wheel: ev.type === wheelEvent, + move: ev.type === 'mousemove' + }; + } + + on(el, 'mousedown', function(ev) { + if (!self.mouseEvents) return; + + // send the button + sendButton(ev); + + // ensure focus + self.focus(); + + // fix for odd bug + if (self.vt200Mouse) { + sendButton({ __proto__: ev, type: 'mouseup' }); + return cancel(ev); + } + + // bind events + if (self.normalMouse) on(document, 'mousemove', sendMove); + + // x10 compatibility mode can't send button releases + if (!self.x10Mouse) { + on(document, 'mouseup', function up(ev) { + sendButton(ev); + if (self.normalMouse) off(document, 'mousemove', sendMove); + off(document, 'mouseup', up); + return cancel(ev); + }); + } + + return cancel(ev); + }); + + on(el, wheelEvent, function(ev) { + if (!self.mouseEvents) return; + if (self.x10Mouse + || self.vt300Mouse + || self.decLocator) return; + sendButton(ev); + return cancel(ev); + }); + + // allow mousewheel scrolling in + // the shell for example + on(el, wheelEvent, function(ev) { + if (self.mouseEvents) return; + if (self.applicationKeypad) return; + if (ev.type === 'DOMMouseScroll') { + self.scrollDisp(ev.detail < 0 ? -5 : 5); + } else { + self.scrollDisp(ev.wheelDeltaY > 0 ? -5 : 5); + } + return cancel(ev); + }); +}; + +/** + * Destroy Terminal + */ + +Terminal.prototype.destroy = function() { + this.readable = false; + this.writable = false; + this._events = {}; + this.handler = function() {}; + this.write = function() {}; + //this.emit('close'); +}; + +/** + * Rendering Engine + */ + +// In the screen buffer, each character +// is stored as a an array with a character +// and a 32-bit integer. +// First value: a utf-16 character. +// Second value: +// Next 9 bits: background color (0-511). +// Next 9 bits: foreground color (0-511). +// Next 14 bits: a mask for misc. flags: +// 1=bold, 2=underline, 4=inverse + +Terminal.prototype.refresh = function(start, end) { + var x + , y + , i + , line + , out + , ch + , width + , data + , attr + , fgColor + , bgColor + , flags + , row + , parent; + + if (end - start >= this.rows / 2) { + parent = this.element.parentNode; + if (parent) parent.removeChild(this.element); + } + + width = this.cols; + y = start; + + for (; y <= end; y++) { + row = y + this.ydisp; + + line = this.lines[row]; + out = ''; + + if (y === this.y + && this.cursorState + && this.ydisp === this.ybase + && !this.cursorHidden) { + x = this.x; + } else { + x = -1; + } + + attr = this.defAttr; + i = 0; + + for (; i < width; i++) { + data = line[i][0]; + ch = line[i][1]; + + if (i === x) data = -1; + + if (data !== attr) { + if (attr !== this.defAttr) { + out += ''; + } + if (data !== this.defAttr) { + if (data === -1) { + out += ''; + } else { + out += ''; + } + } + } + + switch (ch) { + case '&': + out += '&'; + break; + case '<': + out += '<'; + break; + case '>': + out += '>'; + break; + default: + if (ch <= ' ') { + out += ' '; + } else { + out += ch; + } + break; + } + + attr = data; + } + + if (attr !== this.defAttr) { + out += ''; + } + + this.children[y].innerHTML = out; + } + + if (parent) parent.appendChild(this.element); +}; + +Terminal.prototype.cursorBlink = function() { + if (Terminal.focus !== this) return; + this.cursorState ^= 1; + this.refresh(this.y, this.y); +}; + +Terminal.prototype.showCursor = function() { + if (!this.cursorState) { + this.cursorState = 1; + this.refresh(this.y, this.y); + } else { + // Temporarily disabled: + // this.refreshBlink(); + } +}; + +Terminal.prototype.startBlink = function() { + if (!Terminal.cursorBlink) return; + var self = this; + this._blinker = function() { + self.cursorBlink(); + }; + this._blink = setInterval(this._blinker, 500); +}; + +Terminal.prototype.refreshBlink = function() { + if (!Terminal.cursorBlink) return; + clearInterval(this._blink); + this._blink = setInterval(this._blinker, 500); +}; + +Terminal.prototype.scroll = function() { + var row; + + if (++this.ybase === Terminal.scrollback) { + this.ybase = this.ybase / 2 | 0; + this.lines = this.lines.slice(-(this.ybase + this.rows) + 1); + } + + this.ydisp = this.ybase; + + // last line + row = this.ybase + this.rows - 1; + + // subtract the bottom scroll region + row -= this.rows - 1 - this.scrollBottom; + + if (row === this.lines.length) { + // potential optimization: + // pushing is faster than splicing + // when they amount to the same + // behavior. + this.lines.push(this.blankLine()); + } else { + // add our new line + this.lines.splice(row, 0, this.blankLine()); + } + + if (this.scrollTop !== 0) { + if (this.ybase !== 0) { + this.ybase--; + this.ydisp = this.ybase; + } + this.lines.splice(this.ybase + this.scrollTop, 1); + } + + // this.maxRange(); + this.updateRange(this.scrollTop); + this.updateRange(this.scrollBottom); +}; + +Terminal.prototype.scrollDisp = function(disp) { + this.ydisp += disp; + + if (this.ydisp > this.ybase) { + this.ydisp = this.ybase; + } else if (this.ydisp < 0) { + this.ydisp = 0; + } + + this.refresh(0, this.rows - 1); +}; + +Terminal.prototype.write = function(data) { + var l = data.length + , i = 0 + , cs + , ch; + + this.refreshStart = this.y; + this.refreshEnd = this.y; + + if (this.ybase !== this.ydisp) { + this.ydisp = this.ybase; + this.maxRange(); + } + + // this.log(JSON.stringify(data.replace(/\x1b/g, '^['))); + + for (; i < l; i++) { + ch = data[i]; + switch (this.state) { + case normal: + switch (ch) { + // '\0' + // case '\0': + // break; + + // '\a' + case '\x07': + this.bell(); + break; + + // '\n', '\v', '\f' + case '\n': + case '\x0b': + case '\x0c': + if (this.convertEol) { + this.x = 0; + } + this.y++; + if (this.y > this.scrollBottom) { + this.y--; + this.scroll(); + } + break; + + // '\r' + case '\r': + this.x = 0; + break; + + // '\b' + case '\x08': + if (this.x > 0) { + this.x--; + } + break; + + // '\t' + case '\t': + this.x = this.nextStop(); + break; + + // shift out + case '\x0e': + this.setgLevel(1); + break; + + // shift in + case '\x0f': + this.setgLevel(0); + break; + + // '\e' + case '\x1b': + this.state = escaped; + break; + + default: + // ' ' + if (ch >= ' ') { + if (this.charset && this.charset[ch]) { + ch = this.charset[ch]; + } + if (this.x >= this.cols) { + this.x = 0; + this.y++; + if (this.y > this.scrollBottom) { + this.y--; + this.scroll(); + } + } + this.lines[this.y + this.ybase][this.x] = [this.curAttr, ch]; + this.x++; + this.updateRange(this.y); + } + break; + } + break; + case escaped: + switch (ch) { + // ESC [ Control Sequence Introducer ( CSI is 0x9b). + case '[': + this.params = []; + this.currentParam = 0; + this.state = csi; + break; + + // ESC ] Operating System Command ( OSC is 0x9d). + case ']': + this.params = []; + this.currentParam = 0; + this.state = osc; + break; + + // ESC P Device Control String ( DCS is 0x90). + case 'P': + this.params = []; + this.currentParam = 0; + this.state = dcs; + break; + + // ESC _ Application Program Command ( APC is 0x9f). + case '_': + this.state = ignore; + break; + + // ESC ^ Privacy Message ( PM is 0x9e). + case '^': + this.state = ignore; + break; + + // ESC c Full Reset (RIS). + case 'c': + this.reset(); + break; + + // ESC E Next Line ( NEL is 0x85). + // ESC D Index ( IND is 0x84). + case 'E': + this.x = 0; + ; + case 'D': + this.index(); + break; + + // ESC M Reverse Index ( RI is 0x8d). + case 'M': + this.reverseIndex(); + break; + + // ESC % Select default/utf-8 character set. + // @ = default, G = utf-8 + case '%': + //this.charset = null; + this.setgLevel(0); + this.setgCharset(0, Terminal.charsets.US); + this.state = normal; + i++; + break; + + // ESC (,),*,+,-,. Designate G0-G2 Character Set. + case '(': // <-- this seems to get all the attention + case ')': + case '*': + case '+': + case '-': + case '.': + switch (ch) { + case '(': + this.gcharset = 0; + break; + case ')': + this.gcharset = 1; + break; + case '*': + this.gcharset = 2; + break; + case '+': + this.gcharset = 3; + break; + case '-': + this.gcharset = 1; + break; + case '.': + this.gcharset = 2; + break; + } + this.state = charset; + break; + + // Designate G3 Character Set (VT300). + // A = ISO Latin-1 Supplemental. + // Not implemented. + case '/': + this.gcharset = 3; + this.state = charset; + i--; + break; + + // ESC N + // Single Shift Select of G2 Character Set + // ( SS2 is 0x8e). This affects next character only. + case 'N': + break; + // ESC O + // Single Shift Select of G3 Character Set + // ( SS3 is 0x8f). This affects next character only. + case 'O': + break; + // ESC n + // Invoke the G2 Character Set as GL (LS2). + case 'n': + this.setgLevel(2); + break; + // ESC o + // Invoke the G3 Character Set as GL (LS3). + case 'o': + this.setgLevel(3); + break; + // ESC | + // Invoke the G3 Character Set as GR (LS3R). + case '|': + this.setgLevel(3); + break; + // ESC } + // Invoke the G2 Character Set as GR (LS2R). + case '}': + this.setgLevel(2); + break; + // ESC ~ + // Invoke the G1 Character Set as GR (LS1R). + case '~': + this.setgLevel(1); + break; + + // ESC 7 Save Cursor (DECSC). + case '7': + this.saveCursor(); + this.state = normal; + break; + + // ESC 8 Restore Cursor (DECRC). + case '8': + this.restoreCursor(); + this.state = normal; + break; + + // ESC # 3 DEC line height/width + case '#': + this.state = normal; + i++; + break; + + // ESC H Tab Set (HTS is 0x88). + case 'H': + this.tabSet(); + break; + + // ESC = Application Keypad (DECPAM). + case '=': + this.log('Serial port requested application keypad.'); + this.applicationKeypad = true; + this.state = normal; + break; + + // ESC > Normal Keypad (DECPNM). + case '>': + this.log('Switching back to normal keypad.'); + this.applicationKeypad = false; + this.state = normal; + break; + + default: + this.state = normal; + this.error('Unknown ESC control: %s.', ch); + break; + } + break; + + case charset: + switch (ch) { + case '0': // DEC Special Character and Line Drawing Set. + cs = Terminal.charsets.SCLD; + break; + case 'A': // UK + cs = Terminal.charsets.UK; + break; + case 'B': // United States (USASCII). + cs = Terminal.charsets.US; + break; + case '4': // Dutch + cs = Terminal.charsets.Dutch; + break; + case 'C': // Finnish + case '5': + cs = Terminal.charsets.Finnish; + break; + case 'R': // French + cs = Terminal.charsets.French; + break; + case 'Q': // FrenchCanadian + cs = Terminal.charsets.FrenchCanadian; + break; + case 'K': // German + cs = Terminal.charsets.German; + break; + case 'Y': // Italian + cs = Terminal.charsets.Italian; + break; + case 'E': // NorwegianDanish + case '6': + cs = Terminal.charsets.NorwegianDanish; + break; + case 'Z': // Spanish + cs = Terminal.charsets.Spanish; + break; + case 'H': // Swedish + case '7': + cs = Terminal.charsets.Swedish; + break; + case '=': // Swiss + cs = Terminal.charsets.Swiss; + break; + case '/': // ISOLatin (actually /A) + cs = Terminal.charsets.ISOLatin; + i++; + break; + default: // Default + cs = Terminal.charsets.US; + break; + } + this.setgCharset(this.gcharset, cs); + this.gcharset = null; + this.state = normal; + break; + + case osc: + // OSC Ps ; Pt ST + // OSC Ps ; Pt BEL + // Set Text Parameters. + if (ch === '\x1b' || ch === '\x07') { + if (ch === '\x1b') i++; + + this.params.push(this.currentParam); + + switch (this.params[0]) { + case 0: + case 1: + case 2: + if (this.params[1]) { + this.title = this.params[1]; + this.handleTitle(this.title); + } + break; + case 3: + // set X property + break; + case 4: + case 5: + // change dynamic colors + break; + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + // change dynamic ui colors + break; + case 46: + // change log file + break; + case 50: + // dynamic font + break; + case 51: + // emacs shell + break; + case 52: + // manipulate selection data + break; + case 104: + case 105: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + // reset colors + break; + } + + this.params = []; + this.currentParam = 0; + this.state = normal; + } else { + if (!this.params.length) { + if (ch >= '0' && ch <= '9') { + this.currentParam = + this.currentParam * 10 + ch.charCodeAt(0) - 48; + } else if (ch === ';') { + this.params.push(this.currentParam); + this.currentParam = ''; + } + } else { + this.currentParam += ch; + } + } + break; + + case csi: + // '?', '>', '!' + if (ch === '?' || ch === '>' || ch === '!') { + this.prefix = ch; + break; + } + + // 0 - 9 + if (ch >= '0' && ch <= '9') { + this.currentParam = this.currentParam * 10 + ch.charCodeAt(0) - 48; + break; + } + + // '$', '"', ' ', '\'' + if (ch === '$' || ch === '"' || ch === ' ' || ch === '\'') { + this.postfix = ch; + break; + } + + this.params.push(this.currentParam); + this.currentParam = 0; + + // ';' + if (ch === ';') break; + + this.state = normal; + + switch (ch) { + // CSI Ps A + // Cursor Up Ps Times (default = 1) (CUU). + case 'A': + this.cursorUp(this.params); + break; + + // CSI Ps B + // Cursor Down Ps Times (default = 1) (CUD). + case 'B': + this.cursorDown(this.params); + break; + + // CSI Ps C + // Cursor Forward Ps Times (default = 1) (CUF). + case 'C': + this.cursorForward(this.params); + break; + + // CSI Ps D + // Cursor Backward Ps Times (default = 1) (CUB). + case 'D': + this.cursorBackward(this.params); + break; + + // CSI Ps ; Ps H + // Cursor Position [row;column] (default = [1,1]) (CUP). + case 'H': + this.cursorPos(this.params); + break; + + // CSI Ps J Erase in Display (ED). + case 'J': + this.eraseInDisplay(this.params); + break; + + // CSI Ps K Erase in Line (EL). + case 'K': + this.eraseInLine(this.params); + break; + + // CSI Pm m Character Attributes (SGR). + case 'm': + this.charAttributes(this.params); + break; + + // CSI Ps n Device Status Report (DSR). + case 'n': + this.deviceStatus(this.params); + break; + + /** + * Additions + */ + + // CSI Ps @ + // Insert Ps (Blank) Character(s) (default = 1) (ICH). + case '@': + this.insertChars(this.params); + break; + + // CSI Ps E + // Cursor Next Line Ps Times (default = 1) (CNL). + case 'E': + this.cursorNextLine(this.params); + break; + + // CSI Ps F + // Cursor Preceding Line Ps Times (default = 1) (CNL). + case 'F': + this.cursorPrecedingLine(this.params); + break; + + // CSI Ps G + // Cursor Character Absolute [column] (default = [row,1]) (CHA). + case 'G': + this.cursorCharAbsolute(this.params); + break; + + // CSI Ps L + // Insert Ps Line(s) (default = 1) (IL). + case 'L': + this.insertLines(this.params); + break; + + // CSI Ps M + // Delete Ps Line(s) (default = 1) (DL). + case 'M': + this.deleteLines(this.params); + break; + + // CSI Ps P + // Delete Ps Character(s) (default = 1) (DCH). + case 'P': + this.deleteChars(this.params); + break; + + // CSI Ps X + // Erase Ps Character(s) (default = 1) (ECH). + case 'X': + this.eraseChars(this.params); + break; + + // CSI Pm ` Character Position Absolute + // [column] (default = [row,1]) (HPA). + case '`': + this.charPosAbsolute(this.params); + break; + + // 141 61 a * HPR - + // Horizontal Position Relative + case 'a': + this.HPositionRelative(this.params); + break; + + // CSI P s c + // Send Device Attributes (Primary DA). + // CSI > P s c + // Send Device Attributes (Secondary DA) + case 'c': + this.sendDeviceAttributes(this.params); + break; + + // CSI Pm d + // Line Position Absolute [row] (default = [1,column]) (VPA). + case 'd': + this.linePosAbsolute(this.params); + break; + + // 145 65 e * VPR - Vertical Position Relative + case 'e': + this.VPositionRelative(this.params); + break; + + // CSI Ps ; Ps f + // Horizontal and Vertical Position [row;column] (default = + // [1,1]) (HVP). + case 'f': + this.HVPosition(this.params); + break; + + // CSI Pm h Set Mode (SM). + // CSI ? Pm h - mouse escape codes, cursor escape codes + case 'h': + this.setMode(this.params); + break; + + // CSI Pm l Reset Mode (RM). + // CSI ? Pm l + case 'l': + this.resetMode(this.params); + break; + + // CSI Ps ; Ps r + // Set Scrolling Region [top;bottom] (default = full size of win- + // dow) (DECSTBM). + // CSI ? Pm r + case 'r': + this.setScrollRegion(this.params); + break; + + // CSI s + // Save cursor (ANSI.SYS). + case 's': + this.saveCursor(this.params); + break; + + // CSI u + // Restore cursor (ANSI.SYS). + case 'u': + this.restoreCursor(this.params); + break; + + /** + * Lesser Used + */ + + // CSI Ps I + // Cursor Forward Tabulation Ps tab stops (default = 1) (CHT). + case 'I': + this.cursorForwardTab(this.params); + break; + + // CSI Ps S Scroll up Ps lines (default = 1) (SU). + case 'S': + this.scrollUp(this.params); + break; + + // CSI Ps T Scroll down Ps lines (default = 1) (SD). + // CSI Ps ; Ps ; Ps ; Ps ; Ps T + // CSI > Ps; Ps T + case 'T': + // if (this.prefix === '>') { + // this.resetTitleModes(this.params); + // break; + // } + // if (this.params.length > 2) { + // this.initMouseTracking(this.params); + // break; + // } + if (this.params.length < 2 && !this.prefix) { + this.scrollDown(this.params); + } + break; + + // CSI Ps Z + // Cursor Backward Tabulation Ps tab stops (default = 1) (CBT). + case 'Z': + this.cursorBackwardTab(this.params); + break; + + // CSI Ps b Repeat the preceding graphic character Ps times (REP). + case 'b': + this.repeatPrecedingCharacter(this.params); + break; + + // CSI Ps g Tab Clear (TBC). + case 'g': + this.tabClear(this.params); + break; + + // CSI Pm i Media Copy (MC). + // CSI ? Pm i + // case 'i': + // this.mediaCopy(this.params); + // break; + + // CSI Pm m Character Attributes (SGR). + // CSI > Ps; Ps m + // case 'm': // duplicate + // if (this.prefix === '>') { + // this.setResources(this.params); + // } else { + // this.charAttributes(this.params); + // } + // break; + + // CSI Ps n Device Status Report (DSR). + // CSI > Ps n + // case 'n': // duplicate + // if (this.prefix === '>') { + // this.disableModifiers(this.params); + // } else { + // this.deviceStatus(this.params); + // } + // break; + + // CSI > Ps p Set pointer mode. + // CSI ! p Soft terminal reset (DECSTR). + // CSI Ps$ p + // Request ANSI mode (DECRQM). + // CSI ? Ps$ p + // Request DEC private mode (DECRQM). + // CSI Ps ; Ps " p + case 'p': + switch (this.prefix) { + // case '>': + // this.setPointerMode(this.params); + // break; + case '!': + this.softReset(this.params); + break; + // case '?': + // if (this.postfix === '$') { + // this.requestPrivateMode(this.params); + // } + // break; + // default: + // if (this.postfix === '"') { + // this.setConformanceLevel(this.params); + // } else if (this.postfix === '$') { + // this.requestAnsiMode(this.params); + // } + // break; + } + break; + + // CSI Ps q Load LEDs (DECLL). + // CSI Ps SP q + // CSI Ps " q + // case 'q': + // if (this.postfix === ' ') { + // this.setCursorStyle(this.params); + // break; + // } + // if (this.postfix === '"') { + // this.setCharProtectionAttr(this.params); + // break; + // } + // this.loadLEDs(this.params); + // break; + + // CSI Ps ; Ps r + // Set Scrolling Region [top;bottom] (default = full size of win- + // dow) (DECSTBM). + // CSI ? Pm r + // CSI Pt; Pl; Pb; Pr; Ps$ r + // case 'r': // duplicate + // if (this.prefix === '?') { + // this.restorePrivateValues(this.params); + // } else if (this.postfix === '$') { + // this.setAttrInRectangle(this.params); + // } else { + // this.setScrollRegion(this.params); + // } + // break; + + // CSI s Save cursor (ANSI.SYS). + // CSI ? Pm s + // case 's': // duplicate + // if (this.prefix === '?') { + // this.savePrivateValues(this.params); + // } else { + // this.saveCursor(this.params); + // } + // break; + + // CSI Ps ; Ps ; Ps t + // CSI Pt; Pl; Pb; Pr; Ps$ t + // CSI > Ps; Ps t + // CSI Ps SP t + // case 't': + // if (this.postfix === '$') { + // this.reverseAttrInRectangle(this.params); + // } else if (this.postfix === ' ') { + // this.setWarningBellVolume(this.params); + // } else { + // if (this.prefix === '>') { + // this.setTitleModeFeature(this.params); + // } else { + // this.manipulateWindow(this.params); + // } + // } + // break; + + // CSI u Restore cursor (ANSI.SYS). + // CSI Ps SP u + // case 'u': // duplicate + // if (this.postfix === ' ') { + // this.setMarginBellVolume(this.params); + // } else { + // this.restoreCursor(this.params); + // } + // break; + + // CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v + // case 'v': + // if (this.postfix === '$') { + // this.copyRectagle(this.params); + // } + // break; + + // CSI Pt ; Pl ; Pb ; Pr ' w + // case 'w': + // if (this.postfix === '\'') { + // this.enableFilterRectangle(this.params); + // } + // break; + + // CSI Ps x Request Terminal Parameters (DECREQTPARM). + // CSI Ps x Select Attribute Change Extent (DECSACE). + // CSI Pc; Pt; Pl; Pb; Pr$ x + // case 'x': + // if (this.postfix === '$') { + // this.fillRectangle(this.params); + // } else { + // this.requestParameters(this.params); + // //this.__(this.params); + // } + // break; + + // CSI Ps ; Pu ' z + // CSI Pt; Pl; Pb; Pr$ z + // case 'z': + // if (this.postfix === '\'') { + // this.enableLocatorReporting(this.params); + // } else if (this.postfix === '$') { + // this.eraseRectangle(this.params); + // } + // break; + + // CSI Pm ' { + // CSI Pt; Pl; Pb; Pr$ { + // case '{': + // if (this.postfix === '\'') { + // this.setLocatorEvents(this.params); + // } else if (this.postfix === '$') { + // this.selectiveEraseRectangle(this.params); + // } + // break; + + // CSI Ps ' | + // case '|': + // if (this.postfix === '\'') { + // this.requestLocatorPosition(this.params); + // } + // break; + + // CSI P m SP } + // Insert P s Column(s) (default = 1) (DECIC), VT420 and up. + // case '}': + // if (this.postfix === ' ') { + // this.insertColumns(this.params); + // } + // break; + + // CSI P m SP ~ + // Delete P s Column(s) (default = 1) (DECDC), VT420 and up + // case '~': + // if (this.postfix === ' ') { + // this.deleteColumns(this.params); + // } + // break; + + default: + this.error('Unknown CSI code: %s.', ch); + break; + } + + this.prefix = ''; + this.postfix = ''; + break; + + case dcs: + if (ch === '\x1b' || ch === '\x07') { + if (ch === '\x1b') i++; + + switch (this.prefix) { + // User-Defined Keys (DECUDK). + case '': + break; + + // Request Status String (DECRQSS). + // test: echo -e '\eP$q"p\e\\' + case '$q': + var pt = this.currentParam + , valid = false; + + switch (pt) { + // DECSCA + case '"q': + pt = '0"q'; + break; + + // DECSCL + case '"p': + pt = '61"p'; + break; + + // DECSTBM + case 'r': + pt = '' + + (this.scrollTop + 1) + + ';' + + (this.scrollBottom + 1) + + 'r'; + break; + + // SGR + case 'm': + pt = '0m'; + break; + + default: + this.error('Unknown DCS Pt: %s.', pt); + pt = ''; + break; + } + + this.send('\x1bP' + +valid + '$r' + pt + '\x1b\\'); + break; + + // Set Termcap/Terminfo Data (xterm, experimental). + case '+p': + break; + + // Request Termcap/Terminfo String (xterm, experimental) + // Regular xterm does not even respond to this sequence. + // This can cause a small glitch in vim. + // test: echo -ne '\eP+q6b64\e\\' + case '+q': + var pt = this.currentParam + , valid = false; + + this.send('\x1bP' + +valid + '+r' + pt + '\x1b\\'); + break; + + default: + this.error('Unknown DCS prefix: %s.', this.prefix); + break; + } + + this.currentParam = 0; + this.prefix = ''; + this.state = normal; + } else if (!this.currentParam) { + if (!this.prefix && ch !== '$' && ch !== '+') { + this.currentParam = ch; + } else if (this.prefix.length === 2) { + this.currentParam = ch; + } else { + this.prefix += ch; + } + } else { + this.currentParam += ch; + } + break; + + case ignore: + // For PM and APC. + if (ch === '\x1b' || ch === '\x07') { + if (ch === '\x1b') i++; + this.state = normal; + } + break; + } + } + + this.updateRange(this.y); + this.refresh(this.refreshStart, this.refreshEnd); +}; + +Terminal.prototype.writeln = function(data) { + this.write(data + '\r\n'); +}; + +Terminal.prototype.keyDown = function(ev) { + var key; + + switch (ev.keyCode) { + // backspace + case 8: + if (ev.shiftKey) { + key = '\x08'; // ^H + break; + } + key = '\x7f'; // ^? + break; + // tab + case 9: + if (ev.shiftKey) { + key = '\x1b[Z'; + break; + } + key = '\t'; + break; + // return/enter + case 13: + key = '\r'; + break; + // escape + case 27: + key = '\x1b'; + break; + // left-arrow + case 37: + if (this.applicationKeypad) { + key = '\x1bOD'; // SS3 as ^[O for 7-bit + //key = '\x8fD'; // SS3 as 0x8f for 8-bit + break; + } + key = '\x1b[D'; + break; + // right-arrow + case 39: + if (this.applicationKeypad) { + key = '\x1bOC'; + break; + } + key = '\x1b[C'; + break; + // up-arrow + case 38: + if (this.applicationKeypad) { + key = '\x1bOA'; + break; + } + if (ev.ctrlKey) { + this.scrollDisp(-1); + return cancel(ev); + } else { + key = '\x1b[A'; + } + break; + // down-arrow + case 40: + if (this.applicationKeypad) { + key = '\x1bOB'; + break; + } + if (ev.ctrlKey) { + this.scrollDisp(1); + return cancel(ev); + } else { + key = '\x1b[B'; + } + break; + // delete + case 46: + key = '\x1b[3~'; + break; + // insert + case 45: + key = '\x1b[2~'; + break; + // home + case 36: + if (this.applicationKeypad) { + key = '\x1bOH'; + break; + } + key = '\x1bOH'; + break; + // end + case 35: + if (this.applicationKeypad) { + key = '\x1bOF'; + break; + } + key = '\x1bOF'; + break; + // page up + case 33: + if (ev.shiftKey) { + this.scrollDisp(-(this.rows - 1)); + return cancel(ev); + } else { + key = '\x1b[5~'; + } + break; + // page down + case 34: + if (ev.shiftKey) { + this.scrollDisp(this.rows - 1); + return cancel(ev); + } else { + key = '\x1b[6~'; + } + break; + // F1 + case 112: + key = '\x1bOP'; + break; + // F2 + case 113: + key = '\x1bOQ'; + break; + // F3 + case 114: + key = '\x1bOR'; + break; + // F4 + case 115: + key = '\x1bOS'; + break; + // F5 + case 116: + key = '\x1b[15~'; + break; + // F6 + case 117: + key = '\x1b[17~'; + break; + // F7 + case 118: + key = '\x1b[18~'; + break; + // F8 + case 119: + key = '\x1b[19~'; + break; + // F9 + case 120: + key = '\x1b[20~'; + break; + // F10 + case 121: + key = '\x1b[21~'; + break; + // F11 + case 122: + key = '\x1b[23~'; + break; + // F12 + case 123: + key = '\x1b[24~'; + break; + default: + // a-z and space + if (ev.ctrlKey) { + if (ev.keyCode >= 65 && ev.keyCode <= 90) { + key = String.fromCharCode(ev.keyCode - 64); + } else if (ev.keyCode === 32) { + // NUL + key = String.fromCharCode(0); + } else if (ev.keyCode >= 51 && ev.keyCode <= 55) { + // escape, file sep, group sep, record sep, unit sep + key = String.fromCharCode(ev.keyCode - 51 + 27); + } else if (ev.keyCode === 56) { + // delete + key = String.fromCharCode(127); + } else if (ev.keyCode === 219) { + // ^[ - escape + key = String.fromCharCode(27); + } else if (ev.keyCode === 221) { + // ^] - group sep + key = String.fromCharCode(29); + } + } else if ((!isMac && ev.altKey) || (isMac && ev.metaKey)) { + if (ev.keyCode >= 65 && ev.keyCode <= 90) { + key = '\x1b' + String.fromCharCode(ev.keyCode + 32); + } else if (ev.keyCode === 192) { + key = '\x1b`'; + } else if (ev.keyCode >= 48 && ev.keyCode <= 57) { + key = '\x1b' + (ev.keyCode - 48); + } + } + break; + } + + this.emit('keydown', ev); + + if (key) { + this.emit('key', key, ev); + + this.showCursor(); + this.handler(key); + + return cancel(ev); + } + + return true; +}; + +Terminal.prototype.setgLevel = function(g) { + this.glevel = g; + this.charset = this.charsets[g]; +}; + +Terminal.prototype.setgCharset = function(g, charset) { + this.charsets[g] = charset; + if (this.glevel === g) { + this.charset = charset; + } +}; + +Terminal.prototype.keyPress = function(ev) { + var key; + + cancel(ev); + + if (ev.charCode) { + key = ev.charCode; + } else if (ev.which == null) { + key = ev.keyCode; + } else if (ev.which !== 0 && ev.charCode !== 0) { + key = ev.which; + } else { + return false; + } + + if (!key || ev.ctrlKey || ev.altKey || ev.metaKey) return false; + + key = String.fromCharCode(key); + + this.emit('keypress', key, ev); + this.emit('key', key, ev); + + this.showCursor(); + this.handler(key); + + return false; +}; + +Terminal.prototype.send = function(data) { + var self = this; + + if (!this.queue) { + setTimeout(function() { + self.handler(self.queue); + self.queue = ''; + }, 1); + } + + this.queue += data; +}; + +Terminal.prototype.bell = function() { + if (!Terminal.visualBell) return; + var self = this; + this.element.style.borderColor = 'white'; + setTimeout(function() { + self.element.style.borderColor = ''; + }, 10); + if (Terminal.popOnBell) this.focus(); +}; + +Terminal.prototype.log = function() { + if (!Terminal.debug) return; + if (!window.console || !window.console.log) return; + var args = Array.prototype.slice.call(arguments); + window.console.log.apply(window.console, args); +}; + +Terminal.prototype.error = function() { + if (!Terminal.debug) return; + if (!window.console || !window.console.error) return; + var args = Array.prototype.slice.call(arguments); + window.console.error.apply(window.console, args); +}; + +Terminal.prototype.resize = function(x, y) { + var line + , el + , i + , j + , ch; + + if (x < 1) x = 1; + if (y < 1) y = 1; + + // resize cols + j = this.cols; + if (j < x) { + ch = [this.defAttr, ' ']; + i = this.lines.length; + while (i--) { + while (this.lines[i].length < x) { + this.lines[i].push(ch); + } + } + } else if (j > x) { + i = this.lines.length; + while (i--) { + while (this.lines[i].length > x) { + this.lines[i].pop(); + } + } + } + this.setupStops(j); + this.cols = x; + + // resize rows + j = this.rows; + if (j < y) { + el = this.element; + while (j++ < y) { + if (this.lines.length < y + this.ybase) { + this.lines.push(this.blankLine()); + } + if (this.children.length < y) { + line = document.createElement('div'); + el.appendChild(line); + this.children.push(line); + } + } + } else if (j > y) { + while (j-- > y) { + if (this.lines.length > y + this.ybase) { + this.lines.pop(); + } + if (this.children.length > y) { + el = this.children.pop(); + if (!el) continue; + el.parentNode.removeChild(el); + } + } + } + this.rows = y; + + // make sure the cursor stays on screen + if (this.y >= y) this.y = y - 1; + if (this.x >= x) this.x = x - 1; + + this.scrollTop = 0; + this.scrollBottom = y - 1; + + this.refresh(0, this.rows - 1); + + // it's a real nightmare trying + // to resize the original + // screen buffer. just set it + // to null for now. + this.normal = null; +}; + +Terminal.prototype.updateRange = function(y) { + if (y < this.refreshStart) this.refreshStart = y; + if (y > this.refreshEnd) this.refreshEnd = y; +}; + +Terminal.prototype.maxRange = function() { + this.refreshStart = 0; + this.refreshEnd = this.rows - 1; +}; + +Terminal.prototype.setupStops = function(i) { + if (i != null) { + if (!this.tabs[i]) { + i = this.prevStop(i); + } + } else { + this.tabs = {}; + i = 0; + } + + for (; i < this.cols; i += 8) { + this.tabs[i] = true; + } +}; + +Terminal.prototype.prevStop = function(x) { + if (x == null) x = this.x; + while (!this.tabs[--x] && x > 0); + return x >= this.cols + ? this.cols - 1 + : x < 0 ? 0 : x; +}; + +Terminal.prototype.nextStop = function(x) { + if (x == null) x = this.x; + while (!this.tabs[++x] && x < this.cols); + return x >= this.cols + ? this.cols - 1 + : x < 0 ? 0 : x; +}; + +Terminal.prototype.eraseRight = function(x, y) { + var line = this.lines[this.ybase + y] + , ch = [this.curAttr, ' ']; // xterm + + for (; x < this.cols; x++) { + line[x] = ch; + } + + this.updateRange(y); +}; + +Terminal.prototype.eraseLeft = function(x, y) { + var line = this.lines[this.ybase + y] + , ch = [this.curAttr, ' ']; // xterm + + x++; + while (x--) line[x] = ch; + + this.updateRange(y); +}; + +Terminal.prototype.eraseLine = function(y) { + this.eraseRight(0, y); +}; + +Terminal.prototype.blankLine = function(cur) { + var attr = cur + ? this.curAttr + : this.defAttr; + + var ch = [attr, ' '] + , line = [] + , i = 0; + + for (; i < this.cols; i++) { + line[i] = ch; + } + + return line; +}; + +Terminal.prototype.ch = function(cur) { + return cur + ? [this.curAttr, ' '] + : [this.defAttr, ' ']; +}; + +Terminal.prototype.is = function(term) { + var name = this.termName || Terminal.termName; + return (name + '').indexOf(term) === 0; +}; + +Terminal.prototype.handler = function(data) { + this.emit('data', data); +}; + +Terminal.prototype.handleTitle = function(title) { + this.emit('title', title); +}; + +/** + * ESC + */ + +// ESC D Index (IND is 0x84). +Terminal.prototype.index = function() { + this.y++; + if (this.y > this.scrollBottom) { + this.y--; + this.scroll(); + } + this.state = normal; +}; + +// ESC M Reverse Index (RI is 0x8d). +Terminal.prototype.reverseIndex = function() { + var j; + this.y--; + if (this.y < this.scrollTop) { + this.y++; + // possibly move the code below to term.reverseScroll(); + // test: echo -ne '\e[1;1H\e[44m\eM\e[0m' + // blankLine(true) is xterm/linux behavior + this.lines.splice(this.y + this.ybase, 0, this.blankLine(true)); + j = this.rows - 1 - this.scrollBottom; + this.lines.splice(this.rows - 1 + this.ybase - j + 1, 1); + // this.maxRange(); + this.updateRange(this.scrollTop); + this.updateRange(this.scrollBottom); + } + this.state = normal; +}; + +// ESC c Full Reset (RIS). +Terminal.prototype.reset = function() { + //Terminal.call(this, this.cols, this.rows); + Terminal.call(this, this.cols, this.rows, this.handler); + this.refresh(0, this.rows - 1); +}; + +// ESC H Tab Set (HTS is 0x88). +Terminal.prototype.tabSet = function() { + this.tabs[this.x] = true; + this.state = normal; +}; + +/** + * CSI + */ + +// CSI Ps A +// Cursor Up Ps Times (default = 1) (CUU). +Terminal.prototype.cursorUp = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.y -= param; + if (this.y < 0) this.y = 0; +}; + +// CSI Ps B +// Cursor Down Ps Times (default = 1) (CUD). +Terminal.prototype.cursorDown = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.y += param; + if (this.y >= this.rows) { + this.y = this.rows - 1; + } +}; + +// CSI Ps C +// Cursor Forward Ps Times (default = 1) (CUF). +Terminal.prototype.cursorForward = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.x += param; + if (this.x >= this.cols) { + this.x = this.cols - 1; + } +}; + +// CSI Ps D +// Cursor Backward Ps Times (default = 1) (CUB). +Terminal.prototype.cursorBackward = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.x -= param; + if (this.x < 0) this.x = 0; +}; + +// CSI Ps ; Ps H +// Cursor Position [row;column] (default = [1,1]) (CUP). +Terminal.prototype.cursorPos = function(params) { + var row, col; + + row = params[0] - 1; + + if (params.length >= 2) { + col = params[1] - 1; + } else { + col = 0; + } + + if (row < 0) { + row = 0; + } else if (row >= this.rows) { + row = this.rows - 1; + } + + if (col < 0) { + col = 0; + } else if (col >= this.cols) { + col = this.cols - 1; + } + + this.x = col; + this.y = row; +}; + +// CSI Ps J Erase in Display (ED). +// Ps = 0 -> Erase Below (default). +// Ps = 1 -> Erase Above. +// Ps = 2 -> Erase All. +// Ps = 3 -> Erase Saved Lines (xterm). +// CSI ? Ps J +// Erase in Display (DECSED). +// Ps = 0 -> Selective Erase Below (default). +// Ps = 1 -> Selective Erase Above. +// Ps = 2 -> Selective Erase All. +Terminal.prototype.eraseInDisplay = function(params) { + var j; + switch (params[0]) { + case 0: + this.eraseRight(this.x, this.y); + j = this.y + 1; + for (; j < this.rows; j++) { + this.eraseLine(j); + } + break; + case 1: + this.eraseLeft(this.x, this.y); + j = this.y; + while (j--) { + this.eraseLine(j); + } + break; + case 2: + j = this.rows; + while (j--) this.eraseLine(j); + break; + case 3: + ; // no saved lines + break; + } +}; + +// CSI Ps K Erase in Line (EL). +// Ps = 0 -> Erase to Right (default). +// Ps = 1 -> Erase to Left. +// Ps = 2 -> Erase All. +// CSI ? Ps K +// Erase in Line (DECSEL). +// Ps = 0 -> Selective Erase to Right (default). +// Ps = 1 -> Selective Erase to Left. +// Ps = 2 -> Selective Erase All. +Terminal.prototype.eraseInLine = function(params) { + switch (params[0]) { + case 0: + this.eraseRight(this.x, this.y); + break; + case 1: + this.eraseLeft(this.x, this.y); + break; + case 2: + this.eraseLine(this.y); + break; + } +}; + +// CSI Pm m Character Attributes (SGR). +// Ps = 0 -> Normal (default). +// Ps = 1 -> Bold. +// Ps = 4 -> Underlined. +// Ps = 5 -> Blink (appears as Bold). +// Ps = 7 -> Inverse. +// Ps = 8 -> Invisible, i.e., hidden (VT300). +// Ps = 2 2 -> Normal (neither bold nor faint). +// Ps = 2 4 -> Not underlined. +// Ps = 2 5 -> Steady (not blinking). +// Ps = 2 7 -> Positive (not inverse). +// Ps = 2 8 -> Visible, i.e., not hidden (VT300). +// Ps = 3 0 -> Set foreground color to Black. +// Ps = 3 1 -> Set foreground color to Red. +// Ps = 3 2 -> Set foreground color to Green. +// Ps = 3 3 -> Set foreground color to Yellow. +// Ps = 3 4 -> Set foreground color to Blue. +// Ps = 3 5 -> Set foreground color to Magenta. +// Ps = 3 6 -> Set foreground color to Cyan. +// Ps = 3 7 -> Set foreground color to White. +// Ps = 3 9 -> Set foreground color to default (original). +// Ps = 4 0 -> Set background color to Black. +// Ps = 4 1 -> Set background color to Red. +// Ps = 4 2 -> Set background color to Green. +// Ps = 4 3 -> Set background color to Yellow. +// Ps = 4 4 -> Set background color to Blue. +// Ps = 4 5 -> Set background color to Magenta. +// Ps = 4 6 -> Set background color to Cyan. +// Ps = 4 7 -> Set background color to White. +// Ps = 4 9 -> Set background color to default (original). + +// If 16-color support is compiled, the following apply. Assume +// that xterm's resources are set so that the ISO color codes are +// the first 8 of a set of 16. Then the aixterm colors are the +// bright versions of the ISO colors: +// Ps = 9 0 -> Set foreground color to Black. +// Ps = 9 1 -> Set foreground color to Red. +// Ps = 9 2 -> Set foreground color to Green. +// Ps = 9 3 -> Set foreground color to Yellow. +// Ps = 9 4 -> Set foreground color to Blue. +// Ps = 9 5 -> Set foreground color to Magenta. +// Ps = 9 6 -> Set foreground color to Cyan. +// Ps = 9 7 -> Set foreground color to White. +// Ps = 1 0 0 -> Set background color to Black. +// Ps = 1 0 1 -> Set background color to Red. +// Ps = 1 0 2 -> Set background color to Green. +// Ps = 1 0 3 -> Set background color to Yellow. +// Ps = 1 0 4 -> Set background color to Blue. +// Ps = 1 0 5 -> Set background color to Magenta. +// Ps = 1 0 6 -> Set background color to Cyan. +// Ps = 1 0 7 -> Set background color to White. + +// If xterm is compiled with the 16-color support disabled, it +// supports the following, from rxvt: +// Ps = 1 0 0 -> Set foreground and background color to +// default. + +// If 88- or 256-color support is compiled, the following apply. +// Ps = 3 8 ; 5 ; Ps -> Set foreground color to the second +// Ps. +// Ps = 4 8 ; 5 ; Ps -> Set background color to the second +// Ps. +Terminal.prototype.charAttributes = function(params) { + var l = params.length + , i = 0 + , bg + , fg + , p; + + for (; i < l; i++) { + p = params[i]; + if (p >= 30 && p <= 37) { + // fg color 8 + this.curAttr = (this.curAttr & ~(0x1ff << 9)) | ((p - 30) << 9); + } else if (p >= 40 && p <= 47) { + // bg color 8 + this.curAttr = (this.curAttr & ~0x1ff) | (p - 40); + } else if (p >= 90 && p <= 97) { + // fg color 16 + p += 8; + this.curAttr = (this.curAttr & ~(0x1ff << 9)) | ((p - 90) << 9); + } else if (p >= 100 && p <= 107) { + // bg color 16 + p += 8; + this.curAttr = (this.curAttr & ~0x1ff) | (p - 100); + } else if (p === 0) { + // default + this.curAttr = this.defAttr; + } else if (p === 1) { + // bold text + this.curAttr = this.curAttr | (1 << 18); + } else if (p === 4) { + // underlined text + this.curAttr = this.curAttr | (2 << 18); + } else if (p === 7 || p === 27) { + // inverse and positive + // test with: echo -e '\e[31m\e[42mhello\e[7mworld\e[27mhi\e[m' + if (p === 7) { + if ((this.curAttr >> 18) & 4) continue; + this.curAttr = this.curAttr | (4 << 18); + } else if (p === 27) { + if (~(this.curAttr >> 18) & 4) continue; + this.curAttr = this.curAttr & ~(4 << 18); + } + + bg = this.curAttr & 0x1ff; + fg = (this.curAttr >> 9) & 0x1ff; + + this.curAttr = (this.curAttr & ~0x3ffff) | ((bg << 9) | fg); + } else if (p === 22) { + // not bold + this.curAttr = this.curAttr & ~(1 << 18); + } else if (p === 24) { + // not underlined + this.curAttr = this.curAttr & ~(2 << 18); + } else if (p === 39) { + // reset fg + this.curAttr = this.curAttr & ~(0x1ff << 9); + this.curAttr = this.curAttr | (((this.defAttr >> 9) & 0x1ff) << 9); + } else if (p === 49) { + // reset bg + this.curAttr = this.curAttr & ~0x1ff; + this.curAttr = this.curAttr | (this.defAttr & 0x1ff); + } else if (p === 38) { + // fg color 256 + if (params[i+1] !== 5) continue; + i += 2; + p = params[i] & 0xff; + // convert 88 colors to 256 + // if (this.is('rxvt-unicode') && p < 88) p = p * 2.9090 | 0; + this.curAttr = (this.curAttr & ~(0x1ff << 9)) | (p << 9); + } else if (p === 48) { + // bg color 256 + if (params[i+1] !== 5) continue; + i += 2; + p = params[i] & 0xff; + // convert 88 colors to 256 + // if (this.is('rxvt-unicode') && p < 88) p = p * 2.9090 | 0; + this.curAttr = (this.curAttr & ~0x1ff) | p; + } + } +}; + +// CSI Ps n Device Status Report (DSR). +// Ps = 5 -> Status Report. Result (``OK'') is +// CSI 0 n +// Ps = 6 -> Report Cursor Position (CPR) [row;column]. +// Result is +// CSI r ; c R +// CSI ? Ps n +// Device Status Report (DSR, DEC-specific). +// Ps = 6 -> Report Cursor Position (CPR) [row;column] as CSI +// ? r ; c R (assumes page is zero). +// Ps = 1 5 -> Report Printer status as CSI ? 1 0 n (ready). +// or CSI ? 1 1 n (not ready). +// Ps = 2 5 -> Report UDK status as CSI ? 2 0 n (unlocked) +// or CSI ? 2 1 n (locked). +// Ps = 2 6 -> Report Keyboard status as +// CSI ? 2 7 ; 1 ; 0 ; 0 n (North American). +// The last two parameters apply to VT400 & up, and denote key- +// board ready and LK01 respectively. +// Ps = 5 3 -> Report Locator status as +// CSI ? 5 3 n Locator available, if compiled-in, or +// CSI ? 5 0 n No Locator, if not. +Terminal.prototype.deviceStatus = function(params) { + if (!this.prefix) { + switch (params[0]) { + case 5: + // status report + this.send('\x1b[0n'); + break; + case 6: + // cursor position + this.send('\x1b[' + + (this.y + 1) + + ';' + + (this.x + 1) + + 'R'); + break; + } + } else if (this.prefix === '?') { + // modern xterm doesnt seem to + // respond to any of these except ?6, 6, and 5 + switch (params[0]) { + case 6: + // cursor position + this.send('\x1b[?' + + (this.y + 1) + + ';' + + (this.x + 1) + + 'R'); + break; + case 15: + // no printer + // this.send('\x1b[?11n'); + break; + case 25: + // dont support user defined keys + // this.send('\x1b[?21n'); + break; + case 26: + // north american keyboard + // this.send('\x1b[?27;1;0;0n'); + break; + case 53: + // no dec locator/mouse + // this.send('\x1b[?50n'); + break; + } + } +}; + +/** + * Additions + */ + +// CSI Ps @ +// Insert Ps (Blank) Character(s) (default = 1) (ICH). +Terminal.prototype.insertChars = function(params) { + var param, row, j, ch; + + param = params[0]; + if (param < 1) param = 1; + + row = this.y + this.ybase; + j = this.x; + ch = [this.curAttr, ' ']; // xterm + + while (param-- && j < this.cols) { + this.lines[row].splice(j++, 0, ch); + this.lines[row].pop(); + } +}; + +// CSI Ps E +// Cursor Next Line Ps Times (default = 1) (CNL). +// same as CSI Ps B ? +Terminal.prototype.cursorNextLine = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.y += param; + if (this.y >= this.rows) { + this.y = this.rows - 1; + } + this.x = 0; +}; + +// CSI Ps F +// Cursor Preceding Line Ps Times (default = 1) (CNL). +// reuse CSI Ps A ? +Terminal.prototype.cursorPrecedingLine = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.y -= param; + if (this.y < 0) this.y = 0; + this.x = 0; +}; + +// CSI Ps G +// Cursor Character Absolute [column] (default = [row,1]) (CHA). +Terminal.prototype.cursorCharAbsolute = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.x = param - 1; +}; + +// CSI Ps L +// Insert Ps Line(s) (default = 1) (IL). +Terminal.prototype.insertLines = function(params) { + var param, row, j; + + param = params[0]; + if (param < 1) param = 1; + row = this.y + this.ybase; + + j = this.rows - 1 - this.scrollBottom; + j = this.rows - 1 + this.ybase - j + 1; + + while (param--) { + // test: echo -e '\e[44m\e[1L\e[0m' + // blankLine(true) - xterm/linux behavior + this.lines.splice(row, 0, this.blankLine(true)); + this.lines.splice(j, 1); + } + + // this.maxRange(); + this.updateRange(this.y); + this.updateRange(this.scrollBottom); +}; + +// CSI Ps M +// Delete Ps Line(s) (default = 1) (DL). +Terminal.prototype.deleteLines = function(params) { + var param, row, j; + + param = params[0]; + if (param < 1) param = 1; + row = this.y + this.ybase; + + j = this.rows - 1 - this.scrollBottom; + j = this.rows - 1 + this.ybase - j; + + while (param--) { + // test: echo -e '\e[44m\e[1M\e[0m' + // blankLine(true) - xterm/linux behavior + this.lines.splice(j + 1, 0, this.blankLine(true)); + this.lines.splice(row, 1); + } + + // this.maxRange(); + this.updateRange(this.y); + this.updateRange(this.scrollBottom); +}; + +// CSI Ps P +// Delete Ps Character(s) (default = 1) (DCH). +Terminal.prototype.deleteChars = function(params) { + var param, row, ch; + + param = params[0]; + if (param < 1) param = 1; + + row = this.y + this.ybase; + ch = [this.curAttr, ' ']; // xterm + + while (param--) { + this.lines[row].splice(this.x, 1); + this.lines[row].push(ch); + } +}; + +// CSI Ps X +// Erase Ps Character(s) (default = 1) (ECH). +Terminal.prototype.eraseChars = function(params) { + var param, row, j, ch; + + param = params[0]; + if (param < 1) param = 1; + + row = this.y + this.ybase; + j = this.x; + ch = [this.curAttr, ' ']; // xterm + + while (param-- && j < this.cols) { + this.lines[row][j++] = ch; + } +}; + +// CSI Pm ` Character Position Absolute +// [column] (default = [row,1]) (HPA). +Terminal.prototype.charPosAbsolute = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.x = param - 1; + if (this.x >= this.cols) { + this.x = this.cols - 1; + } +}; + +// 141 61 a * HPR - +// Horizontal Position Relative +// reuse CSI Ps C ? +Terminal.prototype.HPositionRelative = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.x += param; + if (this.x >= this.cols) { + this.x = this.cols - 1; + } +}; + +// CSI Ps c Send Device Attributes (Primary DA). +// Ps = 0 or omitted -> request attributes from terminal. The +// response depends on the decTerminalID resource setting. +// -> CSI ? 1 ; 2 c (``VT100 with Advanced Video Option'') +// -> CSI ? 1 ; 0 c (``VT101 with No Options'') +// -> CSI ? 6 c (``VT102'') +// -> CSI ? 6 0 ; 1 ; 2 ; 6 ; 8 ; 9 ; 1 5 ; c (``VT220'') +// The VT100-style response parameters do not mean anything by +// themselves. VT220 parameters do, telling the host what fea- +// tures the terminal supports: +// Ps = 1 -> 132-columns. +// Ps = 2 -> Printer. +// Ps = 6 -> Selective erase. +// Ps = 8 -> User-defined keys. +// Ps = 9 -> National replacement character sets. +// Ps = 1 5 -> Technical characters. +// Ps = 2 2 -> ANSI color, e.g., VT525. +// Ps = 2 9 -> ANSI text locator (i.e., DEC Locator mode). +// CSI > Ps c +// Send Device Attributes (Secondary DA). +// Ps = 0 or omitted -> request the terminal's identification +// code. The response depends on the decTerminalID resource set- +// ting. It should apply only to VT220 and up, but xterm extends +// this to VT100. +// -> CSI > Pp ; Pv ; Pc c +// where Pp denotes the terminal type +// Pp = 0 -> ``VT100''. +// Pp = 1 -> ``VT220''. +// and Pv is the firmware version (for xterm, this was originally +// the XFree86 patch number, starting with 95). In a DEC termi- +// nal, Pc indicates the ROM cartridge registration number and is +// always zero. +// More information: +// xterm/charproc.c - line 2012, for more information. +// vim responds with ^[[?0c or ^[[?1c after the terminal's response (?) +Terminal.prototype.sendDeviceAttributes = function(params) { + if (params[0] > 0) return; + + if (!this.prefix) { + if (this.is('xterm') + || this.is('rxvt-unicode') + || this.is('screen')) { + this.send('\x1b[?1;2c'); + } else if (this.is('linux')) { + this.send('\x1b[?6c'); + } + } else if (this.prefix === '>') { + // xterm and urxvt + // seem to spit this + // out around ~370 times (?). + if (this.is('xterm')) { + this.send('\x1b[>0;276;0c'); + } else if (this.is('rxvt-unicode')) { + this.send('\x1b[>85;95;0c'); + } else if (this.is('linux')) { + // not supported by linux console. + // linux console echoes parameters. + this.send(params[0] + 'c'); + } else if (this.is('screen')) { + this.send('\x1b[>83;40003;0c'); + } + } +}; + +// CSI Pm d +// Line Position Absolute [row] (default = [1,column]) (VPA). +Terminal.prototype.linePosAbsolute = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.y = param - 1; + if (this.y >= this.rows) { + this.y = this.rows - 1; + } +}; + +// 145 65 e * VPR - Vertical Position Relative +// reuse CSI Ps B ? +Terminal.prototype.VPositionRelative = function(params) { + var param = params[0]; + if (param < 1) param = 1; + this.y += param; + if (this.y >= this.rows) { + this.y = this.rows - 1; + } +}; + +// CSI Ps ; Ps f +// Horizontal and Vertical Position [row;column] (default = +// [1,1]) (HVP). +Terminal.prototype.HVPosition = function(params) { + if (params[0] < 1) params[0] = 1; + if (params[1] < 1) params[1] = 1; + + this.y = params[0] - 1; + if (this.y >= this.rows) { + this.y = this.rows - 1; + } + + this.x = params[1] - 1; + if (this.x >= this.cols) { + this.x = this.cols - 1; + } +}; + +// CSI Pm h Set Mode (SM). +// Ps = 2 -> Keyboard Action Mode (AM). +// Ps = 4 -> Insert Mode (IRM). +// Ps = 1 2 -> Send/receive (SRM). +// Ps = 2 0 -> Automatic Newline (LNM). +// CSI ? Pm h +// DEC Private Mode Set (DECSET). +// Ps = 1 -> Application Cursor Keys (DECCKM). +// Ps = 2 -> Designate USASCII for character sets G0-G3 +// (DECANM), and set VT100 mode. +// Ps = 3 -> 132 Column Mode (DECCOLM). +// Ps = 4 -> Smooth (Slow) Scroll (DECSCLM). +// Ps = 5 -> Reverse Video (DECSCNM). +// Ps = 6 -> Origin Mode (DECOM). +// Ps = 7 -> Wraparound Mode (DECAWM). +// Ps = 8 -> Auto-repeat Keys (DECARM). +// Ps = 9 -> Send Mouse X & Y on button press. See the sec- +// tion Mouse Tracking. +// Ps = 1 0 -> Show toolbar (rxvt). +// Ps = 1 2 -> Start Blinking Cursor (att610). +// Ps = 1 8 -> Print form feed (DECPFF). +// Ps = 1 9 -> Set print extent to full screen (DECPEX). +// Ps = 2 5 -> Show Cursor (DECTCEM). +// Ps = 3 0 -> Show scrollbar (rxvt). +// Ps = 3 5 -> Enable font-shifting functions (rxvt). +// Ps = 3 8 -> Enter Tektronix Mode (DECTEK). +// Ps = 4 0 -> Allow 80 -> 132 Mode. +// Ps = 4 1 -> more(1) fix (see curses resource). +// Ps = 4 2 -> Enable Nation Replacement Character sets (DECN- +// RCM). +// Ps = 4 4 -> Turn On Margin Bell. +// Ps = 4 5 -> Reverse-wraparound Mode. +// Ps = 4 6 -> Start Logging. This is normally disabled by a +// compile-time option. +// Ps = 4 7 -> Use Alternate Screen Buffer. (This may be dis- +// abled by the titeInhibit resource). +// Ps = 6 6 -> Application keypad (DECNKM). +// Ps = 6 7 -> Backarrow key sends backspace (DECBKM). +// Ps = 1 0 0 0 -> Send Mouse X & Y on button press and +// release. See the section Mouse Tracking. +// Ps = 1 0 0 1 -> Use Hilite Mouse Tracking. +// Ps = 1 0 0 2 -> Use Cell Motion Mouse Tracking. +// Ps = 1 0 0 3 -> Use All Motion Mouse Tracking. +// Ps = 1 0 0 4 -> Send FocusIn/FocusOut events. +// Ps = 1 0 0 5 -> Enable Extended Mouse Mode. +// Ps = 1 0 1 0 -> Scroll to bottom on tty output (rxvt). +// Ps = 1 0 1 1 -> Scroll to bottom on key press (rxvt). +// Ps = 1 0 3 4 -> Interpret "meta" key, sets eighth bit. +// (enables the eightBitInput resource). +// Ps = 1 0 3 5 -> Enable special modifiers for Alt and Num- +// Lock keys. (This enables the numLock resource). +// Ps = 1 0 3 6 -> Send ESC when Meta modifies a key. (This +// enables the metaSendsEscape resource). +// Ps = 1 0 3 7 -> Send DEL from the editing-keypad Delete +// key. +// Ps = 1 0 3 9 -> Send ESC when Alt modifies a key. (This +// enables the altSendsEscape resource). +// Ps = 1 0 4 0 -> Keep selection even if not highlighted. +// (This enables the keepSelection resource). +// Ps = 1 0 4 1 -> Use the CLIPBOARD selection. (This enables +// the selectToClipboard resource). +// Ps = 1 0 4 2 -> Enable Urgency window manager hint when +// Control-G is received. (This enables the bellIsUrgent +// resource). +// Ps = 1 0 4 3 -> Enable raising of the window when Control-G +// is received. (enables the popOnBell resource). +// Ps = 1 0 4 7 -> Use Alternate Screen Buffer. (This may be +// disabled by the titeInhibit resource). +// Ps = 1 0 4 8 -> Save cursor as in DECSC. (This may be dis- +// abled by the titeInhibit resource). +// Ps = 1 0 4 9 -> Save cursor as in DECSC and use Alternate +// Screen Buffer, clearing it first. (This may be disabled by +// the titeInhibit resource). This combines the effects of the 1 +// 0 4 7 and 1 0 4 8 modes. Use this with terminfo-based +// applications rather than the 4 7 mode. +// Ps = 1 0 5 0 -> Set terminfo/termcap function-key mode. +// Ps = 1 0 5 1 -> Set Sun function-key mode. +// Ps = 1 0 5 2 -> Set HP function-key mode. +// Ps = 1 0 5 3 -> Set SCO function-key mode. +// Ps = 1 0 6 0 -> Set legacy keyboard emulation (X11R6). +// Ps = 1 0 6 1 -> Set VT220 keyboard emulation. +// Ps = 2 0 0 4 -> Set bracketed paste mode. +// Modes: +// http://vt100.net/docs/vt220-rm/chapter4.html +Terminal.prototype.setMode = function(params) { + if (typeof params === 'object') { + var l = params.length + , i = 0; + + for (; i < l; i++) { + this.setMode(params[i]); + } + + return; + } + + if (!this.prefix) { + switch (params) { + case 4: + this.insertMode = true; + break; + case 20: + //this.convertEol = true; + break; + } + } else if (this.prefix === '?') { + switch (params) { + case 1: + this.applicationKeypad = true; + break; + case 2: + this.setgCharset(0, Terminal.charsets.US); + this.setgCharset(1, Terminal.charsets.US); + this.setgCharset(2, Terminal.charsets.US); + this.setgCharset(3, Terminal.charsets.US); + // set VT100 mode here + break; + case 3: // 132 col mode + this.savedCols = this.cols; + this.resize(132, this.rows); + break; + case 6: + this.originMode = true; + break; + case 7: + this.wraparoundMode = true; + break; + case 12: + // this.cursorBlink = true; + break; + case 9: // X10 Mouse + // no release, no motion, no wheel, no modifiers. + case 1000: // vt200 mouse + // no motion. + // no modifiers, except control on the wheel. + case 1002: // button event mouse + case 1003: // any event mouse + // any event - sends motion events, + // even if there is no button held down. + this.x10Mouse = params === 9; + this.vt200Mouse = params === 1000; + this.normalMouse = params > 1000; + this.mouseEvents = true; + this.element.style.cursor = 'default'; + this.log('Binding to mouse events.'); + break; + case 1004: // send focusin/focusout events + // focusin: ^[[I + // focusout: ^[[O + this.sendFocus = true; + break; + case 1005: // utf8 ext mode mouse + this.utfMouse = true; + // for wide terminals + // simply encodes large values as utf8 characters + break; + case 1006: // sgr ext mode mouse + this.sgrMouse = true; + // for wide terminals + // does not add 32 to fields + // press: ^[[ Keyboard Action Mode (AM). +// Ps = 4 -> Replace Mode (IRM). +// Ps = 1 2 -> Send/receive (SRM). +// Ps = 2 0 -> Normal Linefeed (LNM). +// CSI ? Pm l +// DEC Private Mode Reset (DECRST). +// Ps = 1 -> Normal Cursor Keys (DECCKM). +// Ps = 2 -> Designate VT52 mode (DECANM). +// Ps = 3 -> 80 Column Mode (DECCOLM). +// Ps = 4 -> Jump (Fast) Scroll (DECSCLM). +// Ps = 5 -> Normal Video (DECSCNM). +// Ps = 6 -> Normal Cursor Mode (DECOM). +// Ps = 7 -> No Wraparound Mode (DECAWM). +// Ps = 8 -> No Auto-repeat Keys (DECARM). +// Ps = 9 -> Don't send Mouse X & Y on button press. +// Ps = 1 0 -> Hide toolbar (rxvt). +// Ps = 1 2 -> Stop Blinking Cursor (att610). +// Ps = 1 8 -> Don't print form feed (DECPFF). +// Ps = 1 9 -> Limit print to scrolling region (DECPEX). +// Ps = 2 5 -> Hide Cursor (DECTCEM). +// Ps = 3 0 -> Don't show scrollbar (rxvt). +// Ps = 3 5 -> Disable font-shifting functions (rxvt). +// Ps = 4 0 -> Disallow 80 -> 132 Mode. +// Ps = 4 1 -> No more(1) fix (see curses resource). +// Ps = 4 2 -> Disable Nation Replacement Character sets (DEC- +// NRCM). +// Ps = 4 4 -> Turn Off Margin Bell. +// Ps = 4 5 -> No Reverse-wraparound Mode. +// Ps = 4 6 -> Stop Logging. (This is normally disabled by a +// compile-time option). +// Ps = 4 7 -> Use Normal Screen Buffer. +// Ps = 6 6 -> Numeric keypad (DECNKM). +// Ps = 6 7 -> Backarrow key sends delete (DECBKM). +// Ps = 1 0 0 0 -> Don't send Mouse X & Y on button press and +// release. See the section Mouse Tracking. +// Ps = 1 0 0 1 -> Don't use Hilite Mouse Tracking. +// Ps = 1 0 0 2 -> Don't use Cell Motion Mouse Tracking. +// Ps = 1 0 0 3 -> Don't use All Motion Mouse Tracking. +// Ps = 1 0 0 4 -> Don't send FocusIn/FocusOut events. +// Ps = 1 0 0 5 -> Disable Extended Mouse Mode. +// Ps = 1 0 1 0 -> Don't scroll to bottom on tty output +// (rxvt). +// Ps = 1 0 1 1 -> Don't scroll to bottom on key press (rxvt). +// Ps = 1 0 3 4 -> Don't interpret "meta" key. (This disables +// the eightBitInput resource). +// Ps = 1 0 3 5 -> Disable special modifiers for Alt and Num- +// Lock keys. (This disables the numLock resource). +// Ps = 1 0 3 6 -> Don't send ESC when Meta modifies a key. +// (This disables the metaSendsEscape resource). +// Ps = 1 0 3 7 -> Send VT220 Remove from the editing-keypad +// Delete key. +// Ps = 1 0 3 9 -> Don't send ESC when Alt modifies a key. +// (This disables the altSendsEscape resource). +// Ps = 1 0 4 0 -> Do not keep selection when not highlighted. +// (This disables the keepSelection resource). +// Ps = 1 0 4 1 -> Use the PRIMARY selection. (This disables +// the selectToClipboard resource). +// Ps = 1 0 4 2 -> Disable Urgency window manager hint when +// Control-G is received. (This disables the bellIsUrgent +// resource). +// Ps = 1 0 4 3 -> Disable raising of the window when Control- +// G is received. (This disables the popOnBell resource). +// Ps = 1 0 4 7 -> Use Normal Screen Buffer, clearing screen +// first if in the Alternate Screen. (This may be disabled by +// the titeInhibit resource). +// Ps = 1 0 4 8 -> Restore cursor as in DECRC. (This may be +// disabled by the titeInhibit resource). +// Ps = 1 0 4 9 -> Use Normal Screen Buffer and restore cursor +// as in DECRC. (This may be disabled by the titeInhibit +// resource). This combines the effects of the 1 0 4 7 and 1 0 +// 4 8 modes. Use this with terminfo-based applications rather +// than the 4 7 mode. +// Ps = 1 0 5 0 -> Reset terminfo/termcap function-key mode. +// Ps = 1 0 5 1 -> Reset Sun function-key mode. +// Ps = 1 0 5 2 -> Reset HP function-key mode. +// Ps = 1 0 5 3 -> Reset SCO function-key mode. +// Ps = 1 0 6 0 -> Reset legacy keyboard emulation (X11R6). +// Ps = 1 0 6 1 -> Reset keyboard emulation to Sun/PC style. +// Ps = 2 0 0 4 -> Reset bracketed paste mode. +Terminal.prototype.resetMode = function(params) { + if (typeof params === 'object') { + var l = params.length + , i = 0; + + for (; i < l; i++) { + this.resetMode(params[i]); + } + + return; + } + + if (!this.prefix) { + switch (params) { + case 4: + this.insertMode = false; + break; + case 20: + //this.convertEol = false; + break; + } + } else if (this.prefix === '?') { + switch (params) { + case 1: + this.applicationKeypad = false; + break; + case 3: + if (this.cols === 132 && this.savedCols) { + this.resize(this.savedCols, this.rows); + } + delete this.savedCols; + break; + case 6: + this.originMode = false; + break; + case 7: + this.wraparoundMode = false; + break; + case 12: + // this.cursorBlink = false; + break; + case 9: // X10 Mouse + case 1000: // vt200 mouse + case 1002: // button event mouse + case 1003: // any event mouse + this.x10Mouse = false; + this.vt200Mouse = false; + this.normalMouse = false; + this.mouseEvents = false; + this.element.style.cursor = ''; + break; + case 1004: // send focusin/focusout events + this.sendFocus = false; + break; + case 1005: // utf8 ext mode mouse + this.utfMouse = false; + break; + case 1006: // sgr ext mode mouse + this.sgrMouse = false; + break; + case 1015: // urxvt ext mode mouse + this.urxvtMouse = false; + break; + case 25: // hide cursor + this.cursorHidden = true; + break; + case 1049: // alt screen buffer cursor + ; // FALL-THROUGH + case 47: // normal screen buffer + case 1047: // normal screen buffer - clearing it first + if (this.normal) { + this.lines = this.normal.lines; + this.ybase = this.normal.ybase; + this.ydisp = this.normal.ydisp; + this.x = this.normal.x; + this.y = this.normal.y; + this.scrollTop = this.normal.scrollTop; + this.scrollBottom = this.normal.scrollBottom; + this.tabs = this.normal.tabs; + this.normal = null; + // if (params === 1049) { + // this.x = this.savedX; + // this.y = this.savedY; + // } + this.refresh(0, this.rows - 1); + this.showCursor(); + } + break; + } + } +}; + +// CSI Ps ; Ps r +// Set Scrolling Region [top;bottom] (default = full size of win- +// dow) (DECSTBM). +// CSI ? Pm r +Terminal.prototype.setScrollRegion = function(params) { + if (this.prefix) return; + this.scrollTop = (params[0] || 1) - 1; + this.scrollBottom = (params[1] || this.rows) - 1; + this.x = 0; + this.y = 0; +}; + +// CSI s +// Save cursor (ANSI.SYS). +Terminal.prototype.saveCursor = function(params) { + this.savedX = this.x; + this.savedY = this.y; +}; + +// CSI u +// Restore cursor (ANSI.SYS). +Terminal.prototype.restoreCursor = function(params) { + this.x = this.savedX || 0; + this.y = this.savedY || 0; +}; + +/** + * Lesser Used + */ + +// CSI Ps I +// Cursor Forward Tabulation Ps tab stops (default = 1) (CHT). +Terminal.prototype.cursorForwardTab = function(params) { + var param = params[0] || 1; + while (param--) { + this.x = this.nextStop(); + } +}; + +// CSI Ps S Scroll up Ps lines (default = 1) (SU). +Terminal.prototype.scrollUp = function(params) { + var param = params[0] || 1; + while (param--) { + this.lines.splice(this.ybase + this.scrollTop, 1); + this.lines.splice(this.ybase + this.scrollBottom, 0, this.blankLine()); + } + // this.maxRange(); + this.updateRange(this.scrollTop); + this.updateRange(this.scrollBottom); +}; + +// CSI Ps T Scroll down Ps lines (default = 1) (SD). +Terminal.prototype.scrollDown = function(params) { + var param = params[0] || 1; + while (param--) { + this.lines.splice(this.ybase + this.scrollBottom, 1); + this.lines.splice(this.ybase + this.scrollTop, 0, this.blankLine()); + } + // this.maxRange(); + this.updateRange(this.scrollTop); + this.updateRange(this.scrollBottom); +}; + +// CSI Ps ; Ps ; Ps ; Ps ; Ps T +// Initiate highlight mouse tracking. Parameters are +// [func;startx;starty;firstrow;lastrow]. See the section Mouse +// Tracking. +Terminal.prototype.initMouseTracking = function(params) { + // Relevant: DECSET 1001 +}; + +// CSI > Ps; Ps T +// Reset one or more features of the title modes to the default +// value. Normally, "reset" disables the feature. It is possi- +// ble to disable the ability to reset features by compiling a +// different default for the title modes into xterm. +// Ps = 0 -> Do not set window/icon labels using hexadecimal. +// Ps = 1 -> Do not query window/icon labels using hexadeci- +// mal. +// Ps = 2 -> Do not set window/icon labels using UTF-8. +// Ps = 3 -> Do not query window/icon labels using UTF-8. +// (See discussion of "Title Modes"). +Terminal.prototype.resetTitleModes = function(params) { + ; +}; + +// CSI Ps Z Cursor Backward Tabulation Ps tab stops (default = 1) (CBT). +Terminal.prototype.cursorBackwardTab = function(params) { + var param = params[0] || 1; + while (param--) { + this.x = this.prevStop(); + } +}; + +// CSI Ps b Repeat the preceding graphic character Ps times (REP). +Terminal.prototype.repeatPrecedingCharacter = function(params) { + var param = params[0] || 1 + , line = this.lines[this.ybase + this.y] + , ch = line[this.x - 1] || [this.defAttr, ' ']; + + while (param--) line[this.x++] = ch; +}; + +// CSI Ps g Tab Clear (TBC). +// Ps = 0 -> Clear Current Column (default). +// Ps = 3 -> Clear All. +// Potentially: +// Ps = 2 -> Clear Stops on Line. +// http://vt100.net/annarbor/aaa-ug/section6.html +Terminal.prototype.tabClear = function(params) { + var param = params[0]; + if (param <= 0) { + delete this.tabs[this.x]; + } else if (param === 3) { + this.tabs = {}; + } +}; + +// CSI Pm i Media Copy (MC). +// Ps = 0 -> Print screen (default). +// Ps = 4 -> Turn off printer controller mode. +// Ps = 5 -> Turn on printer controller mode. +// CSI ? Pm i +// Media Copy (MC, DEC-specific). +// Ps = 1 -> Print line containing cursor. +// Ps = 4 -> Turn off autoprint mode. +// Ps = 5 -> Turn on autoprint mode. +// Ps = 1 0 -> Print composed display, ignores DECPEX. +// Ps = 1 1 -> Print all pages. +Terminal.prototype.mediaCopy = function(params) { + ; +}; + +// CSI > Ps; Ps m +// Set or reset resource-values used by xterm to decide whether +// to construct escape sequences holding information about the +// modifiers pressed with a given key. The first parameter iden- +// tifies the resource to set/reset. The second parameter is the +// value to assign to the resource. If the second parameter is +// omitted, the resource is reset to its initial value. +// Ps = 1 -> modifyCursorKeys. +// Ps = 2 -> modifyFunctionKeys. +// Ps = 4 -> modifyOtherKeys. +// If no parameters are given, all resources are reset to their +// initial values. +Terminal.prototype.setResources = function(params) { + ; +}; + +// CSI > Ps n +// Disable modifiers which may be enabled via the CSI > Ps; Ps m +// sequence. This corresponds to a resource value of "-1", which +// cannot be set with the other sequence. The parameter identi- +// fies the resource to be disabled: +// Ps = 1 -> modifyCursorKeys. +// Ps = 2 -> modifyFunctionKeys. +// Ps = 4 -> modifyOtherKeys. +// If the parameter is omitted, modifyFunctionKeys is disabled. +// When modifyFunctionKeys is disabled, xterm uses the modifier +// keys to make an extended sequence of functions rather than +// adding a parameter to each function key to denote the modi- +// fiers. +Terminal.prototype.disableModifiers = function(params) { + ; +}; + +// CSI > Ps p +// Set resource value pointerMode. This is used by xterm to +// decide whether to hide the pointer cursor as the user types. +// Valid values for the parameter: +// Ps = 0 -> never hide the pointer. +// Ps = 1 -> hide if the mouse tracking mode is not enabled. +// Ps = 2 -> always hide the pointer. If no parameter is +// given, xterm uses the default, which is 1 . +Terminal.prototype.setPointerMode = function(params) { + ; +}; + +// CSI ! p Soft terminal reset (DECSTR). +// http://vt100.net/docs/vt220-rm/table4-10.html +Terminal.prototype.softReset = function(params) { + this.cursorHidden = false; + this.insertMode = false; + this.originMode = false; + this.wraparoundMode = false; // autowrap + this.applicationKeypad = false; // ? + this.scrollTop = 0; + this.scrollBottom = this.rows - 1; + this.curAttr = this.defAttr; + this.x = this.y = 0; // ? + this.charset = null; + this.glevel = 0; // ?? + this.charsets = [null]; // ?? +}; + +// CSI Ps$ p +// Request ANSI mode (DECRQM). For VT300 and up, reply is +// CSI Ps; Pm$ y +// where Ps is the mode number as in RM, and Pm is the mode +// value: +// 0 - not recognized +// 1 - set +// 2 - reset +// 3 - permanently set +// 4 - permanently reset +Terminal.prototype.requestAnsiMode = function(params) { + ; +}; + +// CSI ? Ps$ p +// Request DEC private mode (DECRQM). For VT300 and up, reply is +// CSI ? Ps; Pm$ p +// where Ps is the mode number as in DECSET, Pm is the mode value +// as in the ANSI DECRQM. +Terminal.prototype.requestPrivateMode = function(params) { + ; +}; + +// CSI Ps ; Ps " p +// Set conformance level (DECSCL). Valid values for the first +// parameter: +// Ps = 6 1 -> VT100. +// Ps = 6 2 -> VT200. +// Ps = 6 3 -> VT300. +// Valid values for the second parameter: +// Ps = 0 -> 8-bit controls. +// Ps = 1 -> 7-bit controls (always set for VT100). +// Ps = 2 -> 8-bit controls. +Terminal.prototype.setConformanceLevel = function(params) { + ; +}; + +// CSI Ps q Load LEDs (DECLL). +// Ps = 0 -> Clear all LEDS (default). +// Ps = 1 -> Light Num Lock. +// Ps = 2 -> Light Caps Lock. +// Ps = 3 -> Light Scroll Lock. +// Ps = 2 1 -> Extinguish Num Lock. +// Ps = 2 2 -> Extinguish Caps Lock. +// Ps = 2 3 -> Extinguish Scroll Lock. +Terminal.prototype.loadLEDs = function(params) { + ; +}; + +// CSI Ps SP q +// Set cursor style (DECSCUSR, VT520). +// Ps = 0 -> blinking block. +// Ps = 1 -> blinking block (default). +// Ps = 2 -> steady block. +// Ps = 3 -> blinking underline. +// Ps = 4 -> steady underline. +Terminal.prototype.setCursorStyle = function(params) { + ; +}; + +// CSI Ps " q +// Select character protection attribute (DECSCA). Valid values +// for the parameter: +// Ps = 0 -> DECSED and DECSEL can erase (default). +// Ps = 1 -> DECSED and DECSEL cannot erase. +// Ps = 2 -> DECSED and DECSEL can erase. +Terminal.prototype.setCharProtectionAttr = function(params) { + ; +}; + +// CSI ? Pm r +// Restore DEC Private Mode Values. The value of Ps previously +// saved is restored. Ps values are the same as for DECSET. +Terminal.prototype.restorePrivateValues = function(params) { + ; +}; + +// CSI Pt; Pl; Pb; Pr; Ps$ r +// Change Attributes in Rectangular Area (DECCARA), VT400 and up. +// Pt; Pl; Pb; Pr denotes the rectangle. +// Ps denotes the SGR attributes to change: 0, 1, 4, 5, 7. +// NOTE: xterm doesn't enable this code by default. +Terminal.prototype.setAttrInRectangle = function(params) { + var t = params[0] + , l = params[1] + , b = params[2] + , r = params[3] + , attr = params[4]; + + var line + , i; + + for (; t < b + 1; t++) { + line = this.lines[this.ybase + t]; + for (i = l; i < r; i++) { + line[i] = [attr, line[i][1]]; + } + } + + // this.maxRange(); + this.updateRange(params[0]); + this.updateRange(params[2]); +}; + +// CSI ? Pm s +// Save DEC Private Mode Values. Ps values are the same as for +// DECSET. +Terminal.prototype.savePrivateValues = function(params) { + ; +}; + +// CSI Ps ; Ps ; Ps t +// Window manipulation (from dtterm, as well as extensions). +// These controls may be disabled using the allowWindowOps +// resource. Valid values for the first (and any additional +// parameters) are: +// Ps = 1 -> De-iconify window. +// Ps = 2 -> Iconify window. +// Ps = 3 ; x ; y -> Move window to [x, y]. +// Ps = 4 ; height ; width -> Resize the xterm window to +// height and width in pixels. +// Ps = 5 -> Raise the xterm window to the front of the stack- +// ing order. +// Ps = 6 -> Lower the xterm window to the bottom of the +// stacking order. +// Ps = 7 -> Refresh the xterm window. +// Ps = 8 ; height ; width -> Resize the text area to +// [height;width] in characters. +// Ps = 9 ; 0 -> Restore maximized window. +// Ps = 9 ; 1 -> Maximize window (i.e., resize to screen +// size). +// Ps = 1 0 ; 0 -> Undo full-screen mode. +// Ps = 1 0 ; 1 -> Change to full-screen. +// Ps = 1 1 -> Report xterm window state. If the xterm window +// is open (non-iconified), it returns CSI 1 t . If the xterm +// window is iconified, it returns CSI 2 t . +// Ps = 1 3 -> Report xterm window position. Result is CSI 3 +// ; x ; y t +// Ps = 1 4 -> Report xterm window in pixels. Result is CSI +// 4 ; height ; width t +// Ps = 1 8 -> Report the size of the text area in characters. +// Result is CSI 8 ; height ; width t +// Ps = 1 9 -> Report the size of the screen in characters. +// Result is CSI 9 ; height ; width t +// Ps = 2 0 -> Report xterm window's icon label. Result is +// OSC L label ST +// Ps = 2 1 -> Report xterm window's title. Result is OSC l +// label ST +// Ps = 2 2 ; 0 -> Save xterm icon and window title on +// stack. +// Ps = 2 2 ; 1 -> Save xterm icon title on stack. +// Ps = 2 2 ; 2 -> Save xterm window title on stack. +// Ps = 2 3 ; 0 -> Restore xterm icon and window title from +// stack. +// Ps = 2 3 ; 1 -> Restore xterm icon title from stack. +// Ps = 2 3 ; 2 -> Restore xterm window title from stack. +// Ps >= 2 4 -> Resize to Ps lines (DECSLPP). +Terminal.prototype.manipulateWindow = function(params) { + ; +}; + +// CSI Pt; Pl; Pb; Pr; Ps$ t +// Reverse Attributes in Rectangular Area (DECRARA), VT400 and +// up. +// Pt; Pl; Pb; Pr denotes the rectangle. +// Ps denotes the attributes to reverse, i.e., 1, 4, 5, 7. +// NOTE: xterm doesn't enable this code by default. +Terminal.prototype.reverseAttrInRectangle = function(params) { + ; +}; + +// CSI > Ps; Ps t +// Set one or more features of the title modes. Each parameter +// enables a single feature. +// Ps = 0 -> Set window/icon labels using hexadecimal. +// Ps = 1 -> Query window/icon labels using hexadecimal. +// Ps = 2 -> Set window/icon labels using UTF-8. +// Ps = 3 -> Query window/icon labels using UTF-8. (See dis- +// cussion of "Title Modes") +Terminal.prototype.setTitleModeFeature = function(params) { + ; +}; + +// CSI Ps SP t +// Set warning-bell volume (DECSWBV, VT520). +// Ps = 0 or 1 -> off. +// Ps = 2 , 3 or 4 -> low. +// Ps = 5 , 6 , 7 , or 8 -> high. +Terminal.prototype.setWarningBellVolume = function(params) { + ; +}; + +// CSI Ps SP u +// Set margin-bell volume (DECSMBV, VT520). +// Ps = 1 -> off. +// Ps = 2 , 3 or 4 -> low. +// Ps = 0 , 5 , 6 , 7 , or 8 -> high. +Terminal.prototype.setMarginBellVolume = function(params) { + ; +}; + +// CSI Pt; Pl; Pb; Pr; Pp; Pt; Pl; Pp$ v +// Copy Rectangular Area (DECCRA, VT400 and up). +// Pt; Pl; Pb; Pr denotes the rectangle. +// Pp denotes the source page. +// Pt; Pl denotes the target location. +// Pp denotes the target page. +// NOTE: xterm doesn't enable this code by default. +Terminal.prototype.copyRectangle = function(params) { + ; +}; + +// CSI Pt ; Pl ; Pb ; Pr ' w +// Enable Filter Rectangle (DECEFR), VT420 and up. +// Parameters are [top;left;bottom;right]. +// Defines the coordinates of a filter rectangle and activates +// it. Anytime the locator is detected outside of the filter +// rectangle, an outside rectangle event is generated and the +// rectangle is disabled. Filter rectangles are always treated +// as "one-shot" events. Any parameters that are omitted default +// to the current locator position. If all parameters are omit- +// ted, any locator motion will be reported. DECELR always can- +// cels any prevous rectangle definition. +Terminal.prototype.enableFilterRectangle = function(params) { + ; +}; + +// CSI Ps x Request Terminal Parameters (DECREQTPARM). +// if Ps is a "0" (default) or "1", and xterm is emulating VT100, +// the control sequence elicits a response of the same form whose +// parameters describe the terminal: +// Ps -> the given Ps incremented by 2. +// Pn = 1 <- no parity. +// Pn = 1 <- eight bits. +// Pn = 1 <- 2 8 transmit 38.4k baud. +// Pn = 1 <- 2 8 receive 38.4k baud. +// Pn = 1 <- clock multiplier. +// Pn = 0 <- STP flags. +Terminal.prototype.requestParameters = function(params) { + ; +}; + +// CSI Ps x Select Attribute Change Extent (DECSACE). +// Ps = 0 -> from start to end position, wrapped. +// Ps = 1 -> from start to end position, wrapped. +// Ps = 2 -> rectangle (exact). +Terminal.prototype.selectChangeExtent = function(params) { + ; +}; + +// CSI Pc; Pt; Pl; Pb; Pr$ x +// Fill Rectangular Area (DECFRA), VT420 and up. +// Pc is the character to use. +// Pt; Pl; Pb; Pr denotes the rectangle. +// NOTE: xterm doesn't enable this code by default. +Terminal.prototype.fillRectangle = function(params) { + var ch = params[0] + , t = params[1] + , l = params[2] + , b = params[3] + , r = params[4]; + + var line + , i; + + for (; t < b + 1; t++) { + line = this.lines[this.ybase + t]; + for (i = l; i < r; i++) { + line[i] = [line[i][0], String.fromCharCode(ch)]; + } + } + + // this.maxRange(); + this.updateRange(params[1]); + this.updateRange(params[3]); +}; + +// CSI Ps ; Pu ' z +// Enable Locator Reporting (DECELR). +// Valid values for the first parameter: +// Ps = 0 -> Locator disabled (default). +// Ps = 1 -> Locator enabled. +// Ps = 2 -> Locator enabled for one report, then disabled. +// The second parameter specifies the coordinate unit for locator +// reports. +// Valid values for the second parameter: +// Pu = 0 <- or omitted -> default to character cells. +// Pu = 1 <- device physical pixels. +// Pu = 2 <- character cells. +Terminal.prototype.enableLocatorReporting = function(params) { + var val = params[0] > 0; + //this.mouseEvents = val; + //this.decLocator = val; +}; + +// CSI Pt; Pl; Pb; Pr$ z +// Erase Rectangular Area (DECERA), VT400 and up. +// Pt; Pl; Pb; Pr denotes the rectangle. +// NOTE: xterm doesn't enable this code by default. +Terminal.prototype.eraseRectangle = function(params) { + var t = params[0] + , l = params[1] + , b = params[2] + , r = params[3]; + + var line + , i + , ch; + + ch = [this.curAttr, ' ']; // xterm? + + for (; t < b + 1; t++) { + line = this.lines[this.ybase + t]; + for (i = l; i < r; i++) { + line[i] = ch; + } + } + + // this.maxRange(); + this.updateRange(params[0]); + this.updateRange(params[2]); +}; + +// CSI Pm ' { +// Select Locator Events (DECSLE). +// Valid values for the first (and any additional parameters) +// are: +// Ps = 0 -> only respond to explicit host requests (DECRQLP). +// (This is default). It also cancels any filter +// rectangle. +// Ps = 1 -> report button down transitions. +// Ps = 2 -> do not report button down transitions. +// Ps = 3 -> report button up transitions. +// Ps = 4 -> do not report button up transitions. +Terminal.prototype.setLocatorEvents = function(params) { + ; +}; + +// CSI Pt; Pl; Pb; Pr$ { +// Selective Erase Rectangular Area (DECSERA), VT400 and up. +// Pt; Pl; Pb; Pr denotes the rectangle. +Terminal.prototype.selectiveEraseRectangle = function(params) { + ; +}; + +// CSI Ps ' | +// Request Locator Position (DECRQLP). +// Valid values for the parameter are: +// Ps = 0 , 1 or omitted -> transmit a single DECLRP locator +// report. + +// If Locator Reporting has been enabled by a DECELR, xterm will +// respond with a DECLRP Locator Report. This report is also +// generated on button up and down events if they have been +// enabled with a DECSLE, or when the locator is detected outside +// of a filter rectangle, if filter rectangles have been enabled +// with a DECEFR. + +// -> CSI Pe ; Pb ; Pr ; Pc ; Pp & w + +// Parameters are [event;button;row;column;page]. +// Valid values for the event: +// Pe = 0 -> locator unavailable - no other parameters sent. +// Pe = 1 -> request - xterm received a DECRQLP. +// Pe = 2 -> left button down. +// Pe = 3 -> left button up. +// Pe = 4 -> middle button down. +// Pe = 5 -> middle button up. +// Pe = 6 -> right button down. +// Pe = 7 -> right button up. +// Pe = 8 -> M4 button down. +// Pe = 9 -> M4 button up. +// Pe = 1 0 -> locator outside filter rectangle. +// ``button'' parameter is a bitmask indicating which buttons are +// pressed: +// Pb = 0 <- no buttons down. +// Pb & 1 <- right button down. +// Pb & 2 <- middle button down. +// Pb & 4 <- left button down. +// Pb & 8 <- M4 button down. +// ``row'' and ``column'' parameters are the coordinates of the +// locator position in the xterm window, encoded as ASCII deci- +// mal. +// The ``page'' parameter is not used by xterm, and will be omit- +// ted. +Terminal.prototype.requestLocatorPosition = function(params) { + ; +}; + +// CSI P m SP } +// Insert P s Column(s) (default = 1) (DECIC), VT420 and up. +// NOTE: xterm doesn't enable this code by default. +Terminal.prototype.insertColumns = function() { + var param = params[0] + , l = this.ybase + this.rows + , ch = [this.curAttr, ' '] // xterm? + , i; + + while (param--) { + for (i = this.ybase; i < l; i++) { + this.lines[i].splice(this.x + 1, 0, ch); + this.lines[i].pop(); + } + } + + this.maxRange(); +}; + +// CSI P m SP ~ +// Delete P s Column(s) (default = 1) (DECDC), VT420 and up +// NOTE: xterm doesn't enable this code by default. +Terminal.prototype.deleteColumns = function() { + var param = params[0] + , l = this.ybase + this.rows + , ch = [this.curAttr, ' '] // xterm? + , i; + + while (param--) { + for (i = this.ybase; i < l; i++) { + this.lines[i].splice(this.x, 1); + this.lines[i].push(ch); + } + } + + this.maxRange(); +}; + +/** + * Character Sets + */ + +Terminal.charsets = {}; + +// DEC Special Character and Line Drawing Set. +// http://vt100.net/docs/vt102-ug/table5-13.html +// A lot of curses apps use this if they see TERM=xterm. +// testing: echo -e '\e(0a\e(B' +// The xterm output sometimes seems to conflict with the +// reference above. xterm seems in line with the reference +// when running vttest however. +// The table below now uses xterm's output from vttest. +Terminal.charsets.SCLD = { // (0 + '`': '\u25c6', // '◆' + 'a': '\u2592', // '▒' + 'b': '\u0009', // '\t' + 'c': '\u000c', // '\f' + 'd': '\u000d', // '\r' + 'e': '\u000a', // '\n' + 'f': '\u00b0', // '°' + 'g': '\u00b1', // '±' + 'h': '\u2424', // '\u2424' (NL) + 'i': '\u000b', // '\v' + 'j': '\u2518', // '┘' + 'k': '\u2510', // '┐' + 'l': '\u250c', // '┌' + 'm': '\u2514', // '└' + 'n': '\u253c', // '┼' + 'o': '\u23ba', // '⎺' + 'p': '\u23bb', // '⎻' + 'q': '\u2500', // '─' + 'r': '\u23bc', // '⎼' + 's': '\u23bd', // '⎽' + 't': '\u251c', // '├' + 'u': '\u2524', // '┤' + 'v': '\u2534', // '┴' + 'w': '\u252c', // '┬' + 'x': '\u2502', // '│' + 'y': '\u2264', // '≤' + 'z': '\u2265', // '≥' + '{': '\u03c0', // 'π' + '|': '\u2260', // '≠' + '}': '\u00a3', // '£' + '~': '\u00b7' // '·' +}; + +Terminal.charsets.UK = null; // (A +Terminal.charsets.US = null; // (B (USASCII) +Terminal.charsets.Dutch = null; // (4 +Terminal.charsets.Finnish = null; // (C or (5 +Terminal.charsets.French = null; // (R +Terminal.charsets.FrenchCanadian = null; // (Q +Terminal.charsets.German = null; // (K +Terminal.charsets.Italian = null; // (Y +Terminal.charsets.NorwegianDanish = null; // (E or (6 +Terminal.charsets.Spanish = null; // (Z +Terminal.charsets.Swedish = null; // (H or (7 +Terminal.charsets.Swiss = null; // (= +Terminal.charsets.ISOLatin = null; // /A + +/** + * Helpers + */ + +function on(el, type, handler, capture) { + el.addEventListener(type, handler, capture || false); +} + +function off(el, type, handler, capture) { + el.removeEventListener(type, handler, capture || false); +} + +function cancel(ev) { + if (ev.preventDefault) ev.preventDefault(); + ev.returnValue = false; + if (ev.stopPropagation) ev.stopPropagation(); + ev.cancelBubble = true; + return false; +} + +function inherits(child, parent) { + function f() { + this.constructor = child; + } + f.prototype = parent.prototype; + child.prototype = new f; +} + +var isMac = ~navigator.userAgent.indexOf('Mac'); + +// if bold is broken, we can't +// use it in the terminal. +function isBoldBroken() { + var el = document.createElement('span'); + el.innerHTML = 'hello world'; + document.body.appendChild(el); + var w1 = el.scrollWidth; + el.style.fontWeight = 'bold'; + var w2 = el.scrollWidth; + document.body.removeChild(el); + return w1 !== w2; +} + +var String = this.String; +var setTimeout = this.setTimeout; +var setInterval = this.setInterval; + +/** + * Expose + */ + +Terminal.EventEmitter = EventEmitter; +Terminal.isMac = isMac; +Terminal.inherits = inherits; +Terminal.on = on; +Terminal.off = off; +Terminal.cancel = cancel; + +if (typeof module !== 'undefined') { + module.exports = Terminal; +} else { + this.Terminal = Terminal; +} + +}).call(function() { + return this || (typeof window !== 'undefined' ? window : global); +}()); diff --git a/static/js/wssh.js b/static/js/wssh.js new file mode 100644 index 000000000..a7b2aae01 --- /dev/null +++ b/static/js/wssh.js @@ -0,0 +1,89 @@ +/* +WSSH Javascript Client + +Usage: + +var client = new WSSHClient(); + +client.connect({ + // Connection and authentication parameters + username: 'root', + hostname: 'localhost', + authentication_method: 'password', // can either be password or private_key + password: 'secretpassword', // do not provide when using private_key + key_passphrase: 'secretpassphrase', // *may* be provided if the private_key is encrypted + + // Callbacks + onError: function(error) { + // Called upon an error + console.error(error); + }, + onConnect: function() { + // Called after a successful connection to the server + console.debug('Connected!'); + + client.send('ls\n'); // You can send data back to the server by using WSSHClient.send() + }, + onClose: function() { + // Called when the remote closes the connection + console.debug('Connection Reset By Peer'); + }, + onData: function(data) { + // Called when data is received from the server + console.debug('Received: ' + data); + } +}); + +*/ + +function WSSHClient() { +}; + +WSSHClient.prototype._generateEndpoint = function(options) { + console.log(options); + if (window.location.protocol == 'https:') { + var protocol = 'wss://'; + } else { + var protocol = 'ws://'; + } + + var endpoint = protocol + window.location.host + ':8080' + '/terminal'; + return endpoint; +}; + +WSSHClient.prototype.connect = function(options) { + var endpoint = this._generateEndpoint(options); + + if (window.WebSocket) { + this._connection = new WebSocket(endpoint); + } + else if (window.MozWebSocket) { + this._connection = MozWebSocket(endpoint); + } + else { + options.onError('WebSocket Not Supported'); + return ; + } + + this._connection.onopen = function() { + options.onConnect(); + }; + + this._connection.onmessage = function (evt) { + var data = JSON.parse(evt.data.toString()); + if (data.error !== undefined) { + options.onError(data.error); + } + else { + options.onData(data.data); + } + }; + + this._connection.onclose = function(evt) { + options.onClose(); + }; +}; + +WSSHClient.prototype.send = function(data) { + this._connection.send(JSON.stringify({'data': data})); +}; diff --git a/templates/jlog/web_terminal.html b/templates/jlog/web_terminal.html new file mode 100644 index 000000000..6f5649443 --- /dev/null +++ b/templates/jlog/web_terminal.html @@ -0,0 +1,275 @@ + + + + + wssh + + + + + + + + +
+ + +
+
+ Connect to a remote SSH server + +
+ +
+ +
+ @ + port +
+
+
+ +
+ + +
+ + + +
+
+ +
+ +
+ +
+
+ +
+
+ +
+ +

+ Copy & Paste your SSH private from + ~/.ssh/id_rsa or + ~/.ssh/id_dsa +

+
+
+ +
+ +
+ +

+ Enter your private key passphrase if it + is encrypted. Leave empty otherwise. +

+
+
+
+ +
+ +
+ +

+ Enter command to be executed or + empty for interactive. +

+
+
+ +
+ +
+ +
+
+ +
+
+ +
+ + + + + + + + +