├── .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 |
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 |
25 | {% endblock %}
--------------------------------------------------------------------------------
/aop/templates/addsvn.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}Add Svn{% endblock %}
3 | {% block content %}
4 | Add Svn
5 |
6 |
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 |
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 |
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 |
18 |
19 |
20 |
21 | # |
22 | Cron Name |
23 | Server Group |
24 | Script Group |
25 |
26 |
27 |
28 |
29 | 1 |
30 | LNMP |
31 | server group |
32 | script group |
33 | run |
34 | view status |
35 | del cron |
36 |
37 |
38 | 1 |
39 | LNMP |
40 | server group |
41 | script group |
42 | run |
43 | view status |
44 | del cron |
45 |
46 |
47 |
48 | Running Status View
49 |
50 |
51 |
52 |
53 | # |
54 | User |
55 | Server |
56 | Script |
57 | Console output |
58 | Final status |
59 |
60 |
61 |
62 |
63 | 1 |
64 | caoyan |
65 | 测试服务器 |
66 | lnmp.sh |
67 | dcsacssacscs |
68 | Done |
69 | Complate |
70 |
71 |
72 | 1 |
73 | caoyan |
74 | 测试服务器 |
75 | lnmp.sh |
76 | dcsacssacscs |
77 | Done |
78 | Complate |
79 |
80 |
81 |
82 | {{result}}
83 | {% endblock %}
--------------------------------------------------------------------------------
/aop/templates/delhost.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}del Server{% endblock %}
3 | {% block content %}
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 | 所属服务器 |
15 | 本地路径 |
16 | svn库路径 |
17 | svn名称 |
18 |
19 |
20 |
21 | {% for svn in svns %}
22 |
23 | {{svn.host}} |
24 | {{svn.svn_local}} |
25 | {{svn.svn_path}} |
26 | {{svn.svn_name}} |
27 |
28 | {% endfor %}
29 |
30 |
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 |
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 |
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 |
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 |
13 |
14 |
15 |
16 | Server Group Name |
17 | Create Date |
18 | Create User |
19 | 操作 |
20 |
21 |
22 |
23 | {% for hostgroup in hostgroups %}
24 |
25 | {{hostgroup.host_groupname}} |
26 | {{hostgroup.create_date}} |
27 | {{hostgroup.create_user}} |
28 | |
29 |
30 | {% endfor %}
31 |
32 |
33 |
34 |
35 | Add Script Group
36 |
37 |
44 |
45 |
46 |
47 | Script Group Name |
48 | Create Date |
49 | Create User |
50 | 操作 |
51 |
52 |
53 |
54 | {% for scriptgroup in scriptgroups %}
55 |
56 | {{scriptgroup.script_groupname}} |
57 | {{scriptgroup.create_date}} |
58 | {{scriptgroup.create_user}} |
59 | |
60 |
61 | {% endfor %}
62 |
63 |
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 | Host Name |
10 | Inter IP:Port |
11 | local IP:Port |
12 | Host User |
13 | Script Dir |
14 | 操作 |
15 |
16 |
17 |
18 | {% for host in host_list %}
19 |
20 | {{host.host_name}} |
21 | {{host.host_w_ip}}:{{host.host_w_port}} |
22 | {{host.host_n_ip}}:{{host.host_n_port}} |
23 | {{host.host_user}} |
24 | {{host.script_dir}} |
25 | |
26 |
27 | {% endfor %}
28 |
29 |
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 |
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 |
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 | Script Name |
10 | Script Path |
11 | Create Date |
12 | Script description |
13 | Create User |
14 | 操作 |
15 |
16 |
17 |
18 | {% for script in script_list %}
19 |
20 | {{script.script_name}} |
21 | {{script.script_file}} |
22 | {{script.script_date}} |
23 | {{script.script_description}} |
24 | {{script.create_user}} |
25 | |
26 |
27 | {% endfor %}
28 |
29 |
30 | {% endblock %}
--------------------------------------------------------------------------------
/aop/templates/showhost.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}index{% endblock %}
3 | {% block content %}
4 |
14 |
15 |
16 |
17 |
18 | Host Name |
19 | Inter IP:Port |
20 | local IP:Port |
21 | Host User |
22 | Script Dir |
23 | 操作 |
24 |
25 |
26 |
27 | {% for host in hosts %}
28 |
29 | {{host.host_name}} |
30 | {{host.host_w_ip}}:{{host.host_w_port}} |
31 | {{host.host_n_ip}}:{{host.host_n_port}} |
32 | {{host.host_user}} |
33 | {{host.script_dir}} |
34 |
35 |
45 | |
46 |
47 | {% endfor %}
48 |
49 |
50 |
59 |
60 |
76 | {% endblock %}
--------------------------------------------------------------------------------
/aop/templates/showhost_bak.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}测试标题{% endblock %}
3 | {% block content %}
4 |
12 |
13 |
14 |
15 |
16 | test |
17 | test |
18 | test |
19 | test |
20 | test |
21 |
22 |
23 |
24 |
25 | asxsxsa |
26 | sasasas |
27 | sasasas |
28 | sasasas |
29 | sasasas |
30 |
31 |
32 | assa |
33 | sasasas |
34 | sasasas |
35 | sasasas |
36 | sasasas |
37 |
38 |
39 | assa |
40 | sasasas |
41 | sasasas |
42 | sasasas |
43 | sasasas |
44 |
45 |
46 | assa |
47 | sasasas |
48 | sasasas |
49 | sasasas |
50 | sasasas |
51 |
52 |
53 | assa |
54 | sasasas |
55 | sasasas |
56 | sasasas |
57 | sasasas |
58 |
59 |
60 | assa |
61 | sasasas |
62 | sasasas |
63 | sasasas |
64 | sasasas |
65 |
66 |
67 | assa |
68 | sasasas |
69 | sasasas |
70 | sasasas |
71 | sasasas |
72 |
73 |
74 | assa |
75 | sasasas |
76 | sasasas |
77 | sasasas |
78 | sasasas |
79 |
80 |
81 | assa |
82 | sasasas |
83 | sasasas |
84 | sasasas |
85 | sasasas |
86 |
87 |
88 | assa |
89 | sasasas |
90 | sasasas |
91 | sasasas |
92 | sasasas |
93 |
94 |
95 | assa |
96 | sasasas |
97 | sasasas |
98 | sasasas |
99 |
100 |
109 |
110 |
111 |
112 | |
113 |
114 |
115 |
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 |
14 |
15 |
16 |
17 |
18 | Script Name |
19 | Script Path |
20 | Create Date |
21 | Script description |
22 | Create User |
23 | 操作 |
24 |
25 |
26 |
27 | {% for script in scripts %}
28 |
29 | {{script.script_name}} |
30 | {{script.script_file}} |
31 | {{script.script_date}} |
32 | {{script.script_description}} |
33 | {{script.create_user}} |
34 |
35 |
44 | |
45 |
46 |
47 |
51 |
52 |
53 | Do you want to delete {{script.script_name}} script?
54 |
55 |
59 |
60 | {% endfor %}
61 |
62 |
63 |
72 |
88 | {% endblock %}
--------------------------------------------------------------------------------
/aop/templates/showsvn.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}Show Svn{% endblock %}
3 | {% block content %}
4 |
15 |
16 |
17 |
18 |
19 | Svn Name |
20 | local path |
21 | Svn path |
22 | By Host |
23 | 操作 |
24 |
25 |
26 |
27 | {% for svn in svns %}
28 |
29 | {{svn.svn_name}} |
30 | {{svn.svn_local}} |
31 | {{svn.svn_path}} |
32 | {{svn.host}} |
33 |
34 |
35 | 更新
36 | 更新到
37 |
41 |
42 | |
43 |
44 | {% endfor %}
45 |
46 |
47 |
48 |
64 |
65 | {% endblock %}
--------------------------------------------------------------------------------
/aop/templates/showuser.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block title %}Show User{% endblock %}
3 | {% block content %}
4 |
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 | {{user_user.username}} |
27 | {{user_user.userprofile.name}} |
28 | {{user_user.userprofile.iphone}} |
29 | {{user_user.email}} |
30 | {% if user.username == "root" %}
31 |
32 | {% if user_user.username != "root" %}
33 |
36 | {% endif %}
37 | |
38 | {% endif %}
39 |
40 | {% endfor %}
41 |
42 |
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 |
18 |
19 |
20 |
21 | # |
22 | Task Name |
23 | Server Group |
24 | Script Group |
25 | Create Date |
26 | Create User |
27 |
28 |
29 |
30 | {% for task in task_list %}
31 |
32 | {{task.id}} |
33 | {{task.task_name}} |
34 | {{task.host_group}} |
35 | {{task.script_group}} |
36 | {{task.task_date}} |
37 | {{task.task_create_user}} |
38 | {% if task.task_status == "0" %}
39 | run |
40 | {% elif task.task_status == "1" %}
41 | run |
42 | {% endif %}
43 | view status |
44 | del task |
45 |
46 | {% endfor %}
47 |
48 |
49 |
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);
--------------------------------------------------------------------------------