├── .gitignore ├── README.md ├── aop ├── __init__.py ├── admin.py ├── aopform.py ├── aopfunction.py ├── models.py ├── templates │ ├── addhost.html │ ├── addhostgroup.html │ ├── addsvn.html │ ├── adduser.html │ ├── base.html │ ├── crontab.html │ ├── delhost.html │ ├── edithost.html │ ├── editsvn.html │ ├── edituser.html │ ├── group.html │ ├── hostgroup_detail.html │ ├── login.html │ ├── script.html │ ├── scriptgroup_detail.html │ ├── showhost.html │ ├── showhost_bak.html │ ├── showscript.html │ ├── showsvn.html │ ├── showuser.html │ ├── svnlog.html │ └── task.html └── views.py ├── aopproject ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py ├── manage.py └── static ├── css ├── bootstrap-responsive.css ├── bootstrap.css ├── bootstrap.min.css └── docs.css ├── img ├── glyphicons-halflings-white.png └── glyphicons-halflings.png └── js ├── aop.js ├── bootstrap.js ├── bootstrap.min.js └── jquery.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | *.log 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Automated operational platform 2 | ==== 3 | 4 | ##环境需求: 5 | * python >=2.5 6 | * mysql >5.1 7 | * nginx >1.2 8 | 9 | ##python模块: 10 | * django >=1.4.5 11 | * flup 12 | * paramiko 13 | * django-excel-response 14 | * MySQL-python 15 | 16 | ##主要功能 17 | * 服务器的资源统计 18 | * svn的在线发布 19 | * 脚本的批量执行 20 | 21 | ##安装部署 22 | * 修改aopproject/settings.py 设置数据库类型,账号密码 23 | * 运行python manage.py syncdb 进行创建数据库表结构 期间添加管理员账号 24 | * 开启服务器:python manage.py runfcgi method=prefork host=127.0.0.1 port=9001 25 | * 配置nginx转发到127.0.0.1:90001端口 26 | * nginx配置文件参考: 27 | 28 |

29 | server {
30 |         listen       80;
31 |         server_name  www.linuxyan.com;
32 |         root /var/www/html;
33 | 
34 |         access_log  /tmp/python.access.log;
35 |         error_log   /tmp/python.error.log;
36 | 
37 |         location /static/ {
38 |                 root /var/www/html;
39 |         }
40 | 
41 |         location / {
42 |                 fastcgi_pass 127.0.0.1:9001;
43 |                 fastcgi_pass_header Authorization;
44 |                 fastcgi_intercept_errors off;
45 |                 fastcgi_param PATH_INFO         $fastcgi_script_name;
46 |                 fastcgi_param REQUEST_METHOD    $request_method;
47 |                 fastcgi_param QUERY_STRING      $query_string;
48 |                 fastcgi_param CONTENT_TYPE      $content_type;
49 |                 fastcgi_param CONTENT_LENGTH    $content_length;
50 |                 fastcgi_param SERVER_PORT       $server_port;
51 |                 fastcgi_param SERVER_PROTOCOL   $server_protocol;
52 |                 fastcgi_param SERVER_NAME       $server_name;
53 |                 fastcgi_param REQUEST_URI       $request_uri;
54 |                 fastcgi_param DOCUMENT_URI      $document_uri;
55 |                 fastcgi_param DOCUMENT_ROOT     $document_root;
56 |                 fastcgi_param SERVER_ADDR       $server_addr;
57 |                 fastcgi_param REMOTE_USER       $remote_user;
58 |                 fastcgi_param REMOTE_ADDR       $remote_addr;
59 |                 fastcgi_param REMOTE_PORT       $remote_port;
60 |                 fastcgi_param SERVER_SOFTWARE   "nginx";
61 |                 fastcgi_param GATEWAY_INTERFACE "CGI/1.1";
62 |         }
63 | }
64 | 
65 | -------------------------------------------------------------------------------- /aop/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxyan/aop/e905d94d2bf870bc9f8d4fde4de6c66e3dfd423d/aop/__init__.py -------------------------------------------------------------------------------- /aop/admin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | from django.contrib import admin 5 | from aop.models import * 6 | 7 | admin.site.register(hosts) 8 | admin.site.register(svns) 9 | admin.site.register(hostgroup) 10 | 11 | admin.site.register(scripts) 12 | admin.site.register(scriptgroup) 13 | admin.site.register(tasks) 14 | admin.site.register(users) -------------------------------------------------------------------------------- /aop/aopform.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | from django.forms import ModelForm 3 | from aop.models import * 4 | from django import forms 5 | from django.contrib.auth.models import User 6 | 7 | 8 | class hostform(ModelForm): 9 | host_name = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"Host Name"})) 10 | host_user = forms.CharField(widget=forms.TextInput(attrs={"class":"input-medium","placeholder":"login user"})) 11 | host_w_ip = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"Inter ip"})) 12 | host_w_port = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"Inter port","class":"input-mini"})) 13 | host_n_ip = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"local ip"})) 14 | host_n_port = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"local port","class":"input-mini"})) 15 | script_dir = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"Example: /bin/aop/"})) 16 | host_description = forms.CharField(widget=forms.Textarea(attrs={"class":"input-xlarge","placeholder":"Server Description","rows":3})) 17 | host_pass = forms.CharField(widget=forms.PasswordInput(attrs={"placeholder":"login pass","class":"input-medium"})) 18 | host_root_pwd = forms.CharField(widget=forms.PasswordInput(attrs={"placeholder":"root pass","class":"input-medium"})) 19 | class Meta: 20 | model = hosts 21 | fields = ('host_name','host_user','host_pass','host_w_ip','host_w_port','host_n_ip','host_n_port','host_root_pwd','script_dir','host_description') 22 | 23 | 24 | class svnform(ModelForm): 25 | svn_name = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"Svn Name"})) 26 | svn_user = forms.CharField(widget=forms.TextInput(attrs={"class":"input-medium","placeholder":"Svn user"})) 27 | svn_pass = forms.CharField(widget=forms.PasswordInput(attrs={"class":"input-medium","placeholder":"Svn pass"})) 28 | svn_local = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"Example: /var/www/html"})) 29 | svn_path = forms.CharField(widget=forms.TextInput(attrs={"placeholder":"Example: svn://xx.xx.com/svnproject"})) 30 | class Meta: 31 | model = svns 32 | fields = ('svn_name','svn_user','svn_pass','svn_local','svn_path','host') 33 | 34 | 35 | 36 | class scriptform(ModelForm): 37 | script_description = forms.CharField(widget=forms.Textarea(attrs={"class":"input-xlarge","placeholder":"Script Description","rows":3})) 38 | class Meta: 39 | model = scripts 40 | fields = ('script_name','script_file','script_description') 41 | 42 | 43 | 44 | class hostgroupform(ModelForm): 45 | class Meta: 46 | model = hostgroup 47 | fields = ('host_groupname','host') 48 | 49 | class scriptgroupform(ModelForm): 50 | class Meta: 51 | model = scriptgroup 52 | fields = ('script_groupname','script') 53 | 54 | class taskform(ModelForm): 55 | class Meta: 56 | model = tasks 57 | fields = ('task_name','script_group','host_group') 58 | 59 | class userform(ModelForm): 60 | class Meta: 61 | model = User 62 | fields = ('username','password','email') 63 | if __name__ == "__main__": 64 | pass 65 | -------------------------------------------------------------------------------- /aop/aopfunction.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | import paramiko,os,time 3 | import threading 4 | from aopproject import settings 5 | import random 6 | import base64 7 | 8 | def ordinary_ssh(host,username,password,port,cmd): 9 | password = de_str(settings.SECRET_KEY,str(password)) 10 | s=paramiko.SSHClient() 11 | s.load_system_host_keys() 12 | s.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 13 | s.connect(hostname = host,port=int(port),username=username, password=password) 14 | stdin, stdout, stderr = s.exec_command(cmd) 15 | result = stdout.read() 16 | result = str(result) 17 | s.close() 18 | return result 19 | 20 | 21 | 22 | #验证服务器信息 23 | def verification_ssh(host,username,password,port,root_pwd,cmd): 24 | root_pwd = de_str(str(settings.SECRET_KEY),str(root_pwd)) 25 | password = de_str(str(settings.SECRET_KEY),str(password)) 26 | 27 | s=paramiko.SSHClient() 28 | s.load_system_host_keys() 29 | s.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 30 | s.connect(hostname = host,port=int(port),username=username, password=password) 31 | if username != 'root': 32 | ssh = s.invoke_shell() 33 | time.sleep(0.1) 34 | ssh.send('su - root\n') 35 | buff = '' 36 | while not buff.endswith(': ') or buff.endswith(': '): 37 | resp = ssh.recv(9999) 38 | buff +=resp 39 | ssh.send(root_pwd) 40 | ssh.send('\n') 41 | buff = '' 42 | while not buff.endswith('# '): 43 | resp = ssh.recv(9999) 44 | buff +=resp 45 | ssh.send(cmd) 46 | ssh.send('\n') 47 | buff = '' 48 | while not buff.endswith('# '): 49 | resp = ssh.recv(9999) 50 | buff +=resp 51 | s.close() 52 | #result = buff.replace('\n','
') 53 | result = buff 54 | else: 55 | stdin, stdout, stderr = s.exec_command(cmd) 56 | result = stdout.read() 57 | result = str(result) 58 | #result = str(result).replace('\n','
') 59 | s.close() 60 | return result 61 | 62 | 63 | def upload_run_script(tasklogpath,host,script_list): 64 | try: 65 | out = open(tasklogpath,'a') 66 | script_dir = str(host.script_dir) 67 | cmd = r"mkdir %s;chmod 777 %s" %(script_dir,script_dir) 68 | verification_ssh(host.host_w_ip,host.host_user,host.host_pass,host.host_w_port,host.host_root_pwd,cmd) 69 | print "Start upload script" 70 | t = paramiko.Transport((host.host_w_ip,host.host_w_port)) 71 | t.connect(username=host.host_user,password=de_str(settings.SECRET_KEY,str(host.host_pass))) 72 | sftp=paramiko.SFTPClient.from_transport(t) 73 | for script in script_list: 74 | local_file_path = os.path.join(settings.WEB_ROOT,'..\\').replace('\\','/')+str(script.script_file) 75 | server_file_path = os.path.join(str(host.script_dir),os.path.basename(str(script.script_file))) 76 | sftp.put(local_file_path,server_file_path) 77 | result = "\nScript %s upload to %s Success!\n" %(os.path.basename(str(script.script_file)),host.host_w_ip) 78 | out.write(result) 79 | file_path = script_dir+'/'+os.path.basename(str(script.script_file)) 80 | cmd = r"chmod 777 %s ; %s" %(file_path,file_path) 81 | print cmd 82 | out.write("\n%s run %s result:\n\n" %(host.host_w_ip,os.path.basename(str(script.script_file)))) 83 | result = verification_ssh(host.host_w_ip,host.host_user,host.host_pass,host.host_w_port,host.host_root_pwd,cmd) 84 | out.write(result+'\n-------------------------------------------------\n') 85 | except Exception as e: 86 | result = "\nScript upload to %s Faild!\n" %host.host_w_ip 87 | out.write(result) 88 | out.write(str(e)) 89 | print e 90 | t.close() 91 | out.close() 92 | 93 | 94 | class task_thread(threading.Thread): 95 | def __init__(self,tasklogpath,host,script_list): 96 | threading.Thread.__init__(self) 97 | self.tasklogpath = tasklogpath 98 | self.host = host 99 | self.script_list = script_list 100 | def run(self): 101 | print "Start upload" 102 | upload_run_script(self.tasklogpath,self.host,self.script_list) 103 | 104 | def start_task_thread(tasklogpath,host_list,script_list): 105 | try: 106 | for host in host_list: 107 | thread = task_thread(tasklogpath,host,script_list) 108 | thread.setDaemon(True) 109 | thread.start() 110 | except Exception as e: 111 | print e 112 | 113 | 114 | 115 | def en_str(key,s): 116 | kar=bytearray(key) 117 | klen=len(kar) 118 | bar=bytearray(s) 119 | offset=random.randint(0,0xff) 120 | rs=bytearray() 121 | rs.append(offset) 122 | for idx,sc in enumerate(bar): 123 | k=idx % klen 124 | rs.append(((sc+offset) % 0xff) ^ (kar[k] & kar[-(k+1)])) 125 | return base64.urlsafe_b64encode(str(rs)) 126 | 127 | def de_str(key,s): 128 | kar=bytearray(key) 129 | klen=len(kar) 130 | bar=bytearray(base64.urlsafe_b64decode(s)) 131 | offset=bar[0] 132 | rs=bytearray() 133 | for idx,sc in enumerate(bar[1:]): 134 | k=idx % klen 135 | t=(sc ^ (kar[k] & kar[-(k+1)])) 136 | if t<=offset: 137 | t+=0xff - offset 138 | else: 139 | t-=offset 140 | rs.append(t) 141 | return str(rs) 142 | 143 | if __name__ == "__main__": 144 | pass -------------------------------------------------------------------------------- /aop/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | from django.db import models 3 | from django.contrib.auth.models import User 4 | # Create your models here. 5 | 6 | #多个svn对应一个host,外键应该在svn表里面 7 | 8 | 9 | class hosts(models.Model): 10 | host_name = models.CharField(max_length=30) 11 | host_user = models.CharField(max_length=30) 12 | host_pass = models.CharField(max_length=50) 13 | host_w_ip = models.IPAddressField() 14 | host_w_port = models.PositiveIntegerField(max_length=10) 15 | host_n_ip = models.IPAddressField() 16 | host_n_port = models.PositiveIntegerField(max_length=10) 17 | host_root_pwd = models.CharField(max_length=50) 18 | script_dir = models.CharField(max_length=100) 19 | host_description = models.TextField(blank=True) 20 | create_user = models.CharField(max_length=10) 21 | 22 | def __unicode__(self): 23 | return self.host_name 24 | 25 | 26 | class svns(models.Model): 27 | svn_name = models.CharField(max_length=20) 28 | svn_user = models.CharField(max_length=30) 29 | svn_pass = models.CharField(max_length=30) 30 | svn_local = models.CharField(max_length=100) 31 | svn_path = models.CharField(max_length=100) 32 | host = models.ForeignKey(hosts) 33 | create_user = models.CharField(max_length=10) 34 | def __unicode__(self): 35 | return self.svn_name 36 | 37 | 38 | class hostgroup(models.Model): 39 | host_groupname = models.CharField(max_length=30) 40 | host = models.ManyToManyField(hosts) 41 | create_date = models.CharField(max_length=30) 42 | create_user = models.CharField(max_length=10) 43 | 44 | def __unicode__(self): 45 | return self.host_groupname 46 | 47 | class scripts(models.Model): 48 | script_name = models.CharField(max_length=30) 49 | script_file = models.FileField(upload_to='aop/script/') 50 | script_date = models.CharField(max_length=50) 51 | script_description = models.TextField(blank=True) 52 | create_user = models.CharField(max_length=10) 53 | def __unicode__(self): 54 | return self.script_name 55 | 56 | class scriptgroup(models.Model): 57 | script_groupname = models.CharField(max_length=30) 58 | script = models.ManyToManyField(scripts) 59 | create_date = models.CharField(max_length=30) 60 | create_user = models.CharField(max_length=10) 61 | def __unicode__(self): 62 | return self.script_groupname 63 | 64 | class tasks(models.Model): 65 | task_name = models.CharField(max_length=50) 66 | script_group = models.ForeignKey(scriptgroup) 67 | host_group = models.ForeignKey(hostgroup) 68 | task_date = models.CharField(max_length=50) 69 | task_status = models.CharField(max_length=10) 70 | task_create_user = models.CharField(max_length=30) 71 | def __unicode__(self): 72 | return self.task_name 73 | 74 | class UserProfile(models.Model): 75 | user = models.OneToOneField(User) 76 | name = models.CharField(u"姓名",max_length=30) 77 | iphone = models.CharField(u'手机',max_length=11) -------------------------------------------------------------------------------- /aop/templates/addhost.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Add Server{% endblock %} 3 | {% block content %} 4 |

Add Server

5 |
6 |
7 |
8 | 9 |
10 | {{ form.host_name }}{{form.host_name.errors}} 11 |
12 |
13 |
14 | 15 |
16 | {{ form.host_w_ip }}{{form.host_w_ip.errors}} 17 |   ssh port: 18 | {{ form.host_w_port }}{{form.host_w_port.errors}} 19 |
20 |
21 |
22 | 23 |
24 | {{ form.host_n_ip }}{{form.host_n_ip.errors}} 25 |   ssh port: 26 | {{ form.host_n_port }}{{form.host_n_port.errors}} 27 |
28 |
29 |
30 | 31 |
32 | {{ form.host_user }}{{form.host_user.errors}} 33 |   passwd: 34 | {{ form.host_pass }}{{form.host_pass.errors}} 35 |
36 |
37 |
38 | 39 |
40 | 41 |   passwd: 42 | {{ form.host_root_pwd }}{{form.host_root_pwd.errors}} 43 |
44 |
45 |
46 | 47 |
48 | {{ form.script_dir }}{{form.script_dir.errors}} 49 |
50 |
51 |
52 | 53 |
54 | {{ form.host_description }}{{form.host_description.errors}} 55 |
56 |
57 |
58 |
59 | 60 |
61 |
62 |
63 | {{result}} 64 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/addhostgroup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Add Server Group{% endblock %} 3 | {% block content %} 4 |

Add Server Group

5 |
6 |
7 |
8 | 9 |
10 | {{ form.host_groupname }}{{form.host_groupname.errors}} 11 |
12 |
13 |
14 | 15 |
16 | {{ form.host }}{{form.host.errors}} 17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/addsvn.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Add Svn{% endblock %} 3 | {% block content %} 4 |

Add Svn

5 |
6 |
7 |
8 | 9 |
10 | {{ form.svn_name }}{{form.svn_name.errors}} 11 |
12 |
13 |
14 | 15 |
16 | {{ form.svn_user }}{{form.svn_user.errors}} 17 |
18 |
19 |
20 | 21 |
22 | {{ form.svn_pass }}{{form.svn_pass.errors}} 23 |
24 |
25 |
26 | 27 |
28 | {{ form.svn_local }}{{form.svn_local.errors}} 29 |
30 |
31 |
32 | 33 |
34 | {{ form.svn_path }}{{form.svn_path.errors}} 35 |
36 |
37 |
38 | 39 |
40 | {{ form.host }}{{form.host.errors}} 41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 |
49 | {{result}} 50 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/adduser.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Add User{% endblock %} 3 | {% block content %} 4 |

