├── README.md ├── static ├── favicon.ico ├── bundle │ ├── ._jquery.min.js │ ├── bundle.bemjson.js │ ├── bundle.bemdecl.js │ ├── bundle.html │ └── bundle.deps.js ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff ├── bundle.html ├── js │ ├── angular-rickshaw.coffee │ ├── ws.coffee │ ├── angular-rickshaw.js │ ├── ws.js │ └── vendor │ │ ├── cubism.min.js │ │ └── bootstrap.min.js └── css │ ├── rickshaw.css │ ├── custom.css │ ├── bootstrap-theme.min.css │ ├── bootstrap-theme.css.map │ └── bootstrap-theme.css ├── t.py ├── events.py ├── qrcode_emitter.py ├── rps.py ├── tank.py ├── users.py ├── midi_emitter.py ├── templates └── index.jade ├── top.py ├── server.py ├── start.py └── LICENSE.txt /README.md: -------------------------------------------------------------------------------- 1 | There is a treasure hidden elsewhere 2 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yandex/opensourcestand/master/static/favicon.ico -------------------------------------------------------------------------------- /t.py: -------------------------------------------------------------------------------- 1 | import zmq 2 | 3 | ctx = zmq.Context() 4 | s = ctx.socket(zmq.PUSH) 5 | s.bind('tcp://127.0.0.1:43000') 6 | -------------------------------------------------------------------------------- /static/bundle/._jquery.min.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yandex/opensourcestand/master/static/bundle/._jquery.min.js -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yandex/opensourcestand/master/static/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yandex/opensourcestand/master/static/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yandex/opensourcestand/master/static/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/bundle/bundle.bemjson.js: -------------------------------------------------------------------------------- 1 | ({ 2 | block: 'page', 3 | js: true, 4 | styles: [ 5 | { elem: 'css', url: 'bundle/bundle.min.css' } 6 | ], 7 | scripts: [ 8 | { elem: 'js', url: 'bundle/bundle.min.js' } 9 | ] 10 | }) 11 | -------------------------------------------------------------------------------- /static/bundle/bundle.bemdecl.js: -------------------------------------------------------------------------------- 1 | exports.blocks = [ 2 | { 3 | "name": "page" 4 | }, 5 | { 6 | "name": "page", 7 | "elems": [ 8 | { 9 | "name": "css" 10 | } 11 | ] 12 | }, 13 | { 14 | "name": "page", 15 | "elems": [ 16 | { 17 | "name": "js" 18 | } 19 | ] 20 | } 21 | ]; 22 | -------------------------------------------------------------------------------- /static/bundle.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /static/bundle/bundle.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /events.py: -------------------------------------------------------------------------------- 1 | 2 | class Event(object): 3 | pass 4 | 5 | class MidiEvent(Event): 6 | def __init__(self, drum, url): 7 | self.drum = drum 8 | self.url = url 9 | 10 | def __str__(self): 11 | return '' % (self.drum, self.url) 12 | 13 | class QRCodeEvent(Event): 14 | def __init__(self, text): 15 | self.text = text 16 | 17 | def __str__(self): 18 | return '' % (self.text) 19 | -------------------------------------------------------------------------------- /qrcode_emitter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import serial 3 | import events 4 | import tornado 5 | import logging 6 | 7 | class Emitter(object): 8 | def __init__(self, state, ioloop): 9 | self.state = state 10 | self.ioloop = ioloop 11 | self.data = '' 12 | 13 | def on_data(self, fd, evs): 14 | char = self.scanner.read(1) 15 | 16 | if char == '\r': 17 | return 18 | 19 | if char == '\n': 20 | # http://yaconf.yandex.net/?1281377701 21 | userid = self.data.split('?')[1] 22 | ev = events.QRCodeEvent(userid) 23 | self.state.post_event(ev) 24 | self.data = '' 25 | return 26 | 27 | self.data += char 28 | 29 | def run(self, port, baudrate=9600): 30 | self.scanner = serial.Serial(port, baudrate) 31 | self.ioloop.add_handler(self.scanner.fileno(), self.on_data, tornado.ioloop.IOLoop.READ) 32 | 33 | -------------------------------------------------------------------------------- /rps.py: -------------------------------------------------------------------------------- 1 | class RPSCounter(object): 2 | H4X0R = ['tom1', 'tom2', 'floor_tom', 'tom2', 'tom2', 'floor_tom', 'ride_edge'] 3 | 4 | def __init__(self): 5 | self.hresult = False 6 | self.cleanup() 7 | 8 | def cleanup(self): 9 | self.counter = 0 10 | self.lsl = [] 11 | self.h4x0r_list = [] 12 | 13 | def update(self, ts): 14 | if self.lsl: 15 | while self.lsl and ts - self.lsl[0][0] > 1: 16 | self.lsl.pop(0) 17 | 18 | def add_event(self, ts, event): 19 | self.counter += 1 20 | self.lsl.append((ts, event)) 21 | self.update(ts) 22 | 23 | self.h4x0r_list.append(event.drum) 24 | diff = len(self.h4x0r_list) - len(RPSCounter.H4X0R) 25 | if diff > 0: 26 | del self.h4x0r_list[:diff] 27 | 28 | if self.h4x0r_list == RPSCounter.H4X0R and not self.hresult: 29 | raise Exception("H4X0R") 30 | 31 | def current_rps(self, ts): 32 | self.update(ts) 33 | return len(self.lsl) 34 | -------------------------------------------------------------------------------- /tank.py: -------------------------------------------------------------------------------- 1 | import os 2 | import zmq 3 | import logging 4 | 5 | class Tank(object): 6 | def __init__(self, host, port): 7 | self.host = host 8 | self.port = port 9 | 10 | def run(self): 11 | self.context = zmq.Context() 12 | self.sock = self.context.socket(zmq.PUSH) 13 | logging.info('binding to \'tcp://0.0.0.0:%s\'' % (self.port, )) 14 | self.sock.bind('tcp://0.0.0.0:%s' % (self.port, )) 15 | 16 | def start(self): 17 | logging.info('Starting tank') 18 | os.system("ssh %s /bin/bash -c ~/start_tank.sh" % (self.host, )) 19 | 20 | def check(self): 21 | logging.info('Checking tank') 22 | if not self.sock.poll(100, zmq.POLLOUT): 23 | raise Exception('Tank is not ready') 24 | #self.sock.send_json((0,), zmq.NOBLOCK) 25 | 26 | def stop(self): 27 | logging.info('Stopping tank') 28 | try: 29 | self.sock.send_json(('stop', ), zmq.NOBLOCK) 30 | except: 31 | logging.error('Tank is not responding') 32 | 33 | def fire(self, url, drum): 34 | logging.debug('Firing with drum %s to url %s' % (drum, url)) 35 | self.sock.send_json([0, url, drum], zmq.NOBLOCK) 36 | 37 | -------------------------------------------------------------------------------- /users.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | class User(object): 4 | def __init__(self, id, name): 5 | self.id = id 6 | self.name = name 7 | self.points = 0 8 | self.improvement = False 9 | 10 | def __str__(self): 11 | return '' % (self.id, self.name) 12 | 13 | class Userlist(object): 14 | def __init__(self): 15 | self.db = sqlite3.connect('users.db') 16 | 17 | def get_user(self, id): 18 | c = self.db.cursor() 19 | row = c.execute('SELECT id, name FROM users WHERE id = ?', (id, )).fetchone() 20 | 21 | if row: 22 | return User(row[0], row[1]) 23 | 24 | raise KeyError('Unknown user') 25 | 26 | if __name__ == '__main__': 27 | users = Userlist() 28 | c = users.db.cursor() 29 | 30 | try: 31 | c.execute('CREATE TABLE users (id text PRIMARY KEY, name text, email text)') 32 | except: 33 | pass 34 | 35 | def cleanup(): 36 | c.execute('DELETE FROM users') 37 | #cleanup() 38 | #for i in range(100): 39 | # c.execute('INSERT INTO users VALUES (?, ?, ?)', ('testuser%d' % i, 'Test User %d' %i, 'test email')) 40 | #users.db.commit() 41 | 42 | #print users.get_user('testuser1') 43 | -------------------------------------------------------------------------------- /midi_emitter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import midi 3 | import midi.sequencer as sequencer 4 | import threading 5 | import logging 6 | import events 7 | 8 | drums_mapping = { 9 | 48: 'tom1', 10 | 45: 'tom2', 11 | 43: 'floor_tom', 12 | 38: 'snare', 13 | 40: 'snare_rim', 14 | 46: 'hat', 15 | 26: 'hat_edge', 16 | 42: 'hat_closed', 17 | 22: 'hat_closed_edge', 18 | 54: 'crash', 19 | 55: 'crash_edge', 20 | 51: 'ride', 21 | 53: 'ride_edge', 22 | 36: 'bass', 23 | } 24 | 25 | #44: 'hat_pedal', 26 | urls_mapping = { 27 | 'tom1': '/', 28 | 'tom2': '/', 29 | 'floor_tom': '/', 30 | 'snare': '/cpu_burn', 31 | 'snare_rim': '/', 32 | 'hat': '/', 33 | 'hat_edge': '/', 34 | 'hat_closed': '/', 35 | 'hat_closed_edge': '/', 36 | 'hat_pedal': '/', 37 | 'crash': '/', 38 | 'crash_edge': '/', 39 | 'ride': '/', 40 | 'ride_edge': '/', 41 | 'bass': '/heavy', 42 | } 43 | 44 | class Emitter(object): 45 | def __init__(self, state): 46 | self.state = state 47 | 48 | def run(self, client, port): 49 | self.seq = sequencer.SequencerRead(sequencer_resolution=120) 50 | self.seq.subscribe_port(client, port) 51 | 52 | self.th = threading.Thread(target=Emitter.event_reader, args=(self,)) 53 | self.th.daemon = True 54 | self.th.start() 55 | 56 | def event_reader(self): 57 | self.seq.start_sequencer() 58 | while True: 59 | event = self.seq.event_read() 60 | if isinstance(event, midi.NoteOnEvent): 61 | try: 62 | logging.debug('MIDI ALSA event: %s' % event) 63 | drum = drums_mapping[event.data[0]] 64 | ev = events.MidiEvent(drum, urls_mapping[drum]) 65 | logging.debug('MIDI event: %s' % ev) 66 | self.state.post_event(ev) 67 | except: 68 | pass 69 | 70 | -------------------------------------------------------------------------------- /templates/index.jade: -------------------------------------------------------------------------------- 1 | !!! 5 2 | html(lang="en") 3 | head 4 | meta(charset="utf-8") 5 | meta(http-equiv="X-UA-Compatible", content="IE=edge") 6 | meta(name="viewport", content="width=device-width, initial-scale=1") 7 | title Yandex.Tank online report 8 | link(rel="shortcut icon", href="static/favicon.ico", type="image/x-icon") 9 | link(rel="icon", href="static/favicon.ico", type="image/x-icon") 10 | link(rel="stylesheet", href="static/css/bootstrap.min.css") 11 | link(rel="stylesheet", href="static/css/bootstrap-theme.min.css") 12 | link(rel="stylesheet", href="static/css/rickshaw.css") 13 | link(rel="stylesheet", href="static/css/custom.css") 14 | script(src="static/js/vendor/socket.io.min.js") 15 | script(src="static/js/vendor/jquery.min.js") 16 | script(src="static/js/vendor/angular.min.js") 17 | script(src="static/js/vendor/bootstrap.min.js") 18 | script(src="static/js/vendor/d3.min.js") 19 | script(src="static/js/vendor/rickshaw.min.js") 20 | script(src="static/js/angular-rickshaw.js") 21 | script(src="static/js/ws.js") 22 | script(type="text/javascript") 23 | document.cached_data = {{cached_data}}; 24 | body 25 | .app.container(ng-app="ng-tank-report", ng-controller="TankReport") 26 | h1.page-header Yandex.Tank online report 27 | #status {{!status}} 28 | #timings 29 | .panel.panel-default 30 | .panel-heading 31 | h3.panel-title {{!quantiles.name}} 32 | .panel-body 33 | rickshaw.panel-body( 34 | rickshaw-series="quantiles.series", 35 | rickshaw-options="quantiles.options", 36 | rickshaw-features="quantiles.features" 37 | ) 38 | .panel.panel-default 39 | .panel-heading 40 | h3.panel-title {{!rps.name}} 41 | .panel-body 42 | rickshaw( 43 | rickshaw-series="rps.series", 44 | rickshaw-options="rps.options", 45 | rickshaw-features="rps.features" 46 | ) 47 | #monitoring 48 | .host(ng-repeat="host in monitoringData") 49 | h3 {{!host.hostname}} 50 | .panel.panel-default(ng-repeat="group in host.groups") 51 | .panel-heading 52 | h3.panel-title {{!group.name}} 53 | .panel-body 54 | rickshaw( 55 | rickshaw-series="group.series", 56 | rickshaw-options="group.options", 57 | rickshaw-features="group.features" 58 | ) 59 | -------------------------------------------------------------------------------- /top.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | 3 | class Top(object): 4 | def __init__(self): 5 | self.db = sqlite3.connect('top.db') 6 | 7 | def add_result(self, user, points): 8 | user.points = points 9 | user.improvement = True 10 | c = self.db.cursor() 11 | 12 | c.execute('INSERT INTO attempts VALUES(datetime("now"), ?, ?)', (user.id, points)) 13 | 14 | row = c.execute('SELECT userid, points FROM rating WHERE userid = ?', (user.id, )).fetchone() 15 | if not row or row[1] < points: 16 | c.execute('INSERT OR REPLACE INTO rating VALUES (datetime("now"), ?, ?, ?)', (user.id, user.name, points)) 17 | elif row: 18 | user.points = row[1] 19 | user.improvement = False 20 | 21 | self.db.commit() 22 | 23 | def add_hresult(self, user): 24 | c = self.db.cursor() 25 | row = c.execute('SELECT * from hrating').fetchone() 26 | if row: 27 | return row 28 | c.execute('INSERT INTO hrating VALUES (datetime("now"), ?)', (user.id,)) 29 | self.db.commit() 30 | return None 31 | 32 | def get_hresults(self): 33 | c = self.db.cursor() 34 | return c.execute('SELECT * from hrating').fetchone() 35 | 36 | def get_results(self, user): 37 | c = self.db.cursor() 38 | 39 | rating = [] 40 | place = 0 41 | found = False 42 | 43 | for row in c.execute('SELECT date, userid, username, points FROM rating ORDER BY points DESC'): 44 | place += 1 45 | rec = dict(zip(('date', 'userid', 'user', 'points'), row)) 46 | 47 | if place > 10: 48 | if found or user is None: 49 | break 50 | 51 | if rec['userid'] != user.id: 52 | continue 53 | 54 | rec['place'] = place 55 | rec['current'] = False 56 | 57 | if user and rec['userid'] == user.id: 58 | rec['current'] = True 59 | rec['improvement'] = user.improvement 60 | found = True 61 | 62 | rating.append(rec) 63 | 64 | return rating 65 | 66 | 67 | if __name__ == '__main__': 68 | top = Top() 69 | c = top.db.cursor() 70 | 71 | try: 72 | c.execute('CREATE TABLE rating (date text, userid text PRIMARY KEY, username text, points integer)') 73 | except: 74 | pass 75 | 76 | try: 77 | c.execute('CREATE TABLE hrating (date text, userid text)') 78 | except: 79 | pass 80 | 81 | try: 82 | c.execute('CREATE TABLE attempts (date text, userid test, points integer)') 83 | except: 84 | pass 85 | 86 | 87 | def cleanup(): 88 | c.execute('DELETE FROM rating') 89 | c.execute('DELETE FROM hrating') 90 | c.execute('DELETE FROM attempts') 91 | #cleanup() 92 | #for i in range(100): 93 | # top.add_result('testuser%d' % i, 'Test User %d' %i, 100 * i) 94 | 95 | #from pprint import pprint 96 | #pprint(top.get_results('testuser')) 97 | 98 | #c.execute('DELETE FROM hrating') 99 | #print c.execute('SELECT * from hrating').fetchone() 100 | #top.db.commit() 101 | #print top.add_hresult('testuser') 102 | -------------------------------------------------------------------------------- /static/js/angular-rickshaw.coffee: -------------------------------------------------------------------------------- 1 | ###* 2 | Based on https://github.com/ngyewch/angular-rickshaw 3 | ### 4 | "use strict" 5 | 6 | angular.module("angular-rickshaw", []).directive "rickshaw", ($compile) -> 7 | restrict: "EA" 8 | scope: 9 | options: "=rickshawOptions" 10 | series: "=rickshawSeries" 11 | features: "=rickshawFeatures" 12 | 13 | 14 | # replace: true, 15 | link: (scope, element, attrs) -> 16 | getSettings = (el) -> 17 | settings = angular.copy(scope.options) 18 | settings.element = el 19 | settings.series = scope.series 20 | settings 21 | update = -> 22 | mainEl = angular.element(element) 23 | mainEl.append graphEl 24 | mainEl.empty() 25 | graphEl = $compile("
")(scope) 26 | mainEl.append graphEl 27 | settings = getSettings(graphEl[0]) 28 | scope.graph = new Rickshaw.Graph(settings) 29 | if scope.features and scope.features.hover 30 | hoverConfig = graph: scope.graph 31 | hoverConfig.xFormatter = scope.features.hover.xFormatter 32 | hoverConfig.yFormatter = scope.features.hover.yFormatter 33 | hoverConfig.formatter = scope.features.hover.formatter 34 | hoverDetail = new Rickshaw.Graph.HoverDetail(hoverConfig) 35 | if scope.features and scope.features.palette 36 | palette = new Rickshaw.Color.Palette(scheme: scope.features.palette) 37 | i = 0 38 | 39 | while i < settings.series.length 40 | settings.series[i].color = palette.color() 41 | i++ 42 | scope.graph.render() 43 | if scope.features and scope.features.xAxis 44 | xAxisConfig = graph: scope.graph 45 | if scope.features.xAxis.timeUnit 46 | time = new Rickshaw.Fixtures.Time() 47 | xAxisConfig.timeUnit = time.unit(scope.features.xAxis.timeUnit) 48 | xAxis = new Rickshaw.Graph.Axis.Time(xAxisConfig) 49 | xAxis.render() 50 | if scope.features and scope.features.yAxis 51 | yAxisConfig = graph: scope.graph 52 | yAxisConfig.tickFormat = Rickshaw.Fixtures.Number[scope.features.yAxis.tickFormat] if scope.features.yAxis.tickFormat 53 | yAxis = new Rickshaw.Graph.Axis.Y(yAxisConfig) 54 | yAxis.render() 55 | if scope.features and scope.features.legend 56 | legendEl = $compile("
")(scope) 57 | mainEl.append legendEl 58 | legend = new Rickshaw.Graph.Legend( 59 | graph: scope.graph 60 | element: legendEl[0] 61 | ) 62 | if scope.features.legend.toggle 63 | shelving = new Rickshaw.Graph.Behavior.Series.Toggle( 64 | graph: scope.graph 65 | legend: legend 66 | ) 67 | if scope.features.legend.highlight 68 | highlighter = new Rickshaw.Graph.Behavior.Series.Highlight( 69 | graph: scope.graph 70 | legend: legend 71 | ) 72 | return 73 | scope.graph = undefined 74 | scope.$watch "options", (newValue, oldValue) -> 75 | update() unless angular.equals(newValue, oldValue) 76 | return 77 | 78 | scope.$watch "series", (newValue, oldValue) -> 79 | update() unless angular.equals(newValue, oldValue) 80 | return 81 | 82 | scope.$watch "features", (newValue, oldValue) -> 83 | update() unless angular.equals(newValue, oldValue) 84 | return 85 | 86 | scope.$on "DataUpdated", () -> 87 | scope.graph.update() 88 | 89 | update() 90 | 91 | controller: ($scope, $element, $attrs) -> 92 | -------------------------------------------------------------------------------- /static/bundle/bundle.deps.js: -------------------------------------------------------------------------------- 1 | exports.deps = [ 2 | { 3 | "block": "i-bem" 4 | }, 5 | { 6 | "block": "i-bem", 7 | "elem": "internal" 8 | }, 9 | { 10 | "block": "inherit" 11 | }, 12 | { 13 | "block": "identify" 14 | }, 15 | { 16 | "block": "next-tick" 17 | }, 18 | { 19 | "block": "objects" 20 | }, 21 | { 22 | "block": "functions" 23 | }, 24 | { 25 | "block": "events" 26 | }, 27 | { 28 | "block": "i-bem", 29 | "mod": "init" 30 | }, 31 | { 32 | "block": "socket" 33 | }, 34 | { 35 | "block": "i-bem", 36 | "elem": "dom" 37 | }, 38 | { 39 | "block": "jquery" 40 | }, 41 | { 42 | "block": "loader" 43 | }, 44 | { 45 | "block": "loader", 46 | "mod": "type" 47 | }, 48 | { 49 | "block": "jquery", 50 | "elem": "config" 51 | }, 52 | { 53 | "block": "ua" 54 | }, 55 | { 56 | "block": "dom" 57 | }, 58 | { 59 | "block": "i-bem", 60 | "elem": "dom", 61 | "mod": "init" 62 | }, 63 | { 64 | "block": "page", 65 | "elem": "css" 66 | }, 67 | { 68 | "block": "page", 69 | "elem": "js" 70 | }, 71 | { 72 | "block": "chart" 73 | }, 74 | { 75 | "block": "user" 76 | }, 77 | { 78 | "block": "user", 79 | "mod": "active" 80 | }, 81 | { 82 | "block": "user", 83 | "elem": "info" 84 | }, 85 | { 86 | "block": "user", 87 | "elem": "level" 88 | }, 89 | { 90 | "block": "user", 91 | "elem": "level-star" 92 | }, 93 | { 94 | "block": "user", 95 | "elem": "name" 96 | }, 97 | { 98 | "block": "user", 99 | "elem": "place" 100 | }, 101 | { 102 | "block": "welcome" 103 | }, 104 | { 105 | "block": "welcome", 106 | "mod": "countdown" 107 | }, 108 | { 109 | "block": "welcome", 110 | "elem": "call-to-action" 111 | }, 112 | { 113 | "block": "welcome", 114 | "elem": "image" 115 | }, 116 | { 117 | "block": "image" 118 | }, 119 | { 120 | "block": "welcome", 121 | "elem": "text" 122 | }, 123 | { 124 | "block": "welcome", 125 | "elem": "time-to-ready" 126 | }, 127 | { 128 | "block": "shooting" 129 | }, 130 | { 131 | "block": "shooting", 132 | "elem": "bullets" 133 | }, 134 | { 135 | "block": "shooting", 136 | "elem": "scores" 137 | }, 138 | { 139 | "block": "shooting", 140 | "elem": "timer" 141 | }, 142 | { 143 | "block": "page", 144 | "elem": "wrap" 145 | }, 146 | { 147 | "block": "i-bem", 148 | "mod": "init", 149 | "val": "auto" 150 | }, 151 | { 152 | "block": "i-bem", 153 | "elem": "dom", 154 | "mod": "init", 155 | "val": "auto" 156 | }, 157 | { 158 | "block": "loader", 159 | "mod": "type", 160 | "val": "js" 161 | }, 162 | { 163 | "block": "user", 164 | "mod": "active", 165 | "val": true 166 | }, 167 | { 168 | "block": "welcome", 169 | "mod": "countdown", 170 | "val": true 171 | }, 172 | { 173 | "block": "page" 174 | } 175 | ]; 176 | -------------------------------------------------------------------------------- /static/js/ws.coffee: -------------------------------------------------------------------------------- 1 | app = angular.module("ng-tank-report", ["angular-rickshaw"]) 2 | 3 | collect_subtree = (storage, subtree, ts) -> 4 | for key, node of subtree 5 | if typeof node is 'number' or typeof node is 'array' 6 | storage[key].push 7 | x: ts 8 | y: node 9 | else 10 | collect_subtree(storage[key], node, ts) 11 | 12 | app.controller "TankReport", ($scope, $element) -> 13 | $scope.status = "Disconnected" 14 | $scope.data = document.cached_data.data 15 | $scope.uuid = document.cached_data.uuid 16 | $scope.updateData = (tankData) -> 17 | for ts, storages of tankData 18 | for storage, data of storages 19 | collect_subtree $scope.data[storage], data, +ts 20 | $scope.$broadcast 'DataUpdated' 21 | $scope.buildSeries = () -> 22 | if $scope.data.responses and $scope.data.responses.overall 23 | overallData = $scope.data.responses.overall 24 | else 25 | overallData = {} 26 | setTimeout((() -> location.reload(true)), 3000) 27 | areaGraphs = ['CPU', 'Memory'] 28 | $scope.monitoringData = ( 29 | ({ 30 | hostname: hostname 31 | groups: ({ 32 | name: groupName 33 | features: 34 | palette: 'spectrum14' 35 | hover: {} 36 | xAxis: {} 37 | yAxis: {} 38 | legend: 39 | toggle: true 40 | highlight: true 41 | options: 42 | renderer: if groupName in areaGraphs then 'area' else 'line' 43 | series: ({ 44 | name: name 45 | data: data 46 | } for name, data of series) 47 | } for groupName, series of groups) 48 | } for hostname, groups of $scope.data.monitoring) 49 | ) 50 | $scope.quantiles = 51 | name: "Response time quantiles" 52 | features: 53 | palette: 'classic9' 54 | hover: {} 55 | xAxis: {} 56 | yAxis: {} 57 | legend: 58 | toggle: true 59 | highlight: true 60 | options: 61 | renderer: 'area' 62 | stack: false 63 | height: $element[0].offsetHeight - 45 - 62 64 | series: ({ 65 | name: name 66 | data: data 67 | } for name, data of overallData.quantiles).sort (a, b) -> 68 | return if parseFloat(a.name) <= parseFloat(b.name) then 1 else -1 69 | $scope.rps = 70 | name: "Responses per second" 71 | features: 72 | palette: 'spectrum14' 73 | hover: {} 74 | xAxis: {} 75 | yAxis: {} 76 | legend: 77 | toggle: true 78 | highlight: true 79 | options: 80 | renderer: 'line' 81 | series: [ 82 | name: 'RPS' 83 | data: overallData.RPS 84 | ] 85 | 86 | $scope.buildSeries() 87 | 88 | conn = new io.connect("http://#{window.location.host}", 89 | 'reconnection limit' : 1000 90 | 'max reconnection attempts' : 'Infinity' 91 | ) 92 | setInterval(( 93 | () ->conn.emit('heartbeat') 94 | ), 3000) 95 | conn.on 'connect', () => 96 | console.log("Connection opened...") 97 | $scope.status = "Connected" 98 | 99 | $scope.$apply() 100 | 101 | conn.on 'disconnect', () => 102 | console.log("Connection closed...") 103 | $scope.status = "Disonnected" 104 | $scope.$apply() 105 | conn.on 'reload', () => 106 | location.reload(true) 107 | conn.on 'message', (msg) => 108 | tankData = JSON.parse msg 109 | if tankData.uuid and $scope.uuid != tankData.uuid 110 | location.reload(true) 111 | else 112 | $scope.updateData(tankData.data) 113 | -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import logging 4 | import tornado.ioloop 5 | import tornado.web 6 | import os.path 7 | import json 8 | import uuid 9 | from tornado import template 10 | from pyjade.ext.tornado import patch_tornado 11 | patch_tornado() 12 | 13 | from tornadio2 import SocketConnection, TornadioRouter, SocketServer, event 14 | 15 | from threading import Thread 16 | 17 | 18 | class Client(SocketConnection): 19 | CONNECTIONS = set() 20 | 21 | def on_open(self, info): 22 | #print 'Client connected' 23 | self.CONNECTIONS.add(self) 24 | self.emit('event', {'data': {'state': 0}}) 25 | 26 | def on_message(self, msg): 27 | print 'Got', msg 28 | 29 | def on_close(self): 30 | #print 'Client disconnected' 31 | self.CONNECTIONS.remove(self) 32 | 33 | @event('heartbeat') 34 | def on_heartbeat(self): 35 | pass 36 | 37 | class MainHandler(tornado.web.RequestHandler): 38 | def initialize(self, template, reportUUID, state): 39 | self.template = template 40 | self.reportUUID = reportUUID 41 | self.state = state 42 | 43 | def get(self): 44 | if self.state is not None: 45 | cached_data = { 46 | 'data': self.state.get_current_state(), 47 | 'uuid': self.reportUUID, 48 | } 49 | else: 50 | cached_data = { 51 | 'data':{}, 52 | 'uuid': self.reportUUID, 53 | } 54 | self.render(self.template, cached_data=json.dumps(cached_data)) 55 | 56 | class JsonHandler(tornado.web.RequestHandler): 57 | def initialize(self, reportUUID, state): 58 | self.reportUUID = reportUUID 59 | self.state = state 60 | 61 | def get(self): 62 | if self.state is not None: 63 | cached_data = { 64 | 'data': self.get_data(), 65 | 'uuid': self.reportUUID, 66 | } 67 | else: 68 | cached_data = { 69 | 'data':{}, 70 | 'uuid': self.reportUUID, 71 | } 72 | self.set_status(200) 73 | self.set_header("Content-type", "application/json") 74 | self.finish(json.dumps(cached_data)) 75 | 76 | def get_data(self): 77 | raise Exception('Not implemented') 78 | 79 | class DataHandler(JsonHandler): 80 | def get_data(self): 81 | return self.state.get_current_state() 82 | 83 | class ResultsHandler(JsonHandler): 84 | def get_data(self): 85 | return self.state.get_results() 86 | 87 | 88 | class TopServer(object): 89 | def __init__(self, state): 90 | router = TornadioRouter(Client) 91 | self.reportUUID = uuid.uuid4().hex 92 | self.app = tornado.web.Application( 93 | router.apply_routes([ 94 | (r"/", MainHandler, dict(template='index.jade', reportUUID=self.reportUUID, state=state)), 95 | (r"/data\.json$", DataHandler, dict(reportUUID=self.reportUUID, state=state)), 96 | (r"/toplist\.json$", ResultsHandler, dict(reportUUID=self.reportUUID, state=state)), 97 | ]), 98 | template_path=os.path.join(os.path.dirname(__file__), "templates"), 99 | static_path=os.path.join(os.path.dirname(__file__), "static"), 100 | debug=True, 101 | ) 102 | 103 | def run(self, ioloop): 104 | self.server = SocketServer(self.app, io_loop=ioloop, auto_start=False) 105 | 106 | def send(self, data): 107 | for connection in Client.CONNECTIONS: 108 | ev = {} 109 | ev['uuid'] = self.reportUUID 110 | ev['data'] = data 111 | #print "Sending data to client ", connection 112 | connection.emit('event', ev) 113 | 114 | def reload(self): 115 | for connection in Client.CONNECTIONS: 116 | connection.emit('reload') 117 | -------------------------------------------------------------------------------- /static/js/angular-rickshaw.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | Based on https://github.com/ngyewch/angular-rickshaw 4 | */ 5 | 6 | (function() { 7 | "use strict"; 8 | angular.module("angular-rickshaw", []).directive("rickshaw", function($compile) { 9 | return { 10 | restrict: "EA", 11 | scope: { 12 | options: "=rickshawOptions", 13 | series: "=rickshawSeries", 14 | features: "=rickshawFeatures" 15 | }, 16 | link: function(scope, element, attrs) { 17 | var getSettings, update; 18 | getSettings = function(el) { 19 | var settings; 20 | settings = angular.copy(scope.options); 21 | settings.element = el; 22 | settings.series = scope.series; 23 | return settings; 24 | }; 25 | update = function() { 26 | var graphEl, highlighter, hoverConfig, hoverDetail, i, legend, legendEl, mainEl, palette, settings, shelving, time, xAxis, xAxisConfig, yAxis, yAxisConfig; 27 | mainEl = angular.element(element); 28 | mainEl.append(graphEl); 29 | mainEl.empty(); 30 | graphEl = $compile("
")(scope); 31 | mainEl.append(graphEl); 32 | settings = getSettings(graphEl[0]); 33 | scope.graph = new Rickshaw.Graph(settings); 34 | if (scope.features && scope.features.hover) { 35 | hoverConfig = { 36 | graph: scope.graph 37 | }; 38 | hoverConfig.xFormatter = scope.features.hover.xFormatter; 39 | hoverConfig.yFormatter = scope.features.hover.yFormatter; 40 | hoverConfig.formatter = scope.features.hover.formatter; 41 | hoverDetail = new Rickshaw.Graph.HoverDetail(hoverConfig); 42 | } 43 | if (scope.features && scope.features.palette) { 44 | palette = new Rickshaw.Color.Palette({ 45 | scheme: scope.features.palette 46 | }); 47 | i = 0; 48 | while (i < settings.series.length) { 49 | settings.series[i].color = palette.color(); 50 | i++; 51 | } 52 | } 53 | scope.graph.render(); 54 | if (scope.features && scope.features.xAxis) { 55 | xAxisConfig = { 56 | graph: scope.graph 57 | }; 58 | if (scope.features.xAxis.timeUnit) { 59 | time = new Rickshaw.Fixtures.Time(); 60 | xAxisConfig.timeUnit = time.unit(scope.features.xAxis.timeUnit); 61 | } 62 | xAxis = new Rickshaw.Graph.Axis.Time(xAxisConfig); 63 | xAxis.render(); 64 | } 65 | if (scope.features && scope.features.yAxis) { 66 | yAxisConfig = { 67 | graph: scope.graph 68 | }; 69 | if (scope.features.yAxis.tickFormat) { 70 | yAxisConfig.tickFormat = Rickshaw.Fixtures.Number[scope.features.yAxis.tickFormat]; 71 | } 72 | yAxis = new Rickshaw.Graph.Axis.Y(yAxisConfig); 73 | yAxis.render(); 74 | } 75 | if (scope.features && scope.features.legend) { 76 | legendEl = $compile("
")(scope); 77 | mainEl.append(legendEl); 78 | legend = new Rickshaw.Graph.Legend({ 79 | graph: scope.graph, 80 | element: legendEl[0] 81 | }); 82 | if (scope.features.legend.toggle) { 83 | shelving = new Rickshaw.Graph.Behavior.Series.Toggle({ 84 | graph: scope.graph, 85 | legend: legend 86 | }); 87 | } 88 | if (scope.features.legend.highlight) { 89 | highlighter = new Rickshaw.Graph.Behavior.Series.Highlight({ 90 | graph: scope.graph, 91 | legend: legend 92 | }); 93 | } 94 | } 95 | }; 96 | scope.graph = void 0; 97 | scope.$watch("options", function(newValue, oldValue) { 98 | if (!angular.equals(newValue, oldValue)) { 99 | update(); 100 | } 101 | }); 102 | scope.$watch("series", function(newValue, oldValue) { 103 | if (!angular.equals(newValue, oldValue)) { 104 | update(); 105 | } 106 | }); 107 | scope.$watch("features", function(newValue, oldValue) { 108 | if (!angular.equals(newValue, oldValue)) { 109 | update(); 110 | } 111 | }); 112 | scope.$on("DataUpdated", function() { 113 | return scope.graph.update(); 114 | }); 115 | return update(); 116 | }, 117 | controller: function($scope, $element, $attrs) {} 118 | }; 119 | }); 120 | 121 | }).call(this); 122 | -------------------------------------------------------------------------------- /static/js/ws.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var app, collect_subtree, 3 | __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; 4 | 5 | app = angular.module("ng-tank-report", ["angular-rickshaw"]); 6 | 7 | collect_subtree = function(storage, subtree, ts) { 8 | var key, node, _results; 9 | _results = []; 10 | for (key in subtree) { 11 | node = subtree[key]; 12 | if (typeof node === 'number' || typeof node === 'array') { 13 | _results.push(storage[key].push({ 14 | x: ts, 15 | y: node 16 | })); 17 | } else { 18 | _results.push(collect_subtree(storage[key], node, ts)); 19 | } 20 | } 21 | return _results; 22 | }; 23 | 24 | app.controller("TankReport", function($scope, $element) { 25 | var conn; 26 | $scope.status = "Disconnected"; 27 | $scope.data = document.cached_data.data; 28 | $scope.uuid = document.cached_data.uuid; 29 | $scope.updateData = function(tankData) { 30 | var data, storage, storages, ts; 31 | for (ts in tankData) { 32 | storages = tankData[ts]; 33 | for (storage in storages) { 34 | data = storages[storage]; 35 | collect_subtree($scope.data[storage], data, +ts); 36 | } 37 | } 38 | return $scope.$broadcast('DataUpdated'); 39 | }; 40 | $scope.buildSeries = function() { 41 | var areaGraphs, data, groupName, groups, hostname, name, overallData, series; 42 | if ($scope.data.responses && $scope.data.responses.overall) { 43 | overallData = $scope.data.responses.overall; 44 | } else { 45 | overallData = {}; 46 | setTimeout((function() { 47 | return location.reload(true); 48 | }), 3000); 49 | } 50 | areaGraphs = ['CPU', 'Memory']; 51 | $scope.monitoringData = (function() { 52 | var _ref, _results; 53 | _ref = $scope.data.monitoring; 54 | _results = []; 55 | for (hostname in _ref) { 56 | groups = _ref[hostname]; 57 | _results.push({ 58 | hostname: hostname, 59 | groups: (function() { 60 | var _results1; 61 | _results1 = []; 62 | for (groupName in groups) { 63 | series = groups[groupName]; 64 | _results1.push({ 65 | name: groupName, 66 | features: { 67 | palette: 'spectrum14', 68 | hover: {}, 69 | xAxis: {}, 70 | yAxis: {}, 71 | legend: { 72 | toggle: true, 73 | highlight: true 74 | } 75 | }, 76 | options: { 77 | renderer: __indexOf.call(areaGraphs, groupName) >= 0 ? 'area' : 'line' 78 | }, 79 | series: (function() { 80 | var _results2; 81 | _results2 = []; 82 | for (name in series) { 83 | data = series[name]; 84 | _results2.push({ 85 | name: name, 86 | data: data 87 | }); 88 | } 89 | return _results2; 90 | })() 91 | }); 92 | } 93 | return _results1; 94 | })() 95 | }); 96 | } 97 | return _results; 98 | })(); 99 | $scope.quantiles = { 100 | name: "Response time quantiles", 101 | features: { 102 | palette: 'classic9', 103 | hover: {}, 104 | xAxis: {}, 105 | yAxis: {}, 106 | legend: { 107 | toggle: true, 108 | highlight: true 109 | } 110 | }, 111 | options: { 112 | renderer: 'area', 113 | stack: false, 114 | height: $element[0].offsetHeight - 45 - 62 115 | }, 116 | series: ((function() { 117 | var _ref, _results; 118 | _ref = overallData.quantiles; 119 | _results = []; 120 | for (name in _ref) { 121 | data = _ref[name]; 122 | _results.push({ 123 | name: name, 124 | data: data 125 | }); 126 | } 127 | return _results; 128 | })()).sort(function(a, b) { 129 | if (parseFloat(a.name) <= parseFloat(b.name)) { 130 | return 1; 131 | } else { 132 | return -1; 133 | } 134 | }) 135 | }; 136 | return $scope.rps = { 137 | name: "Responses per second", 138 | features: { 139 | palette: 'spectrum14', 140 | hover: {}, 141 | xAxis: {}, 142 | yAxis: {}, 143 | legend: { 144 | toggle: true, 145 | highlight: true 146 | } 147 | }, 148 | options: { 149 | renderer: 'line' 150 | }, 151 | series: [ 152 | { 153 | name: 'RPS', 154 | data: overallData.RPS 155 | } 156 | ] 157 | }; 158 | }; 159 | $scope.buildSeries(); 160 | conn = new io.connect("http://" + window.location.host, { 161 | 'reconnection limit': 1000, 162 | 'max reconnection attempts': 'Infinity' 163 | }); 164 | setInterval((function() { 165 | return conn.emit('heartbeat'); 166 | }), 3000); 167 | conn.on('connect', (function(_this) { 168 | return function() { 169 | console.log("Connection opened..."); 170 | $scope.status = "Connected"; 171 | return $scope.$apply(); 172 | }; 173 | })(this)); 174 | conn.on('disconnect', (function(_this) { 175 | return function() { 176 | console.log("Connection closed..."); 177 | $scope.status = "Disonnected"; 178 | return $scope.$apply(); 179 | }; 180 | })(this)); 181 | conn.on('reload', (function(_this) { 182 | return function() { 183 | return location.reload(true); 184 | }; 185 | })(this)); 186 | return conn.on('message', (function(_this) { 187 | return function(msg) { 188 | var tankData; 189 | tankData = JSON.parse(msg); 190 | if (tankData.uuid && $scope.uuid !== tankData.uuid) { 191 | return location.reload(true); 192 | } else { 193 | return $scope.updateData(tankData.data); 194 | } 195 | }; 196 | })(this)); 197 | }); 198 | 199 | }).call(this); 200 | -------------------------------------------------------------------------------- /start.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import os 4 | import server 5 | import tornado 6 | import events 7 | import rps 8 | import top 9 | import tank 10 | import users 11 | import midi_emitter 12 | import qrcode_emitter 13 | from tornado import ioloop 14 | from tornado import options 15 | import logging 16 | 17 | 18 | class State(object): 19 | RESULTS=0 20 | GREETINGS=1 21 | COUNTDOWN=2 22 | ACTION=3 23 | HRESULTS=4 24 | 25 | COUNTDOWN_TIME = 3 26 | ACTION_TIME = 60 27 | 28 | 29 | def __init__(self, ioloop): 30 | self.ioloop = ioloop 31 | self.serv = server.TopServer(self) 32 | #self.tank = tank.Tank(options.options.tank, 43000) 33 | self.tank = tank.Tank('192.168.1.2', 43000) 34 | self.state = State.RESULTS 35 | self.user = None 36 | self.rps = rps.RPSCounter() 37 | self.top = top.Top() 38 | self.users = users.Userlist() 39 | 40 | self.timer_counter = None 41 | self.timer_fn = None 42 | self.timer_cb = tornado.ioloop.PeriodicCallback(self.timer, 1000, self.ioloop) 43 | 44 | 45 | def get_current_state(self): 46 | return {'state': self.state, 47 | 'user': self.user.name if self.user else None, 48 | 'timer': self.timer_counter, 49 | 'rps': self.rps.current_rps(self.ioloop.time()), 50 | 'points': self.rps.counter} 51 | 52 | 53 | def get_results(self): 54 | return self.top.get_results(self.user) 55 | 56 | def run(self): 57 | self.timer_cb.start() 58 | self.serv.run(self.ioloop) 59 | self.tank.run() 60 | self.rps.hresult = self.top.get_hresults() 61 | self.ioloop.start() 62 | 63 | 64 | def greetings(self, event): 65 | if (self.state != State.RESULTS): 66 | raise Exception('Incorrect state transcision!') 67 | 68 | # TODO: get user name from QRCode text 69 | self.user = self.users.get_user(event.text) 70 | self.state = State.GREETINGS 71 | logging.info('Hello, %s' % self.user) 72 | self.serv.send(self.get_current_state()) 73 | self.rps.cleanup() 74 | 75 | 76 | def countdown(self): 77 | if (self.state != State.GREETINGS): 78 | raise Exception('Incorrect state transcision!') 79 | 80 | self.state = State.COUNTDOWN 81 | logging.info('Prepare, %s' % self.user) 82 | self.serv.send(self.get_current_state()) 83 | self.timer_counter = State.COUNTDOWN_TIME 84 | self.timer_fn = State.tank_check 85 | self.tank.start() 86 | 87 | 88 | def tank_check(self): 89 | logging.info('Tank check') 90 | try: 91 | self.tank.check() 92 | self.action() 93 | except: 94 | logging.info('Tank check failed') 95 | self.timer_counter = 1 96 | self.timer_fn = State.tank_check 97 | 98 | 99 | def action(self): 100 | if (self.state != State.COUNTDOWN): 101 | raise Exception('Incorrect state transcision!') 102 | 103 | self.state = State.ACTION 104 | logging.info('Go, %s' % self.user) 105 | self.serv.send(self.get_current_state()) 106 | self.timer_counter = State.ACTION_TIME 107 | self.timer_fn = State.results 108 | 109 | 110 | def results(self): 111 | if (self.state != State.ACTION) and (self.state != state.HRESULTS): 112 | raise Exception('Incorrect state transcision!') 113 | 114 | self.tank.stop() 115 | self.state = State.RESULTS 116 | self.serv.send(self.get_current_state()) 117 | logging.info('Resuts for %s' % self.user) 118 | logging.info('Points earned: %d' % self.rps.counter) 119 | self.top.add_result(self.user, self.rps.counter) 120 | logging.info('Stored results: %d, improved: %s' % (self.user.points, self.user.improvement)) 121 | 122 | 123 | def fire(self, event): 124 | try: 125 | self.tank.fire(event.url, event.drum) 126 | self.rps.add_event(self.ioloop.time(), event) 127 | self.serv.send(self.get_current_state()) 128 | except Exception as e: 129 | if e.message and e.message[0] == 'H': 130 | self.hresults() 131 | 132 | 133 | def hresults(self): 134 | if (self.state != State.ACTION): 135 | raise Exception('Incorrect state transcision!') 136 | 137 | logging.info('Pre-hack for %s' % self.user) 138 | if not self.top.add_hresult(self.user): 139 | self.rps.hresult = True 140 | logging.info('Hacked!!') 141 | self.state = State.HRESULTS 142 | self.timer_counter = State.COUNTDOWN_TIME * 5 143 | self.timer_fn = State.results 144 | 145 | 146 | def timer(self): 147 | if self.timer_counter is None: 148 | return 149 | 150 | logging.debug('timer %d' % self.timer_counter) 151 | self.serv.send(self.get_current_state()) 152 | if self.timer_counter > 0: 153 | self.timer_counter -= 1; 154 | 155 | if self.timer_counter == 0: 156 | self.timer_counter = None 157 | self.timer_fn(self) 158 | 159 | 160 | def post_event(self, event): 161 | self.ioloop.add_callback(State.process_event, self, event) 162 | 163 | def process_event(self, event): 164 | logging.debug('Processing event %s, state: %d' % (event, self.state)) 165 | if self.state == State.RESULTS: 166 | if isinstance(event, events.QRCodeEvent): 167 | self.greetings(event) 168 | return 169 | 170 | if isinstance(event, events.MidiEvent): 171 | if (self.state == State.GREETINGS): 172 | self.countdown() 173 | return 174 | 175 | if (self.state == State.ACTION): 176 | self.fire(event) 177 | return 178 | 179 | 180 | options.define('config', type=str, help='Path to config file', 181 | callback=lambda path: options.parse_config_file(path, final=False)) 182 | options.define('tank', type=str, help='Tank host\'s ip address', default='127.0.0.1') 183 | options.define('midi_device', type=int, help='Midi device number', default=24) 184 | options.define('midi_port', type=int, help='Midi port number', default=0) 185 | options.define('qrscanner_port', type=str, help='QRCode scanner port', default='/dev/ttyUSB0') 186 | 187 | options.parse_command_line() 188 | ioloop = ioloop.IOLoop.instance() 189 | 190 | state = State(ioloop) 191 | 192 | MidiE = midi_emitter.Emitter(state) 193 | MidiE.run(options.options.midi_device, options.options.midi_port) 194 | 195 | QRE = qrcode_emitter.Emitter(state, ioloop) 196 | QRE.run(options.options.qrscanner_port) 197 | 198 | state.run() 199 | 200 | -------------------------------------------------------------------------------- /static/css/rickshaw.css: -------------------------------------------------------------------------------- 1 | .rickshaw_graph .detail { 2 | pointer-events: none; 3 | position: absolute; 4 | top: 0; 5 | z-index: 2; 6 | background: rgba(0, 0, 0, 0.1); 7 | bottom: 0; 8 | width: 1px; 9 | transition: opacity 0.25s linear; 10 | -moz-transition: opacity 0.25s linear; 11 | -o-transition: opacity 0.25s linear; 12 | -webkit-transition: opacity 0.25s linear; 13 | } 14 | .rickshaw_graph .detail.inactive { 15 | opacity: 0; 16 | } 17 | .rickshaw_graph .detail .item.active { 18 | opacity: 1; 19 | } 20 | .rickshaw_graph .detail .x_label { 21 | font-family: Arial, sans-serif; 22 | border-radius: 3px; 23 | padding: 6px; 24 | opacity: 0.5; 25 | border: 1px solid #e0e0e0; 26 | font-size: 12px; 27 | position: absolute; 28 | background: white; 29 | white-space: nowrap; 30 | } 31 | .rickshaw_graph .detail .x_label.left { 32 | left: 0; 33 | } 34 | .rickshaw_graph .detail .x_label.right { 35 | right: 0; 36 | } 37 | .rickshaw_graph .detail .item { 38 | position: absolute; 39 | z-index: 2; 40 | border-radius: 3px; 41 | padding: 0.25em; 42 | font-size: 12px; 43 | font-family: Arial, sans-serif; 44 | opacity: 0; 45 | background: rgba(0, 0, 0, 0.4); 46 | color: white; 47 | border: 1px solid rgba(0, 0, 0, 0.4); 48 | margin-left: 1em; 49 | margin-right: 1em; 50 | margin-top: -1em; 51 | white-space: nowrap; 52 | } 53 | .rickshaw_graph .detail .item.left { 54 | left: 0; 55 | } 56 | .rickshaw_graph .detail .item.right { 57 | right: 0; 58 | } 59 | .rickshaw_graph .detail .item.active { 60 | opacity: 1; 61 | background: rgba(0, 0, 0, 0.8); 62 | } 63 | .rickshaw_graph .detail .item:after { 64 | position: absolute; 65 | display: block; 66 | width: 0; 67 | height: 0; 68 | 69 | content: ""; 70 | 71 | border: 5px solid transparent; 72 | } 73 | .rickshaw_graph .detail .item.left:after { 74 | top: 1em; 75 | left: -5px; 76 | margin-top: -5px; 77 | border-right-color: rgba(0, 0, 0, 0.8); 78 | border-left-width: 0; 79 | } 80 | .rickshaw_graph .detail .item.right:after { 81 | top: 1em; 82 | right: -5px; 83 | margin-top: -5px; 84 | border-left-color: rgba(0, 0, 0, 0.8); 85 | border-right-width: 0; 86 | } 87 | .rickshaw_graph .detail .dot { 88 | width: 4px; 89 | height: 4px; 90 | margin-left: -3px; 91 | margin-top: -3.5px; 92 | border-radius: 5px; 93 | position: absolute; 94 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.6); 95 | box-sizing: content-box; 96 | -moz-box-sizing: content-box; 97 | background: white; 98 | border-width: 2px; 99 | border-style: solid; 100 | display: none; 101 | background-clip: padding-box; 102 | } 103 | .rickshaw_graph .detail .dot.active { 104 | display: block; 105 | } 106 | /* graph */ 107 | 108 | .rickshaw_graph { 109 | position: relative; 110 | } 111 | .rickshaw_graph svg { 112 | display: block; 113 | overflow: hidden; 114 | } 115 | 116 | /* ticks */ 117 | 118 | .rickshaw_graph .x_tick { 119 | position: absolute; 120 | top: 0; 121 | bottom: 0; 122 | width: 0px; 123 | border-left: 1px dotted rgba(0, 0, 0, 0.2); 124 | pointer-events: none; 125 | } 126 | .rickshaw_graph .x_tick .title { 127 | position: absolute; 128 | font-size: 12px; 129 | font-family: Arial, sans-serif; 130 | opacity: 0.5; 131 | white-space: nowrap; 132 | margin-left: 3px; 133 | bottom: 1px; 134 | } 135 | 136 | /* annotations */ 137 | 138 | .rickshaw_annotation_timeline { 139 | height: 1px; 140 | border-top: 1px solid #e0e0e0; 141 | margin-top: 10px; 142 | position: relative; 143 | } 144 | .rickshaw_annotation_timeline .annotation { 145 | position: absolute; 146 | height: 6px; 147 | width: 6px; 148 | margin-left: -2px; 149 | top: -3px; 150 | border-radius: 5px; 151 | background-color: rgba(0, 0, 0, 0.25); 152 | } 153 | .rickshaw_graph .annotation_line { 154 | position: absolute; 155 | top: 0; 156 | bottom: -6px; 157 | width: 0px; 158 | border-left: 2px solid rgba(0, 0, 0, 0.3); 159 | display: none; 160 | } 161 | .rickshaw_graph .annotation_line.active { 162 | display: block; 163 | } 164 | 165 | .rickshaw_graph .annotation_range { 166 | background: rgba(0, 0, 0, 0.1); 167 | display: none; 168 | position: absolute; 169 | top: 0; 170 | bottom: -6px; 171 | } 172 | .rickshaw_graph .annotation_range.active { 173 | display: block; 174 | } 175 | .rickshaw_graph .annotation_range.active.offscreen { 176 | display: none; 177 | } 178 | 179 | .rickshaw_annotation_timeline .annotation .content { 180 | background: white; 181 | color: black; 182 | opacity: 0.9; 183 | padding: 5px 5px; 184 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.8); 185 | border-radius: 3px; 186 | position: relative; 187 | z-index: 20; 188 | font-size: 12px; 189 | padding: 6px 8px 8px; 190 | top: 18px; 191 | left: -11px; 192 | width: 160px; 193 | display: none; 194 | cursor: pointer; 195 | } 196 | .rickshaw_annotation_timeline .annotation .content:before { 197 | content: "\25b2"; 198 | position: absolute; 199 | top: -11px; 200 | color: white; 201 | text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8); 202 | } 203 | .rickshaw_annotation_timeline .annotation.active, 204 | .rickshaw_annotation_timeline .annotation:hover { 205 | background-color: rgba(0, 0, 0, 0.8); 206 | cursor: none; 207 | } 208 | .rickshaw_annotation_timeline .annotation .content:hover { 209 | z-index: 50; 210 | } 211 | .rickshaw_annotation_timeline .annotation.active .content { 212 | display: block; 213 | } 214 | .rickshaw_annotation_timeline .annotation:hover .content { 215 | display: block; 216 | z-index: 50; 217 | } 218 | .rickshaw_graph .y_axis, 219 | .rickshaw_graph .x_axis_d3 { 220 | fill: none; 221 | } 222 | .rickshaw_graph .y_ticks .tick line, 223 | .rickshaw_graph .x_ticks_d3 .tick { 224 | stroke: rgba(0, 0, 0, 0.16); 225 | stroke-width: 2px; 226 | shape-rendering: crisp-edges; 227 | pointer-events: none; 228 | } 229 | .rickshaw_graph .y_grid .tick, 230 | .rickshaw_graph .x_grid_d3 .tick { 231 | z-index: -1; 232 | stroke: rgba(0, 0, 0, 0.20); 233 | stroke-width: 1px; 234 | stroke-dasharray: 1 1; 235 | } 236 | .rickshaw_graph .y_grid .tick[data-y-value="0"] { 237 | stroke-dasharray: 1 0; 238 | } 239 | .rickshaw_graph .y_grid path, 240 | .rickshaw_graph .x_grid_d3 path { 241 | fill: none; 242 | stroke: none; 243 | } 244 | .rickshaw_graph .y_ticks path, 245 | .rickshaw_graph .x_ticks_d3 path { 246 | fill: none; 247 | stroke: #808080; 248 | } 249 | .rickshaw_graph .y_ticks text, 250 | .rickshaw_graph .x_ticks_d3 text { 251 | opacity: 0.5; 252 | font-size: 12px; 253 | pointer-events: none; 254 | } 255 | .rickshaw_graph .x_tick.glow .title, 256 | .rickshaw_graph .y_ticks.glow text { 257 | fill: black; 258 | color: black; 259 | text-shadow: 260 | -1px 1px 0 rgba(255, 255, 255, 0.1), 261 | 1px -1px 0 rgba(255, 255, 255, 0.1), 262 | 1px 1px 0 rgba(255, 255, 255, 0.1), 263 | 0px 1px 0 rgba(255, 255, 255, 0.1), 264 | 0px -1px 0 rgba(255, 255, 255, 0.1), 265 | 1px 0px 0 rgba(255, 255, 255, 0.1), 266 | -1px 0px 0 rgba(255, 255, 255, 0.1), 267 | -1px -1px 0 rgba(255, 255, 255, 0.1); 268 | } 269 | .rickshaw_graph .x_tick.inverse .title, 270 | .rickshaw_graph .y_ticks.inverse text { 271 | fill: white; 272 | color: white; 273 | text-shadow: 274 | -1px 1px 0 rgba(0, 0, 0, 0.8), 275 | 1px -1px 0 rgba(0, 0, 0, 0.8), 276 | 1px 1px 0 rgba(0, 0, 0, 0.8), 277 | 0px 1px 0 rgba(0, 0, 0, 0.8), 278 | 0px -1px 0 rgba(0, 0, 0, 0.8), 279 | 1px 0px 0 rgba(0, 0, 0, 0.8), 280 | -1px 0px 0 rgba(0, 0, 0, 0.8), 281 | -1px -1px 0 rgba(0, 0, 0, 0.8); 282 | } 283 | .rickshaw_legend { 284 | font-family: Arial; 285 | font-size: 12px; 286 | color: white; 287 | background: #404040; 288 | display: inline-block; 289 | padding: 12px 5px; 290 | border-radius: 2px; 291 | position: relative; 292 | } 293 | .rickshaw_legend:hover { 294 | z-index: 10; 295 | } 296 | .rickshaw_legend .swatch { 297 | width: 10px; 298 | height: 10px; 299 | border: 1px solid rgba(0, 0, 0, 0.2); 300 | } 301 | .rickshaw_legend .line { 302 | clear: both; 303 | line-height: 140%; 304 | padding-right: 15px; 305 | } 306 | .rickshaw_legend .line .swatch { 307 | display: inline-block; 308 | margin-right: 3px; 309 | border-radius: 2px; 310 | } 311 | .rickshaw_legend .label { 312 | margin: 0; 313 | white-space: nowrap; 314 | display: inline; 315 | font-size: inherit; 316 | background-color: transparent; 317 | color: inherit; 318 | font-weight: normal; 319 | line-height: normal; 320 | padding: 0px; 321 | text-shadow: none; 322 | } 323 | .rickshaw_legend .action:hover { 324 | opacity: 0.6; 325 | } 326 | .rickshaw_legend .action { 327 | margin-right: 0.2em; 328 | font-size: 10px; 329 | opacity: 0.2; 330 | cursor: pointer; 331 | font-size: 14px; 332 | } 333 | .rickshaw_legend .line.disabled { 334 | opacity: 0.4; 335 | } 336 | .rickshaw_legend ul { 337 | list-style-type: none; 338 | margin: 0; 339 | padding: 0; 340 | margin: 2px; 341 | cursor: pointer; 342 | } 343 | .rickshaw_legend li { 344 | display: inline-block; 345 | padding: 0 0 0 2px; 346 | min-width: 80px; 347 | white-space: nowrap; 348 | } 349 | .rickshaw_legend li:hover { 350 | background: rgba(255, 255, 255, 0.08); 351 | border-radius: 3px; 352 | } 353 | .rickshaw_legend li:active { 354 | background: rgba(255, 255, 255, 0.2); 355 | border-radius: 3px; 356 | } 357 | -------------------------------------------------------------------------------- /static/css/custom.css: -------------------------------------------------------------------------------- 1 | .fs { 2 | height: 100vh; 3 | } 4 | 5 | 6 | .rickshaw_graph .detail { 7 | pointer-events: none; 8 | position: absolute; 9 | top: 0; 10 | z-index: 2; 11 | background: rgba(0, 0, 0, 0.1); 12 | bottom: 0; 13 | width: 1px; 14 | transition: opacity 0.25s linear; 15 | -moz-transition: opacity 0.25s linear; 16 | -o-transition: opacity 0.25s linear; 17 | -webkit-transition: opacity 0.25s linear; 18 | } 19 | .rickshaw_graph .detail.inactive { 20 | opacity: 0; 21 | } 22 | .rickshaw_graph .detail .item.active { 23 | opacity: 1; 24 | } 25 | .rickshaw_graph .detail .x_label { 26 | font-family: Arial, sans-serif; 27 | border-radius: 3px; 28 | padding: 6px; 29 | opacity: 0.5; 30 | border: 1px solid #e0e0e0; 31 | font-size: 12px; 32 | position: absolute; 33 | background: white; 34 | white-space: nowrap; 35 | } 36 | .rickshaw_graph .detail .x_label.left { 37 | left: 0; 38 | } 39 | .rickshaw_graph .detail .x_label.right { 40 | right: 0; 41 | } 42 | .rickshaw_graph .detail .item { 43 | position: absolute; 44 | z-index: 2; 45 | border-radius: 3px; 46 | padding: 0.25em; 47 | font-size: 12px; 48 | font-family: Arial, sans-serif; 49 | opacity: 0; 50 | background: rgba(0, 0, 0, 0.4); 51 | color: white; 52 | border: 1px solid rgba(0, 0, 0, 0.4); 53 | margin-left: 1em; 54 | margin-right: 1em; 55 | margin-top: -1em; 56 | white-space: nowrap; 57 | } 58 | .rickshaw_graph .detail .item.left { 59 | left: 0; 60 | } 61 | .rickshaw_graph .detail .item.right { 62 | right: 0; 63 | } 64 | .rickshaw_graph .detail .item.active { 65 | opacity: 1; 66 | background: rgba(0, 0, 0, 0.8); 67 | } 68 | .rickshaw_graph .detail .item:after { 69 | position: absolute; 70 | display: block; 71 | width: 0; 72 | height: 0; 73 | 74 | content: ""; 75 | 76 | border: 5px solid transparent; 77 | } 78 | .rickshaw_graph .detail .item.left:after { 79 | top: 1em; 80 | left: -5px; 81 | margin-top: -5px; 82 | border-right-color: rgba(0, 0, 0, 0.8); 83 | border-left-width: 0; 84 | } 85 | .rickshaw_graph .detail .item.right:after { 86 | top: 1em; 87 | right: -5px; 88 | margin-top: -5px; 89 | border-left-color: rgba(0, 0, 0, 0.8); 90 | border-right-width: 0; 91 | } 92 | .rickshaw_graph .detail .dot { 93 | width: 4px; 94 | height: 4px; 95 | margin-left: -3px; 96 | margin-top: -3.5px; 97 | border-radius: 5px; 98 | position: absolute; 99 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.6); 100 | box-sizing: content-box; 101 | -moz-box-sizing: content-box; 102 | background: white; 103 | border-width: 2px; 104 | border-style: solid; 105 | display: none; 106 | background-clip: padding-box; 107 | } 108 | .rickshaw_graph .detail .dot.active { 109 | display: block; 110 | } 111 | /* graph */ 112 | 113 | .rickshaw_graph { 114 | position: relative; 115 | } 116 | .rickshaw_graph svg { 117 | display: block; 118 | overflow: hidden; 119 | } 120 | 121 | /* ticks */ 122 | 123 | .rickshaw_graph .x_tick { 124 | position: absolute; 125 | top: 0; 126 | bottom: 0; 127 | width: 0px; 128 | border-left: 1px dotted rgba(0, 0, 0, 0.2); 129 | pointer-events: none; 130 | } 131 | .rickshaw_graph .x_tick .title { 132 | position: absolute; 133 | font-size: 12px; 134 | font-family: Arial, sans-serif; 135 | opacity: 0.5; 136 | white-space: nowrap; 137 | margin-left: 3px; 138 | bottom: 1px; 139 | } 140 | 141 | /* annotations */ 142 | 143 | .rickshaw_annotation_timeline { 144 | height: 1px; 145 | border-top: 1px solid #e0e0e0; 146 | margin-top: 10px; 147 | position: relative; 148 | } 149 | .rickshaw_annotation_timeline .annotation { 150 | position: absolute; 151 | height: 6px; 152 | width: 6px; 153 | margin-left: -2px; 154 | top: -3px; 155 | border-radius: 5px; 156 | background-color: rgba(0, 0, 0, 0.25); 157 | } 158 | .rickshaw_graph .annotation_line { 159 | position: absolute; 160 | top: 0; 161 | bottom: -6px; 162 | width: 0px; 163 | border-left: 2px solid rgba(0, 0, 0, 0.3); 164 | display: none; 165 | } 166 | .rickshaw_graph .annotation_line.active { 167 | display: block; 168 | } 169 | 170 | .rickshaw_graph .annotation_range { 171 | background: rgba(0, 0, 0, 0.1); 172 | display: none; 173 | position: absolute; 174 | top: 0; 175 | bottom: -6px; 176 | } 177 | .rickshaw_graph .annotation_range.active { 178 | display: block; 179 | } 180 | .rickshaw_graph .annotation_range.active.offscreen { 181 | display: none; 182 | } 183 | 184 | .rickshaw_annotation_timeline .annotation .content { 185 | background: white; 186 | color: black; 187 | opacity: 0.9; 188 | padding: 5px 5px; 189 | box-shadow: 0 0 2px rgba(0, 0, 0, 0.8); 190 | border-radius: 3px; 191 | position: relative; 192 | z-index: 20; 193 | font-size: 12px; 194 | padding: 6px 8px 8px; 195 | top: 18px; 196 | left: -11px; 197 | width: 160px; 198 | display: none; 199 | cursor: pointer; 200 | } 201 | .rickshaw_annotation_timeline .annotation .content:before { 202 | content: "\25b2"; 203 | position: absolute; 204 | top: -11px; 205 | color: white; 206 | text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.8); 207 | } 208 | .rickshaw_annotation_timeline .annotation.active, 209 | .rickshaw_annotation_timeline .annotation:hover { 210 | background-color: rgba(0, 0, 0, 0.8); 211 | cursor: none; 212 | } 213 | .rickshaw_annotation_timeline .annotation .content:hover { 214 | z-index: 50; 215 | } 216 | .rickshaw_annotation_timeline .annotation.active .content { 217 | display: block; 218 | } 219 | .rickshaw_annotation_timeline .annotation:hover .content { 220 | display: block; 221 | z-index: 50; 222 | } 223 | .rickshaw_graph .y_axis, 224 | .rickshaw_graph .x_axis_d3 { 225 | fill: none; 226 | } 227 | .rickshaw_graph .y_ticks .tick line, 228 | .rickshaw_graph .x_ticks_d3 .tick { 229 | stroke: rgba(0, 0, 0, 0.16); 230 | stroke-width: 2px; 231 | shape-rendering: crisp-edges; 232 | pointer-events: none; 233 | } 234 | .rickshaw_graph .y_grid .tick, 235 | .rickshaw_graph .x_grid_d3 .tick { 236 | z-index: -1; 237 | stroke: rgba(0, 0, 0, 0.20); 238 | stroke-width: 1px; 239 | stroke-dasharray: 1 1; 240 | } 241 | .rickshaw_graph .y_grid .tick[data-y-value="0"] { 242 | stroke-dasharray: 1 0; 243 | } 244 | .rickshaw_graph .y_grid path, 245 | .rickshaw_graph .x_grid_d3 path { 246 | fill: none; 247 | stroke: none; 248 | } 249 | .rickshaw_graph .y_ticks path, 250 | .rickshaw_graph .x_ticks_d3 path { 251 | fill: none; 252 | stroke: #808080; 253 | } 254 | .rickshaw_graph .y_ticks text, 255 | .rickshaw_graph .x_ticks_d3 text { 256 | opacity: 0.5; 257 | font-size: 12px; 258 | pointer-events: none; 259 | } 260 | .rickshaw_graph .x_tick.glow .title, 261 | .rickshaw_graph .y_ticks.glow text { 262 | fill: black; 263 | color: black; 264 | text-shadow: 265 | -1px 1px 0 rgba(255, 255, 255, 0.1), 266 | 1px -1px 0 rgba(255, 255, 255, 0.1), 267 | 1px 1px 0 rgba(255, 255, 255, 0.1), 268 | 0px 1px 0 rgba(255, 255, 255, 0.1), 269 | 0px -1px 0 rgba(255, 255, 255, 0.1), 270 | 1px 0px 0 rgba(255, 255, 255, 0.1), 271 | -1px 0px 0 rgba(255, 255, 255, 0.1), 272 | -1px -1px 0 rgba(255, 255, 255, 0.1); 273 | } 274 | .rickshaw_graph .x_tick.inverse .title, 275 | .rickshaw_graph .y_ticks.inverse text { 276 | fill: white; 277 | color: white; 278 | text-shadow: 279 | -1px 1px 0 rgba(0, 0, 0, 0.8), 280 | 1px -1px 0 rgba(0, 0, 0, 0.8), 281 | 1px 1px 0 rgba(0, 0, 0, 0.8), 282 | 0px 1px 0 rgba(0, 0, 0, 0.8), 283 | 0px -1px 0 rgba(0, 0, 0, 0.8), 284 | 1px 0px 0 rgba(0, 0, 0, 0.8), 285 | -1px 0px 0 rgba(0, 0, 0, 0.8), 286 | -1px -1px 0 rgba(0, 0, 0, 0.8); 287 | } 288 | .rickshaw_legend { 289 | font-family: Arial; 290 | font-size: 12px; 291 | color: white; 292 | background: #404040; 293 | display: inline-block; 294 | padding: 12px 5px; 295 | border-radius: 2px; 296 | position: relative; 297 | } 298 | .rickshaw_legend:hover { 299 | z-index: 10; 300 | } 301 | .rickshaw_legend .swatch { 302 | width: 10px; 303 | height: 10px; 304 | border: 1px solid rgba(0, 0, 0, 0.2); 305 | } 306 | .rickshaw_legend .line { 307 | clear: both; 308 | line-height: 140%; 309 | padding-right: 15px; 310 | } 311 | .rickshaw_legend .line .swatch { 312 | display: inline-block; 313 | margin-right: 3px; 314 | border-radius: 2px; 315 | } 316 | .rickshaw_legend .label { 317 | margin: 0; 318 | white-space: nowrap; 319 | display: inline; 320 | font-size: inherit; 321 | background-color: transparent; 322 | color: inherit; 323 | font-weight: normal; 324 | line-height: normal; 325 | padding: 0px; 326 | text-shadow: none; 327 | } 328 | .rickshaw_legend .action:hover { 329 | opacity: 0.6; 330 | } 331 | .rickshaw_legend .action { 332 | margin-right: 0.2em; 333 | font-size: 10px; 334 | opacity: 0.2; 335 | cursor: pointer; 336 | font-size: 14px; 337 | } 338 | .rickshaw_legend .line.disabled { 339 | opacity: 0.4; 340 | } 341 | .rickshaw_legend ul { 342 | list-style-type: none; 343 | margin: 0; 344 | padding: 0; 345 | margin: 2px; 346 | cursor: pointer; 347 | } 348 | .rickshaw_legend li { 349 | display: inline-block; 350 | padding: 0 0 0 2px; 351 | min-width: 80px; 352 | white-space: nowrap; 353 | } 354 | .rickshaw_legend li:hover { 355 | background: rgba(255, 255, 255, 0.08); 356 | border-radius: 3px; 357 | } 358 | .rickshaw_legend li:active { 359 | background: rgba(255, 255, 255, 0.2); 360 | border-radius: 3px; 361 | } -------------------------------------------------------------------------------- /static/js/vendor/cubism.min.js: -------------------------------------------------------------------------------- 1 | (function(a){function d(a){return a}function e(){}function j(a){return Math.floor(a/1e3)}function k(a){var b=a.indexOf("|"),c=a.substring(0,b),d=c.lastIndexOf(","),e=c.lastIndexOf(",",d-1),f=c.lastIndexOf(",",e-1),g=c.substring(f+1,e)*1e3,h=c.substring(d+1)*1e3;return a.substring(b+1).split(",").slice(1).map(function(a){return+a})}function l(a){if(!(a instanceof e))throw new Error("invalid context");this.context=a}function o(a,b){return function(c,d,e,f){a(new Date(+c+b),new Date(+d+b),e,f)}}function p(a,b){l.call(this,a),b=+b;var c=b+"";this.valueOf=function(){return b},this.toString=function(){return c}}function r(a,b){function c(b,c){if(c instanceof l){if(b.context!==c.context)throw new Error("mismatch context")}else c=new p(b.context,c);l.call(this,b.context),this.left=b,this.right=c,this.toString=function(){return b+" "+a+" "+c}}var d=c.prototype=Object.create(l.prototype);return d.valueAt=function(a){return b(this.left.valueAt(a),this.right.valueAt(a))},d.shift=function(a){return new c(this.left.shift(a),this.right.shift(a))},d.on=function(a,b){return arguments.length<2?this.left.on(a):(this.left.on(a,b),this.right.on(a,b),this)},function(a){return new c(this,a)}}function u(a){return a&16777214}function v(a){return(a+1&16777214)-1}function z(a){a.style("position","absolute").style("top",0).style("bottom",0).style("width","1px").style("pointer-events","none")}function A(a){return a+"px"}var b=a.cubism={version:"1.6.0"},c=0;b.option=function(a,c){var d=b.options(a);return d.length?d[0]:c},b.options=function(a,b){var c=location.search.substring(1).split("&"),d=[],e=-1,f=c.length,g;while(++e0&&a.focus(--o);break;case 39:o==null&&(o=d-2),o=c)return c;if(a<=b)return b;var d,e,f;for(f=a;f<=c;f++){d=avail_rsts.indexOf(f);if(d>-1){e=avail_rsts[d];break}}var g;for(f=a;f>=b;f--){d=avail_rsts.indexOf(f);if(d>-1){g=avail_rsts[d];break}}return e-ae?3600:(i=f(c),d>g&&i<900?900:d>h&&i<60?60:i)}var d={},e=this;auth_string="Basic "+btoa(a+":"+c),avail_rsts=[1,60,900,3600];var j=function(a){function d(b,d,e){var f="compose="+a+"&start_time="+b+"&end_time="+d+"&resolution="+g(b,d,e);return c+"?"+f}function e(a,b,c,d){var e=[];for(i=a;i<=b;i+=c){var f=[];while(d.length&&d[0].measure_time<=i)f.push(d.shift().value);var g;f.length?g=f.reduce(function(a,b){return a+b})/f.length:g=e.length?e[e.length-1]:0,e.push(g)}return e}var c="https://metrics-api.librato.com/v1/metrics";return request={},request.fire=function(a,c,f,g){function i(j){d3.json(j).header("X-Requested-With","XMLHttpRequest").header("Authorization",auth_string).header("Librato-User-Agent","cubism/"+b.version).get(function(b,j){if(!b){if(j.measurements.length===0)return;j.measurements[0].series.forEach(function(a){h.push(a)});var k="query"in j&&"next_time"in j.query;if(k)i(d(j.query.next_time,c,f));else{var l=e(a,c,f,h);g(l)}}})}var h=[];i(d(a,c,f))},request};return d.metric=function(a){return e.metric(function(b,c,d,e){j(a).fire(h(b),h(c),h(d),function(a){e(null,a)})},a+="")},d.toString=function(){return"librato"},d};var h=function(a){return Math.floor(a/1e3)};f.graphite=function(a){arguments.length||(a="");var b={},c=this;return b.metric=function(b){var d="sum",e=c.metric(function(c,e,f,g){var h=b;f!==1e4&&(h="summarize("+h+",'"+(f%36e5?f%6e4?f/1e3+"sec":f/6e4+"min":f/36e5+"hour")+"','"+d+"')"),d3.text(a+"/render?format=raw"+"&target="+encodeURIComponent("alias("+h+",'')")+"&from="+j(c-2*f)+"&until="+j(e-1e3),function(a){if(!a)return g(new Error("unable to load data"));g(null,k(a))})},b+="");return e.summarize=function(a){return d=a,e},e},b.find=function(b,c){d3.json(a+"/metrics/find?format=completer"+"&query="+encodeURIComponent(b),function(a){if(!a)return c(new Error("unable to find metrics"));c(null,a.metrics.map(function(a){return a.path}))})},b.toString=function(){return a},b},f.gangliaWeb=function(a){var b="",c="/ganglia2/";arguments.length&&(a.host&&(b=a.host),a.uriPathPrefix&&(c=a.uriPathPrefix,c[0]!="/"&&(c="/"+c),c[c.length-1]!="/"&&(c+="/")));var d={},e=this;return d.metric=function(a){var d=a.clusterName,f=a.metricName,g=a.hostName,h=a.isReport||!1,i=a.titleGenerator||function(a){return"clusterName:"+d+" metricName:"+f+(g?" hostName:"+g:"")},j=a.onChangeCallback,k=h?"g":"m",l=e.metric(function(a,e,h,i){function j(){return"c="+d+"&"+k+"="+f+(g?"&h="+g:"")+"&cs="+a/1e3+"&ce="+e/1e3+"&step="+h/1e3+"&graphlot=1"}d3.json(b+c+"graph.php?"+j(),function(a){if(!a)return i(new Error("Unable to fetch GangliaWeb data"));i(null,a[0].data)})},i(a));return l.toString=function(){return i(a)},j&&l.on("change",j),l},d.toString=function(){return b+c},d};var m=l.prototype;b.metric=l,m.valueAt=function(){return NaN},m.alias=function(a){return this.toString=function(){return a},this},m.extent=function(){var a=0,b=this.context.size(),c,d=Infinity,e=-Infinity;while(++ae&&(e=c);return[d,e]},m.on=function(a,b){return arguments.length<2?null:this},m.shift=function(){return this},m.on=function(){return arguments.length<2?null:this},f.metric=function(a,b){function r(b,c){var d=Math.min(j,Math.round((b-g)/i));if(!d||q)return;q=!0,d=Math.min(j,d+n);var f=new Date(c-d*i);a(f,c,i,function(a,b){q=!1;if(a)return console.warn(a);var d=isFinite(g)?Math.round((f-g)/i):0;for(var h=0,j=b.length;h1&&(e.toString=function(){return b}),e};var n=6,q=p.prototype=Object.create(l.prototype);q.valueAt=function(){return+this},q.extent=function(){return[+this,+this]},m.add=r("+",function(a,b){return a+b}),m.subtract=r("-",function(a,b){return a-b}),m.multiply=r("*",function(a,b){return a*b}),m.divide=r("/",function(a,b){return a/b}),f.horizon=function(){function o(o){o.on("mousemove.horizon",function(){a.focus(Math.round(d3.mouse(this)[0]))}).on("mouseout.horizon",function(){a.focus(null)}),o.append("canvas").attr("width",f).attr("height",g),o.append("span").attr("class","title").text(k),o.append("span").attr("class","value"),o.each(function(k,o){function B(c,d){w.save();var i=r.extent();A=i.every(isFinite),t!=null&&(i=t);var j=0,k=Math.max(-i[0],i[1]);if(this===a){if(k==y){j=f-n;var l=(c-u)/v;if(l=0)continue;w.fillRect(x,h(-C),1,q-h(-C))}}}w.restore()}function C(a){a==null&&(a=f-1);var b=r.valueAt(a);x.datum(b).text(isNaN(b)?null:l)}var p=this,q=++c,r=typeof i=="function"?i.call(p,k,o):i,s=typeof m=="function"?m.call(p,k,o):m,t=typeof j=="function"?j.call(p,k,o):j,u=-Infinity,v=a.step(),w=d3.select(p).select("canvas"),x=d3.select(p).select(".value"),y,z=s.length>>1,A;w.datum({id:q,metric:r}),w=w.node().getContext("2d"),a.on("change.horizon-"+q,B),a.on("focus.horizon-"+q,C),r.on("change.horizon-"+q,function(a,b){B(a,b),C(),A&&r.on("change.horizon-"+q,d)})})}var a=this,b="offset",e=document.createElement("canvas"),f=e.width=a.size(),g=e.height=30,h=d3.scale.linear().interpolate(d3.interpolateRound),i=d,j=null,k=d,l=d3.format(".2s"),m=["#08519c","#3182bd","#6baed6","#bdd7e7","#bae4b3","#74c476","#31a354","#006d2c"];return o.remove=function(b){function c(b){b.metric.on("change.horizon-"+b.id,null),a.on("change.horizon-"+b.id,null),a.on("focus.horizon-"+b.id,null)}b.on("mousemove.horizon",null).on("mouseout.horizon",null),b.selectAll("canvas").each(c).remove(),b.selectAll(".title,.value").remove()},o.mode=function(a){return arguments.length?(b=a+"",o):b},o.height=function(a){return arguments.length?(e.height=g=+a,o):g},o.metric=function(a){return arguments.length?(i=a,o):i},o.scale=function(a){return arguments.length?(h=a,o):h},o.extent=function(a){return arguments.length?(j=a,o):j},o.title=function(a){return arguments.length?(k=a,o):k},o.format=function(a){return arguments.length?(l=a,o):l},o.colors=function(a){return arguments.length?(m=a,o):m},o},f.comparison=function(){function o(o){o.on("mousemove.comparison",function(){a.focus(Math.round(d3.mouse(this)[0]))}).on("mouseout.comparison",function(){a.focus(null)}),o.append("canvas").attr("width",b).attr("height",e),o.append("span").attr("class","title").text(j),o.append("span").attr("class","value primary"),o.append("span").attr("class","value change"),o.each(function(j,o){function B(c,d){x.save(),x.clearRect(0,0,b,e);var g=r.extent(),h=s.extent(),i=t==null?g:t;f.domain(i).range([e,0]),A=g.concat(h).every(isFinite);var j=c/a.step()&1?v:u;x.fillStyle=m[2];for(var k=0,l=b;kp&&x.fillRect(j(k),p,1,o-p)}x.fillStyle=m[3];for(k=0;kp&&x.fillRect(j(k),o-n,1,n)}x.restore()}function C(a){a==null&&(a=b-1);var c=r.valueAt(a),d=s.valueAt(a),e=(c-d)/d;y.datum(c).text(isNaN(c)?null:k),z.datum(e).text(isNaN(e)?null:l).attr("class","value change "+(e>0?"positive":e<0?"negative":""))}function D(a,b){B(a,b),C(),A&&(r.on("change.comparison-"+q,d),s.on("change.comparison-"+q,d))}var p=this,q=++c,r=typeof g=="function"?g.call(p,j,o):g,s=typeof h=="function"?h.call(p,j,o):h,t=typeof i=="function"?i.call(p,j,o):i,w=d3.select(p),x=w.select("canvas"),y=w.select(".value.primary"),z=w.select(".value.change"),A;x.datum({id:q,primary:r,secondary:s}),x=x.node().getContext("2d"),r.on("change.comparison-"+q,D),s.on("change.comparison-"+q,D),a.on("change.comparison-"+q,B),a.on("focus.comparison-"+q,C)})}var a=this,b=a.size(),e=120,f=d3.scale.linear().interpolate(d3.interpolateRound),g=function(a){return a[0]},h=function(a){return a[1]},i=null,j=d,k=s,l=t,m=["#9ecae1","#225b84","#a1d99b","#22723a"],n=1.5;return o.remove=function(b){function c(b){b.primary.on("change.comparison-"+b.id,null),b.secondary.on("change.comparison-"+b.id,null),a.on("change.comparison-"+b.id,null),a.on("focus.comparison-"+b.id,null)}b.on("mousemove.comparison",null).on("mouseout.comparison",null),b.selectAll("canvas").each(c).remove(),b.selectAll(".title,.value").remove()},o.height=function(a){return arguments.length?(e=+a,o):e},o.primary=function(a){return arguments.length?(g=a,o):g},o.secondary=function(a){return arguments.length?(h=a,o):h},o.scale=function(a){return arguments.length?(f=a,o):f},o.extent=function(a){return arguments.length?(i=a,o):i},o.title=function(a){return arguments.length?(j=a,o):j},o.formatPrimary=function(a){return arguments.length?(k=a,o):k},o.formatChange=function(a){return arguments.length?(l=a,o):l},o.colors=function(a){return arguments.length?(m=a,o):m},o.strokeWidth=function(a){return arguments.length?(n=a,o):n},o};var s=d3.format(".2s"),t=d3.format("+.0%");f.axis=function(){function g(e){var h=++c,i,j=e.append("svg").datum({id:h}).attr("width",a.size()).attr("height",Math.max(28,-g.tickSize())).append("g").attr("transform","translate(0,"+(d.orient()==="top"?27:4)+")").call(d);a.on("change.axis-"+h,function(){j.call(d),i||(i=d3.select(j.node().appendChild(j.selectAll("text").node().cloneNode(!0))).style("display","none").text(null))}),a.on("focus.axis-"+h,function(a){if(i)if(a==null)i.style("display","none"),j.selectAll("text").style("fill-opacity",null);else{i.style("display",null).attr("x",a).text(f(b.invert(a)));var c=i.node().getComputedTextLength()+6;j.selectAll("text").style("fill-opacity",function(d){return Math.abs(b(d)-a)li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f3f3f3));background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-o-linear-gradient(top,#222 0,#282828 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#222),to(#282828));background-image:linear-gradient(to bottom,#222 0,#282828 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /static/css/bootstrap-theme.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"bootstrap-theme.css","sources":["less/theme.less","less/mixins/vendor-prefixes.less","bootstrap-theme.css","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAeA;;;;;;EAME,0CAAA;EC+CA,6FAAA;EACQ,qFAAA;EC5DT;AFiBC;;;;;;;;;;;;EC0CA,0DAAA;EACQ,kDAAA;EC7CT;AFqCC;;EAEE,wBAAA;EEnCH;AFwCD;EG/CI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EA+B2C,2BAAA;EAA2B,oBAAA;EE7BvE;AFAC;;EAEE,2BAAA;EACA,8BAAA;EEEH;AFCC;;EAEE,2BAAA;EACA,uBAAA;EECH;AFEC;;EAEE,2BAAA;EACA,wBAAA;EEAH;AFeD;EGhDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0BD;AFxBC;;EAEE,2BAAA;EACA,8BAAA;EE0BH;AFvBC;;EAEE,2BAAA;EACA,uBAAA;EEyBH;AFtBC;;EAEE,2BAAA;EACA,wBAAA;EEwBH;AFRD;EGjDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EEkDD;AFhDC;;EAEE,2BAAA;EACA,8BAAA;EEkDH;AF/CC;;EAEE,2BAAA;EACA,uBAAA;EEiDH;AF9CC;;EAEE,2BAAA;EACA,wBAAA;EEgDH;AF/BD;EGlDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0ED;AFxEC;;EAEE,2BAAA;EACA,8BAAA;EE0EH;AFvEC;;EAEE,2BAAA;EACA,uBAAA;EEyEH;AFtEC;;EAEE,2BAAA;EACA,wBAAA;EEwEH;AFtDD;EGnDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EEkGD;AFhGC;;EAEE,2BAAA;EACA,8BAAA;EEkGH;AF/FC;;EAEE,2BAAA;EACA,uBAAA;EEiGH;AF9FC;;EAEE,2BAAA;EACA,wBAAA;EEgGH;AF7ED;EGpDI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EAEA,wHAAA;ECnBF,qEAAA;EJ8BA,6BAAA;EACA,uBAAA;EE0HD;AFxHC;;EAEE,2BAAA;EACA,8BAAA;EE0HH;AFvHC;;EAEE,2BAAA;EACA,uBAAA;EEyHH;AFtHC;;EAEE,2BAAA;EACA,wBAAA;EEwHH;AF7FD;;ECbE,oDAAA;EACQ,4CAAA;EC8GT;AFvFD;;EGvEI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHsEF,2BAAA;EE6FD;AF3FD;;;EG5EI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH4EF,2BAAA;EEiGD;AFvFD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EJ4GA,oBAAA;EC9CA,6FAAA;EACQ,qFAAA;EC4IT;AFlGD;EG1FI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,0DAAA;EACQ,kDAAA;ECqJT;AF/FD;;EAEE,gDAAA;EEiGD;AF7FD;EG5GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ECnBF,qEAAA;EFgOD;AFrGD;EG5GI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EF2CF,yDAAA;EACQ,iDAAA;EC0KT;AF9GD;;EAWI,2CAAA;EEuGH;AFlGD;;;EAGE,kBAAA;EEoGD;AF1FD;EACE,+CAAA;EC3FA,4FAAA;EACQ,oFAAA;ECwLT;AFlFD;EGtJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EE8FD;AFzFD;EGvJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EEsGD;AFhGD;EGxJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EE8GD;AFvGD;EGzJI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EH8IF,uBAAA;EEsHD;AFtGD;EGlKI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED2QH;AFnGD;EG5KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDkRH;AFzGD;EG7KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDyRH;AF/GD;EG9KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDgSH;AFrHD;EG/KI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDuSH;AF3HD;EGhLI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8SH;AF9HD;EGnJI,+MAAA;EACA,0MAAA;EACA,uMAAA;EDoRH;AF1HD;EACE,oBAAA;EC/IA,oDAAA;EACQ,4CAAA;EC4QT;AF3HD;;;EAGE,+BAAA;EGpME,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHkMF,uBAAA;EEiID;AFvHD;ECjKE,mDAAA;EACQ,2CAAA;EC2RT;AFjHD;EG1NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED8UH;AFvHD;EG3NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDqVH;AF7HD;EG5NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED4VH;AFnID;EG7NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDmWH;AFzID;EG9NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;ED0WH;AF/ID;EG/NI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EDiXH;AF9ID;EGvOI,0EAAA;EACA,qEAAA;EACA,+FAAA;EAAA,wEAAA;EACA,6BAAA;EACA,wHAAA;EHqOF,uBAAA;EC1LA,2FAAA;EACQ,mFAAA;EC+UT","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &:disabled,\n &[disabled] {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n",null,"// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} -------------------------------------------------------------------------------- /static/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 16 | } 17 | .btn-default:active, 18 | .btn-primary:active, 19 | .btn-success:active, 20 | .btn-info:active, 21 | .btn-warning:active, 22 | .btn-danger:active, 23 | .btn-default.active, 24 | .btn-primary.active, 25 | .btn-success.active, 26 | .btn-info.active, 27 | .btn-warning.active, 28 | .btn-danger.active { 29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 31 | } 32 | .btn:active, 33 | .btn.active { 34 | background-image: none; 35 | } 36 | .btn-default { 37 | text-shadow: 0 1px 0 #fff; 38 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 39 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 40 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 41 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 42 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 43 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 44 | background-repeat: repeat-x; 45 | border-color: #dbdbdb; 46 | border-color: #ccc; 47 | } 48 | .btn-default:hover, 49 | .btn-default:focus { 50 | background-color: #e0e0e0; 51 | background-position: 0 -15px; 52 | } 53 | .btn-default:active, 54 | .btn-default.active { 55 | background-color: #e0e0e0; 56 | border-color: #dbdbdb; 57 | } 58 | .btn-default:disabled, 59 | .btn-default[disabled] { 60 | background-color: #e0e0e0; 61 | background-image: none; 62 | } 63 | .btn-primary { 64 | background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 65 | background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 66 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2)); 67 | background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); 68 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); 69 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 70 | background-repeat: repeat-x; 71 | border-color: #2b669a; 72 | } 73 | .btn-primary:hover, 74 | .btn-primary:focus { 75 | background-color: #2d6ca2; 76 | background-position: 0 -15px; 77 | } 78 | .btn-primary:active, 79 | .btn-primary.active { 80 | background-color: #2d6ca2; 81 | border-color: #2b669a; 82 | } 83 | .btn-primary:disabled, 84 | .btn-primary[disabled] { 85 | background-color: #2d6ca2; 86 | background-image: none; 87 | } 88 | .btn-success { 89 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 90 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 91 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 92 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 93 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 94 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 95 | background-repeat: repeat-x; 96 | border-color: #3e8f3e; 97 | } 98 | .btn-success:hover, 99 | .btn-success:focus { 100 | background-color: #419641; 101 | background-position: 0 -15px; 102 | } 103 | .btn-success:active, 104 | .btn-success.active { 105 | background-color: #419641; 106 | border-color: #3e8f3e; 107 | } 108 | .btn-success:disabled, 109 | .btn-success[disabled] { 110 | background-color: #419641; 111 | background-image: none; 112 | } 113 | .btn-info { 114 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 115 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 116 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 117 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 118 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 119 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 120 | background-repeat: repeat-x; 121 | border-color: #28a4c9; 122 | } 123 | .btn-info:hover, 124 | .btn-info:focus { 125 | background-color: #2aabd2; 126 | background-position: 0 -15px; 127 | } 128 | .btn-info:active, 129 | .btn-info.active { 130 | background-color: #2aabd2; 131 | border-color: #28a4c9; 132 | } 133 | .btn-info:disabled, 134 | .btn-info[disabled] { 135 | background-color: #2aabd2; 136 | background-image: none; 137 | } 138 | .btn-warning { 139 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 140 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 141 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 142 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 143 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 144 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 145 | background-repeat: repeat-x; 146 | border-color: #e38d13; 147 | } 148 | .btn-warning:hover, 149 | .btn-warning:focus { 150 | background-color: #eb9316; 151 | background-position: 0 -15px; 152 | } 153 | .btn-warning:active, 154 | .btn-warning.active { 155 | background-color: #eb9316; 156 | border-color: #e38d13; 157 | } 158 | .btn-warning:disabled, 159 | .btn-warning[disabled] { 160 | background-color: #eb9316; 161 | background-image: none; 162 | } 163 | .btn-danger { 164 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 165 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 166 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 167 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 168 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 169 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 170 | background-repeat: repeat-x; 171 | border-color: #b92c28; 172 | } 173 | .btn-danger:hover, 174 | .btn-danger:focus { 175 | background-color: #c12e2a; 176 | background-position: 0 -15px; 177 | } 178 | .btn-danger:active, 179 | .btn-danger.active { 180 | background-color: #c12e2a; 181 | border-color: #b92c28; 182 | } 183 | .btn-danger:disabled, 184 | .btn-danger[disabled] { 185 | background-color: #c12e2a; 186 | background-image: none; 187 | } 188 | .thumbnail, 189 | .img-thumbnail { 190 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 191 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 192 | } 193 | .dropdown-menu > li > a:hover, 194 | .dropdown-menu > li > a:focus { 195 | background-color: #e8e8e8; 196 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 197 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 198 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 199 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 200 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 201 | background-repeat: repeat-x; 202 | } 203 | .dropdown-menu > .active > a, 204 | .dropdown-menu > .active > a:hover, 205 | .dropdown-menu > .active > a:focus { 206 | background-color: #357ebd; 207 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 208 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); 209 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); 210 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 211 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 212 | background-repeat: repeat-x; 213 | } 214 | .navbar-default { 215 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 216 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 217 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 218 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 219 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 220 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 221 | background-repeat: repeat-x; 222 | border-radius: 4px; 223 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 224 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 225 | } 226 | .navbar-default .navbar-nav > .active > a { 227 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 228 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 229 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f3f3f3)); 230 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); 231 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); 232 | background-repeat: repeat-x; 233 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 234 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 235 | } 236 | .navbar-brand, 237 | .navbar-nav > li > a { 238 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 239 | } 240 | .navbar-inverse { 241 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 242 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 243 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 244 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 245 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 246 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 247 | background-repeat: repeat-x; 248 | } 249 | .navbar-inverse .navbar-nav > .active > a { 250 | background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%); 251 | background-image: -o-linear-gradient(top, #222 0%, #282828 100%); 252 | background-image: -webkit-gradient(linear, left top, left bottom, from(#222), to(#282828)); 253 | background-image: linear-gradient(to bottom, #222 0%, #282828 100%); 254 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); 255 | background-repeat: repeat-x; 256 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 257 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 258 | } 259 | .navbar-inverse .navbar-brand, 260 | .navbar-inverse .navbar-nav > li > a { 261 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 262 | } 263 | .navbar-static-top, 264 | .navbar-fixed-top, 265 | .navbar-fixed-bottom { 266 | border-radius: 0; 267 | } 268 | .alert { 269 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 270 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 271 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 272 | } 273 | .alert-success { 274 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 275 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 276 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 277 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 278 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 279 | background-repeat: repeat-x; 280 | border-color: #b2dba1; 281 | } 282 | .alert-info { 283 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 284 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 285 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 286 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 287 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 288 | background-repeat: repeat-x; 289 | border-color: #9acfea; 290 | } 291 | .alert-warning { 292 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 293 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 294 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 295 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 296 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 297 | background-repeat: repeat-x; 298 | border-color: #f5e79e; 299 | } 300 | .alert-danger { 301 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 302 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 303 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 304 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 305 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 306 | background-repeat: repeat-x; 307 | border-color: #dca7a7; 308 | } 309 | .progress { 310 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 311 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 312 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 313 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 314 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 315 | background-repeat: repeat-x; 316 | } 317 | .progress-bar { 318 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); 319 | background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%); 320 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9)); 321 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); 322 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); 323 | background-repeat: repeat-x; 324 | } 325 | .progress-bar-success { 326 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 327 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 328 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 329 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 330 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 331 | background-repeat: repeat-x; 332 | } 333 | .progress-bar-info { 334 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 335 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 336 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 337 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 338 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 339 | background-repeat: repeat-x; 340 | } 341 | .progress-bar-warning { 342 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 343 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 344 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 345 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 346 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 347 | background-repeat: repeat-x; 348 | } 349 | .progress-bar-danger { 350 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 351 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 352 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 353 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 354 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 355 | background-repeat: repeat-x; 356 | } 357 | .progress-bar-striped { 358 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 359 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 360 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 361 | } 362 | .list-group { 363 | border-radius: 4px; 364 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 365 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 366 | } 367 | .list-group-item.active, 368 | .list-group-item.active:hover, 369 | .list-group-item.active:focus { 370 | text-shadow: 0 -1px 0 #3071a9; 371 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); 372 | background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%); 373 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3)); 374 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); 375 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); 376 | background-repeat: repeat-x; 377 | border-color: #3278b3; 378 | } 379 | .panel { 380 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 381 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 382 | } 383 | .panel-default > .panel-heading { 384 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 385 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 386 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 387 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 388 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 389 | background-repeat: repeat-x; 390 | } 391 | .panel-primary > .panel-heading { 392 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 393 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); 394 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); 395 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 396 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 397 | background-repeat: repeat-x; 398 | } 399 | .panel-success > .panel-heading { 400 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 401 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 403 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 405 | background-repeat: repeat-x; 406 | } 407 | .panel-info > .panel-heading { 408 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 409 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 410 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 411 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 412 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 413 | background-repeat: repeat-x; 414 | } 415 | .panel-warning > .panel-heading { 416 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 417 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 418 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 419 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 420 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 421 | background-repeat: repeat-x; 422 | } 423 | .panel-danger > .panel-heading { 424 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 425 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 426 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 427 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 428 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 429 | background-repeat: repeat-x; 430 | } 431 | .well { 432 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 433 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 435 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 437 | background-repeat: repeat-x; 438 | border-color: #dcdcdc; 439 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 440 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 441 | } 442 | /*# sourceMappingURL=bootstrap-theme.css.map */ 443 | -------------------------------------------------------------------------------- /static/js/vendor/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.2.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('