├── .gitignore ├── LICENSE ├── README.md ├── __init__.py ├── config.py ├── control.py ├── images ├── nodeinfo.png ├── nodes.png ├── queues.png ├── redis.png └── workers.png ├── logs ├── __init__.py ├── worker.err └── worker.log ├── monitor.py ├── requires.txt ├── server.py ├── static └── bootstrap3.3 │ ├── css │ ├── bootstrap-select.css │ ├── bootstrap-select.min.css │ ├── bootstrap-theme.css │ ├── bootstrap-theme.css.map │ ├── bootstrap-theme.min.css │ ├── bootstrap.css │ ├── bootstrap.css.map │ ├── bootstrap.min.css │ └── justified-nav.css │ ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.svg │ ├── glyphicons-halflings-regular.ttf │ └── glyphicons-halflings-regular.woff │ └── js │ ├── bootstrap-select.js │ ├── bootstrap-select.min.js │ ├── bootstrap.js │ ├── bootstrap.min.js │ ├── jquery-3.1.1.min.js │ └── npm.js ├── sutils ├── __init__.py ├── filter.py ├── queues.py ├── sysinfo.py └── wcontrol.py ├── tasks ├── __init__.py └── spider.py ├── templates ├── fails.html ├── index.html ├── nodeinfo.html ├── nodes.html ├── redis.html ├── rediserror.html ├── redisinfo.html └── workers.html └── worker.py /.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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RTask 2 | ## Python3+Huey+Zerorpc+Redis+Flask=RTask 轻量级分布式任务管理系统 3 | ### 系统简介: 4 | 只需要将任务执行脚本放在tasks目录或者其他目录,进行简单的配置,即可将任务变成分布式任务,并可通过web界面节点的任务进行监控和控制 5 | 6 | ### 运行原理: 7 | 将任务脚本放入tasks目录,脚本需要提供main函数并可传入一个参数供系统调用,用来传入任务id,如果需要将任务执行结果进行保存,将保存函数命名为save,并将需要存储的数据当做参数传入,系统将自动调用save函数存储运行结果;本系统利用redis数据库作为数据队列,数据去重数据库,节点监控数据库,配置文件config.py修改后,在节点机器运行python3 server.py即可,节点会自动在配置的redis数据库中注册节点的信息,监控端运行python3 monitor.py即可访问本地端口8888对节点和任务进行管理,管理端通过zerorpc远程调用控制节点,各个节点通过huey开启多个任务,每一个任务都是一个进程,注意任务数量不要太多,推荐使用协程写任务,然后开启适量的进程数量. 8 | 9 | ## 功能特点 10 | + 配置部署简单,只需要安装相应的第三方库,对配置文件进行简单的配置,运行server.py文件即可 11 | + 支持redis集群 12 | + 节点监控方便,可通过控制面板添加修改任务,启动指定数量任务,监控节点系统和redis系统状态 13 | + 内置数据去重算法,该系统最初为分布式爬虫而设计,故添加了两种数据去重算法,redis SET集合去重占用内存高,无错误率,适用于千万级别数据的去重,bloomfliter算法去重占用内存低,存在错误率,适用于上亿级别的数据去重 14 | 15 | ## 监控端展示 16 | ### 任务队列 17 | ![Alt Text](https://github.com/HatBoy/RTask/blob/master/images/queues.png) 18 | 19 | ### 节点展示 20 | ![Alt Text](https://github.com/HatBoy/RTask/blob/master/images/nodes.png) 21 | 22 | ### 节点状态展示 23 | ![Alt Text](https://github.com/HatBoy/RTask/blob/master/images/nodeinfo.png) 24 | 25 | ### 工作进程控制 26 | ![Alt Text](https://github.com/HatBoy/RTask/blob/master/images/workers.png) 27 | 28 | ### redis状态监控 29 | ![Alt Text](https://github.com/HatBoy/RTask/blob/master/images/redis.png) 30 | 31 | ## 系统使用配置 32 | ### 1.安装第三方依赖库和redis 33 | ### 2.编写任务脚本并预留main方法和save方法,save方法可选 34 | ### 3.配置任务 35 | ```Python3 36 | #coding=UTF-8 37 | 38 | #配置文件,配置系统需要的数据库等参数 39 | 40 | #任务配置 41 | TASK_NAME = 'spider' 42 | #任务返回的结果字典中taskid的名称 43 | TASK_ID = 'id' 44 | #是否开启自动扩展功能,如执行一个任务之后会解析出更多的任务 45 | IS_NEXT = True 46 | #任务返回的结果字典中待爬取的taskid的名称,必须是序列 47 | NEXT_IDS = 'nextids' 48 | #任务的模块名和路径 49 | TASK_MODULE = 'tasks.spider' 50 | #redis队列数据库配置 51 | #redis类型,单机redis(single)还是集群redis(cluster) 52 | QUEUE_REDIS_TYPE = 'single' 53 | QUEUE_REDIS_HOST = '192.168.1.100' 54 | QUEUE_REDIS_PORT = 6379 55 | QUEUE_REDIS_DB = 0 56 | QUEUE_REDIS_PWD = '123456' 57 | QUEUE_REDIS_NODES = [{"host": "127.0.0.1", "port": "7000"}, {"host": "127.0.0.1", "port": "7001"}, {"host": "127.0.0.1", "port": "7002"}, {"host": "127.0.0.1", "port": "7003"}] 58 | 59 | #是否将任务返回的结果保存,如果保存,则自动调用任务的save方法将数据传入 60 | IS_SAVE = True 61 | 62 | #去重配置 63 | #是否开启任务去重功能 64 | IS_FILTER = True 65 | #去重方式,redis集合(set)去重或者bloomfilter算法(bloom)去重 66 | FILTER_TYPE = 'set' 67 | FILTER_REDIS_TYPE = 'single' 68 | FILTER_REDIS_HOST = '192.168.1.101' 69 | FILTER_REDIS_PORT = 6379 70 | FILTER_REDIS_DB = 0 71 | FILTER_REDIS_PWD = '123456' 72 | #redis集群节点 73 | FILTER_REDIS_NODES = [{"host": "127.0.0.1", "port": "7000"}, {"host": "127.0.0.1", "port": "7001"}, {"host": "127.0.0.1", "port": "7002"}, {"host": "127.0.0.1", "port": "7003"}] 74 | #若使用BloomFilter算法去重需要预先知道要去重的数量和错误率 75 | CAPACITY = 100000000 76 | ERROR_RATE = 0.00000001 77 | 78 | #RTask配置,只能是单机redis不支持集群,于存放各个节点,worker等信息,无需集群 79 | RTASK_REDIS_HOST = '192.168.1.102' 80 | RTASK_REDIS_POST = 6379 81 | RTASK_REDIS_DB = 0 82 | #RTASK_REDIS_PWD = None 83 | RTASK_REDIS_PWD = '123456' 84 | #RPC远程连接端口 85 | RPC_PORT = 5555 86 | #远程RPC控制认证密码 87 | RPC_PWD = '123456' 88 | ``` 89 | ### 4.在节点机器运行python3 server.py启动系统,在任意能访问节点和redis数据库的主机以相同的配置运行python3 monitor.py启动监控方 90 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | #coding=UTF-8 -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | #coding=UTF-8 2 | 3 | #配置文件,配置系统需要的数据库等参数 4 | 5 | #任务配置 6 | TASK_NAME = 'spider' 7 | #任务返回的结果字典中taskid的名称 8 | TASK_ID = 'id' 9 | #是否开启自动扩展功能,如执行一个任务之后会解析出更多的任务 10 | IS_NEXT = True 11 | #任务返回的结果字典中待爬取的taskid的名称,必须是序列 12 | NEXT_IDS = 'nextids' 13 | #任务的模块名和路径 14 | TASK_MODULE = 'tasks.spider' 15 | #最大错误次数 16 | MAX_ERROR_NUMS = 10 17 | #超过最大错误次数休眠时间 18 | ERROR_SLEEP = 30*60 19 | #redis队列数据库配置 20 | #redis类型,单机redis(single)还是集群redis(cluster) 21 | QUEUE_REDIS_TYPE = 'single' 22 | QUEUE_REDIS_HOST = '192.168.1.100' 23 | QUEUE_REDIS_PORT = 6379 24 | QUEUE_REDIS_DB = 0 25 | QUEUE_REDIS_PWD = '123456' 26 | QUEUE_REDIS_NODES = [{"host": "127.0.0.1", "port": "7000"}, {"host": "127.0.0.1", "port": "7001"}, {"host": "127.0.0.1", "port": "7002"}, {"host": "127.0.0.1", "port": "7003"}] 27 | 28 | #是否将任务返回的结果保存,如果保存,则自动调用任务的save方法将数据传入 29 | IS_SAVE = True 30 | 31 | #去重配置 32 | #是否开启任务去重功能 33 | IS_FILTER = True 34 | #去重方式,redis集合(set)去重或者bloomfilter算法(bloom)去重 35 | FILTER_TYPE = 'set' 36 | FILTER_REDIS_TYPE = 'single' 37 | FILTER_REDIS_HOST = '192.168.1.101' 38 | FILTER_REDIS_PORT = 6379 39 | FILTER_REDIS_DB = 0 40 | FILTER_REDIS_PWD = '123456' 41 | #redis集群节点 42 | FILTER_REDIS_NODES = [{"host": "127.0.0.1", "port": "7000"}, {"host": "127.0.0.1", "port": "7001"}, {"host": "127.0.0.1", "port": "7002"}, {"host": "127.0.0.1", "port": "7003"}] 43 | #若使用BloomFilter算法去重需要预先知道要去重的数量和错误率 44 | CAPACITY = 100000000 45 | ERROR_RATE = 0.00000001 46 | 47 | #RTask配置,只能是单机redis不支持集群,于存放各个节点,worker等信息,无需集群 48 | RTASK_REDIS_HOST = '192.168.1.102' 49 | RTASK_REDIS_POST = 6379 50 | RTASK_REDIS_DB = 0 51 | #RTASK_REDIS_PWD = None 52 | RTASK_REDIS_PWD = '123456' 53 | #RPC远程连接端口 54 | RPC_PORT = 5555 55 | #远程RPC控制认证密码 56 | RPC_PWD = '123456' 57 | -------------------------------------------------------------------------------- /control.py: -------------------------------------------------------------------------------- 1 | #coding=UTF-8 2 | 3 | import redis 4 | import zerorpc 5 | from config import * 6 | from sutils import queues 7 | 8 | 9 | #节点信息 10 | class NodeInfo(): 11 | def __init__(self): 12 | self.pool = redis.ConnectionPool(host=RTASK_REDIS_HOST, port=RTASK_REDIS_POST, db=RTASK_REDIS_DB, password=RTASK_REDIS_PWD, encoding='utf-8', decode_responses=True) 13 | self.client = redis.StrictRedis(connection_pool=self.pool) 14 | 15 | def node_list(self): 16 | nodes = self.client.hgetall(TASK_NAME+':task_nodes') 17 | node_lists = list() 18 | for k, v in nodes.items(): 19 | #macid = k.decode('UTF-8') 20 | data = eval(v) 21 | rpcip = None 22 | ips = data['ips'] 23 | for ip in ips: 24 | if self.rpcconn_check(ip): 25 | rpcip = ip 26 | break 27 | data['rpcip'] = "tcp://{ip}:{port}".format(ip=rpcip, port=RPC_PORT) 28 | node_lists.append(data) 29 | return node_lists 30 | 31 | def node_search(self, macid): 32 | node = self.client.hget(TASK_NAME+':task_nodes', macid) 33 | node = eval(node) 34 | rpcip = None 35 | ips = node['ips'] 36 | for ip in ips: 37 | if self.rpcconn_check(ip): 38 | rpcip = ip 39 | break 40 | node['rpcip'] = "tcp://{ip}:{port}".format(ip=rpcip, port=RPC_PORT) 41 | return node 42 | 43 | def rpcconn_check(self, ip): 44 | try: 45 | rpc = zerorpc.Client(timeout=3, heartbeat=3) 46 | rpc.connect("tcp://{ip}:{port}".format(ip=ip, port=RPC_PORT)) 47 | ping = rpc.ping() 48 | rpc.close() 49 | return ping 50 | except Exception as e: 51 | return False 52 | 53 | def task_list(self): 54 | tasks = self.client.hgetall(TASK_NAME+':task_status') 55 | node_lists = self.node_list() 56 | macid_rpcip = dict() 57 | for node in node_lists: 58 | macid_rpcip[node['macid']] = node['rpcip'] 59 | task_lists = list() 60 | for k, v in tasks.items(): 61 | data = eval(v) 62 | data['rpcip'] = macid_rpcip[data['macid']] 63 | task_lists.append(data) 64 | task_lists.sort(key=lambda x:x['macid']) 65 | return task_lists 66 | 67 | def node_tasks(self, macid): 68 | nodes = self.client.hget(TASK_NAME+':task_nodes', macid) 69 | node_dict = eval(nodes) 70 | tasks = node_dict['tasks'] 71 | task_lists = list() 72 | for t in tasks: 73 | task = self.client.hget(TASK_NAME+':task_status', t) 74 | task = eval(task) 75 | task_lists.append(task) 76 | return task_lists 77 | 78 | def start_alltasks(self): 79 | alltasks = self.client.hgetall(TASK_NAME+':task_status') 80 | for task_uuid, task_data in alltasks.items(): 81 | task_uuid = task_uuid 82 | task_data = eval(task_data) 83 | status = task_data['status'] 84 | if status == 'stop': 85 | task_data['status'] = 'run' 86 | self.client.hset(TASK_NAME+':task_status', task_uuid, task_data) 87 | 88 | def stop_alltasks(self): 89 | alltasks = self.client.hgetall(TASK_NAME + ':task_status') 90 | for task_uuid, task_data in alltasks.items(): 91 | task_uuid = task_uuid 92 | task_data = eval(task_data) 93 | status = task_data['status'] 94 | if status == 'run': 95 | task_data['status'] = 'stop' 96 | self.client.hset(TASK_NAME + ':task_status', task_uuid, task_data) 97 | 98 | def clear_data(self): 99 | self.client.delete(TASK_NAME+':task_nodes') 100 | self.client.delete(TASK_NAME+':task_status') 101 | 102 | #服务端worker控制 103 | class WorkerControl(): 104 | 105 | def __init__(self, ip): 106 | self.rpc = zerorpc.Client(timeout=3, heartbeat=3) 107 | self.rpc.connect("tcp://{ip}:{port}".format(ip=ip, port=RPC_PORT)) 108 | 109 | def ping(self): 110 | try: 111 | return self.rpc.ping() 112 | except Exception as e: 113 | return False 114 | 115 | def start_worker(self, worker_nums=10): 116 | result = self.rpc.start_worker(worker_nums, RPC_PWD) 117 | return result 118 | 119 | def kill_worker(self): 120 | result = self.rpc.kill_worker(RPC_PWD) 121 | return result 122 | 123 | def worker_status(self): 124 | status = self.rpc.worker_status(RPC_PWD) 125 | return status 126 | 127 | def stop_task(self, task_uuid): 128 | result = self.rpc.stop_task(task_uuid, RPC_PWD) 129 | return result 130 | 131 | def restart_task(self, task_uuid): 132 | result = self.rpc.restart_task(task_uuid, RPC_PWD) 133 | return result 134 | 135 | def stop_alltasks(self): 136 | result = self.rpc.stop_alltasks(RPC_PWD) 137 | return result 138 | 139 | def restart_alltasks(self): 140 | result = self.rpc.restart_alltasks(RPC_PWD) 141 | return result 142 | 143 | def exit_rpc(self): 144 | try: 145 | self.rpc.exit_rpc(RPC_PWD) 146 | return self.rpc.ping() 147 | except Exception as e: 148 | return True 149 | 150 | def close(self): 151 | self.rpc.close() 152 | 153 | #任务队列信息 154 | class QueueInfo(): 155 | 156 | def __init__(self): 157 | self.client = queues.get_redis_client(QUEUE_REDIS_TYPE, QUEUE_REDIS_HOST, QUEUE_REDIS_PORT, QUEUE_REDIS_DB, QUEUE_REDIS_PWD, QUEUE_REDIS_NODES) 158 | self.queues = queues.RedisQueues(conn=self.client) 159 | 160 | def taskid_counts(self): 161 | return self.queues.len(TASK_NAME+':task_ids') 162 | 163 | def taskfail_counts(self): 164 | return self.queues.len(TASK_NAME+':task_fails') 165 | 166 | def taskid_range(self, start, end): 167 | return self.queues.range(TASK_NAME+':task_ids', start, end) 168 | 169 | def taskfail_range(self, start, end): 170 | fail_datas = self.queues.range(TASK_NAME+':task_fails', start, end) 171 | if fail_datas: 172 | return [eval(fail) for fail in fail_datas] 173 | else: 174 | return list() 175 | 176 | def task_index(self, key, index): 177 | return self.queues.index(key, index) 178 | 179 | def taskid_add(self, task_id): 180 | return self.queues.push(TASK_NAME+':task_ids', task_id) 181 | 182 | def task_delete(self, key, value): 183 | count = self.queues.delete_value(key, value) 184 | return count 185 | 186 | def taskid_first(self, task_id): 187 | return self.queues.first(TASK_NAME+':task_ids', task_id) 188 | 189 | def taskid_last(self, task_id): 190 | return self.queues.last(TASK_NAME+':task_ids', task_id) 191 | 192 | def taskfail_rpush(self, value): 193 | taskid = value['taskid'] 194 | self.task_delete(TASK_NAME+':task_fails', value) 195 | return self.queues.push(TASK_NAME+':task_ids', taskid) 196 | 197 | def taskfail_all_rpush(self): 198 | fail_counts = self.taskfail_counts() 199 | fails = self.taskfail_range(0, fail_counts) 200 | fail_ids = [fail['taskid'] for fail in fails] 201 | self.queues.delete_key(TASK_NAME+':task_fails') 202 | for task_id in fail_ids: 203 | self.queues.push(TASK_NAME+':task_ids', task_id) 204 | return 'OK' 205 | 206 | def taskid_empty(self): 207 | return self.queues.delete_key(TASK_NAME+':task_ids') 208 | 209 | def taskfail_empty(self): 210 | return self.queues.delete_key(TASK_NAME+':task_fails') 211 | 212 | 213 | #Redis信息 214 | class RedisInfo(): 215 | 216 | def __init__(self, conn=None): 217 | self.redis = conn 218 | 219 | def info(self): 220 | return self.redis.info() 221 | 222 | def config_get(self): 223 | return self.redis.config_get('*') 224 | 225 | def client_list(self): 226 | clients = self.redis.client_list() 227 | if isinstance(clients, list): 228 | client_lists = list() 229 | for client in clients: 230 | temps = list() 231 | for k, v in client.items(): 232 | temps.append(k+'='+v) 233 | client_lists.append(' '.join(temps)) 234 | return client_lists 235 | else: 236 | client_dicts = dict() 237 | for ip, clients in clients.items(): 238 | client_lists = list() 239 | for client in clients: 240 | temps = list() 241 | for k, v in client.items(): 242 | temps.append(k + '=' + v) 243 | client_lists.append(' '.join(temps)) 244 | client_dicts[ip] = client_lists 245 | return client_dicts 246 | 247 | def save(self, is_bgsave=False): 248 | if is_bgsave: 249 | return self.redis.bgsave() 250 | else: 251 | return self.redis.save() 252 | 253 | 254 | #节点服务器系统信息 255 | class ServerInfo(): 256 | 257 | def __init__(self, ip): 258 | self.rpc = zerorpc.Client(timeout=3, heartbeat=3) 259 | self.rpc.connect("tcp://{ip}:{port}".format(ip=ip, port=RPC_PORT)) 260 | 261 | def get_sysinfo(self): 262 | sysinfo = self.rpc.sysinfo(RPC_PWD) 263 | return sysinfo 264 | 265 | # client = queues.get_redis_client(QUEUE_REDIS_TYPE, QUEUE_REDIS_HOST, QUEUE_REDIS_PORT, QUEUE_REDIS_DB, QUEUE_REDIS_PWD, QUEUE_REDIS_NODES) 266 | # queues = queues.RedisQueues(conn=client) 267 | 268 | 269 | # pool = redis.ConnectionPool(host=QUEUE_REDIS_HOST, port=QUEUE_REDIS_PORT, db=QUEUE_REDIS_DB, password=QUEUE_REDIS_PWD) 270 | # client = redis.StrictRedis(connection_pool=pool) 271 | 272 | # qi = QueueInfo() 273 | # qi.taskfail_rpush({'taskid': '27050696', 'error': "module 'tasks.spider' has no attribute 'save'"}) 274 | 275 | # ni = NodeInfo() 276 | # ni.task_list() -------------------------------------------------------------------------------- /images/nodeinfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/images/nodeinfo.png -------------------------------------------------------------------------------- /images/nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/images/nodes.png -------------------------------------------------------------------------------- /images/queues.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/images/queues.png -------------------------------------------------------------------------------- /images/redis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/images/redis.png -------------------------------------------------------------------------------- /images/workers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/images/workers.png -------------------------------------------------------------------------------- /logs/__init__.py: -------------------------------------------------------------------------------- 1 | #coding=UTF-8 -------------------------------------------------------------------------------- /logs/worker.err: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/logs/worker.err -------------------------------------------------------------------------------- /logs/worker.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/logs/worker.log -------------------------------------------------------------------------------- /monitor.py: -------------------------------------------------------------------------------- 1 | # coding=UTF-8 2 | 3 | from flask import Flask, render_template, request, redirect 4 | from config import * 5 | from control import * 6 | from sutils.queues import get_redis_client 7 | 8 | app = Flask(__name__) 9 | 10 | ##############################################任务队列############################################## 11 | 12 | @app.route('/', methods=['GET', 'POST']) 13 | @app.route('/index/', methods=['GET', 'POST']) 14 | @app.route('/queues/', methods=['GET', 'POST']) 15 | def index(): 16 | redis_errors = redis_check() 17 | if len(redis_errors) > 0: 18 | return render_template('rediserror.html', redis_errors=redis_errors) 19 | name = request.args.get('name', 'ids') 20 | task_name = TASK_NAME 21 | queueinfo = QueueInfo() 22 | taskid_counts = queueinfo.taskid_counts() 23 | taskfail_counts = queueinfo.taskfail_counts() 24 | if name == 'fails': 25 | taskfail_range = queueinfo.taskfail_range(0, 99) 26 | return render_template('fails.html', task_name=task_name, taskid_counts=taskid_counts, 27 | taskfail_counts=taskfail_counts, taskfail_range=taskfail_range) 28 | else: 29 | taskid_range = queueinfo.taskid_range(-100, -1) 30 | if not taskid_range: 31 | taskid_range = list() 32 | taskid_range.reverse() 33 | return render_template('index.html', task_name=task_name, taskid_counts=taskid_counts, 34 | taskfail_counts=taskfail_counts, taskid_range=taskid_range) 35 | 36 | 37 | @app.route('/taskfirst/', methods=['GET', 'POST']) 38 | def taskid_first(): 39 | taskid = request.args.get('taskid', None) 40 | queueinfo = QueueInfo() 41 | queueinfo.taskid_first(taskid) 42 | return redirect('/index/') 43 | 44 | 45 | @app.route('/tasklast/', methods=['GET', 'POST']) 46 | def taskid_last(): 47 | taskid = request.args.get('taskid', None) 48 | queueinfo = QueueInfo() 49 | queueinfo.taskid_last(taskid) 50 | return redirect('/index/') 51 | 52 | 53 | @app.route('/taskdelete/', methods=['GET', 'POST']) 54 | def taskid_delete(): 55 | taskid = request.args.get('taskid', None) 56 | queueinfo = QueueInfo() 57 | queueinfo.task_delete(TASK_NAME + ':task_ids', taskid) 58 | return redirect('/index/') 59 | 60 | 61 | @app.route('/faildelete/', methods=['GET', 'POST']) 62 | def taskfail_delete(): 63 | taskfail = request.args.get('taskfail', None) 64 | queueinfo = QueueInfo() 65 | queueinfo.task_delete(TASK_NAME + ':task_fails', eval(taskfail)) 66 | return redirect('/index/?name=fails') 67 | 68 | 69 | @app.route('/failrpush/', methods=['GET', 'POST']) 70 | def taskfail_rpush(): 71 | taskfail = request.args.get('taskfail', None) 72 | queueinfo = QueueInfo() 73 | queueinfo.taskfail_rpush(eval(taskfail)) 74 | return redirect('/index/?name=fails') 75 | 76 | 77 | @app.route('/failallrpush/', methods=['GET', 'POST']) 78 | def taskfail_all_rpush(): 79 | queueinfo = QueueInfo() 80 | queueinfo.taskfail_all_rpush() 81 | return redirect('/index/?name=fails') 82 | 83 | 84 | @app.route('/emptyfail/', methods=['GET', 'POST']) 85 | def empty_fail(): 86 | queueinfo = QueueInfo() 87 | queueinfo.taskfail_empty() 88 | return redirect('/index/?name=fails') 89 | 90 | 91 | @app.route('/emptytask/', methods=['GET', 'POST']) 92 | def empty_task(): 93 | queueinfo = QueueInfo() 94 | queueinfo.taskid_empty() 95 | return redirect('/index/') 96 | 97 | 98 | @app.route('/addtask/', methods=['GET', 'POST']) 99 | def add_task(): 100 | queueinfo = QueueInfo() 101 | if request.method == 'POST': 102 | taskid = request.form['taskid'] 103 | if taskid.strip(): 104 | queueinfo.taskid_add(taskid.strip()) 105 | return redirect('/index/') 106 | 107 | 108 | ##############################################工作节点############################################## 109 | 110 | @app.route('/nodes/', methods=['GET', 'POST']) 111 | def node_lists(): 112 | redis_errors = redis_check() 113 | if len(redis_errors) > 0: 114 | return render_template('rediserror.html', redis_errors=redis_errors) 115 | nodeinfo = NodeInfo() 116 | node_list = nodeinfo.node_list() 117 | newnode_list = list() 118 | node_nums = len(node_list) 119 | run_nodes = 0 120 | stop_nodes = 0 121 | for node in node_list: 122 | macid = node['macid'] 123 | task_lists = nodeinfo.node_tasks(macid) 124 | task_nums = len(task_lists) 125 | run_nums = 0 126 | stop_nums = 0 127 | if task_nums > 0: 128 | status_show = '运行' 129 | run_nodes += 1 130 | else: 131 | status_show = '停止' 132 | stop_nodes += 1 133 | for task in task_lists: 134 | status = task['status'] 135 | if status == 'run': 136 | run_nums += 1 137 | else: 138 | stop_nums += 1 139 | node['status_show'] = status_show 140 | node['task_nums'] = task_nums 141 | node['run_nums'] = run_nums 142 | node['stop_nums'] = stop_nums 143 | newnode_list.append(node) 144 | return render_template('nodes.html', node_list=newnode_list, node_nums=node_nums, run_nodes=run_nodes, 145 | stop_nodes=stop_nodes) 146 | 147 | 148 | @app.route('/nodeinfo/', methods=['GET', 'POST']) 149 | def node_info(): 150 | rpcip = request.args.get('rpcip', None) 151 | if rpcip.strip(): 152 | ip = rpcip.split(':')[1][2:] 153 | serverinfo = ServerInfo(ip) 154 | nodeinfo = NodeInfo() 155 | system_infos = serverinfo.get_sysinfo() 156 | cpu_info = system_infos['cpu_info'] 157 | memory_info = system_infos['memory_info'] 158 | disk_info = system_infos['disk_info'] 159 | network_info = system_infos['network_info'] 160 | macid = system_infos['macid'] 161 | base_info = nodeinfo.node_search(macid) 162 | task_lists = nodeinfo.node_tasks(macid) 163 | base_info['task_nums'] = len(task_lists) 164 | newtask_lists = list() 165 | run_nums = 0 166 | stop_nums = 0 167 | for task in task_lists: 168 | status = task['status'] 169 | if status == 'run': 170 | status_show = '运行' 171 | operation = '停止' 172 | run_nums += 1 173 | else: 174 | status_show = '停止' 175 | operation = '运行' 176 | stop_nums += 1 177 | task['status_show'] = status_show 178 | task['operation'] = operation 179 | newtask_lists.append(task) 180 | return render_template('nodeinfo.html', base_info=base_info, cpu_info=cpu_info, memory_info=memory_info, 181 | disk_info=disk_info, network_info=network_info, task_lists=newtask_lists, run_nums=run_nums, 182 | stop_nums=stop_nums) 183 | 184 | 185 | @app.route('/nodestop/', methods=['GET', 'POST']) 186 | def node_stop(): 187 | rpcip = request.args.get('rpcip', None) 188 | if rpcip.strip(): 189 | ip = rpcip.split(':')[1][2:] 190 | workercontrol = WorkerControl(ip) 191 | workercontrol.kill_worker() 192 | return redirect('/nodes/') 193 | 194 | 195 | @app.route('/nodedelete/', methods=['GET', 'POST']) 196 | def node_delete(): 197 | rpcip = request.args.get('rpcip', None) 198 | if rpcip.strip(): 199 | ip = rpcip.split(':')[1][2:] 200 | workercontrol = WorkerControl(ip) 201 | workercontrol.exit_rpc() 202 | return redirect('/nodes/') 203 | 204 | 205 | ##############################################运行进程############################################## 206 | 207 | @app.route('/workers/', methods=['GET', 'POST']) 208 | def worker_lists(): 209 | redis_errors = redis_check() 210 | if len(redis_errors) > 0: 211 | return render_template('rediserror.html', redis_errors=redis_errors) 212 | nodeinfo = NodeInfo() 213 | task_lists = nodeinfo.task_list() 214 | node_lists = nodeinfo.node_list() 215 | newtask_lists = list() 216 | task_nums = len(task_lists) 217 | run_nums = 0 218 | stop_nums = 0 219 | for task in task_lists: 220 | status = task['status'] 221 | if status == 'run': 222 | status_show = '运行' 223 | operation = '停止' 224 | run_nums += 1 225 | else: 226 | status_show = '停止' 227 | operation = '运行' 228 | stop_nums += 1 229 | task['status_show'] = status_show 230 | task['operation'] = operation 231 | newtask_lists.append(task) 232 | return render_template('workers.html', task_lists=newtask_lists, task_nums=task_nums, run_nums=run_nums, 233 | stop_nums=stop_nums, node_lists=node_lists) 234 | 235 | 236 | # 停止或者开始单个进程 237 | @app.route('/worker_control/', methods=['GET', 'POST']) 238 | def worker_control(): 239 | status = request.args.get('status', None) 240 | rpcip = request.args.get('rpcip', None) 241 | task_uuid = request.args.get('task_uuid', None) 242 | page = request.args.get('page', None) 243 | if status and rpcip and task_uuid and page: 244 | ip = rpcip.split(':')[1][2:] 245 | workercontrol = WorkerControl(ip) 246 | if status == 'run': 247 | workercontrol.stop_task(task_uuid) 248 | else: 249 | workercontrol.restart_task(task_uuid) 250 | if page == 'workers': 251 | return redirect('/workers/') 252 | else: 253 | return redirect('/nodeinfo/?rpcip=' + rpcip) 254 | 255 | 256 | @app.route('/startworkers/', methods=['GET', 'POST']) 257 | def start_workers(): 258 | if request.method == 'GET': 259 | rpcip = request.form['rpcip'] 260 | task_nums = request.form['task_nums'] 261 | if request.method == 'POST': 262 | rpcip = request.form['rpcip'] 263 | task_nums = request.form['task_nums'] 264 | if rpcip and task_nums: 265 | try: 266 | task_nums = int(task_nums) 267 | if task_nums > 0: 268 | ip = rpcip.split(':')[1][2:] 269 | workercontrol = WorkerControl(ip) 270 | workercontrol.start_worker(task_nums) 271 | except Exception as e: 272 | pass 273 | return redirect('/nodeinfo/?rpcip=' + rpcip) 274 | 275 | 276 | # 打开指定节点的所有进程 277 | @app.route('/startalltasks/', methods=['GET', 'POST']) 278 | def start_alltasks(): 279 | rpcip = request.args.get('rpcip', None) 280 | if rpcip.strip(): 281 | ip = rpcip.split(':')[1][2:] 282 | workercontrol = WorkerControl(ip) 283 | workercontrol.restart_alltasks() 284 | return redirect('/nodeinfo/?rpcip=' + rpcip) 285 | 286 | 287 | # 打开所有节点的所有进程 288 | @app.route('/alltasksstart/', methods=['GET', 'POST']) 289 | def alltasks_start(): 290 | nodeinfo = NodeInfo() 291 | nodeinfo.start_alltasks() 292 | return redirect('/workers/') 293 | 294 | 295 | # 关闭所有节点的所有进程 296 | @app.route('/alltasksstop/', methods=['GET', 'POST']) 297 | def alltasks_stop(): 298 | nodeinfo = NodeInfo() 299 | nodeinfo.stop_alltasks() 300 | return redirect('/workers/') 301 | 302 | 303 | # 关闭指定节点的所有进程 304 | @app.route('/stopalltasks/', methods=['GET', 'POST']) 305 | def stop_alltasks(): 306 | rpcip = request.args.get('rpcip', None) 307 | if rpcip.strip(): 308 | ip = rpcip.split(':')[1][2:] 309 | workercontrol = WorkerControl(ip) 310 | workercontrol.stop_alltasks() 311 | return redirect('/nodeinfo/?rpcip=' + rpcip) 312 | 313 | 314 | ##############################################Redis状态############################################## 315 | 316 | def redis_check(): 317 | redis_errors = list() 318 | try: 319 | queue_client = get_redis_client(QUEUE_REDIS_TYPE, QUEUE_REDIS_HOST, QUEUE_REDIS_PORT, QUEUE_REDIS_DB, 320 | QUEUE_REDIS_PWD, QUEUE_REDIS_NODES) 321 | queue_client.ping() 322 | except Exception as e: 323 | dest = 'Redis任务队列数据库连接失败!请检查Redis连接配置是否正确或者正常运行' 324 | redis_errors.append({'dest': dest, 'error': str(e)}) 325 | if IS_FILTER: 326 | try: 327 | filter_client = get_redis_client(FILTER_REDIS_TYPE, FILTER_REDIS_HOST, FILTER_REDIS_PORT, FILTER_REDIS_DB, 328 | FILTER_REDIS_PWD, FILTER_REDIS_NODES) 329 | filter_client.ping() 330 | except Exception as e: 331 | dest = 'Redis数据去重数据库连接失败!请检查Redis连接配置是否正确或者正常运行' 332 | redis_errors.append({'dest': dest, 'error': str(e)}) 333 | try: 334 | rtask_client = get_redis_client('single', RTASK_REDIS_HOST, RTASK_REDIS_POST, RTASK_REDIS_DB, 335 | RTASK_REDIS_PWD, None) 336 | rtask_client.ping() 337 | except Exception as e: 338 | dest = 'Redis RTask控制数据库连接失败!请检查Redis连接配置是否正确或者正常运行' 339 | redis_errors.append({'dest': dest, 'error': str(e)}) 340 | return redis_errors 341 | 342 | 343 | @app.route('/redis/', methods=['GET', 'POST']) 344 | def redis_list(): 345 | redis_errors = redis_check() 346 | if len(redis_errors) > 0: 347 | return render_template('rediserror.html', redis_errors=redis_errors) 348 | queue_client = get_redis_client(QUEUE_REDIS_TYPE, QUEUE_REDIS_HOST, QUEUE_REDIS_PORT, QUEUE_REDIS_DB, 349 | QUEUE_REDIS_PWD, QUEUE_REDIS_NODES) 350 | filter_client = get_redis_client(FILTER_REDIS_TYPE, FILTER_REDIS_HOST, FILTER_REDIS_PORT, FILTER_REDIS_DB, 351 | FILTER_REDIS_PWD, FILTER_REDIS_NODES) 352 | rtask_client = get_redis_client('single', RTASK_REDIS_HOST, RTASK_REDIS_POST, RTASK_REDIS_DB, 353 | RTASK_REDIS_PWD) 354 | redis_lists = list() 355 | 356 | redisinfo_queue = RedisInfo(queue_client) 357 | queue_info = redisinfo_queue.info() 358 | queue_dict = {'dest': 'Redis任务队列数据库', 'name': 'queue'} 359 | if QUEUE_REDIS_TYPE == 'single': 360 | queue_dict['type'] = '单机' 361 | queue_dict['ip_port'] = QUEUE_REDIS_HOST + ' : ' + str(QUEUE_REDIS_PORT) 362 | queue_dict['dbsize'] = queue_client.dbsize() 363 | queue_dict['clients'] = queue_info['connected_clients'] 364 | queue_dict['used_memory'] = queue_info['used_memory_human'] 365 | elif QUEUE_REDIS_TYPE == 'cluster': 366 | queue_dict['type'] = '集群' 367 | queue_dict['ip_port'] = [node['host'] + ' : ' + node['port'] for node in QUEUE_REDIS_NODES] 368 | queue_dict['dbsize'] = [k + ' : ' + str(v) for k, v in queue_client.dbsize().items()] 369 | queue_dict['clients'] = [k + ' : ' + str(v['connected_clients']) for k, v in queue_info.items()] 370 | queue_dict['used_memory'] = [k + ' : ' + v['used_memory_human'] for k, v in queue_info.items()] 371 | redis_lists.append(queue_dict) 372 | 373 | if IS_FILTER: 374 | redisinfo_filter = RedisInfo(filter_client) 375 | filter_info = redisinfo_filter.info() 376 | filter_dict = {'dest': 'Redis数据去重数据库', 'name': 'filter'} 377 | if FILTER_REDIS_TYPE == 'single': 378 | filter_dict['type'] = '单机' 379 | filter_dict['ip_port'] = FILTER_REDIS_HOST + ' : ' + str(FILTER_REDIS_PORT) 380 | filter_dict['dbsize'] = filter_client.dbsize() 381 | filter_dict['clients'] = filter_info['connected_clients'] 382 | filter_dict['used_memory'] = filter_info['used_memory_human'] 383 | elif FILTER_REDIS_TYPE == 'cluster': 384 | filter_dict['type'] = '集群' 385 | filter_dict['ip_port'] = [node['host'] + ' : ' + node['port'] for node in FILTER_REDIS_NODES] 386 | filter_dict['dbsize'] = [k + ' : ' + str(v) for k, v in filter_client.dbsize().items()] 387 | filter_dict['clients'] = [k + ' : ' + str(v['connected_clients']) for k, v in filter_info.items()] 388 | filter_dict['used_memory'] = [k + ' : ' + v['used_memory_human'] for k, v in filter_info.items()] 389 | redis_lists.append(filter_dict) 390 | 391 | redisinfo_rtask = RedisInfo(rtask_client) 392 | rtask_info = redisinfo_rtask.info() 393 | rtask_dict = {'dest': 'Redis RTask控制数据库', 'name': 'rtask'} 394 | rtask_dict['type'] = '单机' 395 | rtask_dict['ip_port'] = RTASK_REDIS_HOST + ' : ' + str(RTASK_REDIS_POST) 396 | rtask_dict['dbsize'] = rtask_client.dbsize() 397 | rtask_dict['clients'] = rtask_info['connected_clients'] 398 | rtask_dict['used_memory'] = rtask_info['used_memory_human'] 399 | redis_lists.append(rtask_dict) 400 | return render_template('redis.html', redis_lists=redis_lists) 401 | 402 | 403 | @app.route('/redisinfo/', methods=['GET', 'POST']) 404 | def redis_info(): 405 | name = request.args.get('name', None) 406 | if name == 'queue': 407 | redis_client = get_redis_client(QUEUE_REDIS_TYPE, QUEUE_REDIS_HOST, QUEUE_REDIS_PORT, QUEUE_REDIS_DB, 408 | QUEUE_REDIS_PWD, QUEUE_REDIS_NODES) 409 | redis_type = QUEUE_REDIS_TYPE 410 | elif name == 'filter': 411 | redis_client = get_redis_client(FILTER_REDIS_TYPE, FILTER_REDIS_HOST, FILTER_REDIS_PORT, FILTER_REDIS_DB, 412 | FILTER_REDIS_PWD, FILTER_REDIS_NODES) 413 | redis_type = FILTER_REDIS_TYPE 414 | elif name == 'rtask': 415 | redis_client = get_redis_client('single', RTASK_REDIS_HOST, RTASK_REDIS_POST, RTASK_REDIS_DB, 416 | RTASK_REDIS_PWD) 417 | redis_type = 'single' 418 | else: 419 | return redirect('/redis/') 420 | 421 | redisinfo = RedisInfo(redis_client) 422 | redis_info = redisinfo.info() 423 | redis_config = redisinfo.config_get() 424 | redis_clients = redisinfo.client_list() 425 | return render_template('redisinfo.html', redis_info=redis_info, redis_config=redis_config, 426 | redis_clients=redis_clients, redis_type=redis_type) 427 | 428 | @app.route('/redissave/', methods=['GET', 'POST']) 429 | def redis_save(): 430 | name = request.args.get('name', None) 431 | save_type = request.args.get('save_type', None) 432 | if name == 'queue': 433 | if QUEUE_REDIS_TYPE == 'single': 434 | timeout = 3 435 | else: 436 | timeout = None 437 | redis_client = get_redis_client(QUEUE_REDIS_TYPE, QUEUE_REDIS_HOST, QUEUE_REDIS_PORT, QUEUE_REDIS_DB, 438 | QUEUE_REDIS_PWD, QUEUE_REDIS_NODES, timeout=timeout) 439 | elif name == 'filter': 440 | if FILTER_REDIS_TYPE == 'single': 441 | timeout = 3 442 | else: 443 | timeout = None 444 | redis_client = get_redis_client(FILTER_REDIS_TYPE, FILTER_REDIS_HOST, FILTER_REDIS_PORT, FILTER_REDIS_DB, 445 | FILTER_REDIS_PWD, FILTER_REDIS_NODES, timeout=timeout) 446 | elif name == 'rtask': 447 | redis_client = get_redis_client('single', RTASK_REDIS_HOST, RTASK_REDIS_POST, RTASK_REDIS_DB, 448 | RTASK_REDIS_PWD) 449 | else: 450 | return redirect('/redis/') 451 | redisinfo = RedisInfo(redis_client) 452 | if save_type == 'save': 453 | redisinfo.save(is_bgsave=False) 454 | else: 455 | redisinfo.save(is_bgsave=True) 456 | return redirect('/redis/') 457 | 458 | 459 | if __name__ == '__main__': 460 | app.run(host='0.0.0.0', port=8888, debug=True) -------------------------------------------------------------------------------- /requires.txt: -------------------------------------------------------------------------------- 1 | pip3 install murmurhash3 2 | pip3 install redis 3 | pip3 install huey 4 | pip3 install psutil 5 | pip3 install redis-py-cluster 6 | pip3 install zerorpc 7 | pip3 install Flask -------------------------------------------------------------------------------- /server.py: -------------------------------------------------------------------------------- 1 | #coding=UTF-8 2 | 3 | import uuid 4 | import redis 5 | import time 6 | import zerorpc 7 | from sutils import sysinfo 8 | from sutils import wcontrol 9 | from worker import run_task 10 | from config import * 11 | 12 | class RPCServer(): 13 | 14 | def __init__(self): 15 | self.pool = redis.ConnectionPool(host=RTASK_REDIS_HOST, port=RTASK_REDIS_POST, db=RTASK_REDIS_DB, password=RTASK_REDIS_PWD, encoding='utf-8', decode_responses=True) 16 | self.client = redis.StrictRedis(connection_pool=self.pool) 17 | self.macid = sysinfo.get_macid() 18 | self.ips = sysinfo.get_ips() 19 | self.hostname = sysinfo.get_hostname() 20 | self.platform = sysinfo.get_platform() 21 | 22 | def pwd_check(self, password): 23 | if RPC_PWD == password: 24 | return True 25 | else: 26 | return False 27 | 28 | def ping(self): 29 | return True 30 | 31 | def register_host(self, tasks=None): 32 | if tasks is None: 33 | tasks = list() 34 | host_data = {'macid':self.macid, 'tasks':tasks, 'ips':self.ips, 'hostname':self.hostname, 'platform':self.platform} 35 | self.client.hset(TASK_NAME+':task_nodes', self.macid, host_data) 36 | return True 37 | 38 | def unregister_host(self): 39 | self.client.hdel(TASK_NAME+':task_nodes', self.macid) 40 | return True 41 | 42 | def start_worker(self, worker_nums=10, password=None): 43 | if self.pwd_check(password): 44 | try: 45 | wc = wcontrol.WorkerCotrol() 46 | wc.kill_worker(worker_name=TASK_NAME) 47 | self.unregister_tasks() 48 | wc.start_worker(TASK_NAME, worker_nums) 49 | self._start_task(worker_nums) 50 | return 'OK' 51 | except Exception as e: 52 | return 'ERROR : ' + str(e) 53 | else: 54 | return "Password Error!" 55 | 56 | def kill_worker(self, password): 57 | if self.pwd_check(password): 58 | try: 59 | wc = wcontrol.WorkerCotrol() 60 | wc.kill_worker(worker_name=TASK_NAME) 61 | self.unregister_tasks() 62 | self.register_host() 63 | return 'OK' 64 | except Exception as e: 65 | return 'ERROR : ' + str(e) 66 | else: 67 | return "Password Error!" 68 | 69 | def worker_status(self, password): 70 | if self.pwd_check(password): 71 | wc = wcontrol.WorkerCotrol() 72 | status = wc.worker_status() 73 | return status 74 | else: 75 | return "Password Error!" 76 | 77 | def _start_task(self, task_nums=10): 78 | task_uuids = list() 79 | for i in range(task_nums): 80 | task_uuid = str(uuid.uuid4()) 81 | run_task(task_uuid) 82 | task_uuids.append(task_uuid) 83 | self.register_host(task_uuids) 84 | self.register_tasks(task_uuids) 85 | 86 | def get_taskuuids(self): 87 | task_node = self.client.hget(TASK_NAME+':task_nodes', self.macid) 88 | task_uuids = eval(task_node)['tasks'] 89 | return task_uuids 90 | 91 | def register_tasks(self, task_uuids): 92 | for task_uuid in task_uuids: 93 | data = {'macid':self.macid, 'status':'run', 'task_uuid':task_uuid, 'hostname':self.hostname} 94 | self.client.hset(TASK_NAME+':task_status', task_uuid, data) 95 | 96 | def unregister_tasks(self): 97 | task_uuids = self.get_taskuuids() 98 | for task_uuid in task_uuids: 99 | self.client.hdel(TASK_NAME+':task_status', task_uuid) 100 | 101 | def stop_task(self, task_uuid, password): 102 | if self.pwd_check(password): 103 | data = {'macid':self.macid, 'status':'stop', 'task_uuid':task_uuid, 'hostname':self.hostname} 104 | self.client.hset(TASK_NAME+':task_status', task_uuid, data) 105 | return True 106 | else: 107 | return "Password Error!" 108 | 109 | def restart_task(self, task_uuid, password): 110 | if self.pwd_check(password): 111 | data = {'macid':self.macid, 'status':'run', 'task_uuid':task_uuid, 'hostname':self.hostname} 112 | self.client.hset(TASK_NAME+':task_status', task_uuid, data) 113 | return True 114 | else: 115 | return "Password Error!" 116 | 117 | def stop_alltasks(self, password): 118 | if self.pwd_check(password): 119 | task_uuids = self.get_taskuuids() 120 | for task_uuid in task_uuids: 121 | self.stop_task(task_uuid, RPC_PWD) 122 | return True 123 | else: 124 | return "Password Error!" 125 | 126 | def restart_alltasks(self, password): 127 | if self.pwd_check(password): 128 | task_uuids = self.get_taskuuids() 129 | for task_uuid in task_uuids: 130 | self.restart_task(task_uuid, RPC_PWD) 131 | return True 132 | else: 133 | return "Password Error!" 134 | 135 | def sysinfo(self, password): 136 | if self.pwd_check(password): 137 | cpu_info = sysinfo.get_cpu() 138 | memory_info = sysinfo.get_memory() 139 | disk_info = sysinfo.get_disk() 140 | network_info = sysinfo.get_network() 141 | return {'macid':self.macid, 'cpu_info':cpu_info, 'memory_info':memory_info, 'disk_info':disk_info, 'network_info':network_info} 142 | else: 143 | return "Password Error!" 144 | 145 | def exit_rpc(self, password): 146 | if self.pwd_check(password): 147 | self.kill_worker(RPC_PWD) 148 | self.unregister_host() 149 | exit() 150 | else: 151 | return "Password Error!" 152 | 153 | try: 154 | rpc = RPCServer() 155 | rpc.register_host() 156 | s = zerorpc.Server(RPCServer()) 157 | s.bind("tcp://0.0.0.0:{rpc_port}".format(rpc_port=RPC_PORT)) 158 | s.run() 159 | except KeyboardInterrupt: 160 | rpc.kill_worker(RPC_PWD) 161 | rpc.unregister_host() 162 | except Exception as e: 163 | datetime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) 164 | with open('./logs/worker.err', 'a', encoding='UTF-8') as f: 165 | f.write('ErrorTime : ' + datetime + '\n') 166 | f.write('ErrorData : ' + str(e) + '\n') 167 | f.write('##############################\n') -------------------------------------------------------------------------------- /static/bootstrap3.3/css/bootstrap-select.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap-select v1.12.1 (http://silviomoreto.github.io/bootstrap-select) 3 | * 4 | * Copyright 2013-2016 bootstrap-select 5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE) 6 | */ 7 | 8 | select.bs-select-hidden, 9 | select.selectpicker { 10 | display: none !important; 11 | } 12 | .bootstrap-select { 13 | width: 220px \0; 14 | /*IE9 and below*/ 15 | } 16 | .bootstrap-select > .dropdown-toggle { 17 | width: 100%; 18 | padding-right: 25px; 19 | z-index: 1; 20 | } 21 | .bootstrap-select > .dropdown-toggle.bs-placeholder, 22 | .bootstrap-select > .dropdown-toggle.bs-placeholder:hover, 23 | .bootstrap-select > .dropdown-toggle.bs-placeholder:focus, 24 | .bootstrap-select > .dropdown-toggle.bs-placeholder:active { 25 | color: #999; 26 | } 27 | .bootstrap-select > select { 28 | position: absolute !important; 29 | bottom: 0; 30 | left: 50%; 31 | display: block !important; 32 | width: 0.5px !important; 33 | height: 100% !important; 34 | padding: 0 !important; 35 | opacity: 0 !important; 36 | border: none; 37 | } 38 | .bootstrap-select > select.mobile-device { 39 | top: 0; 40 | left: 0; 41 | display: block !important; 42 | width: 100% !important; 43 | z-index: 2; 44 | } 45 | .has-error .bootstrap-select .dropdown-toggle, 46 | .error .bootstrap-select .dropdown-toggle { 47 | border-color: #b94a48; 48 | } 49 | .bootstrap-select.fit-width { 50 | width: auto !important; 51 | } 52 | .bootstrap-select:not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn) { 53 | width: 220px; 54 | } 55 | .bootstrap-select .dropdown-toggle:focus { 56 | outline: thin dotted #333333 !important; 57 | outline: 5px auto -webkit-focus-ring-color !important; 58 | outline-offset: -2px; 59 | } 60 | .bootstrap-select.form-control { 61 | margin-bottom: 0; 62 | padding: 0; 63 | border: none; 64 | } 65 | .bootstrap-select.form-control:not([class*="col-"]) { 66 | width: 100%; 67 | } 68 | .bootstrap-select.form-control.input-group-btn { 69 | z-index: auto; 70 | } 71 | .bootstrap-select.form-control.input-group-btn:not(:first-child):not(:last-child) > .btn { 72 | border-radius: 0; 73 | } 74 | .bootstrap-select.btn-group:not(.input-group-btn), 75 | .bootstrap-select.btn-group[class*="col-"] { 76 | float: none; 77 | display: inline-block; 78 | margin-left: 0; 79 | } 80 | .bootstrap-select.btn-group.dropdown-menu-right, 81 | .bootstrap-select.btn-group[class*="col-"].dropdown-menu-right, 82 | .row .bootstrap-select.btn-group[class*="col-"].dropdown-menu-right { 83 | float: right; 84 | } 85 | .form-inline .bootstrap-select.btn-group, 86 | .form-horizontal .bootstrap-select.btn-group, 87 | .form-group .bootstrap-select.btn-group { 88 | margin-bottom: 0; 89 | } 90 | .form-group-lg .bootstrap-select.btn-group.form-control, 91 | .form-group-sm .bootstrap-select.btn-group.form-control { 92 | padding: 0; 93 | } 94 | .form-inline .bootstrap-select.btn-group .form-control { 95 | width: 100%; 96 | } 97 | .bootstrap-select.btn-group.disabled, 98 | .bootstrap-select.btn-group > .disabled { 99 | cursor: not-allowed; 100 | } 101 | .bootstrap-select.btn-group.disabled:focus, 102 | .bootstrap-select.btn-group > .disabled:focus { 103 | outline: none !important; 104 | } 105 | .bootstrap-select.btn-group.bs-container { 106 | position: absolute; 107 | height: 0 !important; 108 | padding: 0 !important; 109 | } 110 | .bootstrap-select.btn-group.bs-container .dropdown-menu { 111 | z-index: 1060; 112 | } 113 | .bootstrap-select.btn-group .dropdown-toggle .filter-option { 114 | display: inline-block; 115 | overflow: hidden; 116 | width: 100%; 117 | text-align: left; 118 | } 119 | .bootstrap-select.btn-group .dropdown-toggle .caret { 120 | position: absolute; 121 | top: 50%; 122 | right: 12px; 123 | margin-top: -2px; 124 | vertical-align: middle; 125 | } 126 | .bootstrap-select.btn-group[class*="col-"] .dropdown-toggle { 127 | width: 100%; 128 | } 129 | .bootstrap-select.btn-group .dropdown-menu { 130 | min-width: 100%; 131 | -webkit-box-sizing: border-box; 132 | -moz-box-sizing: border-box; 133 | box-sizing: border-box; 134 | } 135 | .bootstrap-select.btn-group .dropdown-menu.inner { 136 | position: static; 137 | float: none; 138 | border: 0; 139 | padding: 0; 140 | margin: 0; 141 | border-radius: 0; 142 | -webkit-box-shadow: none; 143 | box-shadow: none; 144 | } 145 | .bootstrap-select.btn-group .dropdown-menu li { 146 | position: relative; 147 | } 148 | .bootstrap-select.btn-group .dropdown-menu li.active small { 149 | color: #fff; 150 | } 151 | .bootstrap-select.btn-group .dropdown-menu li.disabled a { 152 | cursor: not-allowed; 153 | } 154 | .bootstrap-select.btn-group .dropdown-menu li a { 155 | cursor: pointer; 156 | -webkit-user-select: none; 157 | -moz-user-select: none; 158 | -ms-user-select: none; 159 | user-select: none; 160 | } 161 | .bootstrap-select.btn-group .dropdown-menu li a.opt { 162 | position: relative; 163 | padding-left: 2.25em; 164 | } 165 | .bootstrap-select.btn-group .dropdown-menu li a span.check-mark { 166 | display: none; 167 | } 168 | .bootstrap-select.btn-group .dropdown-menu li a span.text { 169 | display: inline-block; 170 | } 171 | .bootstrap-select.btn-group .dropdown-menu li small { 172 | padding-left: 0.5em; 173 | } 174 | .bootstrap-select.btn-group .dropdown-menu .notify { 175 | position: absolute; 176 | bottom: 5px; 177 | width: 96%; 178 | margin: 0 2%; 179 | min-height: 26px; 180 | padding: 3px 5px; 181 | background: #f5f5f5; 182 | border: 1px solid #e3e3e3; 183 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); 184 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); 185 | pointer-events: none; 186 | opacity: 0.9; 187 | -webkit-box-sizing: border-box; 188 | -moz-box-sizing: border-box; 189 | box-sizing: border-box; 190 | } 191 | .bootstrap-select.btn-group .no-results { 192 | padding: 3px; 193 | background: #f5f5f5; 194 | margin: 0 5px; 195 | white-space: nowrap; 196 | } 197 | .bootstrap-select.btn-group.fit-width .dropdown-toggle .filter-option { 198 | position: static; 199 | } 200 | .bootstrap-select.btn-group.fit-width .dropdown-toggle .caret { 201 | position: static; 202 | top: auto; 203 | margin-top: -1px; 204 | } 205 | .bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark { 206 | position: absolute; 207 | display: inline-block; 208 | right: 15px; 209 | margin-top: 5px; 210 | } 211 | .bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text { 212 | margin-right: 34px; 213 | } 214 | .bootstrap-select.show-menu-arrow.open > .dropdown-toggle { 215 | z-index: 1061; 216 | } 217 | .bootstrap-select.show-menu-arrow .dropdown-toggle:before { 218 | content: ''; 219 | border-left: 7px solid transparent; 220 | border-right: 7px solid transparent; 221 | border-bottom: 7px solid rgba(204, 204, 204, 0.2); 222 | position: absolute; 223 | bottom: -4px; 224 | left: 9px; 225 | display: none; 226 | } 227 | .bootstrap-select.show-menu-arrow .dropdown-toggle:after { 228 | content: ''; 229 | border-left: 6px solid transparent; 230 | border-right: 6px solid transparent; 231 | border-bottom: 6px solid white; 232 | position: absolute; 233 | bottom: -4px; 234 | left: 10px; 235 | display: none; 236 | } 237 | .bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before { 238 | bottom: auto; 239 | top: -3px; 240 | border-top: 7px solid rgba(204, 204, 204, 0.2); 241 | border-bottom: 0; 242 | } 243 | .bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after { 244 | bottom: auto; 245 | top: -3px; 246 | border-top: 6px solid white; 247 | border-bottom: 0; 248 | } 249 | .bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before { 250 | right: 12px; 251 | left: auto; 252 | } 253 | .bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after { 254 | right: 13px; 255 | left: auto; 256 | } 257 | .bootstrap-select.show-menu-arrow.open > .dropdown-toggle:before, 258 | .bootstrap-select.show-menu-arrow.open > .dropdown-toggle:after { 259 | display: block; 260 | } 261 | .bs-searchbox, 262 | .bs-actionsbox, 263 | .bs-donebutton { 264 | padding: 4px 8px; 265 | } 266 | .bs-actionsbox { 267 | width: 100%; 268 | -webkit-box-sizing: border-box; 269 | -moz-box-sizing: border-box; 270 | box-sizing: border-box; 271 | } 272 | .bs-actionsbox .btn-group button { 273 | width: 50%; 274 | } 275 | .bs-donebutton { 276 | float: left; 277 | width: 100%; 278 | -webkit-box-sizing: border-box; 279 | -moz-box-sizing: border-box; 280 | box-sizing: border-box; 281 | } 282 | .bs-donebutton .btn-group button { 283 | width: 100%; 284 | } 285 | .bs-searchbox + .bs-actionsbox { 286 | padding: 0 8px 4px; 287 | } 288 | .bs-searchbox .form-control { 289 | margin-bottom: 0; 290 | width: 100%; 291 | float: none; 292 | } 293 | /*# sourceMappingURL=bootstrap-select.css.map */ -------------------------------------------------------------------------------- /static/bootstrap3.3/css/bootstrap-select.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap-select v1.12.1 (http://silviomoreto.github.io/bootstrap-select) 3 | * 4 | * Copyright 2013-2016 bootstrap-select 5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE) 6 | */select.bs-select-hidden,select.selectpicker{display:none!important}.bootstrap-select{width:220px\9}.bootstrap-select>.dropdown-toggle{width:100%;padding-right:25px;z-index:1}.bootstrap-select>.dropdown-toggle.bs-placeholder,.bootstrap-select>.dropdown-toggle.bs-placeholder:active,.bootstrap-select>.dropdown-toggle.bs-placeholder:focus,.bootstrap-select>.dropdown-toggle.bs-placeholder:hover{color:#999}.bootstrap-select>select{position:absolute!important;bottom:0;left:50%;display:block!important;width:.5px!important;height:100%!important;padding:0!important;opacity:0!important;border:none}.bootstrap-select>select.mobile-device{top:0;left:0;display:block!important;width:100%!important;z-index:2}.error .bootstrap-select .dropdown-toggle,.has-error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select.fit-width{width:auto!important}.bootstrap-select:not([class*=col-]):not([class*=form-control]):not(.input-group-btn){width:220px}.bootstrap-select .dropdown-toggle:focus{outline:thin dotted #333!important;outline:5px auto -webkit-focus-ring-color!important;outline-offset:-2px}.bootstrap-select.form-control{margin-bottom:0;padding:0;border:none}.bootstrap-select.form-control:not([class*=col-]){width:100%}.bootstrap-select.form-control.input-group-btn{z-index:auto}.bootstrap-select.form-control.input-group-btn:not(:first-child):not(:last-child)>.btn{border-radius:0}.bootstrap-select.btn-group:not(.input-group-btn),.bootstrap-select.btn-group[class*=col-]{float:none;display:inline-block;margin-left:0}.bootstrap-select.btn-group.dropdown-menu-right,.bootstrap-select.btn-group[class*=col-].dropdown-menu-right,.row .bootstrap-select.btn-group[class*=col-].dropdown-menu-right{float:right}.form-group .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group{margin-bottom:0}.form-group-lg .bootstrap-select.btn-group.form-control,.form-group-sm .bootstrap-select.btn-group.form-control{padding:0}.form-inline .bootstrap-select.btn-group .form-control{width:100%}.bootstrap-select.btn-group.disabled,.bootstrap-select.btn-group>.disabled{cursor:not-allowed}.bootstrap-select.btn-group.disabled:focus,.bootstrap-select.btn-group>.disabled:focus{outline:0!important}.bootstrap-select.btn-group.bs-container{position:absolute;height:0!important;padding:0!important}.bootstrap-select.btn-group.bs-container .dropdown-menu{z-index:1060}.bootstrap-select.btn-group .dropdown-toggle .filter-option{display:inline-block;overflow:hidden;width:100%;text-align:left}.bootstrap-select.btn-group .dropdown-toggle .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group[class*=col-] .dropdown-toggle{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;float:none;border:0;padding:0;margin:0;border-radius:0;-webkit-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li.active small{color:#fff}.bootstrap-select.btn-group .dropdown-menu li.disabled a{cursor:not-allowed}.bootstrap-select.btn-group .dropdown-menu li a{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.bootstrap-select.btn-group .dropdown-menu li a.opt{position:relative;padding-left:2.25em}.bootstrap-select.btn-group .dropdown-menu li a span.check-mark{display:none}.bootstrap-select.btn-group .dropdown-menu li a span.text{display:inline-block}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:.5em}.bootstrap-select.btn-group .dropdown-menu .notify{position:absolute;bottom:5px;width:96%;margin:0 2%;min-height:26px;padding:3px 5px;background:#f5f5f5;border:1px solid #e3e3e3;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05);pointer-events:none;opacity:.9;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .no-results{padding:3px;background:#f5f5f5;margin:0 5px;white-space:nowrap}.bootstrap-select.btn-group.fit-width .dropdown-toggle .filter-option{position:static}.bootstrap-select.btn-group.fit-width .dropdown-toggle .caret{position:static;top:auto;margin-top:-1px}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a span.check-mark{position:absolute;display:inline-block;right:15px;margin-top:5px}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle{z-index:1061}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid rgba(204,204,204,.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid rgba(204,204,204,.2);border-bottom:0}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #fff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before{display:block}.bs-actionsbox,.bs-donebutton,.bs-searchbox{padding:4px 8px}.bs-actionsbox{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bs-actionsbox .btn-group button{width:50%}.bs-donebutton{float:left;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.bs-donebutton .btn-group button{width:100%}.bs-searchbox+.bs-actionsbox{padding:0 8px 4px}.bs-searchbox .form-control{margin-bottom:0;width:100%;float:none} -------------------------------------------------------------------------------- /static/bootstrap3.3/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | .btn-default, 8 | .btn-primary, 9 | .btn-success, 10 | .btn-info, 11 | .btn-warning, 12 | .btn-danger { 13 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 14 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 16 | } 17 | .btn-default:active, 18 | .btn-primary:active, 19 | .btn-success:active, 20 | .btn-info:active, 21 | .btn-warning:active, 22 | .btn-danger:active, 23 | .btn-default.active, 24 | .btn-primary.active, 25 | .btn-success.active, 26 | .btn-info.active, 27 | .btn-warning.active, 28 | .btn-danger.active { 29 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 31 | } 32 | .btn-default .badge, 33 | .btn-primary .badge, 34 | .btn-success .badge, 35 | .btn-info .badge, 36 | .btn-warning .badge, 37 | .btn-danger .badge { 38 | text-shadow: none; 39 | } 40 | .btn:active, 41 | .btn.active { 42 | background-image: none; 43 | } 44 | .btn-default { 45 | text-shadow: 0 1px 0 #fff; 46 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 47 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 48 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 49 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 50 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 51 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 52 | background-repeat: repeat-x; 53 | border-color: #dbdbdb; 54 | border-color: #ccc; 55 | } 56 | .btn-default:hover, 57 | .btn-default:focus { 58 | background-color: #e0e0e0; 59 | background-position: 0 -15px; 60 | } 61 | .btn-default:active, 62 | .btn-default.active { 63 | background-color: #e0e0e0; 64 | border-color: #dbdbdb; 65 | } 66 | .btn-default:disabled, 67 | .btn-default[disabled] { 68 | background-color: #e0e0e0; 69 | background-image: none; 70 | } 71 | .btn-primary { 72 | background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 73 | background-image: -o-linear-gradient(top, #428bca 0%, #2d6ca2 100%); 74 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#2d6ca2)); 75 | background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%); 76 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0); 77 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 78 | background-repeat: repeat-x; 79 | border-color: #2b669a; 80 | } 81 | .btn-primary:hover, 82 | .btn-primary:focus { 83 | background-color: #2d6ca2; 84 | background-position: 0 -15px; 85 | } 86 | .btn-primary:active, 87 | .btn-primary.active { 88 | background-color: #2d6ca2; 89 | border-color: #2b669a; 90 | } 91 | .btn-primary:disabled, 92 | .btn-primary[disabled] { 93 | background-color: #2d6ca2; 94 | background-image: none; 95 | } 96 | .btn-success { 97 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 98 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 99 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 100 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 101 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 102 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 103 | background-repeat: repeat-x; 104 | border-color: #3e8f3e; 105 | } 106 | .btn-success:hover, 107 | .btn-success:focus { 108 | background-color: #419641; 109 | background-position: 0 -15px; 110 | } 111 | .btn-success:active, 112 | .btn-success.active { 113 | background-color: #419641; 114 | border-color: #3e8f3e; 115 | } 116 | .btn-success:disabled, 117 | .btn-success[disabled] { 118 | background-color: #419641; 119 | background-image: none; 120 | } 121 | .btn-info { 122 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 123 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 124 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 125 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 126 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 127 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 128 | background-repeat: repeat-x; 129 | border-color: #28a4c9; 130 | } 131 | .btn-info:hover, 132 | .btn-info:focus { 133 | background-color: #2aabd2; 134 | background-position: 0 -15px; 135 | } 136 | .btn-info:active, 137 | .btn-info.active { 138 | background-color: #2aabd2; 139 | border-color: #28a4c9; 140 | } 141 | .btn-info:disabled, 142 | .btn-info[disabled] { 143 | background-color: #2aabd2; 144 | background-image: none; 145 | } 146 | .btn-warning { 147 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 148 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 149 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 150 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 151 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 152 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 153 | background-repeat: repeat-x; 154 | border-color: #e38d13; 155 | } 156 | .btn-warning:hover, 157 | .btn-warning:focus { 158 | background-color: #eb9316; 159 | background-position: 0 -15px; 160 | } 161 | .btn-warning:active, 162 | .btn-warning.active { 163 | background-color: #eb9316; 164 | border-color: #e38d13; 165 | } 166 | .btn-warning:disabled, 167 | .btn-warning[disabled] { 168 | background-color: #eb9316; 169 | background-image: none; 170 | } 171 | .btn-danger { 172 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 173 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 174 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 175 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 176 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 177 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 178 | background-repeat: repeat-x; 179 | border-color: #b92c28; 180 | } 181 | .btn-danger:hover, 182 | .btn-danger:focus { 183 | background-color: #c12e2a; 184 | background-position: 0 -15px; 185 | } 186 | .btn-danger:active, 187 | .btn-danger.active { 188 | background-color: #c12e2a; 189 | border-color: #b92c28; 190 | } 191 | .btn-danger:disabled, 192 | .btn-danger[disabled] { 193 | background-color: #c12e2a; 194 | background-image: none; 195 | } 196 | .thumbnail, 197 | .img-thumbnail { 198 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 199 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 200 | } 201 | .dropdown-menu > li > a:hover, 202 | .dropdown-menu > li > a:focus { 203 | background-color: #e8e8e8; 204 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 205 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 206 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 207 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 208 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 209 | background-repeat: repeat-x; 210 | } 211 | .dropdown-menu > .active > a, 212 | .dropdown-menu > .active > a:hover, 213 | .dropdown-menu > .active > a:focus { 214 | background-color: #357ebd; 215 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 216 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); 217 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); 218 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 219 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 220 | background-repeat: repeat-x; 221 | } 222 | .navbar-default { 223 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 224 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 225 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 226 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 227 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 228 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 229 | background-repeat: repeat-x; 230 | border-radius: 4px; 231 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 232 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 233 | } 234 | .navbar-default .navbar-nav > .open > a, 235 | .navbar-default .navbar-nav > .active > a { 236 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 237 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 238 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 239 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 240 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 241 | background-repeat: repeat-x; 242 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 243 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 244 | } 245 | .navbar-brand, 246 | .navbar-nav > li > a { 247 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 248 | } 249 | .navbar-inverse { 250 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 251 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 252 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 253 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 254 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 255 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 256 | background-repeat: repeat-x; 257 | } 258 | .navbar-inverse .navbar-nav > .open > a, 259 | .navbar-inverse .navbar-nav > .active > a { 260 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 261 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 262 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 263 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 264 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 265 | background-repeat: repeat-x; 266 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 267 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 268 | } 269 | .navbar-inverse .navbar-brand, 270 | .navbar-inverse .navbar-nav > li > a { 271 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 272 | } 273 | .navbar-static-top, 274 | .navbar-fixed-top, 275 | .navbar-fixed-bottom { 276 | border-radius: 0; 277 | } 278 | .alert { 279 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 280 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 281 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 282 | } 283 | .alert-success { 284 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 285 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 286 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 287 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 288 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 289 | background-repeat: repeat-x; 290 | border-color: #b2dba1; 291 | } 292 | .alert-info { 293 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 294 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 295 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 296 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 297 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 298 | background-repeat: repeat-x; 299 | border-color: #9acfea; 300 | } 301 | .alert-warning { 302 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 303 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 304 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 305 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 306 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 307 | background-repeat: repeat-x; 308 | border-color: #f5e79e; 309 | } 310 | .alert-danger { 311 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 312 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 313 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 314 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 315 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 316 | background-repeat: repeat-x; 317 | border-color: #dca7a7; 318 | } 319 | .progress { 320 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 321 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 322 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 323 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 325 | background-repeat: repeat-x; 326 | } 327 | .progress-bar { 328 | background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%); 329 | background-image: -o-linear-gradient(top, #428bca 0%, #3071a9 100%); 330 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3071a9)); 331 | background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%); 332 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0); 333 | background-repeat: repeat-x; 334 | } 335 | .progress-bar-success { 336 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 337 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 338 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 339 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 340 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 341 | background-repeat: repeat-x; 342 | } 343 | .progress-bar-info { 344 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 345 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 346 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 347 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 348 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 349 | background-repeat: repeat-x; 350 | } 351 | .progress-bar-warning { 352 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 353 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 354 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 355 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 356 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 357 | background-repeat: repeat-x; 358 | } 359 | .progress-bar-danger { 360 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 361 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 362 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 363 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 364 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 365 | background-repeat: repeat-x; 366 | } 367 | .progress-bar-striped { 368 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 369 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 370 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 371 | } 372 | .list-group { 373 | border-radius: 4px; 374 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 375 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 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-linear-gradient(top, #428bca 0%, #3278b3 100%); 382 | background-image: -o-linear-gradient(top, #428bca 0%, #3278b3 100%); 383 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#3278b3)); 384 | background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%); 385 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0); 386 | background-repeat: repeat-x; 387 | border-color: #3278b3; 388 | } 389 | .list-group-item.active .badge, 390 | .list-group-item.active:hover .badge, 391 | .list-group-item.active:focus .badge { 392 | text-shadow: none; 393 | } 394 | .panel { 395 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 396 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 397 | } 398 | .panel-default > .panel-heading { 399 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 400 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 401 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 402 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 403 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 404 | background-repeat: repeat-x; 405 | } 406 | .panel-primary > .panel-heading { 407 | background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%); 408 | background-image: -o-linear-gradient(top, #428bca 0%, #357ebd 100%); 409 | background-image: -webkit-gradient(linear, left top, left bottom, from(#428bca), to(#357ebd)); 410 | background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%); 411 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0); 412 | background-repeat: repeat-x; 413 | } 414 | .panel-success > .panel-heading { 415 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 416 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 417 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 418 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 419 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 420 | background-repeat: repeat-x; 421 | } 422 | .panel-info > .panel-heading { 423 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 424 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 427 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 428 | background-repeat: repeat-x; 429 | } 430 | .panel-warning > .panel-heading { 431 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 432 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 433 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 434 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 435 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 436 | background-repeat: repeat-x; 437 | } 438 | .panel-danger > .panel-heading { 439 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 440 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 441 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 442 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 443 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 444 | background-repeat: repeat-x; 445 | } 446 | .well { 447 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 448 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 449 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 450 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 451 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 452 | background-repeat: repeat-x; 453 | border-color: #dcdcdc; 454 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 455 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 456 | } 457 | /*# sourceMappingURL=bootstrap-theme.css.map */ 458 | -------------------------------------------------------------------------------- /static/bootstrap3.3/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-default,.btn-primary,.btn-success,.btn-info,.btn-warning,.btn-danger{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(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,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-default .badge,.btn-primary .badge,.btn-success .badge,.btn-info .badge,.btn-warning .badge,.btn-danger .badge{text-shadow:none}.btn:active,.btn.active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.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-default:disabled,.btn-default[disabled]{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-o-linear-gradient(top,#428bca 0,#2d6ca2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#2d6ca2));background-image:linear-gradient(to bottom,#428bca 0,#2d6ca2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#2b669a}.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-primary:disabled,.btn-primary[disabled]{background-color:#2d6ca2;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.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-success:disabled,.btn-success[disabled]{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.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}.btn-info:disabled,.btn-info[disabled]{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.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-warning:disabled,.btn-warning[disabled]{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.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-danger:disabled,.btn-danger[disabled]{background-color:#c12e2a;background-image:none}.thumbnail,.img-thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{background-color:#357ebd;background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.active>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-static-top,.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-o-linear-gradient(top,#428bca 0,#3071a9 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3071a9));background-image:linear-gradient(to bottom,#428bca 0,#3071a9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{text-shadow:0 -1px 0 #3071a9;background-image:-webkit-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-o-linear-gradient(top,#428bca 0,#3278b3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#3278b3));background-image:linear-gradient(to bottom,#428bca 0,#3278b3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);background-repeat:repeat-x;border-color:#3278b3}.list-group-item.active .badge,.list-group-item.active:hover .badge,.list-group-item.active:focus .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-o-linear-gradient(top,#428bca 0,#357ebd 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#428bca),to(#357ebd));background-image:linear-gradient(to bottom,#428bca 0,#357ebd 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} -------------------------------------------------------------------------------- /static/bootstrap3.3/css/justified-nav.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 20px; 3 | } 4 | 5 | .footer { 6 | padding-top: 40px; 7 | padding-bottom: 40px; 8 | margin-top: 40px; 9 | border-top: 1px solid #eee; 10 | } 11 | 12 | /* Main marketing message and sign up button */ 13 | .jumbotron { 14 | text-align: center; 15 | background-color: transparent; 16 | } 17 | .jumbotron .btn { 18 | padding: 14px 24px; 19 | font-size: 21px; 20 | } 21 | 22 | /* Customize the nav-justified links to be fill the entire space of the .navbar */ 23 | 24 | .nav-justified { 25 | background-color: #eee; 26 | border: 1px solid #ccc; 27 | border-radius: 5px; 28 | } 29 | .nav-justified > li > a { 30 | padding-top: 15px; 31 | padding-bottom: 15px; 32 | margin-bottom: 0; 33 | font-weight: bold; 34 | color: #777; 35 | text-align: center; 36 | background-color: #e5e5e5; /* Old browsers */ 37 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e5e5e5)); 38 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e5e5e5 100%); 39 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e5e5e5 100%); 40 | background-image: -webkit-gradient(linear, left top, left bottom, from(top), color-stop(0%, #f5f5f5), to(#e5e5e5)); 41 | background-image: linear-gradient(top, #f5f5f5 0%, #e5e5e5 100%); 42 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f5f5f5', endColorstr='#e5e5e5',GradientType=0 ); /* IE6-9 */ 43 | background-repeat: repeat-x; /* Repeat the gradient */ 44 | border-bottom: 1px solid #d5d5d5; 45 | } 46 | .nav-justified > .active > a, 47 | .nav-justified > .active > a:hover, 48 | .nav-justified > .active > a:focus { 49 | background-color: #ddd; 50 | background-image: none; 51 | -webkit-box-shadow: inset 0 3px 7px rgba(0,0,0,.15); 52 | box-shadow: inset 0 3px 7px rgba(0,0,0,.15); 53 | } 54 | .nav-justified > li:first-child > a { 55 | border-radius: 5px 5px 0 0; 56 | } 57 | .nav-justified > li:last-child > a { 58 | border-bottom: 0; 59 | border-radius: 0 0 5px 5px; 60 | } 61 | 62 | @media (min-width: 768px) { 63 | .nav-justified { 64 | max-height: 52px; 65 | } 66 | .nav-justified > li > a { 67 | border-right: 1px solid #d5d5d5; 68 | border-left: 1px solid #fff; 69 | } 70 | .nav-justified > li:first-child > a { 71 | border-left: 0; 72 | border-radius: 5px 0 0 5px; 73 | } 74 | .nav-justified > li:last-child > a { 75 | border-right: 0; 76 | border-radius: 0 5px 5px 0; 77 | } 78 | } 79 | 80 | /* Responsive: Portrait tablets and up */ 81 | @media screen and (min-width: 768px) { 82 | /* Remove the padding we set earlier */ 83 | .masthead, 84 | .marketing, 85 | .footer { 86 | padding-right: 0; 87 | padding-left: 0; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /static/bootstrap3.3/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/static/bootstrap3.3/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /static/bootstrap3.3/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/static/bootstrap3.3/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /static/bootstrap3.3/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HatBoy/RTask/454c1e347ce3fd405bf19722ff762c926e0a47ea/static/bootstrap3.3/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /static/bootstrap3.3/js/bootstrap-select.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap-select v1.12.1 (http://silviomoreto.github.io/bootstrap-select) 3 | * 4 | * Copyright 2013-2016 bootstrap-select 5 | * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE) 6 | */ 7 | !function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function(a){!function(a){"use strict";function b(b){var c=[{re:/[\xC0-\xC6]/g,ch:"A"},{re:/[\xE0-\xE6]/g,ch:"a"},{re:/[\xC8-\xCB]/g,ch:"E"},{re:/[\xE8-\xEB]/g,ch:"e"},{re:/[\xCC-\xCF]/g,ch:"I"},{re:/[\xEC-\xEF]/g,ch:"i"},{re:/[\xD2-\xD6]/g,ch:"O"},{re:/[\xF2-\xF6]/g,ch:"o"},{re:/[\xD9-\xDC]/g,ch:"U"},{re:/[\xF9-\xFC]/g,ch:"u"},{re:/[\xC7-\xE7]/g,ch:"c"},{re:/[\xD1]/g,ch:"N"},{re:/[\xF1]/g,ch:"n"}];return a.each(c,function(){b=b?b.replace(this.re,this.ch):""}),b}function c(b){var c=arguments,d=b;[].shift.apply(c);var e,f=this.each(function(){var b=a(this);if(b.is("select")){var f=b.data("selectpicker"),g="object"==typeof d&&d;if(f){if(g)for(var h in g)g.hasOwnProperty(h)&&(f.options[h]=g[h])}else{var i=a.extend({},k.DEFAULTS,a.fn.selectpicker.defaults||{},b.data(),g);i.template=a.extend({},k.DEFAULTS.template,a.fn.selectpicker.defaults?a.fn.selectpicker.defaults.template:{},b.data().template,g.template),b.data("selectpicker",f=new k(this,i))}"string"==typeof d&&(e=f[d]instanceof Function?f[d].apply(f,c):f.options[d])}});return"undefined"!=typeof e?e:f}String.prototype.includes||!function(){var a={}.toString,b=function(){try{var a={},b=Object.defineProperty,c=b(a,a,a)&&b}catch(a){}return c}(),c="".indexOf,d=function(b){if(null==this)throw new TypeError;var d=String(this);if(b&&"[object RegExp]"==a.call(b))throw new TypeError;var e=d.length,f=String(b),g=f.length,h=arguments.length>1?arguments[1]:void 0,i=h?Number(h):0;i!=i&&(i=0);var j=Math.min(Math.max(i,0),e);return!(g+j>e)&&c.call(d,f,i)!=-1};b?b(String.prototype,"includes",{value:d,configurable:!0,writable:!0}):String.prototype.includes=d}(),String.prototype.startsWith||!function(){var a=function(){try{var a={},b=Object.defineProperty,c=b(a,a,a)&&b}catch(a){}return c}(),b={}.toString,c=function(a){if(null==this)throw new TypeError;var c=String(this);if(a&&"[object RegExp]"==b.call(a))throw new TypeError;var d=c.length,e=String(a),f=e.length,g=arguments.length>1?arguments[1]:void 0,h=g?Number(g):0;h!=h&&(h=0);var i=Math.min(Math.max(h,0),d);if(f+i>d)return!1;for(var j=-1;++j":">",'"':""","'":"'","`":"`"},g={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},h=function(a){var b=function(b){return a[b]},c="(?:"+Object.keys(a).join("|")+")",d=RegExp(c),e=RegExp(c,"g");return function(a){return a=null==a?"":""+a,d.test(a)?a.replace(e,b):a}},i=h(f),j=h(g),k=function(b,c){d.useDefault||(a.valHooks.select.set=d._set,d.useDefault=!0),this.$element=a(b),this.$newElement=null,this.$button=null,this.$menu=null,this.$lis=null,this.options=c,null===this.options.title&&(this.options.title=this.$element.attr("title"));var e=this.options.windowPadding;"number"==typeof e&&(this.options.windowPadding=[e,e,e,e]),this.val=k.prototype.val,this.render=k.prototype.render,this.refresh=k.prototype.refresh,this.setStyle=k.prototype.setStyle,this.selectAll=k.prototype.selectAll,this.deselectAll=k.prototype.deselectAll,this.destroy=k.prototype.destroy,this.remove=k.prototype.remove,this.show=k.prototype.show,this.hide=k.prototype.hide,this.init()};k.VERSION="1.12.1",k.DEFAULTS={noneSelectedText:"Nothing selected",noneResultsText:"No results matched {0}",countSelectedText:function(a,b){return 1==a?"{0} item selected":"{0} items selected"},maxOptionsText:function(a,b){return[1==a?"Limit reached ({n} item max)":"Limit reached ({n} items max)",1==b?"Group limit reached ({n} item max)":"Group limit reached ({n} items max)"]},selectAllText:"Select All",deselectAllText:"Deselect All",doneButton:!1,doneButtonText:"Close",multipleSeparator:", ",styleBase:"btn",style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",width:!1,container:!1,hideDisabled:!1,showSubtext:!1,showIcon:!0,showContent:!0,dropupAuto:!0,header:!1,liveSearch:!1,liveSearchPlaceholder:null,liveSearchNormalize:!1,liveSearchStyle:"contains",actionsBox:!1,iconBase:"glyphicon",tickIcon:"glyphicon-ok",showTick:!1,template:{caret:''},maxOptions:!1,mobile:!1,selectOnTab:!1,dropdownAlignRight:!1,windowPadding:0},k.prototype={constructor:k,init:function(){var b=this,c=this.$element.attr("id");this.$element.addClass("bs-select-hidden"),this.liObj={},this.multiple=this.$element.prop("multiple"),this.autofocus=this.$element.prop("autofocus"),this.$newElement=this.createView(),this.$element.after(this.$newElement).appendTo(this.$newElement),this.$button=this.$newElement.children("button"),this.$menu=this.$newElement.children(".dropdown-menu"),this.$menuInner=this.$menu.children(".inner"),this.$searchbox=this.$menu.find("input"),this.$element.removeClass("bs-select-hidden"),this.options.dropdownAlignRight===!0&&this.$menu.addClass("dropdown-menu-right"),"undefined"!=typeof c&&(this.$button.attr("data-id",c),a('label[for="'+c+'"]').click(function(a){a.preventDefault(),b.$button.focus()})),this.checkDisabled(),this.clickListener(),this.options.liveSearch&&this.liveSearchListener(),this.render(),this.setStyle(),this.setWidth(),this.options.container&&this.selectPosition(),this.$menu.data("this",this),this.$newElement.data("this",this),this.options.mobile&&this.mobile(),this.$newElement.on({"hide.bs.dropdown":function(a){b.$menuInner.attr("aria-expanded",!1),b.$element.trigger("hide.bs.select",a)},"hidden.bs.dropdown":function(a){b.$element.trigger("hidden.bs.select",a)},"show.bs.dropdown":function(a){b.$menuInner.attr("aria-expanded",!0),b.$element.trigger("show.bs.select",a)},"shown.bs.dropdown":function(a){b.$element.trigger("shown.bs.select",a)}}),b.$element[0].hasAttribute("required")&&this.$element.on("invalid",function(){b.$button.addClass("bs-invalid").focus(),b.$element.on({"focus.bs.select":function(){b.$button.focus(),b.$element.off("focus.bs.select")},"shown.bs.select":function(){b.$element.val(b.$element.val()).off("shown.bs.select")},"rendered.bs.select":function(){this.validity.valid&&b.$button.removeClass("bs-invalid"),b.$element.off("rendered.bs.select")}})}),setTimeout(function(){b.$element.trigger("loaded.bs.select")})},createDropdown:function(){var b=this.multiple||this.options.showTick?" show-tick":"",c=this.$element.parent().hasClass("input-group")?" input-group-btn":"",d=this.autofocus?" autofocus":"",e=this.options.header?'
'+this.options.header+"
":"",f=this.options.liveSearch?'':"",g=this.multiple&&this.options.actionsBox?'
":"",h=this.multiple&&this.options.doneButton?'
":"",j='
";return a(j)},createView:function(){var a=this.createDropdown(),b=this.createLi();return a.find("ul")[0].innerHTML=b,a},reloadLi:function(){var a=this.createLi();this.$menuInner[0].innerHTML=a},createLi:function(){var c=this,d=[],e=0,f=document.createElement("option"),g=-1,h=function(a,b,c,d){return""+a+""},j=function(d,e,f,g){return''+d+''};if(this.options.title&&!this.multiple&&(g--,!this.$element.find(".bs-title-option").length)){var k=this.$element[0];f.className="bs-title-option",f.innerHTML=this.options.title,f.value="",k.insertBefore(f,k.firstChild);var l=a(k.options[k.selectedIndex]);void 0===l.attr("selected")&&void 0===this.$element.data("selected")&&(f.selected=!0)}return this.$element.find("option").each(function(b){var f=a(this);if(g++,!f.hasClass("bs-title-option")){var k=this.className||"",l=this.style.cssText,m=f.data("content")?f.data("content"):f.html(),n=f.data("tokens")?f.data("tokens"):null,o="undefined"!=typeof f.data("subtext")?''+f.data("subtext")+"":"",p="undefined"!=typeof f.data("icon")?' ':"",q=f.parent(),r="OPTGROUP"===q[0].tagName,s=r&&q[0].disabled,t=this.disabled||s;if(""!==p&&t&&(p=""+p+""),c.options.hideDisabled&&(t&&!r||s))return void g--;if(f.data("content")||(m=p+''+m+o+""),r&&f.data("divider")!==!0){if(c.options.hideDisabled&&t){if(void 0===q.data("allOptionsDisabled")){var u=q.children();q.data("allOptionsDisabled",u.filter(":disabled").length===u.length)}if(q.data("allOptionsDisabled"))return void g--}var v=" "+q[0].className||"";if(0===f.index()){e+=1;var w=q[0].label,x="undefined"!=typeof q.data("subtext")?''+q.data("subtext")+"":"",y=q.data("icon")?' ':"";w=y+''+i(w)+x+"",0!==b&&d.length>0&&(g++,d.push(h("",null,"divider",e+"div"))),g++,d.push(h(w,null,"dropdown-header"+v,e))}if(c.options.hideDisabled&&t)return void g--;d.push(h(j(m,"opt "+k+v,l,n),b,"",e))}else if(f.data("divider")===!0)d.push(h("",b,"divider"));else if(f.data("hidden")===!0)d.push(h(j(m,k,l,n),b,"hidden is-hidden"));else{var z=this.previousElementSibling&&"OPTGROUP"===this.previousElementSibling.tagName;if(!z&&c.options.hideDisabled)for(var A=a(this).prevAll(),B=0;B ':"";return b=d.options.showSubtext&&c.data("subtext")&&!d.multiple?' '+c.data("subtext")+"":"","undefined"!=typeof c.attr("title")?c.attr("title"):c.data("content")&&d.options.showContent?c.data("content").toString():e+c.html()+b}}).toArray(),f=this.multiple?e.join(this.options.multipleSeparator):e[0];if(this.multiple&&this.options.selectedTextFormat.indexOf("count")>-1){var g=this.options.selectedTextFormat.split(">");if(g.length>1&&e.length>g[1]||1==g.length&&e.length>=2){c=this.options.hideDisabled?", [disabled]":"";var h=this.$element.find("option").not('[data-divider="true"], [data-hidden="true"]'+c).length,i="function"==typeof this.options.countSelectedText?this.options.countSelectedText(e.length,h):this.options.countSelectedText;f=i.replace("{0}",e.length.toString()).replace("{1}",h.toString())}}void 0==this.options.title&&(this.options.title=this.$element.attr("title")),"static"==this.options.selectedTextFormat&&(f=this.options.title),f||(f="undefined"!=typeof this.options.title?this.options.title:this.options.noneSelectedText),this.$button.attr("title",j(a.trim(f.replace(/<[^>]*>?/g,"")))),this.$button.children(".filter-option").html(f),this.$element.trigger("rendered.bs.select")},setStyle:function(a,b){this.$element.attr("class")&&this.$newElement.addClass(this.$element.attr("class").replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi,""));var c=a?a:this.options.style;"add"==b?this.$button.addClass(c):"remove"==b?this.$button.removeClass(c):(this.$button.removeClass(this.options.style),this.$button.addClass(c))},liHeight:function(b){if(b||this.options.size!==!1&&!this.sizeInfo){var c=document.createElement("div"),d=document.createElement("div"),e=document.createElement("ul"),f=document.createElement("li"),g=document.createElement("li"),h=document.createElement("a"),i=document.createElement("span"),j=this.options.header&&this.$menu.find(".popover-title").length>0?this.$menu.find(".popover-title")[0].cloneNode(!0):null,k=this.options.liveSearch?document.createElement("div"):null,l=this.options.actionsBox&&this.multiple&&this.$menu.find(".bs-actionsbox").length>0?this.$menu.find(".bs-actionsbox")[0].cloneNode(!0):null,m=this.options.doneButton&&this.multiple&&this.$menu.find(".bs-donebutton").length>0?this.$menu.find(".bs-donebutton")[0].cloneNode(!0):null;if(i.className="text",c.className=this.$menu[0].parentNode.className+" open",d.className="dropdown-menu open",e.className="dropdown-menu inner",f.className="divider",i.appendChild(document.createTextNode("Inner text")),h.appendChild(i),g.appendChild(h),e.appendChild(g),e.appendChild(f),j&&d.appendChild(j),k){var n=document.createElement("span");k.className="bs-searchbox",n.className="form-control",k.appendChild(n),d.appendChild(k)}l&&d.appendChild(l),d.appendChild(e),m&&d.appendChild(m),c.appendChild(d),document.body.appendChild(c);var o=h.offsetHeight,p=j?j.offsetHeight:0,q=k?k.offsetHeight:0,r=l?l.offsetHeight:0,s=m?m.offsetHeight:0,t=a(f).outerHeight(!0),u="function"==typeof getComputedStyle&&getComputedStyle(d),v=u?null:a(d),w={vert:parseInt(u?u.paddingTop:v.css("paddingTop"))+parseInt(u?u.paddingBottom:v.css("paddingBottom"))+parseInt(u?u.borderTopWidth:v.css("borderTopWidth"))+parseInt(u?u.borderBottomWidth:v.css("borderBottomWidth")),horiz:parseInt(u?u.paddingLeft:v.css("paddingLeft"))+parseInt(u?u.paddingRight:v.css("paddingRight"))+parseInt(u?u.borderLeftWidth:v.css("borderLeftWidth"))+parseInt(u?u.borderRightWidth:v.css("borderRightWidth"))},x={vert:w.vert+parseInt(u?u.marginTop:v.css("marginTop"))+parseInt(u?u.marginBottom:v.css("marginBottom"))+2,horiz:w.horiz+parseInt(u?u.marginLeft:v.css("marginLeft"))+parseInt(u?u.marginRight:v.css("marginRight"))+2};document.body.removeChild(c),this.sizeInfo={liHeight:o,headerHeight:p,searchHeight:q,actionsHeight:r,doneButtonHeight:s,dividerHeight:t,menuPadding:w,menuExtras:x}}},setSize:function(){if(this.findLis(),this.liHeight(),this.options.header&&this.$menu.css("padding-top",0),this.options.size!==!1){var b,c,d,e,f,g,h,i,j=this,k=this.$menu,l=this.$menuInner,m=a(window),n=this.$newElement[0].offsetHeight,o=this.$newElement[0].offsetWidth,p=this.sizeInfo.liHeight,q=this.sizeInfo.headerHeight,r=this.sizeInfo.searchHeight,s=this.sizeInfo.actionsHeight,t=this.sizeInfo.doneButtonHeight,u=this.sizeInfo.dividerHeight,v=this.sizeInfo.menuPadding,w=this.sizeInfo.menuExtras,x=this.options.hideDisabled?".disabled":"",y=function(){var b,c=j.$newElement.offset(),d=a(j.options.container);j.options.container&&!d.is("body")?(b=d.offset(),b.top+=parseInt(d.css("borderTopWidth")),b.left+=parseInt(d.css("borderLeftWidth"))):b={top:0,left:0};var e=j.options.windowPadding;f=c.top-b.top-m.scrollTop(),g=m.height()-f-n-b.top-e[2],h=c.left-b.left-m.scrollLeft(),i=m.width()-h-o-b.left-e[1],f-=e[0],h-=e[3]};if(y(),"auto"===this.options.size){var z=function(){var m,n=function(b,c){return function(d){return c?d.classList?d.classList.contains(b):a(d).hasClass(b):!(d.classList?d.classList.contains(b):a(d).hasClass(b))}},u=j.$menuInner[0].getElementsByTagName("li"),x=Array.prototype.filter?Array.prototype.filter.call(u,n("hidden",!1)):j.$lis.not(".hidden"),z=Array.prototype.filter?Array.prototype.filter.call(x,n("dropdown-header",!0)):x.filter(".dropdown-header");y(),b=g-w.vert,c=i-w.horiz,j.options.container?(k.data("height")||k.data("height",k.height()),d=k.data("height"),k.data("width")||k.data("width",k.width()),e=k.data("width")):(d=k.height(),e=k.width()),j.options.dropupAuto&&j.$newElement.toggleClass("dropup",f>g&&b-w.verti&&c-w.horiz3?3*p+w.vert-2:0,k.css({"max-height":b+"px",overflow:"hidden","min-height":m+q+r+s+t+"px"}),l.css({"max-height":b-q-r-s-t-v.vert+"px","overflow-y":"auto","min-height":Math.max(m-v.vert,0)+"px"})};z(),this.$searchbox.off("input.getSize propertychange.getSize").on("input.getSize propertychange.getSize",z),m.off("resize.getSize scroll.getSize").on("resize.getSize scroll.getSize",z)}else if(this.options.size&&"auto"!=this.options.size&&this.$lis.not(x).length>this.options.size){var A=this.$lis.not(".divider").not(x).children().slice(0,this.options.size).last().parent().index(),B=this.$lis.slice(0,A+1).filter(".divider").length;b=p*this.options.size+B*u+v.vert,j.options.container?(k.data("height")||k.data("height",k.height()),d=k.data("height")):d=k.height(),j.options.dropupAuto&&this.$newElement.toggleClass("dropup",f>g&&b-w.vert');var b,c,d,e=this,f=a(this.options.container),g=function(a){e.$bsContainer.addClass(a.attr("class").replace(/form-control|fit-width/gi,"")).toggleClass("dropup",a.hasClass("dropup")),b=a.offset(),f.is("body")?c={top:0,left:0}:(c=f.offset(),c.top+=parseInt(f.css("borderTopWidth"))-f.scrollTop(),c.left+=parseInt(f.css("borderLeftWidth"))-f.scrollLeft()),d=a.hasClass("dropup")?0:a[0].offsetHeight,e.$bsContainer.css({top:b.top-c.top+d,left:b.left-c.left,width:a[0].offsetWidth})};this.$button.on("click",function(){var b=a(this);e.isDisabled()||(g(e.$newElement),e.$bsContainer.appendTo(e.options.container).toggleClass("open",!b.hasClass("open")).append(e.$menu))}),a(window).on("resize scroll",function(){g(e.$newElement)}),this.$element.on("hide.bs.select",function(){e.$menu.data("height",e.$menu.height()),e.$bsContainer.detach()})},setSelected:function(a,b,c){c||(this.togglePlaceholder(),c=this.findLis().eq(this.liObj[a])),c.toggleClass("selected",b).find("a").attr("aria-selected",b)},setDisabled:function(a,b,c){c||(c=this.findLis().eq(this.liObj[a])),b?c.addClass("disabled").children("a").attr("href","#").attr("tabindex",-1).attr("aria-disabled",!0):c.removeClass("disabled").children("a").removeAttr("href").attr("tabindex",0).attr("aria-disabled",!1)},isDisabled:function(){return this.$element[0].disabled},checkDisabled:function(){var a=this;this.isDisabled()?(this.$newElement.addClass("disabled"),this.$button.addClass("disabled").attr("tabindex",-1).attr("aria-disabled",!0)):(this.$button.hasClass("disabled")&&(this.$newElement.removeClass("disabled"),this.$button.removeClass("disabled").attr("aria-disabled",!1)),this.$button.attr("tabindex")!=-1||this.$element.data("tabindex")||this.$button.removeAttr("tabindex")),this.$button.click(function(){return!a.isDisabled()})},togglePlaceholder:function(){var a=this.$element.val();this.$button.toggleClass("bs-placeholder",null===a||""===a||a.constructor===Array&&0===a.length)},tabIndex:function(){this.$element.data("tabindex")!==this.$element.attr("tabindex")&&this.$element.attr("tabindex")!==-98&&"-98"!==this.$element.attr("tabindex")&&(this.$element.data("tabindex",this.$element.attr("tabindex")),this.$button.attr("tabindex",this.$element.data("tabindex"))),this.$element.attr("tabindex",-98)},clickListener:function(){var b=this,c=a(document);c.data("spaceSelect",!1),this.$button.on("keyup",function(a){/(32)/.test(a.keyCode.toString(10))&&c.data("spaceSelect")&&(a.preventDefault(),c.data("spaceSelect",!1))}),this.$button.on("click",function(){b.setSize()}),this.$element.on("shown.bs.select",function(){if(b.options.liveSearch||b.multiple){if(!b.multiple){var a=b.liObj[b.$element[0].selectedIndex];if("number"!=typeof a||b.options.size===!1)return;var c=b.$lis.eq(a)[0].offsetTop-b.$menuInner[0].offsetTop;c=c-b.$menuInner[0].offsetHeight/2+b.sizeInfo.liHeight/2,b.$menuInner[0].scrollTop=c}}else b.$menuInner.find(".selected a").focus()}),this.$menuInner.on("click","li a",function(c){var d=a(this),f=d.parent().data("originalIndex"),g=b.$element.val(),h=b.$element.prop("selectedIndex"),i=!0;if(b.multiple&&1!==b.options.maxOptions&&c.stopPropagation(),c.preventDefault(),!b.isDisabled()&&!d.parent().hasClass("disabled")){var j=b.$element.find("option"),k=j.eq(f),l=k.prop("selected"),m=k.parent("optgroup"),n=b.options.maxOptions,o=m.data("maxOptions")||!1;if(b.multiple){if(k.prop("selected",!l),b.setSelected(f,!l),d.blur(),n!==!1||o!==!1){var p=n');t[2]&&(u=u.replace("{var}",t[2][n>1?0:1]),v=v.replace("{var}",t[2][o>1?0:1])),k.prop("selected",!1),b.$menu.append(w),n&&p&&(w.append(a("
"+u+"
")),i=!1,b.$element.trigger("maxReached.bs.select")),o&&q&&(w.append(a("
"+v+"
")),i=!1,b.$element.trigger("maxReachedGrp.bs.select")),setTimeout(function(){b.setSelected(f,!1)},10),w.delay(750).fadeOut(300,function(){a(this).remove()})}}}else j.prop("selected",!1),k.prop("selected",!0),b.$menuInner.find(".selected").removeClass("selected").find("a").attr("aria-selected",!1),b.setSelected(f,!0);!b.multiple||b.multiple&&1===b.options.maxOptions?b.$button.focus():b.options.liveSearch&&b.$searchbox.focus(),i&&(g!=b.$element.val()&&b.multiple||h!=b.$element.prop("selectedIndex")&&!b.multiple)&&(e=[f,k.prop("selected"),l],b.$element.triggerNative("change"))}}),this.$menu.on("click","li.disabled a, .popover-title, .popover-title :not(.close)",function(c){c.currentTarget==this&&(c.preventDefault(),c.stopPropagation(),b.options.liveSearch&&!a(c.target).hasClass("close")?b.$searchbox.focus():b.$button.focus())}),this.$menuInner.on("click",".divider, .dropdown-header",function(a){a.preventDefault(),a.stopPropagation(),b.options.liveSearch?b.$searchbox.focus():b.$button.focus()}),this.$menu.on("click",".popover-title .close",function(){b.$button.click()}),this.$searchbox.on("click",function(a){a.stopPropagation()}),this.$menu.on("click",".actions-btn",function(c){b.options.liveSearch?b.$searchbox.focus():b.$button.focus(),c.preventDefault(),c.stopPropagation(),a(this).hasClass("bs-select-all")?b.selectAll():b.deselectAll()}),this.$element.change(function(){b.render(!1),b.$element.trigger("changed.bs.select",e),e=null})},liveSearchListener:function(){var c=this,d=a('
  • ');this.$button.on("click.dropdown.data-api",function(){c.$menuInner.find(".active").removeClass("active"),c.$searchbox.val()&&(c.$searchbox.val(""),c.$lis.not(".is-hidden").removeClass("hidden"),d.parent().length&&d.remove()),c.multiple||c.$menuInner.find(".selected").addClass("active"),setTimeout(function(){c.$searchbox.focus()},10)}),this.$searchbox.on("click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api",function(a){a.stopPropagation()}),this.$searchbox.on("input propertychange",function(){if(c.$lis.not(".is-hidden").removeClass("hidden"),c.$lis.filter(".active").removeClass("active"),d.remove(),c.$searchbox.val()){var e,f=c.$lis.not(".is-hidden, .divider, .dropdown-header");if(e=c.options.liveSearchNormalize?f.not(":a"+c._searchStyle()+'("'+b(c.$searchbox.val())+'")'):f.not(":"+c._searchStyle()+'("'+c.$searchbox.val()+'")'),e.length===f.length)d.html(c.options.noneResultsText.replace("{0}",'"'+i(c.$searchbox.val())+'"')),c.$menuInner.append(d),c.$lis.addClass("hidden");else{e.addClass("hidden");var g,h=c.$lis.not(".hidden");h.each(function(b){var c=a(this);c.hasClass("divider")?void 0===g?c.addClass("hidden"):(g&&g.addClass("hidden"),g=c):c.hasClass("dropdown-header")&&h.eq(b+1).data("optgroup")!==c.data("optgroup")?c.addClass("hidden"):g=null}),g&&g.addClass("hidden"),f.not(".hidden").first().addClass("active")}}})},_searchStyle:function(){var a={begins:"ibegins",startsWith:"ibegins"};return a[this.options.liveSearchStyle]||"icontains"},val:function(a){return"undefined"!=typeof a?(this.$element.val(a),this.render(),this.$element):this.$element.val()},changeAll:function(b){if(this.multiple){"undefined"==typeof b&&(b=!0),this.findLis();var c=this.$element.find("option"),d=this.$lis.not(".divider, .dropdown-header, .disabled, .hidden"),e=d.length,f=[];if(b){if(d.filter(".selected").length===d.length)return}else if(0===d.filter(".selected").length)return;d.toggleClass("selected",b);for(var g=0;g=48&&c.keyCode<=57||c.keyCode>=96&&c.keyCode<=105||c.keyCode>=65&&c.keyCode<=90))return o.options.container?o.$button.trigger("click"):(o.setSize(),o.$menu.parent().addClass("open"),l=!0),void o.$searchbox.focus();if(o.options.liveSearch&&(/(^9$|27)/.test(c.keyCode.toString(10))&&l&&(c.preventDefault(),c.stopPropagation(),o.$menuInner.click(),o.$button.focus()),d=a('[role="listbox"] li'+p,n),m.val()||/(38|40)/.test(c.keyCode.toString(10))||0===d.filter(".active").length&&(d=o.$menuInner.find("li"),d=o.options.liveSearchNormalize?d.filter(":a"+o._searchStyle()+"("+b(q[c.keyCode])+")"):d.filter(":"+o._searchStyle()+"("+q[c.keyCode]+")"))),d.length){if(/(38|40)/.test(c.keyCode.toString(10)))e=d.index(d.find("a").filter(":focus").parent()),g=d.filter(p).first().index(),h=d.filter(p).last().index(),f=d.eq(e).nextAll(p).eq(0).index(),i=d.eq(e).prevAll(p).eq(0).index(),j=d.eq(f).prevAll(p).eq(0).index(),o.options.liveSearch&&(d.each(function(b){a(this).hasClass("disabled")||a(this).data("index",b)}),e=d.index(d.filter(".active")),g=d.first().data("index"),h=d.last().data("index"),f=d.eq(e).nextAll().eq(0).data("index"),i=d.eq(e).prevAll().eq(0).data("index"),j=d.eq(f).prevAll().eq(0).data("index")),k=m.data("prevIndex"),38==c.keyCode?(o.options.liveSearch&&e--,e!=j&&e>i&&(e=i),eh&&(e=h),e==k&&(e=g)),m.data("prevIndex",e),o.options.liveSearch?(c.preventDefault(),m.hasClass("dropdown-toggle")||(d.removeClass("active").eq(e).addClass("active").children("a").focus(),m.focus())):d.eq(e).children("a").focus();else if(!m.is("input")){var r,s,t=[];d.each(function(){a(this).hasClass("disabled")||a.trim(a(this).children("a").text().toLowerCase()).substring(0,1)==q[c.keyCode]&&t.push(a(this).index())}),r=a(document).data("keycount"),r++,a(document).data("keycount",r),s=a.trim(a(":focus").text().toLowerCase()).substring(0,1),s!=q[c.keyCode]?(r=1,a(document).data("keycount",r)):r>=t.length&&(a(document).data("keycount",0),r>t.length&&(r=1)),d.eq(t[r-1]).children("a").focus()}if((/(13|32)/.test(c.keyCode.toString(10))||/(^9$)/.test(c.keyCode.toString(10))&&o.options.selectOnTab)&&l){if(/(32)/.test(c.keyCode.toString(10))||c.preventDefault(),o.options.liveSearch)/(32)/.test(c.keyCode.toString(10))||(o.$menuInner.find(".active a").click(),m.focus());else{ 8 | var u=a(":focus");u.click(),u.focus(),c.preventDefault(),a(document).data("spaceSelect",!0)}a(document).data("keycount",0)}(/(^9$|27)/.test(c.keyCode.toString(10))&&l&&(o.multiple||o.options.liveSearch)||/(27)/.test(c.keyCode.toString(10))&&!l)&&(o.$menu.parent().removeClass("open"),o.options.container&&o.$newElement.removeClass("open"),o.$button.focus())}},mobile:function(){this.$element.addClass("mobile-device")},refresh:function(){this.$lis=null,this.liObj={},this.reloadLi(),this.render(),this.checkDisabled(),this.liHeight(!0),this.setStyle(),this.setWidth(),this.$lis&&this.$searchbox.trigger("propertychange"),this.$element.trigger("refreshed.bs.select")},hide:function(){this.$newElement.hide()},show:function(){this.$newElement.show()},remove:function(){this.$newElement.remove(),this.$element.remove()},destroy:function(){this.$newElement.before(this.$element).remove(),this.$bsContainer?this.$bsContainer.remove():this.$menu.remove(),this.$element.off(".bs.select").removeData("selectpicker").removeClass("bs-select-hidden selectpicker")}};var l=a.fn.selectpicker;a.fn.selectpicker=c,a.fn.selectpicker.Constructor=k,a.fn.selectpicker.noConflict=function(){return a.fn.selectpicker=l,this},a(document).data("keycount",0).on("keydown.bs.select",'.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input',k.prototype.keydown).on("focusin.modal",'.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input',function(a){a.stopPropagation()}),a(window).on("load.bs.select.data-api",function(){a(".selectpicker").each(function(){var b=a(this);c.call(b,b.data())})})}(a)}); 9 | //# sourceMappingURL=bootstrap-select.js.map -------------------------------------------------------------------------------- /static/bootstrap3.3/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.0 (http://getbootstrap.com) 3 | * Copyright 2011-2014 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.0",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active"));a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus","focus"==b.type)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.0",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c="prev"==a?-1:1,d=this.getItemIndex(b),e=(d+c)%this.$items.length;return this.$items.eq(e)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i="next"==b?"first":"last",j=this;if(!f.length){if(!this.options.wrap)return;f=this.$element.find(".item")[i]()}if(f.hasClass("active"))return this.sliding=!1;var k=f[0],l=a.Event("slide.bs.carousel",{relatedTarget:k,direction:h});if(this.$element.trigger(l),!l.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var m=a(this.$indicators.children()[this.getItemIndex(f)]);m&&m.addClass("active")}var n=a.Event("slid.bs.carousel",{relatedTarget:k,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),j.sliding=!1,setTimeout(function(){j.$element.trigger(n)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(n)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a(this.options.trigger).filter('[href="#'+b.id+'"], [data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.0",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0,trigger:'[data-toggle="collapse"]'},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.find("> .panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":a.extend({},e.data(),{trigger:this});c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=c(d),f={relatedTarget:this};e.hasClass("open")&&(e.trigger(b=a.Event("hide.bs.dropdown",f)),b.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f)))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('