Add User

5 |
6 |
7 |
8 | 9 |
10 | {{ form.username }}{{form.username.errors}} 11 |
12 |
13 |
14 | 15 |
16 | {{ form.password }}{{form.password.errors}} 17 |
18 |
19 |
20 | 21 |
22 | 23 |
24 |
25 |
26 | 27 |
28 | 29 |
30 |
31 | 32 |
33 | 34 |
35 | {{ form.email }}{{form.email.errors}} 36 |
37 |
38 |
39 |
40 | 41 |
42 |
43 |
44 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% block title %}AOP{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 40 | 41 |
42 |
43 |
44 | 52 |
53 |
54 | 55 | {% block content %}{% endblock %} 56 | 57 |
58 |
59 |
60 | 62 | 64 | 65 | 66 | 67 | 68 | 69 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /aop/templates/crontab.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Task Management{% endblock %} 3 | {% block content %} 4 |

Task Management

5 |
6 |
7 |
8 | Task Name{{form.task_name}} 9 |
10 |
11 | Server Group{{form.script_group}} 12 |
13 |
14 | Script Group{{form.host_group}} 15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
#Cron NameServer GroupScript Group
1LNMPserver groupscript grouprunview statusdel cron
1LNMPserver groupscript grouprunview statusdel cron
48 |

Running Status View

49 |
50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 |
#UserServerScriptConsole outputFinal status
1caoyan测试服务器lnmp.shdcsacssacscsDoneComplate
1caoyan测试服务器lnmp.shdcsacssacscsDoneComplate
82 | {{result}} 83 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/delhost.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}del Server{% endblock %} 3 | {% block content %} 4 |
5 |
6 |
7 |
确认删除服务器信息
8 |

删除服务器信息时,服务器上的svn信息也一并会删除!以下svn信息将被删除:

9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | {% for svn in svns %} 22 | 23 | 24 | 25 | 26 | 27 | 28 | {% endfor %} 29 | 30 |
所属服务器本地路径svn库路径svn名称
{{svn.host}}{{svn.svn_local}}{{svn.svn_path}}{{svn.svn_name}}
31 | 点击确认删除服务器信息以及svn信息 32 |
33 |
34 |
35 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/edithost.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Edit Server{% endblock %} 3 | {% block content %} 4 |

Edit Server

5 |
6 |
7 |
8 | 9 |
10 | {{ form.host_name }}{{form.host_name.errors}} 11 |
12 |
13 |
14 | 15 |
16 | {{ form.host_w_ip }}{{form.host_w_ip.errors}} 17 |   ssh port: 18 | {{ form.host_w_port }}{{form.host_w_port.errors}} 19 |
20 |
21 |
22 | 23 |
24 | {{ form.host_n_ip }}{{form.host_n_ip.errors}} 25 |   ssh port: 26 | {{ form.host_n_port }}{{form.host_n_port.errors}} 27 |
28 |
29 |
30 | 31 |
32 | {{ form.host_user }}{{form.host_user.errors}} 33 |   passwd: 34 | {{ form.host_pass }}{{form.host_pass.errors}} 35 |
36 |
37 |
38 | 39 |
40 | 41 |   passwd: 42 | {{ form.host_root_pwd }}{{form.host_root_pwd.errors}} 43 |
44 |
45 |
46 | 47 |
48 | {{ form.script_dir }}{{form.script_dir.errors}} 49 |
50 |
51 |
52 | 53 |
54 | {{ form.host_description }}{{form.host_description.errors}} 55 |
56 |
57 |
58 |
59 | 60 |
61 |
62 |
63 | {{result}} 64 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/editsvn.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Edit Svn{% endblock %} 3 | {% block content %} 4 |

Edit Svn

5 |
6 |
7 |
8 | 9 |
10 | {{ form.svn_name }}{{form.svn_name.errors}} 11 |
12 |
13 |
14 | 15 |
16 | {{ form.svn_user }}{{form.svn_user.errors}} 17 |
18 |
19 |
20 | 21 |
22 | {{ form.svn_pass }}{{form.svn_pass.errors}} 23 |
24 |
25 |
26 | 27 |
28 | {{ form.svn_local }}{{form.svn_local.errors}} 29 |
30 |
31 |
32 | 33 |
34 | {{ form.svn_path }}{{form.svn_path.errors}} 35 |
36 |
37 |
38 | 39 |
40 | {{ form.host }}{{form.host.errors}} 41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 |
49 | {{result}} 50 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/edituser.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Edit User{% endblock %} 3 | {% block content %} 4 |

Edit User

5 |
6 |
7 |
8 | 9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 |
18 |
19 |
20 | 21 |
22 | 23 |
24 |
25 |
26 | 27 |
28 | 29 |
30 |
31 | 32 |
33 | 34 |
35 | 36 |
37 |
38 |
39 |
40 | 41 |
42 |
43 |
44 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/group.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Add Server Group{% endblock %} 3 | {% block content %} 4 |

Add Server Group

5 |
6 |
7 |
8 | Server Group Name{{ host_group_form.host_groupname }} 9 |
10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {% for hostgroup in hostgroups %} 24 | 25 | 26 | 27 | 28 | 29 | 30 | {% endfor %} 31 | 32 |
Server Group NameCreate DateCreate User操作
{{hostgroup.host_groupname}}{{hostgroup.create_date}}{{hostgroup.create_user}}
33 | 34 | 35 |

Add Script Group

36 |
37 |
38 |
39 | Script Group Name{{ script_group_form.script_groupname }} 40 |
41 | 42 | 43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | {% for scriptgroup in scriptgroups %} 55 | 56 | 57 | 58 | 59 | 60 | 61 | {% endfor %} 62 | 63 |
Script Group NameCreate DateCreate User操作
{{scriptgroup.script_groupname}}{{scriptgroup.create_date}}{{scriptgroup.create_user}}
64 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/hostgroup_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Server Group Detail{% endblock %} 3 | {% block content %} 4 |

{{host_group.host_groupname}} Group

5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for host in host_list %} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% endfor %} 28 | 29 |
Host NameInter IP:Portlocal IP:PortHost UserScript Dir操作
{{host.host_name}}{{host.host_w_ip}}:{{host.host_w_port}}{{host.host_n_ip}}:{{host.host_n_port}}{{host.host_user}}{{host.script_dir}}
30 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% block title %}AOP{% endblock %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 32 |
33 | 34 |
35 |
36 |
37 |
38 | 39 |
40 | 41 |
42 |
43 |
44 | 45 |
46 | 47 |
48 |
49 |
50 |
51 | 54 | 55 |
56 |
57 |
58 |
59 | 60 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /aop/templates/script.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Create Script{% endblock %} 3 | {% block content %} 4 |

Create Script

5 |
6 |
7 |
8 | 9 |
10 | {{ form.script_name }}{{form.script_name.errors}} 11 |
12 |
13 |
14 | 15 |
16 | {{ form.script_file }}{{form.script_file.errors}} 17 |
18 |
19 |
20 | 21 |
22 | {{ form.script_description }}{{form.script_description.errors}} 23 |
24 |
25 |
26 |
27 | 28 |
29 |
30 |
31 | {{result}} 32 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/scriptgroup_detail.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Script Group Detail{% endblock %} 3 | {% block content %} 4 |

{{script_group.script_groupname}}

5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% for script in script_list %} 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% endfor %} 28 | 29 |
Script NameScript PathCreate DateScript descriptionCreate User操作
{{script.script_name}}{{script.script_file}}{{script.script_date}}{{script.script_description}}{{script.create_user}}
30 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/showhost.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}index{% endblock %} 3 | {% block content %} 4 |
5 | Add Server   6 | Del Server 7 |
8 | 12 |
13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for host in hosts %} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 46 | 47 | {% endfor %} 48 | 49 |
Host NameInter IP:Portlocal IP:PortHost UserScript Dir操作
{{host.host_name}}{{host.host_w_ip}}:{{host.host_w_port}}{{host.host_n_ip}}:{{host.host_n_port}}{{host.host_user}}{{host.script_dir}} 35 |
36 | Edit 37 | Del 38 | Add Group 39 | 44 |
45 |
50 | 59 | 60 | 76 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/showhost_bak.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}测试标题{% endblock %} 3 | {% block content %} 4 |
5 | 11 |
12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 113 | 114 | 115 |
testtesttesttesttest
asxsxsasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasassasasas
assasasasassasasassasasas 100 |
101 | 102 | Action 103 | 104 | 105 | 108 |
109 | 110 | 111 | 112 |
116 | 126 | 127 | 点击"无ESC关闭,无遮蔽背景"演示 128 | 141 |
142 | 143 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/showscript.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Show Script{% endblock %} 3 | {% block content %} 4 |
5 | Add Script   6 | Del Server 7 |
8 | 12 |
13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for script in scripts %} 28 | 29 | 30 | 31 | 32 | 33 | 34 | 45 | 46 | 60 | {% endfor %} 61 | 62 |
Script NameScript PathCreate DateScript descriptionCreate User操作
{{script.script_name}}{{script.script_file}}{{script.script_date}}{{script.script_description}}{{script.create_user}} 35 |
36 | Del 37 | Add Group 38 | 43 |
44 |
63 | 72 | 88 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/showsvn.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Show Svn{% endblock %} 3 | {% block content %} 4 |
5 | Add Svn   6 | show svn log   7 | Del Svn 8 |
9 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | {% for svn in svns %} 28 | 29 | 30 | 31 | 32 | 33 | 43 | 44 | {% endfor %} 45 | 46 |
Svn Namelocal pathSvn pathBy Host操作
{{svn.svn_name}}{{svn.svn_local}}{{svn.svn_path}}{{svn.host}} 34 |
35 | 更新 36 | 更新到 37 | 41 |
42 |
47 | 48 | 64 | 65 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/showuser.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Show User{% endblock %} 3 | {% block content %} 4 |
5 | {% if user.username == "root" %} 6 | Add User   7 | {% endif %} 8 | Change Personal Data   9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% if user.username == "root" %} 19 | 20 | {% endif %} 21 | 22 | 23 | 24 | {% for user_user in users %} 25 | 26 | 27 | 28 | 29 | 30 | {% if user.username == "root" %} 31 | 38 | {% endif %} 39 | 40 | {% endfor %} 41 | 42 |
用户名姓名手机邮箱操作
{{user_user.username}}{{user_user.userprofile.name}}{{user_user.userprofile.iphone}}{{user_user.email}} 32 | {% if user_user.username != "root" %} 33 |
34 | del 35 |
36 | {% endif %} 37 |
43 | 44 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/svnlog.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Svn log{% endblock %} 3 | {% block content %} 4 | Svn {{svnname}} update result! 5 |
6 |

{% autoescape off %}{{result}}{% endautoescape %}

7 | 8 | {% endblock %} -------------------------------------------------------------------------------- /aop/templates/task.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Task Management{% endblock %} 3 | {% block content %} 4 |

Task Management

5 |
6 |
7 |
8 | Task Name{{form.task_name}} 9 |
10 |
11 | Server Group{{form.script_group}} 12 |
13 |
14 | Script Group{{form.host_group}} 15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | {% for task in task_list %} 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {% if task.task_status == "0" %} 39 | 40 | {% elif task.task_status == "1" %} 41 | 42 | {% endif %} 43 | 44 | 45 | 46 | {% endfor %} 47 | 48 | 49 |
#Task NameServer GroupScript GroupCreate DateCreate User
{{task.id}}{{task.task_name}}{{task.host_group}}{{task.script_group}}{{task.task_date}}{{task.task_create_user}}runrunview statusdel task
50 |

Running Status View

