├── .gitignore ├── LICENSE ├── README.md ├── app ├── __init__.py ├── assembler.py ├── assembly_store.py ├── rest_api.py ├── static │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.min.css │ │ ├── jquery-ui.css │ │ ├── local.css │ │ └── ui-lightness │ │ │ ├── images │ │ │ ├── animated-overlay.gif │ │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ │ │ ├── ui-bg_flat_10_000000_40x100.png │ │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ │ │ ├── ui-icons_222222_256x240.png │ │ │ ├── ui-icons_228ef1_256x240.png │ │ │ ├── ui-icons_ef8c08_256x240.png │ │ │ ├── ui-icons_ffd27a_256x240.png │ │ │ └── ui-icons_ffffff_256x240.png │ │ │ ├── jquery-ui-1.10.4.css │ │ │ └── jquery-ui-1.10.4.min.css │ ├── img │ │ └── logo.png │ └── js │ │ ├── backbone.js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ ├── filter.js │ │ ├── jquery-latest.js │ │ ├── jquery-ui-1.10.4.min.js │ │ ├── jstz.min.js │ │ ├── save.js │ │ ├── signature_pad.js │ │ └── signature_pad.min.js ├── templates │ ├── layout.tpl │ ├── main.tpl │ └── save_modal.tpl └── views.py ├── assembler_test.py ├── dash.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Pete Markowsky 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dash - the quick dash assembler / disassembler 2 | 3 | Dash is a simple flask based web application for writing and editing assembly. 4 | 5 | Think of it as a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) for various assembly languages. 6 | 7 | # Installation 8 | 9 | Dash depends on Python 2.7, [capstone](http://www.capstone-engine.org/) and [keystone](http://www.keystone-engine.org/). So first things first install those as per the docs on their sites. 10 | 11 | Once you've installed capstone and keystone, use pip to install all of the flask requirements. 12 | 13 | `pip install -r requirements.txt` 14 | 15 | This will install flask-restful. 16 | 17 | # Usage 18 | 19 | To start from the command line where you've checked out dash go run 20 | 21 | `python dash.py` 22 | 23 | This will start the server on port 5555,browse there and away you go. 24 | 25 | ![basic_session](https://pbs.twimg.com/media/Cmr52ejUkAAcyqO.jpg) 26 | 27 | ## Writing Basic Assembly 28 | 29 | To write assembly simply click on the *mnemonic* field and type in the mnemoic and hit enter e.g. XOR eax, eax. On x86 only right now if you start an instruction with a jmp or a call it will attempt to offer you auto-completion suggestions for labels. 30 | 31 | For example if you add a label to an instruction called *myLabel* and then later start typing `JMP M` Dash will attempt to make auto-complete suggestions for you. 32 | 33 | ## Adding Comments 34 | 35 | Simply edit the comments field to keep 36 | 37 | ## Editing Bytes 38 | 39 | The opcodes column is directly editable as well. Here you need to enter in each byte as a hexadecimal number. This will cause dash to disassemble. 40 | 41 | ## Changing Processor Modes 42 | 43 | You can change which processor mode dash works in, when this happens it will disassemble all of the bytes in the opcodes fields of each row in the new mode. This could be useful if you want to look at things like [polyglot shellcode](http://phrack.org/issues/57/14.html). 44 | 45 | Changing Dash's configuration is accomplish using the three dropdown menus in the upper right hand corner. 46 | 47 | These are: 48 | * ARCH: The CPU architechture to operate in 49 | * MODE: Right now this is just 16-bit, 32-bit, or 64-bit 50 | * ENDIANESS: which is tells dash to assemble instructions as big endian or little endian 51 | 52 | Supported Configurations are: 53 | * x86 16-bit Little Endian 54 | * x86 32-bit Little Endian 55 | * x86 64-bit Little Endian 56 | * ARM 16-bit mode Big or Little Endian (This is Thumb) 57 | * ARM 32-bit mode Big or Little Endian (This is just ARMv7) 58 | * ARM64 64-bit mode Little Endian (This is AArch64) 59 | * MIPS 32-bit Big or Little Endian 60 | 61 | *Note* dash will not change modes to an unsupported configuration e.g. Big Endian X86. 62 | -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | A web based front end for simple assembly / disassembly experiments 3 | """ 4 | from flask import Flask 5 | 6 | app = Flask(__name__) 7 | 8 | from app import views 9 | -------------------------------------------------------------------------------- /app/assembler.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module that encapsilates all assembling and disassembling logic for Dash. 3 | """ 4 | import binascii 5 | import logging 6 | import re 7 | import struct 8 | 9 | # third party modules 10 | import capstone 11 | import keystone 12 | 13 | 14 | # constants 15 | LITTLE_ENDIAN = 0 16 | BIG_ENDIAN = 1 17 | X86_16 = 0 18 | X86_32 = 1 19 | X86_64 = 2 20 | ARM_16 = 3 # THUMB MODE 21 | ARM_32 = 4 22 | ARM_64 = 5 23 | MIPS_32 = 6 24 | 25 | LOGGER = logging.getLogger("assembler_module") 26 | LOGGER.setLevel(logging.ERROR) 27 | CONSOLE_HANDLER = logging.StreamHandler() 28 | CONSOLE_HANDLER.setLevel(logging.ERROR) 29 | formatter = \ 30 | logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 31 | CONSOLE_HANDLER.setFormatter(formatter) 32 | LOGGER.addHandler(CONSOLE_HANDLER) 33 | 34 | 35 | class AssemblerError(Exception): 36 | """Generic exception class for Assembler Errors.""" 37 | pass 38 | 39 | 40 | class Assembler(object): 41 | """Class to encapsilate all assembling and disassembling logic.""" 42 | def __init__(self): 43 | """ 44 | Constructor. 45 | 46 | Returns: 47 | A new Assembler instance 48 | """ 49 | # we default to x86 in 32-bit mode 50 | self.SetArchAndMode(X86_32, LITTLE_ENDIAN) 51 | 52 | def CheckOpcodeBytes(self, row, store): 53 | """ 54 | Check to see if we've set a filter. 55 | """ 56 | if not store.filter_bytes: 57 | return 58 | 59 | for ch in store.filter_bytes: 60 | if ch in row.opcode: 61 | store.SetErrorAtIndex(row.index) 62 | break 63 | 64 | def SetArchAndMode(self, arch_mode, endianess): 65 | """ 66 | Set the architechture and mode to assemble and disassemble in 67 | 68 | Args: 69 | arch_mode: an Integer describing the architechture and mode to assemble 70 | / disassemble in 71 | endianess: the endianess of the memory to configure for 72 | 73 | Returns: 74 | self 75 | """ 76 | arches_and_modes = {(X86_16, LITTLE_ENDIAN): ((keystone.KS_ARCH_X86, 77 | keystone.KS_MODE_16|keystone.KS_MODE_LITTLE_ENDIAN), 78 | (capstone.CS_ARCH_X86, 79 | capstone.CS_MODE_16|capstone.CS_MODE_LITTLE_ENDIAN)), 80 | (X86_32, LITTLE_ENDIAN): ((keystone.KS_ARCH_X86, 81 | keystone.KS_MODE_32|keystone.KS_MODE_LITTLE_ENDIAN), 82 | (capstone.CS_ARCH_X86, 83 | capstone.CS_MODE_32|capstone.CS_MODE_LITTLE_ENDIAN)), 84 | (X86_64, LITTLE_ENDIAN): ((keystone.KS_ARCH_X86, keystone.KS_MODE_64), 85 | (capstone.CS_ARCH_X86, 86 | capstone.CS_MODE_64|capstone.CS_MODE_LITTLE_ENDIAN)), 87 | (ARM_16, BIG_ENDIAN): ((keystone.KS_ARCH_ARM, 88 | keystone.KS_MODE_THUMB|keystone.KS_MODE_BIG_ENDIAN), 89 | (capstone.CS_ARCH_ARM, 90 | capstone.CS_MODE_THUMB|capstone.CS_MODE_BIG_ENDIAN)), 91 | (ARM_16, LITTLE_ENDIAN): ((keystone.KS_ARCH_ARM, 92 | keystone.KS_MODE_THUMB|keystone.KS_MODE_LITTLE_ENDIAN), 93 | (capstone.CS_ARCH_ARM, 94 | capstone.CS_MODE_THUMB|capstone.CS_MODE_LITTLE_ENDIAN)), 95 | (ARM_32, BIG_ENDIAN): ((keystone.KS_ARCH_ARM, 96 | keystone.KS_MODE_ARM|keystone.KS_MODE_BIG_ENDIAN), 97 | (capstone.CS_ARCH_ARM, 98 | capstone.CS_MODE_ARM|capstone.CS_MODE_BIG_ENDIAN)), 99 | (ARM_32, LITTLE_ENDIAN): ((keystone.KS_ARCH_ARM, 100 | keystone.KS_MODE_ARM|keystone.KS_MODE_LITTLE_ENDIAN), 101 | (capstone.CS_ARCH_ARM, 102 | capstone.CS_MODE_ARM|capstone.CS_MODE_LITTLE_ENDIAN)), 103 | (ARM_64, LITTLE_ENDIAN): ((keystone.KS_ARCH_ARM64, 104 | keystone.KS_MODE_LITTLE_ENDIAN), 105 | (capstone.CS_ARCH_ARM64, capstone.CS_MODE_LITTLE_ENDIAN)), 106 | (MIPS_32, BIG_ENDIAN): ((keystone.KS_ARCH_MIPS, 107 | keystone.KS_MODE_32|keystone.KS_MODE_BIG_ENDIAN|keystone.KS_MODE_MIPS32), 108 | (capstone.CS_ARCH_MIPS, 109 | capstone.CS_MODE_32|capstone.CS_MODE_BIG_ENDIAN)), 110 | (MIPS_32, LITTLE_ENDIAN): ((keystone.KS_ARCH_MIPS, 111 | keystone.KS_MODE_32|keystone.KS_MODE_LITTLE_ENDIAN|keystone.KS_MODE_MIPS32), 112 | (capstone.CS_ARCH_MIPS, 113 | capstone.CS_MODE_32|capstone.CS_MODE_LITTLE_ENDIAN)) 114 | } 115 | new_settings = arches_and_modes.get((arch_mode, endianess), None) 116 | 117 | if not new_settings: 118 | # leave the settings as is 119 | return 120 | self.arch_mode = arch_mode 121 | self.endianess = endianess 122 | 123 | self.asm_arch = new_settings[0][0] 124 | self.asm_mode = new_settings[0][1] 125 | self.disasm_arch = new_settings[1][0] 126 | self.disasm_mode = new_settings[1][1] 127 | self.assembler = keystone.Ks(self.asm_arch, self.asm_mode) 128 | self.disassembler = capstone.Cs(self.disasm_arch, self.disasm_mode) 129 | return self 130 | 131 | 132 | def IsADataDefinitionInstruction(self, mnemonic): 133 | """ 134 | Is this instruction a db, dw, dd, or dq instruction? 135 | 136 | Args: 137 | mnemonic: a string mnemonic 138 | 139 | Returns: 140 | True if it's an instruction that defines data. False otherwise. 141 | """ 142 | for inst in ['DB', 'DW', 'DD', 'DQ', 'DS']: 143 | if mnemonic.upper().strip().startswith(inst): 144 | return True 145 | return False 146 | 147 | def HandleNumber(self, value_str, max_size): 148 | """ 149 | Logic for handline handling parsing the numerical portions of data 150 | definitions instructions such as 151 | db 0xff 152 | dw 0xffff 153 | dd 0xfffffffff 154 | dq 0xffffffffffffffff 155 | 156 | Args: 157 | value_str: A string containing the integer value to convert 158 | max_size: The maximum size as defined by the command the value_str 159 | cannot exceed this size. 160 | 161 | Returns: 162 | None on error or the integer value of the result. 163 | """ 164 | if value_str.startswith('0x'): 165 | base = 16 166 | else: 167 | base = 10 168 | try: 169 | value = int(value_str, base) 170 | if value >= max_size: 171 | return None 172 | else: 173 | return value 174 | except ValueError as exc: 175 | LOGGER.error(str(exc)) 176 | return None 177 | 178 | def HandleStringDataDefinition(self, mnemonic): 179 | """ 180 | Handle a String operand for a data definiton. e.g. ds "blahahafh" 181 | 182 | Args: 183 | mnemonic: 184 | 185 | Returns: 186 | None, None on error or the pack string and the string 187 | to pack otherwise. 188 | """ 189 | # we match all ascii characters except for double quotes chars to avoid 190 | # balancing this can be fixed later 191 | mnemonic = mnemonic.strip() 192 | match = re.search("\"([\x01-\x21\x23-\x7f]*)\"$", mnemonic) 193 | if not match: 194 | return (None, None) 195 | # this will automatically NULL terminate the string 196 | # extract the string delimited by the double quotes 197 | data = bytes(match.group(1)) 198 | pack_string = "%ds" % (len(data) + 1) 199 | return pack_string, data 200 | 201 | def HandleByteDataDefinition(self, mnemonic): 202 | """ 203 | Handle instrucitons like db 0x44 or db 0x00, 0x04, 0x08, 0x10 204 | 205 | Args: 206 | mnemonic: a string representing the numeric operands separated by commas 207 | 208 | Returns: 209 | None, None on error or the pack string and a string of byte values 210 | """ 211 | pack_string = "" 212 | byte_values = [] 213 | for operand in mnemonic.split(","): 214 | value = self.HandleNumber(operand.strip(), 256) 215 | if value is None: 216 | return None, None 217 | else: 218 | pack_string += "B" 219 | byte_values.append(value) 220 | return pack_string, byte_values 221 | 222 | def HandleDataDefinitionInstruction(self, mnemonic): 223 | """ 224 | Convert a data definition instruciton to it's respective bytes. 225 | 226 | Args: 227 | mnemonic: A string mnemonic that defines raw bytes the assembler 228 | should skip over 229 | 230 | Returns: 231 | A string of byte values or None when the value cannot be parsed or 232 | exceeds the range. 233 | """ 234 | if self.endianess == LITTLE_ENDIAN: 235 | pack_string = '<' 236 | else: 237 | pack_string = '>' 238 | 239 | value = None 240 | 241 | inst_fields = mnemonic.split() 242 | 243 | # guantee we have at least one operand here 244 | if inst_fields < 2: 245 | return None 246 | 247 | # check to see if this is a dw, dd, or dq instruction. 248 | operation = inst_fields[0].upper() 249 | if operation == 'DW': 250 | value = [self.HandleNumber(inst_fields[1], 0xffff)] 251 | pack_string += "H" 252 | elif operation == 'DD': 253 | value = [self.HandleNumber(inst_fields[1], 0xffffffff)] 254 | pack_string += "I" 255 | # create a qword value 256 | elif operation == 'DQ': 257 | value = [self.HandleNumber(inst_fields[1], 0xffffffffffffffff)] 258 | pack_string += "Q" 259 | # handle a ds instruction as ds "bytes", 0x0 260 | elif operation == 'DS': 261 | extra_pack_str, value = self.HandleStringDataDefinition(inst_fields[1]) 262 | if extra_pack_str: 263 | pack_string += extra_pack_str 264 | return struct.pack(pack_string, value) 265 | # handle a db instruction as db byte or db byte, byte, byte, byte 266 | elif operation == 'DB': 267 | extra_pack_str, value = self.HandleByteDataDefinition(" ".join(inst_fields[1:])) 268 | if extra_pack_str: 269 | pack_string += extra_pack_str 270 | 271 | if value != None: 272 | return struct.pack(pack_string, *value) 273 | else: 274 | return None 275 | 276 | def RelaxInstructions(self, store, list_of_fixups, labels): 277 | """ 278 | Relax assembly instructions as necessary. 279 | 280 | Args: 281 | store: An AssemblyStore instance. 282 | list_of_fixups: a dictionary of instructions and their indices that need to be 283 | adjusted. 284 | labels: A dictionary of label names to addresses. 285 | 286 | Returns: 287 | N / A 288 | 289 | Side Effects: 290 | This will adjust the assembled instructions using wider versions 291 | when a labels address is beyond the range of the short forms 292 | (e.g. jumps and calls on x86) 293 | """ 294 | done_relaxing = False 295 | 296 | #last rounds label addresses 297 | last_rounds_label_addresses = labels 298 | 299 | while not done_relaxing: 300 | for row in store.GetRowsIterator(): 301 | if row.index not in list_of_fixups: 302 | continue 303 | 304 | mnemonic, label = list_of_fixups[row.index] 305 | label_addr_st = hex(labels[label]).replace('L', '') 306 | mnemonic = mnemonic.replace(label, label_addr_st) 307 | 308 | try: 309 | encoded_bytes, inst_count = self.assembler.asm(mnemonic, 310 | addr=row.address) 311 | if inst_count != 1: 312 | raise AssemblerError("mnemonic in row %d contains multiple statements" % row.index) 313 | 314 | opcode_str = "".join(["%02x" % byte for byte in encoded_bytes]) 315 | row.opcode = binascii.unhexlify(opcode_str) 316 | store.UpdateRow(row.index, row) 317 | 318 | except keystone.KsError as exc: 319 | LOGGER.error(str(exc)) 320 | store.SetErrorAtIndex(row.index) 321 | break 322 | 323 | # collect the labels updated addresses 324 | for row in store.GetRowsIterator(): 325 | if row.label != '': 326 | labels[row.label.upper()] = row.address 327 | 328 | # check to see if any labels differ at all if yes then continue 329 | # relaxing 330 | if labels == last_rounds_label_addresses: 331 | done_relaxing = True 332 | for row in store.GetRowsIterator(): 333 | self.CheckOpcodeBytes(row, store) 334 | else: 335 | last_rounds_label_addresses = labels 336 | 337 | def Assemble(self, store): 338 | """Assemble the mnemonics provided in the store. 339 | 340 | This will assemble all instructions before and after in order to support 341 | labels 342 | 343 | Args: 344 | store: An AssemblyStore instance 345 | 346 | Returns: 347 | N / A 348 | 349 | Side Effects: 350 | Updates the assembly store at the given path (row index) 351 | """ 352 | store.ClearErrors() 353 | cur_addr = None 354 | label_fixup_rows = {} 355 | known_label_addresses = {} 356 | 357 | for row in store.GetRowsIterator(): 358 | if not row.in_use: 359 | continue 360 | 361 | if not cur_addr: 362 | cur_addr = row.address 363 | 364 | if row.label: 365 | known_label_addresses[row.label.upper()] = cur_addr 366 | 367 | if self.IsADataDefinitionInstruction(row.mnemonic): 368 | encoded_bytes = self.HandleDataDefinitionInstruction(row.mnemonic) 369 | if encoded_bytes: 370 | row.opcode = encoded_bytes 371 | row.address = cur_addr 372 | cur_addr += len(encoded_bytes) 373 | store.UpdateRow(row.index, row) 374 | continue 375 | else: 376 | store.SetErrorAtIndex(row.index) 377 | continue 378 | 379 | try: 380 | # check if this row contains a label and adjust the mnemonic we're assembling 381 | asm_label = store.ContainsLabel(row.mnemonic) 382 | if asm_label: 383 | if asm_label in known_label_addresses: 384 | asm_label_addr_str = hex(known_label_addresses[asm_label]).replace('L', '') 385 | mnemonic = row.mnemonic.replace(asm_label, asm_label_addr_str) 386 | else: 387 | # store the original mnemonic replacing the new one with 388 | label_fixup_rows[row.index] = (row.mnemonic, asm_label) 389 | mnemonic = row.mnemonic.replace(asm_label, hex(row.address + 1).replace('L', '')) 390 | else: 391 | mnemonic = row.mnemonic 392 | 393 | encoded_bytes, inst_count = self.assembler.asm(mnemonic, 394 | addr=cur_addr) 395 | if inst_count != 1: 396 | raise AssemblerError("mnemonic in row %d contains multiple statements" % row.index) 397 | opcode_str = "".join(["%02x" % byte for byte in encoded_bytes]) 398 | row.opcode = binascii.unhexlify(opcode_str) 399 | 400 | self.CheckOpcodeBytes(row, store) 401 | 402 | row.address = cur_addr 403 | cur_addr += len(encoded_bytes) 404 | store.UpdateRow(row.index, row) 405 | except Exception as exc: 406 | LOGGER.error(str(exc)) 407 | store.SetErrorAtIndex(row.index) 408 | break 409 | 410 | # this is a quick and dirty means of dealing with label fixups and should 411 | # be arch dependent as we want to be able to support relaxation. 412 | if label_fixup_rows and known_label_addresses: 413 | self.RelaxInstructions(store, label_fixup_rows, known_label_addresses) 414 | 415 | return 416 | 417 | def DisassembleAll(self, store): 418 | """ 419 | Disassemble all rows from bytes. 420 | 421 | This is normally only called if dash is instructed to switch between CPU 422 | modes. 423 | 424 | Args: 425 | store: an AssemblyStore instance 426 | 427 | Returns: 428 | N / A 429 | 430 | Side Effects: 431 | Creates a new set of rows based on disassembling the bytes in the 432 | AssemblyStore mode. 433 | """ 434 | byte_buffer = "" 435 | starting_address = None 436 | for row in store.GetRowsIterator(): 437 | if not starting_address: 438 | starting_address = row.address 439 | byte_buffer += row.opcode 440 | 441 | # clear out all of the rows 442 | store.Reset() 443 | store.AddRows(20) 444 | 445 | index = 0 446 | byte_len = 0 447 | 448 | while byte_len < len(byte_buffer): 449 | insts = self.disassembler.disasm(byte_buffer[byte_len:], starting_address) 450 | 451 | for inst in insts: 452 | store.CreateRowFromCapstoneInst(index, inst) 453 | index += 1 454 | byte_len += len(inst.bytes) 455 | starting_address += len(inst.bytes) 456 | 457 | # if we hit instructions we can't decode 458 | if byte_len < len(byte_buffer): 459 | # try and consume the minimum instruction size worth of data as 460 | # a dq,dd or db 461 | if self.arch_mode in (X86_16, X86_32, X86_64): 462 | store.InsertDBRowAt(starting_address, index, 463 | byte_buffer[byte_len:byte_len + 1]) 464 | byte_len += 1 465 | starting_address += 1 466 | elif self.arch_mode == ARM_16: 467 | # grab two bytes 468 | if (len(byte_buffer) - byte_len) >= 2: 469 | store.InsertDHRowAt(starting_address, index, 470 | byte_buffer[byte_len:byte_len + 2], 471 | self.endianess) 472 | byte_len += 2 473 | starting_address += 2 474 | else: 475 | store.InsertDbRowAt(starting_address, index, 476 | byte_buffer[byte_len:byte_len+1]) 477 | byte_len += 1 478 | starting_address += 1 479 | elif self.arch_mode in (ARM_32, MIPS_32, ARM_64): 480 | # grab four bytes 481 | if len(byte_buffer) - byte_len >= 4: 482 | store.InsertDDRowAt(starting_address, index, 483 | byte_buffer[byte_len:byte_len + 4], 484 | self.endianess) 485 | byte_len += 4 486 | starting_address += 4 487 | else: 488 | # use db for the remainder 489 | new_len += store.InsertDbMultibyteRow(starting_address, index, 490 | byte_buffer[byte_len:]) 491 | byte_len += new_len 492 | starting_address += new_len 493 | 494 | index += 1 495 | 496 | 497 | def Disassemble(self, index, store): 498 | """ 499 | Disassembles the instruction given the opcode string taken from a row at 500 | the index provided. 501 | 502 | Args: 503 | index: an integer row index in the AssemblyStore 504 | store: The AssemblyStore instance 505 | 506 | Returns: 507 | N / A 508 | 509 | Side Effects: 510 | Updates the AssemblyStore row specified by the index. 511 | """ 512 | row = store.GetRow(index) 513 | # disassemble and set in the store 514 | instructions = list(self.disassembler.disasm(row.opcode, row.address)) 515 | 516 | if instructions: 517 | row.opcode = str(instructions[0].bytes) 518 | 519 | for ch in store.filter_bytes: 520 | if ch in row.opcode: 521 | store.SetErrorAtIndex(row.index) 522 | break 523 | 524 | row.SetMnemonic("%s %s" % (instructions[0].mnemonic, instructions[0].op_str)) 525 | 526 | store.UpdateRow(row.index, row) 527 | 528 | if len(instructions) > 1: 529 | for i in xrange(1, len(instructions)): 530 | store.CreateRowFromCapstoneInst(row.index + i, instructions[i]) 531 | else: 532 | store.SetErrorAtIndex(index) 533 | 534 | -------------------------------------------------------------------------------- /app/assembly_store.py: -------------------------------------------------------------------------------- 1 | """ 2 | assembly_store.py: classes and logic for generating and storing the state of 3 | the program. 4 | 5 | Author: Pete Markowsky 6 | """ 7 | import binascii 8 | import cPickle 9 | import struct 10 | 11 | X86 = 'x86' 12 | X64 = 'x64' 13 | ARM = 'arm' 14 | ARM64 = 'arm64' 15 | MIPS = 'mips' 16 | 17 | 18 | class RowData(object): 19 | """ 20 | Object representing an individual row of assembly. 21 | """ 22 | def __init__(self, offset, label, address, opcode, mnemonic, comment, 23 | index=0, in_use=False, stack_delta=0): 24 | self.offset = offset 25 | self.label = label 26 | self.address = address 27 | self.opcode = opcode 28 | self.mnemonic = mnemonic 29 | self.comment = comment 30 | self.index = index 31 | self.in_use = in_use 32 | self.error = False 33 | self.targets = [0] 34 | self.is_a_data_defintion_inst = False 35 | self.is_branch_or_call = False 36 | self.stack_delta = stack_delta 37 | 38 | def ToDict(self): 39 | """ 40 | Return a row as a dict for conversion to JSON 41 | """ 42 | error_st = 0 43 | if self.error: 44 | error_st = 1 45 | 46 | return {'offset': self.offset, 47 | 'label': self.label, 48 | 'address': self.DisplayAddress(), 49 | 'opcode': self.DisplayOpcode(), 50 | 'mnemonic': self.mnemonic, 51 | 'comment': self.comment, 52 | 'index': self.index, 53 | 'error': error_st, 54 | 'in_use': self.in_use, 55 | 'targets': self.targets, 56 | 'is_a_data_definition_inst': self.is_a_data_defintion_inst, 57 | 'is_a_branch_or_call': self.is_branch_or_call} 58 | 59 | def SetComment(self, comment): 60 | """ 61 | Set a row's comment field if possible (this will fail with non-ascii). 62 | 63 | Args: 64 | comment: A string comment this expects to be utf-8 that can decode 65 | as ascii. 66 | 67 | Returns: 68 | N / A 69 | """ 70 | try: 71 | self.comment = comment.encode('ascii') 72 | except UnicodeDecodeError: 73 | pass 74 | 75 | def SetLabel(self, label): 76 | """ 77 | Set a RowData's label field if possible (this will fail with non-ascii). 78 | 79 | Args: 80 | label: A string label this expects utf-8 that can be decoded as ascii 81 | 82 | Returns: 83 | N / A 84 | """ 85 | try: 86 | self.label = label.encode('ascii').upper() 87 | except UnicodeDecodeError: 88 | pass 89 | 90 | def SetAddress(self, address): 91 | """ 92 | Set the address from a string. 93 | """ 94 | try: 95 | if address.startswith('0x'): 96 | self.address = int(address, 16) 97 | else: 98 | self.address = int(address) 99 | except ValueError: 100 | pass 101 | 102 | def DisplayAddress(self): 103 | """ 104 | Format an address as a hexadecimal string for display. 105 | """ 106 | return hex(self.address).replace('L', '') 107 | 108 | def SetOpcode(self, hex_str): 109 | """ 110 | Set the opcodes for the row and make sure that the string is a proper 111 | hex string. 112 | """ 113 | try: 114 | self.opcode = binascii.unhexlify(hex_str.replace(' ', '')) 115 | self.in_use = True 116 | except TypeError: 117 | self.in_use = False 118 | self.opcode = hex_str 119 | self.mnemonic = '' 120 | self.error = True 121 | 122 | def SetMnemonic(self, mnemonic): 123 | """ 124 | Set the mnemonic of the row. 125 | 126 | Args: 127 | mnemonic: a string 128 | 129 | Returns: 130 | N / A 131 | """ 132 | if mnemonic == '': 133 | self.opcodes = '' 134 | self.in_use = False 135 | return 136 | 137 | self.mnemonic = mnemonic 138 | 139 | # this is a hack find a better way to do this 140 | normalized_mnemonic = mnemonic.lower().strip() 141 | # FIXME -- this is hard coded for x86/x64 specific 142 | if normalized_mnemonic.startswith('j') or \ 143 | normalized_mnemonic.startswith('call'): 144 | self.is_branch_or_call = True 145 | else: 146 | self.is_branch_or_call = False 147 | 148 | if normalized_mnemonic.split()[0] in ('db', 'dw', 'dd', 'dq'): 149 | self.is_a_data_defintion_inst = True 150 | else: 151 | self.is_a_data_defintion_inst = False 152 | # fix capitalization 153 | # TODO better formatting 154 | new_mnemonic = self.mnemonic.split() 155 | self.mnemonic = '' 156 | self.mnemonic += new_mnemonic[0].upper() + ' ' + \ 157 | ''.join(new_mnemonic[1:]) 158 | self.in_use = True 159 | 160 | def DisplayOpcode(self): 161 | """ 162 | Format the opcode string for display 163 | 164 | Args: 165 | N / A 166 | 167 | Returns: 168 | a string of hex bytes separated with spaces 169 | """ 170 | original_str = binascii.hexlify(self.opcode) 171 | hex_str = '' 172 | 173 | for i in xrange(len(original_str)): 174 | hex_str += original_str[i] 175 | if i % 2 == 1: 176 | hex_str += ' ' 177 | 178 | return hex_str.upper().strip() 179 | 180 | 181 | class AssemblyStoreError(Exception): 182 | pass 183 | 184 | 185 | class AssemblyStore(object): 186 | """ 187 | This class holds all of the state information for the current assembler 188 | session 189 | """ 190 | _instance = None 191 | 192 | def __new__(cls, *args, **kwargs): 193 | """ 194 | Override the new operator so as to keept the assembly store a 195 | singleton. 196 | """ 197 | if not cls._instance: 198 | cls._instance = super(AssemblyStore, cls).__new__(cls, *args, 199 | **kwargs) 200 | return cls._instance 201 | 202 | def __init__(self): 203 | self.bits = 32 204 | self.display_labels = True 205 | self.rows = [] 206 | self.filter_bytes = "" 207 | self.cfg = None 208 | self.labels = set([]) 209 | 210 | # add 20 empty rows by default. 211 | self.AddRows(20) 212 | 213 | def DeepCopyRow(self, index): 214 | """ 215 | Fast deep copy of a row using cPickle 216 | """ 217 | if index < 0 or index >= len(self.rows): 218 | raise AssemblyStoreError("Invalid row index %s" % str(index)) 219 | 220 | row = self.rows[index] 221 | return cPickle.loads(cPickle.dumps(row, -1)) 222 | 223 | def SetBits(self, bits): 224 | """ 225 | Set the operating mode e.g. 16, 32, or 64 226 | 227 | Args: 228 | bits: an integer that's either 16,32, or 64 229 | 230 | Returns: 231 | True if the value was set False otherwise. 232 | """ 233 | if bits in (16, 32, 64): 234 | self.bits = bits 235 | return True 236 | else: 237 | return False 238 | 239 | def SetEndianess(self, little=True): 240 | self.little_endian = little 241 | 242 | def Reset(self): 243 | """ 244 | Reset the AssemblyStore's state to an empty AssemblyStore. 245 | """ 246 | self.cfg = None 247 | self.rows = [] 248 | 249 | def CreateRowFromCapstoneInst(self, index, inst): 250 | """ 251 | Create rows from a distorm3 instruction instance. 252 | 253 | Args: 254 | index: a positive integer 255 | inst: a capstone.CsInsn instance 256 | 257 | Returns: 258 | N / A 259 | """ 260 | mnemonic = "%s %s" % (inst.mnemonic.upper(), inst.op_str) 261 | row = RowData(0, '', inst.address, str(inst.bytes), mnemonic, '', 262 | index, in_use=True) 263 | # check to see if the instruction is a branch instruction else set 264 | # it's target to address plus length of instructionBytes 265 | self.InsertRowAt(index, row) 266 | self.UpdateOffsetsAndAddresses() 267 | 268 | def InsertDBRowAt(self, address, index, byte): 269 | mnemonic = "db 0x%02x" % ord(byte) 270 | row = RowData(0, '', address, byte, mnemonic, '', 271 | index, in_use=True) 272 | self.InsertRowAt(index, row) 273 | 274 | def InsertDBMultibyteRowAt(self, address, index, bytes_vals): 275 | mnemonic = "db " + ", ".join(map(lambda x: "0x%02x" % ord(x), byte_vals)) 276 | row = RowData(0, '', address, chr(byte), mnemonic, '', 277 | index, in_use=True) 278 | self.InsertRowAt(index, row) 279 | return len(byte_vals) 280 | 281 | 282 | def InsertDHRowAt(self, address, index, byte_vals, big_endian=False): 283 | if big_endian: 284 | val = struct.unpack(">H")[0] 285 | else: 286 | val = struct.unpack("I")[0] 296 | else: 297 | val = struct.unpack(" li > a:hover, 188 | .dropdown-menu > li > a:focus { 189 | background-color: #e8e8e8; 190 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f5f5f5), to(#e8e8e8)); 191 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 192 | background-image: -moz-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 193 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 194 | background-repeat: repeat-x; 195 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 196 | } 197 | 198 | .dropdown-menu > .active > a, 199 | .dropdown-menu > .active > a:hover, 200 | .dropdown-menu > .active > a:focus { 201 | background-color: #357ebd; 202 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#357ebd)); 203 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 204 | background-image: -moz-linear-gradient(top, #428bca 0%, #357ebd 100%); 205 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 206 | background-repeat: repeat-x; 207 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 208 | } 209 | 210 | .navbar-default { 211 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ffffff), to(#f8f8f8)); 212 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); 213 | background-image: -moz-linear-gradient(top, #ffffff 0%, #f8f8f8 100%); 214 | background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%); 215 | background-repeat: repeat-x; 216 | border-radius: 4px; 217 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 218 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 219 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); 220 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075); 221 | } 222 | 223 | .navbar-default .navbar-nav > .active > a { 224 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ebebeb), to(#f3f3f3)); 225 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 226 | background-image: -moz-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); 227 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); 228 | background-repeat: repeat-x; 229 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); 230 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); 231 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075); 232 | } 233 | 234 | .navbar-brand, 235 | .navbar-nav > li > a { 236 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); 237 | } 238 | 239 | .navbar-inverse { 240 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#3c3c3c), to(#222222)); 241 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%); 242 | background-image: -moz-linear-gradient(top, #3c3c3c 0%, #222222 100%); 243 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%); 244 | background-repeat: repeat-x; 245 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 246 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 247 | } 248 | 249 | .navbar-inverse .navbar-nav > .active > a { 250 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#222222), to(#282828)); 251 | background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%); 252 | background-image: -moz-linear-gradient(top, #222222 0%, #282828 100%); 253 | background-image: linear-gradient(to bottom, #222222 0%, #282828 100%); 254 | background-repeat: repeat-x; 255 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); 256 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); 257 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25); 258 | } 259 | 260 | .navbar-inverse .navbar-brand, 261 | .navbar-inverse .navbar-nav > li > a { 262 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 263 | } 264 | 265 | .navbar-static-top, 266 | .navbar-fixed-top, 267 | .navbar-fixed-bottom { 268 | border-radius: 0; 269 | } 270 | 271 | .alert { 272 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); 273 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); 274 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05); 275 | } 276 | 277 | .alert-success { 278 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#dff0d8), to(#c8e5bc)); 279 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 280 | background-image: -moz-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 281 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 282 | background-repeat: repeat-x; 283 | border-color: #b2dba1; 284 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 285 | } 286 | 287 | .alert-info { 288 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9edf7), to(#b9def0)); 289 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 290 | background-image: -moz-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 291 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 292 | background-repeat: repeat-x; 293 | border-color: #9acfea; 294 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 295 | } 296 | 297 | .alert-warning { 298 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#fcf8e3), to(#f8efc0)); 299 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 300 | background-image: -moz-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 301 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 302 | background-repeat: repeat-x; 303 | border-color: #f5e79e; 304 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 305 | } 306 | 307 | .alert-danger { 308 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f2dede), to(#e7c3c3)); 309 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 310 | background-image: -moz-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 311 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 312 | background-repeat: repeat-x; 313 | border-color: #dca7a7; 314 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 315 | } 316 | 317 | .progress { 318 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#ebebeb), to(#f5f5f5)); 319 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 320 | background-image: -moz-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 321 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 322 | background-repeat: repeat-x; 323 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 324 | } 325 | 326 | .progress-bar { 327 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9)); 328 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); 329 | background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%); 330 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); 331 | background-repeat: repeat-x; 332 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); 333 | } 334 | 335 | .progress-bar-success { 336 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5cb85c), to(#449d44)); 337 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 338 | background-image: -moz-linear-gradient(top, #5cb85c 0%, #449d44 100%); 339 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 340 | background-repeat: repeat-x; 341 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 342 | } 343 | 344 | .progress-bar-info { 345 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#5bc0de), to(#31b0d5)); 346 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 347 | background-image: -moz-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 348 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 349 | background-repeat: repeat-x; 350 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 351 | } 352 | 353 | .progress-bar-warning { 354 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f0ad4e), to(#ec971f)); 355 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 356 | background-image: -moz-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 357 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 358 | background-repeat: repeat-x; 359 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 360 | } 361 | 362 | .progress-bar-danger { 363 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9534f), to(#c9302c)); 364 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 365 | background-image: -moz-linear-gradient(top, #d9534f 0%, #c9302c 100%); 366 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 367 | background-repeat: repeat-x; 368 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 369 | } 370 | 371 | .list-group { 372 | border-radius: 4px; 373 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 374 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075); 375 | } 376 | 377 | .list-group-item.active, 378 | .list-group-item.active:hover, 379 | .list-group-item.active:focus { 380 | text-shadow: 0 -1px 0 #3071a9; 381 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3278b3)); 382 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%); 383 | background-image: -moz-linear-gradient(top, #428bca 0%, #3278b3 100%); 384 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); 385 | background-repeat: repeat-x; 386 | border-color: #3278b3; 387 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); 388 | } 389 | 390 | .panel { 391 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 392 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); 393 | } 394 | 395 | .panel-default > .panel-heading { 396 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f5f5f5), to(#e8e8e8)); 397 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 398 | background-image: -moz-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 399 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 400 | background-repeat: repeat-x; 401 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 402 | } 403 | 404 | .panel-primary > .panel-heading { 405 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#357ebd)); 406 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 407 | background-image: -moz-linear-gradient(top, #428bca 0%, #357ebd 100%); 408 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 409 | background-repeat: repeat-x; 410 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 411 | } 412 | 413 | .panel-success > .panel-heading { 414 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#dff0d8), to(#d0e9c6)); 415 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 416 | background-image: -moz-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 417 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 418 | background-repeat: repeat-x; 419 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 420 | } 421 | 422 | .panel-info > .panel-heading { 423 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#d9edf7), to(#c4e3f3)); 424 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 425 | background-image: -moz-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 427 | background-repeat: repeat-x; 428 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 429 | } 430 | 431 | .panel-warning > .panel-heading { 432 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#fcf8e3), to(#faf2cc)); 433 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 434 | background-image: -moz-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 435 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 436 | background-repeat: repeat-x; 437 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 438 | } 439 | 440 | .panel-danger > .panel-heading { 441 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#f2dede), to(#ebcccc)); 442 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 443 | background-image: -moz-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 444 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 445 | background-repeat: repeat-x; 446 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 447 | } 448 | 449 | .well { 450 | background-image: -webkit-gradient(linear, left 0%, left 100%, from(#e8e8e8), to(#f5f5f5)); 451 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 452 | background-image: -moz-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 453 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 454 | background-repeat: repeat-x; 455 | border-color: #dcdcdc; 456 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 457 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); 458 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1); 459 | } -------------------------------------------------------------------------------- /app/static/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.0.2 by @fat and @mdo 3 | * Copyright 2013 Twitter, Inc. 4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0 5 | * 6 | * Designed and built with all the love in the world by @mdo and @fat. 7 | */ 8 | 9 | .btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 1px rgba(0,0,0,0.075)}.btn-default:active,.btn-primary:active,.btn-success:active,.btn-info:active,.btn-warning:active,.btn-danger:active,.btn-default.active,.btn-primary.active,.btn-success.active,.btn-info.active,.btn-warning.active,.btn-danger.active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#e0e0e0));background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-moz-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe0e0e0',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-default:hover,.btn-default:focus{background-color:#e0e0e0;background-position:0 -15px}.btn-default:active,.btn-default.active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-primary{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#2d6ca2));background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-moz-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);background-repeat:repeat-x;border-color:#2b669a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff2d6ca2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus{background-color:#2d6ca2;background-position:0 -15px}.btn-primary:active,.btn-primary.active{background-color:#2d6ca2;border-color:#2b669a}.btn-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#419641));background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);background-repeat:repeat-x;border-color:#3e8f3e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff419641',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus{background-color:#419641;background-position:0 -15px}.btn-success:active,.btn-success.active{background-color:#419641;border-color:#3e8f3e}.btn-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#eb9316));background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);background-repeat:repeat-x;border-color:#e38d13;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffeb9316',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus{background-color:#eb9316;background-position:0 -15px}.btn-warning:active,.btn-warning.active{background-color:#eb9316;border-color:#e38d13}.btn-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c12e2a));background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);background-repeat:repeat-x;border-color:#b92c28;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc12e2a',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus{background-color:#c12e2a;background-position:0 -15px}.btn-danger:active,.btn-danger.active{background-color:#c12e2a;border-color:#b92c28}.btn-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#2aabd2));background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);background-repeat:repeat-x;border-color:#28a4c9;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2aabd2',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus{background-color:#2aabd2;background-position:0 -15px}.btn-info:active,.btn-info.active{background-color:#2aabd2;border-color:#28a4c9}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,0,0,0.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.navbar-default{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fff),to(#f8f8f8));background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-moz-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);background-repeat:repeat-x;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff8f8f8',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.15),0 1px 5px rgba(0,0,0,0.075)}.navbar-default .navbar-nav>.active>a{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f3f3f3));background-image:-webkit-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f3f3f3 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f3f3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff3f3f3',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.075);box-shadow:inset 0 3px 9px rgba(0,0,0,0.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,0.25)}.navbar-inverse{background-image:-webkit-gradient(linear,left 0,left 100%,from(#3c3c3c),to(#222));background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-moz-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-gradient(linear,left 0,left 100%,from(#222),to(#282828));background-image:-webkit-linear-gradient(top,#222 0,#282828 100%);background-image:-moz-linear-gradient(top,#222 0,#282828 100%);background-image:linear-gradient(to bottom,#222 0,#282828 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff282828',GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,0.25);box-shadow:inset 0 3px 9px rgba(0,0,0,0.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,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,0.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.25),0 1px 2px rgba(0,0,0,0.05)}.alert-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#c8e5bc));background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);background-repeat:repeat-x;border-color:#b2dba1;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffc8e5bc',GradientType=0)}.alert-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#b9def0));background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);background-repeat:repeat-x;border-color:#9acfea;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffb9def0',GradientType=0)}.alert-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#f8efc0));background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);background-repeat:repeat-x;border-color:#f5e79e;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fff8efc0',GradientType=0)}.alert-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#e7c3c3));background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-moz-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);background-repeat:repeat-x;border-color:#dca7a7;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffe7c3c3',GradientType=0)}.progress{background-image:-webkit-gradient(linear,left 0,left 100%,from(#ebebeb),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-moz-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb',endColorstr='#fff5f5f5',GradientType=0)}.progress-bar{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#3071a9));background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-moz-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3071a9',GradientType=0)}.progress-bar-success{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5cb85c),to(#449d44));background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-moz-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c',endColorstr='#ff449d44',GradientType=0)}.progress-bar-info{background-image:-webkit-gradient(linear,left 0,left 100%,from(#5bc0de),to(#31b0d5));background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-moz-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff31b0d5',GradientType=0)}.progress-bar-warning{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f0ad4e),to(#ec971f));background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-moz-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e',endColorstr='#ffec971f',GradientType=0)}.progress-bar-danger{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9534f),to(#c9302c));background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-moz-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f',endColorstr='#ffc9302c',GradientType=0)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.075);box-shadow:0 1px 2px rgba(0,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-gradient(linear,left 0,left 100%,from(#428bca),to(#3278b3));background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-moz-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);background-repeat:repeat-x;border-color:#3278b3;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff3278b3',GradientType=0)}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.panel-default>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f5f5f5),to(#e8e8e8));background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-moz-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#ffe8e8e8',GradientType=0)}.panel-primary>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#428bca),to(#357ebd));background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-moz-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca',endColorstr='#ff357ebd',GradientType=0)}.panel-success>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#dff0d8),to(#d0e9c6));background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-moz-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8',endColorstr='#ffd0e9c6',GradientType=0)}.panel-info>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#d9edf7),to(#c4e3f3));background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-moz-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7',endColorstr='#ffc4e3f3',GradientType=0)}.panel-warning>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#fcf8e3),to(#faf2cc));background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-moz-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3',endColorstr='#fffaf2cc',GradientType=0)}.panel-danger>.panel-heading{background-image:-webkit-gradient(linear,left 0,left 100%,from(#f2dede),to(#ebcccc));background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-moz-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede',endColorstr='#ffebcccc',GradientType=0)}.well{background-image:-webkit-gradient(linear,left 0,left 100%,from(#e8e8e8),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-moz-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);background-repeat:repeat-x;border-color:#dcdcdc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 3px rgba(0,0,0,0.05),0 1px 0 rgba(255,255,255,0.1)} -------------------------------------------------------------------------------- /app/static/css/local.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: red; 3 | } 4 | 5 | a:hover 6 | { 7 | color: grey; 8 | } 9 | 10 | #main_container 11 | { 12 | padding-top: 10px; 13 | margin-top: 10px; 14 | } 15 | 16 | .navbar-logo-img 17 | { 18 | padding-top: 10px; 19 | max-width: 100px; 20 | } 21 | 22 | .scrollable-menu 23 | { 24 | height: auto; 25 | max-height: 120px; 26 | overflow-x: hidden; 27 | } 28 | 29 | .sigpreview 30 | { 31 | max-width: 400px; 32 | max-height:69px; 33 | } 34 | 35 | .search-bar 36 | { 37 | max-width: 300px; 38 | } 39 | 40 | .command-button 41 | { 42 | width: 200px; 43 | } 44 | 45 | .asm-mnemonic 46 | { 47 | background-color: lightblue; 48 | opacity: 0.8; 49 | font-family:"Lucida Console", Monaco, monospace; 50 | } 51 | 52 | .asm-opcode 53 | { 54 | background-color: lightgrey; 55 | } -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/animated-overlay.gif -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/css/ui-lightness/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /app/static/css/ui-lightness/jquery-ui-1.10.4.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.10.4 - 2014-04-02 2 | * http://jqueryui.com 3 | * Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css 4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px 5 | * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ 6 | 7 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;min-height:0}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;width:100%;list-style-image:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;min-height:0;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("images/animated-overlay.gif");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #e78f08;background:#f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #fbcb09;background:#fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#c77405;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #fbd850;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_228ef1_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffd27a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);border-radius:5px} -------------------------------------------------------------------------------- /app/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmarkowsky/dash/5995a1e0c902be2a1c983ddb8a768118afaaff14/app/static/img/logo.png -------------------------------------------------------------------------------- /app/static/js/backbone.js: -------------------------------------------------------------------------------- 1 | (function(t,e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION="1.1.2";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,"once",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,"off",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,"el"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}if(a.type==="PATCH"&&k){a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,h,s);return h};var k=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var H=/(\(\?)?:\w+/g;var A=/\*\w+/g;var I=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,"\\$&").replace(S,"(?:$1)?").replace(H,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=("/"+this.root+"/").replace(O,"/");if(n&&this._wantsHashChange){var a=e.$('