├── README.md
├── run.py
├── xk_application
├── __init__.py
├── xk_app.py
└── xk_main.py
├── xk_config
├── __init__.py
├── xk_setting.sample.py
└── xk_url.py
├── xk_db_sql
└── xk_dnsmasq.sql
├── xk_handler
├── __init__.py
├── xk_dhcp.py
├── xk_dns.py
├── xk_index.py
├── xk_login.py
├── xk_public.py
├── xk_test.py
└── xk_users.py
├── xk_html
├── xk_dhcp_host.html
├── xk_dhcp_pool.html
├── xk_domain.html
├── xk_footer.html
├── xk_index.html
├── xk_login.html
├── xk_nav.html
├── xk_record.html
├── xk_top_nav.html
├── xk_users.html
└── xk_users_logs.html
├── xk_screenshot
├── xk_dashboard.png
├── xk_dhcp.png
├── xk_domain.png
├── xk_login.png
└── xk_record.png
└── xk_static
├── bootstrap
├── css
│ ├── bootstrap-responsive.css
│ ├── bootstrap-responsive.min.css
│ ├── bootstrap.css
│ └── bootstrap.min.css
├── img
│ ├── glyphicons-halflings-white.png
│ └── glyphicons-halflings.png
└── js
│ ├── bootstrap.js
│ └── bootstrap.min.js
├── css
├── bootstrap-switch.css
├── xk_dnsmasqweb.css
└── xk_login.css
├── images
├── 160x120.gif
├── 260x180.gif
├── 360x268.gif
├── 670x240.gif
└── login_bg.png
└── js
├── bootstrap-switch.js
├── html5shiv.min.js
├── jquery-1.8.3.min.js
├── xk_dhcp.js
├── xk_dnsmasqweb.js
└── xk_users.js
/README.md:
--------------------------------------------------------------------------------
1 | DNSmasqWeb
2 | ==========
3 |
4 | 基于DNSmasq的开源轻量级DNS解析、DHCP地址分配的开源系统
5 |
6 | Desgin By [Xiaok](http://github.luxiaok.com)
7 |
8 |
9 | ## 【Python运维圈】微信公众号 ##
10 |
11 | 
12 |
13 | >也可以微信搜索 **Python运维圈**
14 |
15 |
16 | ## 技术交流QQ群 ##
17 |
18 | **459457262**
19 |
20 | >加群时请注明来自 **Github**
21 |
22 |
23 | ## 一、应用说明 ##
24 | * 本系统可同时提供DNS解析功能和DHCP地址分配功能
25 | * 本系统可以用于机房内网、公司内网、家庭内网等类似内部网络环境
26 | * 系统基于DNSmasq,Web端基于Python语言和Tornado框架
27 |
28 | ## 二、运行环境 ##
29 | * OS:RHEL 6.5 x64
30 | * Python:2.7.8
31 | * DnsMasq:2.72
32 | * Tornado:4.0.2
33 | * Jinja2:2.7.3
34 |
35 | 注意:以上是测试运行正常的环境,其他环境请自行测试
36 |
37 | ## 三、DNSmasq配置说明 ##
38 | * 常规安装(版本:2.48)
39 |
40 | `yum -y install dnsmasq`
41 |
42 | `chkconfig dnsmasq on`
43 |
44 | * 编辑安装(版本:2.72)
45 |
46 | `wget http://www.thekelleys.org.uk/dnsmasq/dnsmasq-2.72.tar.gz`
47 |
48 | `tar zxf dnsmasq-2.72.tar.gz`
49 |
50 | `cd dnsmasq-2.72`
51 |
52 | `vim Makefile`
53 |
54 | `PREFIX = /usr/local/dnsmasq`
55 |
56 | `make && make install`
57 |
58 | `cp dnsmasq.conf.example /etc/dnsmasq.conf`
59 |
60 | `ln -s /usr/local/dnsmasq/sbin/dnsmasq /usr/sbin/`
61 |
62 | `dnsmasq --version`
63 |
64 | * 主配文件:/etc/dnsmasq.conf
65 |
66 | `resolv-file=/etc/dnsmasq.resolv.conf`
67 |
68 | `addn-hosts=/etc/dnsmasq.hosts`
69 |
70 | `conf-dir=/etc/dnsmasq.d`
71 |
72 | ## 四、Web配置 ##
73 | * 安装Tornado
74 |
75 | `easy_install tornado`
76 |
77 | * 安装jinja2
78 |
79 | `easy_install tornado`
80 |
81 | * 安装数据库驱动
82 |
83 | `yum -y install MySQL-python`
84 |
85 | `easy_install torndb`
86 |
87 | * 导入数据库文件
88 |
89 | `mysql> create database xk_dnsmasq;`
90 |
91 | `mysql> use xk_dnsmasq;`
92 |
93 | `mysql> source xk_db_sql/xk_dnsmasq.sql;`
94 |
95 | * 配置Web
96 |
97 | `cp xk_config/xk_setting.sample.py xk_config/xk_setting.py`
98 |
99 | 在文件xk_config/xk_setting.py设置MySQL的主机、端口、用户名、密码
100 |
101 | * 启动Web端
102 |
103 | `python run.py`
104 |
105 | 默认用户名/密码:admin/admin
106 |
107 | 默认端口:9886
108 |
109 | ## 五、截图 ##
110 |
111 | * 登录页面
112 |
113 | 
114 |
115 | * 控制中心
116 |
117 | 
118 |
119 | * 域名管理
120 |
121 | 
122 |
123 | * DNS记录管理
124 |
125 | 
126 |
127 | * DHCP管理
128 |
129 | 
--------------------------------------------------------------------------------
/run.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # DNSmasq Web Admin
4 | # Desgin By Xiaok
5 | # 2014-11-23 02:18:50
6 |
7 | from xk_application.xk_app import *
8 |
9 | if __name__ == "__main__":
10 | main()
11 |
--------------------------------------------------------------------------------
/xk_application/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_application/__init__.py
--------------------------------------------------------------------------------
/xk_application/xk_app.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | import torndb
5 | import tornado.httpserver
6 | import tornado.ioloop
7 | import tornado.web
8 | import tornado.netutil
9 | import tornado.process
10 | import time
11 | from xk_config.xk_setting import *
12 | from xk_config.xk_url import *
13 |
14 | MainSetting = dict(
15 | template_path = 'xk_html',
16 | static_path = 'xk_static',
17 | static_url_prefix = '/xk_static/',
18 | xsrf_cookies = False,
19 | cookie_secret = "db884468559f4c432bf1c1775f3dc9da",
20 | login_url = "/login",
21 | debug = options.debug,
22 | autoreload = options.debug,
23 | )
24 |
25 | class HttpApplication(tornado.web.Application):
26 | def __init__(self):
27 | handlers = HandlersURL
28 | settings = MainSetting
29 | tornado.web.Application.__init__(self, handlers, **settings)
30 |
31 | # Have one global connection to DB across all handlers
32 | self.db = torndb.Connection(
33 | host=options.mysql_host, database=options.mysql_database,
34 | user=options.mysql_user, password=options.mysql_password,
35 | time_zone='+8:00',charset='utf8')
36 |
37 | ping_db = lambda: self.db.query("select now()")
38 | #def print_test():
39 | # print "Hello Test"
40 | # 每3分钟执行一次数据库查询,防止mysql gone away,时间间隔要小于msyql的wait_timeout时长
41 | tornado.ioloop.PeriodicCallback(ping_db,3 * 60 * 1000).start()
42 | #tornado.ioloop.PeriodicCallback(print_test,1 * 30 * 1000).start()
43 |
44 | def main():
45 | if options.ipv6:
46 | host = None
47 | else:
48 | host = "0.0.0.0"
49 | tornado.options.parse_command_line()
50 |
51 | if options.debug:
52 | http_server = tornado.httpserver.HTTPServer(request_callback=HttpApplication(),xheaders=True)
53 | http_server.listen(options.port,host)
54 | now = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
55 | print '[%s] Listen On Port %s' % ( now, options.port )
56 | else:
57 | http_sockets = tornado.netutil.bind_sockets(options.port,host)
58 | tornado.process.fork_processes(num_processes=options.processes)
59 | http_server = tornado.httpserver.HTTPServer(request_callback=HttpApplication(),xheaders=True)
60 | http_server.add_sockets(http_sockets)
61 |
62 | tornado.ioloop.IOLoop.instance().start()
63 |
--------------------------------------------------------------------------------
/xk_application/xk_main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Jinja2 For Tornado
4 | # Design By Xiaok
5 | # 2014-11-15 22:01:17
6 | import sys
7 | reload(sys)
8 | sys.setdefaultencoding('utf8')
9 | import os
10 | from tornado.web import RequestHandler
11 | from tornado.web import authenticated as Auth
12 | from jinja2 import Environment, FileSystemLoader, TemplateNotFound
13 | import datetime
14 | import time
15 | import functools
16 | from hashlib import md5
17 |
18 | class TemplateRendering:
19 | """
20 | A simple class to hold methods for rendering templates.
21 | """
22 | def render_template(self, template_name, **kwargs):
23 | template_dirs = []
24 | if self.settings.get('template_path', ''):
25 | template_dirs.append(
26 | self.settings["template_path"]
27 | )
28 |
29 | env = Environment(loader=FileSystemLoader(template_dirs),trim_blocks=True) # trim_blocks去除生成html产生的大量空行
30 |
31 | try:
32 | template = env.get_template(template_name)
33 | except TemplateNotFound:
34 | raise TemplateNotFound(template_name)
35 | content = template.render(kwargs)
36 | return content
37 |
38 | class BaseHandler(RequestHandler, TemplateRendering):
39 | # 自定义Header信息
40 | def set_default_headers(self):
41 | self.set_header("Server","XK-WebServer/2014")
42 | self.set_header("X-Powered-By","LuXiaok")
43 | self.set_header("Date",self.get_time())
44 |
45 | @property
46 | def db(self):
47 | return self.application.db
48 |
49 | def get_current_user(self):
50 | username = self.get_secure_cookie("xk_auth_token")
51 | if not username: return None
52 | #return self.db.get("SELECT * FROM xk_users WHERE id = %s", int(user_id))
53 | return username
54 |
55 | #@property
56 | def user_info(self):
57 | if self.current_user:
58 | user = self.db.get("SELECT id,username,name FROM xk_users WHERE username = %s", self.current_user)
59 | return user
60 | else:
61 | return None
62 |
63 | # 或者文件的MD5值
64 | def get_md5(self,file):
65 | m = md5()
66 | # 需要使用二进制格式读取文件内容
67 | f = open(file, 'rb')
68 | m.update(f.read())
69 | f.close()
70 | return m.hexdigest()
71 |
72 | # 格式化时间
73 | def get_time(self,s=None):
74 | return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(s))
75 |
76 | # 格式化文件大小
77 | def format_size(self,i):
78 | i = int(i)
79 | unit = 'Bytes'
80 | if i >= 1024:
81 | i = i / 1024.0
82 | unit = 'KB'
83 | if i >= 1024:
84 | i = i / 1024
85 | unit = 'MB'
86 | if i >= 1024:
87 | i = i / 1024
88 | unit = 'GB'
89 | else:
90 | return '%d %s' % (i,unit)
91 | return '%.2f %s' % (i,unit)
92 |
93 | # 格式化秒
94 | def format_seconds(self,s):
95 | s = int(s)
96 | D = 0
97 | H = 0
98 | M = 0
99 | S = s
100 | if S > 59:
101 | M = S / 60
102 | S = S % 60
103 | if M > 59:
104 | H = M / 60
105 | M = M % 60
106 | if H > 23:
107 | D = H / 24
108 | H = H % 24
109 | return { 'days':D, 'hours':H, 'minutes':M, 'seconds':S }
110 |
111 | """
112 | RequestHandler already has a `render()` method. I'm writing another
113 | method `render2()` and keeping the API almost same.
114 | """
115 | def render2(self, template_name, **kwargs):
116 | """
117 | This is for making some extra context variables available to
118 | the template
119 | """
120 | kwargs.update({
121 | 'settings': self.settings,
122 | 'STATIC_URL': self.settings.get('static_url_prefix', '/xk_static/'),
123 | 'static_url': self.static_url,
124 | 'get_time': self.get_time,
125 | 'user_info': self.user_info,
126 | 'format_size': self.format_size,
127 | 'format_seconds': self.format_seconds,
128 | 'request': self.request,
129 | 'xsrf_token': self.xsrf_token,
130 | 'xsrf_form_html': self.xsrf_form_html,
131 | })
132 | content = self.render_template(template_name, **kwargs)
133 | self.write(content)
134 |
135 | # 模块权限管理装饰器
136 | def Perm(method):
137 | @functools.wraps(method)
138 | def wrapper(self, *args, **kwargs):
139 | #### 权限控制 ####
140 | class_name = self.__class__.__name__ #获取类名,其实获取到了待用该方法的类名,方便更加精确的权限判断
141 | request_method = self.request.method #获取请求方法名:GET|POST
142 | #print "Class Name: %s" % class_name
143 | #print "Method: %s" % request_method
144 | permission = self.db.get("select is_admin from login_users where username = %s and status = 'yes'",self.current_user)
145 | if permission:
146 | is_admin = permission['is_admin']
147 | if is_admin == "no":
148 | self.write(''' Sorry,您没有权限操作!''')
149 | return
150 | ###########
151 | return method(self, *args, **kwargs)
152 | return wrapper
153 |
154 |
--------------------------------------------------------------------------------
/xk_config/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_config/__init__.py
--------------------------------------------------------------------------------
/xk_config/xk_setting.sample.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | from tornado.options import define, options
5 |
6 | # HTTP Port Setting
7 | define("port", default=9886, help="Run on the given port", type=int)
8 |
9 | # Debug Setting
10 | define("debug", default=True, help="Debug Setting",type=bool)
11 |
12 | # IPv6 Setting
13 | define("ipv6", default=False, help="IPv6 Setting",type=bool)
14 |
15 | # Worker Processes Setting
16 | define("processes", default=4, help="Worker Processes Setting", type=int)
17 |
18 | # MySQL Config Options
19 | define("mysql_host", default="127.0.0.1:3306", help="Database Host and Port")
20 | define("mysql_database", default="xk_dnsmasq", help="Database Name")
21 | define("mysql_user", default="test", help="Database User")
22 | define("mysql_password", default="test", help="Database Password")
23 |
--------------------------------------------------------------------------------
/xk_config/xk_url.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | #Design By Xiaok
4 |
5 | from xk_handler import *
6 |
7 | HandlersURL = [
8 | (r"/(|login)/?", xk_login.LoginHandler),
9 | (r"/logout", xk_login.LogoutHandler),
10 | (r"/dashboard/?", xk_index.IndexHandler),
11 | (r"/dns/domain", xk_dns.DnsDomainHandler),
12 | (r"/dns/record", xk_dns.DnsRecordHandler),
13 | (r"/dhcp/pool", xk_dhcp.DhcpPoolHandler),
14 | (r"/dhcp/host", xk_dhcp.DhcpHostHandler),
15 | (r"/public/api", xk_public.PublicAPIHandler),
16 | (r"/users", xk_users.UsersHandler),
17 | (r"/users/logs", xk_users.LoginLogsHandler),
18 | (r"/test", xk_test.TestHandler),
19 | #(r"/(favicon\.ico)", tornado.web.StaticFileHandler, dict(path=settings['static_path']+"images/icon")),
20 | ]
21 |
--------------------------------------------------------------------------------
/xk_db_sql/xk_dnsmasq.sql:
--------------------------------------------------------------------------------
1 | -- MySQL dump 10.13 Distrib 5.5.36-34.1, for Linux (x86_64)
2 | --
3 | -- Host: localhost Database: xk_dnsmasq
4 | -- ------------------------------------------------------
5 | -- Server version 5.5.36-34.1-log
6 |
7 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
8 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
9 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
10 | /*!40101 SET NAMES utf8 */;
11 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
12 | /*!40103 SET TIME_ZONE='+00:00' */;
13 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
14 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
15 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
16 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
17 |
18 | --
19 | -- Table structure for table `xk_dhcp_host`
20 | --
21 |
22 | DROP TABLE IF EXISTS `xk_dhcp_host`;
23 | /*!40101 SET @saved_cs_client = @@character_set_client */;
24 | /*!40101 SET character_set_client = utf8 */;
25 | CREATE TABLE `xk_dhcp_host` (
26 | `id` int(11) NOT NULL AUTO_INCREMENT,
27 | `hostname` varchar(50) DEFAULT NULL COMMENT '主机名',
28 | `mac` varchar(20) DEFAULT NULL COMMENT 'MAC地址',
29 | `ip` varchar(15) DEFAULT NULL COMMENT 'IP地址',
30 | `comment` varchar(30) DEFAULT NULL COMMENT '备注',
31 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
32 | `status` varchar(3) NOT NULL DEFAULT 'yes' COMMENT '规则状态',
33 | `action` varchar(10) NOT NULL DEFAULT 'allow' COMMENT '规则动作',
34 | PRIMARY KEY (`id`)
35 | ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
36 | /*!40101 SET character_set_client = @saved_cs_client */;
37 |
38 | --
39 | -- Dumping data for table `xk_dhcp_host`
40 | --
41 |
42 | LOCK TABLES `xk_dhcp_host` WRITE;
43 | /*!40000 ALTER TABLE `xk_dhcp_host` DISABLE KEYS */;
44 | INSERT INTO `xk_dhcp_host` VALUES (3,'rhel65xx','00:0c:29:f6:04:34','192.168.1.60','rhel 6.5xfff','2014-11-26 14:17:12','yes','allow'),(4,'test','00:0c:29:f6:04:35','192.168.1.61','dd','2014-11-26 14:27:22','yes','allow'),(5,'win7','00:0c:29:f6:04:29','192.168.1.7','win7x64','2014-11-26 14:39:51','yes','allow'),(6,'winxp','00:0c:29:f6:04:33','192.168.1.33','33xp','2014-11-26 15:29:01','yes','allow');
45 | /*!40000 ALTER TABLE `xk_dhcp_host` ENABLE KEYS */;
46 | UNLOCK TABLES;
47 |
48 | --
49 | -- Table structure for table `xk_domain`
50 | --
51 |
52 | DROP TABLE IF EXISTS `xk_domain`;
53 | /*!40101 SET @saved_cs_client = @@character_set_client */;
54 | /*!40101 SET character_set_client = utf8 */;
55 | CREATE TABLE `xk_domain` (
56 | `id` int(11) NOT NULL AUTO_INCREMENT,
57 | `domain` varchar(60) NOT NULL COMMENT '域名',
58 | `file` varchar(200) NOT NULL COMMENT '配置文件',
59 | `file_md5` varchar(64) NOT NULL COMMENT 'MD5值',
60 | `create_time` datetime NOT NULL COMMENT '创建时间',
61 | `up_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
62 | `comment` varchar(200) NOT NULL COMMENT '备注',
63 | `status` varchar(3) NOT NULL DEFAULT 'yes' COMMENT '状态',
64 | PRIMARY KEY (`id`)
65 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
66 | /*!40101 SET character_set_client = @saved_cs_client */;
67 |
68 | --
69 | -- Dumping data for table `xk_domain`
70 | --
71 |
72 | LOCK TABLES `xk_domain` WRITE;
73 | /*!40000 ALTER TABLE `xk_domain` DISABLE KEYS */;
74 | INSERT INTO `xk_domain` VALUES (1,'luxiaok.com','luxiaok.com.conf','5dcd3226a211b004c9376d864ab99d7f','2014-11-22 22:25:26','2014-11-24 14:28:25','测试域名','yes'),(2,'test.com','test.com.conf','6f91829bebd8663db73498090ab69557','2014-11-22 22:34:00','2014-11-22 19:47:02','测试域名2','yes'),(3,'qq.com','qq.com.conf','4228386eafc1a2f3dc4c908f84d34a6b','2014-11-23 17:58:32','2014-11-23 09:58:32','QQ域名','yes'),(4,'google.com','google.com.conf','1023883e5729868925ffca6032eb5300','2014-11-24 22:48:07','2014-11-24 15:34:25','Google','yes');
75 | /*!40000 ALTER TABLE `xk_domain` ENABLE KEYS */;
76 | UNLOCK TABLES;
77 |
78 | --
79 | -- Table structure for table `xk_login_logs`
80 | --
81 |
82 | DROP TABLE IF EXISTS `xk_login_logs`;
83 | /*!40101 SET @saved_cs_client = @@character_set_client */;
84 | /*!40101 SET character_set_client = utf8 */;
85 | CREATE TABLE `xk_login_logs` (
86 | `id` int(5) NOT NULL AUTO_INCREMENT,
87 | `uid` int(3) NOT NULL COMMENT '用户ID',
88 | `username` varchar(30) DEFAULT NULL COMMENT '登录用户名',
89 | `login_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登录时间',
90 | `login_host` varchar(15) DEFAULT NULL COMMENT '登录IP',
91 | `login_location` varchar(20) DEFAULT NULL COMMENT '登录地区',
92 | `login_status` int(1) NOT NULL DEFAULT '0' COMMENT '0:成功,1:失败,2:用户被禁用,3:用户名错误,4:密码错误,5:异常,6:未知状态',
93 | `user_agent` varchar(200) DEFAULT NULL COMMENT '用户代理',
94 | PRIMARY KEY (`id`)
95 | ) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;
96 | /*!40101 SET character_set_client = @saved_cs_client */;
97 |
98 | --
99 | -- Dumping data for table `xk_login_logs`
100 | --
101 |
102 | LOCK TABLES `xk_login_logs` WRITE;
103 | /*!40000 ALTER TABLE `xk_login_logs` DISABLE KEYS */;
104 | INSERT INTO `xk_login_logs` VALUES (1,1,'luxiaok','2014-11-22 09:03:00','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(2,1,'luxiaok','2014-11-22 09:03:08','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(3,1,'luxiaok','2014-11-22 09:06:16','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(4,2,'admin','2014-11-22 09:06:40','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(5,1,'luxiaok','2014-11-22 09:58:03','192.168.1.7',NULL,0,'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'),(6,1,'luxiaok','2014-11-22 10:03:53','192.168.1.7',NULL,0,'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'),(7,1,'luxiaok','2014-11-22 10:05:19','192.168.1.7',NULL,0,'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'),(8,1,'luxiaok','2014-11-22 10:20:29','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(9,1,'luxiaok','2014-11-23 02:38:29','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(10,1,'luxiaok','2014-11-23 03:20:17','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(11,1,'luxiaok','2014-11-23 03:25:42','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(12,1,'luxiaok','2014-11-23 04:16:41','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(13,1,'luxiaok','2014-11-23 04:20:18','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(14,1,'luxiaok','2014-11-23 04:27:27','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(15,1,'luxiaok','2014-11-23 08:03:08','192.168.1.7',NULL,0,'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'),(16,1,'luxiaok','2014-11-23 12:23:00','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(17,1,'luxiaok','2014-11-24 14:20:54','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(18,1,'luxiaok','2014-11-25 14:34:16','192.168.1.7',NULL,0,'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)'),(19,1,'luxiaok','2014-11-25 15:10:21','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36'),(20,1,'luxiaok','2014-11-26 12:51:41','192.168.1.7',NULL,0,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36');
105 | /*!40000 ALTER TABLE `xk_login_logs` ENABLE KEYS */;
106 | UNLOCK TABLES;
107 |
108 | --
109 | -- Table structure for table `xk_options`
110 | --
111 |
112 | DROP TABLE IF EXISTS `xk_options`;
113 | /*!40101 SET @saved_cs_client = @@character_set_client */;
114 | /*!40101 SET character_set_client = utf8 */;
115 | CREATE TABLE `xk_options` (
116 | `id` int(11) NOT NULL AUTO_INCREMENT,
117 | `type` varchar(20) DEFAULT NULL,
118 | `name` varchar(100) NOT NULL,
119 | `value` varchar(200) DEFAULT NULL,
120 | `comment` varchar(200) DEFAULT NULL,
121 | PRIMARY KEY (`id`),
122 | UNIQUE KEY `name` (`name`)
123 | ) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;
124 | /*!40101 SET character_set_client = @saved_cs_client */;
125 |
126 | --
127 | -- Dumping data for table `xk_options`
128 | --
129 |
130 | LOCK TABLES `xk_options` WRITE;
131 | /*!40000 ALTER TABLE `xk_options` DISABLE KEYS */;
132 | INSERT INTO `xk_options` VALUES (1,'dhcp','xk_dhcp_status','yes','DHCP开关'),(2,'dhcp','xk_dhcp_pool_start','192.168.1.11','DHCP地址池开始地址'),(3,'dhcp','xk_dhcp_pool_stop','192.168.1.101','DHCP地址池结束地址'),(4,'dhcp','xk_dhcp_pool_netmask','255.255.255.0','DHCP地址池子网掩码'),(5,'dhcp','xk_dhcp_pool_lease','6h','DHCP租约'),(6,'dhcp','xk_dhcp_pool_gw','192.168.1.254','DHCP默认网关'),(7,'dhcp','xk_dhcp_pool_dns1','114.114.114.114','DHCP主DNS服务器'),(8,'dhcp','xk_dhcp_pool_dns2','8.8.8.8','DHCP辅助DNS服务器'),(9,'dhcp','xk_dhcp_pool_domain','luxiaok.com','DHCP缺省域名'),(10,'dhcp','xk_dhcp_pool_ntp','','DHCP时间服务器'),(11,'dhcp','xk_dhcp_pool_comment','test','DHCP地址池备注'),(12,'dhcp','xk_dhcp_conf_md5','','DHCP配置文件的MD5值');
133 | /*!40000 ALTER TABLE `xk_options` ENABLE KEYS */;
134 | UNLOCK TABLES;
135 |
136 | --
137 | -- Table structure for table `xk_record`
138 | --
139 |
140 | DROP TABLE IF EXISTS `xk_record`;
141 | /*!40101 SET @saved_cs_client = @@character_set_client */;
142 | /*!40101 SET character_set_client = utf8 */;
143 | CREATE TABLE `xk_record` (
144 | `id` int(11) NOT NULL AUTO_INCREMENT,
145 | `did` int(11) NOT NULL COMMENT '域名ID',
146 | `record` varchar(50) NOT NULL COMMENT '主机记录',
147 | `type` varchar(10) NOT NULL COMMENT '记录类型',
148 | `value` varchar(50) NOT NULL COMMENT '记录值',
149 | `priority` int(11) DEFAULT NULL COMMENT 'MX优先级',
150 | `create_time` datetime NOT NULL COMMENT '创建时间',
151 | `up_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
152 | `comment` varchar(100) DEFAULT NULL COMMENT '备注',
153 | `status` varchar(3) NOT NULL DEFAULT 'yes' COMMENT '状态值',
154 | PRIMARY KEY (`id`)
155 | ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
156 | /*!40101 SET character_set_client = @saved_cs_client */;
157 |
158 | --
159 | -- Dumping data for table `xk_record`
160 | --
161 |
162 | LOCK TABLES `xk_record` WRITE;
163 | /*!40000 ALTER TABLE `xk_record` DISABLE KEYS */;
164 | INSERT INTO `xk_record` VALUES (1,1,'www2','A','192.168.1.12',NULL,'2014-11-22 23:23:00','2014-11-23 11:32:51','2222','yes'),(2,2,'blog','A','192.168.1.1',NULL,'2014-11-22 23:29:06','2014-11-22 16:59:01','测试博客','yes'),(4,2,'news','A','192.168.1.2',NULL,'2014-11-22 23:32:23','2014-11-22 17:02:03','新网页','yes'),(5,2,'mail','A','113.108.16.61',NULL,'2014-11-23 00:08:09','2014-11-22 16:08:09','','yes'),(7,2,'www','A','192.168.2.9',NULL,'2014-11-23 01:57:21','2014-11-22 17:57:21','','yes'),(8,1,'blog','A','192.168.1.99',NULL,'2014-11-23 02:06:54','2014-11-22 18:06:54','','yes'),(9,1,'@','MX','mail.luxiaok.com',50,'2014-11-23 03:05:35','2014-11-22 19:19:40','MX记录','yes'),(10,1,'mail','A','192.168.2.28',NULL,'2014-11-23 03:05:57','2014-11-22 19:05:57','','yes'),(11,2,'@','MX','mail.test.com',12,'2014-11-23 03:20:14','2014-11-22 19:20:14','','yes'),(12,2,'@','TXT','Hello World',NULL,'2014-11-23 03:24:57','2014-11-22 19:24:57','','yes'),(13,2,'hello','TXT','Hello Luxiaok',NULL,'2014-11-23 03:28:26','2014-11-22 19:28:26','','yes'),(14,2,'mail3','CNAME','mail.test.com',NULL,'2014-11-23 03:46:55','2014-11-22 19:46:55','','yes'),(15,1,'host1','CNAME','www.luxiaok.com',NULL,'2014-11-23 17:58:04','2014-11-24 14:28:24','','yes'),(16,3,'www','A','180.96.86.192',NULL,'2014-11-23 17:59:19','2014-11-23 09:59:19','','yes'),(17,1,'www','A','192.168.1.118',NULL,'2014-11-24 22:24:17','2014-11-24 14:24:17','','yes'),(18,4,'','A','192.88.1.88',NULL,'2014-11-24 22:48:33','2014-11-24 15:33:27','测试泛解析','yes'),(19,4,'www','A','192.168.1.1',NULL,'2014-11-24 23:34:21','2014-11-24 15:34:21','www','yes');
165 | /*!40000 ALTER TABLE `xk_record` ENABLE KEYS */;
166 | UNLOCK TABLES;
167 |
168 | --
169 | -- Table structure for table `xk_users`
170 | --
171 |
172 | DROP TABLE IF EXISTS `xk_users`;
173 | /*!40101 SET @saved_cs_client = @@character_set_client */;
174 | /*!40101 SET character_set_client = utf8 */;
175 | CREATE TABLE `xk_users` (
176 | `id` int(3) NOT NULL AUTO_INCREMENT,
177 | `username` varchar(20) NOT NULL,
178 | `name` varchar(30) NOT NULL,
179 | `password` varchar(64) NOT NULL,
180 | `mobile` varchar(15) DEFAULT NULL COMMENT '电话号码',
181 | `email` varchar(50) DEFAULT NULL COMMENT '电子邮件',
182 | `cdate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
183 | `mdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
184 | `mask` varchar(3) NOT NULL DEFAULT '999',
185 | `is_admin` varchar(3) NOT NULL DEFAULT 'no' COMMENT '是否为管理员',
186 | `status` varchar(3) NOT NULL DEFAULT 'yes',
187 | `comment` varchar(50) DEFAULT NULL,
188 | PRIMARY KEY (`id`),
189 | UNIQUE KEY `username` (`username`)
190 | ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用户';
191 | /*!40101 SET character_set_client = @saved_cs_client */;
192 |
193 | --
194 | -- Dumping data for table `xk_users`
195 | --
196 |
197 | LOCK TABLES `xk_users` WRITE;
198 | /*!40000 ALTER TABLE `xk_users` DISABLE KEYS */;
199 | INSERT INTO `xk_users` VALUES (1,'luxiaok','陆小K','6b1230a362a507f432b56d4694cb7846',NULL,NULL,'2014-11-22 16:37:50','2014-11-22 08:37:50','999','yes','yes','陆小K'),(2,'admin','管理员','21232f297a57a5a743894a0e4a801fc3',NULL,NULL,'2014-11-22 16:37:50','2014-11-22 08:37:50','999','yes','yes','系统管理员'),(3,'test','测试用户','098f6bcd4621d373cade4e832627b4f6',NULL,NULL,'2014-11-22 16:46:18','2014-11-22 08:46:18','999','no','no','测试用户');
200 | /*!40000 ALTER TABLE `xk_users` ENABLE KEYS */;
201 | UNLOCK TABLES;
202 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
203 |
204 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
205 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
206 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
207 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
208 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
209 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
210 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
211 |
212 | -- Dump completed on 2014-11-26 23:31:55
213 |
--------------------------------------------------------------------------------
/xk_handler/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # Desgin By Xiaok
3 | __all__ = [
4 | 'xk_dhcp',
5 | 'xk_dns',
6 | 'xk_index',
7 | 'xk_login',
8 | 'xk_public',
9 | 'xk_test',
10 | 'xk_users'
11 | ]
--------------------------------------------------------------------------------
/xk_handler/xk_dhcp.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | from xk_application.xk_main import *
5 |
6 | class DhcpPoolHandler(BaseHandler):
7 | @Auth
8 | def get(self):
9 | #
10 | dhcp_options = self.db.query('''select * from xk_options where type = "dhcp"''')
11 | dhcp = {}
12 | for i in dhcp_options:
13 | dhcp[i['name']] = i['value']
14 | self.render2("xk_dhcp_pool.html",dhcp=dhcp,dhcp_pool="active")
15 |
16 | @Auth
17 | def post(self):
18 | status = self.get_argument("status")
19 | range_start = self.get_argument("range_start")
20 | range_end = self.get_argument("range_end")
21 | netmask = self.get_argument("netmask")
22 | lease = self.get_argument("lease")
23 | router = self.get_argument("router")
24 | dns1 = self.get_argument("dns1")
25 | dns2 = self.get_argument("dns2")
26 | domain = self.get_argument("domain")
27 | ntp = self.get_argument("ntp",'')
28 | comment = self.get_argument("comment")
29 | #self.db.execute('''insert into xk_dhcp_pool ( name,range_start,range_end,netmask,router,dns1,dns2,domain,lease,comment )
30 | # values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)''',name,range_start,range_end,netmask,router,dns1,dns2,domain,lease,comment)
31 | self.db.execute('''
32 | insert into xk_options (name,value,comment) values
33 | ('xk_dhcp_status',%s,'DHCP开关'),
34 | ('xk_dhcp_pool_start',%s,'DHCP地址池开始地址'),
35 | ('xk_dhcp_pool_stop',%s,'DHCP地址池结束地址'),
36 | ('xk_dhcp_pool_netmask',%s,'DHCP地址池子网掩码'),
37 | ('xk_dhcp_pool_lease',%s,'DHCP租约'),
38 | ('xk_dhcp_pool_gw',%s,'DHCP默认网关'),
39 | ('xk_dhcp_pool_dns1',%s,'DHCP主DNS服务器'),
40 | ('xk_dhcp_pool_dns2',%s,'DHCP辅助DNS服务器'),
41 | ('xk_dhcp_pool_domain',%s,'DHCP缺省域名'),
42 | ('xk_dhcp_pool_ntp',%s,'DHCP时间服务器'),
43 | ('xk_dhcp_pool_comment',%s,'DHCP地址池备注')
44 | ON DUPLICATE KEY UPDATE name=values(name),value=values(value),comment=values(comment)
45 | ''',status,range_start,range_end,netmask,lease,router,dns1,dns2,domain,ntp,comment)
46 | self.write("1")
47 |
48 | class DhcpHostHandler(BaseHandler):
49 | @Auth
50 | def get(self):
51 | dhcp_hosts = self.db.query("select *,case when action = 'allow' then 'selected' else '' end as allow_selected, case when action = 'ignore' then 'selected' else '' end as ignore_selected from xk_dhcp_host")
52 | self.render2("xk_dhcp_host.html",dhcp_hosts=dhcp_hosts,dhcp_pool="active")
53 |
54 | @Auth
55 | def post(self):
56 | hostname = self.get_argument("hostname")
57 | mac = self.get_argument("mac")
58 | ip = self.get_argument("ip")
59 | action = self.get_argument("action")
60 | comment = self.get_argument("comment")
61 | fun = self.get_argument("fun","add")
62 | id_ = self.get_argument("id",0) # For Edit
63 | sql_mac = "select id,mac from xk_dhcp_host where mac = '%s'" % mac.lower()
64 | sql_ip = "select id,ip from xk_dhcp_host where ip = '%s'" % ip
65 | if fun == "edit":
66 | sql = " and id != %s" % id_
67 | sql_mac += sql
68 | sql_ip += sql
69 | check_mac = self.db.query(sql_mac)
70 | check_ip = self.db.query(sql_ip)
71 | if check_mac:
72 | self.write("2") # MAC地址冲突
73 | return
74 | if check_ip:
75 | self.write("3") # IP地址冲突
76 | return
77 | if fun == "add":
78 | self.db.execute(" insert into xk_dhcp_host (hostname,mac,ip,action,comment) values (%s,%s,%s,%s,%s) ",hostname,mac.lower(),ip,action,comment)
79 | else: # For Edit
80 | self.db.execute("update xk_dhcp_host set hostname = %s, mac = %s, ip = %s, action = %s, comment = %s where id = %s",hostname,mac,ip,action,comment,id_)
81 | self.write("1")
82 |
83 |
--------------------------------------------------------------------------------
/xk_handler/xk_dns.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | from xk_application.xk_main import *
5 |
6 | class DnsDomainHandler(BaseHandler):
7 | @Auth
8 | def get(self):
9 | #print self.get_login_url()
10 | #print self.current_user
11 | #print self.user_info()
12 | domains = self.db.query("select * from xk_domain")
13 | self.render2("xk_domain.html",domain="active",domains=domains)
14 |
15 | @Auth
16 | def post(self):
17 | domain = self.get_argument("domain")
18 | file = self.get_argument("file")
19 | comment = self.get_argument("comment")
20 | fun = self.get_argument("fun","add")
21 | if fun == "add":
22 | if_domain = self.db.get("select id,domain from xk_domain where domain = %s",domain)
23 | if if_domain:
24 | self.write("2")
25 | return
26 | f = open("/etc/dnsmasq.d/" + file,'w')
27 | f.write("# "+domain+"\n")
28 | f.close()
29 | file_md5 = self.get_md5("/etc/dnsmasq.d/"+file)
30 | self.db.execute("insert into xk_domain (domain,file,file_md5,create_time,comment) values (%s,%s,%s,%s,%s)",domain,file,file_md5,self.get_time(),comment)
31 | self.write("1")
32 | elif fun == "edit":
33 | id_ = self.get_argument("id")
34 | self.db.execute("update xk_domain set domain = %s, file = %s, comment = %s where id = %s",domain,file,comment,id_)
35 | self.write("1")
36 |
37 | class DnsRecordHandler(BaseHandler):
38 | @Auth
39 | def get(self):
40 | did = self.get_argument("did",0)
41 | domains = self.db.query("select id,domain from xk_domain where status = 'yes'")
42 | cur_domain = self.db.get("select * from xk_domain where id = %s",did)
43 | records = self.db.query("select * from xk_record where did = %s",did)
44 | self.render2("xk_record.html",record="active",domains=domains,did=int(did),records=records,cur_domain=cur_domain)
45 |
46 | @Auth
47 | def post(self):
48 | did = self.get_argument("did")
49 | record = self.get_argument("record")
50 | type = self.get_argument("type")
51 | value = self.get_argument("value")
52 | priority = self.get_argument("priority")
53 | comment = self.get_argument("comment")
54 | fun = self.get_argument("fun","add")
55 | if type == "MX":
56 | priority = int(priority)
57 | else:
58 | priority = None
59 | if fun == "add":
60 | self.db.execute("insert into xk_record (did,record,type,value,priority,comment,create_time) values (%s,%s,%s,%s,%s,%s,%s)",did,record,type,value,priority,comment,self.get_time())
61 | self.write("1")
62 | elif fun == "edit":
63 | id = self.get_argument("id")
64 | self.db.execute("update xk_record set record = %s, type = %s, value = %s, priority = %s, comment = %s where id = %s",record,type,value,priority,comment,id)
65 | self.write("1")
--------------------------------------------------------------------------------
/xk_handler/xk_index.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | from xk_application.xk_main import *
5 | import platform,os
6 |
7 | class IndexHandler(BaseHandler):
8 | def get_hostname(self):
9 | h = os.popen("hostname")
10 | return h.read().strip()
11 |
12 | # 获取服务器运行时间
13 | def get_uptime(self):
14 | f = open('/proc/uptime','r')
15 | r = f.read()
16 | u = r.split()
17 | f.close()
18 | uptime = self.format_seconds(int(float(u[0])))
19 | cpu_num = os.popen("cat /proc/cpuinfo | grep processor | wc -l")
20 | cpu_num = int(cpu_num.read().strip())
21 | free = int(float(u[1])) * 100 / (int(float(u[0]))*cpu_num)
22 | uptime['free'] = free
23 | return uptime
24 |
25 | def get_ip(self):
26 | r = os.popen("ip a | grep inet | grep -Ev 'inet6|127.0.0.1' | awk -F'[ /]+' '{print $3}'")
27 | r = r.read()
28 | ip = r.split()
29 | if len(ip) > 1:
30 | ip = ', '.join(ip)
31 | else:
32 | ip = ip[0]
33 | return ip
34 |
35 | def get_load(self):
36 | f = open('/proc/loadavg')
37 | l = f.read().split()
38 | f.close()
39 | loadavg_1 = l[0]
40 | loadavg_5 = l[1]
41 | loadavg_15 = l[2]
42 | return [loadavg_1,loadavg_5,loadavg_15]
43 |
44 | def get_mem(self):
45 | f = open('/proc/meminfo')
46 | m = f.readlines()
47 | f.close()
48 | mem = {}
49 | for n in m:
50 | if len(n) < 2 : continue
51 | name = n.split(':')[0]
52 | var = n.split()[1]
53 | mem[name] = int(var) * 1024 # 单位默认是K,乘以1024转换为字节
54 | mem['MemUsed'] = mem['MemTotal'] - mem['MemFree'] - mem['Buffers'] - mem['Cached']
55 | MemUsedPercent = mem['MemUsed'] * 100 / mem['MemTotal']
56 | mem['MemUsedPercent'] = MemUsedPercent
57 | return mem
58 |
59 | def get_hdd(self):
60 | d = os.statvfs('/')
61 | all = d.f_frsize * d.f_blocks
62 | free = d.f_frsize * d.f_bavail
63 | used = ( d.f_blocks - d.f_bavail ) * d.f_frsize
64 | usedPercent = ( d.f_blocks - d.f_bavail ) * 100 / d.f_blocks
65 | return {"all":all, "free":free, "used":used, "usedPercent":usedPercent}
66 |
67 | def net_stat(self):
68 | net = {}
69 | f = open("/proc/net/dev")
70 | lines = f.readlines()
71 | f.close()
72 | i = 1
73 | for line in lines:
74 | if i < 3 :
75 | i += 1
76 | continue
77 | con = line.split(':')
78 | name = con[0].split()[0]
79 | var = con[1].split()
80 | net[name] = var
81 | i += 1
82 | net_in = 0
83 | net_out = 0
84 | for i in net:
85 | if i == 'lo':continue
86 | net_in += int(net[i][0])
87 | net_out += int(net[i][8])
88 | #net_in = net_in / 1024 / 1024
89 | #net_out = net_out / 1024 /1024
90 | return {"in":net_in,"out":net_out}
91 |
92 | def get_os_version(self):
93 | OS = platform.linux_distribution()
94 | os_arch = platform.machine()
95 | if 'Red Hat Enterprise Linux Server' in OS:
96 | os_name = 'RHEL'
97 | else:
98 | os_name = OS[0]
99 | os_version = OS[1]
100 | return "%s %s %s" % ( os_name,os_version,os_arch)
101 |
102 | def get_dnsmasq(self):
103 | status = os.system("/etc/init.d/dnsmasq status")
104 | v1 = os.popen("dnsmasq --version | head -1 | awk '{print $3}'")
105 | version = v1.read().strip()
106 | return {"version":version, "status":status}
107 |
108 | def get_cpu(self):
109 | cpu = os.popen('top -bi -n 1').read().split('\n')[2]
110 | cpu = cpu.split(", ")[3].split('%')[0]
111 | return 100.0 - float(cpu)
112 |
113 | @Auth
114 | def get(self):
115 | #print self.get_login_url()
116 | #print self.current_user
117 | #print self.user_info()
118 | data = {
119 | "uptime":self.get_uptime(),
120 | "ip":self.get_ip(),
121 | "net":self.net_stat(),
122 | "mem":self.get_mem(),
123 | "load":self.get_load(),
124 | "os":self.get_os_version(),
125 | "hdd":self.get_hdd(),
126 | "dnsmasq":self.get_dnsmasq(),
127 | "hostname":self.get_hostname(),
128 | "cpu":self.get_cpu()
129 | }
130 | #print data
131 | self.render2("xk_index.html",dashboard="active",data=data)
132 |
--------------------------------------------------------------------------------
/xk_handler/xk_login.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | from xk_application.xk_main import *
5 |
6 | class LoginHandler(BaseHandler):
7 | def get(self,*args):
8 | #print args # 传入了一个login的参数进来了
9 | if self.current_user:
10 | return self.redirect('/dashboard')
11 | self.render2("xk_login.html")
12 |
13 | def post(self,*args):
14 | username = self.get_argument('username')
15 | password = self.get_argument('password')
16 | remember = self.get_argument('remember','no')
17 | user = self.db.get('''select id,username,status from xk_users where username = %s and password = md5(%s)''',username,password)
18 | if user:
19 | if user['status'] == 'no':
20 | self.write('''''')
21 | return
22 | else:
23 | self.write('''''')
24 | return
25 | # 获取客户端信息,并写入登录日志
26 | headers = self.request.headers
27 | login_host = self.request.remote_ip
28 | #login_host = "210.75.225.254" # For Test and Debug
29 | user_agent = headers.get('User-Agent')
30 | # 写登录日志
31 | self.db.execute(''' insert into xk_login_logs (uid,username,login_host,user_agent) values (%s,%s,%s,%s) ''',user['id'],user['username'],login_host,user_agent)
32 | # 登录成功,客户端写cooike
33 | if remember == 'yes':
34 | expires = 30
35 | else:
36 | expires = None
37 | self.set_secure_cookie('xk_auth_token',username,expires_days=expires)
38 | # 跳转到登录前的页面
39 | referer_url = self.get_argument("next", "/dashboard")
40 | self.redirect(referer_url)
41 |
42 | class LogoutHandler(BaseHandler):
43 | def get(self):
44 | self.clear_cookie("xk_auth_token")
45 | self. redirect(self.get_login_url())
--------------------------------------------------------------------------------
/xk_handler/xk_public.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | from xk_application.xk_main import *
5 | import os
6 |
7 | class PublicAPIHandler(BaseHandler):
8 | def reload_dhcp(self,file,force=False):
9 | dhcp_conf = self.db.query("select * from xk_options where type = 'dhcp'")
10 | d = {}
11 | for i in dhcp_conf:
12 | d[i['name']] = i['value']
13 | if d['xk_dhcp_status'] != 'yes':
14 | f = open(file,'w')
15 | f.write("# DHCP is stopped.")
16 | f.close()
17 | new_md5 = self.get_md5(file)
18 | self.db.execute("update xk_options set value = %s where name = 'xk_dhcp_conf_md5' and type = 'dhcp'",new_md5)
19 | sv_rt = os.system("/etc/init.d/dnsmasq restart")
20 | #return 5 # 停止DHCP
21 | return 2 # 返回成功状态码
22 | if force is False:
23 | check_md5 = self.get_md5(file)
24 | if check_md5 != d['xk_dhcp_conf_md5']:
25 | return 1 # MD5校验失败
26 | if not d['xk_dhcp_pool_domain']:
27 | d['xk_dhcp_pool_domain'] = 'luxiaok.com'
28 | if not d['xk_dhcp_pool_dns2']:
29 | d['xk_dhcp_pool_dns2'] = "8.8.8.8"
30 | conf = '''# Gen By Luxiaok
31 | # Address Pool
32 | dhcp-range=%s,%s,%s,%s
33 | # Gateway,3
34 | dhcp-option=option:router,%s
35 | # DNS Server
36 | dhcp-option=6,%s,%s
37 | # NTP Server,4 or 42
38 | #dhcp-option=42,202.120.2.101
39 | # DNS Domain
40 | dhcp-option=15,%s\n''' % (d['xk_dhcp_pool_start'],d['xk_dhcp_pool_stop'],d['xk_dhcp_pool_netmask'],d['xk_dhcp_pool_lease'],d['xk_dhcp_pool_gw'],d['xk_dhcp_pool_dns1'],d['xk_dhcp_pool_dns2'],d['xk_dhcp_pool_domain'])
41 | dhcp_hosts = self.db.query("select * from xk_dhcp_host where status = 'yes'")
42 | if dhcp_hosts:
43 | for i in dhcp_hosts:
44 | if i['action'] == 'allow':
45 | conf += "# %s\ndhcp-host=%s,%s\n" % (i['hostname'],i['mac'],i['ip'])
46 | else:
47 | conf += "# %s\ndhcp-host=%s,ignore\n" % (i['hostname'],i['mac'])
48 | try:
49 | f = open(file,'w')
50 | f.write(conf)
51 | except:
52 | return 4 # 写入配置失败
53 | finally:
54 | f.close()
55 | new_md5 = self.get_md5(file)
56 | #print new_md5
57 | self.db.execute("update xk_options set value = %s where name = 'xk_dhcp_conf_md5' and type = 'dhcp'",new_md5)
58 | sv_rt = os.system("/etc/init.d/dnsmasq restart")
59 | if sv_rt == 0:
60 | return 2 # 写入文件成功,重新加载配置成功
61 | else:
62 | return 3 # 重启服务失败
63 |
64 | @Auth
65 | def get(self):
66 | module = self.get_argument("module")
67 | fun = self.get_argument("fun")
68 | value = self.get_argument("value",None)
69 | id = self.get_argument("id",None)
70 | redirect_id = self.get_argument("did",None)
71 | if module == "record":
72 | if fun == "ch_status":
73 | self.db.execute("update xk_record set status = %s where id = %s",value,id)
74 | self.redirect("/dns/record?did="+redirect_id)
75 | elif fun == "del":
76 | self.db.execute("delete from xk_record where id = %s",id)
77 | self.redirect("/dns/record?did="+redirect_id)
78 | elif module == "domain":
79 | if fun == "ch_status":
80 | self.db.execute("update xk_domain set status = %s where id = %s",value,id)
81 | self.redirect("/dns/domain")
82 | elif fun == "del":
83 | # 获取该域名的配置文件
84 | domain = self.db.get("select * from xk_domain where id = %s",id)
85 | file = domain['file']
86 | file_md5 = domain['file_md5']
87 | # 删除该域名的DNSmasq的配置文件
88 | os.remove("/etc/dnsmasq.d/"+file)
89 | # 同时删除域名的所有记录
90 | self.db.execute("delete from xk_record where did = %s",id)
91 | # 删除域名
92 | self.db.execute("delete from xk_domain where id = %s",id)
93 | self.redirect("/domain")
94 | elif module == "dnsmasq": # 同步解析
95 | if fun == "update": # 从数据库更新配置文件并重新加载服务
96 | records = self.db.query("select r.record,d.domain,r.value,d.file,d.file_md5,r.type,r.priority from xk_record as r left join xk_domain as d on r.did = d.id where r.status = 'yes' and d.status = 'yes' and r.did = %s order by d.domain,inet_aton(r.value)",id)
97 | # A记录
98 | file_content = ''
99 | for i in records:
100 | if i['type'] == "A":
101 | file_content += "address=/" + i['record'] + "." + i['domain'] + "/" + i['value'] + "\n"
102 | elif i['type'] == "MX":
103 | file_content += "mx-host=" + i["domain"] + "," + i["value"] + "," + str(i['priority']) + "\n"
104 | elif i['type'] == "TXT":
105 | file_content += "txt-record="
106 | if i["record"] != "@":
107 | file_content += i['record'] + "."
108 | file_content += i["domain"] + ',"' + i["value"] + '"\n'
109 | elif i['type'] == "CNAME":
110 | file_content += "cname=" + i['record'] + "." + i["domain"] + "," + i["value"] + "\n"
111 |
112 | force = self.get_argument("force","no")
113 | check_md5 = i['file_md5']
114 | if force == "no":
115 | check_md5 = self.get_md5("/etc/dnsmasq.d/" + i['file'])
116 | if check_md5 == i['file_md5']:
117 | f = open("/etc/dnsmasq.d/" + i['file'],"w")
118 | f.write(file_content)
119 | f.close()
120 | sv_rt = os.system("/etc/init.d/dnsmasq restart")
121 | if sv_rt == 0:
122 | update_md5 = self.get_md5("/etc/dnsmasq.d/" + i['file'])
123 | self.db.execute("update xk_domain set file_md5 = %s where id = %s",update_md5,id)
124 | self.write("0") # 成功
125 | else:
126 | self.write("1") # 服务重启失败
127 | else: # md5匹配不上
128 | self.write("2") # 校验配置文件失败
129 |
130 | elif fun in ("reload","restart","start","stop"):
131 | sv_rt = os.system("/etc/init.d/dnsmasq " + fun)
132 | if sv_rt == 0:
133 | self.write("0") # 成功
134 | else:
135 | self.write("1") # 失败
136 | elif module == "dhcp_host":
137 | if fun == "ch_status":
138 | self.db.execute("update xk_dhcp_host set status = %s where id = %s",value,id)
139 | self.redirect("/dhcp/host")
140 | elif fun == "del":
141 | self.db.execute("delete from xk_dhcp_host where id = %s",id)
142 | self.redirect("/dhcp/host")
143 | elif fun == "ch_action":
144 | self.db.execute("update xk_dhcp_host set action = %s where id = %s",value,id)
145 | self.redirect("/dhcp/host")
146 | elif module == "dhcp":
147 | if fun == "reload":
148 | # Test URL: http://www.yourdomain.com:9886/public/api?module=dhcp&fun=reload&value=force
149 | if value == "force":
150 | force = True
151 | else:
152 | force = False
153 | rt = self.reload_dhcp("/etc/dnsmasq.d/dhcp.conf",force)
154 | self.write(str(rt))
155 | return
156 | elif module == "users":
157 | if fun == "ch_status":
158 | self.db.execute("update xk_users set status = %s where id = %s",value,id)
159 | self.redirect("/users")
160 | elif fun == "del":
161 | self.db.execute("delete from xk_users where id = %s",id)
162 | self.redirect("/users")
163 | elif module == "login_logs":
164 | if fun == "clear":
165 | try:
166 | self.db.execute("truncate xk_login_logs")
167 | self.write("1")
168 | return
169 | except:
170 | self.write("2")
171 |
172 |
173 |
--------------------------------------------------------------------------------
/xk_handler/xk_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | from xk_application.xk_main import *
5 |
6 | class TestHandler(BaseHandler):
7 | #@Auth
8 | def get(self):
9 | self.write("Hello,Test!")
--------------------------------------------------------------------------------
/xk_handler/xk_users.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | #-*- coding:utf8 -*-
3 | # Desgin By Xiaok
4 | from xk_application.xk_main import *
5 |
6 | class UsersHandler(BaseHandler):
7 | def get(self):
8 | users = self.db.query("select * from xk_users")
9 | self.render2("xk_users.html",users=users,users_admin="active")
10 |
11 | def post(self):
12 | username = self.get_argument("username",None)
13 | name = self.get_argument("name",None)
14 | email = self.get_argument("email",None)
15 | mobile = self.get_argument("mobile",None)
16 | password = self.get_argument("password",None)
17 | comment = self.get_argument("comment",None)
18 | id = self.get_argument("id",None)
19 | fun = self.get_argument("fun")
20 | if fun == "add":
21 | check_user = self.db.get("select id,username,name from xk_users where username = %s",username)
22 | if check_user:
23 | self.write("2")
24 | return
25 | self.db.execute("insert into xk_users (username,name,email,mobile,password,comment,cdate) values (%s,%s,%s,%s,md5(%s),%s,CURRENT_TIMESTAMP)",username,name,email,mobile,password,comment)
26 | self.write("1")
27 | return
28 | elif fun == "edit":
29 | self.db.execute("update xk_users set name=%s,email=%s,mobile=%s,comment=%s where id=%s",name,email,mobile,comment,id)
30 | self.write("1")
31 | elif fun == "pass":
32 | self.db.execute("update xk_users set password=md5(%s) where id=%s",password,id)
33 | self.write("1")
34 |
35 | class LoginLogsHandler(BaseHandler):
36 | def get(self):
37 | logs = self.db.query("select * from xk_login_logs")
38 | self.render2("xk_users_logs.html",logs=logs,users_logs="active")
39 |
--------------------------------------------------------------------------------
/xk_html/xk_dhcp_host.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | DHCP管理 - DnsMasqWeb - Desgin By Xiaok
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {% include "xk_top_nav.html" %}
17 |
18 | {% include "xk_nav.html" %}
19 |
20 |
DHCP绑定规则 | 地址池管理
21 |
22 |
23 |
24 |
25 |
26 |
66 |
67 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
241 | {% include "xk_footer.html" %}
242 |
243 |
--------------------------------------------------------------------------------
/xk_html/xk_dhcp_pool.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | DHCP管理 - DnsMasqWeb - Desgin By Xiaok
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {% include "xk_top_nav.html" %}
18 |
19 | {% include "xk_nav.html" %}
20 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
193 | {% include "xk_footer.html" %}
194 |
195 |
--------------------------------------------------------------------------------
/xk_html/xk_domain.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 域名管理 - DnsMasqWeb - Desgin By Xiaok
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {% include "xk_top_nav.html" %}
17 |
18 | {% include "xk_nav.html" %}
19 |
96 |
97 |
98 |
99 |
100 |
101 |
191 | {% include "xk_footer.html" %}
192 |
193 |
--------------------------------------------------------------------------------
/xk_html/xk_footer.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/xk_html/xk_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | DnsMasq控制台 - Desgin By Xiaok
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {% include "xk_top_nav.html" %}
18 |
19 | {% include "xk_nav.html" %}
20 |
21 |
22 | 控制中心
23 |
24 |
40 |
41 |
42 |
系统信息
43 |
44 | -
45 |
46 | 主机名 {{data['hostname']}}
47 | Refresh
48 | Reboot
49 | Shutdown
50 | 操作系统 {{data['os']}}
51 |
52 | -
53 | IP地址 {{data['ip']}}
54 | 流出流量 {{format_size(data['net']['out'])}} | 流入流量 {{format_size(data['net']['in'])}}
55 |
56 | -
57 | CPU使用率 {{data['cpu']}}%
58 |
59 |
60 | -
61 | 系统空闲率 {{data['uptime']['free']}}%
62 |
63 |
64 |
65 |
66 |
67 |
系统状态
68 |
69 | -
70 | {% if data['dnsmasq']['status'] == 0 %}
71 | {% set st_color = 'green' %}
72 | {% set st_msg = '运行中 ...' %}
73 | {% set next_run = 'stop' %}
74 | {% set next_run_msg = '停止' %}
75 | {% else %}
76 | {% set st_color = 'red' %}
77 | {% set st_msg = '服务异常' %}
78 | {% set next_run = 'start' %}
79 | {% set next_run_msg = '启动' %}
80 | {% endif %}
81 |
82 | DNSmasq {{st_msg}}
83 | Relaod
84 | Restart
85 | {{next_run | title}}
86 | 版本 {{data['dnsmasq']['version']}}
87 |
88 | -
89 | 系统负载
90 | 1分钟 {{data['load'][0]}} | 5分钟 {{data['load'][1]}} | 15分钟 {{data['load'][2]}}
91 |
92 | -
93 | 磁盘使用 {{format_size(data['hdd']['used'])}} / {{format_size(data['hdd']['all'])}} | {{data['hdd']['usedPercent']}}%
94 |
95 |
96 | -
97 | 内存使用 {{format_size(data['mem']['MemUsed'])}} / {{format_size(data['mem']['MemTotal'])}} | {{data['mem']['MemUsedPercent']}}%
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | {% include "xk_footer.html" %}
108 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/xk_html/xk_login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Login - DNSmasqWeb - Desgin By Xiaok
6 |
7 |
8 |
9 |
10 |
23 |
27 |
28 |
--------------------------------------------------------------------------------
/xk_html/xk_nav.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 | -
8 | 控制中心
9 |
10 | -
11 | 域名管理
12 |
13 | -
14 | DNS管理
15 |
16 | -
17 | DHCP管理
18 |
19 | -
20 | 消息中心
21 |
22 | -
23 | 系统设置
24 |
25 |
28 | -
29 | 用户管理
30 |
31 | -
32 | 添加用户
33 |
34 | -
35 | 日志管理
36 |
37 | -
38 |
39 | -
40 | 帮助
41 |
42 |
45 | -
46 | 关于项目
47 |
48 | -
49 | 关于作者
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/xk_html/xk_record.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 记录管理 - DnsMasqWeb - Desgin By Xiaok
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | {% include "xk_top_nav.html" %}
20 |
21 | {% include "xk_nav.html" %}
22 |
137 |
138 |
139 |
265 | {% include "xk_footer.html" %}
266 |
267 |
--------------------------------------------------------------------------------
/xk_html/xk_top_nav.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/xk_html/xk_users.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 用户管理 - DnsMasqWeb - Desgin By Xiaok
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {% include "xk_top_nav.html" %}
17 |
18 | {% include "xk_nav.html" %}
19 |
20 |
21 | 用户管理
22 |
23 |
24 |
25 |
26 |
27 |
99 |
104 |
105 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 | {% include "xk_footer.html" %}
152 |
153 |
--------------------------------------------------------------------------------
/xk_html/xk_users_logs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 用户登录日志管理 - DnsMasqWeb - Desgin By Xiaok
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {% include "xk_top_nav.html" %}
17 |
18 | {% include "xk_nav.html" %}
19 |
20 |
21 | 用户登录日志
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | # |
30 | UID |
31 | 用户名 |
32 | 姓名 |
33 | 登录时间 |
34 | 登录主机 |
35 | 登录地区 |
36 | 用户代理 |
37 |
38 |
39 |
40 | {% for log in logs %}
41 |
42 | {{ loop.index }} |
43 | {{ log['uid'] }} |
44 | {{ log['username'] }} |
45 | |
46 | {{ log['login_time'] }} |
47 | {{ log['login_host'] }} |
48 | {{ log['login_localtion'] or '' }} |
49 | {{ log['user_agent'] | truncate(40)}} |
50 |
51 | {% endfor %}
52 |
53 |
54 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
91 | {% include "xk_footer.html" %}
92 |
93 |
--------------------------------------------------------------------------------
/xk_screenshot/xk_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_screenshot/xk_dashboard.png
--------------------------------------------------------------------------------
/xk_screenshot/xk_dhcp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_screenshot/xk_dhcp.png
--------------------------------------------------------------------------------
/xk_screenshot/xk_domain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_screenshot/xk_domain.png
--------------------------------------------------------------------------------
/xk_screenshot/xk_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_screenshot/xk_login.png
--------------------------------------------------------------------------------
/xk_screenshot/xk_record.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_screenshot/xk_record.png
--------------------------------------------------------------------------------
/xk_static/bootstrap/css/bootstrap-responsive.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Responsive v2.3.2
3 | *
4 | * Copyright 2013 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 by @mdo and @fat.
9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
10 |
--------------------------------------------------------------------------------
/xk_static/bootstrap/img/glyphicons-halflings-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_static/bootstrap/img/glyphicons-halflings-white.png
--------------------------------------------------------------------------------
/xk_static/bootstrap/img/glyphicons-halflings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_static/bootstrap/img/glyphicons-halflings.png
--------------------------------------------------------------------------------
/xk_static/bootstrap/js/bootstrap.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap.js by @fat & @mdo
3 | * Copyright 2013 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(".dropdown-backdrop").remove(),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||("ontouchstart"in document.documentElement&&e('').insertBefore(e(this)).on("click",r),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);
--------------------------------------------------------------------------------
/xk_static/css/bootstrap-switch.css:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-switch - v3.2.2
3 | * http://www.bootstrap-switch.org
4 | * ========================================================================
5 | * Copyright 2012-2013 Mattia Larentis
6 | *
7 | * ========================================================================
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | .clearfix {
23 | *zoom: 1;
24 | }
25 | .clearfix:before,
26 | .clearfix:after {
27 | display: table;
28 | content: "";
29 | line-height: 0;
30 | }
31 | .clearfix:after {
32 | clear: both;
33 | }
34 | .hide-text {
35 | font: 0/0 a;
36 | color: transparent;
37 | text-shadow: none;
38 | background-color: transparent;
39 | border: 0;
40 | }
41 | .input-block-level {
42 | display: block;
43 | width: 100%;
44 | min-height: 30px;
45 | -webkit-box-sizing: border-box;
46 | -moz-box-sizing: border-box;
47 | box-sizing: border-box;
48 | }
49 | .bootstrap-switch {
50 | display: inline-block;
51 | cursor: pointer;
52 | -webkit-border-radius: 5px;
53 | -moz-border-radius: 5px;
54 | border-radius: 5px;
55 | border: 1px solid;
56 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
57 | position: relative;
58 | text-align: left;
59 | overflow: hidden;
60 | line-height: 8px;
61 | -webkit-user-select: none;
62 | -moz-user-select: none;
63 | -ms-user-select: none;
64 | -o-user-select: none;
65 | user-select: none;
66 | vertical-align: middle;
67 | min-width: 100px;
68 | -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
69 | -moz-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
70 | -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
71 | transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
72 | }
73 | .bootstrap-switch.bootstrap-switch-mini {
74 | min-width: 71px;
75 | }
76 | .bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,
77 | .bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,
78 | .bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label {
79 | padding-bottom: 4px;
80 | padding-top: 4px;
81 | font-size: 10px;
82 | line-height: 9px;
83 | }
84 | .bootstrap-switch.bootstrap-switch-small {
85 | min-width: 79px;
86 | }
87 | .bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,
88 | .bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,
89 | .bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label {
90 | padding-bottom: 3px;
91 | padding-top: 3px;
92 | font-size: 12px;
93 | line-height: 18px;
94 | }
95 | .bootstrap-switch.bootstrap-switch-large {
96 | min-width: 120px;
97 | }
98 | .bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,
99 | .bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,
100 | .bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label {
101 | padding-bottom: 9px;
102 | padding-top: 9px;
103 | font-size: 16px;
104 | line-height: normal;
105 | }
106 | .bootstrap-switch.bootstrap-switch-disabled,
107 | .bootstrap-switch.bootstrap-switch-readonly,
108 | .bootstrap-switch.bootstrap-switch-indeterminate {
109 | opacity: 0.5;
110 | filter: alpha(opacity=50);
111 | cursor: default !important;
112 | }
113 | .bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,
114 | .bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,
115 | .bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,
116 | .bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,
117 | .bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,
118 | .bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,
119 | .bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,
120 | .bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label,
121 | .bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label {
122 | cursor: default !important;
123 | }
124 | .bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container {
125 | -webkit-transition: margin-left 0.5s;
126 | -moz-transition: margin-left 0.5s;
127 | -o-transition: margin-left 0.5s;
128 | transition: margin-left 0.5s;
129 | }
130 | .bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-on {
131 | -webkit-border-top-left-radius: 0;
132 | -moz-border-radius-topleft: 0;
133 | border-top-left-radius: 0;
134 | -webkit-border-bottom-left-radius: 0;
135 | -moz-border-radius-bottomleft: 0;
136 | border-bottom-left-radius: 0;
137 | -webkit-border-top-right-radius: 4px;
138 | -moz-border-radius-topright: 4px;
139 | border-top-right-radius: 4px;
140 | -webkit-border-bottom-right-radius: 4px;
141 | -moz-border-radius-bottomright: 4px;
142 | border-bottom-right-radius: 4px;
143 | }
144 | .bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-off {
145 | -webkit-border-top-right-radius: 0;
146 | -moz-border-radius-topright: 0;
147 | border-top-right-radius: 0;
148 | -webkit-border-bottom-right-radius: 0;
149 | -moz-border-radius-bottomright: 0;
150 | border-bottom-right-radius: 0;
151 | -webkit-border-top-left-radius: 4px;
152 | -moz-border-radius-topleft: 4px;
153 | border-top-left-radius: 4px;
154 | -webkit-border-bottom-left-radius: 4px;
155 | -moz-border-radius-bottomleft: 4px;
156 | border-bottom-left-radius: 4px;
157 | }
158 | .bootstrap-switch.bootstrap-switch-focused {
159 | border-color: rgba(82, 168, 236, 0.8);
160 | outline: 0;
161 | outline: thin dotted \9;
162 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82, 168, 236, .6);
163 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82, 168, 236, .6);
164 | box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82, 168, 236, .6);
165 | }
166 | .bootstrap-switch.bootstrap-switch-on .bootstrap-switch-container,
167 | .bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-off .bootstrap-switch-container {
168 | margin-left: 0%;
169 | }
170 | .bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label,
171 | .bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-off .bootstrap-switch-label {
172 | -webkit-border-top-right-radius: 4px;
173 | -moz-border-radius-topright: 4px;
174 | border-top-right-radius: 4px;
175 | -webkit-border-bottom-right-radius: 4px;
176 | -moz-border-radius-bottomright: 4px;
177 | border-bottom-right-radius: 4px;
178 | }
179 | .bootstrap-switch.bootstrap-switch-off .bootstrap-switch-container,
180 | .bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-on .bootstrap-switch-container {
181 | margin-left: -50%;
182 | }
183 | .bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label,
184 | .bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-on .bootstrap-switch-label {
185 | -webkit-border-top-left-radius: 4px;
186 | -moz-border-radius-topleft: 4px;
187 | border-top-left-radius: 4px;
188 | -webkit-border-bottom-left-radius: 4px;
189 | -moz-border-radius-bottomleft: 4px;
190 | border-bottom-left-radius: 4px;
191 | }
192 | .bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-container {
193 | margin-left: -25%;
194 | }
195 | .bootstrap-switch .bootstrap-switch-container {
196 | display: inline-block;
197 | width: 150%;
198 | top: 0;
199 | -webkit-border-radius: 4px;
200 | -moz-border-radius: 4px;
201 | border-radius: 4px;
202 | -webkit-transform: translate3d(0, 0, 0);
203 | -moz-transform: translate3d(0, 0, 0);
204 | -o-transform: translate3d(0, 0, 0);
205 | transform: translate3d(0, 0, 0);
206 | }
207 | .bootstrap-switch .bootstrap-switch-handle-on,
208 | .bootstrap-switch .bootstrap-switch-handle-off,
209 | .bootstrap-switch .bootstrap-switch-label {
210 | -webkit-box-sizing: border-box;
211 | -moz-box-sizing: border-box;
212 | box-sizing: border-box;
213 | cursor: pointer;
214 | display: inline-block !important;
215 | height: 100%;
216 | padding-bottom: 4px;
217 | padding-top: 4px;
218 | font-size: 14px;
219 | line-height: 20px;
220 | }
221 | .bootstrap-switch .bootstrap-switch-handle-on,
222 | .bootstrap-switch .bootstrap-switch-handle-off {
223 | text-align: center;
224 | z-index: 1;
225 | width: 33.333333333%;
226 | }
227 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary,
228 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary {
229 | color: #ffffff;
230 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
231 | background-color: #005fcc;
232 | background-image: -moz-linear-gradient(top, #0044cc, #0088cc);
233 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0044cc), to(#0088cc));
234 | background-image: -webkit-linear-gradient(top, #0044cc, #0088cc);
235 | background-image: -o-linear-gradient(top, #0044cc, #0088cc);
236 | background-image: linear-gradient(to bottom, #0044cc, #0088cc);
237 | background-repeat: repeat-x;
238 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0044cc', endColorstr='#ff0088cc', GradientType=0);
239 | border-color: #0088cc #0088cc #005580;
240 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
241 | *background-color: #0088cc;
242 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
243 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
244 | }
245 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary:hover,
246 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary:hover,
247 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary:focus,
248 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary:focus,
249 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary:active,
250 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary:active,
251 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary.active,
252 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary.active,
253 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary.disabled,
254 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary.disabled,
255 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary[disabled],
256 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary[disabled] {
257 | color: #ffffff;
258 | background-color: #0088cc;
259 | *background-color: #0077b3;
260 | }
261 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary:active,
262 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary:active,
263 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary.active,
264 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary.active {
265 | background-color: #006699 \9;
266 | }
267 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info,
268 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info {
269 | color: #ffffff;
270 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
271 | background-color: #41a7c5;
272 | background-image: -moz-linear-gradient(top, #2f96b4, #5bc0de);
273 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#2f96b4), to(#5bc0de));
274 | background-image: -webkit-linear-gradient(top, #2f96b4, #5bc0de);
275 | background-image: -o-linear-gradient(top, #2f96b4, #5bc0de);
276 | background-image: linear-gradient(to bottom, #2f96b4, #5bc0de);
277 | background-repeat: repeat-x;
278 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff2f96b4', endColorstr='#ff5bc0de', GradientType=0);
279 | border-color: #5bc0de #5bc0de #28a1c5;
280 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
281 | *background-color: #5bc0de;
282 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
283 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
284 | }
285 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info:hover,
286 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info:hover,
287 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info:focus,
288 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info:focus,
289 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info:active,
290 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info:active,
291 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info.active,
292 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info.active,
293 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info.disabled,
294 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info.disabled,
295 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info[disabled],
296 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info[disabled] {
297 | color: #ffffff;
298 | background-color: #5bc0de;
299 | *background-color: #46b8da;
300 | }
301 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info:active,
302 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info:active,
303 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info.active,
304 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info.active {
305 | background-color: #31b0d5 \9;
306 | }
307 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success,
308 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success {
309 | color: #ffffff;
310 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
311 | background-color: #58b058;
312 | background-image: -moz-linear-gradient(top, #51a351, #62c462);
313 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#51a351), to(#62c462));
314 | background-image: -webkit-linear-gradient(top, #51a351, #62c462);
315 | background-image: -o-linear-gradient(top, #51a351, #62c462);
316 | background-image: linear-gradient(to bottom, #51a351, #62c462);
317 | background-repeat: repeat-x;
318 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff51a351', endColorstr='#ff62c462', GradientType=0);
319 | border-color: #62c462 #62c462 #3b9e3b;
320 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
321 | *background-color: #62c462;
322 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
323 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
324 | }
325 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success:hover,
326 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success:hover,
327 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success:focus,
328 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success:focus,
329 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success:active,
330 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success:active,
331 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success.active,
332 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success.active,
333 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success.disabled,
334 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success.disabled,
335 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success[disabled],
336 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success[disabled] {
337 | color: #ffffff;
338 | background-color: #62c462;
339 | *background-color: #4fbd4f;
340 | }
341 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success:active,
342 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success:active,
343 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success.active,
344 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success.active {
345 | background-color: #42b142 \9;
346 | }
347 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning,
348 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning {
349 | color: #ffffff;
350 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
351 | background-color: #f9a123;
352 | background-image: -moz-linear-gradient(top, #f89406, #fbb450);
353 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f89406), to(#fbb450));
354 | background-image: -webkit-linear-gradient(top, #f89406, #fbb450);
355 | background-image: -o-linear-gradient(top, #f89406, #fbb450);
356 | background-image: linear-gradient(to bottom, #f89406, #fbb450);
357 | background-repeat: repeat-x;
358 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff89406', endColorstr='#fffbb450', GradientType=0);
359 | border-color: #fbb450 #fbb450 #f89406;
360 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
361 | *background-color: #fbb450;
362 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
363 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
364 | }
365 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning:hover,
366 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning:hover,
367 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning:focus,
368 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning:focus,
369 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning:active,
370 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning:active,
371 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning.active,
372 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning.active,
373 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning.disabled,
374 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning.disabled,
375 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning[disabled],
376 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning[disabled] {
377 | color: #ffffff;
378 | background-color: #fbb450;
379 | *background-color: #faa937;
380 | }
381 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning:active,
382 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning:active,
383 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning.active,
384 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning.active {
385 | background-color: #fa9f1e \9;
386 | }
387 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger,
388 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger {
389 | color: #ffffff;
390 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
391 | background-color: #d14641;
392 | background-image: -moz-linear-gradient(top, #bd362f, #ee5f5b);
393 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#bd362f), to(#ee5f5b));
394 | background-image: -webkit-linear-gradient(top, #bd362f, #ee5f5b);
395 | background-image: -o-linear-gradient(top, #bd362f, #ee5f5b);
396 | background-image: linear-gradient(to bottom, #bd362f, #ee5f5b);
397 | background-repeat: repeat-x;
398 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffbd362f', endColorstr='#ffee5f5b', GradientType=0);
399 | border-color: #ee5f5b #ee5f5b #e51d18;
400 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
401 | *background-color: #ee5f5b;
402 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
403 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
404 | }
405 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger:hover,
406 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger:hover,
407 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger:focus,
408 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger:focus,
409 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger:active,
410 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger:active,
411 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger.active,
412 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger.active,
413 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger.disabled,
414 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger.disabled,
415 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger[disabled],
416 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger[disabled] {
417 | color: #ffffff;
418 | background-color: #ee5f5b;
419 | *background-color: #ec4844;
420 | }
421 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger:active,
422 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger:active,
423 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger.active,
424 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger.active {
425 | background-color: #e9322d \9;
426 | }
427 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default,
428 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default {
429 | color: #333333;
430 | text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
431 | background-color: #f0f0f0;
432 | background-image: -moz-linear-gradient(top, #e6e6e6, #ffffff);
433 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#e6e6e6), to(#ffffff));
434 | background-image: -webkit-linear-gradient(top, #e6e6e6, #ffffff);
435 | background-image: -o-linear-gradient(top, #e6e6e6, #ffffff);
436 | background-image: linear-gradient(to bottom, #e6e6e6, #ffffff);
437 | background-repeat: repeat-x;
438 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6', endColorstr='#ffffffff', GradientType=0);
439 | border-color: #ffffff #ffffff #d9d9d9;
440 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
441 | *background-color: #ffffff;
442 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
443 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
444 | }
445 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default:hover,
446 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default:hover,
447 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default:focus,
448 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default:focus,
449 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default:active,
450 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default:active,
451 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default.active,
452 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default.active,
453 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default.disabled,
454 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default.disabled,
455 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default[disabled],
456 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default[disabled] {
457 | color: #333333;
458 | background-color: #ffffff;
459 | *background-color: #f2f2f2;
460 | }
461 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default:active,
462 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default:active,
463 | .bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default.active,
464 | .bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default.active {
465 | background-color: #e6e6e6 \9;
466 | }
467 | .bootstrap-switch .bootstrap-switch-label {
468 | text-align: center;
469 | margin-top: -1px;
470 | margin-bottom: -1px;
471 | z-index: 100;
472 | width: 33.333333333%;
473 | border-left: 1px solid #cccccc;
474 | border-right: 1px solid #cccccc;
475 | color: #333333;
476 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
477 | background-color: #f5f5f5;
478 | background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
479 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
480 | background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
481 | background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
482 | background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
483 | background-repeat: repeat-x;
484 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
485 | border-color: #e6e6e6 #e6e6e6 #bfbfbf;
486 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
487 | *background-color: #e6e6e6;
488 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
489 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
490 | }
491 | .bootstrap-switch .bootstrap-switch-label:hover,
492 | .bootstrap-switch .bootstrap-switch-label:focus,
493 | .bootstrap-switch .bootstrap-switch-label:active,
494 | .bootstrap-switch .bootstrap-switch-label.active,
495 | .bootstrap-switch .bootstrap-switch-label.disabled,
496 | .bootstrap-switch .bootstrap-switch-label[disabled] {
497 | color: #333333;
498 | background-color: #e6e6e6;
499 | *background-color: #d9d9d9;
500 | }
501 | .bootstrap-switch .bootstrap-switch-label:active,
502 | .bootstrap-switch .bootstrap-switch-label.active {
503 | background-color: #cccccc \9;
504 | }
505 | .bootstrap-switch .bootstrap-switch-handle-on {
506 | -webkit-border-top-left-radius: 4px;
507 | -moz-border-radius-topleft: 4px;
508 | border-top-left-radius: 4px;
509 | -webkit-border-bottom-left-radius: 4px;
510 | -moz-border-radius-bottomleft: 4px;
511 | border-bottom-left-radius: 4px;
512 | }
513 | .bootstrap-switch .bootstrap-switch-handle-off {
514 | -webkit-border-top-right-radius: 4px;
515 | -moz-border-radius-topright: 4px;
516 | border-top-right-radius: 4px;
517 | -webkit-border-bottom-right-radius: 4px;
518 | -moz-border-radius-bottomright: 4px;
519 | border-bottom-right-radius: 4px;
520 | }
521 | .bootstrap-switch input[type='radio'],
522 | .bootstrap-switch input[type='checkbox'] {
523 | position: absolute !important;
524 | top: 0;
525 | left: 0;
526 | opacity: 0;
527 | filter: alpha(opacity=0);
528 | z-index: -1;
529 | }
530 | .bootstrap-switch input[type='radio'].form-control,
531 | .bootstrap-switch input[type='checkbox'].form-control {
532 | height: auto;
533 | }
534 |
--------------------------------------------------------------------------------
/xk_static/css/xk_dnsmasqweb.css:
--------------------------------------------------------------------------------
1 | /* Akira CSS by Shawn Drew */
2 |
3 | /* general */
4 | body {padding-top:10px; padding-bottom:10px;}
5 |
6 | h1 {padding-bottom:0.2em;}
7 |
8 | .meta {color:#999; font-size:.9em; display:block;}
9 | .meta em {font-style:normal; font-weight:bold;}
10 |
11 | /* login */
12 | #login-page.container {width:320px;}
13 |
14 | /* dashboard */
15 | .summary {display:table; width:100%; padding:0; margin:0 0 20px 0;}
16 | .summary ul {margin:0; padding:0; overflow:hidden; display:table-row;}
17 | .summary li {margin:0; padding:19px; display:table-cell; border-right:1px solid #eee;}
18 | .summary li:last-child {border:none;}
19 | .summary a {display:block; font-size:1.2em; line-height:1.4em; text-transform:uppercase; color:#000;}
20 | .summary .count {display:block; font-size:1.75em; font-weight:bold;}
21 |
22 | /* dashboard - ie fixes */
23 | .ie7 .summary {display:block;}
24 | .ie7 .summary ul {margin:0; padding:0; overflow:hidden; display:block;}
25 | .ie7 .summary li {float:left;}
26 |
27 | .ielt9 .summary .last {border:none;}
28 |
29 | /* tasks */
30 | .tasks {margin:0; padding:0;}
31 | .tasks li {list-style-type:none; padding-bottom:0.3em;}
32 | .tasks input {vertical-align:baseline;}
33 | .tasks .meta {padding-left:18px;}
34 | .tasks.done {opacity:0.8;}
35 |
36 | /* messages */
37 | .messages {margin:0; padding:0;}
38 | .messages .messages {padding-top:19px;}
39 | .messages li {list-style-type:none; padding-bottom:0.3em;}
40 | .messages .well {padding:19px;}
41 | .messages .messages .well {border:none; -webkit-box-shadow:none;-moz-box-shadow:none; box-shadow:none; border-left:3px solid #eee;border-left:3px solid rgba(0, 0, 0, 0.05);}
42 |
43 | /* blank slate */
44 | .blank-slate {text-align:center;}
45 |
46 | /* files */
47 | .files li {list-style-type:none;}
48 | .files .meta {padding-left:18px;}
49 |
50 | .zebra-list {margin:0 0 18px 0; padding:0;}
51 | .zebra-list li {border:1px solid #DDD; padding:8px; border-bottom:none;}
52 | .zebra-list li:nth-child(odd) {background-color:#F9F9F9;}
53 | .zebra-list li:first-child {-webkit-border-radius:4px 4px 0 0; -moz-border-radius:4px 4px 0 0; border-radius:4px 4px 0 0;}
54 | .zebra-list li:last-child {border-bottom:1px solid #DDD; -webkit-border-radius:0 0 4px 4px; -moz-border-radius:0 0 4px 4px; border-radius:0 0 4px 4px;}
55 |
56 | /* 覆盖bootstrap中table做对齐的样式 */
57 | .table th,
58 | .table td {
59 | text-align: center;
60 | vertical-align: middle;
61 | }
62 |
63 | .display_no {
64 | display: none;
65 | }
66 |
--------------------------------------------------------------------------------
/xk_static/css/xk_login.css:
--------------------------------------------------------------------------------
1 | body{
2 | background: #444 url(../images/login_bg.png);
3 | font-family:"Microsoft YaHei";
4 | }
5 | .loginBox{
6 | width:280px;
7 | height:220px;
8 | padding:0 20px;
9 | border:1px solid #fff;
10 | color:#000;
11 | border-radius:8px;
12 | background: white;
13 | box-shadow:0 0 15px #222;
14 | background: -moz-linear-gradient(top, #fff, #efefef 8%);
15 | background: -webkit-gradient(linear, 0 0, 0 100%, from(#f6f6f6), to(#f4f4f4));
16 | font:14px/2em 'Microsoft YaHei';
17 | text-align: center;
18 | position: fixed;
19 | margin-top: 12%;
20 | margin-left: 298px;
21 | }
22 | .loginBox h2{
23 | height:45px;
24 | font-size:20px;
25 | font-weight:normal;
26 | }
27 | .loginBox span{
28 | padding-right: 12px;
29 | }
30 | .LoginFooter {
31 | width: 100%;
32 | text-align: center;
33 | color: #FFF;
34 | position: fixed;
35 | bottom: 60px;
36 | }
37 | .LoginFooter a {
38 | color: #FFF;
39 | }
--------------------------------------------------------------------------------
/xk_static/images/160x120.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_static/images/160x120.gif
--------------------------------------------------------------------------------
/xk_static/images/260x180.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_static/images/260x180.gif
--------------------------------------------------------------------------------
/xk_static/images/360x268.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_static/images/360x268.gif
--------------------------------------------------------------------------------
/xk_static/images/670x240.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_static/images/670x240.gif
--------------------------------------------------------------------------------
/xk_static/images/login_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/luxiaok/DNSmasqWeb/26989d1fd2583bdc74047a9119379aaf20c9b0f5/xk_static/images/login_bg.png
--------------------------------------------------------------------------------
/xk_static/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document);
--------------------------------------------------------------------------------
/xk_static/js/xk_dhcp.js:
--------------------------------------------------------------------------------
1 | /* Gen By Xiaok */
2 | function reload_dhcp(force) {
3 | $.ajax({
4 | type: "GET",
5 | url: "/public/api",
6 | data: { "module":"dhcp","fun":"reload","value":force},
7 | dataType: "text",
8 | success: function(msg){
9 | if (msg == "2") {
10 | alert("刷新DHCP配置成功!");
11 | location.reload();
12 | } else if (msg == "1") {
13 | // 配置文件MD5校验失败,是否强制执行?
14 | if ( confirm("配置文件MD5校验失败,是否强制执行?") ) {
15 | reload_dhcp("force");
16 | return true;
17 | };
18 | return false;
19 | } else if (msg == "3") {
20 | // 重启服务失败
21 | alert("重启DNSmasq服务失败!");
22 | return false;
23 | } else if (msg == "4") {
24 | // 写入配置失败
25 | alert("写入DHCP配置失败!");
26 | return false;
27 | } else {
28 | alert("提示:操作失败!");
29 | return false;
30 | }
31 | },
32 | error:function(){
33 | alert("提示:服务器内部错误!");
34 | return false;
35 | },
36 | });
37 | };
38 |
--------------------------------------------------------------------------------
/xk_static/js/xk_dnsmasqweb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery.ScrollTo - Easy element scrolling using jQuery.
3 | * Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
4 | * Dual licensed under MIT and GPL.
5 | * Date: 5/25/2009
6 | * @author Ariel Flesler
7 | * @version 1.4.2
8 | *
9 | * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
10 | */
11 | ;(function(d){var k=d.scrollTo=function(a,i,e){d(window).scrollTo(a,i,e)};k.defaults={axis:'xy',duration:parseFloat(d.fn.jquery)>=1.3?0:1};k.window=function(a){return d(window)._scrollable()};d.fn._scrollable=function(){return this.map(function(){var a=this,i=!a.nodeName||d.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!i)return a;var e=(a.contentWindow||a).document||a.ownerDocument||a;return d.browser.safari||e.compatMode=='BackCompat'?e.body:e.documentElement})};d.fn.scrollTo=function(n,j,b){if(typeof j=='object'){b=j;j=0}if(typeof b=='function')b={onAfter:b};if(n=='max')n=9e9;b=d.extend({},k.defaults,b);j=j||b.speed||b.duration;b.queue=b.queue&&b.axis.length>1;if(b.queue)j/=2;b.offset=p(b.offset);b.over=p(b.over);return this._scrollable().each(function(){var q=this,r=d(q),f=n,s,g={},u=r.is('html,body');switch(typeof f){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(f)){f=p(f);break}f=d(f,this);case'object':if(f.is||f.style)s=(f=d(f)).offset()}d.each(b.axis.split(''),function(a,i){var e=i=='x'?'Left':'Top',h=e.toLowerCase(),c='scroll'+e,l=q[c],m=k.max(q,i);if(s){g[c]=s[h]+(u?0:l-r.offset()[h]);if(b.margin){g[c]-=parseInt(f.css('margin'+e))||0;g[c]-=parseInt(f.css('border'+e+'Width'))||0}g[c]+=b.offset[h]||0;if(b.over[h])g[c]+=f[i=='x'?'width':'height']()*b.over[h]}else{var o=f[h];g[c]=o.slice&&o.slice(-1)=='%'?parseFloat(o)/100*m:o}if(/^\d+$/.test(g[c]))g[c]=g[c]<=0?0:Math.min(g[c],m);if(!a&&b.queue){if(l!=g[c])t(b.onAfterFirst);delete g[c]}});t(b.onAfter);function t(a){r.animate(g,j,b.easing,a&&function(){a.call(this,n,b)})}}).end()};k.max=function(a,i){var e=i=='x'?'Width':'Height',h='scroll'+e;if(!d(a).is('html,body'))return a[h]-d(a)[e.toLowerCase()]();var c='client'+e,l=a.ownerDocument.documentElement,m=a.ownerDocument.body;return Math.max(l[h],m[h])-Math.min(l[c],m[c])};function p(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery);
12 |
13 |
14 | (function($){
15 |
16 | $(function() {
17 |
18 | /* toggle links */
19 | $('.toggle-link').click(function(e) {
20 |
21 | var target = $($(this).attr('href')).toggleClass('hidden');
22 |
23 | $.scrollTo(target);
24 |
25 | e.preventDefault();
26 |
27 | });
28 |
29 | });
30 |
31 | })(this.jQuery);
32 |
33 | // 选中所有
34 | $("#checkbox_all").click(
35 | function(){
36 | $(this).parent().parent().parent().parent().find("input[type='checkbox']").attr('checked', $(this).is(':checked'));
37 | }
38 | );
--------------------------------------------------------------------------------
/xk_static/js/xk_users.js:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * For User Page
4 | * Desgin By Xiaok
5 | * 2014-12-10 23:22:54
6 | *
7 | */
8 |
9 | function add_user() {
10 | username = $("#username").val();
11 | name = $("#name").val();
12 | email = $("#email").val();
13 | mobile = $("#mobile").val();
14 | password = $("#password").val();
15 | password2 = $("#password2").val();
16 | comment = $("#comment").val();
17 | if (username == '') {
18 | alert("请输入用户名!");
19 | $("#username").focus();
20 | return false;
21 | };
22 | if (name == '') {
23 | alert("请输入姓名!");
24 | $("#name").focus();
25 | return false;
26 | };
27 | if (password == '') {
28 | alert("请输入密码!");
29 | $("#password").focus();
30 | return false;
31 | };
32 | if (password2 == '') {
33 | alert("请再次输入密码!");
34 | $("#password2").focus();
35 | return false;
36 | };
37 | if (password != password2) {
38 | alert("密码不一致!");
39 | $("#password").val("");
40 | $("#password2").val("");
41 | $("#password").focus();
42 | return false;
43 | };
44 | $.ajax({
45 | type: "POST",
46 | url: "/users",
47 | data: {
48 | 'username': username,
49 | 'name': name,
50 | "email": email,
51 | "mobile": mobile,
52 | "password": password,
53 | 'comment': comment,
54 | "fun": "add"
55 | },
56 | dataType: "text",
57 | success: function(msg) {
58 | if (msg == "1") {
59 | alert("添加成功!");
60 | window.location.href = "/users";
61 | } else if (msg == "2") {
62 | alert("用户已存在!");
63 | $("#username").focus();
64 | } else {
65 | alert("提示:添加用户失败!");
66 | }
67 | },
68 | error: function() {
69 | alert("提示:服务器内部错误!");
70 | },
71 | });
72 | };
73 | function show_add() {
74 | $("#add_line").removeClass("display_no");
75 | $("#domain").focus();
76 | };
77 | function cancel_add() {
78 | $("#add_line").addClass("display_no");
79 | };
80 | function to_edit(id) {
81 | show_id = "#line_" + id;
82 | edit_id = "#edit_line_" + id;
83 | $(show_id).addClass("display_no");
84 | $(edit_id).removeClass("display_no");
85 | };
86 | function to_line(id) {
87 | show_id = "#line_" + id;
88 | edit_id = "#edit_line_" + id;
89 | $(show_id).removeClass("display_no");
90 | $(edit_id).addClass("display_no");
91 | };
92 | /* 编辑保存记录 */
93 | function save_info(id) {
94 | //username = $("#username_"+id).val();
95 | name = $("#name_" + id).val();
96 | email = $("#email_" + id).val();
97 | mobile = $("#mobile_" + id).val();
98 | comment = $("#comment_" + id).val();
99 | $.ajax({
100 | type: "POST",
101 | url: "/users",
102 | data: {
103 | "id": id,
104 | "name": name,
105 | "email": email,
106 | "mobile": mobile,
107 | "comment": comment,
108 | "fun": "edit"
109 | },
110 | dataType: "text",
111 | success: function(msg) {
112 | if (msg == "1") {
113 | alert("修改成功!");
114 | location.href = "/users";
115 | } else {
116 | alert("提示:修改失败!");
117 | return false;
118 | }
119 | },
120 | error: function() {
121 | alert("提示:服务器内部错误!");
122 | return false;
123 | },
124 | });
125 | };
126 | function ch_pass(id, username) {
127 | $("#cur_uid").val(id);
128 | $("#cur_user").val(username);
129 | $("#oldpass").val("**********");
130 | $("#userlist").addClass("display_no");
131 | $("#pass_form").removeClass("display_no");
132 | };
133 | function cancel_pass() {
134 | $("#pass_form").addClass("display_no");
135 | $("#userlist").removeClass("display_no");
136 | };
137 | function save_pass() {
138 | uid = $("#cur_uid").val();
139 | username = $("#cur_user").val();
140 | pass1 = $("#newpass").val();
141 | pass2 = $("#newpass2").val();
142 | if (pass1 == '' || pass2 == '') {
143 | alert("密码不能为空!");
144 | $("#newpass").focus();
145 | return false;
146 | }
147 | if (pass1 != pass2) {
148 | alert("两次输入密码不一致!!");
149 | $("#newpass").val("");
150 | $("#newpass2").val("");
151 | $("#newpass").focus();
152 | return false;
153 | };
154 | $.ajax({
155 | type: "POST",
156 | url: "/users",
157 | data: {
158 | "id": uid,
159 | "password": pass1,
160 | "fun": "pass"
161 | },
162 | dataType: "text",
163 | success: function(msg) {
164 | if (msg == "1") {
165 | alert("修改密码成功!");
166 | location.href = "/users";
167 | } else {
168 | alert("提示:修改密码失败!");
169 | return false;
170 | }
171 | },
172 | error: function() {
173 | alert("提示:服务器内部错误!");
174 | return false;
175 | },
176 | });
177 | };
178 |
179 | /*
180 | *
181 | * For User Page
182 | * Desgin By Xiaok
183 | * 2014-12-10 23:22:54
184 | *
185 | */
--------------------------------------------------------------------------------