51 |
52 |
53 | {% autoescape off %}{{result}} {% endautoescape %} 54 |
55 | {% endblock %} -------------------------------------------------------------------------------- /aop/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | from django.shortcuts import render_to_response,render 3 | from django.http import HttpResponse,HttpResponseRedirect 4 | from django.db import models 5 | from django.db.models import Q 6 | from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 7 | from django.forms.models import model_to_dict 8 | from aopform import * 9 | from aop.models import hosts,svns,hostgroup,scripts,tasks,scriptgroup,UserProfile 10 | import os,paramiko,time,string 11 | from aopproject import settings 12 | from django.contrib.auth.models import User 13 | from django.contrib.auth import authenticate, login as user_login, logout as user_logout 14 | from django.contrib.auth.decorators import login_required 15 | from aopfunction import * 16 | 17 | import sys 18 | reload(sys) 19 | sys.setdefaultencoding("utf-8") 20 | 21 | def login(request): 22 | if request.method == 'POST': 23 | username = request.POST['username'] 24 | password = request.POST['password'] 25 | user = authenticate(username=username, password=password) 26 | if user is not None: 27 | if user.is_active: 28 | user_login(request, user) 29 | return HttpResponseRedirect('/') 30 | else: 31 | return HttpResponse('用户没有启用!') 32 | else: 33 | return HttpResponse('用户名或者密码错误!') 34 | else: 35 | return render_to_response('login.html') 36 | 37 | def loginout(request): 38 | user_logout(request) 39 | return HttpResponseRedirect('/login/') 40 | 41 | 42 | @login_required(login_url='/login/') 43 | def index(request): 44 | if request.method == 'POST': 45 | search = request.POST.get("search",'null') 46 | print request.POST,search 47 | qset = ( 48 | Q(host_name__icontains = search) | 49 | Q(host_w_ip__icontains = search) | 50 | Q(host_w_port__icontains = search) | 51 | Q(host_n_ip__icontains = search) | 52 | Q(host_n_port__icontains = search) | 53 | Q(host_user__icontains = search) 54 | ) 55 | host_list = hosts.objects.filter(qset) 56 | paginator = Paginator(host_list, 10) 57 | page = request.GET.get('page') 58 | try: 59 | host = paginator.page(page) 60 | except PageNotAnInteger: 61 | host = paginator.page(1) 62 | except EmptyPage: 63 | host = paginator.page(paginator.num_pages) 64 | host_group = hostgroup.objects.all() 65 | return render(request,'showhost.html',{'hosts':host,'hostgroups':host_group}) 66 | else: 67 | host_list = hosts.objects.all() 68 | paginator = Paginator(host_list, 10) 69 | page = request.GET.get('page') 70 | try: 71 | host = paginator.page(page) 72 | except PageNotAnInteger: 73 | host = paginator.page(1) 74 | except EmptyPage: 75 | host = paginator.page(paginator.num_pages) 76 | host_group = hostgroup.objects.all() 77 | return render(request,'showhost.html',{'hosts':host,'hostgroups':host_group}) 78 | 79 | @login_required(login_url='/login/') 80 | def hostadd(request): 81 | if request.method == 'POST': 82 | form = hostform(request.POST) 83 | if form.is_valid(): 84 | host_name = form.cleaned_data['host_name'] 85 | host_user = form.cleaned_data['host_user'] 86 | host_pass = en_str(settings.SECRET_KEY,str(form.cleaned_data['host_pass'])) 87 | host_w_ip = form.cleaned_data['host_w_ip'] 88 | host_w_port = form.cleaned_data['host_w_port'] 89 | host_n_ip = form.cleaned_data['host_n_ip'] 90 | host_n_port = form.cleaned_data['host_n_port'] 91 | host_root_pwd = en_str(settings.SECRET_KEY,str(form.cleaned_data['host_root_pwd'])) 92 | script_dir = form.cleaned_data['script_dir'] 93 | host_description = form.cleaned_data['host_description'] 94 | try: 95 | hosts(host_name=host_name,host_user=host_user,host_pass=host_pass,host_w_ip=host_w_ip,host_w_port=host_w_port,host_n_ip=host_n_ip,host_n_port=host_n_port,host_root_pwd=host_root_pwd,script_dir=script_dir,host_description=host_description,create_user=request.user).save() 96 | result = "Add Server %s success!"%host_name 97 | except: 98 | result = "Add Server %s Failed!"%host_name 99 | form = hostform() 100 | return render(request,'addhost.html',{'form':form,'result':result}) 101 | #return render_to_response('addhost.html',{'form':form,'result':result}) 102 | return HttpResponseRedirect('/hostadd') 103 | else: 104 | form = hostform() 105 | return render(request,'addhost.html',{'form':form}) 106 | 107 | @login_required(login_url='/login/') 108 | def hostedit(request,host_id): 109 | host = hosts.objects.get(id=host_id) 110 | if request.user.username != host.create_user and request.user.username != "root": 111 | return HttpResponse("你木有权限编辑本条记录!") 112 | if request.method == 'POST': 113 | form = hostform(request.POST) 114 | if form.is_valid(): 115 | try: 116 | host = hosts.objects.get(id=host_id) 117 | host.host_name = form.cleaned_data['host_name'] 118 | host.host_user = form.cleaned_data['host_user'] 119 | host.host_pass = en_str(settings.SECRET_KEY,str(form.cleaned_data['host_pass'])) 120 | host.host_w_ip = form.cleaned_data['host_w_ip'] 121 | host.host_w_port = form.cleaned_data['host_w_port'] 122 | host.host_n_ip = form.cleaned_data['host_n_ip'] 123 | host.host_n_port = form.cleaned_data['host_n_port'] 124 | host.host_root_pwd = en_str(settings.SECRET_KEY,str(form.cleaned_data['host_root_pwd'])) 125 | host.script_dir = form.cleaned_data['script_dir'] 126 | host.host_description = form.cleaned_data['host_description'] 127 | host.create_user = request.user 128 | host.save() 129 | except: 130 | return HttpResponse("更新服务器信息失败!") 131 | return HttpResponseRedirect('/') 132 | else: 133 | return HttpResponse("服务器信息不完整!") 134 | 135 | else: 136 | try: 137 | host = hosts.objects.get(id=host_id) 138 | except: 139 | return HttpResponse("服务器信息不存在!") 140 | form=hostform(model_to_dict(host)) 141 | return render(request,'edithost.html',{'form':form}) 142 | 143 | @login_required(login_url='/login/') 144 | def showsvn(request): 145 | if request.method == "POST": 146 | search = request.POST.get("search",'null') 147 | qset = ( 148 | Q(svn_name__icontains = search) | 149 | Q(svn_user__icontains = search) | 150 | Q(svn_local__icontains = search) | 151 | Q(svn_path__icontains = search) ) 152 | svn_list = svns.objects.filter(qset) 153 | paginator = Paginator(svn_list, 10) 154 | page = 1 155 | try: 156 | svn = paginator.page(page) 157 | except PageNotAnInteger: 158 | svn = paginator.page(1) 159 | except EmptyPage: 160 | svn = paginator.page(paginator.num_pages) 161 | return render(request,'showsvn.html',{'svns':svn}) 162 | else: 163 | svn_list = svns.objects.all() 164 | paginator = Paginator(svn_list, 10) 165 | page = request.GET.get('page') 166 | try: 167 | svn = paginator.page(page) 168 | except PageNotAnInteger: 169 | svn = paginator.page(1) 170 | except EmptyPage: 171 | svn = paginator.page(paginator.num_pages) 172 | return render(request,'showsvn.html',{'svns':svn}) 173 | 174 | @login_required(login_url='/login/') 175 | def svnadd(request): 176 | if request.method == "POST": 177 | form = svnform(request.POST) 178 | if form.is_valid(): 179 | svn_name = form.cleaned_data['svn_name'] 180 | svn_user = form.cleaned_data['svn_user'] 181 | svn_pass = en_str(settings.SECRET_KEY,str(form.cleaned_data['svn_pass'])) 182 | svn_local = form.cleaned_data['svn_local'] 183 | svn_path = form.cleaned_data['svn_path'] 184 | host = form.cleaned_data['host'] 185 | try: 186 | svns(svn_name=svn_name,svn_user=svn_user,svn_pass=svn_pass,svn_local=svn_local,svn_path=svn_path,host=host,create_user=request.user).save() 187 | except: 188 | result = "Add Svn %s Failed!"%svn_name 189 | form = svnform() 190 | return render(request,'addsvn.html',{'form':form,'result':result}) 191 | return HttpResponseRedirect('/svnadd') 192 | 193 | else: 194 | form = svnform() 195 | return render(request,'addsvn.html',{'form':form}) 196 | 197 | @login_required(login_url='/login/') 198 | def svnedit(request,svn_id): 199 | svn = svns.objects.get(id=svn_id) 200 | if request.user.username != svn.create_user and request.user.username != "root": 201 | return HttpResponse("你木有权限编辑本条记录!") 202 | if request.method == 'POST': 203 | form = svnform(request.POST) 204 | if form.is_valid(): 205 | try: 206 | svn = svns.objects.get(id=svn_id) 207 | svn.svn_name = form.cleaned_data['svn_name'] 208 | svn.svn_user = form.cleaned_data['svn_user'] 209 | svn.svn_pass = en_str(settings.SECRET_KEY,str(form.cleaned_data['svn_pass'])) 210 | svn.svn_local = form.cleaned_data['svn_local'] 211 | svn.svn_path = form.cleaned_data['svn_path'] 212 | svn.host = form.cleaned_data['host'] 213 | svn.create_user = request.user 214 | svn.save() 215 | except: 216 | return HttpResponse("更新svn信息失败!") 217 | return HttpResponseRedirect('/showsvn/') 218 | else: 219 | try: 220 | svn = svns.objects.get(id=svn_id) 221 | except: 222 | return HttpResponse("SVN信息不存在!") 223 | form = svnform(model_to_dict(svn)) 224 | return render(request,'editsvn.html',{'form':form}) 225 | 226 | 227 | 228 | @login_required(login_url='/login/') 229 | def svnupdate(request,svn_id,u_type): 230 | svn = svns.objects.get(id =svn_id) 231 | host = svn.host 232 | u_type = u_type.encode('utf-8') 233 | if u_type == "1": 234 | cmd = r"svn update %s" %svn.svn_local 235 | elif u_type == "2": 236 | version_cmd = r"svn info %s |grep Revision: |awk '{print $2}'" %svn.svn_local 237 | try: 238 | now_version = ordinary_ssh(host=host.host_w_ip,username=host.host_user,password=host.host_pass,port=host.host_w_port,cmd=version_cmd) 239 | except: 240 | HttpResponse("获取当前版本失败!") 241 | print now_version 242 | restore_version = string.atoi(now_version)-1 243 | cmd = r"svn up -r %d %s" %(restore_version,svn.svn_local) 244 | logname = time.strftime("%Y-%m-%d")+"-svn.log" 245 | svnlog = os.path.join(settings.WEB_ROOT,'..\\','aop','svnlog\\').replace('\\','/') +logname 246 | try: 247 | result = verification_ssh(host=host.host_w_ip,username=host.host_user,password=host.host_pass,port=host.host_w_port,root_pwd=host.host_root_pwd,cmd=cmd) 248 | except Exception as e: 249 | return HttpResponse(str(e)) 250 | if not os.path.exists(svnlog): 251 | f = open(svnlog,'a') 252 | f.close() 253 | out = open(svnlog,'a') 254 | svnname = svn.svn_name 255 | ss = '
'+str(time.strftime('%Y-%m-%d %H:%M'))+'
' 256 | result = ss + svnname.encode('utf-8') + ":
" +result.replace('\n','
') 257 | out.write(result.replace('
','\n')+'\n') 258 | out.write('\n-----------------------------------------------------------------\n') 259 | out.close() 260 | return render(request,'svnlog.html',{'result':result,'svnname':svnname}) 261 | 262 | @login_required(login_url='/login/') 263 | def showsvnlog(request): 264 | logname = time.strftime("%Y-%m-%d")+"-svn.log" 265 | svnlog = os.path.join(settings.WEB_ROOT,'..\\','aop','svnlog\\').replace('\\','/') +logname 266 | try: 267 | f = open(svnlog) 268 | result = f.read() 269 | result = result.replace('\n','
') 270 | except Exception as e: 271 | return HttpResponse("读取日志失败!
%s" %str(e)) 272 | f.close() 273 | return render(request,'svnlog.html',{'result':result}) 274 | 275 | 276 | @login_required(login_url='/login/') 277 | def hostdel(request,host_id): 278 | host = hosts.objects.get(id=host_id) 279 | if request.user.username != host.create_user and request.user.username != "root": 280 | return HttpResponse("你木有权限删除本条记录!") 281 | svn = svns.objects.filter(host_id=host_id) 282 | return render(request,'delhost.html',{'svns':svn,'host_id':host_id}) 283 | 284 | #确认删除服务器信息以及svn信息 285 | @login_required(login_url='/login/') 286 | def confirm_del(request,host_id): 287 | host = hosts.objects.get(id=host_id) 288 | if request.user.username != host.create_user and request.user.username != "root": 289 | return HttpResponse("你木有权限删除本条记录!") 290 | hosts.objects.filter(id=host_id).delete() 291 | return HttpResponseRedirect('/') 292 | 293 | 294 | @login_required(login_url='/login/') 295 | def addscript(request): 296 | if request.method == 'POST': 297 | form = scriptform(request.POST,request.FILES) 298 | if form.is_valid(): 299 | script_name = request.POST.get('script_name') 300 | script_file = request.FILES.get('script_file') 301 | script_date = time.strftime('%Y-%m-%d %H:%M') 302 | script_description = request.POST.get('script_description') 303 | scripts(script_name=script_name,script_file=script_file,script_date=script_date,script_description=script_description,create_user=request.user).save() 304 | return HttpResponseRedirect('/showscript/') 305 | else: 306 | return HttpResponse("Upload script Failed!") 307 | else: 308 | form = scriptform() 309 | return render(request,'script.html',{'form':form}) 310 | 311 | @login_required(login_url='/login/') 312 | def showscript(request): 313 | if request.method == 'POST': 314 | search = request.POST.get("search",'null') 315 | qset = ( 316 | Q(script_name__icontains = search) | 317 | Q(script_file__icontains = search) | 318 | Q(script_date__icontains = search) | 319 | Q(script_description__icontains = search) 320 | ) 321 | script_list = scripts.objects.filter(qset) 322 | paginator = Paginator(script_list, 10) 323 | page = request.GET.get('page') 324 | try: 325 | script = paginator.page(page) 326 | except PageNotAnInteger: 327 | script = paginator.page(1) 328 | except EmptyPage: 329 | script = paginator.page(paginator.num_pages) 330 | script_group = scriptgroup.objects.all() 331 | return render(request,'showscript.html',{'scripts':script,'scriptgroups':script_group}) 332 | else: 333 | script_list = scripts.objects.all() 334 | paginator = Paginator(script_list, 10) 335 | page = request.GET.get('page') 336 | try: 337 | script = paginator.page(page) 338 | except PageNotAnInteger: 339 | script = paginator.page(1) 340 | except EmptyPage: 341 | script = paginator.page(paginator.num_pages) 342 | script_group = scriptgroup.objects.all() 343 | return render(request,'showscript.html',{'scripts':script,'scriptgroups':script_group}) 344 | 345 | @login_required(login_url='/login/') 346 | def delscript(request,script_id): 347 | script = scripts.objects.get(id=script_id) 348 | if request.user.username != script.create_user and request.user.username != "root": 349 | return HttpResponse("你木有权限删除本条记录!") 350 | scripts.objects.filter(id=script_id).delete() 351 | return HttpResponseRedirect('/showscript/') 352 | 353 | @login_required(login_url='/login/') 354 | def group(request): 355 | if request.method == 'POST': 356 | grouptype = request.POST['grouptype'] 357 | if grouptype == "servergroup": 358 | form = hostgroupform(request.method) 359 | if form.is_valid: 360 | host_groupname = request.POST['host_groupname'] 361 | create_date = time.strftime('%Y-%m-%d %H:%M') 362 | group = hostgroup() 363 | group.host_groupname=host_groupname 364 | group.create_date = create_date 365 | group.create_user = request.user 366 | group.save() 367 | else: 368 | form = scriptgroupform(request.method) 369 | if form.is_valid: 370 | script_groupname = request.POST['script_groupname'] 371 | create_date = time.strftime('%Y-%m-%d %H:%M') 372 | group = scriptgroup() 373 | group.script_groupname = script_groupname 374 | group.create_date = create_date 375 | group.create_user = request.user 376 | group.save() 377 | return HttpResponseRedirect('/group/') 378 | else: 379 | host_group_form = hostgroupform() 380 | hostgroups = hostgroup.objects.all() 381 | script_group_form = scriptgroupform() 382 | scriptgroups = scriptgroup.objects.all() 383 | return render(request,'group.html',{'host_group_form':host_group_form,'script_group_form':script_group_form,'hostgroups':hostgroups,'scriptgroups':scriptgroups}) 384 | 385 | @login_required(login_url='/login/') 386 | def hostgroup_detail(request,group_id): 387 | host_group = hostgroup.objects.get(id=group_id) 388 | host_list = host_group.host.all() 389 | return render(request,'hostgroup_detail.html',{'host_group':host_group,'host_list':host_list}) 390 | 391 | @login_required(login_url='/login/') 392 | def scriptgroup_detail(request,group_id): 393 | script_group = scriptgroup.objects.get(id=group_id) 394 | script_list = script_group.script.all() 395 | return render(request,'scriptgroup_detail.html',{'script_group':script_group,'script_list':script_list}) 396 | 397 | @login_required(login_url='/login/') 398 | def hostgroup_del(request,group_id): 399 | host_group = hostgroup.objects.get(id=group_id) 400 | if request.user.username != host_group.create_user and request.user.username != "root": 401 | return HttpResponse("你木有权限删除本条记录!") 402 | hostgroup.objects.filter(id=group_id).delete() 403 | return HttpResponseRedirect('/group/') 404 | 405 | @login_required(login_url='/login/') 406 | def hostgroup_del_host(request): 407 | if request.method == 'POST': 408 | try: 409 | group_id=request.POST['group_id'] 410 | host_id = request.POST['host_id'] 411 | host_group = hostgroup.objects.get(id=group_id) 412 | host = hosts.objects.get(id=host_id) 413 | host_group.host.remove(host) 414 | result = "success" 415 | return HttpResponse(result,mimetype='application/html') 416 | except: 417 | result = "error" 418 | return HttpResponse(result,mimetype='application/html') 419 | 420 | @login_required(login_url='/login/') 421 | def scriptgroup_del(request,group_id): 422 | script_group = scriptgroup.objects.get(id=group_id) 423 | if request.user.username != script_group.create_user and request.user.username != "root": 424 | return HttpResponse("你木有权限删除本条记录!") 425 | scriptgroup.objects.filter(id=group_id).delete() 426 | return HttpResponseRedirect('/group/') 427 | 428 | @login_required(login_url='/login/') 429 | def scriptgroup_del_script(request): 430 | if request.method == 'POST': 431 | try: 432 | group_id = request.POST['group_id'] 433 | script_id = request.POST['script_id'] 434 | script_group = scriptgroup.objects.get(id=group_id) 435 | script = scripts.objects.get(id=script_id) 436 | script_group.script.remove(script) 437 | result = "success" 438 | return HttpResponse(result,mimetype='application/html') 439 | except: 440 | result = "error" 441 | return HttpResponse(result,mimetype='application/html') 442 | 443 | @login_required(login_url='/login/') 444 | def addtogroup(request): 445 | if request.method == 'POST': 446 | grouptype = request.POST['grouptype'] 447 | if grouptype == "servergroup": 448 | host_id = request.POST['host_id'] 449 | group_id = request.POST['group_id'] 450 | host = hosts.objects.get(id=host_id) 451 | group = hostgroup.objects.get(id=group_id) 452 | try : 453 | group.host.get(id=host_id) 454 | result = str(host.host_name)+". Already Exists Server Group ."+str(group.host_groupname)+". Add to Server Group Failed!" 455 | except: 456 | group.host.add(host) 457 | group.save() 458 | result = str(host.host_name)+". add to Server Group ."+str(group.host_groupname)+". Success!" 459 | return HttpResponse(result,mimetype='application/html') 460 | elif grouptype == "scriptgroup": 461 | script_id = request.POST['script_id'] 462 | group_id = request.POST['group_id'] 463 | script = scripts.objects.get(id=script_id) 464 | group = scriptgroup.objects.get(id=group_id) 465 | try: 466 | group.script.get(id=script_id) 467 | result = str(script.script_name) +"Already Exists Script Group"+str(group.script_groupname)+". Add to Script Group Failed!" 468 | except: 469 | group.script.add(script) 470 | group.save() 471 | result = str(script.script_name)+". add to Server Group ."+str(group.script_groupname)+". Success!" 472 | return HttpResponse(result,mimetype='application/html') 473 | 474 | else: 475 | return HttpResponse("xx") 476 | 477 | 478 | @login_required(login_url='/login/') 479 | def task(request): 480 | if request.method == 'POST': 481 | form = taskform(request.POST) 482 | if form.is_valid(): 483 | try: 484 | task_name = form.cleaned_data['task_name'] 485 | script_group = form.cleaned_data['script_group'] 486 | host_group = form.cleaned_data['host_group'] 487 | task_date = time.strftime('%Y-%m-%d %H:%M') 488 | task_status = "0" 489 | task = tasks() 490 | task.task_name = task_name 491 | task.script_group = script_group 492 | task.host_group = host_group 493 | task.task_date = task_date 494 | task.task_status = task_status 495 | task.task_create_user = request.user 496 | task.save() 497 | return HttpResponseRedirect('/task/') 498 | except: 499 | return HttpResponse("添加任务失败!") 500 | else: 501 | form = taskform() 502 | task_list = tasks.objects.all() 503 | return render(request,'task.html',{'form':form,'task_list':task_list}) 504 | 505 | @login_required(login_url='/login/') 506 | def task_del(request,task_id): 507 | task = tasks.objects.get(id=task_id) 508 | if request.user.username != task.task_create_user and request.user.username != "root": 509 | return HttpResponse("你木有权限删除本条记录!") 510 | tasks.objects.filter(id=task_id).delete() 511 | return HttpResponseRedirect('/task/') 512 | 513 | 514 | @login_required(login_url='/login/') 515 | def task_run(request): 516 | if request.method == 'POST': 517 | task_id = request.POST['task_id'] 518 | task = tasks.objects.get(id=task_id) 519 | if request.user.username != task.task_create_user and request.user.username != "root": 520 | result = "没有权限执行此任务!" 521 | return HttpResponse(result,mimetype='application/html') 522 | task = tasks.objects.get(id=task_id) 523 | host_list = task.host_group.host.all() 524 | script_list = task.script_group.script.all() 525 | tasklogname = "task_"+str(task.task_name)+".log" 526 | tasklogpath = os.path.join(settings.WEB_ROOT,'..\\','aop','tasklog\\').replace('\\','/') +tasklogname 527 | try: 528 | start_task_thread(tasklogpath,host_list,script_list) 529 | result = "Add Task queue Success!" 530 | except: 531 | result = "Add Task queue Faild!" 532 | return HttpResponse(result,mimetype='application/html') 533 | 534 | @login_required(login_url='/login/') 535 | def task_status(request,task_id): 536 | form = taskform() 537 | task_list = tasks.objects.all() 538 | task = tasks.objects.get(id=task_id) 539 | task_log = "task_"+str(task.task_name)+".log" 540 | tasklogpath = os.path.join(settings.WEB_ROOT,'..\\','aop','tasklog\\').replace('\\','/') +task_log 541 | try: 542 | f = open(tasklogpath,'r') 543 | all_text = f.read() 544 | result = all_text.replace('\n','
') 545 | return render(request,'task.html',{'form':form,'task_list':task_list,'result':result}) 546 | except: 547 | result = "read result Faild!" 548 | return render(request,'task.html',{'form':form,'task_list':task_list,'result':result}) 549 | 550 | @login_required(login_url='/login/') 551 | def showuser(request): 552 | users = User.objects.all() 553 | return render(request,'showuser.html',{'users':users}) 554 | 555 | @login_required(login_url='/login/') 556 | def adduser(request): 557 | if request.user.username != "root": 558 | return HttpResponse("你木有权限添加用户!") 559 | if request.method == 'POST': 560 | form = userform(request.POST) 561 | if form.is_valid(): 562 | try: 563 | username = form.cleaned_data['username'] 564 | password = form.cleaned_data['password'] 565 | email = form.cleaned_data['email'] 566 | user = User.objects.create_user(username=username,password=password,email=email) 567 | user.save() 568 | name = request.POST['xingming'] 569 | iphone = request.POST['iphone'] 570 | UserProfile(user=user,name=name,iphone=iphone).save() 571 | return HttpResponseRedirect('/showuser/') 572 | except Exception as e: 573 | return HttpResponse(e) 574 | else: 575 | form = userform() 576 | return render(request,'adduser.html',{'form':form}) 577 | 578 | @login_required(login_url='/login/') 579 | def deluser(request,user_id): 580 | if request.user.username != "root": 581 | return HttpResponse("你木有权限删除此用户!") 582 | User.objects.filter(id=user_id).delete() 583 | return HttpResponseRedirect('/showuser/') 584 | 585 | @login_required(login_url='/login/') 586 | def edituser(request,user_id): 587 | if request.method == 'POST': 588 | try: 589 | password = request.POST['password'] 590 | name = request.POST['xingming'] 591 | iphone = request.POST['iphone'] 592 | email = request.POST['email'] 593 | user = User.objects.get(id=user_id) 594 | user.email = email 595 | user.set_password(password) 596 | user.save() 597 | userprofile = UserProfile.objects.get(user=user) 598 | userprofile.name = name 599 | userprofile.iphone = iphone 600 | userprofile.save() 601 | return HttpResponseRedirect('/showuser/') 602 | except Exception as e: 603 | return HttpResponse(e) 604 | 605 | else: 606 | user = User.objects.get(id=user_id) 607 | return render(request,'edituser.html',{'user':user}) 608 | 609 | 610 | 611 | def test(request): 612 | return render_to_response('showhost_bak.html') 613 | 614 | 615 | 616 | 617 | #from django.contrib.auth.models import User; 618 | #user = User.objects.create_user(username='updatesvn',password='updatesvn123',email='a@a.com') 619 | #user.save 620 | #user.set_password("L8ka65##702") 621 | #user.save() -------------------------------------------------------------------------------- /aopproject/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxyan/aop/e905d94d2bf870bc9f8d4fde4de6c66e3dfd423d/aopproject/__init__.py -------------------------------------------------------------------------------- /aopproject/settings.py: -------------------------------------------------------------------------------- 1 | # Django settings for aopproject project. 2 | import os 3 | DEBUG = True 4 | TEMPLATE_DEBUG = DEBUG 5 | 6 | WEB_ROOT = os.path.dirname(os.path.abspath(__file__)).replace('\\','/') 7 | 8 | ADMINS = ( 9 | # ('Your Name', 'your_email@example.com'), 10 | ) 11 | 12 | MANAGERS = ADMINS 13 | 14 | DATABASES = { 15 | 'default': { 16 | 'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'. 17 | 'NAME': 'aopdbtest', # Or path to database file if using sqlite3. 18 | 'USER': 'root', # Not used with sqlite3. 19 | 'PASSWORD': 'linuxcy@126', # Not used with sqlite3. 20 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. 21 | 'PORT': '', # Set to empty string for default. Not used with sqlite3. 22 | } 23 | } 24 | 25 | # Hosts/domain names that are valid for this site; required if DEBUG is False 26 | # See https://docs.djangoproject.com/en/1.4/ref/settings/#allowed-hosts 27 | ALLOWED_HOSTS = [] 28 | 29 | # Local time zone for this installation. Choices can be found here: 30 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name 31 | # although not all choices may be available on all operating systems. 32 | # In a Windows environment this must be set to your system time zone. 33 | TIME_ZONE = 'Asia/Shanghai' 34 | 35 | # Language code for this installation. All choices can be found here: 36 | # http://www.i18nguy.com/unicode/language-identifiers.html 37 | LANGUAGE_CODE = 'zh-cn' 38 | 39 | SITE_ID = 1 40 | 41 | # If you set this to False, Django will make some optimizations so as not 42 | # to load the internationalization machinery. 43 | USE_I18N = True 44 | 45 | # If you set this to False, Django will not format dates, numbers and 46 | # calendars according to the current locale. 47 | USE_L10N = True 48 | 49 | # If you set this to False, Django will not use timezone-aware datetimes. 50 | USE_TZ = True 51 | 52 | # Absolute filesystem path to the directory that will hold user-uploaded files. 53 | # Example: "/home/media/media.lawrence.com/media/" 54 | MEDIA_ROOT = os.path.join(WEB_ROOT,'../').replace('\\','/') 55 | 56 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a 57 | # trailing slash. 58 | # Examples: "http://media.lawrence.com/media/", "http://example.com/media/" 59 | MEDIA_URL = '' 60 | 61 | # Absolute path to the directory static files should be collected to. 62 | # Don't put anything in this directory yourself; store your static files 63 | # in apps' "static/" subdirectories and in STATICFILES_DIRS. 64 | # Example: "/home/media/media.lawrence.com/static/" 65 | STATIC_ROOT = '' 66 | 67 | # URL prefix for static files. 68 | # Example: "http://media.lawrence.com/static/" 69 | STATIC_URL = '/static/' 70 | 71 | # Additional locations of static files 72 | STATICFILES_DIRS = ( 73 | # Put strings here, like "/home/html/static" or "C:/www/django/static". 74 | # Always use forward slashes, even on Windows. 75 | # Don't forget to use absolute paths, not relative paths. 76 | os.path.join(WEB_ROOT,'../static/').replace('\\','/'), 77 | ) 78 | 79 | # List of finder classes that know how to find static files in 80 | # various locations. 81 | STATICFILES_FINDERS = ( 82 | 'django.contrib.staticfiles.finders.FileSystemFinder', 83 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder', 84 | # 'django.contrib.staticfiles.finders.DefaultStorageFinder', 85 | ) 86 | 87 | # Make this unique, and don't share it with anybody. 88 | SECRET_KEY = '0@v66d*5j4yb^sp$yg128#c@4$iyv^^%%)s+^u4fx^snjjyg=u' 89 | 90 | # List of callables that know how to import templates from various sources. 91 | TEMPLATE_LOADERS = ( 92 | 'django.template.loaders.filesystem.Loader', 93 | 'django.template.loaders.app_directories.Loader', 94 | # 'django.template.loaders.eggs.Loader', 95 | ) 96 | 97 | MIDDLEWARE_CLASSES = ( 98 | 'django.middleware.common.CommonMiddleware', 99 | 'django.contrib.sessions.middleware.SessionMiddleware', 100 | #'django.middleware.csrf.CsrfViewMiddleware', 101 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 102 | 'django.contrib.messages.middleware.MessageMiddleware', 103 | # Uncomment the next line for simple clickjacking protection: 104 | # 'django.middleware.clickjacking.XFrameOptionsMiddleware', 105 | ) 106 | 107 | ROOT_URLCONF = 'aopproject.urls' 108 | 109 | # Python dotted path to the WSGI application used by Django's runserver. 110 | WSGI_APPLICATION = 'aopproject.wsgi.application' 111 | 112 | TEMPLATE_DIRS = ( 113 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". 114 | # Always use forward slashes, even on Windows. 115 | # Don't forget to use absolute paths, not relative paths. 116 | ) 117 | 118 | INSTALLED_APPS = ( 119 | 'django.contrib.auth', 120 | 'django.contrib.contenttypes', 121 | 'django.contrib.sessions', 122 | 'django.contrib.sites', 123 | 'django.contrib.messages', 124 | 'django.contrib.staticfiles', 125 | # Uncomment the next line to enable the admin: 126 | #'django.contrib.admin', 127 | # Uncomment the next line to enable admin documentation: 128 | #'django.contrib.admindocs', 129 | 'aop', 130 | ) 131 | 132 | # A sample logging configuration. The only tangible logging 133 | # performed by this configuration is to send an email to 134 | # the site admins on every HTTP 500 error when DEBUG=False. 135 | # See http://docs.djangoproject.com/en/dev/topics/logging for 136 | # more details on how to customize your logging configuration. 137 | LOGGING = { 138 | 'version': 1, 139 | 'disable_existing_loggers': False, 140 | 'filters': { 141 | 'require_debug_false': { 142 | '()': 'django.utils.log.RequireDebugFalse' 143 | } 144 | }, 145 | 'handlers': { 146 | 'mail_admins': { 147 | 'level': 'ERROR', 148 | 'filters': ['require_debug_false'], 149 | 'class': 'django.utils.log.AdminEmailHandler' 150 | } 151 | }, 152 | 'loggers': { 153 | 'django.request': { 154 | 'handlers': ['mail_admins'], 155 | 'level': 'ERROR', 156 | 'propagate': True, 157 | }, 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /aopproject/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import patterns, include, url 2 | from django.contrib import admin 3 | # Uncomment the next two lines to enable the admin: 4 | #from django.contrib import admin 5 | #admin.autodiscover() 6 | 7 | urlpatterns = patterns('aop.views', 8 | # Examples: 9 | # url(r'^$', 'aopproject.views.home', name='home'), 10 | # url(r'^aopproject/', include('aopproject.foo.urls')), 11 | 12 | # Uncomment the admin/doc line below to enable admin documentation: 13 | #url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 14 | 15 | # Uncomment the next line to enable the admin: 16 | #url(r'^admin/', include(admin.site.urls)), 17 | url(r'^login/$', 'login'), 18 | url(r'^loginout/$', 'loginout'), 19 | url(r'^$', 'index'), 20 | url(r'^svnadd/$', 'svnadd'), 21 | url(r'^hostadd/$', 'hostadd'), 22 | url(r'^hostedit/(?P[^/]+)$', 'hostedit'), 23 | url(r'^hostdel/(?P[^/]+)$', 'hostdel'), 24 | url(r'^confirm_del/(?P[^/]+)$', 'confirm_del'), 25 | url(r'^showsvn/$', 'showsvn'), 26 | url(r'^showsvnlog/$', 'showsvnlog'), 27 | url(r'^svnedit/(?P[^/]+)$', 'svnedit'), 28 | url(r'^svnupdate/(?P[^/]+)/(?P[^/]+)$', 'svnupdate'), 29 | url(r'^group/$', 'group'), 30 | url(r'^task/$', 'task'), 31 | url(r'^task_del/(?P[^/]+)$', 'task_del'), 32 | url(r'^task_status/(?P[^/]+)$', 'task_status'), 33 | url(r'^task_run/$', 'task_run'), 34 | url(r'^addtogroup/$', 'addtogroup'), 35 | url(r'^addscript/$', 'addscript'), 36 | url(r'^showscript/$', 'showscript'), 37 | url(r'^delscript/(?P[^/]+)$', 'delscript'), 38 | url(r'^hostgroup_detail/(?P[^/]+)$', 'hostgroup_detail'), 39 | url(r'^hostgroup_del/(?P[^/]+)$', 'hostgroup_del'), 40 | url(r'^scriptgroup_detail/(?P[^/]+)$', 'scriptgroup_detail'), 41 | url(r'^scriptgroup_del/(?P[^/]+)$', 'scriptgroup_del'), 42 | url(r'^hostgroup_del_host/$', 'hostgroup_del_host'), 43 | url(r'^scriptgroup_del_script/$', 'scriptgroup_del_script'), 44 | url(r'^showuser/$', 'showuser'), 45 | url(r'^adduser/$', 'adduser'), 46 | url(r'^edituser/(?P[^/]+)$', 'edituser'), 47 | url(r'^deluser/(?P[^/]+)$', 'deluser'), 48 | url(r'^test/$', 'test'), 49 | 50 | ) 51 | -------------------------------------------------------------------------------- /aopproject/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for aopproject project. 3 | 4 | This module contains the WSGI application used by Django's development server 5 | and any production WSGI deployments. It should expose a module-level variable 6 | named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover 7 | this application via the ``WSGI_APPLICATION`` setting. 8 | 9 | Usually you will have the standard Django WSGI application here, but it also 10 | might make sense to replace the whole Django WSGI application with a custom one 11 | that later delegates to the Django one. For example, you could introduce WSGI 12 | middleware here, or combine a Django application with an application of another 13 | framework. 14 | 15 | """ 16 | import os 17 | 18 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "aopproject.settings") 19 | 20 | # This application object is used by any WSGI server configured to use this 21 | # file. This includes Django's development server, if the WSGI_APPLICATION 22 | # setting points here. 23 | from django.core.wsgi import get_wsgi_application 24 | application = get_wsgi_application() 25 | 26 | # Apply WSGI middleware here. 27 | # from helloworld.wsgi import HelloWorldApplication 28 | # application = HelloWorldApplication(application) 29 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "aopproject.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | 12 | -------------------------------------------------------------------------------- /static/css/bootstrap-responsive.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.1 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | .clearfix { 12 | *zoom: 1; 13 | } 14 | 15 | .clearfix:before, 16 | .clearfix:after { 17 | display: table; 18 | line-height: 0; 19 | content: ""; 20 | } 21 | 22 | .clearfix:after { 23 | clear: both; 24 | } 25 | 26 | .hide-text { 27 | font: 0/0 a; 28 | color: transparent; 29 | text-shadow: none; 30 | background-color: transparent; 31 | border: 0; 32 | } 33 | 34 | .input-block-level { 35 | display: block; 36 | width: 100%; 37 | min-height: 30px; 38 | -webkit-box-sizing: border-box; 39 | -moz-box-sizing: border-box; 40 | box-sizing: border-box; 41 | } 42 | 43 | @-ms-viewport { 44 | width: device-width; 45 | } 46 | 47 | .hidden { 48 | display: none; 49 | visibility: hidden; 50 | } 51 | 52 | .visible-phone { 53 | display: none !important; 54 | } 55 | 56 | .visible-tablet { 57 | display: none !important; 58 | } 59 | 60 | .hidden-desktop { 61 | display: none !important; 62 | } 63 | 64 | .visible-desktop { 65 | display: inherit !important; 66 | } 67 | 68 | @media (min-width: 768px) and (max-width: 979px) { 69 | .hidden-desktop { 70 | display: inherit !important; 71 | } 72 | .visible-desktop { 73 | display: none !important ; 74 | } 75 | .visible-tablet { 76 | display: inherit !important; 77 | } 78 | .hidden-tablet { 79 | display: none !important; 80 | } 81 | } 82 | 83 | @media (max-width: 767px) { 84 | .hidden-desktop { 85 | display: inherit !important; 86 | } 87 | .visible-desktop { 88 | display: none !important; 89 | } 90 | .visible-phone { 91 | display: inherit !important; 92 | } 93 | .hidden-phone { 94 | display: none !important; 95 | } 96 | } 97 | 98 | .visible-print { 99 | display: none !important; 100 | } 101 | 102 | @media print { 103 | .visible-print { 104 | display: inherit !important; 105 | } 106 | .hidden-print { 107 | display: none !important; 108 | } 109 | } 110 | 111 | @media (min-width: 1200px) { 112 | .row { 113 | margin-left: -30px; 114 | *zoom: 1; 115 | } 116 | .row:before, 117 | .row:after { 118 | display: table; 119 | line-height: 0; 120 | content: ""; 121 | } 122 | .row:after { 123 | clear: both; 124 | } 125 | [class*="span"] { 126 | float: left; 127 | min-height: 1px; 128 | margin-left: 30px; 129 | } 130 | .container, 131 | .navbar-static-top .container, 132 | .navbar-fixed-top .container, 133 | .navbar-fixed-bottom .container { 134 | width: 1170px; 135 | } 136 | .span12 { 137 | width: 1170px; 138 | } 139 | .span11 { 140 | width: 1070px; 141 | } 142 | .span10 { 143 | width: 970px; 144 | } 145 | .span9 { 146 | width: 870px; 147 | } 148 | .span8 { 149 | width: 770px; 150 | } 151 | .span7 { 152 | width: 670px; 153 | } 154 | .span6 { 155 | width: 570px; 156 | } 157 | .span5 { 158 | width: 470px; 159 | } 160 | .span4 { 161 | width: 370px; 162 | } 163 | .span3 { 164 | width: 270px; 165 | } 166 | .span2 { 167 | width: 170px; 168 | } 169 | .span1 { 170 | width: 70px; 171 | } 172 | .offset12 { 173 | margin-left: 1230px; 174 | } 175 | .offset11 { 176 | margin-left: 1130px; 177 | } 178 | .offset10 { 179 | margin-left: 1030px; 180 | } 181 | .offset9 { 182 | margin-left: 930px; 183 | } 184 | .offset8 { 185 | margin-left: 830px; 186 | } 187 | .offset7 { 188 | margin-left: 730px; 189 | } 190 | .offset6 { 191 | margin-left: 630px; 192 | } 193 | .offset5 { 194 | margin-left: 530px; 195 | } 196 | .offset4 { 197 | margin-left: 430px; 198 | } 199 | .offset3 { 200 | margin-left: 330px; 201 | } 202 | .offset2 { 203 | margin-left: 230px; 204 | } 205 | .offset1 { 206 | margin-left: 130px; 207 | } 208 | .row-fluid { 209 | width: 100%; 210 | *zoom: 1; 211 | } 212 | .row-fluid:before, 213 | .row-fluid:after { 214 | display: table; 215 | line-height: 0; 216 | content: ""; 217 | } 218 | .row-fluid:after { 219 | clear: both; 220 | } 221 | .row-fluid [class*="span"] { 222 | display: block; 223 | float: left; 224 | width: 100%; 225 | min-height: 30px; 226 | margin-left: 2.564102564102564%; 227 | *margin-left: 2.5109110747408616%; 228 | -webkit-box-sizing: border-box; 229 | -moz-box-sizing: border-box; 230 | box-sizing: border-box; 231 | } 232 | .row-fluid [class*="span"]:first-child { 233 | margin-left: 0; 234 | } 235 | .row-fluid .controls-row [class*="span"] + [class*="span"] { 236 | margin-left: 2.564102564102564%; 237 | } 238 | .row-fluid .span12 { 239 | width: 100%; 240 | *width: 99.94680851063829%; 241 | } 242 | .row-fluid .span11 { 243 | width: 91.45299145299145%; 244 | *width: 91.39979996362975%; 245 | } 246 | .row-fluid .span10 { 247 | width: 82.90598290598291%; 248 | *width: 82.8527914166212%; 249 | } 250 | .row-fluid .span9 { 251 | width: 74.35897435897436%; 252 | *width: 74.30578286961266%; 253 | } 254 | .row-fluid .span8 { 255 | width: 65.81196581196582%; 256 | *width: 65.75877432260411%; 257 | } 258 | .row-fluid .span7 { 259 | width: 57.26495726495726%; 260 | *width: 57.21176577559556%; 261 | } 262 | .row-fluid .span6 { 263 | width: 48.717948717948715%; 264 | *width: 48.664757228587014%; 265 | } 266 | .row-fluid .span5 { 267 | width: 40.17094017094017%; 268 | *width: 40.11774868157847%; 269 | } 270 | .row-fluid .span4 { 271 | width: 31.623931623931625%; 272 | *width: 31.570740134569924%; 273 | } 274 | .row-fluid .span3 { 275 | width: 23.076923076923077%; 276 | *width: 23.023731587561375%; 277 | } 278 | .row-fluid .span2 { 279 | width: 14.52991452991453%; 280 | *width: 14.476723040552828%; 281 | } 282 | .row-fluid .span1 { 283 | width: 5.982905982905983%; 284 | *width: 5.929714493544281%; 285 | } 286 | .row-fluid .offset12 { 287 | margin-left: 105.12820512820512%; 288 | *margin-left: 105.02182214948171%; 289 | } 290 | .row-fluid .offset12:first-child { 291 | margin-left: 102.56410256410257%; 292 | *margin-left: 102.45771958537915%; 293 | } 294 | .row-fluid .offset11 { 295 | margin-left: 96.58119658119658%; 296 | *margin-left: 96.47481360247316%; 297 | } 298 | .row-fluid .offset11:first-child { 299 | margin-left: 94.01709401709402%; 300 | *margin-left: 93.91071103837061%; 301 | } 302 | .row-fluid .offset10 { 303 | margin-left: 88.03418803418803%; 304 | *margin-left: 87.92780505546462%; 305 | } 306 | .row-fluid .offset10:first-child { 307 | margin-left: 85.47008547008548%; 308 | *margin-left: 85.36370249136206%; 309 | } 310 | .row-fluid .offset9 { 311 | margin-left: 79.48717948717949%; 312 | *margin-left: 79.38079650845607%; 313 | } 314 | .row-fluid .offset9:first-child { 315 | margin-left: 76.92307692307693%; 316 | *margin-left: 76.81669394435352%; 317 | } 318 | .row-fluid .offset8 { 319 | margin-left: 70.94017094017094%; 320 | *margin-left: 70.83378796144753%; 321 | } 322 | .row-fluid .offset8:first-child { 323 | margin-left: 68.37606837606839%; 324 | *margin-left: 68.26968539734497%; 325 | } 326 | .row-fluid .offset7 { 327 | margin-left: 62.393162393162385%; 328 | *margin-left: 62.28677941443899%; 329 | } 330 | .row-fluid .offset7:first-child { 331 | margin-left: 59.82905982905982%; 332 | *margin-left: 59.72267685033642%; 333 | } 334 | .row-fluid .offset6 { 335 | margin-left: 53.84615384615384%; 336 | *margin-left: 53.739770867430444%; 337 | } 338 | .row-fluid .offset6:first-child { 339 | margin-left: 51.28205128205128%; 340 | *margin-left: 51.175668303327875%; 341 | } 342 | .row-fluid .offset5 { 343 | margin-left: 45.299145299145295%; 344 | *margin-left: 45.1927623204219%; 345 | } 346 | .row-fluid .offset5:first-child { 347 | margin-left: 42.73504273504273%; 348 | *margin-left: 42.62865975631933%; 349 | } 350 | .row-fluid .offset4 { 351 | margin-left: 36.75213675213675%; 352 | *margin-left: 36.645753773413354%; 353 | } 354 | .row-fluid .offset4:first-child { 355 | margin-left: 34.18803418803419%; 356 | *margin-left: 34.081651209310785%; 357 | } 358 | .row-fluid .offset3 { 359 | margin-left: 28.205128205128204%; 360 | *margin-left: 28.0987452264048%; 361 | } 362 | .row-fluid .offset3:first-child { 363 | margin-left: 25.641025641025642%; 364 | *margin-left: 25.53464266230224%; 365 | } 366 | .row-fluid .offset2 { 367 | margin-left: 19.65811965811966%; 368 | *margin-left: 19.551736679396257%; 369 | } 370 | .row-fluid .offset2:first-child { 371 | margin-left: 17.094017094017094%; 372 | *margin-left: 16.98763411529369%; 373 | } 374 | .row-fluid .offset1 { 375 | margin-left: 11.11111111111111%; 376 | *margin-left: 11.004728132387708%; 377 | } 378 | .row-fluid .offset1:first-child { 379 | margin-left: 8.547008547008547%; 380 | *margin-left: 8.440625568285142%; 381 | } 382 | input, 383 | textarea, 384 | .uneditable-input { 385 | margin-left: 0; 386 | } 387 | .controls-row [class*="span"] + [class*="span"] { 388 | margin-left: 30px; 389 | } 390 | input.span12, 391 | textarea.span12, 392 | .uneditable-input.span12 { 393 | width: 1156px; 394 | } 395 | input.span11, 396 | textarea.span11, 397 | .uneditable-input.span11 { 398 | width: 1056px; 399 | } 400 | input.span10, 401 | textarea.span10, 402 | .uneditable-input.span10 { 403 | width: 956px; 404 | } 405 | input.span9, 406 | textarea.span9, 407 | .uneditable-input.span9 { 408 | width: 856px; 409 | } 410 | input.span8, 411 | textarea.span8, 412 | .uneditable-input.span8 { 413 | width: 756px; 414 | } 415 | input.span7, 416 | textarea.span7, 417 | .uneditable-input.span7 { 418 | width: 656px; 419 | } 420 | input.span6, 421 | textarea.span6, 422 | .uneditable-input.span6 { 423 | width: 556px; 424 | } 425 | input.span5, 426 | textarea.span5, 427 | .uneditable-input.span5 { 428 | width: 456px; 429 | } 430 | input.span4, 431 | textarea.span4, 432 | .uneditable-input.span4 { 433 | width: 356px; 434 | } 435 | input.span3, 436 | textarea.span3, 437 | .uneditable-input.span3 { 438 | width: 256px; 439 | } 440 | input.span2, 441 | textarea.span2, 442 | .uneditable-input.span2 { 443 | width: 156px; 444 | } 445 | input.span1, 446 | textarea.span1, 447 | .uneditable-input.span1 { 448 | width: 56px; 449 | } 450 | .thumbnails { 451 | margin-left: -30px; 452 | } 453 | .thumbnails > li { 454 | margin-left: 30px; 455 | } 456 | .row-fluid .thumbnails { 457 | margin-left: 0; 458 | } 459 | } 460 | 461 | @media (min-width: 768px) and (max-width: 979px) { 462 | .row { 463 | margin-left: -20px; 464 | *zoom: 1; 465 | } 466 | .row:before, 467 | .row:after { 468 | display: table; 469 | line-height: 0; 470 | content: ""; 471 | } 472 | .row:after { 473 | clear: both; 474 | } 475 | [class*="span"] { 476 | float: left; 477 | min-height: 1px; 478 | margin-left: 20px; 479 | } 480 | .container, 481 | .navbar-static-top .container, 482 | .navbar-fixed-top .container, 483 | .navbar-fixed-bottom .container { 484 | width: 724px; 485 | } 486 | .span12 { 487 | width: 724px; 488 | } 489 | .span11 { 490 | width: 662px; 491 | } 492 | .span10 { 493 | width: 600px; 494 | } 495 | .span9 { 496 | width: 538px; 497 | } 498 | .span8 { 499 | width: 476px; 500 | } 501 | .span7 { 502 | width: 414px; 503 | } 504 | .span6 { 505 | width: 352px; 506 | } 507 | .span5 { 508 | width: 290px; 509 | } 510 | .span4 { 511 | width: 228px; 512 | } 513 | .span3 { 514 | width: 166px; 515 | } 516 | .span2 { 517 | width: 104px; 518 | } 519 | .span1 { 520 | width: 42px; 521 | } 522 | .offset12 { 523 | margin-left: 764px; 524 | } 525 | .offset11 { 526 | margin-left: 702px; 527 | } 528 | .offset10 { 529 | margin-left: 640px; 530 | } 531 | .offset9 { 532 | margin-left: 578px; 533 | } 534 | .offset8 { 535 | margin-left: 516px; 536 | } 537 | .offset7 { 538 | margin-left: 454px; 539 | } 540 | .offset6 { 541 | margin-left: 392px; 542 | } 543 | .offset5 { 544 | margin-left: 330px; 545 | } 546 | .offset4 { 547 | margin-left: 268px; 548 | } 549 | .offset3 { 550 | margin-left: 206px; 551 | } 552 | .offset2 { 553 | margin-left: 144px; 554 | } 555 | .offset1 { 556 | margin-left: 82px; 557 | } 558 | .row-fluid { 559 | width: 100%; 560 | *zoom: 1; 561 | } 562 | .row-fluid:before, 563 | .row-fluid:after { 564 | display: table; 565 | line-height: 0; 566 | content: ""; 567 | } 568 | .row-fluid:after { 569 | clear: both; 570 | } 571 | .row-fluid [class*="span"] { 572 | display: block; 573 | float: left; 574 | width: 100%; 575 | min-height: 30px; 576 | margin-left: 2.7624309392265194%; 577 | *margin-left: 2.709239449864817%; 578 | -webkit-box-sizing: border-box; 579 | -moz-box-sizing: border-box; 580 | box-sizing: border-box; 581 | } 582 | .row-fluid [class*="span"]:first-child { 583 | margin-left: 0; 584 | } 585 | .row-fluid .controls-row [class*="span"] + [class*="span"] { 586 | margin-left: 2.7624309392265194%; 587 | } 588 | .row-fluid .span12 { 589 | width: 100%; 590 | *width: 99.94680851063829%; 591 | } 592 | .row-fluid .span11 { 593 | width: 91.43646408839778%; 594 | *width: 91.38327259903608%; 595 | } 596 | .row-fluid .span10 { 597 | width: 82.87292817679558%; 598 | *width: 82.81973668743387%; 599 | } 600 | .row-fluid .span9 { 601 | width: 74.30939226519337%; 602 | *width: 74.25620077583166%; 603 | } 604 | .row-fluid .span8 { 605 | width: 65.74585635359117%; 606 | *width: 65.69266486422946%; 607 | } 608 | .row-fluid .span7 { 609 | width: 57.18232044198895%; 610 | *width: 57.12912895262725%; 611 | } 612 | .row-fluid .span6 { 613 | width: 48.61878453038674%; 614 | *width: 48.56559304102504%; 615 | } 616 | .row-fluid .span5 { 617 | width: 40.05524861878453%; 618 | *width: 40.00205712942283%; 619 | } 620 | .row-fluid .span4 { 621 | width: 31.491712707182323%; 622 | *width: 31.43852121782062%; 623 | } 624 | .row-fluid .span3 { 625 | width: 22.92817679558011%; 626 | *width: 22.87498530621841%; 627 | } 628 | .row-fluid .span2 { 629 | width: 14.3646408839779%; 630 | *width: 14.311449394616199%; 631 | } 632 | .row-fluid .span1 { 633 | width: 5.801104972375691%; 634 | *width: 5.747913483013988%; 635 | } 636 | .row-fluid .offset12 { 637 | margin-left: 105.52486187845304%; 638 | *margin-left: 105.41847889972962%; 639 | } 640 | .row-fluid .offset12:first-child { 641 | margin-left: 102.76243093922652%; 642 | *margin-left: 102.6560479605031%; 643 | } 644 | .row-fluid .offset11 { 645 | margin-left: 96.96132596685082%; 646 | *margin-left: 96.8549429881274%; 647 | } 648 | .row-fluid .offset11:first-child { 649 | margin-left: 94.1988950276243%; 650 | *margin-left: 94.09251204890089%; 651 | } 652 | .row-fluid .offset10 { 653 | margin-left: 88.39779005524862%; 654 | *margin-left: 88.2914070765252%; 655 | } 656 | .row-fluid .offset10:first-child { 657 | margin-left: 85.6353591160221%; 658 | *margin-left: 85.52897613729868%; 659 | } 660 | .row-fluid .offset9 { 661 | margin-left: 79.8342541436464%; 662 | *margin-left: 79.72787116492299%; 663 | } 664 | .row-fluid .offset9:first-child { 665 | margin-left: 77.07182320441989%; 666 | *margin-left: 76.96544022569647%; 667 | } 668 | .row-fluid .offset8 { 669 | margin-left: 71.2707182320442%; 670 | *margin-left: 71.16433525332079%; 671 | } 672 | .row-fluid .offset8:first-child { 673 | margin-left: 68.50828729281768%; 674 | *margin-left: 68.40190431409427%; 675 | } 676 | .row-fluid .offset7 { 677 | margin-left: 62.70718232044199%; 678 | *margin-left: 62.600799341718584%; 679 | } 680 | .row-fluid .offset7:first-child { 681 | margin-left: 59.94475138121547%; 682 | *margin-left: 59.838368402492065%; 683 | } 684 | .row-fluid .offset6 { 685 | margin-left: 54.14364640883978%; 686 | *margin-left: 54.037263430116376%; 687 | } 688 | .row-fluid .offset6:first-child { 689 | margin-left: 51.38121546961326%; 690 | *margin-left: 51.27483249088986%; 691 | } 692 | .row-fluid .offset5 { 693 | margin-left: 45.58011049723757%; 694 | *margin-left: 45.47372751851417%; 695 | } 696 | .row-fluid .offset5:first-child { 697 | margin-left: 42.81767955801105%; 698 | *margin-left: 42.71129657928765%; 699 | } 700 | .row-fluid .offset4 { 701 | margin-left: 37.01657458563536%; 702 | *margin-left: 36.91019160691196%; 703 | } 704 | .row-fluid .offset4:first-child { 705 | margin-left: 34.25414364640884%; 706 | *margin-left: 34.14776066768544%; 707 | } 708 | .row-fluid .offset3 { 709 | margin-left: 28.45303867403315%; 710 | *margin-left: 28.346655695309746%; 711 | } 712 | .row-fluid .offset3:first-child { 713 | margin-left: 25.69060773480663%; 714 | *margin-left: 25.584224756083227%; 715 | } 716 | .row-fluid .offset2 { 717 | margin-left: 19.88950276243094%; 718 | *margin-left: 19.783119783707537%; 719 | } 720 | .row-fluid .offset2:first-child { 721 | margin-left: 17.12707182320442%; 722 | *margin-left: 17.02068884448102%; 723 | } 724 | .row-fluid .offset1 { 725 | margin-left: 11.32596685082873%; 726 | *margin-left: 11.219583872105325%; 727 | } 728 | .row-fluid .offset1:first-child { 729 | margin-left: 8.56353591160221%; 730 | *margin-left: 8.457152932878806%; 731 | } 732 | input, 733 | textarea, 734 | .uneditable-input { 735 | margin-left: 0; 736 | } 737 | .controls-row [class*="span"] + [class*="span"] { 738 | margin-left: 20px; 739 | } 740 | input.span12, 741 | textarea.span12, 742 | .uneditable-input.span12 { 743 | width: 710px; 744 | } 745 | input.span11, 746 | textarea.span11, 747 | .uneditable-input.span11 { 748 | width: 648px; 749 | } 750 | input.span10, 751 | textarea.span10, 752 | .uneditable-input.span10 { 753 | width: 586px; 754 | } 755 | input.span9, 756 | textarea.span9, 757 | .uneditable-input.span9 { 758 | width: 524px; 759 | } 760 | input.span8, 761 | textarea.span8, 762 | .uneditable-input.span8 { 763 | width: 462px; 764 | } 765 | input.span7, 766 | textarea.span7, 767 | .uneditable-input.span7 { 768 | width: 400px; 769 | } 770 | input.span6, 771 | textarea.span6, 772 | .uneditable-input.span6 { 773 | width: 338px; 774 | } 775 | input.span5, 776 | textarea.span5, 777 | .uneditable-input.span5 { 778 | width: 276px; 779 | } 780 | input.span4, 781 | textarea.span4, 782 | .uneditable-input.span4 { 783 | width: 214px; 784 | } 785 | input.span3, 786 | textarea.span3, 787 | .uneditable-input.span3 { 788 | width: 152px; 789 | } 790 | input.span2, 791 | textarea.span2, 792 | .uneditable-input.span2 { 793 | width: 90px; 794 | } 795 | input.span1, 796 | textarea.span1, 797 | .uneditable-input.span1 { 798 | width: 28px; 799 | } 800 | } 801 | 802 | @media (max-width: 767px) { 803 | body { 804 | padding-right: 20px; 805 | padding-left: 20px; 806 | } 807 | .navbar-fixed-top, 808 | .navbar-fixed-bottom, 809 | .navbar-static-top { 810 | margin-right: -20px; 811 | margin-left: -20px; 812 | } 813 | .container-fluid { 814 | padding: 0; 815 | } 816 | .dl-horizontal dt { 817 | float: none; 818 | width: auto; 819 | clear: none; 820 | text-align: left; 821 | } 822 | .dl-horizontal dd { 823 | margin-left: 0; 824 | } 825 | .container { 826 | width: auto; 827 | } 828 | .row-fluid { 829 | width: 100%; 830 | } 831 | .row, 832 | .thumbnails { 833 | margin-left: 0; 834 | } 835 | .thumbnails > li { 836 | float: none; 837 | margin-left: 0; 838 | } 839 | [class*="span"], 840 | .uneditable-input[class*="span"], 841 | .row-fluid [class*="span"] { 842 | display: block; 843 | float: none; 844 | width: 100%; 845 | margin-left: 0; 846 | -webkit-box-sizing: border-box; 847 | -moz-box-sizing: border-box; 848 | box-sizing: border-box; 849 | } 850 | .span12, 851 | .row-fluid .span12 { 852 | width: 100%; 853 | -webkit-box-sizing: border-box; 854 | -moz-box-sizing: border-box; 855 | box-sizing: border-box; 856 | } 857 | .row-fluid [class*="offset"]:first-child { 858 | margin-left: 0; 859 | } 860 | .input-large, 861 | .input-xlarge, 862 | .input-xxlarge, 863 | input[class*="span"], 864 | select[class*="span"], 865 | textarea[class*="span"], 866 | .uneditable-input { 867 | display: block; 868 | width: 100%; 869 | min-height: 30px; 870 | -webkit-box-sizing: border-box; 871 | -moz-box-sizing: border-box; 872 | box-sizing: border-box; 873 | } 874 | .input-prepend input, 875 | .input-append input, 876 | .input-prepend input[class*="span"], 877 | .input-append input[class*="span"] { 878 | display: inline-block; 879 | width: auto; 880 | } 881 | .controls-row [class*="span"] + [class*="span"] { 882 | margin-left: 0; 883 | } 884 | .modal { 885 | position: fixed; 886 | top: 20px; 887 | right: 20px; 888 | left: 20px; 889 | width: auto; 890 | margin: 0; 891 | } 892 | .modal.fade { 893 | top: -100px; 894 | } 895 | .modal.fade.in { 896 | top: 20px; 897 | } 898 | } 899 | 900 | @media (max-width: 480px) { 901 | .nav-collapse { 902 | -webkit-transform: translate3d(0, 0, 0); 903 | } 904 | .page-header h1 small { 905 | display: block; 906 | line-height: 20px; 907 | } 908 | input[type="checkbox"], 909 | input[type="radio"] { 910 | border: 1px solid #ccc; 911 | } 912 | .form-horizontal .control-label { 913 | float: none; 914 | width: auto; 915 | padding-top: 0; 916 | text-align: left; 917 | } 918 | .form-horizontal .controls { 919 | margin-left: 0; 920 | } 921 | .form-horizontal .control-list { 922 | padding-top: 0; 923 | } 924 | .form-horizontal .form-actions { 925 | padding-right: 10px; 926 | padding-left: 10px; 927 | } 928 | .media .pull-left, 929 | .media .pull-right { 930 | display: block; 931 | float: none; 932 | margin-bottom: 10px; 933 | } 934 | .media-object { 935 | margin-right: 0; 936 | margin-left: 0; 937 | } 938 | .modal { 939 | top: 10px; 940 | right: 10px; 941 | left: 10px; 942 | } 943 | .modal-header .close { 944 | padding: 10px; 945 | margin: -10px; 946 | } 947 | .carousel-caption { 948 | position: static; 949 | } 950 | } 951 | 952 | @media (max-width: 979px) { 953 | body { 954 | padding-top: 0; 955 | } 956 | .navbar-fixed-top, 957 | .navbar-fixed-bottom { 958 | position: static; 959 | } 960 | .navbar-fixed-top { 961 | margin-bottom: 20px; 962 | } 963 | .navbar-fixed-bottom { 964 | margin-top: 20px; 965 | } 966 | .navbar-fixed-top .navbar-inner, 967 | .navbar-fixed-bottom .navbar-inner { 968 | padding: 5px; 969 | } 970 | .navbar .container { 971 | width: auto; 972 | padding: 0; 973 | } 974 | .navbar .brand { 975 | padding-right: 10px; 976 | padding-left: 10px; 977 | margin: 0 0 0 -5px; 978 | } 979 | .nav-collapse { 980 | clear: both; 981 | } 982 | .nav-collapse .nav { 983 | float: none; 984 | margin: 0 0 10px; 985 | } 986 | .nav-collapse .nav > li { 987 | float: none; 988 | } 989 | .nav-collapse .nav > li > a { 990 | margin-bottom: 2px; 991 | } 992 | .nav-collapse .nav > .divider-vertical { 993 | display: none; 994 | } 995 | .nav-collapse .nav .nav-header { 996 | color: #777777; 997 | text-shadow: none; 998 | } 999 | .nav-collapse .nav > li > a, 1000 | .nav-collapse .dropdown-menu a { 1001 | padding: 9px 15px; 1002 | font-weight: bold; 1003 | color: #777777; 1004 | -webkit-border-radius: 3px; 1005 | -moz-border-radius: 3px; 1006 | border-radius: 3px; 1007 | } 1008 | .nav-collapse .btn { 1009 | padding: 4px 10px 4px; 1010 | font-weight: normal; 1011 | -webkit-border-radius: 4px; 1012 | -moz-border-radius: 4px; 1013 | border-radius: 4px; 1014 | } 1015 | .nav-collapse .dropdown-menu li + li a { 1016 | margin-bottom: 2px; 1017 | } 1018 | .nav-collapse .nav > li > a:hover, 1019 | .nav-collapse .nav > li > a:focus, 1020 | .nav-collapse .dropdown-menu a:hover, 1021 | .nav-collapse .dropdown-menu a:focus { 1022 | background-color: #f2f2f2; 1023 | } 1024 | .navbar-inverse .nav-collapse .nav > li > a, 1025 | .navbar-inverse .nav-collapse .dropdown-menu a { 1026 | color: #999999; 1027 | } 1028 | .navbar-inverse .nav-collapse .nav > li > a:hover, 1029 | .navbar-inverse .nav-collapse .nav > li > a:focus, 1030 | .navbar-inverse .nav-collapse .dropdown-menu a:hover, 1031 | .navbar-inverse .nav-collapse .dropdown-menu a:focus { 1032 | background-color: #111111; 1033 | } 1034 | .nav-collapse.in .btn-group { 1035 | padding: 0; 1036 | margin-top: 5px; 1037 | } 1038 | .nav-collapse .dropdown-menu { 1039 | position: static; 1040 | top: auto; 1041 | left: auto; 1042 | display: none; 1043 | float: none; 1044 | max-width: none; 1045 | padding: 0; 1046 | margin: 0 15px; 1047 | background-color: transparent; 1048 | border: none; 1049 | -webkit-border-radius: 0; 1050 | -moz-border-radius: 0; 1051 | border-radius: 0; 1052 | -webkit-box-shadow: none; 1053 | -moz-box-shadow: none; 1054 | box-shadow: none; 1055 | } 1056 | .nav-collapse .open > .dropdown-menu { 1057 | display: block; 1058 | } 1059 | .nav-collapse .dropdown-menu:before, 1060 | .nav-collapse .dropdown-menu:after { 1061 | display: none; 1062 | } 1063 | .nav-collapse .dropdown-menu .divider { 1064 | display: none; 1065 | } 1066 | .nav-collapse .nav > li > .dropdown-menu:before, 1067 | .nav-collapse .nav > li > .dropdown-menu:after { 1068 | display: none; 1069 | } 1070 | .nav-collapse .navbar-form, 1071 | .nav-collapse .navbar-search { 1072 | float: none; 1073 | padding: 10px 15px; 1074 | margin: 10px 0; 1075 | border-top: 1px solid #f2f2f2; 1076 | border-bottom: 1px solid #f2f2f2; 1077 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1078 | -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1079 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); 1080 | } 1081 | .navbar-inverse .nav-collapse .navbar-form, 1082 | .navbar-inverse .nav-collapse .navbar-search { 1083 | border-top-color: #111111; 1084 | border-bottom-color: #111111; 1085 | } 1086 | .navbar .nav-collapse .nav.pull-right { 1087 | float: none; 1088 | margin-left: 0; 1089 | } 1090 | .nav-collapse, 1091 | .nav-collapse.collapse { 1092 | height: 0; 1093 | overflow: hidden; 1094 | } 1095 | .navbar .btn-navbar { 1096 | display: block; 1097 | } 1098 | .navbar-static .navbar-inner { 1099 | padding-right: 10px; 1100 | padding-left: 10px; 1101 | } 1102 | } 1103 | 1104 | @media (min-width: 980px) { 1105 | .nav-collapse.collapse { 1106 | height: auto !important; 1107 | overflow: visible !important; 1108 | } 1109 | } 1110 | -------------------------------------------------------------------------------- /static/css/docs.css: -------------------------------------------------------------------------------- 1 | /* Add additional stylesheets below 2 | -------------------------------------------------- */ 3 | /* 4 | Bootstrap's documentation styles 5 | Special styles for presenting Bootstrap's documentation and examples 6 | */ 7 | 8 | 9 | 10 | /* Body and structure 11 | -------------------------------------------------- */ 12 | 13 | body { 14 | position: relative; 15 | padding-top: 40px; 16 | } 17 | 18 | /* Code in headings */ 19 | h3 code { 20 | font-size: 14px; 21 | font-weight: normal; 22 | } 23 | 24 | 25 | 26 | /* Tweak navbar brand link to be super sleek 27 | -------------------------------------------------- */ 28 | 29 | body > .navbar { 30 | font-size: 13px; 31 | } 32 | 33 | /* Change the docs' brand */ 34 | body > .navbar .brand { 35 | padding-right: 0; 36 | padding-left: 0; 37 | margin-left: 20px; 38 | float: right; 39 | font-weight: bold; 40 | color: #000; 41 | text-shadow: 0 1px 0 rgba(255,255,255,.1), 0 0 30px rgba(255,255,255,.125); 42 | -webkit-transition: all .2s linear; 43 | -moz-transition: all .2s linear; 44 | transition: all .2s linear; 45 | } 46 | body > .navbar .brand:hover { 47 | text-decoration: none; 48 | text-shadow: 0 1px 0 rgba(255,255,255,.1), 0 0 30px rgba(255,255,255,.4); 49 | } 50 | 51 | 52 | /* Sections 53 | -------------------------------------------------- */ 54 | 55 | /* padding for in-page bookmarks and fixed navbar */ 56 | section { 57 | padding-top: 30px; 58 | } 59 | section > .page-header, 60 | section > .lead { 61 | color: #5a5a5a; 62 | } 63 | section > ul li { 64 | margin-bottom: 5px; 65 | } 66 | 67 | /* Separators (hr) */ 68 | .bs-docs-separator { 69 | margin: 40px 0 39px; 70 | } 71 | 72 | /* Faded out hr */ 73 | hr.soften { 74 | height: 1px; 75 | margin: 70px 0; 76 | background-image: -webkit-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); 77 | background-image: -moz-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); 78 | background-image: -ms-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); 79 | background-image: -o-linear-gradient(left, rgba(0,0,0,0), rgba(0,0,0,.1), rgba(0,0,0,0)); 80 | border: 0; 81 | } 82 | 83 | 84 | 85 | /* Jumbotrons 86 | -------------------------------------------------- */ 87 | 88 | /* Base class 89 | ------------------------- */ 90 | .jumbotron { 91 | position: relative; 92 | padding: 40px 0; 93 | color: #fff; 94 | text-align: center; 95 | text-shadow: 0 1px 3px rgba(0,0,0,.4), 0 0 30px rgba(0,0,0,.075); 96 | background: #020031; /* Old browsers */ 97 | background: -moz-linear-gradient(45deg, #020031 0%, #6d3353 100%); /* FF3.6+ */ 98 | background: -webkit-gradient(linear, left bottom, right top, color-stop(0%,#020031), color-stop(100%,#6d3353)); /* Chrome,Safari4+ */ 99 | background: -webkit-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* Chrome10+,Safari5.1+ */ 100 | background: -o-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* Opera 11.10+ */ 101 | background: -ms-linear-gradient(45deg, #020031 0%,#6d3353 100%); /* IE10+ */ 102 | background: linear-gradient(45deg, #020031 0%,#6d3353 100%); /* W3C */ 103 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#020031', endColorstr='#6d3353',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ 104 | -webkit-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); 105 | -moz-box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); 106 | box-shadow: inset 0 3px 7px rgba(0,0,0,.2), inset 0 -3px 7px rgba(0,0,0,.2); 107 | } 108 | .jumbotron h1 { 109 | font-size: 80px; 110 | font-weight: bold; 111 | letter-spacing: -1px; 112 | line-height: 1; 113 | } 114 | .jumbotron p { 115 | font-size: 24px; 116 | font-weight: 300; 117 | line-height: 1.25; 118 | margin-bottom: 30px; 119 | } 120 | 121 | /* Link styles (used on .masthead-links as well) */ 122 | .jumbotron a { 123 | color: #fff; 124 | color: rgba(255,255,255,.5); 125 | -webkit-transition: all .2s ease-in-out; 126 | -moz-transition: all .2s ease-in-out; 127 | transition: all .2s ease-in-out; 128 | } 129 | .jumbotron a:hover { 130 | color: #fff; 131 | text-shadow: 0 0 10px rgba(255,255,255,.25); 132 | } 133 | 134 | /* Download button */ 135 | .masthead .btn { 136 | padding: 19px 24px; 137 | font-size: 24px; 138 | font-weight: 200; 139 | color: #fff; /* redeclare to override the `.jumbotron a` */ 140 | border: 0; 141 | -webkit-border-radius: 6px; 142 | -moz-border-radius: 6px; 143 | border-radius: 6px; 144 | -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 145 | -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 146 | box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 147 | -webkit-transition: none; 148 | -moz-transition: none; 149 | transition: none; 150 | } 151 | .masthead .btn:hover { 152 | -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 153 | -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 154 | box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 5px rgba(0,0,0,.25); 155 | } 156 | .masthead .btn:active { 157 | -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); 158 | -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); 159 | box-shadow: inset 0 2px 4px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.1); 160 | } 161 | 162 | 163 | /* Pattern overlay 164 | ------------------------- */ 165 | .jumbotron .container { 166 | position: relative; 167 | z-index: 2; 168 | } 169 | .jumbotron:after { 170 | content: ''; 171 | display: block; 172 | position: absolute; 173 | top: 0; 174 | right: 0; 175 | bottom: 0; 176 | left: 0; 177 | background: url(../img/bs-docs-masthead-pattern.png) repeat center center; 178 | opacity: .4; 179 | } 180 | @media 181 | only screen and (-webkit-min-device-pixel-ratio: 2), 182 | only screen and ( min--moz-device-pixel-ratio: 2), 183 | only screen and ( -o-min-device-pixel-ratio: 2/1) { 184 | 185 | .jumbotron:after { 186 | background-size: 150px 150px; 187 | } 188 | 189 | } 190 | 191 | /* Masthead (docs home) 192 | ------------------------- */ 193 | .masthead { 194 | padding: 70px 0 80px; 195 | margin-bottom: 0; 196 | color: #fff; 197 | } 198 | .masthead h1 { 199 | font-size: 120px; 200 | line-height: 1; 201 | letter-spacing: -2px; 202 | } 203 | .masthead p { 204 | font-size: 40px; 205 | font-weight: 200; 206 | line-height: 1.25; 207 | } 208 | 209 | /* Textual links in masthead */ 210 | .masthead-links { 211 | margin: 0; 212 | list-style: none; 213 | } 214 | .masthead-links li { 215 | display: inline; 216 | padding: 0 10px; 217 | color: rgba(255,255,255,.25); 218 | } 219 | 220 | /* Social proof buttons from GitHub & Twitter */ 221 | .bs-docs-social { 222 | padding: 15px 0; 223 | text-align: center; 224 | background-color: #f5f5f5; 225 | border-top: 1px solid #fff; 226 | border-bottom: 1px solid #ddd; 227 | } 228 | 229 | /* Quick links on Home */ 230 | .bs-docs-social-buttons { 231 | margin-left: 0; 232 | margin-bottom: 0; 233 | padding-left: 0; 234 | list-style: none; 235 | } 236 | .bs-docs-social-buttons li { 237 | display: inline-block; 238 | padding: 5px 8px; 239 | line-height: 1; 240 | *display: inline; 241 | *zoom: 1; 242 | } 243 | 244 | /* Subhead (other pages) 245 | ------------------------- */ 246 | .subhead { 247 | text-align: left; 248 | border-bottom: 1px solid #ddd; 249 | } 250 | .subhead h1 { 251 | font-size: 60px; 252 | } 253 | .subhead p { 254 | margin-bottom: 20px; 255 | } 256 | .subhead .navbar { 257 | display: none; 258 | } 259 | 260 | 261 | 262 | /* Marketing section of Overview 263 | -------------------------------------------------- */ 264 | 265 | .marketing { 266 | text-align: center; 267 | color: #5a5a5a; 268 | } 269 | .marketing h1 { 270 | margin: 60px 0 10px; 271 | font-size: 60px; 272 | font-weight: 200; 273 | line-height: 1; 274 | letter-spacing: -1px; 275 | } 276 | .marketing h2 { 277 | font-weight: 200; 278 | margin-bottom: 5px; 279 | } 280 | .marketing p { 281 | font-size: 16px; 282 | line-height: 1.5; 283 | } 284 | .marketing .marketing-byline { 285 | margin-bottom: 40px; 286 | font-size: 20px; 287 | font-weight: 300; 288 | line-height: 1.25; 289 | color: #999; 290 | } 291 | .marketing-img { 292 | display: block; 293 | margin: 0 auto 30px; 294 | max-height: 145px; 295 | } 296 | 297 | 298 | 299 | /* Footer 300 | -------------------------------------------------- */ 301 | 302 | .footer { 303 | text-align: center; 304 | padding: 30px 0; 305 | margin-top: 70px; 306 | border-top: 1px solid #e5e5e5; 307 | background-color: #f5f5f5; 308 | } 309 | .footer p { 310 | margin-bottom: 0; 311 | color: #777; 312 | } 313 | .footer-links { 314 | margin: 10px 0; 315 | } 316 | .footer-links li { 317 | display: inline; 318 | padding: 0 2px; 319 | } 320 | .footer-links li:first-child { 321 | padding-left: 0; 322 | } 323 | 324 | 325 | 326 | /* Special grid styles 327 | -------------------------------------------------- */ 328 | 329 | .show-grid { 330 | margin-top: 10px; 331 | margin-bottom: 20px; 332 | } 333 | .show-grid [class*="span"] { 334 | background-color: #eee; 335 | text-align: center; 336 | -webkit-border-radius: 3px; 337 | -moz-border-radius: 3px; 338 | border-radius: 3px; 339 | min-height: 40px; 340 | line-height: 40px; 341 | } 342 | .show-grid [class*="span"]:hover { 343 | background-color: #ddd; 344 | } 345 | .show-grid .show-grid { 346 | margin-top: 0; 347 | margin-bottom: 0; 348 | } 349 | .show-grid .show-grid [class*="span"] { 350 | margin-top: 5px; 351 | } 352 | .show-grid [class*="span"] [class*="span"] { 353 | background-color: #ccc; 354 | } 355 | .show-grid [class*="span"] [class*="span"] [class*="span"] { 356 | background-color: #999; 357 | } 358 | 359 | 360 | 361 | /* Mini layout previews 362 | -------------------------------------------------- */ 363 | .mini-layout { 364 | border: 1px solid #ddd; 365 | -webkit-border-radius: 6px; 366 | -moz-border-radius: 6px; 367 | border-radius: 6px; 368 | -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.075); 369 | -moz-box-shadow: 0 1px 2px rgba(0,0,0,.075); 370 | box-shadow: 0 1px 2px rgba(0,0,0,.075); 371 | } 372 | .mini-layout, 373 | .mini-layout .mini-layout-body, 374 | .mini-layout.fluid .mini-layout-sidebar { 375 | height: 300px; 376 | } 377 | .mini-layout { 378 | margin-bottom: 20px; 379 | padding: 9px; 380 | } 381 | .mini-layout div { 382 | -webkit-border-radius: 3px; 383 | -moz-border-radius: 3px; 384 | border-radius: 3px; 385 | } 386 | .mini-layout .mini-layout-body { 387 | background-color: #dceaf4; 388 | margin: 0 auto; 389 | width: 70%; 390 | } 391 | .mini-layout.fluid .mini-layout-sidebar, 392 | .mini-layout.fluid .mini-layout-header, 393 | .mini-layout.fluid .mini-layout-body { 394 | float: left; 395 | } 396 | .mini-layout.fluid .mini-layout-sidebar { 397 | background-color: #bbd8e9; 398 | width: 20%; 399 | } 400 | .mini-layout.fluid .mini-layout-body { 401 | width: 77.5%; 402 | margin-left: 2.5%; 403 | } 404 | 405 | 406 | 407 | /* Download page 408 | -------------------------------------------------- */ 409 | 410 | .download .page-header { 411 | margin-top: 36px; 412 | } 413 | .page-header .toggle-all { 414 | margin-top: 5px; 415 | } 416 | 417 | /* Space out h3s when following a section */ 418 | .download h3 { 419 | margin-bottom: 5px; 420 | } 421 | .download-builder input + h3, 422 | .download-builder .checkbox + h3 { 423 | margin-top: 9px; 424 | } 425 | 426 | /* Fields for variables */ 427 | .download-builder input[type=text] { 428 | margin-bottom: 9px; 429 | font-family: Menlo, Monaco, "Courier New", monospace; 430 | font-size: 12px; 431 | color: #d14; 432 | } 433 | .download-builder input[type=text]:focus { 434 | background-color: #fff; 435 | } 436 | 437 | /* Custom, larger checkbox labels */ 438 | .download .checkbox { 439 | padding: 6px 10px 6px 25px; 440 | font-size: 13px; 441 | line-height: 18px; 442 | color: #555; 443 | background-color: #f9f9f9; 444 | -webkit-border-radius: 3px; 445 | -moz-border-radius: 3px; 446 | border-radius: 3px; 447 | cursor: pointer; 448 | } 449 | .download .checkbox:hover { 450 | color: #333; 451 | background-color: #f5f5f5; 452 | } 453 | .download .checkbox small { 454 | font-size: 12px; 455 | color: #777; 456 | } 457 | 458 | /* Variables section */ 459 | #variables label { 460 | margin-bottom: 0; 461 | } 462 | 463 | /* Giant download button */ 464 | .download-btn { 465 | margin: 36px 0 108px; 466 | } 467 | #download p, 468 | #download h4 { 469 | max-width: 50%; 470 | margin: 0 auto; 471 | color: #999; 472 | text-align: center; 473 | } 474 | #download h4 { 475 | margin-bottom: 0; 476 | } 477 | #download p { 478 | margin-bottom: 18px; 479 | } 480 | .download-btn .btn { 481 | display: block; 482 | width: auto; 483 | padding: 19px 24px; 484 | margin-bottom: 27px; 485 | font-size: 30px; 486 | line-height: 1; 487 | text-align: center; 488 | -webkit-border-radius: 6px; 489 | -moz-border-radius: 6px; 490 | border-radius: 6px; 491 | } 492 | 493 | 494 | 495 | /* Misc 496 | -------------------------------------------------- */ 497 | 498 | /* Make tables spaced out a bit more */ 499 | h2 + table, 500 | h3 + table, 501 | h4 + table, 502 | h2 + .row { 503 | margin-top: 5px; 504 | } 505 | 506 | /* Example sites showcase */ 507 | .example-sites { 508 | xmargin-left: 20px; 509 | } 510 | .example-sites img { 511 | max-width: 100%; 512 | margin: 0 auto; 513 | } 514 | 515 | .scrollspy-example { 516 | height: 200px; 517 | overflow: auto; 518 | position: relative; 519 | } 520 | 521 | 522 | /* Fake the :focus state to demo it */ 523 | .focused { 524 | border-color: rgba(82,168,236,.8); 525 | -webkit-box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); 526 | -moz-box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); 527 | box-shadow: inset 0 1px 3px rgba(0,0,0,.1), 0 0 8px rgba(82,168,236,.6); 528 | outline: 0; 529 | } 530 | 531 | /* For input sizes, make them display block */ 532 | .docs-input-sizes select, 533 | .docs-input-sizes input[type=text] { 534 | display: block; 535 | margin-bottom: 9px; 536 | } 537 | 538 | /* Icons 539 | ------------------------- */ 540 | .the-icons { 541 | margin-left: 0; 542 | list-style: none; 543 | } 544 | .the-icons li { 545 | float: left; 546 | width: 25%; 547 | line-height: 25px; 548 | } 549 | .the-icons i:hover { 550 | background-color: rgba(255,0,0,.25); 551 | } 552 | 553 | /* Example page 554 | ------------------------- */ 555 | .bootstrap-examples h4 { 556 | margin: 10px 0 5px; 557 | } 558 | .bootstrap-examples p { 559 | font-size: 13px; 560 | line-height: 18px; 561 | } 562 | .bootstrap-examples .thumbnail { 563 | margin-bottom: 9px; 564 | background-color: #fff; 565 | } 566 | 567 | 568 | 569 | /* Bootstrap code examples 570 | -------------------------------------------------- */ 571 | 572 | /* Base class */ 573 | .bs-docs-example { 574 | position: relative; 575 | margin: 15px 0; 576 | padding: 39px 19px 14px; 577 | *padding-top: 19px; 578 | background-color: #fff; 579 | border: 1px solid #ddd; 580 | -webkit-border-radius: 4px; 581 | -moz-border-radius: 4px; 582 | border-radius: 4px; 583 | } 584 | 585 | /* Echo out a label for the example */ 586 | .bs-docs-example:after { 587 | content: "Example"; 588 | position: absolute; 589 | top: -1px; 590 | left: -1px; 591 | padding: 3px 7px; 592 | font-size: 12px; 593 | font-weight: bold; 594 | background-color: #f5f5f5; 595 | border: 1px solid #ddd; 596 | color: #9da0a4; 597 | -webkit-border-radius: 4px 0 4px 0; 598 | -moz-border-radius: 4px 0 4px 0; 599 | border-radius: 4px 0 4px 0; 600 | } 601 | 602 | /* Remove spacing between an example and it's code */ 603 | .bs-docs-example + .prettyprint { 604 | margin-top: -20px; 605 | padding-top: 15px; 606 | } 607 | 608 | /* Tweak examples 609 | ------------------------- */ 610 | .bs-docs-example > p:last-child { 611 | margin-bottom: 0; 612 | } 613 | .bs-docs-example .table, 614 | .bs-docs-example .progress, 615 | .bs-docs-example .well, 616 | .bs-docs-example .alert, 617 | .bs-docs-example .hero-unit, 618 | .bs-docs-example .pagination, 619 | .bs-docs-example .navbar, 620 | .bs-docs-example > .nav, 621 | .bs-docs-example blockquote { 622 | margin-bottom: 5px; 623 | } 624 | .bs-docs-example .pagination { 625 | margin-top: 0; 626 | } 627 | .bs-navbar-top-example, 628 | .bs-navbar-bottom-example { 629 | z-index: 1; 630 | padding: 0; 631 | height: 90px; 632 | overflow: hidden; /* cut the drop shadows off */ 633 | } 634 | .bs-navbar-top-example .navbar-fixed-top, 635 | .bs-navbar-bottom-example .navbar-fixed-bottom { 636 | margin-left: 0; 637 | margin-right: 0; 638 | } 639 | .bs-navbar-top-example { 640 | -webkit-border-radius: 0 0 4px 4px; 641 | -moz-border-radius: 0 0 4px 4px; 642 | border-radius: 0 0 4px 4px; 643 | } 644 | .bs-navbar-top-example:after { 645 | top: auto; 646 | bottom: -1px; 647 | -webkit-border-radius: 0 4px 0 4px; 648 | -moz-border-radius: 0 4px 0 4px; 649 | border-radius: 0 4px 0 4px; 650 | } 651 | .bs-navbar-bottom-example { 652 | -webkit-border-radius: 4px 4px 0 0; 653 | -moz-border-radius: 4px 4px 0 0; 654 | border-radius: 4px 4px 0 0; 655 | } 656 | .bs-navbar-bottom-example .navbar { 657 | margin-bottom: 0; 658 | } 659 | form.bs-docs-example { 660 | padding-bottom: 19px; 661 | } 662 | 663 | /* Images */ 664 | .bs-docs-example-images img { 665 | margin: 10px; 666 | display: inline-block; 667 | } 668 | 669 | /* Tooltips */ 670 | .bs-docs-tooltip-examples { 671 | text-align: center; 672 | margin: 0 0 10px; 673 | list-style: none; 674 | } 675 | .bs-docs-tooltip-examples li { 676 | display: inline; 677 | padding: 0 10px; 678 | } 679 | 680 | /* Popovers */ 681 | .bs-docs-example-popover { 682 | padding-bottom: 24px; 683 | background-color: #f9f9f9; 684 | } 685 | .bs-docs-example-popover .popover { 686 | position: relative; 687 | display: block; 688 | float: left; 689 | width: 260px; 690 | margin: 20px; 691 | } 692 | 693 | /* Dropdowns */ 694 | .bs-docs-example-submenus { 695 | min-height: 180px; 696 | } 697 | .bs-docs-example-submenus > .pull-left + .pull-left { 698 | margin-left: 20px; 699 | } 700 | .bs-docs-example-submenus .dropup > .dropdown-menu, 701 | .bs-docs-example-submenus .dropdown > .dropdown-menu { 702 | display: block; 703 | position: static; 704 | margin-bottom: 5px; 705 | *width: 180px; 706 | } 707 | 708 | 709 | 710 | /* Responsive docs 711 | -------------------------------------------------- */ 712 | 713 | /* Utility classes table 714 | ------------------------- */ 715 | .responsive-utilities th small { 716 | display: block; 717 | font-weight: normal; 718 | color: #999; 719 | } 720 | .responsive-utilities tbody th { 721 | font-weight: normal; 722 | } 723 | .responsive-utilities td { 724 | text-align: center; 725 | } 726 | .responsive-utilities td.is-visible { 727 | color: #468847; 728 | background-color: #dff0d8 !important; 729 | } 730 | .responsive-utilities td.is-hidden { 731 | color: #ccc; 732 | background-color: #f9f9f9 !important; 733 | } 734 | 735 | /* Responsive tests 736 | ------------------------- */ 737 | .responsive-utilities-test { 738 | margin-top: 5px; 739 | margin-left: 0; 740 | list-style: none; 741 | overflow: hidden; /* clear floats */ 742 | } 743 | .responsive-utilities-test li { 744 | position: relative; 745 | float: left; 746 | width: 25%; 747 | height: 43px; 748 | font-size: 14px; 749 | font-weight: bold; 750 | line-height: 43px; 751 | color: #999; 752 | text-align: center; 753 | border: 1px solid #ddd; 754 | -webkit-border-radius: 4px; 755 | -moz-border-radius: 4px; 756 | border-radius: 4px; 757 | } 758 | .responsive-utilities-test li + li { 759 | margin-left: 10px; 760 | } 761 | .responsive-utilities-test span { 762 | position: absolute; 763 | top: -1px; 764 | left: -1px; 765 | right: -1px; 766 | bottom: -1px; 767 | -webkit-border-radius: 4px; 768 | -moz-border-radius: 4px; 769 | border-radius: 4px; 770 | } 771 | .responsive-utilities-test span { 772 | color: #468847; 773 | background-color: #dff0d8; 774 | border: 1px solid #d6e9c6; 775 | } 776 | 777 | 778 | 779 | /* Sidenav for Docs 780 | -------------------------------------------------- */ 781 | 782 | .bs-docs-sidenav { 783 | width: 228px; 784 | margin: 30px 0 0; 785 | padding: 0; 786 | background-color: #fff; 787 | -webkit-border-radius: 6px; 788 | -moz-border-radius: 6px; 789 | border-radius: 6px; 790 | -webkit-box-shadow: 0 1px 4px rgba(0,0,0,.065); 791 | -moz-box-shadow: 0 1px 4px rgba(0,0,0,.065); 792 | box-shadow: 0 1px 4px rgba(0,0,0,.065); 793 | } 794 | .bs-docs-sidenav > li > a { 795 | display: block; 796 | width: 190px \9; 797 | margin: 0 0 -1px; 798 | padding: 8px 14px; 799 | border: 1px solid #e5e5e5; 800 | } 801 | .bs-docs-sidenav > li:first-child > a { 802 | -webkit-border-radius: 6px 6px 0 0; 803 | -moz-border-radius: 6px 6px 0 0; 804 | border-radius: 6px 6px 0 0; 805 | } 806 | .bs-docs-sidenav > li:last-child > a { 807 | -webkit-border-radius: 0 0 6px 6px; 808 | -moz-border-radius: 0 0 6px 6px; 809 | border-radius: 0 0 6px 6px; 810 | } 811 | .bs-docs-sidenav > .active > a { 812 | position: relative; 813 | z-index: 2; 814 | padding: 9px 15px; 815 | border: 0; 816 | text-shadow: 0 1px 0 rgba(0,0,0,.15); 817 | -webkit-box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); 818 | -moz-box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); 819 | box-shadow: inset 1px 0 0 rgba(0,0,0,.1), inset -1px 0 0 rgba(0,0,0,.1); 820 | } 821 | /* Chevrons */ 822 | .bs-docs-sidenav .icon-chevron-right { 823 | float: right; 824 | margin-top: 2px; 825 | margin-right: -6px; 826 | opacity: .25; 827 | } 828 | .bs-docs-sidenav > li > a:hover { 829 | background-color: #f5f5f5; 830 | } 831 | .bs-docs-sidenav a:hover .icon-chevron-right { 832 | opacity: .5; 833 | } 834 | .bs-docs-sidenav .active .icon-chevron-right, 835 | .bs-docs-sidenav .active a:hover .icon-chevron-right { 836 | background-image: url(../img/glyphicons-halflings-white.png); 837 | opacity: 1; 838 | } 839 | .bs-docs-sidenav.affix { 840 | top: 40px; 841 | } 842 | .bs-docs-sidenav.affix-bottom { 843 | position: absolute; 844 | top: auto; 845 | bottom: 270px; 846 | } 847 | 848 | 849 | 850 | 851 | /* Responsive 852 | -------------------------------------------------- */ 853 | 854 | /* Desktop large 855 | ------------------------- */ 856 | @media (min-width: 1200px) { 857 | .bs-docs-container { 858 | max-width: 970px; 859 | } 860 | .bs-docs-sidenav { 861 | width: 258px; 862 | } 863 | .bs-docs-sidenav > li > a { 864 | width: 230px \9; /* Override the previous IE8-9 hack */ 865 | } 866 | } 867 | 868 | /* Desktop 869 | ------------------------- */ 870 | @media (max-width: 980px) { 871 | /* Unfloat brand */ 872 | body > .navbar-fixed-top .brand { 873 | float: left; 874 | margin-left: 0; 875 | padding-left: 10px; 876 | padding-right: 10px; 877 | } 878 | 879 | /* Inline-block quick links for more spacing */ 880 | .quick-links li { 881 | display: inline-block; 882 | margin: 5px; 883 | } 884 | 885 | /* When affixed, space properly */ 886 | .bs-docs-sidenav { 887 | top: 0; 888 | width: 218px; 889 | margin-top: 30px; 890 | margin-right: 0; 891 | } 892 | } 893 | 894 | /* Tablet to desktop 895 | ------------------------- */ 896 | @media (min-width: 768px) and (max-width: 979px) { 897 | /* Remove any padding from the body */ 898 | body { 899 | padding-top: 0; 900 | } 901 | /* Widen masthead and social buttons to fill body padding */ 902 | .jumbotron { 903 | margin-top: -20px; /* Offset bottom margin on .navbar */ 904 | } 905 | /* Adjust sidenav width */ 906 | .bs-docs-sidenav { 907 | width: 166px; 908 | margin-top: 20px; 909 | } 910 | .bs-docs-sidenav.affix { 911 | top: 0; 912 | } 913 | } 914 | 915 | /* Tablet 916 | ------------------------- */ 917 | @media (max-width: 767px) { 918 | /* Remove any padding from the body */ 919 | body { 920 | padding-top: 0; 921 | } 922 | 923 | /* Widen masthead and social buttons to fill body padding */ 924 | .jumbotron { 925 | padding: 40px 20px; 926 | margin-top: -20px; /* Offset bottom margin on .navbar */ 927 | margin-right: -20px; 928 | margin-left: -20px; 929 | } 930 | .masthead h1 { 931 | font-size: 90px; 932 | } 933 | .masthead p, 934 | .masthead .btn { 935 | font-size: 24px; 936 | } 937 | .marketing .span4 { 938 | margin-bottom: 40px; 939 | } 940 | .bs-docs-social { 941 | margin: 0 -20px; 942 | } 943 | 944 | /* Space out the show-grid examples */ 945 | .show-grid [class*="span"] { 946 | margin-bottom: 5px; 947 | } 948 | 949 | /* Sidenav */ 950 | .bs-docs-sidenav { 951 | width: auto; 952 | margin-bottom: 20px; 953 | } 954 | .bs-docs-sidenav.affix { 955 | position: static; 956 | width: auto; 957 | top: 0; 958 | } 959 | 960 | /* Unfloat the back to top link in footer */ 961 | .footer { 962 | margin-left: -20px; 963 | margin-right: -20px; 964 | padding-left: 20px; 965 | padding-right: 20px; 966 | } 967 | .footer p { 968 | margin-bottom: 9px; 969 | } 970 | } 971 | 972 | /* Landscape phones 973 | ------------------------- */ 974 | @media (max-width: 480px) { 975 | /* Remove padding above jumbotron */ 976 | body { 977 | padding-top: 0; 978 | } 979 | 980 | /* Change up some type stuff */ 981 | h2 small { 982 | display: block; 983 | } 984 | 985 | /* Downsize the jumbotrons */ 986 | .jumbotron h1 { 987 | font-size: 45px; 988 | } 989 | .jumbotron p, 990 | .jumbotron .btn { 991 | font-size: 18px; 992 | } 993 | .jumbotron .btn { 994 | display: block; 995 | margin: 0 auto; 996 | } 997 | 998 | /* center align subhead text like the masthead */ 999 | .subhead h1, 1000 | .subhead p { 1001 | text-align: center; 1002 | } 1003 | 1004 | /* Marketing on home */ 1005 | .marketing h1 { 1006 | font-size: 30px; 1007 | } 1008 | .marketing-byline { 1009 | font-size: 18px; 1010 | } 1011 | 1012 | /* center example sites */ 1013 | .example-sites { 1014 | margin-left: 0; 1015 | } 1016 | .example-sites > li { 1017 | float: none; 1018 | display: block; 1019 | max-width: 280px; 1020 | margin: 0 auto 18px; 1021 | text-align: center; 1022 | } 1023 | .example-sites .thumbnail > img { 1024 | max-width: 270px; 1025 | } 1026 | 1027 | /* Do our best to make tables work in narrow viewports */ 1028 | table code { 1029 | white-space: normal; 1030 | word-wrap: break-word; 1031 | word-break: break-all; 1032 | } 1033 | 1034 | /* Examples: dropdowns */ 1035 | .bs-docs-example-submenus > .pull-left { 1036 | float: none; 1037 | clear: both; 1038 | } 1039 | .bs-docs-example-submenus > .pull-left, 1040 | .bs-docs-example-submenus > .pull-left + .pull-left { 1041 | margin-left: 0; 1042 | } 1043 | .bs-docs-example-submenus p { 1044 | margin-bottom: 0; 1045 | } 1046 | .bs-docs-example-submenus .dropup > .dropdown-menu, 1047 | .bs-docs-example-submenus .dropdown > .dropdown-menu { 1048 | margin-bottom: 10px; 1049 | float: none; 1050 | max-width: 180px; 1051 | } 1052 | 1053 | /* Examples: modal */ 1054 | .modal-example .modal { 1055 | position: relative; 1056 | top: auto; 1057 | right: auto; 1058 | bottom: auto; 1059 | left: auto; 1060 | } 1061 | 1062 | /* Tighten up footer */ 1063 | .footer { 1064 | padding-top: 20px; 1065 | padding-bottom: 20px; 1066 | } 1067 | } 1068 | -------------------------------------------------------------------------------- /static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxyan/aop/e905d94d2bf870bc9f8d4fde4de6c66e3dfd423d/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/linuxyan/aop/e905d94d2bf870bc9f8d4fde4de6c66e3dfd423d/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /static/js/aop.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | 3 | //$("#send").click(function(){ 4 | // $.post("svnadd/", 5 | // { 6 | // email:$('#inputEmail').val(), 7 | // passwd:$('#inputPassword').val() 8 | // }, 9 | // function(result){ 10 | // alert(result); 11 | // }); 12 | // }); 13 | 14 | //$("a[name='Edit']").click(function(){ 15 | // var $v =$("a[name='Edit']").attr('id'); 16 | // alert($v); 17 | //}); 18 | 19 | $("a[name='addservergroup']").click(function(){ 20 | var $group_id =$(this).attr('id'); 21 | var $host_id = $(this).attr('value'); 22 | $.post("/addtogroup/", 23 | { 24 | grouptype:"servergroup", 25 | host_id:$host_id, 26 | group_id:$group_id 27 | }, 28 | function(result){ 29 | $('#addgroupstatus').text(result); 30 | $(".alert").alert(); 31 | $('#myModal').modal({ 32 | backdrop:true, 33 | keyboard:true, 34 | show:true}); 35 | });}); 36 | 37 | 38 | $("a[name='addscriptgroup']").click(function(){ 39 | var $group_id =$(this).attr('id'); 40 | var $script_id = $(this).attr('value'); 41 | $.post("/addtogroup/", 42 | { 43 | grouptype:"scriptgroup", 44 | script_id:$script_id, 45 | group_id:$group_id 46 | }, 47 | function(result){ 48 | $('#addgroupstatus').text(result); 49 | $('#myModal').modal({ 50 | backdrop:true, 51 | keyboard:true, 52 | show:true}); 53 | });}); 54 | 55 | $("a[name='hostgroup_del_host']").click(function(){ 56 | var $host_id =$(this).attr('id'); 57 | var $group_id = $(this).attr('value'); 58 | $.post("/hostgroup_del_host/", 59 | { 60 | host_id:$host_id, 61 | group_id:$group_id 62 | }, 63 | function(result){ 64 | //$("#group_host_table").load(location.href+"#group_host_table>*"); 65 | location.reload(); 66 | }); 67 | }); 68 | 69 | $("a[name='scriptgroup_del_script']").click(function(){ 70 | var $script_id =$(this).attr('id'); 71 | var $group_id = $(this).attr('value'); 72 | $.post("/scriptgroup_del_script/", 73 | { 74 | script_id:$script_id, 75 | group_id:$group_id 76 | }, 77 | function(result){ 78 | //$("#group_host_table").load(location.href+"#group_host_table>*"); 79 | location.reload(); 80 | }); 81 | }); 82 | 83 | $("a[name='runtask']").click(function(){ 84 | var $task_id =$(this).attr('id'); 85 | $.post("/task_run/", 86 | { 87 | task_id:$task_id 88 | }, 89 | function(result){ 90 | alert(result); 91 | location.reload(); 92 | }); 93 | }); 94 | 95 | 96 | 97 | 98 | }); -------------------------------------------------------------------------------- /static/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Bootstrap.js v2.3.1 by @fat & @mdo 3 | * Copyright 2012 Twitter, Inc. 4 | * http://www.apache.org/licenses/LICENSE-2.0.txt 5 | */ 6 | !function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()};var r=e.fn.alert;e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e.fn.alert.noConflict=function(){return e.fn.alert=r,this},e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")};var n=e.fn.button;e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e.fn.button.noConflict=function(){return e.fn.button=n,this},e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.$indicators=this.$element.find(".carousel-indicators"),this.options=n,this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},getActiveIndex:function(){return this.$active=this.$element.find(".item.active"),this.$items=this.$active.parent().children(),this.$items.index(this.$active)},to:function(t){var n=this.getActiveIndex(),r=this;if(t>this.$items.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){r.to(t)}):n==t?this.pause().cycle():this.slide(t>n?"next":"prev",e(this.$items[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle(!0)),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0],direction:o});if(i.hasClass("active"))return;this.$indicators.length&&(this.$indicators.find(".active").removeClass("active"),this.$element.one("slid",function(){var t=e(a.$indicators.children()[a.getActiveIndex()]);t&&t.addClass("active")}));if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}};var n=e.fn.carousel;e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.pause().cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e.fn.carousel.noConflict=function(){return e.fn.carousel=n,this},e(document).on("click.carousel.data-api","[data-slide], [data-slide-to]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data()),o;i.carousel(s),(o=n.attr("data-slide-to"))&&i.data("carousel").pause().to(o).cycle(),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning||this.$element.hasClass("in"))return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning||!this.$element.hasClass("in"))return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}};var n=e.fn.collapse;e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=e.extend({},e.fn.collapse.defaults,r.data(),typeof n=="object"&&n);i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e.fn.collapse.noConflict=function(){return e.fn.collapse=n,this},e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=n&&e(n);if(!r||!r.length)r=t.parent();return r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||s.toggleClass("open"),n.focus(),!1},keydown:function(n){var r,s,o,u,a,f;if(!/(38|40|27)/.test(n.keyCode))return;r=e(this),n.preventDefault(),n.stopPropagation();if(r.is(".disabled, :disabled"))return;u=i(r),a=u.hasClass("open");if(!a||a&&n.keyCode==27)return n.which==27&&u.find(t).focus(),r.click();s=e("[role=menu] li:not(.divider):visible a",u);if(!s.length)return;f=s.index(s.filter(":focus")),n.keyCode==38&&f>0&&f--,n.keyCode==40&&f').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!t)return;i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,t):t()):t&&t()}};var n=e.fn.modal;e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e.fn.modal.noConflict=function(){return e.fn.modal=n,this},e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s,o,u,a;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,o=this.options.trigger.split(" ");for(a=o.length;a--;)u=o[a],u=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):u!="manual"&&(i=u=="hover"?"mouseenter":"focus",s=u=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this)));this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,this.$element.data(),t),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e.fn[this.type].defaults,r={},i;this._options&&e.each(this._options,function(e,t){n[e]!=t&&(r[e]=t)},this),i=e(t.currentTarget)[this.type](r).data(this.type);if(!i.options.delay||!i.options.delay.show)return i.show();clearTimeout(this.timeout),i.hoverState="in",this.timeout=setTimeout(function(){i.hoverState=="in"&&i.show()},i.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var t,n,r,i,s,o,u=e.Event("show");if(this.hasContent()&&this.enabled){this.$element.trigger(u);if(u.isDefaultPrevented())return;t=this.tip(),this.setContent(),this.options.animation&&t.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,t[0],this.$element[0]):this.options.placement,t.detach().css({top:0,left:0,display:"block"}),this.options.container?t.appendTo(this.options.container):t.insertAfter(this.$element),n=this.getPosition(),r=t[0].offsetWidth,i=t[0].offsetHeight;switch(s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}this.applyPlacement(o,s),this.$element.trigger("shown")}},applyPlacement:function(e,t){var n=this.tip(),r=n[0].offsetWidth,i=n[0].offsetHeight,s,o,u,a;n.offset(e).addClass(t).addClass("in"),s=n[0].offsetWidth,o=n[0].offsetHeight,t=="top"&&o!=i&&(e.top=e.top+i-o,a=!0),t=="bottom"||t=="top"?(u=0,e.left<0&&(u=e.left*-2,e.left=0,n.offset(e),s=n[0].offsetWidth,o=n[0].offsetHeight),this.replaceArrow(u-r+s,s,"left")):this.replaceArrow(o-i,o,"top"),a&&n.offset(e)},replaceArrow:function(e,t,n){this.arrow().css(n,e?50*(1-e/t)+"%":"")},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function i(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip(),r=e.Event("hide");this.$element.trigger(r);if(r.isDefaultPrevented())return;return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?i():n.detach(),this.$element.trigger("hidden"),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").attr("title","")},hasContent:function(){return this.getTitle()},getPosition:function(){var t=this.$element[0];return e.extend({},typeof t.getBoundingClientRect=="function"?t.getBoundingClientRect():{width:t.offsetWidth,height:t.offsetHeight},this.$element.offset())},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},arrow:function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=t?e(t.currentTarget)[this.type](this._options).data(this.type):this;n.tip().hasClass("in")?n.hide():n.show()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}};var n=e.fn.tooltip;e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},e.fn.tooltip.noConflict=function(){return e.fn.tooltip=n,this}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=(typeof n.content=="function"?n.content.call(t[0]):n.content)||t.attr("data-content"),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}});var n=e.fn.popover;e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'

'}),e.fn.popover.noConflict=function(){return e.fn.popover=n,this}}(window.jQuery),!function(e){"use strict";function t(t,n){var r=e.proxy(this.process,this),i=e(t).is("body")?e(window):e(t),s;this.options=e.extend({},e.fn.scrollspy.defaults,n),this.$scrollElement=i.on("scroll.scroll-spy.data-api",r),this.selector=(this.options.target||(s=e(t).attr("href"))&&s.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=e("body"),this.refresh(),this.process()}t.prototype={constructor:t,refresh:function(){var t=this,n;this.offsets=e([]),this.targets=e([]),n=this.$body.find(this.selector).map(function(){var n=e(this),r=n.data("target")||n.attr("href"),i=/^#\w/.test(r)&&e(r);return i&&i.length&&[[i.position().top+(!e.isWindow(t.$scrollElement.get(0))&&t.$scrollElement.scrollTop()),r]]||null}).sort(function(e,t){return e[0]-t[0]}).each(function(){t.offsets.push(this[0]),t.targets.push(this[1])})},process:function(){var e=this.$scrollElement.scrollTop()+this.options.offset,t=this.$scrollElement[0].scrollHeight||this.$body[0].scrollHeight,n=t-this.$scrollElement.height(),r=this.offsets,i=this.targets,s=this.activeTarget,o;if(e>=n)return s!=(o=i.last()[0])&&this.activate(o);for(o=r.length;o--;)s!=i[o]&&e>=r[o]&&(!r[o+1]||e<=r[o+1])&&this.activate(i[o])},activate:function(t){var n,r;this.activeTarget=t,e(this.selector).parent(".active").removeClass("active"),r=this.selector+'[data-target="'+t+'"],'+this.selector+'[href="'+t+'"]',n=e(r).parent("li").addClass("active"),n.parent(".dropdown-menu").length&&(n=n.closest("li.dropdown").addClass("active")),n.trigger("activate")}};var n=e.fn.scrollspy;e.fn.scrollspy=function(n){return this.each(function(){var r=e(this),i=r.data("scrollspy"),s=typeof n=="object"&&n;i||r.data("scrollspy",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.scrollspy.Constructor=t,e.fn.scrollspy.defaults={offset:10},e.fn.scrollspy.noConflict=function(){return e.fn.scrollspy=n,this},e(window).on("load",function(){e('[data-spy="scroll"]').each(function(){var t=e(this);t.scrollspy(t.data())})})}(window.jQuery),!function(e){"use strict";var t=function(t){this.element=e(t)};t.prototype={constructor:t,show:function(){var t=this.element,n=t.closest("ul:not(.dropdown-menu)"),r=t.attr("data-target"),i,s,o;r||(r=t.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,""));if(t.parent("li").hasClass("active"))return;i=n.find(".active:last a")[0],o=e.Event("show",{relatedTarget:i}),t.trigger(o);if(o.isDefaultPrevented())return;s=e(r),this.activate(t.parent("li"),n),this.activate(s,s.parent(),function(){t.trigger({type:"shown",relatedTarget:i})})},activate:function(t,n,r){function o(){i.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),t.addClass("active"),s?(t[0].offsetWidth,t.addClass("in")):t.removeClass("fade"),t.parent(".dropdown-menu")&&t.closest("li.dropdown").addClass("active"),r&&r()}var i=n.find("> .active"),s=r&&e.support.transition&&i.hasClass("fade");s?i.one(e.support.transition.end,o):o(),i.removeClass("in")}};var n=e.fn.tab;e.fn.tab=function(n){return this.each(function(){var r=e(this),i=r.data("tab");i||r.data("tab",i=new t(this)),typeof n=="string"&&i[n]()})},e.fn.tab.Constructor=t,e.fn.tab.noConflict=function(){return e.fn.tab=n,this},e(document).on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(t){t.preventDefault(),e(this).tab("show")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.source=this.options.source,this.$menu=e(this.options.menu),this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.position(),{height:this.$element[0].offsetHeight});return this.$menu.insertAfter(this.$element).css({top:t.top+t.height,left:t.left}).show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),t.first().addClass("active"),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("focus",e.proxy(this.focus,this)).on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),this.eventSupported("keydown")&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this)).on("mouseleave","li",e.proxy(this.mouseleave,this))},eventSupported:function(e){var t=e in this.$element;return t||(this.$element.setAttribute(e,"return;"),t=typeof this.$element[e]=="function"),t},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:case 16:case 17:case 18:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},focus:function(e){this.focused=!0},blur:function(e){this.focused=!1,!this.mousedover&&this.shown&&this.hide()},click:function(e){e.stopPropagation(),e.preventDefault(),this.select(),this.$element.focus()},mouseenter:function(t){this.mousedover=!0,this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")},mouseleave:function(e){this.mousedover=!1,!this.focused&&this.shown&&this.hide()}};var n=e.fn.typeahead;e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e.fn.typeahead.noConflict=function(){return e.fn.typeahead=n,this},e(document).on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;n.typeahead(n.data())})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.options=e.extend({},e.fn.affix.defaults,n),this.$window=e(window).on("scroll.affix.data-api",e.proxy(this.checkPosition,this)).on("click.affix.data-api",e.proxy(function(){setTimeout(e.proxy(this.checkPosition,this),1)},this)),this.$element=e(t),this.checkPosition()};t.prototype.checkPosition=function(){if(!this.$element.is(":visible"))return;var t=e(document).height(),n=this.$window.scrollTop(),r=this.$element.offset(),i=this.options.offset,s=i.bottom,o=i.top,u="affix affix-top affix-bottom",a;typeof i!="object"&&(s=o=i),typeof o=="function"&&(o=i.top()),typeof s=="function"&&(s=i.bottom()),a=this.unpin!=null&&n+this.unpin<=r.top?!1:s!=null&&r.top+this.$element.height()>=t-s?"bottom":o!=null&&n<=o?"top":!1;if(this.affixed===a)return;this.affixed=a,this.unpin=a=="bottom"?r.top-n:null,this.$element.removeClass(u).addClass("affix"+(a?"-"+a:""))};var n=e.fn.affix;e.fn.affix=function(n){return this.each(function(){var r=e(this),i=r.data("affix"),s=typeof n=="object"&&n;i||r.data("affix",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.affix.Constructor=t,e.fn.affix.defaults={offset:0},e.fn.affix.noConflict=function(){return e.fn.affix=n,this},e(window).on("load",function(){e('[data-spy="affix"]').each(function(){var t=e(this),n=t.data();n.offset=n.offset||{},n.offsetBottom&&(n.offset.bottom=n.offsetBottom),n.offsetTop&&(n.offset.top=n.offsetTop),t.affix(n)})})}(window.jQuery); --------------------------------------------------------------------------------