diff --git a/Makefile b/Makefile deleted file mode 100644 index d3a2532..0000000 --- a/Makefile +++ /dev/null @@ -1,124 +0,0 @@ -PY?=python -PELICAN?=pelican -PELICANOPTS= - -BASEDIR=$(CURDIR) -INPUTDIR=$(BASEDIR)/content -OUTPUTDIR=$(BASEDIR)/output -CONFFILE=$(BASEDIR)/pelicanconf.py -PUBLISHCONF=$(BASEDIR)/publishconf.py - -FTP_HOST=localhost -FTP_USER=anonymous -FTP_TARGET_DIR=/ - -SSH_HOST=localhost -SSH_PORT=22 -SSH_USER=root -SSH_TARGET_DIR=/var/www - -S3_BUCKET=my_s3_bucket - -CLOUDFILES_USERNAME=my_rackspace_username -CLOUDFILES_API_KEY=my_rackspace_api_key -CLOUDFILES_CONTAINER=my_cloudfiles_container - -DROPBOX_DIR=~/Dropbox/Public/ - -GITHUB_PAGES_BRANCH=gh-pages - -DEBUG ?= 0 -ifeq ($(DEBUG), 1) - PELICANOPTS += -D -endif - -RELATIVE ?= 0 -ifeq ($(RELATIVE), 1) - PELICANOPTS += --relative-urls -endif - -help: - @echo 'Makefile for a pelican Web site ' - @echo ' ' - @echo 'Usage: ' - @echo ' make html (re)generate the web site ' - @echo ' make clean remove the generated files ' - @echo ' make regenerate regenerate files upon modification ' - @echo ' make publish generate using production settings ' - @echo ' make serve [PORT=8000] serve site at http://localhost:8000' - @echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 ' - @echo ' make devserver [PORT=8000] start/restart develop_server.sh ' - @echo ' make stopserver stop local server ' - @echo ' make ssh_upload upload the web site via SSH ' - @echo ' make rsync_upload upload the web site via rsync+ssh ' - @echo ' make dropbox_upload upload the web site via Dropbox ' - @echo ' make ftp_upload upload the web site via FTP ' - @echo ' make s3_upload upload the web site via S3 ' - @echo ' make cf_upload upload the web site via Cloud Files' - @echo ' make github upload the web site via gh-pages ' - @echo ' ' - @echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html ' - @echo 'Set the RELATIVE variable to 1 to enable relative urls ' - @echo ' ' - -html: - $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) - -clean: - [ ! -d $(OUTPUTDIR) ] || rm -rf $(OUTPUTDIR) - -regenerate: - $(PELICAN) -r $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) - -serve: -ifdef PORT - cd $(OUTPUTDIR) && $(PY) -m pelican.server $(PORT) -else - cd $(OUTPUTDIR) && $(PY) -m pelican.server -endif - -serve-global: -ifdef SERVER - cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 $(SERVER) -else - cd $(OUTPUTDIR) && $(PY) -m pelican.server 80 0.0.0.0 -endif - - -devserver: -ifdef PORT - $(BASEDIR)/develop_server.sh restart $(PORT) -else - $(BASEDIR)/develop_server.sh restart -endif - -stopserver: - $(BASEDIR)/develop_server.sh stop - @echo 'Stopped Pelican and SimpleHTTPServer processes running in background.' - -publish: - $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS) - -ssh_upload: publish - scp -P $(SSH_PORT) -r $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) - -rsync_upload: publish - rsync -e "ssh -p $(SSH_PORT)" -P -rvzc --delete $(OUTPUTDIR)/ $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) --cvs-exclude - -dropbox_upload: publish - cp -r $(OUTPUTDIR)/* $(DROPBOX_DIR) - -ftp_upload: publish - lftp ftp://$(FTP_USER)@$(FTP_HOST) -e "mirror -R $(OUTPUTDIR) $(FTP_TARGET_DIR) ; quit" - -s3_upload: publish - s3cmd sync $(OUTPUTDIR)/ s3://$(S3_BUCKET) --acl-public --delete-removed --guess-mime-type - -cf_upload: publish - cd $(OUTPUTDIR) && swift -v -A https://auth.api.rackspacecloud.com/v1.0 -U $(CLOUDFILES_USERNAME) -K $(CLOUDFILES_API_KEY) upload -c $(CLOUDFILES_CONTAINER) . - -github: publish - ghp-import -m "Generate Pelican site" -b $(GITHUB_PAGES_BRANCH) $(OUTPUTDIR) - git push origin $(GITHUB_PAGES_BRANCH) - -.PHONY: html help clean regenerate serve serve-global devserver publish ssh_upload rsync_upload dropbox_upload ftp_upload s3_upload cf_upload github diff --git a/content/debian-update-with-ansible.md b/content/debian-update-with-ansible.md deleted file mode 100644 index 1667080..0000000 --- a/content/debian-update-with-ansible.md +++ /dev/null @@ -1,80 +0,0 @@ -Title: Debian updates with Ansible -Date: 2016-01-31 -Category: Ansible Playbook - -I've recently bought a [HP Proliant Microserver Gen8](http://www8.hp.com/us/en/products/proliant-servers/product-detail.html?oid=5379860) to play around with LXC and try new stuff. - -From the 4 Debian machines I had to keep up-to-date, I now have 7, so it became quite time-consumming to manually SSH to each of them whenever an update became available. - -I ended up looking at [Ansible](http://www.ansible.com/) to speed up the process and, within an hour, I had a working playbook that updates the debian packages, pip packages and git repos installed on all of my servers with a single command. - -I figured I'd share the playbook I use to update the Debian packages ! - -## The playbook - -I modified [this gist](https://gist.github.com/maethor/380676f6b1cec8cc7439) to only use apt-get instead of both apt-get and aptitude. - -```yaml -- hosts: all - tasks: - - - name: update cache - apt: update_cache=yes - - - name: list packages to upgrade (1/2) - shell: apt-get upgrade -s -V | awk '/=>/{print $1}' - register: updates - changed_when: False - - - name: list packages to upgrade (2/2) - debug: msg="{{ updates.stdout_lines | count }} packages to upgrade ({{ updates.stdout_lines | join(', ') }})" - when: (updates.stdout_lines) - - - name: upgrade packages - apt: upgrade=dist - when: (updates.stdout_lines) - - - name: check what the new version is - shell: lsb_release -r | awk '{print $2}' - changed_when: False - register: new_release - - - name: notify distribution version upgrade - debug: msg="Debian has been upgraded from {{ ansible_lsb.release }} to {{ new_release.stdout }}" - when: ansible_lsb.release != new_release.stdout - - - name: /wheezy/ install the debian-goodies package if it is missing - apt: name=debian-goodies state=present - when: ansible_distribution_release == 'wheezy' - - - name: /jessie/ install the needrestart package if it is missing - apt: name=needrestart state=present default_release=jessie-backports - when: ansible_distribution_release == 'jessie' - - - name: /wheezy/ list services to restart (1/3) - shell: checkrestart | awk '/^service/{print $2}' - register: wheezy_services - changed_when: False - when: ansible_distribution_release == 'wheezy' - - - name: /jessie/ list services to restart (1/3) - shell: needrestart -blrl | awk '/^NEEDRESTART-SVC/{print $2}' - register: jessie_services - changed_when: False - when: ansible_distribution_release != 'wheezy' - - - name: merge services list (2/3) - set_fact: - services: "{{ wheezy_services if ansible_distribution_release == 'wheezy' else jessie_services }}" - - - name: list services to restart (3/3) - debug: msg="{{ services.stdout_lines | count }} services to restart ({{ services.stdout_lines | join (', ') }})" - when: (services.stdout_lines) - - - name: cache cleanup - shell: apt-get autoclean -``` - -## Conclusion - -That's all ! Please leave a comment if you've found this playbook helpful ! diff --git a/content/flexget.md b/content/flexget.md deleted file mode 100644 index db00db1..0000000 --- a/content/flexget.md +++ /dev/null @@ -1,251 +0,0 @@ -Title: Flexget init script -Date: 2015-05-05 -Category: Script - -I've been using [Flexget](http://flexget.com/) for the past two years or so as a download automator. - -Since I wrote an [init script](http://flexget.com/wiki/Daemon/Startup#InsservscriptDebiancompatible) for it a while back, and it is compatible with Debian Jessie / systemd, I figured I'd share it here. - -## The script - -All of the following should be done as the root user. - -First, create a /etc/default/flexget file with the following content : - -```bash -# Configuration file for /etc/init.d/flexget - -# User to run flexget as. -# Daemon will not start if left empty. -FGUSER="" - -# Full path to the flexget config.yml file to use. -# Defaults to FGUSER $HOME/.flexget/config.yml -CONFIG="" - -# Path to the directory where flexget should log. Do not add trailing slash. -# Defaults to the FGUSER $HOME/.flexget directory -LOG="" - -# Log verbosity -# Available options : none critical error warning info verbose debug trace -# Defaults to info -LEVEL="" -``` - -Please note that the FGUSER variable needs to be defined for the daemon to start. It can be set to your current user, or you can run flexget as its own user. - -You can create a flexget user with the following command : - -```bash -useradd -m -d /var/lib/flexget -r -s /bin/false flexget -``` - -Then, create the /etc/init.d/flexget file : - -```bash -#!/bin/bash - -### BEGIN INIT INFO -# Provides: flexget -# Required-Start: $network $remote_fs -# Required-Stop: $network $remote_fs -# Should-Start: -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Flexget -# Description: FlexGet is a multipurpose automation tool -# for content like torrents, nzbs, podcasts, -# comics, series, movies, etc. -### END INIT INFO - -# Author: Antoine Joubert, 19/01/2014 - -NAME="flexget" -DAEMON="/usr/local/bin/flexget" -SETTINGS="/etc/default/$NAME" - -DESC="Flexget" -PIDFILE="/var/run/$NAME.pid" - -set -e - -. /lib/lsb/init-functions - -unset FGUSER CONFIG LOG LEVEL - -# Exit if flexget not installed -if [ ! -x "$DAEMON" ]; then - log_action_msg "$DESC: Could not find flexget executable. Exiting." - exit 2 -fi - -# Read configuration variables -if [ -r /etc/default/$NAME ]; then - . /etc/default/$NAME -else - log_action_msg "$DESC: /etc/default/$NAME not found. Exiting." - exit 2 -fi - -# Exit if FGUSER has not been set in /etc/default/flexget -if [ -z $FGUSER ]; then - log_action_msg "$DESC: FGUSER not set in /etc/default/$NAME. Exiting." - exit 2 -fi - -# Function to verify if flexget is already running -run_check() { - if [ -e $PIDFILE ]; then - status_of_proc -p $PIDFILE $DAEMON $NAME > /dev/null && RETVAL=0 || RETVAL="$?" - else - RETVAL="2" - fi -} - -end_log() { - if [ $RETVAL -eq 0 ]; then - log_end_msg 0 - return 0 - else - log_end_msg 1 - exit 1 - fi -} - -# Function to define config file, log file and log level -conf_check() { - if [ -z $CONFIG ]; then - OPTIONS="$OPTIONS" - else - OPTIONS="-c $CONFIG" - fi - - if [ -z $LOG ]; then - OPTIONS="$OPTIONS" - else - OPTIONS="$OPTIONS -l $LOG/flexget.log" - if [ ! -d $LOG ]; then - mkdir -p -m 750 $LOG - chown $FGUSER $LOG - fi - fi - - if [ -z $LEVEL ]; then - OPTIONS="$OPTIONS" - else - OPTIONS="$OPTIONS -L $LEVEL" - fi -} - -start_flexget() { - run_check - if [ $RETVAL = 0 ]; then - log_action_msg "$DESC: Already running with PID $(cat $PIDFILE). Aborting." - exit 2 - else - conf_check - log_daemon_msg "$DESC: Starting the daemon." - start-stop-daemon --start --background --quiet --pidfile $PIDFILE --make-pidfile \ - --chuid $FGUSER --user $FGUSER --exec $DAEMON -- $OPTIONS daemon start - RETVAL=$? - end_log - fi -} - -stop_flexget() { - run_check - if [ $RETVAL = 0 ]; then - log_daemon_msg "$DESC: Stopping the daemon." - start-stop-daemon --stop --quiet --chuid "$FGUSER" --pidfile "$PIDFILE" --retry 30 - RETVAL=$? - [ -e "$PIDFILE" ] && rm -f "$PIDFILE" - end_log - else - log_action_msg "$DESC: Not currently running. Aborting." - exit 2 - fi -} - -status_flexget() { - run_check - if [ $RETVAL = 0 ]; then - log_action_msg "$DESC: Currently running with PID $(cat $PIDFILE)." - else - log_action_msg "$DESC: Not currently running." - fi - exit $RETVAL -} - -case "$1" in - start) - start_flexget - ;; - stop) - stop_flexget - ;; - restart) - stop_flexget && sleep 2 && start_flexget - ;; - status) - status_flexget - ;; - *) - echo "Usage: $0 {start|stop|restart|status}" - ;; -esac - -exit 0 - -``` - -Then, give execution rights to the script : - -```bash -chmod +x /etc/init.d/flexget -``` - -And then, generate the necessary symlinks for the service to start on boot : - -*Debian Jessie* - -```bash -systemctl enable flexget -``` - -*Debian Wheezy* - -```bash -insserv flexget -``` - -To start, stop or check if the daemon is running : - -*Debian Jessie* - -```bash -systemctl start flexget -systemctl stop flexget -systemctl status flexget -``` - -*Debian Wheezy / Jessie* - -```bash -service flexget start -service flexget stop -service flexget status -``` - -*Debian Wheezy* - -```bash -/etc/init.d/flexget start -/etc/init.d/flexget stop -/etc/init.d/flexget status -``` - -## Conclusion - -That's all ! If you are using this script, please let me know in the comment section below ! diff --git a/content/git-setup.md b/content/git-setup.md deleted file mode 100644 index a020442..0000000 --- a/content/git-setup.md +++ /dev/null @@ -1,180 +0,0 @@ -Title: Private Git Repo -Date: 2016-01-31 -Category: Tutorial - -I've decided to migrate this blog to [Pelican](http://blog.getpelican.com/). I've been playing around with it over the week-end, and it turns out to be way easier to manage than [Jekyll](https://jekyllrb.com/). Themes are much easier to install and configure, so it ends up looking better as well ! - -Since I'm basically recreating this blog from scratch, I've decided to delete the old git repo that was hosting it and to create a new one. - -Setting up your own private git repo is pretty easy to achieve and is already well-documented on the [Git](https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server) website. - -Every time I want to create a new repo, I've had time to forget how to do it and I end up looking for that page, so I figured I'd write a few lines on the subject. - -In this tutorial, I'll configure a git repo on a distant server running Debian 8 (Jessie). This repo will be remotely accessible using SSH. Two users will be able to connect to it : me and the www-data user on my webserver. - -## SSH Keys - -If you don't have one already, you'll need a ssh-key to connect to the git repo. - -On your computer, in a shell, as your usual user : - -```bash -ssh-keygen -t rsa -b 3072 -Generating public/private rsa key pair. -Enter file in which to save the key (/home/user/.ssh/id_rsa): -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Your identification has been saved in /home/user/.ssh/id_rsa. -Your public key has been saved in /home/user/id_rsa.pub. -The key fingerprint is: -[Redacted] -``` - -For security reasons, configuring a passphrase is recommended. On Mac OS X and most desktop environnements on Linux, you can store this passphrase for the duration of your session using the `ssh-add` command, so you won't have to type it every time you want to connect to a host. - -On the server, we also have to create a ssh-key for the user that is running our webserver (you'll need to have sudo installed) : - -```bash -sudo -H -u www-data ssh-keygen -t rsa -b 3072 -Generating public/private rsa key pair. -Enter file in which to save the key (/var/www/.ssh/id_rsa): -Enter passphrase (empty for no passphrase): -Enter same passphrase again: -Your identification has been saved in /var/www/.ssh/id_rsa. -Your public key has been saved in /var/www/.ssh/id_rsa.pub. -The key fingerprint is: -[Redacted] -``` - -If you decide to configure a passphrase for that ssh-key, you'll have to type it every time you'll want to pull from your repo. - -## Server management - -All of the commands in this section have to be run as root. - -First thing first, we have to install the git package on the server that will be hosting our git repos : - -```bash -apt update && apt install git -y -``` - -Then, we have to create a user named git : - -```bash -useradd -s /usr/bin/git-shell -m -r git -``` - -This will create a system user (UID < 1000) with a /home/git home directory. If you want to host your git repos somewhere else on your filesystem, you should add a `-d /home/directory/for/git` in the previous command. - -This user will use the git-shell shell. This limits remote connection to that user to git commands (like the rssh shell can limit remote connection to a user to scp or rsync commands). - -We have to configure our system to allow the use of this shell : - -```bash -echo '/usr/bin/git-shell' >> /etc/shells -``` - -From this point, you should have to following output if you try to SSH to your server with that user : - -```bash -ssh git@git.captainark.net -fatal: Interactive git shell is not enabled. -hint: ~/git-shell-commands should exist and have read and execute access. -Connection to git@git.captainark.net closed. -``` - -We now need to create the .ssh/authorized_keys file for the git user with the correct permissions : - -```bash -sudo -H -u git mkdir /home/git/.ssh && chmod 700 /home/git/.ssh -sudo -H -u git touch /home/git/.ssh/authorized_keys && chmod 600 /home/git/.ssh/authorized_keys -``` - -You can now copy/paste the content of the two `$HOME/.ssh/id_rsa.pub` files we've created earlier using the `ssh-keygen` command in `/home/git/.ssh/authorized_keys`. - -The last thing we have to do is to create our first git repo. In this example, my project will be called 'captainarkdotnet' as it will be hosting this blog : - -```bash -sudo -H -u git mkdir /home/git/captainarkdotnet.git -cd /home/git/captainarkdotnet.git -sudo -H -u git git init --bare -``` - -The last command should give you the following output : - -```bash -Initialized empty Git repository in /home/git/captainarkdotnet.git/.git/ -``` - -We're done with the server configuration. Let's now actually push stuff to our repo ! - -### Initial push - -The files for my blog are store in the ~/Documents/projects/captainarkdotnet on my computer. Before doing anything else, we first have to make sure that we currently are in that folder : - -```bash -cd ~/Documents/projects/captainarkdotnet -``` - -Let's now push the content of that folder to our repo : - -```bash -git init -git add . -git commit -m 'initial commit' -git remote add origin git@git.captainark.net:captainarkdotnet.git -git push origin master -``` - -Please note that you'll need to edit **git.captainark.net** to the FQDN or IP of your git server, and **captainarkdotnet.git** to the name of the git project on your server. - -If everything went well, the last command should give you the following output : - -```bash -Counting objects: 69, done. -Delta compression using up to 4 threads. -Compressing objects: 100% (64/64), done. -Writing objects: 100% (69/69), 1.01 MiB | 0 bytes/s, done. -Total 69 (delta 15), reused 0 (delta 0) -To git@git.captainark.net:captainarkdotnet.git - * [new branch] master -> master -``` - -That's it, we've now pushed our first commit to our server ! - -## First pull - -Alright, time to pull the files we've just pushed on our webserver. I personally store my web content in `/var/www` ; if you don't, you'll have to adjust the path accordingly : - -```bash -cd /var/www -sudo -H -u www-data git clone git@git.captainark.net:captainarkdotnet.git -``` - -SSH will ask you to type 'yes' since it's the first time the www-data user connects to the server. If everything goes well, you should have the following output : - -```bash -Cloning into 'captainarkdotnet'... -remote: Counting objects: 70, done. -remote: Compressing objects: 100% (65/65), done. -remote: Total 70 (delta 16), reused 0 (delta 0) -Receiving objects: 100% (70/70), 1.01 MiB | 0 bytes/s, done. -Resolving deltas: 100% (16/16), done. -Checking connectivity... done. -``` - -## Conclusion - -That's it ! We now have a working private git repo ! I won't go into details into the git commands in this tutorial, but here's a quick overwiew of the ones I use the most : - -- `git add .` recursively adds all files from the directory to the repo ; -- `git commit -a -m 'This is a comment'` commits the current state of your local repo with the 'This is a comment' comment ; -- `git push` pushes your commits to the distant repo ; -- `git pull` pulls the latest version of the distant repo locally ; -- `git branch -av` shows all available branches for the repo ; -- `git checkout -b testing remotes/origin/testing` create a local 'testing' branch based on the remote 'remotes/origin/testing' branch ; -- once a branch has been copied locally, you can switch to it with the `git checkout {branch}` command. - -For more information on git a command, use `man git-{command}` ! - -If you've found this tutorial in any way helpful, please feel free to leave a comment ! diff --git a/content/images/tmux.png b/content/images/tmux.png deleted file mode 100644 index 4ec4ee2..0000000 Binary files a/content/images/tmux.png and /dev/null differ diff --git a/content/images/tmux_fullsize.png b/content/images/tmux_fullsize.png deleted file mode 100644 index 9899041..0000000 Binary files a/content/images/tmux_fullsize.png and /dev/null differ diff --git a/content/mailserver.md b/content/mailserver.md deleted file mode 100644 index f173930..0000000 --- a/content/mailserver.md +++ /dev/null @@ -1,1131 +0,0 @@ -Title: Setting up a mail server -Date: 2015-04-24 -Category: Tutorial - -In this first tutorial, I'll explain how I've configured my mail server using the following : - -- A server running Linux Debian (jessie) ; -- Postfix ; -- Postfix-policyd-spf-python ; -- Dovecot ; -- Spamassassin ; -- OpenDKIM ; -- OpenDMARC ; -- Monit ; -- Rainloop. - -I'm assuming you have some basic knowledge of Linux and DNS configuration. - -You can host this server at home, but you might have issues with your ISP not allowing outbound traffic on TCP port 25, and your emails might be considered to be spam by other providers if your IP is dynamic and/or you can't configure a reverse DNS record on it. - -The cheapest VMs from [DigitalOcean](https://www.digitalocean.com/?refcode=1cd69e4c3389) or [Vultr](http://www.vultr.com/?ref=6804947) are powerful enough to have this configuration running smoothly. - -We'll also need a SSL certificate for this configuration. You can create an auto-signed one or get a free valid one from [StartSSL](http://www.startssl.com/). For the purpose of this tutorial, I'll consider you've chosen the latter. - -You'll also need a domain name. I've chosen [Namecheap](http://www.namecheap.com/?aff=85990) as a registrar. I won't go into details on how to configure it, but you'll need at the very least a A record on your server's IP as well as a MX record pointing to it. - -I use the captainark.net domain as an example throughout this tutorial. You'll have to use your actual domain for your configuration to work ! - -*Note: links in this section are sponsored.* - -## Initial configuration - -### Installing the required packages - -First thing first, we need to install the packages we'll need for this configuration : - -```bash -apt update - -apt install mysql-server mysql-client postfix postfix-mysql \ -postfix-policyd-spf-python dovecot-core dovecot-imapd dovecot-lmtpd \ -dovecot-mysql dovecot-sieve dovecot-managesieved dovecot-antispam \ -opendkim opendkim-tools monit opendmarc spamassassin spamc -``` - -During its installation, Postfix will prompt you with configuration questions. Choose "Internet Site", and when asked about your System mail name, provide it with your server's FQDN (it should be the output of the `hostname -f` command on your server). - -You'll also have to set-up a password for the MySQL root user. - -### Additional configuration - -The PTR records on your server's IPv4 and/or IPv6 should match your server's FQDN (a `dig -x` on your server's IP should match a `hostname -f` on your server). - -You'll have to open the following TCP ports on your server for this configuration to work : 25, 465, 587 and 993. - -If you don't want to have to remember the root user MySQL password, you can create a .my.cnf file in your current user home directory containing the following lines : - -```bash -[client] -host = localhost -user = root -password = myverysecurepassword -socket = /var/run/mysqld/mysqld.sock -``` - -Once it has been created, change the permissions on the file to make sure no other user can read it : - -```bash -chmod 600 ~/.my.cnf -``` - -I also like to change the default MySQL shell to see what database I'm using at any given time. Since I use bash, I achieve this the following way : - -```bash -echo 'export MYSQL_PS1="[\u@\h] (\d)> "' > ~/.bash_aliases -``` - -You'll have to logout from the current shell for the modification to be taken into account (if you're using SSH, log out and back into your server). - -You should now be able to log into MySQL without specifying a password, and it should look like this : - -```bash -:~$ mysql mysql -[...] -[root@localhost] (mysql)> -``` - -## Configuring the MySQL database - -### Initial configuration - -We now need to configure the MySQL database Postfix and Dovecot will be using. In this tutorial, we'll be calling it "mail", but you can name it whatever you want. - -First, in a mysql shell, let's create the MySQL database : - -```sql -CREATE DATABASE mail; -``` - -Now, we are going to create the user that Postfix and Dovecot will be using to access the database. We will only be granting this user select permission : - -```sql -GRANT SELECT ON mail.* TO 'mail'@'localhost' IDENTIFIED BY 'mailpassword'; -FLUSH PRIVILEGES; -``` - -We are now going to create the necessary tables for our needs. Let's first use the mail database : - -```sql -USE mail; -``` - -The first table we are going to create will contain the domains we will be using with our mail server : - -```sql -CREATE TABLE `virtual_domains` ( -`id` INT NOT NULL AUTO_INCREMENT, -`name` VARCHAR(50) NOT NULL, -PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -``` - -Then, we are going to create the table that will contain our users and their password : - -```sql -CREATE TABLE `virtual_users` ( -`id` INT NOT NULL AUTO_INCREMENT, -`domain_id` INT NOT NULL, -`password` VARCHAR(106) NOT NULL, -`email` VARCHAR(120) NOT NULL, -PRIMARY KEY (`id`), -UNIQUE KEY `email` (`email`), -FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -``` - -Finally, the last table we are going to create will contain our mail aliases : - -```sql -CREATE TABLE `virtual_aliases` ( -`id` INT NOT NULL AUTO_INCREMENT, -`domain_id` INT NOT NULL, -`source` varchar(100) NOT NULL, -`destination` varchar(100) NOT NULL, -PRIMARY KEY (`id`), -FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; -``` - -### Domains, users and aliases management - -We are now going to add data to the tables we have created. - -First, let's add a domain to the virtual_domains table : - -```sql -INSERT INTO virtual_domains (`name`) VALUES ('captainark.net'); -``` - -We can now create users associated with this domain in the virtual_users table : - -```sql -INSERT INTO virtual_users (`domain_id`, `password` , `email`) VALUES -('1', ENCRYPT('notanactualpassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), -'example@captainark.net'); -``` - -This is not mandatory, but we can also create our first mail alias : - -```sql -INSERT INTO virtual_aliases (`domain_id`, `source`, `destination`) VALUES -('1', 'alias@captainark.net', 'example@captainark.net'); -``` - -Now, all messages sent to alias@captainark.net will be forwarded to example@captainark.net. - -Use the same syntax to create additional domains, users and aliases. If you have more than one domains configured, be sure to associate your users and aliases with the correct domain_id. - -## Configuring Postfix - -Next, we are going to configure [Postfix](http://www.postfix.org/). - -### Configuration backup - -First, let's backup the original configuration files : - -```bash -cp /etc/postfix/main.cf /etc/postfix/main.cf.orig -cp /etc/postfix/master.cf /etc/postfix/master.cf.orig -``` - -### User and group creation - -We are now going to create a user and group called vmail that will be used by both Postfix and Dovecot : - -```bash -groupadd -g 5000 vmail -useradd -g vmail -u 5000 vmail -d /var/mail -m -s /bin/false -``` - -### SSL certificates - -Next, we are going to create the folder where we will store the SSL certificates : - -```bash -mkdir /etc/postfix/ssl -chown root: /etc/postfix/ssl && chmod 600 /etc/postfix/ssl -``` - -Purists will probably want to store their certificates in /etc/ssl/private. If you choose to do so, you'll have to adapt the path of those files for the remainder of this tutorial. - -If you've decided to create a certificate with StartSSL, you'll end up with two files, a .crt and a .key. I'll name those files server.crt and server-with-passphrase.key. Put both these files in the folder we've just created. - -Now, let's remove the passphrase from the key : - -```bash -cd /etc/postfix/ssl -openssl rsa -in server-with-passphrase.key -out server.key -``` - -You'll be prompted for the passphrase you chose during the certificate generation. - -Next, we have to download the appropriate intermediate certificate : - -```bash -wget -O /etc/postfix/ssl/sub.class1.server.ca.pem \ -http://www.startssl.com/certs/sub.class1.server.ca.pem -``` - -We now have to make sure that the permissions on those files are correct : - -```bash -chown root: /etc/postfix/ssl/* && chmod 600 /etc/postfix/ssl/* -``` - -The last thing we have to do here is to generate Diffie-Hellman keys for Perfect Forward Secrecy (PFS) : - -```bash -openssl gendh -out /etc/postfix/dh_512.pem -2 512 -openssl gendh -out /etc/postfix/dh_1024.pem -2 1024 -``` - -### Postifx configuration - -First, let's edit the /etc/postfix/main.cf file. It should end up looking something like that : - -``` -smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU) -biff = no - -broken_sasl_auth_clients = yes -config_directory = /etc/postfix -disable_vrfy_command = yes -smtpd_data_restrictions = reject_unauth_pipelining, permit -smtpd_helo_required = yes - -queue_directory = /var/spool/postfix -append_dot_mydomain = no -readme_directory = no - -smtpd_use_tls=yes -smtpd_tls_auth_only = yes -smtpd_tls_cert_file=/etc/postfix/ssl/server.crt -smtpd_tls_key_file=/etc/postfix/ssl/server.key -smtpd_tls_CAfile=/etc/postfix/ssl/sub.class1.server.ca.pem -smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3 -smtpd_tls_protocols=!SSLv2,!SSLv3 -smtpd_tls_mandatory_ciphers=high -smtpd_tls_dh1024_param_file = /etc/postfix/dh_1024.pem -smtpd_tls_dh512_param_file = /etc/postfix/dh_512.pem -smtpd_tls_eecdh_grade = strong -smtpd_tls_loglevel = 1 -smtpd_tls_received_header = yes -smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache - -tls_preempt_cipherlist = yes -tls_random_source = dev:/dev/urandom - -smtpd_data_restrictions = reject_unauth_pipelining, permit -smtpd_helo_required = yes - -smtp_tls_CAfile = $smtpd_tls_CAfile -smtp_tls_mandatory_protocols=!SSLv2,!SSLv3 -smtp_tls_protocols=!SSLv2,!SSLv3 -smtp_tls_security_level = may -smtp_tls_loglevel = 1 -smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache - -smtpd_milters = -non_smtpd_milters = $smtpd_milters -milter_protocol = 2 -milter_default_action = accept - -smtpd_recipient_restrictions = - reject_invalid_hostname, - reject_non_fqdn_hostname, - reject_non_fqdn_sender, - reject_non_fqdn_recipient, - reject_unknown_sender_domain, - reject_unknown_recipient_domain, - permit_mynetworks, - permit_sasl_authenticated, - reject_unauth_destination, - permit - -smtpd_sasl_auth_enable = yes -smtpd_sasl_local_domain = $myhostname -smtpd_sasl_security_options = noanonymous -smtpd_sasl_tls_security_options = $smtpd_sasl_security_options -smtpd_tls_auth_only = yes -smtpd_sasl_type = dovecot -smtpd_sasl_path = private/auth - -myhostname = myserver.captainark.net ### CHANGE THIS -alias_maps = hash:/etc/aliases -alias_database = hash:/etc/aliases -myorigin = /etc/mailname -mydestination = localhost, myserver.captainark.net ### CHANGE THIS -relayhost = -mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 -mailbox_size_limit = 0 -recipient_delimiter = + -default_transport = smtp -relay_transport = smtp -inet_interfaces = all -inet_protocols = all - -virtual_transport = lmtp:unix:private/dovecot-lmtp -virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf -virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf -virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf -``` - -The variable "myhostname" has to be defined to you server's FQDN. The file /etc/mailname should contain your server's FQDN as well. - -Next, we need to edit the /etc/postfix/master.cf file. You need to uncomment the following lines : - -``` -submission inet n - - - - smtpd - -o syslog_name=postfix/submission - -o smtpd_tls_security_level=encrypt - -o tls_preempt_cipherlist=yes - -o smtpd_sasl_auth_enable=yes - -o smtpd_client_restrictions=permit_sasl_authenticated,reject - -smtps inet n - - - - smtpd - -o syslog_name=postfix/smtps - -o smtpd_tls_wrappermode=yes - -o smtpd_sasl_auth_enable=yes - -o smtpd_client_restrictions=permit_sasl_authenticated,reject -``` - -You also have to add the following lines at the end of the file : - -``` -dovecot unix - n n - - pipe - flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient} -``` - -### MySQL access for Postfix - -We now need to allow Postfix to connect to the MySQL database we have created earlier. To that end, we must create three files. - -/etc/postfix/mysql-virtual-mailbox-domains.cf should contain the following lines : - -``` -user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT 1 FROM virtual_domains WHERE name='%s' -``` - -/etc/postfix/mysql-virtual-mailbox-maps.cf should contain the following lines : - -``` -user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT 1 FROM virtual_users WHERE email='%s' -``` - -/etc/postfix/mysql-virtual-alias-maps.cf should contain the following lines : - -``` -user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT destination FROM virtual_aliases WHERE source='%s' -``` - -Since these files contain a password, let's make sure they are not world-readable : - -```bash -chown root: /etc/postfix/mysql* && chmod 600 /etc/postfix/mysql* -``` - -You can use the command postmap to confirm that everything is working properly : - -```bash -postmap -q captainark.net mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf - -postmap -q example@captainark.net mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf - -postmap -q alias@captainark.net mysql:/etc/postfix/mysql-virtual-alias-maps.cf -``` - -Let's restart postfix for our modifications to be taken into account : - -```bash -systemctl restart postfix -``` - -That's it for Postfix, for now ; Dovecot is next ! - -## Configuring Dovecot - -### Dovecot global configuration - -By default, on Debian, [Dovecot](http://www.dovecot.org/) uses multiple configuration files in /etc/dovecot/conf.d. I found it annoying to maintain, and I ended up only using the /etc/doveconf.conf file. - -As always, let's start by backing up the original configuration file : - -```bash -mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.orig -``` - -Next, we are going to create a new /etc/dovecot/dovecot.conf file. It should contain the following lines : - -``` -!include_try /usr/share/dovecot/protocols.d/*.protocol -protocols = imap lmtp sieve - -mail_location = maildir:/var/mail/%d/%n -mail_privileged_group = vmail -mail_plugin_dir = /usr/lib/dovecot/modules -mail_plugins = - -disable_plaintext_auth = yes -auth_mechanisms = plain login - -service director { - unix_listener login/director { - } - fifo_listener login/proxy-notify { - } - unix_listener director-userdb { - } - inet_listener { - } -} - -namespace inbox { - inbox = yes - type = private - mailbox Drafts { - auto = subscribe - special_use = \Drafts - } - mailbox Junk { - auto = subscribe - special_use = \Junk - } - mailbox Sent { - auto = subscribe - special_use = \Sent - } - mailbox Trash { - auto = subscribe - special_use = \Trash - } -} - -service imap-login { - inet_listener imap { - port = 0 - } - inet_listener imaps { - port = 993 - ssl = yes - } -} - -service pop3-login { - inet_listener pop3 { - port = 0 - } - inet_listener pop3s { - port = 0 - } -} - -service lmtp { - unix_listener /var/spool/postfix/private/dovecot-lmtp { - mode = 0600 - user = postfix - group = postfix - } -} - -service imap { -} - -service pop3 { -} - -service auth { - unix_listener /var/spool/postfix/private/auth { - mode = 0666 - user = postfix - group = postfix - } - unix_listener auth-userdb { - mode = 0600 - user = vmail - } - user = dovecot -} - -service auth-worker { - user = vmail -} - -service dict { - unix_listener dict { - } -} - -ssl = required -ssl_cert = " -TrustedAuthservIDs "" -IgnoreHosts /etc/opendkim.d/TrustedHosts - -RejectFailures false - -UserID opendmarc:opendmarc -PidFile /run/opendmarc.pid -Socket local:/var/spool/postfix/opendmarc/opendmarc.sock -``` - -### Postfix integration - -The last thing we have to do is to configure Postfix to communicate with OpenDMARC. - -First, let's create the necessary folders : - -```bash -mkdir /var/spool/postfix/opendmarc -chown opendmarc: /var/spool/postfix/opendmarc -``` - -We also have to add the postfix user to the opendmarc group : - -```bash -useradd -G opendmarc postfix -``` - -Now, let's edit the /etc/postfix/master.cf file, like so : - -``` -smtpd_milters = unix:/opendkim/opendkim.sock, unix:/opendmarc/opendmarc.sock -``` - -We now have to restart OpenDMARC and Postfix : - -```bash -systemctl restart opendmarc -systemctl restart postfix -``` - -You should now see the following headers in your incoming emails : - -``` -Authentication-Results: myserver.captainark.net; dmarc=pass header.from=gmail.com -``` - -### DNS side - -DMARC, like SPF and DKIM, is based on DNS TXT records. - -Here is how I configured it for the captainark.net domain : - -``` -_dmarc IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@captainark.net; ruf=mailto:postmaster@captainark.net" -``` - -This tells other providers to not reject or quarantine emails should a SPF or DKIM check fail, but to send a daily report of those checks to postmaster@captainark.net. - -For more information on the DMARC syntax, here is an [article from Google](https://support.google.com/a/answer/2466563?hl=en). - -## Configuring Monit - -[Monit](http://mmonit.com/monit/) is a daemon that makes sure that other daemons are running. If they crash, it restarts them automatically. Is is not directly related to a mail server per say, but it's pretty easy to set up. - -First, as always, let's backup the original configuration file : - -```bash -mv /etc/monit/monitrc /etc/monit/monitrc.orig -``` - -We now have to create a new /etc/monit/monitrc file with the following content : - -``` -set daemon 30 -set logfile syslog facility log_daemon - -set httpd port 2812 and -use address localhost -allow localhost - -set mailserver localhost -with timeout 30 seconds -using hostname myserver.captainark.net - -set mail-format { from: monit@captainark.net } - -include /etc/monit/conf.d/* -``` - -Then, we are going to create a /etc/monit/conf.d/mail file with the following content : - -``` -check process postfix - with pidfile "/var/spool/postfix/pid/master.pid" - start program = "/bin/systemctl start postfix" - stop program = "/bin/systemctl stop postfix" - alert monit@captainark.net - group mail - -check process dovecot - with pidfile "/run/dovecot/master.pid" - start program = "/bin/systemctl start dovecot" - stop program = "/bin/systemctl stop dovecot" - alert monit@captainark.net - group mail - depends on postfix - -check process spamassassin - with pidfile "/run/spamassassin.pid" - start program = "/bin/systemctl start spamassassin" - stop program = "/bin/systemctl stop spamassassin" - alert monit@captainark.net - group mail - depends on postfix, dovecot - -check process opendkim - with pidfile "/run/opendkim/opendkim.pid" - start program = "/bin/systemctl start opendkim" - stop program = "/bin/systemctl stop opendkim" - alert monit@captainark.net - group mail - depends on postfix, dovecot - -check process opendmarc - with pidfile "/run/opendmarc/opendmarc.pid" - start program = "/bin/systemctl start opendmarc" - stop program = "/bin/systemctl stop opendmarc" - alert monit@captainark.net - group mail - depends on postfix, dovecot -``` - -Let's make sure that permissions on the file are correct : - -```bash -chown root: /etc/monit/conf.d/mail && chmod 600 /etc/monit/conf.d/mail -``` - -Then, we have to reload the monit daemon : - -```bash -monit reload -``` - -Now, the `monit summary` command should have the following output : - -``` -The Monit daemon 5.4 uptime: 3d 0h 41m - -Process 'postfix' Running -Process 'dovecot' Running -Process 'spamassassin' Running -Process 'opendkim' Running -Process 'opendmarc' Running -``` - -## Configuring Rainloop - -[Rainloop](http://www.rainloop.net/) is a web-based email client. I won't go into details on how to configure it in this tutorial ; here's a link to the [official documentation](http://www.rainloop.net/docs/installation/). - -You'll need a web server with PHP 5.3+ to run Rainloop. You do not have to run Rainloop on the same host as your mail server. No database is required. - -## Conclusion - -We now have a mail server that should be running pretty smoothly. It could still be improved by setting up things such as greylisting or virus detection. - -If you have found this tutorial useful, if you've found an error in it or if you have any question, please feel free to leave a comment below or to contact me on [Twitter](https://twitter.com/captainark). - -## References - -Here are the tutorials I used to set up my own mail server : - -- [A complete tutorial on setting up a mail server](http://sealedabstract.com/code/nsa-proof-your-e-mail-in-2-hours/) -- [Another complete tutorial](https://docs.raccoon.io/mail-server-setup-with-postfix-dovecot/) -- [A third tutorial from DigitalOcean](https://www.digitalocean.com/community/tutorials/how-to-configure-a-mail-server-using-postfix-dovecot-mysql-and-spamassasin) -- [A tutorial on setting up OpenDKIM](https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy) -- [A tutorial on setting up OpenDMARC](https://guillaume.vaillant.me/?p=481) (in french) diff --git a/content/my-tmux-conf.md b/content/my-tmux-conf.md deleted file mode 100644 index ba6042d..0000000 --- a/content/my-tmux-conf.md +++ /dev/null @@ -1,189 +0,0 @@ -Title: My tmux configuration -Date: 2016-02-02 -Category: Configuration example - -[tmux](https://tmux.github.io/) is a terminal mutiplexer. It lets you have multiples shells running in a single terminal emulator window and it keeps those shells running in the background should you need to close your terminal emulator. - -I've played around with the configuration quite a bit to find settings that suit my needs. Here's what it ended up looking like : - -[![tmux](images/tmux.png)](images/tmux_fullsize.png) - -This screenshot was done on Mac OS X, using the Terminal app and this [Solarized theme](https://github.com/tomislav/osx-terminal.app-colors-solarized). - -I figured I'd share my tmux configuration here ! - -## Installing tmux - -tmux is available on Debian. I suggest using the [jessie backports](https://packages.debian.org/jessie-backports/tmux) version : - -`apt -t jessie-backports install tmux` - -tmux is also available on Mac OS X using [brew](http://brew.sh/) : - -`brew install tmux` - -## tmux.conf - -I used screen before tmux, so I configured the prefix key on C-a instead of C-b. tmux has the advantage of being *much* simpler to configure than screen. - -If you want to use this configuration, simply copy the following in ~/.tmux.conf. This file is read by default when tmux starts. - -If you simply want to try it out, copy it in a file somewhere else and have tmux load with the -f parameter (`tmux -f ~/tmux-test.conf`). - -``` -# use utf8 -set -g utf8 -set-option -g status-utf8 on -set-window-option -g utf8 on - -# do not wait on esc key -set-option -g escape-time 0 - -# completely disable automatic rename -set-window-option -g automatic-rename off - -# basic settings -set -g default-terminal "screen-256color" -set -g aggressive-resize off -set-window-option -g xterm-keys on -#set-window-option -g mode-mouse off - -# command history -set -g history-limit 10000 - -# messages -set -g message-bg default -set -g message-fg red - -# no visual activity -set -g visual-activity off -set -g visual-bell off - -# status bar -set-option -g status-justify centre -set-option -g status-bg default -set-option -g status-fg blue -set-option -g status-interval 5 -set-option -g status-left-length 30 -set-option -g status-left '#[fg=red][ #[fg=white]#H #[fg=red]]#[default]' -set-option -g status-right '#[fg=red][ #[fg=white]%R %d/%m #[fg=red]]#[default]' - -# modes -set-option -g mode-bg default -set-option -g mode-fg blue - -# inactive window format -set-window-option -g window-status-format '#I:#W#F' -set-window-option -g monitor-activity on -#set-window-option -g monitor-content on # not available in tmux 2.0 - -# activity in a window -set-window-option -g window-status-activity-attr dim -set-window-option -g window-status-activity-bg default -set-window-option -g window-status-activity-fg yellow - -# content in a window # not available in tmux 2.0 -#set-window-option -g window-status-content-attr dim -#set-window-option -g window-status-content-bg default -#set-window-option -g window-status-content-fg red - -# active window format -set-window-option -g window-status-current-fg white -set-window-option -g window-status-current-bg default -set-window-option -g window-status-current-format '#[fg=red](#[default]#I:#W#F#[fg=red])#[default]' - -# reload tmux configuration -unbind r -bind r source-file ~/.tmux.conf \; display "Configuration reloaded!" - -# Screen-like keybinds -unbind C-b -set -g prefix ^A -set -g prefix2 ^Q -bind a send-prefix -bind q send-prefix - -unbind c -bind c new-window -unbind ^C -bind ^C new-window - -unbind n -bind n next-window -unbind ^N -bind ^N next-window - -unbind A -bind A command-prompt "rename-window %%" - -unbind p -bind p previous-window -unbind ^P -bind ^P previous-window - -unbind a -bind a last-window -unbind ^A -bind ^A last-window - -unbind [ -bind Escape copy-mode - -unbind w -bind w list-windows - -unbind k -bind k confirm-before "kill-window" - -unbind l -bind l refresh-client - -unbind '"' -bind '"' choose-window -``` - -## Aliases - -I also use two functions with tmux (in ~/.bash_aliases). - -The first one creates a new "mytmux" tmux session if one doesn't exist yet, opens 10 shells and selects the first one. - -```bash -mytmux() { - tmux has-session -t mytmux - if [ $? != 0 ]; then - tmux new-session -s mytmux -n $(hostname) -d - tmux new-window -t mytmux:1 -n $(hostname) - tmux new-window -t mytmux:2 -n $(hostname) - tmux new-window -t mytmux:3 -n $(hostname) - tmux new-window -t mytmux:4 -n $(hostname) - tmux new-window -t mytmux:5 -n $(hostname) - tmux new-window -t mytmux:6 -n $(hostname) - tmux new-window -t mytmux:7 -n $(hostname) - tmux new-window -t mytmux:8 -n $(hostname) - tmux new-window -t mytmux:9 -n $(hostname) - tmux select-window -t mytmux:0 - fi - tmux attach -t mytmux -} -``` - -The second one changes the tmux window name whenever I ssh to a remote host, and switches the window name back to the name of my computer when I logout from the host. - -```bash -if [ -n "$TMUX" ]; then - ssh() { - if [ $# -le 2 ]; then - tmux rename-window "${@: -1}" - command ssh "$@" - tmux rename-window "$(hostname)" - else - command ssh "$@" - fi - } -fi -``` - -## Conclusion - -That's all ! As always, please do leave a comment if you've found something useful in this article ! \ No newline at end of file diff --git a/content/mysqlbackup.md b/content/mysqlbackup.md deleted file mode 100644 index 97cef33..0000000 --- a/content/mysqlbackup.md +++ /dev/null @@ -1,49 +0,0 @@ -Title: MySQL backup script -Date: 2016-03-13 -Category: Script - -I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but hey, I figured I'd share it here anyway. - -## The script - -For the script to work, you'll need to edit a few variable to match your configuration. - -- `BACKUPDIR` is the path of the directory where you want your backups to be stored. -- `BACKUPUSR` is the user that will connect to MySQL to dump the databases. It should have access to all you databases without needing a password. -- `EXCLUDELIST` is a list of databases that should not be backed-up. Leaving it as is is probably fine. - -```bash -#!/bin/bash - -BACKUPDIR="/home/user/backup" -BACKUPUSR="user" -EXCLUDELIST="^Databases$|^information_schema$|^mysql$|^performance_schema$" - -sqlbk() { - for each in $(mysqlshow | awk '/[[:alnum:]]/{print $2}'); do - if [[ $each =~ $EXCLUDELIST ]]; then - true - else - mysqldump $each | bzip2 > ${BACKUPDIR}/${each}.sql.bz2 - chown ${BACKUPUSR}: ${BACKUPDIR}/${each}.sql.bz2 && chmod 600 ${BACKUPDIR}/${each}.sql.bz2 - fi - done -} - -[[ -e /etc/init.d/mysql ]] && sqlbk -``` - -I personnaly have this script running once a week, in my user's personnal crontab (editable using the `crontab -e` command) : - -``` -## WEEKLY DATABASE BACKUP -@weekly /home/user/bin/backupdb -``` - -# Conclusion - -You've probably noticed that the script erases the previous backup when a new one is made. - -I don't need to keep multiple versions of the same database backup on my servers because they are all saved remotely on a daily basis using [Rsnapshot](http://rsnapshot.org/). I'll probably write an article on the subject in the future. - -As usual, feedback is always appreciated ! \ No newline at end of file diff --git a/content/pages/about.md b/content/pages/about.md deleted file mode 100644 index e3ee736..0000000 --- a/content/pages/about.md +++ /dev/null @@ -1,3 +0,0 @@ -Title: About - -My blog. diff --git a/content/pages/resume.md b/content/pages/resume.md deleted file mode 100644 index 82a3881..0000000 --- a/content/pages/resume.md +++ /dev/null @@ -1,81 +0,0 @@ -Title: Resume - -## Profile - -Hi ! I'm Antoine. I'm a 28 years old Systems and Network administrator, specialized in Linux and network management. I am not currently looking for a new opportunity. - -If you find my profile interesting or if you have any questions, please [send me an email](mailto:contact@captainark.net) ! - -## Skills Summary - -- Expertise in Linux and Cisco IOS routing, firewalling, QoS and VLAN configuration, for IPv4 and IPv6 ; -- Knowledge of dynamic routing protocols (BGP, OSPF, EIGRP) and VPN software (OpenVPN) ; -- Experience with a DDOS mitigation system (Arbor TMS) ; -- Expertise in standard network and systems analyzing and troubleshooting tools (tcpdump, dig, atop, wireshark, traceroute) ; -- Knowledge of monitoring software (nagios, shinken, cacti, smokeping, observium, ELK) ; -- Experience with Linux servers and desktops installation, configuration, administration and troubleshooting (on both Debian and RedHat based distributions) ; -- Familiarity with the most common network protocols (HTTP, DNS, DHCP, SMTP, POP, IMAP, CIFS) and their associated daemons (nginx, apache, bind, powerdns, dhcpd, dnsmasq, postfix, dovecot, samba) ; -- Ability to write and debug bash, batch and powershell scripts ; -- Experience with clustering and high-availability technologies (heartbeat, ipvsadm, VRRP, HSRP, SLB) ; -- Knowledge of virtualization technologies (VMWare Workstation, KVM, Xen, Proxmox, LXC) ; -- Experience with information resources management and incident management software (GLPI, OCS Inventory, FusionInventory) ; -- Familiarity with Windows desktop (8, 7 and XP) and server (2012, 2008, 2003) families, and with Mac OS X. - -## Work Experience - -**NAMESHIELD (Angers, France)** - -*Network Architect, from 09/2015 to now* - -- Technical projects management : - * WiFi deployment, using Cisco WLC and Aironet devices as well as Freeradius for EAP-TLS/802.1x user authentication ; - * VLAN deployment ; - * L2 VPN setup using OpenVPN to securely propagate private VLANs over the internet ; - -*Systems and Network Administrator, from 10/2013 to 08/2015* - -- Technical projects management, notably : - * Definition, configuration and maintenance of a highly-available networking architecture for WAN, site-to-site and road warrior VPN access ; - * Setup of a DDOS mitigation system and its associated procedures ; - * IPv6 deployment, on both LAN and data-center hosted machines ; - * Setup of a centralized logging solution and its associated scripts to generate statistics ; -- Linux systems, VOIP Phones, Cisco switches and routers configuration, deployment, administration and troubleshooting ; -- Daily monitoring and production control, and incident management ; -- User support on Linux and Windows systems. - -**INIT SYS - Alphalink Group (Pornic, France)** - -*Systems and Network Administration Technician, from 10/2012 to 08/2013* - -- Linux systems and services installation and configuration, on both physical and virtual machines ; -- Documentation of newly installed systems and their role within the existing infrastructure ; -- Servers and network monitoring and optimisation ; -- Systems and network maintenance operations during closed business hours ; -- Automation of redundant tasks through scripting ; -- Level 3 customer and internal support ; - -*Technical Support Engineer, from 02/2012 to 10/2012* - -- Level 1 customer support for both French and international customers and suppliers over the telephone and by e-mail ; -- Troubleshooting customers and internal users networking and system issues using standard tools and, when needed, through research and reproduction ; -- Contacting and following up with the appropriate internal services when needed to solve the issue. - -**CHALLANS City Hall (Challans, France)** - -*Internship, from 09/2011 to 11/2011* - -- Installation and configuration of a highly-available front-end reverse proxy ; -- Documentation of the installation and configuration process ; -- Level 1 user support. - -## Education - -**Technical Support Engineer - Six months training course** - -*IMIE, Rezé (France) from 02/2011 to 09/2011* - -**Bachelor Graduate in French Civil Law** - -*Universities of Nantes and Poitiers (France) from 2006 to 2010* - - diff --git a/content/postfixadmin.md b/content/postfixadmin.md deleted file mode 100644 index 4627c6d..0000000 --- a/content/postfixadmin.md +++ /dev/null @@ -1,150 +0,0 @@ -Title: Postfix Admin -Date: 2016-03-06 -Category: Tutorial - -As I explained in [this previous tutorial](https://www.captainark.net/setting-up-a-mail-server.html), I've been running my own mail server without any issue for some time now. - -However, every time I've wanted to add a domain, create a new mailbox or change a user's password, I've had to do it manually from a SQL shell. As fun as it may be, it does get old very fast, so I've decided to install a web frontend to manage this database. - -After a bit a googling, I've settled on [Postfix Admin](http://postfixadmin.sourceforge.net/). - -The latest stable version of Postfix Admin was released in 2009. Version 3.0 has been in the works for some time now and the project can be cloned from their [Github repo](https://github.com/postfixadmin/postfixadmin). - -I've also tried [ViMbAdmin](http://www.vimbadmin.net/), but it felt a little heavy considering what I was going to use it for. - -You'll need a web server with PHP support to run Postfix Admin. I personnaly run nginx with php5-fpm, but I won't explain how to configure it here. I'll simply explain how to migrate your current database to one managed with Postfix Admin with as little downtime as possible. - -# Creating a new database - -Since the database managed by Postfix Admin does not use the same schema as the one we've created in my previous tutorial, we'll have to create a new one. We will give all privileges on that database to the same user as before, `'mail'@'localhost'`. - -```sql -CREATE DATABASE mailnew; -GRANT ALL PRIVILEGES ON mailnew.* TO 'mail'@'localhost'; -FLUSH PRIVILEGES; -``` - -At this point, you can clone the Postfix Admin project from Github and go through the installation process. - -While editing the config.inc.php file (or config.local.php file if you've decided to copy it), make sure that the `database_name` option is set to use the `mailnew` database we've just created. - -Also, make sure that the `encrypt` option is set to `dovecot:SHA512-CRYPT`. - -The installation process will create all the necessary tables in the database. - -**At this point, you'll have to recreate all domains, mailboxes and aliases that you have configured in your current mail database using the Postfix Admin interface.** - -# Postfix configuration - -Once you're done with Postfix Admin, it's time to configure Postfix to use its schema. - -First thing first, let's backup our current configuration : - -``` -mkdir /etc/postfix/mysql-backup -cp -a /etc/postfix/mysql-virtual* /etc/postfix/mysql-backup/ -``` - -Next, we have to edit the 3 files we've just backed-up. The only line that actually changes is the one beginning with `query`. - -The first file is /etc/postfix/mysql-virtual-mailbox-domains.cf : - -``` -user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT 1 FROM domain WHERE domain='%s' AND active='1' -``` - -The second one is /etc/postfix/mysql-virtual-mailbox-maps.cf : - -``` -user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT 1 FROM mailbox WHERE username='%s' AND active='1' -``` - -And the last one is /etc/postfix/mysql-virtual-alias-maps.cf : - -``` -user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT goto FROM alias WHERE address='%s' AND active='1' -``` - -# Dovecot configuration - -Same as with Postfix, we now need to configure Dovecot to use the Postfix Admin schema. - -First, let's backup our current configuration : - -```bash -cp -a /etc/dovecot/sql.conf /etc/dovecot/sql.conf.bak -``` - -Next, we have to edit the /etc/dovecot/sql.conf file. The only line that changes is the one beginning with `password_query`. - -``` -driver = mysql -connect = host=localhost dbname=mail user=mail password=mailpassword -default_pass_scheme = SHA512-CRYPT -password_query = SELECT username as user, password FROM mailbox WHERE username='%u' AND active='1'; -``` - -# Migrating to the new schema - -We're done with the configuration part. Time to migrate to the new schema. - -First, let's create a backup of our current mail database : - -```bash -mysqldump mail | bzip2 > /home/user/mail.sql.bz2 -``` - -Next, in a SQL shell, we're going to drop and recreate the mail database : - -```sql -DROP DATABASE mail; -CREATE DATABASE mail; -``` - -We now have to dump the contents of the mailnew database into the newly created mail database : - -```bash -mysqldump mailnew | mysql mail -``` - -Next, let's restart Postfix and Dovecot so that they start using the new database schema : - -```bash -systemctl restart postfix -systemctl restart dovecot -``` - -At this point, Postfix and Dovecot are using the Postfix Admin schema in the mail database. - -The last thing we have to do is to edit Postfix Admin's config.inc.php file to use the mail database as well instead of the mailnew database that it should be currently using. - -# Cleanup - -Once you've confirmed that everything is working properly, you can delete the backup files we've created : - -```bash -rm -rf /etc/postfix/mysql-backup -rm /etc/dovecot/sql.conf.bak -``` - -You can drop the mailnew database as well : - -```sql -DROP DATABASE mailnew; -``` - -# Conclusion - -That's all ! As always, please do leave a comment if this article has been of any use to you ! \ No newline at end of file diff --git a/content/static/bg.png b/content/static/bg.png deleted file mode 100644 index ad5afe9..0000000 Binary files a/content/static/bg.png and /dev/null differ diff --git a/content/static/favicon.ico b/content/static/favicon.ico deleted file mode 100644 index 8babcf1..0000000 Binary files a/content/static/favicon.ico and /dev/null differ diff --git a/content/static/robots.txt b/content/static/robots.txt deleted file mode 100644 index e69de29..0000000 diff --git a/content/webdav-nginx.md b/content/webdav-nginx.md deleted file mode 100644 index a2c7cb2..0000000 --- a/content/webdav-nginx.md +++ /dev/null @@ -1,358 +0,0 @@ -Title: WebDAV with nginx -Date: 2016-03-26 -Category: Tutorial - -This website has been hosted on an [Online.net](https://www.online.net) dedicated server since its creation. I've been one of their customers for the past 3 years now, and I still don't have anything bad to say about them. - -They recently upgraded their personnal range, and I took the opportunity to upgrade from a single server running all of my services to 2 servers running LXC containers that are hosting my services. - -It took me 2 days to migrate everything, but it was worth it. If I decide to switch servers again, I'll have to migrate the containers instead of the services themselves. Considering they are stored on a separate BTRFS volume, it shouldn't take me more than a few hours at most. - -During the migration, I realized that I needed to make files that were hosted on one server accessible to the other. I could have gone with CIFS or NFS, but I wanted to have encryption built-in instead of having to rely on a VPN for that. Since I figured it was a good opportunity to learn something new, I ended up going with WebDAV. - -In this tutorial, I'll explain how I've configured a read-only WebDAV share using [nginx](https://www.nginx.com/) and [Let'sEncrypt](https://letsencrypt.org/) SSL certificates between two Debian Jessie containers. - -## Server configuration - -### Installing the required packages - -First thing first, we need to install the packages we'll need for this configuration : - -```bash -apt update - -apt -t jessie-backports install nginx letsencrypt -apt install apache2-utils -``` - -### Getting our first certificate from letsencrypt - -#### letsencrypt configuration - -Let's create a configuration file for letsencrypt : - -```bash -mkdir /etc/letsencrypt - -echo 'rsa-key-size = 3072 -renew-by-default -text = True -agree-tos = True -renew-by-default = True -authenticator = webroot -email = admin@example.com -webroot-path = /var/www/letsencrypt/' > /etc/letsencrypt/cli.ini -``` - -*Please do modify admin@example.com by your actual e-mail address.* - -We also need to create the directory structure where letsencrypt ACME challenge temporary files will be stored : - -``` -mkdir -p /var/www/letsencrypt/.well-known -``` - -#### nginx configuration - -We now need to configure nginx by adding the following in the `/etc/nginx/sites-available/default` file, anywhere in the `server{}` block that is configured to listen on port 80. - -``` -location /.well-known/acme-challenge { - root /var/www/letsencrypt; -} -``` - -Let's make sure that we haven't done anything wrong : - -```bash -nginx -t -``` - -The command should give you the following output : - -``` -nginx: the configuration file /etc/nginx/nginx.conf syntax is ok -nginx: configuration file /etc/nginx/nginx.conf test is successful -``` - -If that's the case, you can safely reload the nginx daemon : - -``` -nginx -s reload -``` - -#### Certificate request - -Now that letsencrypt and nginx are properly configured, we can request our certificate from letsencrypt : - -```bash -letsencrypt --config /etc/letsencrypt/cli.ini certonly -w /var/www/letsencrypt -d www.example.com -``` - -*Please do modify www.example.com by your server's FQDN, and please note that the letsencrypt servers need to be able to resolve that name to your server's IP.* - -If everything goes well, your certificates will be generated and stored in the /etc/letsencrypt folder. - -### WebDAV configuration - -Now that we've obtained our certificate from letsencrypt, we can begin configuring nginx. - -First, we need to comment two SSL directives from the default nginx configuration : - -``` -sed -i '/ssl_/ s/^/#/' /etc/nginx/nginx.conf -``` - -Let's now create a `/etc/nginx/conf.d/ssl.conf` with the following content : - -``` -ssl_session_timeout 1d; -ssl_session_cache shared:SSL:50m; -ssl_session_tickets off; - -ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; -ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem; -ssl_trusted_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem; - -ssl_dhparam /etc/nginx/ssl/dhparam.pem; - -ssl_protocols TLSv1 TLSv1.1 TLSv1.2; -ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; -ssl_prefer_server_ciphers on; - -add_header Strict-Transport-Security max-age=15768000; -add_header X-Frame-Options DENY; -add_header X-Content-Type-Options nosniff; - -ssl_stapling on; -ssl_stapling_verify on; -resolver 127.0.0.1 valid=300s; -resolver_timeout 5s; -``` - -*This configuration will work if you're using a single certificate on your server. If not, you'll have to remove the `ssl_certificate`, `ssl_certificate_key` and `ssl_trusted_certificate` directives from this file and move them to the correct `server{}` block.* - -We now need to generate a `dhparam.pem` file : - -```bash -mkdir /etc/nginx/ssl && chmod 700 /etc/nginx/ssl -openssl dhparam -out /etc/nginx/ssl/dhparam.pem 3072 -chmod 600 /etc/nginx/ssl/dhparam.pem -``` - -Let's now generate a HTTP basic authentication file. This example creates a user named example : - -``` -mkdir /etc/nginx/auth - -htpasswd -c /etc/nginx/auth/webdav example -New password: -Re-type new password: -Adding password for user user -``` - -This file has to be readable by the user running your webserver. For security reasons, we'll make it readable only by him : - -``` -chown -R www-data:nogroup /etc/nginx/auth -chmod 700 /etc/nginx/auth -chmod 400 /etc/nginx/auth/webdav -``` - -Let's now modify our `/etc/nginx/sites-available/default` file with the following content : - -``` -server { - listen 80 default_server; - listen [::]:80 default_server ipv6only=on; - server_name ""; - - return 444; -} - -server { - listen 443 default_server ssl http2; - listen [::]:443 default_server ipv6only=on ssl http2; - server_name ""; - - return 444; -} -``` - -We now have to create a `/etc/nginx/sites-available/example` file that will contain our actual webdav configuration. This example makes a `data` folder stored in `/var/www/` accessible. - -``` -server { - listen 80; - listen [::]:80; - server_name www.example.com; - return 301 https://$server_name$request_uri; -} - -server { - listen 443 ssl http2; - listen [::]:443 ssl http2; - server_name www.example.com; - - root /var/www; - - location / { - index index.html; - } - - location /.well-known/acme-challenge { - root /var/www/letsencrypt; - } - - location /data { - client_body_temp_path /tmp; - dav_methods PUT DELETE MKCOL COPY MOVE; - dav_ext_methods PROPFIND OPTIONS; - create_full_put_path on; - dav_access user:r group:r; - - auth_basic "Restricted access"; - auth_basic_user_file auth/webdav; - - limit_except GET { - allow ; - deny all; - } - } - -} -``` - -The last thing we have to do is to create a symlink so that nginx will load our configuration : - -``` -ln -s /etc/nginx/sites-available/example /etc/nginx/sites-enabled/example -``` - -Like before, let's make sure our configuration is correct and then reload the daemon : - -``` -nginx -t -nginx -s reload -``` - -That's it for the WebDAV configuration server-side ! - -### nginx monitoring - -If you're using monit, you can easily monitor the nginx daemon by copying the following in `/etc/monit/conf.d/nginx` : - -``` -check process nginx - with pidfile "/run/nginx.pid" - start program = "/bin/systemctl start nginx" - stop program = "/bin/systemctl stop nginx" - alert monit@example.com -``` - -### Certificates auto-renewal - -This goes beyond the scope of the article, but since letsencrypt certficates are only valid for 3 months, you'll need to renew them regularily. You can do so manually or you can setup a cron that does it for you. - -I personnaly use the following script : - -``` -#!/bin/bash - -PRG="/usr/bin/letsencrypt" -CONFIG="/etc/letsencrypt/cli.ini" -MAILDEST="admin@example.com" -GLOBAL=0 - -# www.example.com -$PRG --config $CONFIG certonly -w /var/www/letsencrypt -d www.example.com -[[ $? != 0 ]] && GLOBAL=$(( $GLOBAL + 1 )) - -if [[ $GLOBAL == 0 ]]; then - /usr/sbin/nginx -s reload -else - echo "Something went wrong while renewing the certificates on $(hostname -f) - Manual action needed." | mail -s "Letsencrypt error on $(hostname -f)" $MAILDEST -fi -``` - -You can add multiple domains in the script. As long as you add all 3 lines for each domain, it will not automatically reload nginx if one or more certificate could not be renewed and will send an e-mail to the address configured in the `MAILDEST` variable. - -You can configure this script in the root user crontab using the `crontab -e` command : - -``` -## LETSENCRYPT CERTIFICATE AUTORENEWAL -30 03 01 */2 * /root/bin/tlsrenew -``` -This will run the script every two months, on the first day of the month, at 3:30 AM. - -## Client configuration - -### Installing the required packages - -A single package is required to mount a webdav volume on Debian : - -``` -apt update && apt install davfs2 -``` - -### Mounting the share manually - -If like me, you want to mount your webdav share in a LXC container, you'll first need to make sure that the following line is present in its configuration file : - -``` -lxc.cgroup.devices.allow = c 10:229 rwm -``` - -You'll also need to create the `/dev/fuse` node in the container : - -``` -mknod /dev/fuse c 10 229 -``` - -In any case, we have to edit the `/etc/davfs2/secrets` file to add the mount point, username and password that will be used to mount the share : - -``` -echo '/data webdav notanactualpassword' >> /etc/davfs2/secrets -``` - -Once that's done, we can mount our share with the following command : - -``` -mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root -``` - -You might need to edit the parameters depending on which users you want to make the share available to. - -### Mouting the share on boot - -A davfs volume can be mounted via the `/etc/fstab` file, but I decided to use monit instead so that the volume would be mounted again automatically should my WebDAV server reboot. - -In order to do so, I first created a `davfs.txt` file in the `/var/www/data` folder on my WebDAV server : - -``` -touch /var/www/data/davfs.txt -``` - -I then created the following `/root/bin/mount_davfs` script : - -``` -#!/bin/bash - -mknod /dev/fuse c 10 229 -mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root -``` - -The last thing I did was create a `/etc/monit/conf.d/davfs` file with the following content : - -``` -check file davfs with path /data/davfs.txt - alert monit@example.com - if does not exist then exec "/root/bin/mount_davfs" -``` - -That way, if monit notices that the `/data/davfs.txt` file becomes inaccessible for some reason, it will try remouting the share. - -## Conclusion - -That's all ! Hopefully this has been useful to someone. Please do comment below if you have any question or if this has been helpful ! \ No newline at end of file diff --git a/develop_server.sh b/develop_server.sh deleted file mode 100755 index 8c2f27f..0000000 --- a/develop_server.sh +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env bash -## -# This section should match your Makefile -## -PY=${PY:-python} -PELICAN=${PELICAN:-pelican} -PELICANOPTS= - -BASEDIR=$(pwd) -INPUTDIR=$BASEDIR/content -OUTPUTDIR=$BASEDIR/output -CONFFILE=$BASEDIR/pelicanconf.py - -### -# Don't change stuff below here unless you are sure -### - -SRV_PID=$BASEDIR/srv.pid -PELICAN_PID=$BASEDIR/pelican.pid - -function usage(){ - echo "usage: $0 (stop) (start) (restart) [port]" - echo "This starts Pelican in debug and reload mode and then launches" - echo "an HTTP server to help site development. It doesn't read" - echo "your Pelican settings, so if you edit any paths in your Makefile" - echo "you will need to edit your settings as well." - exit 3 -} - -function alive() { - kill -0 $1 >/dev/null 2>&1 -} - -function shut_down(){ - PID=$(cat $SRV_PID) - if [[ $? -eq 0 ]]; then - if alive $PID; then - echo "Stopping HTTP server" - kill $PID - else - echo "Stale PID, deleting" - fi - rm $SRV_PID - else - echo "HTTP server PIDFile not found" - fi - - PID=$(cat $PELICAN_PID) - if [[ $? -eq 0 ]]; then - if alive $PID; then - echo "Killing Pelican" - kill $PID - else - echo "Stale PID, deleting" - fi - rm $PELICAN_PID - else - echo "Pelican PIDFile not found" - fi -} - -function start_up(){ - local port=$1 - echo "Starting up Pelican and HTTP server" - shift - $PELICAN --debug --autoreload -r $INPUTDIR -o $OUTPUTDIR -s $CONFFILE $PELICANOPTS & - pelican_pid=$! - echo $pelican_pid > $PELICAN_PID - cd $OUTPUTDIR - $PY -m pelican.server $port & - srv_pid=$! - echo $srv_pid > $SRV_PID - cd $BASEDIR - sleep 1 - if ! alive $pelican_pid ; then - echo "Pelican didn't start. Is the Pelican package installed?" - return 1 - elif ! alive $srv_pid ; then - echo "The HTTP server didn't start. Is there another service using port" $port "?" - return 1 - fi - echo 'Pelican and HTTP server processes now running in background.' -} - -### -# MAIN -### -[[ ($# -eq 0) || ($# -gt 2) ]] && usage -port='' -[[ $# -eq 2 ]] && port=$2 - -if [[ $1 == "stop" ]]; then - shut_down -elif [[ $1 == "restart" ]]; then - shut_down - start_up $port -elif [[ $1 == "start" ]]; then - if ! start_up $port; then - shut_down - fi -else - usage -fi diff --git a/fabfile.py b/fabfile.py deleted file mode 100644 index 95796b5..0000000 --- a/fabfile.py +++ /dev/null @@ -1,94 +0,0 @@ -from fabric.api import * -import fabric.contrib.project as project -import os -import shutil -import sys -import SocketServer - -from pelican.server import ComplexHTTPRequestHandler - -# Local path configuration (can be absolute or relative to fabfile) -env.deploy_path = 'output' -DEPLOY_PATH = env.deploy_path - -# Remote server configuration -production = 'root@localhost:22' -dest_path = '/var/www' - -# Rackspace Cloud Files configuration settings -env.cloudfiles_username = 'my_rackspace_username' -env.cloudfiles_api_key = 'my_rackspace_api_key' -env.cloudfiles_container = 'my_cloudfiles_container' - -# Github Pages configuration -env.github_pages_branch = "gh-pages" - -# Port for `serve` -PORT = 8000 - -def clean(): - """Remove generated files""" - if os.path.isdir(DEPLOY_PATH): - shutil.rmtree(DEPLOY_PATH) - os.makedirs(DEPLOY_PATH) - -def build(): - """Build local version of site""" - local('pelican -s pelicanconf.py') - -def rebuild(): - """`clean` then `build`""" - clean() - build() - -def regenerate(): - """Automatically regenerate site upon file modification""" - local('pelican -r -s pelicanconf.py') - -def serve(): - """Serve site at http://localhost:8000/""" - os.chdir(env.deploy_path) - - class AddressReuseTCPServer(SocketServer.TCPServer): - allow_reuse_address = True - - server = AddressReuseTCPServer(('', PORT), ComplexHTTPRequestHandler) - - sys.stderr.write('Serving on port {0} ...\n'.format(PORT)) - server.serve_forever() - -def reserve(): - """`build`, then `serve`""" - build() - serve() - -def preview(): - """Build production version of site""" - local('pelican -s publishconf.py') - -def cf_upload(): - """Publish to Rackspace Cloud Files""" - rebuild() - with lcd(DEPLOY_PATH): - local('swift -v -A https://auth.api.rackspacecloud.com/v1.0 ' - '-U {cloudfiles_username} ' - '-K {cloudfiles_api_key} ' - 'upload -c {cloudfiles_container} .'.format(**env)) - -@hosts(production) -def publish(): - """Publish to production via rsync""" - local('pelican -s publishconf.py') - project.rsync_project( - remote_dir=dest_path, - exclude=".DS_Store", - local_dir=DEPLOY_PATH.rstrip('/') + '/', - delete=True, - extra_opts='-c', - ) - -def gh_pages(): - """Publish to GitHub Pages""" - rebuild() - local("ghp-import -b {github_pages_branch} {deploy_path}".format(**env)) - local("git push origin {github_pages_branch}".format(**env)) diff --git a/output/archives.html b/output/archives.html deleted file mode 100644 index 267fdc0..0000000 --- a/output/archives.html +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Archives - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Archives for Sysadmining. All day. Every day.

-
-
-
-
-
- - -
-
-
-
-
Sat 26 March 2016
-
WebDAV with nginx
-
Sun 13 March 2016
-
MySQL backup script
-
Sun 06 March 2016
-
Postfix Admin
-
Tue 02 February 2016
-
My tmux configuration
-
Sun 31 January 2016
-
Debian updates with Ansible
-
Sun 31 January 2016
-
Private Git Repo
-
Tue 05 May 2015
-
Flexget init script
-
Fri 24 April 2015
-
Setting up a mail server
-
-
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/author/antoine-joubert.html b/output/author/antoine-joubert.html deleted file mode 100644 index 5bb6e88..0000000 --- a/output/author/antoine-joubert.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Articles by Antoine Joubert - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Articles by Antoine Joubert

-
-
-
-
-
- - -
-
-
-
- -

- WebDAV with nginx -

-
-

- This website has been hosted on an Online.net dedicated server since its creation. I've been one of their customers for the past 3 years... -

- -

There are comments.

-
- -

- MySQL backup script -

-
-

- I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but... -

- -

There are comments.

-
- -

- Postfix Admin -

-
-

- As I explained in this previous tutorial, I've been running my own mail server without any issue for some time now. However, every time... -

- -

There are comments.

-
- -

- My tmux configuration -

-
-

- tmux is a terminal mutiplexer. It lets you have multiples shells running in a single terminal emulator window and it keeps those shells... -

- -

There are comments.

-
- -

- Debian updates with Ansible -

-
-

- I've recently bought a HP Proliant Microserver Gen8 to play around with LXC and try new stuff. From the 4 Debian machines I had to keep... -

- -

There are comments.

-
- -

- Private Git Repo -

-
-

- I've decided to migrate this blog to Pelican. I've been playing around with it over the week-end, and it turns out to be way easier to... -

- -

There are comments.

-
- -

- Flexget init script -

-
-

- I've been using Flexget for the past two years or so as a download automator. Since I wrote an init script for it a while back, and it... -

- -

There are comments.

-
- -

- Setting up a mail server -

-
-

- In this first tutorial, I'll explain how I've configured my mail server using the following : A server running Linux Debian (jessie) ;... -

- -

There are comments.

- -
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/authors.html b/output/authors.html deleted file mode 100644 index 2e0ccec..0000000 --- a/output/authors.html +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Authors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Articles by

-
-
-
-
-
- - - - -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/bg.png b/output/bg.png deleted file mode 100644 index ad5afe9..0000000 Binary files a/output/bg.png and /dev/null differ diff --git a/output/categories.html b/output/categories.html deleted file mode 100644 index d086817..0000000 --- a/output/categories.html +++ /dev/null @@ -1,201 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Categories - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Sysadmining. All day. Every day. - Categories

-
-
-
-
-
- - - - -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/category/ansible-playbook.html b/output/category/ansible-playbook.html deleted file mode 100644 index 3af4436..0000000 --- a/output/category/ansible-playbook.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Articles in the Ansible Playbook category - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Articles in the Ansible Playbook category

-
-
-
-
-
- - -
-
-
-
- -

- Debian updates with Ansible -

-
-

- I've recently bought a HP Proliant Microserver Gen8 to play around with LXC and try new stuff. From the 4 Debian machines I had to keep... -

- -

There are comments.

- -
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/category/configuration-example.html b/output/category/configuration-example.html deleted file mode 100644 index f61890b..0000000 --- a/output/category/configuration-example.html +++ /dev/null @@ -1,210 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Articles in the Configuration example category - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Articles in the Configuration example category

-
-
-
-
-
- - -
-
-
-
- -

- My tmux configuration -

-
-

- tmux is a terminal mutiplexer. It lets you have multiples shells running in a single terminal emulator window and it keeps those shells... -

- -

There are comments.

- -
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/category/script.html b/output/category/script.html deleted file mode 100644 index c55b783..0000000 --- a/output/category/script.html +++ /dev/null @@ -1,224 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Articles in the Script category - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Articles in the Script category

-
-
-
-
-
- - -
-
-
-
- -

- MySQL backup script -

-
-

- I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but... -

- -

There are comments.

-
- -

- Flexget init script -

-
-

- I've been using Flexget for the past two years or so as a download automator. Since I wrote an init script for it a while back, and it... -

- -

There are comments.

- -
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/category/tutorial.html b/output/category/tutorial.html deleted file mode 100644 index 92d96cd..0000000 --- a/output/category/tutorial.html +++ /dev/null @@ -1,252 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Articles in the Tutorial category - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Articles in the Tutorial category

-
-
-
-
-
- - -
-
-
-
- -

- WebDAV with nginx -

-
-

- This website has been hosted on an Online.net dedicated server since its creation. I've been one of their customers for the past 3 years... -

- -

There are comments.

-
- -

- Postfix Admin -

-
-

- As I explained in this previous tutorial, I've been running my own mail server without any issue for some time now. However, every time... -

- -

There are comments.

-
- -

- Private Git Repo -

-
-

- I've decided to migrate this blog to Pelican. I've been playing around with it over the week-end, and it turns out to be way easier to... -

- -

There are comments.

-
- -

- Setting up a mail server -

-
-

- In this first tutorial, I'll explain how I've configured my mail server using the following : A server running Linux Debian (jessie) ;... -

- -

There are comments.

- -
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/debian-updates-with-ansible.html b/output/debian-updates-with-ansible.html deleted file mode 100644 index d1d2176..0000000 --- a/output/debian-updates-with-ansible.html +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - - Debian updates with Ansible - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Debian updates with Ansible

- Posted by - Antoine Joubert - on Sun 31 January 2016 - - -
-
-
-
-
- - -
-
-
- -
-

I've recently bought a HP Proliant Microserver Gen8 to play around with LXC and try new stuff.

-

From the 4 Debian machines I had to keep up-to-date, I now have 7, so it became quite time-consumming to manually SSH to each of them whenever an update became available.

-

I ended up looking at Ansible to speed up the process and, within an hour, I had a working playbook that updates the debian packages, pip packages and git repos installed on all of my servers with a single command.

-

I figured I'd share the playbook I use to update the Debian packages !

-

The playbook

-

I modified this gist to only use apt-get instead of both apt-get and aptitude.

-
- hosts: all
-  tasks:
-
-    - name: update cache
-      apt: update_cache=yes
-
-    - name: list packages to upgrade (1/2)
-      shell: apt-get upgrade -s -V | awk '/=>/{print $1}'
-      register: updates
-      changed_when: False
-
-    - name: list packages to upgrade (2/2)
-      debug: msg="{{ updates.stdout_lines | count }} packages to upgrade ({{ updates.stdout_lines | join(', ') }})"
-      when: (updates.stdout_lines)
-
-    - name: upgrade packages
-      apt: upgrade=dist
-      when: (updates.stdout_lines)
-
-    - name: check what the new version is
-      shell: lsb_release -r | awk '{print $2}'
-      changed_when: False
-      register: new_release
-
-    - name: notify distribution version upgrade
-      debug: msg="Debian has been upgraded from {{ ansible_lsb.release }} to {{ new_release.stdout }}"
-      when: ansible_lsb.release != new_release.stdout
-
-    - name: /wheezy/ install the debian-goodies package if it is missing
-      apt: name=debian-goodies state=present
-      when: ansible_distribution_release == 'wheezy'
-
-    - name: /jessie/ install the needrestart package if it is missing
-      apt: name=needrestart state=present default_release=jessie-backports
-      when: ansible_distribution_release == 'jessie'
-
-    - name: /wheezy/ list services to restart (1/3)
-      shell: checkrestart | awk '/^service/{print $2}'
-      register: wheezy_services
-      changed_when: False
-      when: ansible_distribution_release == 'wheezy'
-
-    - name: /jessie/ list services to restart (1/3)
-      shell: needrestart -blrl | awk '/^NEEDRESTART-SVC/{print $2}'
-      register: jessie_services
-      changed_when: False
-      when: ansible_distribution_release != 'wheezy'
-
-    - name: merge services list (2/3)
-      set_fact:
-        services: "{{ wheezy_services if ansible_distribution_release == 'wheezy' else jessie_services }}"
-
-    - name: list services to restart (3/3)
-      debug: msg="{{ services.stdout_lines | count }} services to restart ({{ services.stdout_lines | join (', ') }})"
-      when: (services.stdout_lines)
-
-    - name: cache cleanup
-      shell: apt-get autoclean
-
- - -

Conclusion

-

That's all ! Please leave a comment if you've found this playbook helpful !

-
- - -
- -
-

Comments !

-
- - -
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/favicon.ico b/output/favicon.ico deleted file mode 100644 index 8babcf1..0000000 Binary files a/output/favicon.ico and /dev/null differ diff --git a/output/flexget-init-script.html b/output/flexget-init-script.html deleted file mode 100644 index 9c4e144..0000000 --- a/output/flexget-init-script.html +++ /dev/null @@ -1,469 +0,0 @@ - - - - - - - - - - Flexget init script - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Flexget init script

- Posted by - Antoine Joubert - on Tue 05 May 2015 - - -
-
-
-
-
- - -
-
-
- -
-

I've been using Flexget for the past two years or so as a download automator.

-

Since I wrote an init script for it a while back, and it is compatible with Debian Jessie / systemd, I figured I'd share it here.

-

The script

-

All of the following should be done as the root user.

-

First, create a /etc/default/flexget file with the following content :

-
# Configuration file for /etc/init.d/flexget
-
-# User to run flexget as.
-# Daemon will not start if left empty.
-FGUSER=""
-
-# Full path to the flexget config.yml file to use.
-# Defaults to FGUSER $HOME/.flexget/config.yml
-CONFIG=""
-
-# Path to the directory where flexget should log. Do not add trailing slash.
-# Defaults to the FGUSER $HOME/.flexget directory
-LOG=""
-
-# Log verbosity 
-# Available options : none critical error warning info verbose debug trace
-# Defaults to info
-LEVEL=""
-
- - -

Please note that the FGUSER variable needs to be defined for the daemon to start. It can be set to your current user, or you can run flexget as its own user.

-

You can create a flexget user with the following command :

-
useradd -m -d /var/lib/flexget -r -s /bin/false flexget
-
- - -

Then, create the /etc/init.d/flexget file :

-
#!/bin/bash
-
-### BEGIN INIT INFO
-# Provides:          flexget
-# Required-Start:    $network $remote_fs
-# Required-Stop:     $network $remote_fs
-# Should-Start:      
-# Should-Stop:       
-# Default-Start:     2 3 4 5
-# Default-Stop:      0 1 6
-# Short-Description: Flexget
-# Description:       FlexGet is a multipurpose automation tool 
-#                    for content like torrents, nzbs, podcasts,
-#                    comics, series, movies, etc.
-### END INIT INFO
-
-# Author: Antoine Joubert, 19/01/2014
-
-NAME="flexget"
-DAEMON="/usr/local/bin/flexget"
-SETTINGS="/etc/default/$NAME"
-
-DESC="Flexget"
-PIDFILE="/var/run/$NAME.pid"
-
-set -e
-
-. /lib/lsb/init-functions
-
-unset FGUSER CONFIG LOG LEVEL
-
-# Exit if flexget not installed
-if [ ! -x "$DAEMON" ]; then
-  log_action_msg "$DESC: Could not find flexget executable. Exiting."
-  exit 2
-fi
-
-# Read configuration variables
-if [ -r /etc/default/$NAME ]; then
-  . /etc/default/$NAME
-else
-  log_action_msg "$DESC: /etc/default/$NAME not found. Exiting."
-  exit 2
-fi
-
-# Exit if FGUSER has not been set in /etc/default/flexget
-if [ -z $FGUSER ]; then
-  log_action_msg "$DESC: FGUSER not set in /etc/default/$NAME. Exiting."
-  exit 2
-fi
-
-# Function to verify if flexget is already running
-run_check() {
-  if [ -e $PIDFILE ]; then
-    status_of_proc -p $PIDFILE $DAEMON $NAME > /dev/null && RETVAL=0 || RETVAL="$?"
-  else
-    RETVAL="2"
-  fi
-}
-
-end_log() {
-  if [ $RETVAL -eq 0 ]; then
-    log_end_msg 0
-    return 0
-  else
-    log_end_msg 1
-    exit 1
-  fi
-}
-
-# Function to define config file, log file and log level
-conf_check() {
-  if [ -z $CONFIG ]; then
-    OPTIONS="$OPTIONS"
-  else
-    OPTIONS="-c $CONFIG"
-  fi
-
-  if [ -z $LOG ]; then
-    OPTIONS="$OPTIONS"
-  else
-    OPTIONS="$OPTIONS -l $LOG/flexget.log"
-    if [ ! -d $LOG ]; then 
-      mkdir -p -m 750 $LOG
-      chown $FGUSER $LOG
-    fi
-  fi
-
-  if [ -z $LEVEL ]; then
-    OPTIONS="$OPTIONS"
-  else
-    OPTIONS="$OPTIONS -L $LEVEL"
-  fi
-}
-
-start_flexget() {
-  run_check
-  if [ $RETVAL = 0 ]; then
-    log_action_msg "$DESC: Already running with PID $(cat $PIDFILE). Aborting."
-    exit 2
-  else
-    conf_check
-    log_daemon_msg "$DESC: Starting the daemon."
-    start-stop-daemon --start --background --quiet --pidfile $PIDFILE --make-pidfile \
-    --chuid $FGUSER --user $FGUSER --exec $DAEMON -- $OPTIONS daemon start
-    RETVAL=$?
-    end_log
-  fi
-}
-
-stop_flexget() {
-  run_check
-  if [ $RETVAL = 0 ]; then
-    log_daemon_msg "$DESC: Stopping the daemon."
-    start-stop-daemon --stop --quiet --chuid "$FGUSER" --pidfile "$PIDFILE" --retry 30
-    RETVAL=$?
-    [ -e "$PIDFILE" ] && rm -f "$PIDFILE"
-    end_log
-  else
-    log_action_msg "$DESC: Not currently running. Aborting."
-  exit 2
-  fi
-}
-
-status_flexget() {
-  run_check
-  if [ $RETVAL = 0 ]; then
-    log_action_msg "$DESC: Currently running with PID $(cat $PIDFILE)."
-  else
-    log_action_msg "$DESC: Not currently running."
-  fi
-  exit $RETVAL
-}
-
-case "$1" in
-  start)
-    start_flexget
-  ;;
-  stop)
-    stop_flexget
-  ;;
-  restart)
-    stop_flexget && sleep 2 && start_flexget
-  ;;
-  status)
-    status_flexget
-  ;;
-  *)
-    echo "Usage: $0 {start|stop|restart|status}"
-  ;;
-esac
-
-exit 0
-
- - -

Then, give execution rights to the script :

-
chmod +x /etc/init.d/flexget
-
- - -

And then, generate the necessary symlinks for the service to start on boot :

-

Debian Jessie

-
systemctl enable flexget
-
- - -

Debian Wheezy

-
insserv flexget
-
- - -

To start, stop or check if the daemon is running :

-

Debian Jessie

-
systemctl start flexget
-systemctl stop flexget
-systemctl status flexget
-
- - -

Debian Wheezy / Jessie

-
service flexget start
-service flexget stop
-service flexget status
-
- - -

Debian Wheezy

-
/etc/init.d/flexget start
-/etc/init.d/flexget stop
-/etc/init.d/flexget status
-
- - -

Conclusion

-

That's all ! If you are using this script, please let me know in the comment section below !

-
- - -
- -
-

Comments !

-
- - -
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/images/tmux.png b/output/images/tmux.png deleted file mode 100644 index 4ec4ee2..0000000 Binary files a/output/images/tmux.png and /dev/null differ diff --git a/output/images/tmux_fullsize.png b/output/images/tmux_fullsize.png deleted file mode 100644 index 9899041..0000000 Binary files a/output/images/tmux_fullsize.png and /dev/null differ diff --git a/output/index.html b/output/index.html deleted file mode 100644 index 9a938f4..0000000 --- a/output/index.html +++ /dev/null @@ -1,311 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Sysadmining. All day. Every day.

-
- Yet Another Blog about Linux and Networking -
-
-
-
-
- - -
-
-
-
- -

- WebDAV with nginx -

-
-

- This website has been hosted on an Online.net dedicated server since its creation. I've been one of their customers for the past 3 years... -

- -

There are comments.

-
- -

- MySQL backup script -

-
-

- I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but... -

- -

There are comments.

-
- -

- Postfix Admin -

-
-

- As I explained in this previous tutorial, I've been running my own mail server without any issue for some time now. However, every time... -

- -

There are comments.

-
- -

- My tmux configuration -

-
-

- tmux is a terminal mutiplexer. It lets you have multiples shells running in a single terminal emulator window and it keeps those shells... -

- -

There are comments.

-
- -

- Debian updates with Ansible -

-
-

- I've recently bought a HP Proliant Microserver Gen8 to play around with LXC and try new stuff. From the 4 Debian machines I had to keep... -

- -

There are comments.

-
- -

- Private Git Repo -

-
-

- I've decided to migrate this blog to Pelican. I've been playing around with it over the week-end, and it turns out to be way easier to... -

- -

There are comments.

-
- -

- Flexget init script -

-
-

- I've been using Flexget for the past two years or so as a download automator. Since I wrote an init script for it a while back, and it... -

- -

There are comments.

-
- -

- Setting up a mail server -

-
-

- In this first tutorial, I'll explain how I've configured my mail server using the following : A server running Linux Debian (jessie) ;... -

- -

There are comments.

- -
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/my-tmux-configuration.html b/output/my-tmux-configuration.html deleted file mode 100644 index 19abdb7..0000000 --- a/output/my-tmux-configuration.html +++ /dev/null @@ -1,406 +0,0 @@ - - - - - - - - - - My tmux configuration - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

My tmux configuration

- Posted by - Antoine Joubert - on Tue 02 February 2016 - - -
-
-
-
-
- - -
-
-
- -
-

tmux is a terminal mutiplexer. It lets you have multiples shells running in a single terminal emulator window and it keeps those shells running in the background should you need to close your terminal emulator.

-

I've played around with the configuration quite a bit to find settings that suit my needs. Here's what it ended up looking like :

-

tmux

-

This screenshot was done on Mac OS X, using the Terminal app and this Solarized theme.

-

I figured I'd share my tmux configuration here !

-

Installing tmux

-

tmux is available on Debian. I suggest using the jessie backports version :

-

apt -t jessie-backports install tmux

-

tmux is also available on Mac OS X using brew :

-

brew install tmux

-

tmux.conf

-

I used screen before tmux, so I configured the prefix key on C-a instead of C-b. tmux has the advantage of being much simpler to configure than screen.

-

If you want to use this configuration, simply copy the following in ~/.tmux.conf. This file is read by default when tmux starts.

-

If you simply want to try it out, copy it in a file somewhere else and have tmux load with the -f parameter (tmux -f ~/tmux-test.conf).

-
# use utf8
-set -g utf8
-set-option -g status-utf8 on
-set-window-option -g utf8 on
-
-# do not wait on esc key
-set-option -g escape-time 0
-
-# completely disable automatic rename
-set-window-option -g automatic-rename off
-
-# basic settings
-set -g default-terminal "screen-256color"
-set -g aggressive-resize off
-set-window-option -g xterm-keys on
-#set-window-option -g mode-mouse off
-
-# command history
-set -g history-limit 10000
-
-# messages
-set -g message-bg default
-set -g message-fg red
-
-# no visual activity
-set -g visual-activity off
-set -g visual-bell off
-
-# status bar
-set-option -g status-justify centre
-set-option -g status-bg default
-set-option -g status-fg blue
-set-option -g status-interval 5
-set-option -g status-left-length 30
-set-option -g status-left '#[fg=red][ #[fg=white]#H #[fg=red]]#[default]'
-set-option -g status-right '#[fg=red][ #[fg=white]%R %d/%m #[fg=red]]#[default]'
-
-# modes
-set-option -g mode-bg default
-set-option -g mode-fg blue
-
-# inactive window format
-set-window-option -g window-status-format '#I:#W#F'
-set-window-option -g monitor-activity on
-#set-window-option -g monitor-content on # not available in tmux 2.0
-
-# activity in a window
-set-window-option -g window-status-activity-attr dim
-set-window-option -g window-status-activity-bg default
-set-window-option -g window-status-activity-fg yellow
-
-# content in a window # not available in tmux 2.0
-#set-window-option -g window-status-content-attr dim
-#set-window-option -g window-status-content-bg default
-#set-window-option -g window-status-content-fg red
-
-# active window format
-set-window-option -g window-status-current-fg white
-set-window-option -g window-status-current-bg default
-set-window-option -g window-status-current-format '#[fg=red](#[default]#I:#W#F#[fg=red])#[default]'
-
-# reload tmux configuration
-unbind r
-bind r source-file ~/.tmux.conf \; display "Configuration reloaded!"
-
-# Screen-like keybinds
-unbind C-b
-set -g prefix ^A
-set -g prefix2 ^Q
-bind a send-prefix
-bind q send-prefix
-
-unbind c
-bind c new-window
-unbind ^C
-bind ^C new-window
-
-unbind n
-bind n next-window
-unbind ^N
-bind ^N next-window
-
-unbind A
-bind A command-prompt "rename-window %%"
-
-unbind p
-bind p previous-window
-unbind ^P
-bind ^P previous-window
-
-unbind a
-bind a last-window
-unbind ^A
-bind ^A last-window
-
-unbind [
-bind Escape copy-mode
-
-unbind w
-bind w list-windows
-
-unbind k
-bind k confirm-before "kill-window"
-
-unbind l
-bind l refresh-client
-
-unbind '"'
-bind '"' choose-window
-
- - -

Aliases

-

I also use two functions with tmux (in ~/.bash_aliases).

-

The first one creates a new "mytmux" tmux session if one doesn't exist yet, opens 10 shells and selects the first one.

-
mytmux() {
-  tmux has-session -t mytmux
-  if [ $? != 0 ]; then
-    tmux new-session -s mytmux -n $(hostname) -d
-    tmux new-window -t mytmux:1 -n $(hostname)
-    tmux new-window -t mytmux:2 -n $(hostname)
-    tmux new-window -t mytmux:3 -n $(hostname)
-    tmux new-window -t mytmux:4 -n $(hostname)
-    tmux new-window -t mytmux:5 -n $(hostname)
-    tmux new-window -t mytmux:6 -n $(hostname)
-    tmux new-window -t mytmux:7 -n $(hostname)
-    tmux new-window -t mytmux:8 -n $(hostname)
-    tmux new-window -t mytmux:9 -n $(hostname)
-    tmux select-window -t mytmux:0
-  fi
-  tmux attach -t mytmux
-}
-
- - -

The second one changes the tmux window name whenever I ssh to a remote host, and switches the window name back to the name of my computer when I logout from the host.

-
if [ -n "$TMUX" ]; then
-  ssh() {
-    if [ $# -le 2 ]; then
-      tmux rename-window "${@: -1}"
-      command ssh "$@"
-      tmux rename-window "$(hostname)"
-    else
-      command ssh "$@"
-    fi
-  }
-fi
-
- - -

Conclusion

-

That's all ! As always, please do leave a comment if you've found something useful in this article !

-
- - -
- -
-

Comments !

-
- - -
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/mysql-backup-script.html b/output/mysql-backup-script.html deleted file mode 100644 index 07d6f5e..0000000 --- a/output/mysql-backup-script.html +++ /dev/null @@ -1,279 +0,0 @@ - - - - - - - - - - MySQL backup script - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

MySQL backup script

- Posted by - Antoine Joubert - on Sun 13 March 2016 - - -
-
-
-
-
- - -
-
-
- -
-

I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but hey, I figured I'd share it here anyway.

-

The script

-

For the script to work, you'll need to edit a few variable to match your configuration.

-
    -
  • BACKUPDIR is the path of the directory where you want your backups to be stored.
  • -
  • BACKUPUSR is the user that will connect to MySQL to dump the databases. It should have access to all you databases without needing a password.
  • -
  • EXCLUDELIST is a list of databases that should not be backed-up. Leaving it as is is probably fine.
  • -
-
#!/bin/bash
-
-BACKUPDIR="/home/user/backup"
-BACKUPUSR="user"
-EXCLUDELIST="^Databases$|^information_schema$|^mysql$|^performance_schema$"
-
-sqlbk() {
-  for each in $(mysqlshow | awk '/[[:alnum:]]/{print $2}'); do
-    if [[ $each =~ $EXCLUDELIST ]]; then
-      true
-    else
-      mysqldump $each | bzip2 > ${BACKUPDIR}/${each}.sql.bz2
-      chown ${BACKUPUSR}: ${BACKUPDIR}/${each}.sql.bz2 && chmod 600 ${BACKUPDIR}/${each}.sql.bz2
-    fi
-  done
-}
-
-[[ -e /etc/init.d/mysql ]] && sqlbk
-
- - -

I personnaly have this script running once a week, in my user's personnal crontab (editable using the crontab -e command) :

-
## WEEKLY DATABASE BACKUP
-@weekly /home/user/bin/backupdb
-
- - -

Conclusion

-

You've probably noticed that the script erases the previous backup when a new one is made.

-

I don't need to keep multiple versions of the same database backup on my servers because they are all saved remotely on a daily basis using Rsnapshot. I'll probably write an article on the subject in the future.

-

As usual, feedback is always appreciated !

-
- - -
- -
-

Comments !

-
- - -
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/pages/about.html b/output/pages/about.html deleted file mode 100644 index 9073e4e..0000000 --- a/output/pages/about.html +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - - - - About - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

About

-
-
-
-
-
- - -
-
-
-
-

My blog.

-
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/pages/resume.html b/output/pages/resume.html deleted file mode 100644 index e88efa9..0000000 --- a/output/pages/resume.html +++ /dev/null @@ -1,263 +0,0 @@ - - - - - - - - - - Resume - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Resume

-
-
-
-
-
- - -
-
-
-
-

Profile

-

Hi ! I'm Antoine. I'm a 28 years old Systems and Network administrator, specialized in Linux and network management. I am not currently looking for a new opportunity.

-

If you find my profile interesting or if you have any questions, please send me an email !

-

Skills Summary

-
    -
  • Expertise in Linux and Cisco IOS routing, firewalling, QoS and VLAN configuration, for IPv4 and IPv6 ;
  • -
  • Knowledge of dynamic routing protocols (BGP, OSPF, EIGRP) and VPN software (OpenVPN) ;
  • -
  • Experience with a DDOS mitigation system (Arbor TMS) ;
  • -
  • Expertise in standard network and systems analyzing and troubleshooting tools (tcpdump, dig, atop, wireshark, traceroute) ;
  • -
  • Knowledge of monitoring software (nagios, shinken, cacti, smokeping, observium, ELK) ;
  • -
  • Experience with Linux servers and desktops installation, configuration, administration and troubleshooting (on both Debian and RedHat based distributions) ;
  • -
  • Familiarity with the most common network protocols (HTTP, DNS, DHCP, SMTP, POP, IMAP, CIFS) and their associated daemons (nginx, apache, bind, powerdns, dhcpd, dnsmasq, postfix, dovecot, samba) ;
  • -
  • Ability to write and debug bash, batch and powershell scripts ;
  • -
  • Experience with clustering and high-availability technologies (heartbeat, ipvsadm, VRRP, HSRP, SLB) ;
  • -
  • Knowledge of virtualization technologies (VMWare Workstation, KVM, Xen, Proxmox, LXC) ;
  • -
  • Experience with information resources management and incident management software (GLPI, OCS Inventory, FusionInventory) ;
  • -
  • Familiarity with Windows desktop (8, 7 and XP) and server (2012, 2008, 2003) families, and with Mac OS X.
  • -
-

Work Experience

-

NAMESHIELD (Angers, France)

-

Network Architect, from 09/2015 to now

-
    -
  • Technical projects management :
  • -
  • WiFi deployment, using Cisco WLC and Aironet devices as well as Freeradius for EAP-TLS/802.1x user authentication ;
  • -
  • VLAN deployment ;
  • -
  • L2 VPN setup using OpenVPN to securely propagate private VLANs over the internet ;
  • -
-

Systems and Network Administrator, from 10/2013 to 08/2015

-
    -
  • Technical projects management, notably :
  • -
  • Definition, configuration and maintenance of a highly-available networking architecture for WAN, site-to-site and road warrior VPN access ;
  • -
  • Setup of a DDOS mitigation system and its associated procedures ;
  • -
  • IPv6 deployment, on both LAN and data-center hosted machines ;
  • -
  • Setup of a centralized logging solution and its associated scripts to generate statistics ;
  • -
  • Linux systems, VOIP Phones, Cisco switches and routers configuration, deployment, administration and troubleshooting ;
  • -
  • Daily monitoring and production control, and incident management ;
  • -
  • User support on Linux and Windows systems.
  • -
-

INIT SYS - Alphalink Group (Pornic, France)

-

Systems and Network Administration Technician, from 10/2012 to 08/2013

-
    -
  • Linux systems and services installation and configuration, on both physical and virtual machines ;
  • -
  • Documentation of newly installed systems and their role within the existing infrastructure ;
  • -
  • Servers and network monitoring and optimisation ;
  • -
  • Systems and network maintenance operations during closed business hours ;
  • -
  • Automation of redundant tasks through scripting ;
  • -
  • Level 3 customer and internal support ;
  • -
-

Technical Support Engineer, from 02/2012 to 10/2012

-
    -
  • Level 1 customer support for both French and international customers and suppliers over the telephone and by e-mail ;
  • -
  • Troubleshooting customers and internal users networking and system issues using standard tools and, when needed, through research and reproduction ;
  • -
  • Contacting and following up with the appropriate internal services when needed to solve the issue.
  • -
-

CHALLANS City Hall (Challans, France)

-

Internship, from 09/2011 to 11/2011

-
    -
  • Installation and configuration of a highly-available front-end reverse proxy ;
  • -
  • Documentation of the installation and configuration process ;
  • -
  • Level 1 user support.
  • -
-

Education

-

Technical Support Engineer - Six months training course

-

IMIE, Rezé (France) from 02/2011 to 09/2011

-

Bachelor Graduate in French Civil Law

-

Universities of Nantes and Poitiers (France) from 2006 to 2010

-
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/postfix-admin.html b/output/postfix-admin.html deleted file mode 100644 index b69ad24..0000000 --- a/output/postfix-admin.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - - - - - - Postfix Admin - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Postfix Admin

- Posted by - Antoine Joubert - on Sun 06 March 2016 - - -
-
-
-
-
- - -
-
-
- -
-

As I explained in this previous tutorial, I've been running my own mail server without any issue for some time now.

-

However, every time I've wanted to add a domain, create a new mailbox or change a user's password, I've had to do it manually from a SQL shell. As fun as it may be, it does get old very fast, so I've decided to install a web frontend to manage this database.

-

After a bit a googling, I've settled on Postfix Admin.

-

The latest stable version of Postfix Admin was released in 2009. Version 3.0 has been in the works for some time now and the project can be cloned from their Github repo.

-

I've also tried ViMbAdmin, but it felt a little heavy considering what I was going to use it for.

-

You'll need a web server with PHP support to run Postfix Admin. I personnaly run nginx with php5-fpm, but I won't explain how to configure it here. I'll simply explain how to migrate your current database to one managed with Postfix Admin with as little downtime as possible.

-

Creating a new database

-

Since the database managed by Postfix Admin does not use the same schema as the one we've created in my previous tutorial, we'll have to create a new one. We will give all privileges on that database to the same user as before, 'mail'@'localhost'.

-
CREATE DATABASE mailnew;
-GRANT ALL PRIVILEGES ON mailnew.* TO 'mail'@'localhost';
-FLUSH PRIVILEGES;
-
- - -

At this point, you can clone the Postfix Admin project from Github and go through the installation process.

-

While editing the config.inc.php file (or config.local.php file if you've decided to copy it), make sure that the database_name option is set to use the mailnew database we've just created.

-

Also, make sure that the encrypt option is set to dovecot:SHA512-CRYPT.

-

The installation process will create all the necessary tables in the database.

-

At this point, you'll have to recreate all domains, mailboxes and aliases that you have configured in your current mail database using the Postfix Admin interface.

-

Postfix configuration

-

Once you're done with Postfix Admin, it's time to configure Postfix to use its schema.

-

First thing first, let's backup our current configuration :

-
mkdir /etc/postfix/mysql-backup
-cp -a /etc/postfix/mysql-virtual* /etc/postfix/mysql-backup/
-
- - -

Next, we have to edit the 3 files we've just backed-up. The only line that actually changes is the one beginning with query.

-

The first file is /etc/postfix/mysql-virtual-mailbox-domains.cf :

-
user = mail
-password = mailpassword
-hosts = 127.0.0.1
-dbname = mail
-query = SELECT 1 FROM domain WHERE domain='%s' AND active='1'
-
- - -

The second one is /etc/postfix/mysql-virtual-mailbox-maps.cf :

-
user = mail
-password = mailpassword
-hosts = 127.0.0.1
-dbname = mail
-query = SELECT 1 FROM mailbox WHERE username='%s' AND active='1'
-
- - -

And the last one is /etc/postfix/mysql-virtual-alias-maps.cf :

-
user = mail
-password = mailpassword
-hosts = 127.0.0.1
-dbname = mail
-query = SELECT goto FROM alias WHERE address='%s' AND active='1'
-
- - -

Dovecot configuration

-

Same as with Postfix, we now need to configure Dovecot to use the Postfix Admin schema.

-

First, let's backup our current configuration :

-
cp -a /etc/dovecot/sql.conf /etc/dovecot/sql.conf.bak
-
- - -

Next, we have to edit the /etc/dovecot/sql.conf file. The only line that changes is the one beginning with password_query.

-
driver = mysql
-connect = host=localhost dbname=mail user=mail password=mailpassword
-default_pass_scheme = SHA512-CRYPT
-password_query = SELECT username as user, password FROM mailbox WHERE username='%u' AND active='1';
-
- - -

Migrating to the new schema

-

We're done with the configuration part. Time to migrate to the new schema.

-

First, let's create a backup of our current mail database :

-
mysqldump mail | bzip2 > /home/user/mail.sql.bz2
-
- - -

Next, in a SQL shell, we're going to drop and recreate the mail database :

-
DROP DATABASE mail;
-CREATE DATABASE mail;
-
- - -

We now have to dump the contents of the mailnew database into the newly created mail database :

-
mysqldump mailnew | mysql mail
-
- - -

Next, let's restart Postfix and Dovecot so that they start using the new database schema :

-
systemctl restart postfix
-systemctl restart dovecot
-
- - -

At this point, Postfix and Dovecot are using the Postfix Admin schema in the mail database.

-

The last thing we have to do is to edit Postfix Admin's config.inc.php file to use the mail database as well instead of the mailnew database that it should be currently using.

-

Cleanup

-

Once you've confirmed that everything is working properly, you can delete the backup files we've created :

-
rm -rf /etc/postfix/mysql-backup
-rm /etc/dovecot/sql.conf.bak 
-
- - -

You can drop the mailnew database as well :

-
DROP DATABASE mailnew;
-
- - -

Conclusion

-

That's all ! As always, please do leave a comment if this article has been of any use to you !

-
- - -
- -
-

Comments !

-
- - -
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/private-git-repo.html b/output/private-git-repo.html deleted file mode 100644 index 1aeed8f..0000000 --- a/output/private-git-repo.html +++ /dev/null @@ -1,381 +0,0 @@ - - - - - - - - - - Private Git Repo - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Private Git Repo

- Posted by - Antoine Joubert - on Sun 31 January 2016 - - -
-
-
-
-
- - -
-
-
- -
-

I've decided to migrate this blog to Pelican. I've been playing around with it over the week-end, and it turns out to be way easier to manage than Jekyll. Themes are much easier to install and configure, so it ends up looking better as well !

-

Since I'm basically recreating this blog from scratch, I've decided to delete the old git repo that was hosting it and to create a new one.

-

Setting up your own private git repo is pretty easy to achieve and is already well-documented on the Git website.

-

Every time I want to create a new repo, I've had time to forget how to do it and I end up looking for that page, so I figured I'd write a few lines on the subject.

-

In this tutorial, I'll configure a git repo on a distant server running Debian 8 (Jessie). This repo will be remotely accessible using SSH. Two users will be able to connect to it : me and the www-data user on my webserver.

-

SSH Keys

-

If you don't have one already, you'll need a ssh-key to connect to the git repo.

-

On your computer, in a shell, as your usual user :

-
ssh-keygen -t rsa -b 3072
-Generating public/private rsa key pair.
-Enter file in which to save the key (/home/user/.ssh/id_rsa): 
-Enter passphrase (empty for no passphrase): 
-Enter same passphrase again: 
-Your identification has been saved in /home/user/.ssh/id_rsa.
-Your public key has been saved in /home/user/id_rsa.pub.
-The key fingerprint is:
-[Redacted]
-
- - -

For security reasons, configuring a passphrase is recommended. On Mac OS X and most desktop environnements on Linux, you can store this passphrase for the duration of your session using the ssh-add command, so you won't have to type it every time you want to connect to a host.

-

On the server, we also have to create a ssh-key for the user that is running our webserver (you'll need to have sudo installed) :

-
sudo -H -u www-data ssh-keygen -t rsa -b 3072
-Generating public/private rsa key pair.
-Enter file in which to save the key (/var/www/.ssh/id_rsa): 
-Enter passphrase (empty for no passphrase): 
-Enter same passphrase again: 
-Your identification has been saved in /var/www/.ssh/id_rsa.
-Your public key has been saved in /var/www/.ssh/id_rsa.pub.
-The key fingerprint is:
-[Redacted]
-
- - -

If you decide to configure a passphrase for that ssh-key, you'll have to type it every time you'll want to pull from your repo.

-

Server management

-

All of the commands in this section have to be run as root.

-

First thing first, we have to install the git package on the server that will be hosting our git repos :

-
apt update && apt install git -y
-
- - -

Then, we have to create a user named git :

-
useradd -s /usr/bin/git-shell -m -r git
-
- - -

This will create a system user (UID < 1000) with a /home/git home directory. If you want to host your git repos somewhere else on your filesystem, you should add a -d /home/directory/for/git in the previous command.

-

This user will use the git-shell shell. This limits remote connection to that user to git commands (like the rssh shell can limit remote connection to a user to scp or rsync commands).

-

We have to configure our system to allow the use of this shell :

-
echo '/usr/bin/git-shell' >> /etc/shells
-
- - -

From this point, you should have to following output if you try to SSH to your server with that user :

-
ssh git@git.captainark.net
-fatal: Interactive git shell is not enabled.
-hint: ~/git-shell-commands should exist and have read and execute access.
-Connection to git@git.captainark.net closed.
-
- - -

We now need to create the .ssh/authorized_keys file for the git user with the correct permissions :

-
sudo -H -u git mkdir /home/git/.ssh && chmod 700 /home/git/.ssh
-sudo -H -u git touch /home/git/.ssh/authorized_keys && chmod 600 /home/git/.ssh/authorized_keys
-
- - -

You can now copy/paste the content of the two $HOME/.ssh/id_rsa.pub files we've created earlier using the ssh-keygen command in /home/git/.ssh/authorized_keys.

-

The last thing we have to do is to create our first git repo. In this example, my project will be called 'captainarkdotnet' as it will be hosting this blog :

-
sudo -H -u git mkdir /home/git/captainarkdotnet.git
-cd /home/git/captainarkdotnet.git
-sudo -H -u git git init --bare
-
- - -

The last command should give you the following output :

-
Initialized empty Git repository in /home/git/captainarkdotnet.git/.git/
-
- - -

We're done with the server configuration. Let's now actually push stuff to our repo !

-

Initial push

-

The files for my blog are store in the ~/Documents/projects/captainarkdotnet on my computer. Before doing anything else, we first have to make sure that we currently are in that folder :

-
cd ~/Documents/projects/captainarkdotnet
-
- - -

Let's now push the content of that folder to our repo :

-
git init
-git add .
-git commit -m 'initial commit'
-git remote add origin git@git.captainark.net:captainarkdotnet.git
-git push origin master
-
- - -

Please note that you'll need to edit git.captainark.net to the FQDN or IP of your git server, and captainarkdotnet.git to the name of the git project on your server.

-

If everything went well, the last command should give you the following output :

-
Counting objects: 69, done.
-Delta compression using up to 4 threads.
-Compressing objects: 100% (64/64), done.
-Writing objects: 100% (69/69), 1.01 MiB | 0 bytes/s, done.
-Total 69 (delta 15), reused 0 (delta 0)
-To git@git.captainark.net:captainarkdotnet.git
- * [new branch]      master -> master
-
- - -

That's it, we've now pushed our first commit to our server !

-

First pull

-

Alright, time to pull the files we've just pushed on our webserver. I personally store my web content in /var/www ; if you don't, you'll have to adjust the path accordingly :

-
cd /var/www
-sudo -H -u www-data git clone git@git.captainark.net:captainarkdotnet.git
-
- - -

SSH will ask you to type 'yes' since it's the first time the www-data user connects to the server. If everything goes well, you should have the following output :

-
Cloning into 'captainarkdotnet'...
-remote: Counting objects: 70, done.
-remote: Compressing objects: 100% (65/65), done.
-remote: Total 70 (delta 16), reused 0 (delta 0)
-Receiving objects: 100% (70/70), 1.01 MiB | 0 bytes/s, done.
-Resolving deltas: 100% (16/16), done.
-Checking connectivity... done.
-
- - -

Conclusion

-

That's it ! We now have a working private git repo ! I won't go into details into the git commands in this tutorial, but here's a quick overwiew of the ones I use the most :

-
    -
  • git add . recursively adds all files from the directory to the repo ;
  • -
  • git commit -a -m 'This is a comment' commits the current state of your local repo with the 'This is a comment' comment ;
  • -
  • git push pushes your commits to the distant repo ;
  • -
  • git pull pulls the latest version of the distant repo locally ;
  • -
  • git branch -av shows all available branches for the repo ;
  • -
  • git checkout -b testing remotes/origin/testing create a local 'testing' branch based on the remote 'remotes/origin/testing' branch ;
  • -
  • once a branch has been copied locally, you can switch to it with the git checkout {branch} command.
  • -
-

For more information on git a command, use man git-{command} !

-

If you've found this tutorial in any way helpful, please feel free to leave a comment !

-
- - -
- -
-

Comments !

-
- - -
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/robots.txt b/output/robots.txt deleted file mode 100644 index e69de29..0000000 diff --git a/output/rss.xml b/output/rss.xml deleted file mode 100644 index 67d18df..0000000 --- a/output/rss.xml +++ /dev/null @@ -1,2043 +0,0 @@ - -Sysadmining. All day. Every day.https://captainark.net/2016-03-26T00:00:00+01:00WebDAV with nginx2016-03-26T00:00:00+01:002016-03-26T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-03-26:/webdav-with-nginx.html<p>This website has been hosted on an <a href="https://www.online.net">Online.net</a> dedicated server since its creation. I've been one of their customers for the past 3 years now, and I still don't have anything bad to say about them.</p> -<p>They recently upgraded their personnal range, and I took the opportunity to upgrade …</p><p>This website has been hosted on an <a href="https://www.online.net">Online.net</a> dedicated server since its creation. I've been one of their customers for the past 3 years now, and I still don't have anything bad to say about them.</p> -<p>They recently upgraded their personnal range, and I took the opportunity to upgrade from a single server running all of my services to 2 servers running LXC containers that are hosting my services.</p> -<p>It took me 2 days to migrate everything, but it was worth it. If I decide to switch servers again, I'll have to migrate the containers instead of the services themselves. Considering they are stored on a separate BTRFS volume, it shouldn't take me more than a few hours at most.</p> -<p>During the migration, I realized that I needed to make files that were hosted on one server accessible to the other. I could have gone with CIFS or NFS, but I wanted to have encryption built-in instead of having to rely on a VPN for that. Since I figured it was a good opportunity to learn something new, I ended up going with WebDAV.</p> -<p>In this tutorial, I'll explain how I've configured a read-only WebDAV share using <a href="https://www.nginx.com/">nginx</a> and <a href="https://letsencrypt.org/">Let'sEncrypt</a> SSL certificates between two Debian Jessie containers.</p> -<h2>Server configuration</h2> -<h3>Installing the required packages</h3> -<p>First thing first, we need to install the packages we'll need for this configuration :</p> -<div class="highlight"><pre><span></span>apt update - -apt -t jessie-backports install nginx letsencrypt -apt install apache2-utils -</pre></div> - - -<h3>Getting our first certificate from letsencrypt</h3> -<h4>letsencrypt configuration</h4> -<p>Let's create a configuration file for letsencrypt :</p> -<div class="highlight"><pre><span></span>mkdir /etc/letsencrypt - -<span class="nb">echo</span> <span class="s1">&#39;rsa-key-size = 3072</span> -<span class="s1">renew-by-default</span> -<span class="s1">text = True</span> -<span class="s1">agree-tos = True</span> -<span class="s1">renew-by-default = True</span> -<span class="s1">authenticator = webroot</span> -<span class="s1">email = admin@example.com</span> -<span class="s1">webroot-path = /var/www/letsencrypt/&#39;</span> &gt; /etc/letsencrypt/cli.ini -</pre></div> - - -<p><em>Please do modify admin@example.com by your actual e-mail address.</em></p> -<p>We also need to create the directory structure where letsencrypt ACME challenge temporary files will be stored :</p> -<div class="highlight"><pre><span></span>mkdir -p /var/www/letsencrypt/.well-known -</pre></div> - - -<h4>nginx configuration</h4> -<p>We now need to configure nginx by adding the following in the <code>/etc/nginx/sites-available/default</code> file, anywhere in the <code>server{}</code> block that is configured to listen on port 80.</p> -<div class="highlight"><pre><span></span>location /.well-known/acme-challenge { - root /var/www/letsencrypt; -} -</pre></div> - - -<p>Let's make sure that we haven't done anything wrong :</p> -<div class="highlight"><pre><span></span>nginx -t -</pre></div> - - -<p>The command should give you the following output :</p> -<div class="highlight"><pre><span></span><span class="n">nginx</span><span class="o">:</span> <span class="n">the</span> <span class="n">configuration</span> <span class="n">file</span> <span class="sr">/etc/nginx/</span><span class="n">nginx</span><span class="o">.</span><span class="na">conf</span> <span class="n">syntax</span> <span class="k">is</span> <span class="n">ok</span> -<span class="n">nginx</span><span class="o">:</span> <span class="n">configuration</span> <span class="n">file</span> <span class="sr">/etc/nginx/</span><span class="n">nginx</span><span class="o">.</span><span class="na">conf</span> <span class="n">test</span> <span class="k">is</span> <span class="n">successful</span> -</pre></div> - - -<p>If that's the case, you can safely reload the nginx daemon :</p> -<div class="highlight"><pre><span></span>nginx -s reload -</pre></div> - - -<h4>Certificate request</h4> -<p>Now that letsencrypt and nginx are properly configured, we can request our certificate from letsencrypt :</p> -<div class="highlight"><pre><span></span>letsencrypt --config /etc/letsencrypt/cli.ini certonly -w /var/www/letsencrypt -d www.example.com -</pre></div> - - -<p><em>Please do modify www.example.com by your server's FQDN, and please note that the letsencrypt servers need to be able to resolve that name to your server's IP.</em></p> -<p>If everything goes well, your certificates will be generated and stored in the /etc/letsencrypt folder.</p> -<h3>WebDAV configuration</h3> -<p>Now that we've obtained our certificate from letsencrypt, we can begin configuring nginx.</p> -<p>First, we need to comment two SSL directives from the default nginx configuration :</p> -<div class="highlight"><pre><span></span>sed -i &#39;/ssl_/ s/^/#/&#39; /etc/nginx/nginx.conf -</pre></div> - - -<p>Let's now create a <code>/etc/nginx/conf.d/ssl.conf</code> with the following content :</p> -<div class="highlight"><pre><span></span><span class="nt">ssl_session_timeout</span> <span class="nt">1d</span><span class="o">;</span> -<span class="nt">ssl_session_cache</span> <span class="nt">shared</span><span class="p">:</span><span class="nd">SSL</span><span class="p">:</span><span class="nd">50m</span><span class="o">;</span> -<span class="nt">ssl_session_tickets</span> <span class="nt">off</span><span class="o">;</span> - -<span class="nt">ssl_certificate</span> <span class="o">/</span><span class="nt">etc</span><span class="o">/</span><span class="nt">letsencrypt</span><span class="o">/</span><span class="nt">live</span><span class="o">/</span><span class="nt">www</span><span class="p">.</span><span class="nc">example</span><span class="p">.</span><span class="nc">com</span><span class="o">/</span><span class="nt">fullchain</span><span class="p">.</span><span class="nc">pem</span><span class="o">;</span> -<span class="nt">ssl_certificate_key</span> <span class="o">/</span><span class="nt">etc</span><span class="o">/</span><span class="nt">letsencrypt</span><span class="o">/</span><span class="nt">live</span><span class="o">/</span><span class="nt">www</span><span class="p">.</span><span class="nc">example</span><span class="p">.</span><span class="nc">com</span><span class="o">/</span><span class="nt">privkey</span><span class="p">.</span><span class="nc">pem</span><span class="o">;</span> -<span class="nt">ssl_trusted_certificate</span> <span class="o">/</span><span class="nt">etc</span><span class="o">/</span><span class="nt">letsencrypt</span><span class="o">/</span><span class="nt">live</span><span class="o">/</span><span class="nt">www</span><span class="p">.</span><span class="nc">example</span><span class="p">.</span><span class="nc">com</span><span class="o">/</span><span class="nt">fullchain</span><span class="p">.</span><span class="nc">pem</span><span class="o">;</span> - -<span class="nt">ssl_dhparam</span> <span class="o">/</span><span class="nt">etc</span><span class="o">/</span><span class="nt">nginx</span><span class="o">/</span><span class="nt">ssl</span><span class="o">/</span><span class="nt">dhparam</span><span class="p">.</span><span class="nc">pem</span><span class="o">;</span> - -<span class="nt">ssl_protocols</span> <span class="nt">TLSv1</span> <span class="nt">TLSv1</span><span class="p">.</span><span class="nc">1</span> <span class="nt">TLSv1</span><span class="p">.</span><span class="nc">2</span><span class="o">;</span> -<span class="nt">ssl_ciphers</span> <span class="s1">&#39;ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS&#39;</span><span class="o">;</span> -<span class="nt">ssl_prefer_server_ciphers</span> <span class="nt">on</span><span class="o">;</span> - -<span class="nt">add_header</span> <span class="nt">Strict-Transport-Security</span> <span class="nt">max-age</span><span class="o">=</span><span class="nt">15768000</span><span class="o">;</span> -<span class="nt">add_header</span> <span class="nt">X-Frame-Options</span> <span class="nt">DENY</span><span class="o">;</span> -<span class="nt">add_header</span> <span class="nt">X-Content-Type-Options</span> <span class="nt">nosniff</span><span class="o">;</span> - -<span class="nt">ssl_stapling</span> <span class="nt">on</span><span class="o">;</span> -<span class="nt">ssl_stapling_verify</span> <span class="nt">on</span><span class="o">;</span> -<span class="nt">resolver</span> <span class="nt">127</span><span class="p">.</span><span class="nc">0</span><span class="p">.</span><span class="nc">0</span><span class="p">.</span><span class="nc">1</span> <span class="nt">valid</span><span class="o">=</span><span class="nt">300s</span><span class="o">;</span> -<span class="nt">resolver_timeout</span> <span class="nt">5s</span><span class="o">;</span> -</pre></div> - - -<p><em>This configuration will work if you're using a single certificate on your server. If not, you'll have to remove the <code>ssl_certificate</code>, <code>ssl_certificate_key</code> and <code>ssl_trusted_certificate</code> directives from this file and move them to the correct <code>server{}</code> block.</em></p> -<p>We now need to generate a <code>dhparam.pem</code> file :</p> -<div class="highlight"><pre><span></span>mkdir /etc/nginx/ssl <span class="o">&amp;&amp;</span> chmod <span class="m">700</span> /etc/nginx/ssl -openssl dhparam -out /etc/nginx/ssl/dhparam.pem <span class="m">3072</span> -chmod <span class="m">600</span> /etc/nginx/ssl/dhparam.pem -</pre></div> - - -<p>Let's now generate a HTTP basic authentication file. This example creates a user named example :</p> -<div class="highlight"><pre><span></span>mkdir /etc/nginx/auth - -htpasswd -c /etc/nginx/auth/webdav example -New password: -Re-type new password: -Adding password for user user -</pre></div> - - -<p>This file has to be readable by the user running your webserver. For security reasons, we'll make it readable only by him :</p> -<div class="highlight"><pre><span></span>chown -R www-data:nogroup /etc/nginx/auth -chmod 700 /etc/nginx/auth -chmod 400 /etc/nginx/auth/webdav -</pre></div> - - -<p>Let's now modify our <code>/etc/nginx/sites-available/default</code> file with the following content :</p> -<div class="highlight"><pre><span></span>server { - listen 80 default_server; - listen [::]:80 default_server ipv6only=on; - server_name &quot;&quot;; - - return 444; -} - -server { - listen 443 default_server ssl http2; - listen [::]:443 default_server ipv6only=on ssl http2; - server_name &quot;&quot;; - - return 444; -} -</pre></div> - - -<p>We now have to create a <code>/etc/nginx/sites-available/example</code> file that will contain our actual webdav configuration. This example makes a <code>data</code> folder stored in <code>/var/www/</code> accessible.</p> -<div class="highlight"><pre><span></span><span class="nt">server</span> <span class="p">{</span> - <span class="err">listen</span> <span class="err">80</span><span class="p">;</span> - <span class="n">listen</span> <span class="cp">[</span><span class="p">::</span><span class="cp">]</span><span class="p">:</span><span class="mi">80</span><span class="p">;</span> - <span class="err">server_name</span> <span class="err">www.example.com</span><span class="p">;</span> - <span class="err">return</span> <span class="err">301</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="err">$</span><span class="n">server_name</span><span class="err">$</span><span class="n">request_uri</span><span class="p">;</span> -<span class="p">}</span> - -<span class="nt">server</span> <span class="p">{</span> - <span class="err">listen</span> <span class="err">443</span> <span class="err">ssl</span> <span class="err">http2</span><span class="p">;</span> - <span class="n">listen</span> <span class="cp">[</span><span class="p">::</span><span class="cp">]</span><span class="p">:</span><span class="mi">443</span> <span class="n">ssl</span> <span class="n">http2</span><span class="p">;</span> - <span class="err">server_name</span> <span class="err">www.example.com</span><span class="p">;</span> - - <span class="err">root</span> <span class="err">/var/www</span><span class="p">;</span> - - <span class="err">location</span> <span class="err">/</span> <span class="err">{</span> - <span class="err">index</span> <span class="err">index.html</span><span class="p">;</span> - <span class="p">}</span> - - <span class="nt">location</span> <span class="o">/</span><span class="p">.</span><span class="nc">well-known</span><span class="o">/</span><span class="nt">acme-challenge</span> <span class="p">{</span> - <span class="err">root</span> <span class="err">/var/www/letsencrypt</span><span class="p">;</span> - <span class="p">}</span> - - <span class="nt">location</span> <span class="o">/</span><span class="nt">data</span> <span class="p">{</span> - <span class="err">client_body_temp_path</span> <span class="err">/tmp</span><span class="p">;</span> - <span class="err">dav_methods</span> <span class="err">PUT</span> <span class="err">DELETE</span> <span class="err">MKCOL</span> <span class="err">COPY</span> <span class="err">MOVE</span><span class="p">;</span> - <span class="err">dav_ext_methods</span> <span class="err">PROPFIND</span> <span class="err">OPTIONS</span><span class="p">;</span> - <span class="err">create_full_put_path</span> <span class="err">on</span><span class="p">;</span> - <span class="err">dav_access</span> <span class="n">user</span><span class="p">:</span><span class="n">r</span> <span class="n">group</span><span class="o">:</span><span class="n">r</span><span class="p">;</span> - - <span class="err">auth_basic</span> <span class="err">&quot;Restricted</span> <span class="err">access&quot;</span><span class="p">;</span> - <span class="err">auth_basic_user_file</span> <span class="err">auth/webdav</span><span class="p">;</span> - - <span class="err">limit_except</span> <span class="err">GET</span> <span class="err">{</span> - <span class="err">allow</span> <span class="err">&lt;YOUR</span> <span class="err">IP</span> <span class="err">HERE&gt;</span><span class="p">;</span> - <span class="err">deny</span> <span class="err">all</span><span class="p">;</span> - <span class="p">}</span> - <span class="err">}</span> - -<span class="err">}</span> -</pre></div> - - -<p>The last thing we have to do is to create a symlink so that nginx will load our configuration :</p> -<div class="highlight"><pre><span></span>ln -s /etc/nginx/sites-available/example /etc/nginx/sites-enabled/example -</pre></div> - - -<p>Like before, let's make sure our configuration is correct and then reload the daemon :</p> -<div class="highlight"><pre><span></span>nginx -t -nginx -s reload -</pre></div> - - -<p>That's it for the WebDAV configuration server-side !</p> -<h3>nginx monitoring</h3> -<p>If you're using monit, you can easily monitor the nginx daemon by copying the following in <code>/etc/monit/conf.d/nginx</code> :</p> -<div class="highlight"><pre><span></span>check process nginx - with pidfile &quot;/run/nginx.pid&quot; - start program = &quot;/bin/systemctl start nginx&quot; - stop program = &quot;/bin/systemctl stop nginx&quot; - alert monit@example.com -</pre></div> - - -<h3>Certificates auto-renewal</h3> -<p>This goes beyond the scope of the article, but since letsencrypt certficates are only valid for 3 months, you'll need to renew them regularily. You can do so manually or you can setup a cron that does it for you.</p> -<p>I personnaly use the following script :</p> -<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 -10 -11 -12 -13 -14 -15 -16 -17</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span> - -<span class="nv">PRG</span><span class="o">=</span><span class="s2">&quot;/usr/bin/letsencrypt&quot;</span> -<span class="nv">CONFIG</span><span class="o">=</span><span class="s2">&quot;/etc/letsencrypt/cli.ini&quot;</span> -<span class="nv">MAILDEST</span><span class="o">=</span><span class="s2">&quot;admin@example.com&quot;</span> -<span class="nv">GLOBAL</span><span class="o">=</span><span class="m">0</span> - -<span class="c1"># www.example.com</span> -<span class="nv">$PRG</span> --config <span class="nv">$CONFIG</span> certonly -w /var/www/letsencrypt -d www.example.com -<span class="o">[[</span> <span class="nv">$?</span> !<span class="o">=</span> <span class="m">0</span> <span class="o">]]</span> <span class="o">&amp;&amp;</span> <span class="nv">GLOBAL</span><span class="o">=</span><span class="k">$((</span> <span class="nv">$GLOBAL</span> <span class="o">+</span> <span class="m">1</span> <span class="k">))</span> - -<span class="k">if</span> <span class="o">[[</span> <span class="nv">$GLOBAL</span> <span class="o">==</span> <span class="m">0</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> - /usr/sbin/nginx -s reload -<span class="k">else</span> - <span class="nb">echo</span> <span class="s2">&quot;Something went wrong while renewing the certificates on </span><span class="k">$(</span>hostname -f<span class="k">)</span><span class="s2"></span> -<span class="s2"> Manual action needed.&quot;</span> <span class="p">|</span> mail -s <span class="s2">&quot;Letsencrypt error on </span><span class="k">$(</span>hostname -f<span class="k">)</span><span class="s2">&quot;</span> <span class="nv">$MAILDEST</span> -<span class="k">fi</span> -</pre></div> -</td></tr></table> - -<p>You can add multiple domains in the script. As long as you add all 3 lines for each domain, it will not automatically reload nginx if one or more certificate could not be renewed and will send an e-mail to the address configured in the <code>MAILDEST</code> variable.</p> -<p>You can configure this script in the root user crontab using the <code>crontab -e</code> command :</p> -<div class="highlight"><pre><span></span>## LETSENCRYPT CERTIFICATE AUTORENEWAL -30 03 01 */2 * /root/bin/tlsrenew -</pre></div> - - -<p>This will run the script every two months, on the first day of the month, at 3:30 AM.</p> -<h2>Client configuration</h2> -<h3>Installing the required packages</h3> -<p>A single package is required to mount a webdav volume on Debian :</p> -<div class="highlight"><pre><span></span>apt update &amp;&amp; apt install davfs2 -</pre></div> - - -<h3>Mounting the share manually</h3> -<p>If like me, you want to mount your webdav share in a LXC container, you'll first need to make sure that the following line is present in its configuration file :</p> -<div class="highlight"><pre><span></span>lxc.cgroup.devices.allow = c 10:229 rwm -</pre></div> - - -<p>You'll also need to create the <code>/dev/fuse</code> node in the container :</p> -<div class="highlight"><pre><span></span>mknod /dev/fuse c 10 229 -</pre></div> - - -<p>In any case, we have to edit the <code>/etc/davfs2/secrets</code> file to add the mount point, username and password that will be used to mount the share :</p> -<div class="highlight"><pre><span></span>echo &#39;/data webdav notanactualpassword&#39; &gt;&gt; /etc/davfs2/secrets -</pre></div> - - -<p>Once that's done, we can mount our share with the following command :</p> -<div class="highlight"><pre><span></span>mount -t davfs https://www.example.com/data /data -o ro,dir_mode=750,file_mode=640,uid=root,gid=root -</pre></div> - - -<p>You might need to edit the parameters depending on which users you want to make the share available to.</p> -<h3>Mouting the share on boot</h3> -<p>A davfs volume can be mounted via the <code>/etc/fstab</code> file, but I decided to use monit instead so that the volume would be mounted again automatically should my WebDAV server reboot.</p> -<p>In order to do so, I first created a <code>davfs.txt</code> file in the <code>/var/www/data</code> folder on my WebDAV server :</p> -<div class="highlight"><pre><span></span>touch /var/www/data/davfs.txt -</pre></div> - - -<p>I then created the following <code>/root/bin/mount_davfs</code> script :</p> -<table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1 -2 -3 -4</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span> - -mknod /dev/fuse c <span class="m">10</span> <span class="m">229</span> -mount -t davfs https://www.example.com/data /data -o ro,dir_mode<span class="o">=</span><span class="m">750</span>,file_mode<span class="o">=</span><span class="m">640</span>,uid<span class="o">=</span>root,gid<span class="o">=</span>root -</pre></div> -</td></tr></table> - -<p>The last thing I did was create a <code>/etc/monit/conf.d/davfs</code> file with the following content :</p> -<div class="highlight"><pre><span></span>check file davfs with path /data/davfs.txt - alert monit@example.com - if does not exist then exec &quot;/root/bin/mount_davfs&quot; -</pre></div> - - -<p>That way, if monit notices that the <code>/data/davfs.txt</code> file becomes inaccessible for some reason, it will try remouting the share.</p> -<h2>Conclusion</h2> -<p>That's all ! Hopefully this has been useful to someone. Please do comment below if you have any question or if this has been helpful !</p>MySQL backup script2016-03-13T00:00:00+01:002016-03-13T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-03-13:/mysql-backup-script.html<p>I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but hey, I figured I'd share it here anyway.</p> -<h2>The script</h2> -<p>For the script to work, you'll need to edit a few variable to match your …</p><p>I wrote a MySQL database backup script a while back. I known they are more than enough of them already floating around the internet, but hey, I figured I'd share it here anyway.</p> -<h2>The script</h2> -<p>For the script to work, you'll need to edit a few variable to match your configuration.</p> -<ul> -<li><code>BACKUPDIR</code> is the path of the directory where you want your backups to be stored.</li> -<li><code>BACKUPUSR</code> is the user that will connect to MySQL to dump the databases. It should have access to all you databases without needing a password.</li> -<li><code>EXCLUDELIST</code> is a list of databases that should not be backed-up. Leaving it as is is probably fine.</li> -</ul> -<div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span> - -<span class="nv">BACKUPDIR</span><span class="o">=</span><span class="s2">&quot;/home/user/backup&quot;</span> -<span class="nv">BACKUPUSR</span><span class="o">=</span><span class="s2">&quot;user&quot;</span> -<span class="nv">EXCLUDELIST</span><span class="o">=</span><span class="s2">&quot;^Databases</span>$<span class="s2">|^information_schema</span>$<span class="s2">|^mysql</span>$<span class="s2">|^performance_schema</span>$<span class="s2">&quot;</span> - -sqlbk<span class="o">()</span> <span class="o">{</span> - <span class="k">for</span> each in <span class="k">$(</span>mysqlshow <span class="p">|</span> awk <span class="s1">&#39;/[[:alnum:]]/{print $2}&#39;</span><span class="k">)</span><span class="p">;</span> <span class="k">do</span> - <span class="k">if</span> <span class="o">[[</span> <span class="nv">$each</span> <span class="o">=</span>~ <span class="nv">$EXCLUDELIST</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span> - <span class="nb">true</span> - <span class="k">else</span> - mysqldump <span class="nv">$each</span> <span class="p">|</span> bzip2 &gt; <span class="si">${</span><span class="nv">BACKUPDIR</span><span class="si">}</span>/<span class="si">${</span><span class="nv">each</span><span class="si">}</span>.sql.bz2 - chown <span class="si">${</span><span class="nv">BACKUPUSR</span><span class="si">}</span>: <span class="si">${</span><span class="nv">BACKUPDIR</span><span class="si">}</span>/<span class="si">${</span><span class="nv">each</span><span class="si">}</span>.sql.bz2 <span class="o">&amp;&amp;</span> chmod <span class="m">600</span> <span class="si">${</span><span class="nv">BACKUPDIR</span><span class="si">}</span>/<span class="si">${</span><span class="nv">each</span><span class="si">}</span>.sql.bz2 - <span class="k">fi</span> - <span class="k">done</span> -<span class="o">}</span> - -<span class="o">[[</span> -e /etc/init.d/mysql <span class="o">]]</span> <span class="o">&amp;&amp;</span> sqlbk -</pre></div> - - -<p>I personnaly have this script running once a week, in my user's personnal crontab (editable using the <code>crontab -e</code> command) :</p> -<div class="highlight"><pre><span></span>## WEEKLY DATABASE BACKUP -@weekly /home/user/bin/backupdb -</pre></div> - - -<h1>Conclusion</h1> -<p>You've probably noticed that the script erases the previous backup when a new one is made.</p> -<p>I don't need to keep multiple versions of the same database backup on my servers because they are all saved remotely on a daily basis using <a href="http://rsnapshot.org/">Rsnapshot</a>. I'll probably write an article on the subject in the future.</p> -<p>As usual, feedback is always appreciated !</p>Postfix Admin2016-03-06T00:00:00+01:002016-03-06T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-03-06:/postfix-admin.html<p>As I explained in <a href="https://www.captainark.net/setting-up-a-mail-server.html">this previous tutorial</a>, I've been running my own mail server without any issue for some time now.</p> -<p>However, every time I've wanted to add a domain, create a new mailbox or change a user's password, I've had to do it manually from a SQL shell. As …</p><p>As I explained in <a href="https://www.captainark.net/setting-up-a-mail-server.html">this previous tutorial</a>, I've been running my own mail server without any issue for some time now.</p> -<p>However, every time I've wanted to add a domain, create a new mailbox or change a user's password, I've had to do it manually from a SQL shell. As fun as it may be, it does get old very fast, so I've decided to install a web frontend to manage this database.</p> -<p>After a bit a googling, I've settled on <a href="http://postfixadmin.sourceforge.net/">Postfix Admin</a>.</p> -<p>The latest stable version of Postfix Admin was released in 2009. Version 3.0 has been in the works for some time now and the project can be cloned from their <a href="https://github.com/postfixadmin/postfixadmin">Github repo</a>.</p> -<p>I've also tried <a href="http://www.vimbadmin.net/">ViMbAdmin</a>, but it felt a little heavy considering what I was going to use it for.</p> -<p>You'll need a web server with PHP support to run Postfix Admin. I personnaly run nginx with php5-fpm, but I won't explain how to configure it here. I'll simply explain how to migrate your current database to one managed with Postfix Admin with as little downtime as possible.</p> -<h1>Creating a new database</h1> -<p>Since the database managed by Postfix Admin does not use the same schema as the one we've created in my previous tutorial, we'll have to create a new one. We will give all privileges on that database to the same user as before, <code>'mail'@'localhost'</code>.</p> -<div class="highlight"><pre><span></span><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">mailnew</span><span class="p">;</span> -<span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="n">mailnew</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">&#39;mail&#39;</span><span class="o">@</span><span class="s1">&#39;localhost&#39;</span><span class="p">;</span> -<span class="n">FLUSH</span> <span class="k">PRIVILEGES</span><span class="p">;</span> -</pre></div> - - -<p>At this point, you can clone the Postfix Admin project from Github and go through the installation process.</p> -<p>While editing the config.inc.php file (or config.local.php file if you've decided to copy it), make sure that the <code>database_name</code> option is set to use the <code>mailnew</code> database we've just created.</p> -<p>Also, make sure that the <code>encrypt</code> option is set to <code>dovecot:SHA512-CRYPT</code>.</p> -<p>The installation process will create all the necessary tables in the database.</p> -<p><strong>At this point, you'll have to recreate all domains, mailboxes and aliases that you have configured in your current mail database using the Postfix Admin interface.</strong></p> -<h1>Postfix configuration</h1> -<p>Once you're done with Postfix Admin, it's time to configure Postfix to use its schema.</p> -<p>First thing first, let's backup our current configuration :</p> -<div class="highlight"><pre><span></span>mkdir /etc/postfix/mysql-backup -cp -a /etc/postfix/mysql-virtual* /etc/postfix/mysql-backup/ -</pre></div> - - -<p>Next, we have to edit the 3 files we've just backed-up. The only line that actually changes is the one beginning with <code>query</code>.</p> -<p>The first file is /etc/postfix/mysql-virtual-mailbox-domains.cf :</p> -<div class="highlight"><pre><span></span>user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT 1 FROM domain WHERE domain=&#39;%s&#39; AND active=&#39;1&#39; -</pre></div> - - -<p>The second one is /etc/postfix/mysql-virtual-mailbox-maps.cf :</p> -<div class="highlight"><pre><span></span>user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT 1 FROM mailbox WHERE username=&#39;%s&#39; AND active=&#39;1&#39; -</pre></div> - - -<p>And the last one is /etc/postfix/mysql-virtual-alias-maps.cf :</p> -<div class="highlight"><pre><span></span>user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT goto FROM alias WHERE address=&#39;%s&#39; AND active=&#39;1&#39; -</pre></div> - - -<h1>Dovecot configuration</h1> -<p>Same as with Postfix, we now need to configure Dovecot to use the Postfix Admin schema.</p> -<p>First, let's backup our current configuration :</p> -<div class="highlight"><pre><span></span>cp -a /etc/dovecot/sql.conf /etc/dovecot/sql.conf.bak -</pre></div> - - -<p>Next, we have to edit the /etc/dovecot/sql.conf file. The only line that changes is the one beginning with <code>password_query</code>.</p> -<div class="highlight"><pre><span></span>driver = mysql -connect = host=localhost dbname=mail user=mail password=mailpassword -default_pass_scheme = SHA512-CRYPT -password_query = SELECT username as user, password FROM mailbox WHERE username=&#39;%u&#39; AND active=&#39;1&#39;; -</pre></div> - - -<h1>Migrating to the new schema</h1> -<p>We're done with the configuration part. Time to migrate to the new schema.</p> -<p>First, let's create a backup of our current mail database :</p> -<div class="highlight"><pre><span></span>mysqldump mail <span class="p">|</span> bzip2 &gt; /home/user/mail.sql.bz2 -</pre></div> - - -<p>Next, in a SQL shell, we're going to drop and recreate the mail database :</p> -<div class="highlight"><pre><span></span><span class="k">DROP</span> <span class="k">DATABASE</span> <span class="n">mail</span><span class="p">;</span> -<span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">mail</span><span class="p">;</span> -</pre></div> - - -<p>We now have to dump the contents of the mailnew database into the newly created mail database :</p> -<div class="highlight"><pre><span></span>mysqldump mailnew <span class="p">|</span> mysql mail -</pre></div> - - -<p>Next, let's restart Postfix and Dovecot so that they start using the new database schema :</p> -<div class="highlight"><pre><span></span>systemctl restart postfix -systemctl restart dovecot -</pre></div> - - -<p>At this point, Postfix and Dovecot are using the Postfix Admin schema in the mail database.</p> -<p>The last thing we have to do is to edit Postfix Admin's config.inc.php file to use the mail database as well instead of the mailnew database that it should be currently using.</p> -<h1>Cleanup</h1> -<p>Once you've confirmed that everything is working properly, you can delete the backup files we've created :</p> -<div class="highlight"><pre><span></span>rm -rf /etc/postfix/mysql-backup -rm /etc/dovecot/sql.conf.bak -</pre></div> - - -<p>You can drop the mailnew database as well :</p> -<div class="highlight"><pre><span></span><span class="k">DROP</span> <span class="k">DATABASE</span> <span class="n">mailnew</span><span class="p">;</span> -</pre></div> - - -<h1>Conclusion</h1> -<p>That's all ! As always, please do leave a comment if this article has been of any use to you !</p>My tmux configuration2016-02-02T00:00:00+01:002016-02-02T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-02-02:/my-tmux-configuration.html<p><a href="https://tmux.github.io/">tmux</a> is a terminal mutiplexer. It lets you have multiples shells running in a single terminal emulator window and it keeps those shells running in the background should you need to close your terminal emulator.</p> -<p>I've played around with the configuration quite a bit to find settings that suit my …</p><p><a href="https://tmux.github.io/">tmux</a> is a terminal mutiplexer. It lets you have multiples shells running in a single terminal emulator window and it keeps those shells running in the background should you need to close your terminal emulator.</p> -<p>I've played around with the configuration quite a bit to find settings that suit my needs. Here's what it ended up looking like :</p> -<p><a href="images/tmux_fullsize.png"><img alt="tmux" src="images/tmux.png"></a></p> -<p>This screenshot was done on Mac OS X, using the Terminal app and this <a href="https://github.com/tomislav/osx-terminal.app-colors-solarized">Solarized theme</a>.</p> -<p>I figured I'd share my tmux configuration here !</p> -<h2>Installing tmux</h2> -<p>tmux is available on Debian. I suggest using the <a href="https://packages.debian.org/jessie-backports/tmux">jessie backports</a> version :</p> -<p><code>apt -t jessie-backports install tmux</code></p> -<p>tmux is also available on Mac OS X using <a href="http://brew.sh/">brew</a> :</p> -<p><code>brew install tmux</code></p> -<h2>tmux.conf</h2> -<p>I used screen before tmux, so I configured the prefix key on C-a instead of C-b. tmux has the advantage of being <em>much</em> simpler to configure than screen.</p> -<p>If you want to use this configuration, simply copy the following in ~/.tmux.conf. This file is read by default when tmux starts.</p> -<p>If you simply want to try it out, copy it in a file somewhere else and have tmux load with the -f parameter (<code>tmux -f ~/tmux-test.conf</code>).</p> -<div class="highlight"><pre><span></span># use utf8 -set -g utf8 -set-option -g status-utf8 on -set-window-option -g utf8 on - -# do not wait on esc key -set-option -g escape-time 0 - -# completely disable automatic rename -set-window-option -g automatic-rename off - -# basic settings -set -g default-terminal &quot;screen-256color&quot; -set -g aggressive-resize off -set-window-option -g xterm-keys on -#set-window-option -g mode-mouse off - -# command history -set -g history-limit 10000 - -# messages -set -g message-bg default -set -g message-fg red - -# no visual activity -set -g visual-activity off -set -g visual-bell off - -# status bar -set-option -g status-justify centre -set-option -g status-bg default -set-option -g status-fg blue -set-option -g status-interval 5 -set-option -g status-left-length 30 -set-option -g status-left &#39;#[fg=red][ #[fg=white]#H #[fg=red]]#[default]&#39; -set-option -g status-right &#39;#[fg=red][ #[fg=white]%R %d/%m #[fg=red]]#[default]&#39; - -# modes -set-option -g mode-bg default -set-option -g mode-fg blue - -# inactive window format -set-window-option -g window-status-format &#39;#I:#W#F&#39; -set-window-option -g monitor-activity on -#set-window-option -g monitor-content on # not available in tmux 2.0 - -# activity in a window -set-window-option -g window-status-activity-attr dim -set-window-option -g window-status-activity-bg default -set-window-option -g window-status-activity-fg yellow - -# content in a window # not available in tmux 2.0 -#set-window-option -g window-status-content-attr dim -#set-window-option -g window-status-content-bg default -#set-window-option -g window-status-content-fg red - -# active window format -set-window-option -g window-status-current-fg white -set-window-option -g window-status-current-bg default -set-window-option -g window-status-current-format &#39;#[fg=red](#[default]#I:#W#F#[fg=red])#[default]&#39; - -# reload tmux configuration -unbind r -bind r source-file ~/.tmux.conf \; display &quot;Configuration reloaded!&quot; - -# Screen-like keybinds -unbind C-b -set -g prefix ^A -set -g prefix2 ^Q -bind a send-prefix -bind q send-prefix - -unbind c -bind c new-window -unbind ^C -bind ^C new-window - -unbind n -bind n next-window -unbind ^N -bind ^N next-window - -unbind A -bind A command-prompt &quot;rename-window %%&quot; - -unbind p -bind p previous-window -unbind ^P -bind ^P previous-window - -unbind a -bind a last-window -unbind ^A -bind ^A last-window - -unbind [ -bind Escape copy-mode - -unbind w -bind w list-windows - -unbind k -bind k confirm-before &quot;kill-window&quot; - -unbind l -bind l refresh-client - -unbind &#39;&quot;&#39; -bind &#39;&quot;&#39; choose-window -</pre></div> - - -<h2>Aliases</h2> -<p>I also use two functions with tmux (in ~/.bash_aliases).</p> -<p>The first one creates a new "mytmux" tmux session if one doesn't exist yet, opens 10 shells and selects the first one.</p> -<div class="highlight"><pre><span></span>mytmux<span class="o">()</span> <span class="o">{</span> - tmux has-session -t mytmux - <span class="k">if</span> <span class="o">[</span> <span class="nv">$?</span> !<span class="o">=</span> <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - tmux new-session -s mytmux -n <span class="k">$(</span>hostname<span class="k">)</span> -d - tmux new-window -t mytmux:1 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux new-window -t mytmux:2 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux new-window -t mytmux:3 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux new-window -t mytmux:4 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux new-window -t mytmux:5 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux new-window -t mytmux:6 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux new-window -t mytmux:7 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux new-window -t mytmux:8 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux new-window -t mytmux:9 -n <span class="k">$(</span>hostname<span class="k">)</span> - tmux <span class="k">select</span>-window -t mytmux:0 - <span class="k">fi</span> - tmux attach -t mytmux -<span class="o">}</span> -</pre></div> - - -<p>The second one changes the tmux window name whenever I ssh to a remote host, and switches the window name back to the name of my computer when I logout from the host.</p> -<div class="highlight"><pre><span></span><span class="k">if</span> <span class="o">[</span> -n <span class="s2">&quot;</span><span class="nv">$TMUX</span><span class="s2">&quot;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - ssh<span class="o">()</span> <span class="o">{</span> - <span class="k">if</span> <span class="o">[</span> <span class="nv">$#</span> -le <span class="m">2</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - tmux rename-window <span class="s2">&quot;</span><span class="si">${</span><span class="p">@: -1</span><span class="si">}</span><span class="s2">&quot;</span> - <span class="nb">command</span> ssh <span class="s2">&quot;</span><span class="nv">$@</span><span class="s2">&quot;</span> - tmux rename-window <span class="s2">&quot;</span><span class="k">$(</span>hostname<span class="k">)</span><span class="s2">&quot;</span> - <span class="k">else</span> - <span class="nb">command</span> ssh <span class="s2">&quot;</span><span class="nv">$@</span><span class="s2">&quot;</span> - <span class="k">fi</span> - <span class="o">}</span> -<span class="k">fi</span> -</pre></div> - - -<h2>Conclusion</h2> -<p>That's all ! As always, please do leave a comment if you've found something useful in this article !</p>Debian updates with Ansible2016-01-31T00:00:00+01:002016-01-31T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-01-31:/debian-updates-with-ansible.html<p>I've recently bought a <a href="http://www8.hp.com/us/en/products/proliant-servers/product-detail.html?oid=5379860">HP Proliant Microserver Gen8</a> to play around with LXC and try new stuff.</p> -<p>From the 4 Debian machines I had to keep up-to-date, I now have 7, so it became quite time-consumming to manually SSH to each of them whenever an update became available.</p> -<p>I ended …</p><p>I've recently bought a <a href="http://www8.hp.com/us/en/products/proliant-servers/product-detail.html?oid=5379860">HP Proliant Microserver Gen8</a> to play around with LXC and try new stuff.</p> -<p>From the 4 Debian machines I had to keep up-to-date, I now have 7, so it became quite time-consumming to manually SSH to each of them whenever an update became available.</p> -<p>I ended up looking at <a href="http://www.ansible.com/">Ansible</a> to speed up the process and, within an hour, I had a working playbook that updates the debian packages, pip packages and git repos installed on all of my servers with a single command.</p> -<p>I figured I'd share the playbook I use to update the Debian packages !</p> -<h2>The playbook</h2> -<p>I modified <a href="https://gist.github.com/maethor/380676f6b1cec8cc7439">this gist</a> to only use apt-get instead of both apt-get and aptitude.</p> -<div class="highlight"><pre><span></span><span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">hosts</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">all</span> - <span class="l l-Scalar l-Scalar-Plain">tasks</span><span class="p p-Indicator">:</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">update cache</span> - <span class="l l-Scalar l-Scalar-Plain">apt</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">update_cache=yes</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">list packages to upgrade (1/2)</span> - <span class="l l-Scalar l-Scalar-Plain">shell</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">apt-get upgrade -s -V | awk &#39;/=&gt;/{print $1}&#39;</span> - <span class="l l-Scalar l-Scalar-Plain">register</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">updates</span> - <span class="l l-Scalar l-Scalar-Plain">changed_when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">False</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">list packages to upgrade (2/2)</span> - <span class="l l-Scalar l-Scalar-Plain">debug</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">msg=&quot;{{ updates.stdout_lines | count }} packages to upgrade ({{ updates.stdout_lines | join(&#39;, &#39;) }})&quot;</span> - <span class="l l-Scalar l-Scalar-Plain">when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">(updates.stdout_lines)</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">upgrade packages</span> - <span class="l l-Scalar l-Scalar-Plain">apt</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">upgrade=dist</span> - <span class="l l-Scalar l-Scalar-Plain">when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">(updates.stdout_lines)</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">check what the new version is</span> - <span class="l l-Scalar l-Scalar-Plain">shell</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">lsb_release -r | awk &#39;{print $2}&#39;</span> - <span class="l l-Scalar l-Scalar-Plain">changed_when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">False</span> - <span class="l l-Scalar l-Scalar-Plain">register</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">new_release</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">notify distribution version upgrade</span> - <span class="l l-Scalar l-Scalar-Plain">debug</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">msg=&quot;Debian has been upgraded from {{ ansible_lsb.release }} to {{ new_release.stdout }}&quot;</span> - <span class="l l-Scalar l-Scalar-Plain">when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">ansible_lsb.release != new_release.stdout</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">/wheezy/ install the debian-goodies package if it is missing</span> - <span class="l l-Scalar l-Scalar-Plain">apt</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">name=debian-goodies state=present</span> - <span class="l l-Scalar l-Scalar-Plain">when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">ansible_distribution_release == &#39;wheezy&#39;</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">/jessie/ install the needrestart package if it is missing</span> - <span class="l l-Scalar l-Scalar-Plain">apt</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">name=needrestart state=present default_release=jessie-backports</span> - <span class="l l-Scalar l-Scalar-Plain">when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">ansible_distribution_release == &#39;jessie&#39;</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">/wheezy/ list services to restart (1/3)</span> - <span class="l l-Scalar l-Scalar-Plain">shell</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">checkrestart | awk &#39;/^service/{print $2}&#39;</span> - <span class="l l-Scalar l-Scalar-Plain">register</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">wheezy_services</span> - <span class="l l-Scalar l-Scalar-Plain">changed_when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">False</span> - <span class="l l-Scalar l-Scalar-Plain">when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">ansible_distribution_release == &#39;wheezy&#39;</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">/jessie/ list services to restart (1/3)</span> - <span class="l l-Scalar l-Scalar-Plain">shell</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">needrestart -blrl | awk &#39;/^NEEDRESTART-SVC/{print $2}&#39;</span> - <span class="l l-Scalar l-Scalar-Plain">register</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">jessie_services</span> - <span class="l l-Scalar l-Scalar-Plain">changed_when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">False</span> - <span class="l l-Scalar l-Scalar-Plain">when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">ansible_distribution_release != &#39;wheezy&#39;</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">merge services list (2/3)</span> - <span class="l l-Scalar l-Scalar-Plain">set_fact</span><span class="p p-Indicator">:</span> - <span class="l l-Scalar l-Scalar-Plain">services</span><span class="p p-Indicator">:</span> <span class="s">&quot;{{</span><span class="nv"> </span><span class="s">wheezy_services</span><span class="nv"> </span><span class="s">if</span><span class="nv"> </span><span class="s">ansible_distribution_release</span><span class="nv"> </span><span class="s">==</span><span class="nv"> </span><span class="s">&#39;wheezy&#39;</span><span class="nv"> </span><span class="s">else</span><span class="nv"> </span><span class="s">jessie_services</span><span class="nv"> </span><span class="s">}}&quot;</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">list services to restart (3/3)</span> - <span class="l l-Scalar l-Scalar-Plain">debug</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">msg=&quot;{{ services.stdout_lines | count }} services to restart ({{ services.stdout_lines | join (&#39;, &#39;) }})&quot;</span> - <span class="l l-Scalar l-Scalar-Plain">when</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">(services.stdout_lines)</span> - - <span class="p p-Indicator">-</span> <span class="l l-Scalar l-Scalar-Plain">name</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">cache cleanup</span> - <span class="l l-Scalar l-Scalar-Plain">shell</span><span class="p p-Indicator">:</span> <span class="l l-Scalar l-Scalar-Plain">apt-get autoclean</span> -</pre></div> - - -<h2>Conclusion</h2> -<p>That's all ! Please leave a comment if you've found this playbook helpful !</p>Private Git Repo2016-01-31T00:00:00+01:002016-01-31T00:00:00+01:00Antoine Jouberttag:captainark.net,2016-01-31:/private-git-repo.html<p>I've decided to migrate this blog to <a href="http://blog.getpelican.com/">Pelican</a>. I've been playing around with it over the week-end, and it turns out to be way easier to manage than <a href="https://jekyllrb.com/">Jekyll</a>. Themes are much easier to install and configure, so it ends up looking better as well !</p> -<p>Since I'm basically recreating this …</p><p>I've decided to migrate this blog to <a href="http://blog.getpelican.com/">Pelican</a>. I've been playing around with it over the week-end, and it turns out to be way easier to manage than <a href="https://jekyllrb.com/">Jekyll</a>. Themes are much easier to install and configure, so it ends up looking better as well !</p> -<p>Since I'm basically recreating this blog from scratch, I've decided to delete the old git repo that was hosting it and to create a new one.</p> -<p>Setting up your own private git repo is pretty easy to achieve and is already well-documented on the <a href="https://git-scm.com/book/en/v2/Git-on-the-Server-Setting-Up-the-Server">Git</a> website.</p> -<p>Every time I want to create a new repo, I've had time to forget how to do it and I end up looking for that page, so I figured I'd write a few lines on the subject.</p> -<p>In this tutorial, I'll configure a git repo on a distant server running Debian 8 (Jessie). This repo will be remotely accessible using SSH. Two users will be able to connect to it : me and the www-data user on my webserver.</p> -<h2>SSH Keys</h2> -<p>If you don't have one already, you'll need a ssh-key to connect to the git repo.</p> -<p>On your computer, in a shell, as your usual user :</p> -<div class="highlight"><pre><span></span>ssh-keygen -t rsa -b <span class="m">3072</span> -Generating public/private rsa key pair. -Enter file in which to save the key <span class="o">(</span>/home/user/.ssh/id_rsa<span class="o">)</span>: -Enter passphrase <span class="o">(</span>empty <span class="k">for</span> no passphrase<span class="o">)</span>: -Enter same passphrase again: -Your identification has been saved in /home/user/.ssh/id_rsa. -Your public key has been saved in /home/user/id_rsa.pub. -The key fingerprint is: -<span class="o">[</span>Redacted<span class="o">]</span> -</pre></div> - - -<p>For security reasons, configuring a passphrase is recommended. On Mac OS X and most desktop environnements on Linux, you can store this passphrase for the duration of your session using the <code>ssh-add</code> command, so you won't have to type it every time you want to connect to a host.</p> -<p>On the server, we also have to create a ssh-key for the user that is running our webserver (you'll need to have sudo installed) :</p> -<div class="highlight"><pre><span></span>sudo -H -u www-data ssh-keygen -t rsa -b <span class="m">3072</span> -Generating public/private rsa key pair. -Enter file in which to save the key <span class="o">(</span>/var/www/.ssh/id_rsa<span class="o">)</span>: -Enter passphrase <span class="o">(</span>empty <span class="k">for</span> no passphrase<span class="o">)</span>: -Enter same passphrase again: -Your identification has been saved in /var/www/.ssh/id_rsa. -Your public key has been saved in /var/www/.ssh/id_rsa.pub. -The key fingerprint is: -<span class="o">[</span>Redacted<span class="o">]</span> -</pre></div> - - -<p>If you decide to configure a passphrase for that ssh-key, you'll have to type it every time you'll want to pull from your repo.</p> -<h2>Server management</h2> -<p>All of the commands in this section have to be run as root.</p> -<p>First thing first, we have to install the git package on the server that will be hosting our git repos :</p> -<div class="highlight"><pre><span></span>apt update <span class="o">&amp;&amp;</span> apt install git -y -</pre></div> - - -<p>Then, we have to create a user named git :</p> -<div class="highlight"><pre><span></span>useradd -s /usr/bin/git-shell -m -r git -</pre></div> - - -<p>This will create a system user (UID &lt; 1000) with a /home/git home directory. If you want to host your git repos somewhere else on your filesystem, you should add a <code>-d /home/directory/for/git</code> in the previous command.</p> -<p>This user will use the git-shell shell. This limits remote connection to that user to git commands (like the rssh shell can limit remote connection to a user to scp or rsync commands).</p> -<p>We have to configure our system to allow the use of this shell :</p> -<div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s1">&#39;/usr/bin/git-shell&#39;</span> &gt;&gt; /etc/shells -</pre></div> - - -<p>From this point, you should have to following output if you try to SSH to your server with that user :</p> -<div class="highlight"><pre><span></span>ssh git@git.captainark.net -fatal: Interactive git shell is not enabled. -hint: ~/git-shell-commands should exist and have <span class="nb">read</span> and execute access. -Connection to git@git.captainark.net closed. -</pre></div> - - -<p>We now need to create the .ssh/authorized_keys file for the git user with the correct permissions :</p> -<div class="highlight"><pre><span></span>sudo -H -u git mkdir /home/git/.ssh <span class="o">&amp;&amp;</span> chmod <span class="m">700</span> /home/git/.ssh -sudo -H -u git touch /home/git/.ssh/authorized_keys <span class="o">&amp;&amp;</span> chmod <span class="m">600</span> /home/git/.ssh/authorized_keys -</pre></div> - - -<p>You can now copy/paste the content of the two <code>$HOME/.ssh/id_rsa.pub</code> files we've created earlier using the <code>ssh-keygen</code> command in <code>/home/git/.ssh/authorized_keys</code>.</p> -<p>The last thing we have to do is to create our first git repo. In this example, my project will be called 'captainarkdotnet' as it will be hosting this blog :</p> -<div class="highlight"><pre><span></span>sudo -H -u git mkdir /home/git/captainarkdotnet.git -<span class="nb">cd</span> /home/git/captainarkdotnet.git -sudo -H -u git git init --bare -</pre></div> - - -<p>The last command should give you the following output :</p> -<div class="highlight"><pre><span></span>Initialized empty Git repository in /home/git/captainarkdotnet.git/.git/ -</pre></div> - - -<p>We're done with the server configuration. Let's now actually push stuff to our repo !</p> -<h3>Initial push</h3> -<p>The files for my blog are store in the ~/Documents/projects/captainarkdotnet on my computer. Before doing anything else, we first have to make sure that we currently are in that folder :</p> -<div class="highlight"><pre><span></span><span class="nb">cd</span> ~/Documents/projects/captainarkdotnet -</pre></div> - - -<p>Let's now push the content of that folder to our repo :</p> -<div class="highlight"><pre><span></span>git init -git add . -git commit -m <span class="s1">&#39;initial commit&#39;</span> -git remote add origin git@git.captainark.net:captainarkdotnet.git -git push origin master -</pre></div> - - -<p>Please note that you'll need to edit <strong>git.captainark.net</strong> to the FQDN or IP of your git server, and <strong>captainarkdotnet.git</strong> to the name of the git project on your server.</p> -<p>If everything went well, the last command should give you the following output :</p> -<div class="highlight"><pre><span></span>Counting objects: <span class="m">69</span>, <span class="k">done</span>. -Delta compression using up to <span class="m">4</span> threads. -Compressing objects: <span class="m">100</span>% <span class="o">(</span><span class="m">64</span>/64<span class="o">)</span>, <span class="k">done</span>. -Writing objects: <span class="m">100</span>% <span class="o">(</span><span class="m">69</span>/69<span class="o">)</span>, <span class="m">1</span>.01 MiB <span class="p">|</span> <span class="m">0</span> bytes/s, <span class="k">done</span>. -Total <span class="m">69</span> <span class="o">(</span>delta <span class="m">15</span><span class="o">)</span>, reused <span class="m">0</span> <span class="o">(</span>delta <span class="m">0</span><span class="o">)</span> -To git@git.captainark.net:captainarkdotnet.git - * <span class="o">[</span>new branch<span class="o">]</span> master -&gt; master -</pre></div> - - -<p>That's it, we've now pushed our first commit to our server !</p> -<h2>First pull</h2> -<p>Alright, time to pull the files we've just pushed on our webserver. I personally store my web content in <code>/var/www</code> ; if you don't, you'll have to adjust the path accordingly :</p> -<div class="highlight"><pre><span></span><span class="nb">cd</span> /var/www -sudo -H -u www-data git clone git@git.captainark.net:captainarkdotnet.git -</pre></div> - - -<p>SSH will ask you to type 'yes' since it's the first time the www-data user connects to the server. If everything goes well, you should have the following output :</p> -<div class="highlight"><pre><span></span>Cloning into <span class="s1">&#39;captainarkdotnet&#39;</span>... -remote: Counting objects: <span class="m">70</span>, <span class="k">done</span>. -remote: Compressing objects: <span class="m">100</span>% <span class="o">(</span><span class="m">65</span>/65<span class="o">)</span>, <span class="k">done</span>. -remote: Total <span class="m">70</span> <span class="o">(</span>delta <span class="m">16</span><span class="o">)</span>, reused <span class="m">0</span> <span class="o">(</span>delta <span class="m">0</span><span class="o">)</span> -Receiving objects: <span class="m">100</span>% <span class="o">(</span><span class="m">70</span>/70<span class="o">)</span>, <span class="m">1</span>.01 MiB <span class="p">|</span> <span class="m">0</span> bytes/s, <span class="k">done</span>. -Resolving deltas: <span class="m">100</span>% <span class="o">(</span><span class="m">16</span>/16<span class="o">)</span>, <span class="k">done</span>. -Checking connectivity... <span class="k">done</span>. -</pre></div> - - -<h2>Conclusion</h2> -<p>That's it ! We now have a working private git repo ! I won't go into details into the git commands in this tutorial, but here's a quick overwiew of the ones I use the most :</p> -<ul> -<li><code>git add .</code> recursively adds all files from the directory to the repo ;</li> -<li><code>git commit -a -m 'This is a comment'</code> commits the current state of your local repo with the 'This is a comment' comment ;</li> -<li><code>git push</code> pushes your commits to the distant repo ;</li> -<li><code>git pull</code> pulls the latest version of the distant repo locally ;</li> -<li><code>git branch -av</code> shows all available branches for the repo ;</li> -<li><code>git checkout -b testing remotes/origin/testing</code> create a local 'testing' branch based on the remote 'remotes/origin/testing' branch ;</li> -<li>once a branch has been copied locally, you can switch to it with the <code>git checkout {branch}</code> command.</li> -</ul> -<p>For more information on git a command, use <code>man git-{command}</code> !</p> -<p>If you've found this tutorial in any way helpful, please feel free to leave a comment !</p>Flexget init script2015-05-05T00:00:00+02:002015-05-05T00:00:00+02:00Antoine Jouberttag:captainark.net,2015-05-05:/flexget-init-script.html<p>I've been using <a href="http://flexget.com/">Flexget</a> for the past two years or so as a download automator.</p> -<p>Since I wrote an <a href="http://flexget.com/wiki/Daemon/Startup#InsservscriptDebiancompatible">init script</a> for it a while back, and it is compatible with Debian Jessie / systemd, I figured I'd share it here.</p> -<h2>The script</h2> -<p>All of the following should be done as …</p><p>I've been using <a href="http://flexget.com/">Flexget</a> for the past two years or so as a download automator.</p> -<p>Since I wrote an <a href="http://flexget.com/wiki/Daemon/Startup#InsservscriptDebiancompatible">init script</a> for it a while back, and it is compatible with Debian Jessie / systemd, I figured I'd share it here.</p> -<h2>The script</h2> -<p>All of the following should be done as the root user.</p> -<p>First, create a /etc/default/flexget file with the following content :</p> -<div class="highlight"><pre><span></span><span class="c1"># Configuration file for /etc/init.d/flexget</span> - -<span class="c1"># User to run flexget as.</span> -<span class="c1"># Daemon will not start if left empty.</span> -<span class="nv">FGUSER</span><span class="o">=</span><span class="s2">&quot;&quot;</span> - -<span class="c1"># Full path to the flexget config.yml file to use.</span> -<span class="c1"># Defaults to FGUSER $HOME/.flexget/config.yml</span> -<span class="nv">CONFIG</span><span class="o">=</span><span class="s2">&quot;&quot;</span> - -<span class="c1"># Path to the directory where flexget should log. Do not add trailing slash.</span> -<span class="c1"># Defaults to the FGUSER $HOME/.flexget directory</span> -<span class="nv">LOG</span><span class="o">=</span><span class="s2">&quot;&quot;</span> - -<span class="c1"># Log verbosity </span> -<span class="c1"># Available options : none critical error warning info verbose debug trace</span> -<span class="c1"># Defaults to info</span> -<span class="nv">LEVEL</span><span class="o">=</span><span class="s2">&quot;&quot;</span> -</pre></div> - - -<p>Please note that the FGUSER variable needs to be defined for the daemon to start. It can be set to your current user, or you can run flexget as its own user.</p> -<p>You can create a flexget user with the following command :</p> -<div class="highlight"><pre><span></span>useradd -m -d /var/lib/flexget -r -s /bin/false flexget -</pre></div> - - -<p>Then, create the /etc/init.d/flexget file :</p> -<div class="highlight"><pre><span></span><span class="ch">#!/bin/bash</span> - -<span class="c1">### BEGIN INIT INFO</span> -<span class="c1"># Provides: flexget</span> -<span class="c1"># Required-Start: $network $remote_fs</span> -<span class="c1"># Required-Stop: $network $remote_fs</span> -<span class="c1"># Should-Start: </span> -<span class="c1"># Should-Stop: </span> -<span class="c1"># Default-Start: 2 3 4 5</span> -<span class="c1"># Default-Stop: 0 1 6</span> -<span class="c1"># Short-Description: Flexget</span> -<span class="c1"># Description: FlexGet is a multipurpose automation tool </span> -<span class="c1"># for content like torrents, nzbs, podcasts,</span> -<span class="c1"># comics, series, movies, etc.</span> -<span class="c1">### END INIT INFO</span> - -<span class="c1"># Author: Antoine Joubert, 19/01/2014</span> - -<span class="nv">NAME</span><span class="o">=</span><span class="s2">&quot;flexget&quot;</span> -<span class="nv">DAEMON</span><span class="o">=</span><span class="s2">&quot;/usr/local/bin/flexget&quot;</span> -<span class="nv">SETTINGS</span><span class="o">=</span><span class="s2">&quot;/etc/default/</span><span class="nv">$NAME</span><span class="s2">&quot;</span> - -<span class="nv">DESC</span><span class="o">=</span><span class="s2">&quot;Flexget&quot;</span> -<span class="nv">PIDFILE</span><span class="o">=</span><span class="s2">&quot;/var/run/</span><span class="nv">$NAME</span><span class="s2">.pid&quot;</span> - -<span class="nb">set</span> -e - -. /lib/lsb/init-functions - -<span class="nb">unset</span> FGUSER CONFIG LOG LEVEL - -<span class="c1"># Exit if flexget not installed</span> -<span class="k">if</span> <span class="o">[</span> ! -x <span class="s2">&quot;</span><span class="nv">$DAEMON</span><span class="s2">&quot;</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - log_action_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: Could not find flexget executable. Exiting.&quot;</span> - <span class="nb">exit</span> <span class="m">2</span> -<span class="k">fi</span> - -<span class="c1"># Read configuration variables</span> -<span class="k">if</span> <span class="o">[</span> -r /etc/default/<span class="nv">$NAME</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - . /etc/default/<span class="nv">$NAME</span> -<span class="k">else</span> - log_action_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: /etc/default/</span><span class="nv">$NAME</span><span class="s2"> not found. Exiting.&quot;</span> - <span class="nb">exit</span> <span class="m">2</span> -<span class="k">fi</span> - -<span class="c1"># Exit if FGUSER has not been set in /etc/default/flexget</span> -<span class="k">if</span> <span class="o">[</span> -z <span class="nv">$FGUSER</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - log_action_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: FGUSER not set in /etc/default/</span><span class="nv">$NAME</span><span class="s2">. Exiting.&quot;</span> - <span class="nb">exit</span> <span class="m">2</span> -<span class="k">fi</span> - -<span class="c1"># Function to verify if flexget is already running</span> -run_check<span class="o">()</span> <span class="o">{</span> - <span class="k">if</span> <span class="o">[</span> -e <span class="nv">$PIDFILE</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - status_of_proc -p <span class="nv">$PIDFILE</span> <span class="nv">$DAEMON</span> <span class="nv">$NAME</span> &gt; /dev/null <span class="o">&amp;&amp;</span> <span class="nv">RETVAL</span><span class="o">=</span><span class="m">0</span> <span class="o">||</span> <span class="nv">RETVAL</span><span class="o">=</span><span class="s2">&quot;</span><span class="nv">$?</span><span class="s2">&quot;</span> - <span class="k">else</span> - <span class="nv">RETVAL</span><span class="o">=</span><span class="s2">&quot;2&quot;</span> - <span class="k">fi</span> -<span class="o">}</span> - -end_log<span class="o">()</span> <span class="o">{</span> - <span class="k">if</span> <span class="o">[</span> <span class="nv">$RETVAL</span> -eq <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - log_end_msg <span class="m">0</span> - <span class="k">return</span> <span class="m">0</span> - <span class="k">else</span> - log_end_msg <span class="m">1</span> - <span class="nb">exit</span> <span class="m">1</span> - <span class="k">fi</span> -<span class="o">}</span> - -<span class="c1"># Function to define config file, log file and log level</span> -conf_check<span class="o">()</span> <span class="o">{</span> - <span class="k">if</span> <span class="o">[</span> -z <span class="nv">$CONFIG</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - <span class="nv">OPTIONS</span><span class="o">=</span><span class="s2">&quot;</span><span class="nv">$OPTIONS</span><span class="s2">&quot;</span> - <span class="k">else</span> - <span class="nv">OPTIONS</span><span class="o">=</span><span class="s2">&quot;-c </span><span class="nv">$CONFIG</span><span class="s2">&quot;</span> - <span class="k">fi</span> - - <span class="k">if</span> <span class="o">[</span> -z <span class="nv">$LOG</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - <span class="nv">OPTIONS</span><span class="o">=</span><span class="s2">&quot;</span><span class="nv">$OPTIONS</span><span class="s2">&quot;</span> - <span class="k">else</span> - <span class="nv">OPTIONS</span><span class="o">=</span><span class="s2">&quot;</span><span class="nv">$OPTIONS</span><span class="s2"> -l </span><span class="nv">$LOG</span><span class="s2">/flexget.log&quot;</span> - <span class="k">if</span> <span class="o">[</span> ! -d <span class="nv">$LOG</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - mkdir -p -m <span class="m">750</span> <span class="nv">$LOG</span> - chown <span class="nv">$FGUSER</span> <span class="nv">$LOG</span> - <span class="k">fi</span> - <span class="k">fi</span> - - <span class="k">if</span> <span class="o">[</span> -z <span class="nv">$LEVEL</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - <span class="nv">OPTIONS</span><span class="o">=</span><span class="s2">&quot;</span><span class="nv">$OPTIONS</span><span class="s2">&quot;</span> - <span class="k">else</span> - <span class="nv">OPTIONS</span><span class="o">=</span><span class="s2">&quot;</span><span class="nv">$OPTIONS</span><span class="s2"> -L </span><span class="nv">$LEVEL</span><span class="s2">&quot;</span> - <span class="k">fi</span> -<span class="o">}</span> - -start_flexget<span class="o">()</span> <span class="o">{</span> - run_check - <span class="k">if</span> <span class="o">[</span> <span class="nv">$RETVAL</span> <span class="o">=</span> <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - log_action_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: Already running with PID </span><span class="k">$(</span>cat <span class="nv">$PIDFILE</span><span class="k">)</span><span class="s2">. Aborting.&quot;</span> - <span class="nb">exit</span> <span class="m">2</span> - <span class="k">else</span> - conf_check - log_daemon_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: Starting the daemon.&quot;</span> - start-stop-daemon --start --background --quiet --pidfile <span class="nv">$PIDFILE</span> --make-pidfile <span class="se">\</span> - --chuid <span class="nv">$FGUSER</span> --user <span class="nv">$FGUSER</span> --exec <span class="nv">$DAEMON</span> -- <span class="nv">$OPTIONS</span> daemon start - <span class="nv">RETVAL</span><span class="o">=</span><span class="nv">$?</span> - end_log - <span class="k">fi</span> -<span class="o">}</span> - -stop_flexget<span class="o">()</span> <span class="o">{</span> - run_check - <span class="k">if</span> <span class="o">[</span> <span class="nv">$RETVAL</span> <span class="o">=</span> <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - log_daemon_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: Stopping the daemon.&quot;</span> - start-stop-daemon --stop --quiet --chuid <span class="s2">&quot;</span><span class="nv">$FGUSER</span><span class="s2">&quot;</span> --pidfile <span class="s2">&quot;</span><span class="nv">$PIDFILE</span><span class="s2">&quot;</span> --retry <span class="m">30</span> - <span class="nv">RETVAL</span><span class="o">=</span><span class="nv">$?</span> - <span class="o">[</span> -e <span class="s2">&quot;</span><span class="nv">$PIDFILE</span><span class="s2">&quot;</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> rm -f <span class="s2">&quot;</span><span class="nv">$PIDFILE</span><span class="s2">&quot;</span> - end_log - <span class="k">else</span> - log_action_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: Not currently running. Aborting.&quot;</span> - <span class="nb">exit</span> <span class="m">2</span> - <span class="k">fi</span> -<span class="o">}</span> - -status_flexget<span class="o">()</span> <span class="o">{</span> - run_check - <span class="k">if</span> <span class="o">[</span> <span class="nv">$RETVAL</span> <span class="o">=</span> <span class="m">0</span> <span class="o">]</span><span class="p">;</span> <span class="k">then</span> - log_action_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: Currently running with PID </span><span class="k">$(</span>cat <span class="nv">$PIDFILE</span><span class="k">)</span><span class="s2">.&quot;</span> - <span class="k">else</span> - log_action_msg <span class="s2">&quot;</span><span class="nv">$DESC</span><span class="s2">: Not currently running.&quot;</span> - <span class="k">fi</span> - <span class="nb">exit</span> <span class="nv">$RETVAL</span> -<span class="o">}</span> - -<span class="k">case</span> <span class="s2">&quot;</span><span class="nv">$1</span><span class="s2">&quot;</span> in - start<span class="o">)</span> - start_flexget - <span class="p">;;</span> - stop<span class="o">)</span> - stop_flexget - <span class="p">;;</span> - restart<span class="o">)</span> - stop_flexget <span class="o">&amp;&amp;</span> sleep <span class="m">2</span> <span class="o">&amp;&amp;</span> start_flexget - <span class="p">;;</span> - status<span class="o">)</span> - status_flexget - <span class="p">;;</span> - *<span class="o">)</span> - <span class="nb">echo</span> <span class="s2">&quot;Usage: </span><span class="nv">$0</span><span class="s2"> {start|stop|restart|status}&quot;</span> - <span class="p">;;</span> -<span class="k">esac</span> - -<span class="nb">exit</span> <span class="m">0</span> -</pre></div> - - -<p>Then, give execution rights to the script :</p> -<div class="highlight"><pre><span></span>chmod +x /etc/init.d/flexget -</pre></div> - - -<p>And then, generate the necessary symlinks for the service to start on boot :</p> -<p><em>Debian Jessie</em></p> -<div class="highlight"><pre><span></span>systemctl <span class="nb">enable</span> flexget -</pre></div> - - -<p><em>Debian Wheezy</em></p> -<div class="highlight"><pre><span></span>insserv flexget -</pre></div> - - -<p>To start, stop or check if the daemon is running :</p> -<p><em>Debian Jessie</em></p> -<div class="highlight"><pre><span></span>systemctl start flexget -systemctl stop flexget -systemctl status flexget -</pre></div> - - -<p><em>Debian Wheezy / Jessie</em></p> -<div class="highlight"><pre><span></span>service flexget start -service flexget stop -service flexget status -</pre></div> - - -<p><em>Debian Wheezy</em></p> -<div class="highlight"><pre><span></span>/etc/init.d/flexget start -/etc/init.d/flexget stop -/etc/init.d/flexget status -</pre></div> - - -<h2>Conclusion</h2> -<p>That's all ! If you are using this script, please let me know in the comment section below !</p>Setting up a mail server2015-04-24T00:00:00+02:002015-04-24T00:00:00+02:00Antoine Jouberttag:captainark.net,2015-04-24:/setting-up-a-mail-server.html<p>In this first tutorial, I'll explain how I've configured my mail server using the following :</p> -<ul> -<li>A server running Linux Debian (jessie) ;</li> -<li>Postfix ;</li> -<li>Postfix-policyd-spf-python ;</li> -<li>Dovecot ;</li> -<li>Spamassassin ;</li> -<li>OpenDKIM ;</li> -<li>OpenDMARC ;</li> -<li>Monit ;</li> -<li>Rainloop.</li> -</ul> -<p>I'm assuming you have some basic knowledge of Linux and DNS configuration.</p> -<p>You can host this server at home, but you …</p><p>In this first tutorial, I'll explain how I've configured my mail server using the following :</p> -<ul> -<li>A server running Linux Debian (jessie) ;</li> -<li>Postfix ;</li> -<li>Postfix-policyd-spf-python ;</li> -<li>Dovecot ;</li> -<li>Spamassassin ;</li> -<li>OpenDKIM ;</li> -<li>OpenDMARC ;</li> -<li>Monit ;</li> -<li>Rainloop.</li> -</ul> -<p>I'm assuming you have some basic knowledge of Linux and DNS configuration.</p> -<p>You can host this server at home, but you might have issues with your ISP not allowing outbound traffic on TCP port 25, and your emails might be considered to be spam by other providers if your IP is dynamic and/or you can't configure a reverse DNS record on it.</p> -<p>The cheapest VMs from <a href="https://www.digitalocean.com/?refcode=1cd69e4c3389">DigitalOcean</a> or <a href="http://www.vultr.com/?ref=6804947">Vultr</a> are powerful enough to have this configuration running smoothly.</p> -<p>We'll also need a SSL certificate for this configuration. You can create an auto-signed one or get a free valid one from <a href="http://www.startssl.com/">StartSSL</a>. For the purpose of this tutorial, I'll consider you've chosen the latter.</p> -<p>You'll also need a domain name. I've chosen <a href="http://www.namecheap.com/?aff=85990">Namecheap</a> as a registrar. I won't go into details on how to configure it, but you'll need at the very least a A record on your server's IP as well as a MX record pointing to it.</p> -<p>I use the captainark.net domain as an example throughout this tutorial. You'll have to use your actual domain for your configuration to work !</p> -<p><em>Note: links in this section are sponsored.</em></p> -<h2>Initial configuration</h2> -<h3>Installing the required packages</h3> -<p>First thing first, we need to install the packages we'll need for this configuration :</p> -<div class="highlight"><pre><span></span>apt update - -apt install mysql-server mysql-client postfix postfix-mysql <span class="se">\</span> -postfix-policyd-spf-python dovecot-core dovecot-imapd dovecot-lmtpd <span class="se">\</span> -dovecot-mysql dovecot-sieve dovecot-managesieved dovecot-antispam <span class="se">\</span> -opendkim opendkim-tools monit opendmarc spamassassin spamc -</pre></div> - - -<p>During its installation, Postfix will prompt you with configuration questions. Choose "Internet Site", and when asked about your System mail name, provide it with your server's FQDN (it should be the output of the <code>hostname -f</code> command on your server).</p> -<p>You'll also have to set-up a password for the MySQL root user.</p> -<h3>Additional configuration</h3> -<p>The PTR records on your server's IPv4 and/or IPv6 should match your server's FQDN (a <code>dig -x</code> on your server's IP should match a <code>hostname -f</code> on your server).</p> -<p>You'll have to open the following TCP ports on your server for this configuration to work : 25, 465, 587 and 993.</p> -<p>If you don't want to have to remember the root user MySQL password, you can create a .my.cnf file in your current user home directory containing the following lines :</p> -<div class="highlight"><pre><span></span><span class="o">[</span>client<span class="o">]</span> -<span class="nv">host</span> <span class="o">=</span> localhost -<span class="nv">user</span> <span class="o">=</span> root -<span class="nv">password</span> <span class="o">=</span> myverysecurepassword -<span class="nv">socket</span> <span class="o">=</span> /var/run/mysqld/mysqld.sock -</pre></div> - - -<p>Once it has been created, change the permissions on the file to make sure no other user can read it :</p> -<div class="highlight"><pre><span></span>chmod <span class="m">600</span> ~/.my.cnf -</pre></div> - - -<p>I also like to change the default MySQL shell to see what database I'm using at any given time. Since I use bash, I achieve this the following way :</p> -<div class="highlight"><pre><span></span><span class="nb">echo</span> <span class="s1">&#39;export MYSQL_PS1=&quot;[\u@\h] (\d)&gt; &quot;&#39;</span> &gt; ~/.bash_aliases -</pre></div> - - -<p>You'll have to logout from the current shell for the modification to be taken into account (if you're using SSH, log out and back into your server).</p> -<p>You should now be able to log into MySQL without specifying a password, and it should look like this :</p> -<div class="highlight"><pre><span></span>:~$ mysql mysql -<span class="o">[</span>...<span class="o">]</span> -<span class="o">[</span>root@localhost<span class="o">]</span> <span class="o">(</span>mysql<span class="o">)</span>&gt; -</pre></div> - - -<h2>Configuring the MySQL database</h2> -<h3>Initial configuration</h3> -<p>We now need to configure the MySQL database Postfix and Dovecot will be using. In this tutorial, we'll be calling it "mail", but you can name it whatever you want.</p> -<p>First, in a mysql shell, let's create the MySQL database :</p> -<div class="highlight"><pre><span></span><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">mail</span><span class="p">;</span> -</pre></div> - - -<p>Now, we are going to create the user that Postfix and Dovecot will be using to access the database. We will only be granting this user select permission :</p> -<div class="highlight"><pre><span></span><span class="k">GRANT</span> <span class="k">SELECT</span> <span class="k">ON</span> <span class="n">mail</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">&#39;mail&#39;</span><span class="o">@</span><span class="s1">&#39;localhost&#39;</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">&#39;mailpassword&#39;</span><span class="p">;</span> -<span class="n">FLUSH</span> <span class="k">PRIVILEGES</span><span class="p">;</span> -</pre></div> - - -<p>We are now going to create the necessary tables for our needs. Let's first use the mail database :</p> -<div class="highlight"><pre><span></span><span class="n">USE</span> <span class="n">mail</span><span class="p">;</span> -</pre></div> - - -<p>The first table we are going to create will contain the domains we will be using with our mail server :</p> -<div class="highlight"><pre><span></span><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="o">`</span><span class="n">virtual_domains</span><span class="o">`</span> <span class="p">(</span> -<span class="o">`</span><span class="n">id</span><span class="o">`</span> <span class="nb">INT</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="n">AUTO_INCREMENT</span><span class="p">,</span> -<span class="o">`</span><span class="n">name</span><span class="o">`</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">50</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> -<span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="o">`</span><span class="n">id</span><span class="o">`</span><span class="p">)</span> -<span class="p">)</span> <span class="n">ENGINE</span><span class="o">=</span><span class="n">InnoDB</span> <span class="k">DEFAULT</span> <span class="n">CHARSET</span><span class="o">=</span><span class="n">utf8</span><span class="p">;</span> -</pre></div> - - -<p>Then, we are going to create the table that will contain our users and their password :</p> -<div class="highlight"><pre><span></span><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="o">`</span><span class="n">virtual_users</span><span class="o">`</span> <span class="p">(</span> -<span class="o">`</span><span class="n">id</span><span class="o">`</span> <span class="nb">INT</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="n">AUTO_INCREMENT</span><span class="p">,</span> -<span class="o">`</span><span class="n">domain_id</span><span class="o">`</span> <span class="nb">INT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> -<span class="o">`</span><span class="n">password</span><span class="o">`</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">106</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> -<span class="o">`</span><span class="n">email</span><span class="o">`</span> <span class="nb">VARCHAR</span><span class="p">(</span><span class="mi">120</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> -<span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="o">`</span><span class="n">id</span><span class="o">`</span><span class="p">),</span> -<span class="k">UNIQUE</span> <span class="k">KEY</span> <span class="o">`</span><span class="n">email</span><span class="o">`</span> <span class="p">(</span><span class="o">`</span><span class="n">email</span><span class="o">`</span><span class="p">),</span> -<span class="k">FOREIGN</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">domain_id</span><span class="p">)</span> <span class="k">REFERENCES</span> <span class="n">virtual_domains</span><span class="p">(</span><span class="n">id</span><span class="p">)</span> <span class="k">ON</span> <span class="k">DELETE</span> <span class="k">CASCADE</span> -<span class="p">)</span> <span class="n">ENGINE</span><span class="o">=</span><span class="n">InnoDB</span> <span class="k">DEFAULT</span> <span class="n">CHARSET</span><span class="o">=</span><span class="n">utf8</span><span class="p">;</span> -</pre></div> - - -<p>Finally, the last table we are going to create will contain our mail aliases :</p> -<div class="highlight"><pre><span></span><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="o">`</span><span class="n">virtual_aliases</span><span class="o">`</span> <span class="p">(</span> -<span class="o">`</span><span class="n">id</span><span class="o">`</span> <span class="nb">INT</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="n">AUTO_INCREMENT</span><span class="p">,</span> -<span class="o">`</span><span class="n">domain_id</span><span class="o">`</span> <span class="nb">INT</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> -<span class="o">`</span><span class="k">source</span><span class="o">`</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> -<span class="o">`</span><span class="n">destination</span><span class="o">`</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> -<span class="k">PRIMARY</span> <span class="k">KEY</span> <span class="p">(</span><span class="o">`</span><span class="n">id</span><span class="o">`</span><span class="p">),</span> -<span class="k">FOREIGN</span> <span class="k">KEY</span> <span class="p">(</span><span class="n">domain_id</span><span class="p">)</span> <span class="k">REFERENCES</span> <span class="n">virtual_domains</span><span class="p">(</span><span class="n">id</span><span class="p">)</span> <span class="k">ON</span> <span class="k">DELETE</span> <span class="k">CASCADE</span> -<span class="p">)</span> <span class="n">ENGINE</span><span class="o">=</span><span class="n">InnoDB</span> <span class="k">DEFAULT</span> <span class="n">CHARSET</span><span class="o">=</span><span class="n">utf8</span><span class="p">;</span> -</pre></div> - - -<h3>Domains, users and aliases management</h3> -<p>We are now going to add data to the tables we have created.</p> -<p>First, let's add a domain to the virtual_domains table :</p> -<div class="highlight"><pre><span></span><span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">virtual_domains</span> <span class="p">(</span><span class="o">`</span><span class="n">name</span><span class="o">`</span><span class="p">)</span> <span class="k">VALUES</span> <span class="p">(</span><span class="s1">&#39;captainark.net&#39;</span><span class="p">);</span> -</pre></div> - - -<p>We can now create users associated with this domain in the virtual_users table :</p> -<div class="highlight"><pre><span></span><span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">virtual_users</span> <span class="p">(</span><span class="o">`</span><span class="n">domain_id</span><span class="o">`</span><span class="p">,</span> <span class="o">`</span><span class="n">password</span><span class="o">`</span> <span class="p">,</span> <span class="o">`</span><span class="n">email</span><span class="o">`</span><span class="p">)</span> <span class="k">VALUES</span> -<span class="p">(</span><span class="s1">&#39;1&#39;</span><span class="p">,</span> <span class="n">ENCRYPT</span><span class="p">(</span><span class="s1">&#39;notanactualpassword&#39;</span><span class="p">,</span> <span class="n">CONCAT</span><span class="p">(</span><span class="s1">&#39;$6$&#39;</span><span class="p">,</span> <span class="k">SUBSTRING</span><span class="p">(</span><span class="n">SHA</span><span class="p">(</span><span class="n">RAND</span><span class="p">()),</span> <span class="o">-</span><span class="mi">16</span><span class="p">))),</span> -<span class="s1">&#39;example@captainark.net&#39;</span><span class="p">);</span> -</pre></div> - - -<p>This is not mandatory, but we can also create our first mail alias :</p> -<div class="highlight"><pre><span></span><span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">virtual_aliases</span> <span class="p">(</span><span class="o">`</span><span class="n">domain_id</span><span class="o">`</span><span class="p">,</span> <span class="o">`</span><span class="k">source</span><span class="o">`</span><span class="p">,</span> <span class="o">`</span><span class="n">destination</span><span class="o">`</span><span class="p">)</span> <span class="k">VALUES</span> -<span class="p">(</span><span class="s1">&#39;1&#39;</span><span class="p">,</span> <span class="s1">&#39;alias@captainark.net&#39;</span><span class="p">,</span> <span class="s1">&#39;example@captainark.net&#39;</span><span class="p">);</span> -</pre></div> - - -<p>Now, all messages sent to alias@captainark.net will be forwarded to example@captainark.net.</p> -<p>Use the same syntax to create additional domains, users and aliases. If you have more than one domains configured, be sure to associate your users and aliases with the correct domain_id.</p> -<h2>Configuring Postfix</h2> -<p>Next, we are going to configure <a href="http://www.postfix.org/">Postfix</a>.</p> -<h3>Configuration backup</h3> -<p>First, let's backup the original configuration files :</p> -<div class="highlight"><pre><span></span>cp /etc/postfix/main.cf /etc/postfix/main.cf.orig -cp /etc/postfix/master.cf /etc/postfix/master.cf.orig -</pre></div> - - -<h3>User and group creation</h3> -<p>We are now going to create a user and group called vmail that will be used by both Postfix and Dovecot :</p> -<div class="highlight"><pre><span></span>groupadd -g <span class="m">5000</span> vmail -useradd -g vmail -u <span class="m">5000</span> vmail -d /var/mail -m -s /bin/false -</pre></div> - - -<h3>SSL certificates</h3> -<p>Next, we are going to create the folder where we will store the SSL certificates :</p> -<div class="highlight"><pre><span></span>mkdir /etc/postfix/ssl -chown root: /etc/postfix/ssl <span class="o">&amp;&amp;</span> chmod <span class="m">600</span> /etc/postfix/ssl -</pre></div> - - -<p>Purists will probably want to store their certificates in /etc/ssl/private. If you choose to do so, you'll have to adapt the path of those files for the remainder of this tutorial.</p> -<p>If you've decided to create a certificate with StartSSL, you'll end up with two files, a .crt and a .key. I'll name those files server.crt and server-with-passphrase.key. Put both these files in the folder we've just created.</p> -<p>Now, let's remove the passphrase from the key :</p> -<div class="highlight"><pre><span></span><span class="nb">cd</span> /etc/postfix/ssl -openssl rsa -in server-with-passphrase.key -out server.key -</pre></div> - - -<p>You'll be prompted for the passphrase you chose during the certificate generation.</p> -<p>Next, we have to download the appropriate intermediate certificate :</p> -<div class="highlight"><pre><span></span>wget -O /etc/postfix/ssl/sub.class1.server.ca.pem <span class="se">\</span> -http://www.startssl.com/certs/sub.class1.server.ca.pem -</pre></div> - - -<p>We now have to make sure that the permissions on those files are correct :</p> -<div class="highlight"><pre><span></span>chown root: /etc/postfix/ssl/* <span class="o">&amp;&amp;</span> chmod <span class="m">600</span> /etc/postfix/ssl/* -</pre></div> - - -<p>The last thing we have to do here is to generate Diffie-Hellman keys for Perfect Forward Secrecy (PFS) :</p> -<div class="highlight"><pre><span></span>openssl gendh -out /etc/postfix/dh_512.pem -2 <span class="m">512</span> -openssl gendh -out /etc/postfix/dh_1024.pem -2 <span class="m">1024</span> -</pre></div> - - -<h3>Postifx configuration</h3> -<p>First, let's edit the /etc/postfix/main.cf file. It should end up looking something like that :</p> -<div class="highlight"><pre><span></span>smtpd_banner = <span class="nv">$myhostname</span> ESMTP <span class="nv">$mail_name</span> (Debian/GNU) -biff = no - -broken_sasl_auth_clients = yes -config_directory = /etc/postfix -disable_vrfy_command = yes -smtpd_data_restrictions = reject_unauth_pipelining, permit -smtpd_helo_required = yes - -queue_directory = /var/spool/postfix -append_dot_mydomain = no -readme_directory = no - -smtpd_use_tls=yes -smtpd_tls_auth_only = yes -smtpd_tls_cert_file=/etc/postfix/ssl/server.crt -smtpd_tls_key_file=/etc/postfix/ssl/server.key -smtpd_tls_CAfile=/etc/postfix/ssl/sub.class1.server.ca.pem -smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3 -smtpd_tls_protocols=!SSLv2,!SSLv3 -smtpd_tls_mandatory_ciphers=high -smtpd_tls_dh1024_param_file = /etc/postfix/dh_1024.pem -smtpd_tls_dh512_param_file = /etc/postfix/dh_512.pem -smtpd_tls_eecdh_grade = strong -smtpd_tls_loglevel = 1 -smtpd_tls_received_header = yes -smtpd_tls_session_cache_database = btree:<span class="cp">${</span><span class="n">data_directory</span><span class="cp">}</span>/smtpd_scache - -tls_preempt_cipherlist = yes -tls_random_source = dev:/dev/urandom - -smtpd_data_restrictions = reject_unauth_pipelining, permit -smtpd_helo_required = yes - -smtp_tls_CAfile = <span class="nv">$smtpd_tls_CAfile</span> -smtp_tls_mandatory_protocols=!SSLv2,!SSLv3 -smtp_tls_protocols=!SSLv2,!SSLv3 -smtp_tls_security_level = may -smtp_tls_loglevel = 1 -smtp_tls_session_cache_database = btree:<span class="cp">${</span><span class="n">data_directory</span><span class="cp">}</span>/smtp_scache - -smtpd_milters = -non_smtpd_milters = <span class="nv">$smtpd_milters</span> -milter_protocol = 2 -milter_default_action = accept - -smtpd_recipient_restrictions = - reject_invalid_hostname, - reject_non_fqdn_hostname, - reject_non_fqdn_sender, - reject_non_fqdn_recipient, - reject_unknown_sender_domain, - reject_unknown_recipient_domain, - permit_mynetworks, - permit_sasl_authenticated, - reject_unauth_destination, - permit - -smtpd_sasl_auth_enable = yes -smtpd_sasl_local_domain = <span class="nv">$myhostname</span> -smtpd_sasl_security_options = noanonymous -smtpd_sasl_tls_security_options = <span class="nv">$smtpd_sasl_security_options</span> -smtpd_tls_auth_only = yes -smtpd_sasl_type = dovecot -smtpd_sasl_path = private/auth - -myhostname = myserver.captainark.net ### CHANGE THIS -alias_maps = hash:/etc/aliases -alias_database = hash:/etc/aliases -myorigin = /etc/mailname -mydestination = localhost, myserver.captainark.net ### CHANGE THIS -relayhost = -mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 -mailbox_size_limit = 0 -recipient_delimiter = + -default_transport = smtp -relay_transport = smtp -inet_interfaces = all -inet_protocols = all - -virtual_transport = lmtp:unix:private/dovecot-lmtp -virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf -virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf -virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf -</pre></div> - - -<p>The variable "myhostname" has to be defined to you server's FQDN. The file /etc/mailname should contain your server's FQDN as well.</p> -<p>Next, we need to edit the /etc/postfix/master.cf file. You need to uncomment the following lines :</p> -<div class="highlight"><pre><span></span>submission inet n - - - - smtpd - -o syslog_name=postfix/submission - -o smtpd_tls_security_level=encrypt - -o tls_preempt_cipherlist=yes - -o smtpd_sasl_auth_enable=yes - -o smtpd_client_restrictions=permit_sasl_authenticated,reject - -smtps inet n - - - - smtpd - -o syslog_name=postfix/smtps - -o smtpd_tls_wrappermode=yes - -o smtpd_sasl_auth_enable=yes - -o smtpd_client_restrictions=permit_sasl_authenticated,reject -</pre></div> - - -<p>You also have to add the following lines at the end of the file :</p> -<div class="highlight"><pre><span></span>dovecot unix - n n - - pipe - flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f <span class="cp">${</span><span class="n">sender</span><span class="cp">}</span> -d <span class="cp">${</span><span class="n">recipient</span><span class="cp">}</span> -</pre></div> - - -<h3>MySQL access for Postfix</h3> -<p>We now need to allow Postfix to connect to the MySQL database we have created earlier. To that end, we must create three files.</p> -<p>/etc/postfix/mysql-virtual-mailbox-domains.cf should contain the following lines :</p> -<div class="highlight"><pre><span></span>user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT 1 FROM virtual_domains WHERE name=&#39;%s&#39; -</pre></div> - - -<p>/etc/postfix/mysql-virtual-mailbox-maps.cf should contain the following lines :</p> -<div class="highlight"><pre><span></span>user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT 1 FROM virtual_users WHERE email=&#39;%s&#39; -</pre></div> - - -<p>/etc/postfix/mysql-virtual-alias-maps.cf should contain the following lines :</p> -<div class="highlight"><pre><span></span>user = mail -password = mailpassword -hosts = 127.0.0.1 -dbname = mail -query = SELECT destination FROM virtual_aliases WHERE source=&#39;%s&#39; -</pre></div> - - -<p>Since these files contain a password, let's make sure they are not world-readable :</p> -<div class="highlight"><pre><span></span>chown root: /etc/postfix/mysql* <span class="o">&amp;&amp;</span> chmod <span class="m">600</span> /etc/postfix/mysql* -</pre></div> - - -<p>You can use the command postmap to confirm that everything is working properly :</p> -<div class="highlight"><pre><span></span>postmap -q captainark.net mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf - -postmap -q example@captainark.net mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf - -postmap -q alias@captainark.net mysql:/etc/postfix/mysql-virtual-alias-maps.cf -</pre></div> - - -<p>Let's restart postfix for our modifications to be taken into account :</p> -<div class="highlight"><pre><span></span>systemctl restart postfix -</pre></div> - - -<p>That's it for Postfix, for now ; Dovecot is next !</p> -<h2>Configuring Dovecot</h2> -<h3>Dovecot global configuration</h3> -<p>By default, on Debian, <a href="http://www.dovecot.org/">Dovecot</a> uses multiple configuration files in /etc/dovecot/conf.d. I found it annoying to maintain, and I ended up only using the /etc/doveconf.conf file.</p> -<p>As always, let's start by backing up the original configuration file :</p> -<div class="highlight"><pre><span></span>mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.orig -</pre></div> - - -<p>Next, we are going to create a new /etc/dovecot/dovecot.conf file. It should contain the following lines :</p> -<div class="highlight"><pre><span></span><span class="sx">!include_try /usr/share/dovecot/protocols.d/*.protocol</span> -<span class="n">protocols</span> <span class="p">=</span> <span class="n">imap</span> <span class="n">lmtp</span> <span class="n">sieve</span> - -<span class="n">mail_location</span> <span class="p">=</span> <span class="n">maildir</span><span class="p">:</span><span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">mail</span><span class="o">/</span><span class="c">%d/%n</span> -<span class="n">mail_privileged_group</span> <span class="p">=</span> <span class="n">vmail</span> -<span class="n">mail_plugin_dir</span> <span class="p">=</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">dovecot</span><span class="o">/</span><span class="n">modules</span> -<span class="n">mail_plugins</span> <span class="p">=</span> - -<span class="n">disable_plaintext_auth</span> <span class="p">=</span> <span class="n">yes</span> -<span class="n">auth_mechanisms</span> <span class="p">=</span> <span class="n">plain</span> <span class="n">login</span> - -<span class="n">service</span> <span class="n">director</span> <span class="p">{</span> - <span class="n">unix_listener</span> <span class="n">login</span><span class="o">/</span><span class="n">director</span> <span class="p">{</span> - <span class="p">}</span> - <span class="n">fifo_listener</span> <span class="n">login</span><span class="o">/</span><span class="n">proxy</span><span class="o">-</span><span class="n">notify</span> <span class="p">{</span> - <span class="p">}</span> - <span class="n">unix_listener</span> <span class="n">director</span><span class="o">-</span><span class="n">userdb</span> <span class="p">{</span> - <span class="p">}</span> - <span class="n">inet_listener</span> <span class="p">{</span> - <span class="p">}</span> -<span class="p">}</span> - -<span class="n">namespace</span> <span class="n">inbox</span> <span class="p">{</span> - <span class="n">inbox</span> <span class="p">=</span> <span class="n">yes</span> - <span class="n">type</span> <span class="p">=</span> <span class="n">private</span> - <span class="n">mailbox</span> <span class="n">Drafts</span> <span class="p">{</span> - <span class="n">auto</span> <span class="p">=</span> <span class="n">subscribe</span> - <span class="n">special_use</span> <span class="p">=</span> <span class="o">\</span><span class="n">Drafts</span> - <span class="p">}</span> - <span class="n">mailbox</span> <span class="n">Junk</span> <span class="p">{</span> - <span class="n">auto</span> <span class="p">=</span> <span class="n">subscribe</span> - <span class="n">special_use</span> <span class="p">=</span> <span class="o">\</span><span class="n">Junk</span> - <span class="p">}</span> - <span class="n">mailbox</span> <span class="n">Sent</span> <span class="p">{</span> - <span class="n">auto</span> <span class="p">=</span> <span class="n">subscribe</span> - <span class="n">special_use</span> <span class="p">=</span> <span class="o">\</span><span class="n">Sent</span> - <span class="p">}</span> - <span class="n">mailbox</span> <span class="n">Trash</span> <span class="p">{</span> - <span class="n">auto</span> <span class="p">=</span> <span class="n">subscribe</span> - <span class="n">special_use</span> <span class="p">=</span> <span class="o">\</span><span class="n">Trash</span> - <span class="p">}</span> -<span class="p">}</span> - -<span class="n">service</span> <span class="n">imap</span><span class="o">-</span><span class="n">login</span> <span class="p">{</span> - <span class="n">inet_listener</span> <span class="n">imap</span> <span class="p">{</span> - <span class="n">port</span> <span class="p">=</span> <span class="mi">0</span> - <span class="p">}</span> - <span class="n">inet_listener</span> <span class="n">imaps</span> <span class="p">{</span> - <span class="n">port</span> <span class="p">=</span> <span class="mi">993</span> - <span class="n">ssl</span> <span class="p">=</span> <span class="n">yes</span> - <span class="p">}</span> -<span class="p">}</span> - -<span class="n">service</span> <span class="n">pop3</span><span class="o">-</span><span class="n">login</span> <span class="p">{</span> - <span class="n">inet_listener</span> <span class="n">pop3</span> <span class="p">{</span> - <span class="n">port</span> <span class="p">=</span> <span class="mi">0</span> - <span class="p">}</span> - <span class="n">inet_listener</span> <span class="n">pop3s</span> <span class="p">{</span> - <span class="n">port</span> <span class="p">=</span> <span class="mi">0</span> - <span class="p">}</span> -<span class="p">}</span> - -<span class="n">service</span> <span class="n">lmtp</span> <span class="p">{</span> - <span class="n">unix_listener</span> <span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">spool</span><span class="o">/</span><span class="n">postfix</span><span class="o">/</span><span class="n">private</span><span class="o">/</span><span class="n">dovecot</span><span class="o">-</span><span class="n">lmtp</span> <span class="p">{</span> - <span class="n">mode</span> <span class="p">=</span> <span class="mi">0600</span> - <span class="n">user</span> <span class="p">=</span> <span class="n">postfix</span> - <span class="n">group</span> <span class="p">=</span> <span class="n">postfix</span> - <span class="p">}</span> -<span class="p">}</span> - -<span class="n">service</span> <span class="n">imap</span> <span class="p">{</span> -<span class="p">}</span> - -<span class="n">service</span> <span class="n">pop3</span> <span class="p">{</span> -<span class="p">}</span> - -<span class="n">service</span> <span class="n">auth</span> <span class="p">{</span> - <span class="n">unix_listener</span> <span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">spool</span><span class="o">/</span><span class="n">postfix</span><span class="o">/</span><span class="n">private</span><span class="o">/</span><span class="n">auth</span> <span class="p">{</span> - <span class="n">mode</span> <span class="p">=</span> <span class="mi">0666</span> - <span class="n">user</span> <span class="p">=</span> <span class="n">postfix</span> - <span class="n">group</span> <span class="p">=</span> <span class="n">postfix</span> - <span class="p">}</span> - <span class="n">unix_listener</span> <span class="n">auth</span><span class="o">-</span><span class="n">userdb</span> <span class="p">{</span> - <span class="n">mode</span> <span class="p">=</span> <span class="mi">0600</span> - <span class="n">user</span> <span class="p">=</span> <span class="n">vmail</span> - <span class="p">}</span> - <span class="n">user</span> <span class="p">=</span> <span class="n">dovecot</span> -<span class="p">}</span> - -<span class="n">service</span> <span class="n">auth</span><span class="o">-</span><span class="n">worker</span> <span class="p">{</span> - <span class="n">user</span> <span class="p">=</span> <span class="n">vmail</span> -<span class="p">}</span> - -<span class="n">service</span> <span class="n">dict</span> <span class="p">{</span> - <span class="n">unix_listener</span> <span class="n">dict</span> <span class="p">{</span> - <span class="p">}</span> -<span class="p">}</span> - -<span class="n">ssl</span> <span class="p">=</span> <span class="n">required</span> -<span class="n">ssl_cert</span> <span class="p">=</span> <span class="o">&lt;/</span><span class="n">etc</span><span class="o">/</span><span class="n">postfix</span><span class="o">/</span><span class="n">ssl</span><span class="o">/</span><span class="n">server</span><span class="p">.</span><span class="n">crt</span> -<span class="n">ssl_key</span> <span class="p">=</span> <span class="o">&lt;/</span><span class="n">etc</span><span class="o">/</span><span class="n">postfix</span><span class="o">/</span><span class="n">ssl</span><span class="o">/</span><span class="n">server</span><span class="p">.</span><span class="n">key</span> -<span class="n">ssl_ca</span> <span class="p">=</span> <span class="o">&lt;/</span><span class="n">etc</span><span class="o">/</span><span class="n">postfix</span><span class="o">/</span><span class="n">ssl</span><span class="o">/</span><span class="n">sub</span><span class="p">.</span><span class="n">class1</span><span class="p">.</span><span class="n">server</span><span class="p">.</span><span class="n">ca</span><span class="p">.</span><span class="n">pem</span> -<span class="n">ssl_protocols</span> <span class="p">=</span> !<span class="n">SSLv2</span> !<span class="n">SSLv3</span> -<span class="n">ssl_cipher_list</span> <span class="p">=</span> <span class="n">AES128</span><span class="o">+</span><span class="n">EECDH</span><span class="p">:</span><span class="n">AES128</span><span class="o">+</span><span class="n">EDH</span><span class="p">:</span>!<span class="n">aNULL</span><span class="p">;</span> -<span class="n">protocol</span> <span class="n">lda</span> <span class="p">{</span> - <span class="n">mail_plugins</span> <span class="p">=</span> $<span class="n">mail_plugins</span> <span class="n">sieve</span> -<span class="p">}</span> - -<span class="n">protocol</span> <span class="n">imap</span> <span class="p">{</span> - <span class="n">mail_plugins</span> <span class="p">=</span> $<span class="n">mail_plugins</span> -<span class="p">}</span> -<span class="n">protocol</span> <span class="n">lmtp</span> <span class="p">{</span> - <span class="n">mail_plugins</span> <span class="p">=</span> $<span class="n">mail_plugins</span> <span class="n">sieve</span> -<span class="p">}</span> - -<span class="n">plugin</span> <span class="p">{</span> - <span class="n">sieve</span> <span class="p">=</span> <span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">mail</span><span class="o">/</span><span class="n">sieve</span><span class="o">/</span><span class="n">users</span><span class="o">/</span><span class="c">%u.sieve</span> - <span class="n">sieve_after</span> <span class="p">=</span> <span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">mail</span><span class="o">/</span><span class="n">sieve</span><span class="o">/</span><span class="n">after</span> - <span class="n">sieve_before</span> <span class="p">=</span> <span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">mail</span><span class="o">/</span><span class="n">sieve</span><span class="o">/</span><span class="n">before</span> - <span class="n">sieve_global_dir</span> <span class="p">=</span> <span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">dovecot</span><span class="o">/</span><span class="n">sieve</span><span class="o">/</span> - <span class="n">sieve_dir</span> <span class="p">=</span> <span class="o">~/</span><span class="n">sieve</span> -<span class="p">}</span> - -<span class="n">passdb</span> <span class="p">{</span> - <span class="n">driver</span> <span class="p">=</span> <span class="n">sql</span> - <span class="n">args</span> <span class="p">=</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">dovecot</span><span class="o">/</span><span class="n">sql</span><span class="p">.</span><span class="n">conf</span> -<span class="p">}</span> -<span class="n">userdb</span> <span class="p">{</span> - <span class="n">driver</span> <span class="p">=</span> <span class="n">static</span> - <span class="n">args</span> <span class="p">=</span> <span class="n">uid</span><span class="p">=</span><span class="n">vmail</span> <span class="n">gid</span><span class="p">=</span><span class="n">vmail</span> <span class="n">home</span><span class="p">=</span><span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">mail</span><span class="o">/</span><span class="c">%d/%n</span> -<span class="p">}</span> -</pre></div> - - -<p>Dovecot will use the same SSL certificate as Postfix.</p> -<p>Using this configuration, your virtual users' emails will be stored in /var/mail/$domain/$user/ and will be owned by the vmail user.</p> -<p>For this to work, we have to create the domain folder :</p> -<div class="highlight"><pre><span></span>mkdir -p /var/mail/captainark.net -chown vmail: /var/mail/captainark.net <span class="o">&amp;&amp;</span> chmod <span class="m">770</span> /var/mail/captainark.net -</pre></div> - - -<p>Dovecot will create the virtual users' folders automatically.</p> -<h3>Dovecot access to the MySQL database</h3> -<p>We now need to allow Dovecot to connect to the mail database we have populated earlier. To do so, we are going to create a /etc/dovecot/sql.conf file with the following content :</p> -<div class="highlight"><pre><span></span>driver = mysql -connect = host=localhost dbname=mail user=mail password=mailpassword -default_pass_scheme = SHA512-CRYPT -password_query = SELECT email as user, password FROM virtual_users WHERE email=&#39;%u&#39;; -</pre></div> - - -<p>You'll have to change the password to the one you have defined earlier. Since this file contains a password, let's make sure it's not world-readable :</p> -<div class="highlight"><pre><span></span>chown root: /etc/dovecot/sql.conf <span class="o">&amp;&amp;</span> chmod <span class="m">600</span> /etc/dovecot/sql.conf -</pre></div> - - -<h3>Configuring Sieve</h3> -<p>The last thing we need to configure here is sieve. The idea is to have all messages flagged as spam automatically moved to the mailbox Junk folder.</p> -<p>To do so, let's first create the required folders :</p> -<div class="highlight"><pre><span></span>mkdir -p /var/mail/sieve/before -mkdir /var/mail/sieve/after -mkdir /var/mail/sieve/users -chown -R vmail: /var/mail/sieve <span class="o">&amp;&amp;</span> chmod -R <span class="m">770</span> /var/mail/sieve -</pre></div> - - -<p>If you want to have sieve rules for a specific user, simply create $user@$domain.sieve file in the users folder (example@captainark.net in my case).</p> -<p>All .sieve files in the before folder will be used for all your virtual users, before their individual configuration ; the .sieve files in the after folder will be used, well, you guessed it, after.</p> -<p>Let's create a filter.sieve file in the /var/mail/sieve/before folder with the following content :</p> -<div class="highlight"><pre><span></span>require [&quot;envelope&quot;, &quot;fileinto&quot;, &quot;imap4flags&quot;, &quot;regex&quot;]; - -if not header :regex &quot;message-id&quot; &quot;.*@.*\.&quot; { - fileinto &quot;Junk&quot;; -} - -if header :contains &quot;X-Spam-Level&quot; &quot;*****&quot; { - fileinto &quot;Junk&quot;; -} -</pre></div> - - -<p>Last thing we have to do is to change the permissions on the newly created file :</p> -<div class="highlight"><pre><span></span>chown vmail: /var/mail/sieve/before/filter.sieve <span class="o">&amp;&amp;</span> <span class="se">\</span> -chmod <span class="m">660</span> /var/mail/sieve/before/filter.sieve -</pre></div> - - -<p>That's all ; now, all email we receive that is flagged as spam by SpamAssassin will be moved to the Junk folder.</p> -<p>Let's restart dovecot :</p> -<div class="highlight"><pre><span></span>systemctl restart dovecot -</pre></div> - - -<p>We now have a working mail server !</p> -<p>To connect to it and access your mailbox, configure your email client as follow :</p> -<ul> -<li>Username: example@captainark.net ;</li> -<li>Password: the password you chose for your virtual user ;</li> -<li>IMAP: your server's FQDN, port 993 (SSL/TLS with normal password) ;</li> -<li>SMTP: your server's FQDN, port 465 (SSL/TLS with normal password).</li> -</ul> -<h2>Configuring SpamAssassin</h2> -<h3>The alternatives</h3> -<p>Next thing we have to do is to configure the actual anti-spam. I tried a few, but I ended up sticking with <a href="http://spamassassin.apache.org/">SpamAssassin</a>. Here's why :</p> -<ul> -<li><a href="http://dspam.nuclearelephant.com/">DSPAM</a> is <a href="http://sourceforge.net/p/dspam/mailman/message/32585111/">no longer maintained</a> and <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=754810">has been removed from Debian Jessie</a> ;</li> -<li><a href="https://rspamd.com/">Rspamd</a> is interesting, has been <a href="https://packages.debian.org/source/jessie/rspamd">integrated in Debian Jessie</a>, but is poorly documented at this time ;</li> -<li><a href="http://bogofilter.sourceforge.net/">Bogofilter</a> does not seem to have the greatest server integration.</li> -</ul> -<h3>The actual configuration</h3> -<p>SpamAssassin's configuration is pretty straightforward. First, let's edit the /etc/default/spamassassin file :</p> -<div class="highlight"><pre><span></span>ENABLED=1 -[...] -CRON=1 -</pre></div> - - -<p>Before the cron runs for the first time, we have to manually update SpamAssassin's ruleset :</p> -<div class="highlight"><pre><span></span>sa-learn -</pre></div> - - -<p>Next, as usual, let's back up the original configuration file :</p> -<div class="highlight"><pre><span></span>mv /etc/spamassassin/local.cf /etc/spamassassin/local.cf.orig -</pre></div> - - -<p>Let's create a new /etc/spamassassin/local.cf file with the following content :</p> -<div class="highlight"><pre><span></span>rewrite_header Subject [SPAM] -report_safe 0 -required_score 5.0 -use_bayes 1 -bayes_auto_learn 1 - -whitelist_from *@captainark.net -</pre></div> - - -<p>Next, to have Postfix send incoming emails through SpamAssassin, we have to edit the /etc/postfix/master.cf file. At the very beginning, we have to add a line under the smtp definition :</p> -<div class="highlight"><pre><span></span>smtp inet n - - - - smtpd - -o content_filter=spamassassin -</pre></div> - - -<p>At the very end of the same file, we have to add the following lines :</p> -<div class="highlight"><pre><span></span>spamassassin unix - n n - - pipe - user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f <span class="cp">${</span><span class="n">sender</span><span class="cp">}</span> <span class="cp">${</span><span class="n">recipient</span><span class="cp">}</span> -</pre></div> - - -<p>Let's restart SpamAssassin and Postfix :</p> -<div class="highlight"><pre><span></span>systemctl restart postfix -systemctl restart spamassassin -</pre></div> - - -<p>That's all for SpamAssassin ! To check if it is working, send yourself an email from another provider. You should see the following headers in it :</p> -<div class="highlight"><pre><span></span>X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on - myserver.captainark.net -X-Spam-Level: -</pre></div> - - -<h2>Configuring SPF</h2> -<h3>Allowing your server to send emails for your domain</h3> -<p><a href="http://www.openspf.org/">SPF</a> (Sender Policy Framework) is a mechanism that confirms that your server's IP is allowed to send emails for your domain. Technically, it is a TXT DNS record which looks something like this :</p> -<div class="highlight"><pre><span></span>captainark.net IN TXT &quot;v=spf1 mx ~all&quot; -</pre></div> - - -<p>This DNS record lets other mail servers know that hosts that have a MX record for my domain are also allowed to send emails for it.</p> -<p>For more information on SPF syntax, you can consult the <a href="http://www.openspf.org/SPF_Record_Syntax">official documentation</a>.</p> -<p>Without a properly configured SPF record, other mail servers might flag your emails as spam or outright drop them.</p> -<h3>Checking SPF record for inbound mail</h3> -<p>Now that we have set up our own SPF record, let's configure Postfix to check that other mail servers communicating with us have done the same.</p> -<p>First, let's add the two following lines at the end of /etc/postfix-policyd-spf-python/policyd-spf.conf :</p> -<div class="highlight"><pre><span></span>Header_Type = AR -Authserv_Id = &quot;&lt;server&#39;s FQDN&gt;&quot; -</pre></div> - - -<p>Then, let's edit the /etc/postfix/master.cf file and add the following lines at the end :</p> -<div class="highlight"><pre><span></span>policy-spf unix - n n - - spawn - user=nobody argv=/usr/bin/policyd-spf -</pre></div> - - -<p>Let's now edit the /etc/postfix/main.cf. In the "smtpd_recipient_restrictions" section, add the "check_policy_service" line as seen below :</p> -<div class="highlight"><pre><span></span>smtpd_recipient_restrictions = -[...] - reject_unauth_destination, - check_policy_service unix:private/policy-spf, - permit -</pre></div> - - -<p>We now have to restart postfix :</p> -<div class="highlight"><pre><span></span>systemctl restart postfix -</pre></div> - - -<p>Our server is now checking other mail server's SPF records.</p> -<p>To make sure that it is working, send yourself an email from another provider. You should see the following header in it :</p> -<div class="highlight"><pre><span></span><span class="nt">Authentication-Results</span><span class="o">:</span> <span class="nt">myserver</span><span class="p">.</span><span class="nc">captainark</span><span class="p">.</span><span class="nc">net</span><span class="o">;</span> <span class="nt">spf</span><span class="o">=</span><span class="nt">pass</span> <span class="o">(</span><span class="nt">sender</span> <span class="nt">SPF</span> <span class="nt">authorized</span><span class="o">)</span> -<span class="cp">[</span><span class="nx">...</span><span class="cp">]</span> <span class="nt">receiver</span><span class="o">=</span><span class="nt">example</span><span class="p">@</span><span class="k">captainark</span><span class="p">.</span><span class="nc">net</span><span class="o">)</span> -</pre></div> - - -<h2>Configuring OpenDKIM</h2> -<p><a href="http://www.dkim.org/">DKIM</a> (DomainKeys Identified Mail) is a mechanism that validates a domain name identity for an email through cryptographic authentication.</p> -<p>While not mandatory, setting up DKIM improves the odds of emails sent from your server not being flagged as spam by other providers.</p> -<p>With this configuration, OpenDKIM will also check the key for inbound emails.</p> -<h3>Software side</h3> -<p>First, let's backup the original configuration file and create a folder for the configuration files :</p> -<div class="highlight"><pre><span></span>mv /etc/opendkim.conf /etc/opendkim.conf.orig -mkdir /etc/opendkim.d -</pre></div> - - -<p>We now have to create a /etc/opendkim.conf file with the following content :</p> -<div class="highlight"><pre><span></span>AutoRestart Yes -AutoRestartRate 10/1h -UMask 002 -Syslog yes -SyslogSuccess Yes -LogWhy Yes - -OversignHeaders From -AlwaysAddARHeader yes - -Canonicalization relaxed/simple - -ExternalIgnoreList refile:/etc/opendkim.d/TrustedHosts -InternalHosts refile:/etc/opendkim.d/dkim/TrustedHosts -KeyTable refile:/etc/opendkim.d/dkim/KeyTable -SigningTable refile:/etc/opendkim.d/dkim/SigningTable - -Mode sv -PidFile /run/opendkim/opendkim.pid -SignatureAlgorithm rsa-sha256 - -UserID opendkim:opendkim - -Socket local:/var/spool/postfix/opendkim/opendkim.sock -</pre></div> - - -<p>Let's then create the necessary folders :</p> -<div class="highlight"><pre><span></span>mkdir -p /etc/opendkim.d/keys/captainark.net/ -</pre></div> - - -<p>Now, we are going to create the /etc/opendkim.d/TrustedHosts file with the following content :</p> -<div class="highlight"><pre><span></span>localhost -127.0.0.1 -::1 -captainark.net -</pre></div> - - -<p>This file contains the hosts and domains for which OpenDKIM should sign emails.</p> -<p>Next, let's create the /etc/opendkim.d/KeyTable :</p> -<div class="highlight"><pre><span></span>mail._domainkey.captainark.net captainark.net:mail:/etc/opendkim.d/keys/captainark.net/mail.private -</pre></div> - - -<p>This file tells OpenDKIM which key it should use for each selector.</p> -<p>Finally, let's create the /etc/opendkim.d/SigningTable file :</p> -<div class="highlight"><pre><span></span>*@captainark.net mail._domainkey.captainark.net -</pre></div> - - -<p>This file tells OpenDKIM which selector it should use for each domain.</p> -<p>We now have to generate the private/public key pair for our domain :</p> -<div class="highlight"><pre><span></span><span class="nb">cd</span> /etc/opendkim.d/keys/captainark.net/ -opendkim-genkey -s mail -d captainark.net -</pre></div> - - -<p>This creates two files ; mail.private contains our private key, mail.txt contains our public key.</p> -<p>Let's change the permissions on those files :</p> -<div class="highlight"><pre><span></span>chown -R opendkim: /etc/opendkim.d/keys -chmod -R <span class="m">700</span> /etc/opendkim.d/keys -chmod <span class="m">600</span> /etc/opendkim.d/captainark.net/* -</pre></div> - - -<h3>Postfix integration</h3> -<p>The last thing we have to do is to configure Postfix to communicate with OpenDKIM.</p> -<p>First, let's create the necessary folders :</p> -<div class="highlight"><pre><span></span>mkdir /var/spool/postfix/opendkim -chown opendkim: /var/spool/postfix/opendkim -</pre></div> - - -<p>We also have to add the postfix user to the opendkim group :</p> -<div class="highlight"><pre><span></span>useradd -G opendkim postfix -</pre></div> - - -<p>Now, let's edit the /etc/postfix/master.cf file, like so :</p> -<div class="highlight"><pre><span></span>smtpd_milters = unix:/opendkim/opendkim.sock -</pre></div> - - -<p>We now have to restart OpenDKIM and Postfix :</p> -<div class="highlight"><pre><span></span>systemctl restart opendkim -systemctl restart postfix -</pre></div> - - -<h3>DNS side</h3> -<p>For DKIM to work, you have to configure a DNS TXT record in your zone. This record was automatically generated by OpenDKIM in the mail.txt file mentioned earlier :</p> -<div class="highlight"><pre><span></span>mail._domainkey IN TXT &quot;v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkJq0CW3tl2XHZ1CN5XdbqRDU7KfXOJ70nlwI09bHmDU63/Yz3J5rl863S0t2ncVHfIudZANj0OaiJe5HRR7WCsjuNIhQFfPFGIWLNClpxqdQVQURI38sAGeyn7Ed/Cor1AiWABzFWzel0kvXILw8K/NTzxaAPeSa9ttwQEgSmowIDAQAB&quot; ; ----- DKIM key mail for captainark.net -</pre></div> - - -<p>All you have to do is to copy and paste this record in your DNS zone file.</p> -<p>To make sure that OpenDKIM is working, you can send an empty email to <a href="mailto:check-auth@verifier.port25.com">check-auth@verifier.port25.com</a>. You should receive a response with the following content :</p> -<div class="highlight"><pre><span></span>========================================================== -Summary of Results -========================================================== -SPF check: pass -DomainKeys check: neutral -DKIM check: pass -Sender-ID check: pass -SpamAssassin check: ham -</pre></div> - - -<h2>Configuring OpenDMARC</h2> -<p><a href="http://dmarc.org/">DMARC</a> (Domain-based Message Authentication, Reporting &amp; Conformance) standardizes SPF and DKIM authentication mechanisms.</p> -<p>It lets the owner of a domain name indicate that his email is protected by SPF and/or DKIM and what other providers should do with emails that do not pass those checks.</p> -<h3>Software side</h3> -<p>Once again, let's backup the original configuration file :</p> -<div class="highlight"><pre><span></span>mv /etc/opendmarc.conf /etc/opendmarc.conf.orig -</pre></div> - - -<p>We now have to create a /etc/opendmarc.conf file with the following content :</p> -<div class="highlight"><pre><span></span>AutoRestart Yes -AutoRestartRate 10/1h -UMask 0002 -Syslog true - -AuthservID &quot;&lt;your server&#39;s FQDN&gt;&quot; -TrustedAuthservIDs &quot;&lt;your server&#39;s FQDN&gt;&quot; -IgnoreHosts /etc/opendkim.d/TrustedHosts - -RejectFailures false - -UserID opendmarc:opendmarc -PidFile /run/opendmarc.pid -Socket local:/var/spool/postfix/opendmarc/opendmarc.sock -</pre></div> - - -<h3>Postfix integration</h3> -<p>The last thing we have to do is to configure Postfix to communicate with OpenDMARC.</p> -<p>First, let's create the necessary folders :</p> -<div class="highlight"><pre><span></span>mkdir /var/spool/postfix/opendmarc -chown opendmarc: /var/spool/postfix/opendmarc -</pre></div> - - -<p>We also have to add the postfix user to the opendmarc group :</p> -<div class="highlight"><pre><span></span>useradd -G opendmarc postfix -</pre></div> - - -<p>Now, let's edit the /etc/postfix/master.cf file, like so :</p> -<div class="highlight"><pre><span></span>smtpd_milters = unix:/opendkim/opendkim.sock, unix:/opendmarc/opendmarc.sock -</pre></div> - - -<p>We now have to restart OpenDMARC and Postfix :</p> -<div class="highlight"><pre><span></span>systemctl restart opendmarc -systemctl restart postfix -</pre></div> - - -<p>You should now see the following headers in your incoming emails :</p> -<div class="highlight"><pre><span></span><span class="nt">Authentication-Results</span><span class="o">:</span> <span class="nt">myserver</span><span class="p">.</span><span class="nc">captainark</span><span class="p">.</span><span class="nc">net</span><span class="o">;</span> <span class="nt">dmarc</span><span class="o">=</span><span class="nt">pass</span> <span class="nt">header</span><span class="p">.</span><span class="nc">from</span><span class="o">=</span><span class="nt">gmail</span><span class="p">.</span><span class="nc">com</span> -</pre></div> - - -<h3>DNS side</h3> -<p>DMARC, like SPF and DKIM, is based on DNS TXT records.</p> -<p>Here is how I configured it for the captainark.net domain :</p> -<div class="highlight"><pre><span></span><span class="nt">_dmarc</span> <span class="nt">IN</span> <span class="nt">TXT</span> <span class="s2">&quot;v=DMARC1; p=none; rua=mailto:postmaster@captainark.net; ruf=mailto:postmaster@captainark.net&quot;</span> -</pre></div> - - -<p>This tells other providers to not reject or quarantine emails should a SPF or DKIM check fail, but to send a daily report of those checks to postmaster@captainark.net.</p> -<p>For more information on the DMARC syntax, here is an <a href="https://support.google.com/a/answer/2466563?hl=en">article from Google</a>.</p> -<h2>Configuring Monit</h2> -<p><a href="http://mmonit.com/monit/">Monit</a> is a daemon that makes sure that other daemons are running. If they crash, it restarts them automatically. Is is not directly related to a mail server per say, but it's pretty easy to set up.</p> -<p>First, as always, let's backup the original configuration file :</p> -<div class="highlight"><pre><span></span>mv /etc/monit/monitrc /etc/monit/monitrc.orig -</pre></div> - - -<p>We now have to create a new /etc/monit/monitrc file with the following content :</p> -<div class="highlight"><pre><span></span>set daemon 30 -set logfile syslog facility log_daemon - -set httpd port 2812 and -use address localhost -allow localhost - -set mailserver localhost -with timeout 30 seconds -using hostname myserver.captainark.net - -set mail-format { from: monit@captainark.net } - -include /etc/monit/conf.d/* -</pre></div> - - -<p>Then, we are going to create a /etc/monit/conf.d/mail file with the following content :</p> -<div class="highlight"><pre><span></span>check process postfix - with pidfile &quot;/var/spool/postfix/pid/master.pid&quot; - start program = &quot;/bin/systemctl start postfix&quot; - stop program = &quot;/bin/systemctl stop postfix&quot; - alert monit@captainark.net - group mail - -check process dovecot - with pidfile &quot;/run/dovecot/master.pid&quot; - start program = &quot;/bin/systemctl start dovecot&quot; - stop program = &quot;/bin/systemctl stop dovecot&quot; - alert monit@captainark.net - group mail - depends on postfix - -check process spamassassin - with pidfile &quot;/run/spamassassin.pid&quot; - start program = &quot;/bin/systemctl start spamassassin&quot; - stop program = &quot;/bin/systemctl stop spamassassin&quot; - alert monit@captainark.net - group mail - depends on postfix, dovecot - -check process opendkim - with pidfile &quot;/run/opendkim/opendkim.pid&quot; - start program = &quot;/bin/systemctl start opendkim&quot; - stop program = &quot;/bin/systemctl stop opendkim&quot; - alert monit@captainark.net - group mail - depends on postfix, dovecot - -check process opendmarc - with pidfile &quot;/run/opendmarc/opendmarc.pid&quot; - start program = &quot;/bin/systemctl start opendmarc&quot; - stop program = &quot;/bin/systemctl stop opendmarc&quot; - alert monit@captainark.net - group mail - depends on postfix, dovecot -</pre></div> - - -<p>Let's make sure that permissions on the file are correct :</p> -<div class="highlight"><pre><span></span>chown root: /etc/monit/conf.d/mail <span class="o">&amp;&amp;</span> chmod <span class="m">600</span> /etc/monit/conf.d/mail -</pre></div> - - -<p>Then, we have to reload the monit daemon :</p> -<div class="highlight"><pre><span></span>monit reload -</pre></div> - - -<p>Now, the <code>monit summary</code> command should have the following output :</p> -<div class="highlight"><pre><span></span>The Monit daemon 5.4 uptime: 3d 0h 41m - -Process &#39;postfix&#39; Running -Process &#39;dovecot&#39; Running -Process &#39;spamassassin&#39; Running -Process &#39;opendkim&#39; Running -Process &#39;opendmarc&#39; Running -</pre></div> - - -<h2>Configuring Rainloop</h2> -<p><a href="http://www.rainloop.net/">Rainloop</a> is a web-based email client. I won't go into details on how to configure it in this tutorial ; here's a link to the <a href="http://www.rainloop.net/docs/installation/">official documentation</a>.</p> -<p>You'll need a web server with PHP 5.3+ to run Rainloop. You do not have to run Rainloop on the same host as your mail server. No database is required.</p> -<h2>Conclusion</h2> -<p>We now have a mail server that should be running pretty smoothly. It could still be improved by setting up things such as greylisting or virus detection.</p> -<p>If you have found this tutorial useful, if you've found an error in it or if you have any question, please feel free to leave a comment below or to contact me on <a href="https://twitter.com/captainark">Twitter</a>.</p> -<h2>References</h2> -<p>Here are the tutorials I used to set up my own mail server :</p> -<ul> -<li><a href="http://sealedabstract.com/code/nsa-proof-your-e-mail-in-2-hours/">A complete tutorial on setting up a mail server</a></li> -<li><a href="https://docs.raccoon.io/mail-server-setup-with-postfix-dovecot/">Another complete tutorial</a></li> -<li><a href="https://www.digitalocean.com/community/tutorials/how-to-configure-a-mail-server-using-postfix-dovecot-mysql-and-spamassasin">A third tutorial from DigitalOcean</a></li> -<li><a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-dkim-with-postfix-on-debian-wheezy">A tutorial on setting up OpenDKIM</a></li> -<li><a href="https://guillaume.vaillant.me/?p=481">A tutorial on setting up OpenDMARC</a> (in french)</li> -</ul> \ No newline at end of file diff --git a/output/setting-up-a-mail-server.html b/output/setting-up-a-mail-server.html deleted file mode 100644 index da7de20..0000000 --- a/output/setting-up-a-mail-server.html +++ /dev/null @@ -1,1196 +0,0 @@ - - - - - - - - - - Setting up a mail server - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Setting up a mail server

- Posted by - Antoine Joubert - on Fri 24 April 2015 - - -
-
-
-
-
- - -
-
-
- -
-

In this first tutorial, I'll explain how I've configured my mail server using the following :

-
    -
  • A server running Linux Debian (jessie) ;
  • -
  • Postfix ;
  • -
  • Postfix-policyd-spf-python ;
  • -
  • Dovecot ;
  • -
  • Spamassassin ;
  • -
  • OpenDKIM ;
  • -
  • OpenDMARC ;
  • -
  • Monit ;
  • -
  • Rainloop.
  • -
-

I'm assuming you have some basic knowledge of Linux and DNS configuration.

-

You can host this server at home, but you might have issues with your ISP not allowing outbound traffic on TCP port 25, and your emails might be considered to be spam by other providers if your IP is dynamic and/or you can't configure a reverse DNS record on it.

-

The cheapest VMs from DigitalOcean or Vultr are powerful enough to have this configuration running smoothly.

-

We'll also need a SSL certificate for this configuration. You can create an auto-signed one or get a free valid one from StartSSL. For the purpose of this tutorial, I'll consider you've chosen the latter.

-

You'll also need a domain name. I've chosen Namecheap as a registrar. I won't go into details on how to configure it, but you'll need at the very least a A record on your server's IP as well as a MX record pointing to it.

-

I use the captainark.net domain as an example throughout this tutorial. You'll have to use your actual domain for your configuration to work !

-

Note: links in this section are sponsored.

-

Initial configuration

-

Installing the required packages

-

First thing first, we need to install the packages we'll need for this configuration :

-
apt update
-
-apt install mysql-server mysql-client postfix postfix-mysql \
-postfix-policyd-spf-python dovecot-core dovecot-imapd dovecot-lmtpd \
-dovecot-mysql dovecot-sieve dovecot-managesieved dovecot-antispam \
-opendkim opendkim-tools monit opendmarc spamassassin spamc
-
- - -

During its installation, Postfix will prompt you with configuration questions. Choose "Internet Site", and when asked about your System mail name, provide it with your server's FQDN (it should be the output of the hostname -f command on your server).

-

You'll also have to set-up a password for the MySQL root user.

-

Additional configuration

-

The PTR records on your server's IPv4 and/or IPv6 should match your server's FQDN (a dig -x on your server's IP should match a hostname -f on your server).

-

You'll have to open the following TCP ports on your server for this configuration to work : 25, 465, 587 and 993.

-

If you don't want to have to remember the root user MySQL password, you can create a .my.cnf file in your current user home directory containing the following lines :

-
[client]
-host     = localhost
-user     = root
-password = myverysecurepassword
-socket   = /var/run/mysqld/mysqld.sock
-
- - -

Once it has been created, change the permissions on the file to make sure no other user can read it :

-
chmod 600 ~/.my.cnf
-
- - -

I also like to change the default MySQL shell to see what database I'm using at any given time. Since I use bash, I achieve this the following way :

-
echo 'export MYSQL_PS1="[\u@\h] (\d)> "' > ~/.bash_aliases
-
- - -

You'll have to logout from the current shell for the modification to be taken into account (if you're using SSH, log out and back into your server).

-

You should now be able to log into MySQL without specifying a password, and it should look like this :

-
:~$ mysql mysql
-[...]
-[root@localhost] (mysql)>
-
- - -

Configuring the MySQL database

-

Initial configuration

-

We now need to configure the MySQL database Postfix and Dovecot will be using. In this tutorial, we'll be calling it "mail", but you can name it whatever you want.

-

First, in a mysql shell, let's create the MySQL database :

-
CREATE DATABASE mail;
-
- - -

Now, we are going to create the user that Postfix and Dovecot will be using to access the database. We will only be granting this user select permission :

-
GRANT SELECT ON mail.* TO 'mail'@'localhost' IDENTIFIED BY 'mailpassword';
-FLUSH PRIVILEGES;
-
- - -

We are now going to create the necessary tables for our needs. Let's first use the mail database :

-
USE mail;
-
- - -

The first table we are going to create will contain the domains we will be using with our mail server :

-
CREATE TABLE `virtual_domains` (
-`id`  INT NOT NULL AUTO_INCREMENT,
-`name` VARCHAR(50) NOT NULL,
-PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
- - -

Then, we are going to create the table that will contain our users and their password :

-
CREATE TABLE `virtual_users` (
-`id` INT NOT NULL AUTO_INCREMENT,
-`domain_id` INT NOT NULL,
-`password` VARCHAR(106) NOT NULL,
-`email` VARCHAR(120) NOT NULL,
-PRIMARY KEY (`id`),
-UNIQUE KEY `email` (`email`),
-FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
- - -

Finally, the last table we are going to create will contain our mail aliases :

-
CREATE TABLE `virtual_aliases` (
-`id` INT NOT NULL AUTO_INCREMENT,
-`domain_id` INT NOT NULL,
-`source` varchar(100) NOT NULL,
-`destination` varchar(100) NOT NULL,
-PRIMARY KEY (`id`),
-FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
- - -

Domains, users and aliases management

-

We are now going to add data to the tables we have created.

-

First, let's add a domain to the virtual_domains table :

-
INSERT INTO virtual_domains (`name`) VALUES ('captainark.net');
-
- - -

We can now create users associated with this domain in the virtual_users table :

-
INSERT INTO virtual_users (`domain_id`, `password` , `email`) VALUES
-('1', ENCRYPT('notanactualpassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))),
-'example@captainark.net');
-
- - -

This is not mandatory, but we can also create our first mail alias :

-
INSERT INTO virtual_aliases (`domain_id`, `source`, `destination`) VALUES
-('1', 'alias@captainark.net', 'example@captainark.net');
-
- - -

Now, all messages sent to alias@captainark.net will be forwarded to example@captainark.net.

-

Use the same syntax to create additional domains, users and aliases. If you have more than one domains configured, be sure to associate your users and aliases with the correct domain_id.

-

Configuring Postfix

-

Next, we are going to configure Postfix.

-

Configuration backup

-

First, let's backup the original configuration files :

-
cp /etc/postfix/main.cf /etc/postfix/main.cf.orig
-cp /etc/postfix/master.cf /etc/postfix/master.cf.orig
-
- - -

User and group creation

-

We are now going to create a user and group called vmail that will be used by both Postfix and Dovecot :

-
groupadd -g 5000 vmail
-useradd -g vmail -u 5000 vmail -d /var/mail -m -s /bin/false
-
- - -

SSL certificates

-

Next, we are going to create the folder where we will store the SSL certificates :

-
mkdir /etc/postfix/ssl
-chown root: /etc/postfix/ssl && chmod 600 /etc/postfix/ssl
-
- - -

Purists will probably want to store their certificates in /etc/ssl/private. If you choose to do so, you'll have to adapt the path of those files for the remainder of this tutorial.

-

If you've decided to create a certificate with StartSSL, you'll end up with two files, a .crt and a .key. I'll name those files server.crt and server-with-passphrase.key. Put both these files in the folder we've just created.

-

Now, let's remove the passphrase from the key :

-
cd /etc/postfix/ssl
-openssl rsa -in server-with-passphrase.key -out server.key
-
- - -

You'll be prompted for the passphrase you chose during the certificate generation.

-

Next, we have to download the appropriate intermediate certificate :

-
wget -O /etc/postfix/ssl/sub.class1.server.ca.pem \
-http://www.startssl.com/certs/sub.class1.server.ca.pem
-
- - -

We now have to make sure that the permissions on those files are correct :

-
chown root: /etc/postfix/ssl/* && chmod 600 /etc/postfix/ssl/*
-
- - -

The last thing we have to do here is to generate Diffie-Hellman keys for Perfect Forward Secrecy (PFS) :

-
openssl gendh -out /etc/postfix/dh_512.pem -2 512
-openssl gendh -out /etc/postfix/dh_1024.pem -2 1024
-
- - -

Postifx configuration

-

First, let's edit the /etc/postfix/main.cf file. It should end up looking something like that :

-
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
-biff = no
-
-broken_sasl_auth_clients = yes
-config_directory = /etc/postfix
-disable_vrfy_command = yes
-smtpd_data_restrictions = reject_unauth_pipelining, permit
-smtpd_helo_required = yes
-
-queue_directory = /var/spool/postfix
-append_dot_mydomain = no
-readme_directory = no
-
-smtpd_use_tls=yes
-smtpd_tls_auth_only = yes
-smtpd_tls_cert_file=/etc/postfix/ssl/server.crt
-smtpd_tls_key_file=/etc/postfix/ssl/server.key
-smtpd_tls_CAfile=/etc/postfix/ssl/sub.class1.server.ca.pem
-smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3
-smtpd_tls_protocols=!SSLv2,!SSLv3
-smtpd_tls_mandatory_ciphers=high
-smtpd_tls_dh1024_param_file = /etc/postfix/dh_1024.pem
-smtpd_tls_dh512_param_file = /etc/postfix/dh_512.pem
-smtpd_tls_eecdh_grade = strong
-smtpd_tls_loglevel = 1
-smtpd_tls_received_header = yes
-smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
-
-tls_preempt_cipherlist = yes
-tls_random_source = dev:/dev/urandom
-
-smtpd_data_restrictions = reject_unauth_pipelining, permit
-smtpd_helo_required = yes
-
-smtp_tls_CAfile = $smtpd_tls_CAfile
-smtp_tls_mandatory_protocols=!SSLv2,!SSLv3
-smtp_tls_protocols=!SSLv2,!SSLv3
-smtp_tls_security_level = may
-smtp_tls_loglevel = 1
-smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
-
-smtpd_milters =
-non_smtpd_milters = $smtpd_milters
-milter_protocol = 2
-milter_default_action = accept
-
-smtpd_recipient_restrictions =
-  reject_invalid_hostname,
-  reject_non_fqdn_hostname,
-  reject_non_fqdn_sender,
-  reject_non_fqdn_recipient,
-  reject_unknown_sender_domain,
-  reject_unknown_recipient_domain,
-  permit_mynetworks,
-  permit_sasl_authenticated,
-  reject_unauth_destination,
-  permit
-
-smtpd_sasl_auth_enable = yes
-smtpd_sasl_local_domain = $myhostname
-smtpd_sasl_security_options = noanonymous
-smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
-smtpd_tls_auth_only = yes
-smtpd_sasl_type = dovecot
-smtpd_sasl_path = private/auth
-
-myhostname = myserver.captainark.net ### CHANGE THIS
-alias_maps = hash:/etc/aliases
-alias_database = hash:/etc/aliases
-myorigin = /etc/mailname
-mydestination = localhost, myserver.captainark.net ### CHANGE THIS
-relayhost =
-mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
-mailbox_size_limit = 0
-recipient_delimiter = +
-default_transport = smtp
-relay_transport = smtp
-inet_interfaces = all
-inet_protocols = all
-
-virtual_transport = lmtp:unix:private/dovecot-lmtp
-virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
-virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
-virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
-
- - -

The variable "myhostname" has to be defined to you server's FQDN. The file /etc/mailname should contain your server's FQDN as well.

-

Next, we need to edit the /etc/postfix/master.cf file. You need to uncomment the following lines :

-
submission inet n       -       -       -       -       smtpd
-  -o syslog_name=postfix/submission
-  -o smtpd_tls_security_level=encrypt
-  -o tls_preempt_cipherlist=yes
-  -o smtpd_sasl_auth_enable=yes
-  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-
-smtps     inet  n       -       -       -       -       smtpd
-  -o syslog_name=postfix/smtps
-  -o smtpd_tls_wrappermode=yes
-  -o smtpd_sasl_auth_enable=yes
-  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
-
- - -

You also have to add the following lines at the end of the file :

-
dovecot    unix  -       n       n       -       -       pipe
-  flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}
-
- - -

MySQL access for Postfix

-

We now need to allow Postfix to connect to the MySQL database we have created earlier. To that end, we must create three files.

-

/etc/postfix/mysql-virtual-mailbox-domains.cf should contain the following lines :

-
user = mail
-password = mailpassword
-hosts = 127.0.0.1
-dbname = mail
-query = SELECT 1 FROM virtual_domains WHERE name='%s'
-
- - -

/etc/postfix/mysql-virtual-mailbox-maps.cf should contain the following lines :

-
user = mail
-password = mailpassword
-hosts = 127.0.0.1
-dbname = mail
-query = SELECT 1 FROM virtual_users WHERE email='%s'
-
- - -

/etc/postfix/mysql-virtual-alias-maps.cf should contain the following lines :

-
user = mail
-password = mailpassword
-hosts = 127.0.0.1
-dbname = mail
-query = SELECT destination FROM virtual_aliases WHERE source='%s'
-
- - -

Since these files contain a password, let's make sure they are not world-readable :

-
chown root: /etc/postfix/mysql* && chmod 600 /etc/postfix/mysql*
-
- - -

You can use the command postmap to confirm that everything is working properly :

-
postmap -q captainark.net mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
-
-postmap -q example@captainark.net mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
-
-postmap -q alias@captainark.net mysql:/etc/postfix/mysql-virtual-alias-maps.cf
-
- - -

Let's restart postfix for our modifications to be taken into account :

-
systemctl restart postfix
-
- - -

That's it for Postfix, for now ; Dovecot is next !

-

Configuring Dovecot

-

Dovecot global configuration

-

By default, on Debian, Dovecot uses multiple configuration files in /etc/dovecot/conf.d. I found it annoying to maintain, and I ended up only using the /etc/doveconf.conf file.

-

As always, let's start by backing up the original configuration file :

-
mv /etc/dovecot/dovecot.conf /etc/dovecot/dovecot.conf.orig
-
- - -

Next, we are going to create a new /etc/dovecot/dovecot.conf file. It should contain the following lines :

-
!include_try /usr/share/dovecot/protocols.d/*.protocol
-protocols = imap lmtp sieve
-
-mail_location = maildir:/var/mail/%d/%n
-mail_privileged_group = vmail
-mail_plugin_dir = /usr/lib/dovecot/modules
-mail_plugins =
-
-disable_plaintext_auth = yes
-auth_mechanisms = plain login
-
-service director {
-  unix_listener login/director {
-  }
-  fifo_listener login/proxy-notify {
-  }
-  unix_listener director-userdb {
-  }
-  inet_listener {
-  }
-}
-
-namespace inbox {
-  inbox = yes
-  type = private
-    mailbox Drafts {
-      auto = subscribe
-      special_use = \Drafts
-    }
-    mailbox Junk {
-      auto = subscribe
-      special_use = \Junk
-    }
-    mailbox Sent {
-      auto = subscribe
-      special_use = \Sent
-    }
-    mailbox Trash {
-      auto = subscribe
-      special_use = \Trash
-    }
-}
-
-service imap-login {
-  inet_listener imap {
-    port = 0
-  }
-  inet_listener imaps {
-    port = 993
-    ssl = yes
-  }
-}
-
-service pop3-login {
-  inet_listener pop3 {
-    port = 0
-  }
-  inet_listener pop3s {
-    port = 0
-  }
-}
-
-service lmtp {
-  unix_listener /var/spool/postfix/private/dovecot-lmtp {
-    mode = 0600
-    user = postfix
-    group = postfix
-  }
-}
-
-service imap {
-}
-
-service pop3 {
-}
-
-service auth {
-  unix_listener /var/spool/postfix/private/auth {
-    mode = 0666
-    user = postfix
-    group = postfix
-  }
-  unix_listener auth-userdb {
-    mode = 0600
-    user = vmail
-  }
-  user = dovecot
-}
-
-service auth-worker {
-  user = vmail
-}
-
-service dict {
-  unix_listener dict {
-  }
-}
-
-ssl = required
-ssl_cert = </etc/postfix/ssl/server.crt
-ssl_key = </etc/postfix/ssl/server.key
-ssl_ca = </etc/postfix/ssl/sub.class1.server.ca.pem
-ssl_protocols = !SSLv2 !SSLv3
-ssl_cipher_list = AES128+EECDH:AES128+EDH:!aNULL;
-protocol lda {
-  mail_plugins = $mail_plugins sieve
-}
-
-protocol imap {
-  mail_plugins = $mail_plugins
-}
-protocol lmtp {
-  mail_plugins = $mail_plugins sieve
-}
-
-plugin {
-  sieve = /var/mail/sieve/users/%u.sieve
-  sieve_after = /var/mail/sieve/after
-  sieve_before = /var/mail/sieve/before
-  sieve_global_dir = /var/lib/dovecot/sieve/
-  sieve_dir = ~/sieve
-}
-
-passdb {
-  driver = sql
-  args = /etc/dovecot/sql.conf
-}
-userdb {
-  driver = static
-  args = uid=vmail gid=vmail home=/var/mail/%d/%n
-}
-
- - -

Dovecot will use the same SSL certificate as Postfix.

-

Using this configuration, your virtual users' emails will be stored in /var/mail/$domain/$user/ and will be owned by the vmail user.

-

For this to work, we have to create the domain folder :

-
mkdir -p /var/mail/captainark.net
-chown vmail: /var/mail/captainark.net && chmod 770 /var/mail/captainark.net
-
- - -

Dovecot will create the virtual users' folders automatically.

-

Dovecot access to the MySQL database

-

We now need to allow Dovecot to connect to the mail database we have populated earlier. To do so, we are going to create a /etc/dovecot/sql.conf file with the following content :

-
driver = mysql
-connect = host=localhost dbname=mail user=mail password=mailpassword
-default_pass_scheme = SHA512-CRYPT
-password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
-
- - -

You'll have to change the password to the one you have defined earlier. Since this file contains a password, let's make sure it's not world-readable :

-
chown root: /etc/dovecot/sql.conf && chmod 600 /etc/dovecot/sql.conf
-
- - -

Configuring Sieve

-

The last thing we need to configure here is sieve. The idea is to have all messages flagged as spam automatically moved to the mailbox Junk folder.

-

To do so, let's first create the required folders :

-
mkdir -p /var/mail/sieve/before
-mkdir /var/mail/sieve/after
-mkdir /var/mail/sieve/users
-chown -R vmail: /var/mail/sieve && chmod -R 770 /var/mail/sieve
-
- - -

If you want to have sieve rules for a specific user, simply create $user@$domain.sieve file in the users folder (example@captainark.net in my case).

-

All .sieve files in the before folder will be used for all your virtual users, before their individual configuration ; the .sieve files in the after folder will be used, well, you guessed it, after.

-

Let's create a filter.sieve file in the /var/mail/sieve/before folder with the following content :

-
require ["envelope", "fileinto", "imap4flags", "regex"];
-
-if not header :regex "message-id" ".*@.*\." {
-      fileinto "Junk";
-}
-
-if header :contains "X-Spam-Level" "*****" {
-      fileinto "Junk";
-}
-
- - -

Last thing we have to do is to change the permissions on the newly created file :

-
chown vmail: /var/mail/sieve/before/filter.sieve && \
-chmod 660 /var/mail/sieve/before/filter.sieve
-
- - -

That's all ; now, all email we receive that is flagged as spam by SpamAssassin will be moved to the Junk folder.

-

Let's restart dovecot :

-
systemctl restart dovecot
-
- - -

We now have a working mail server !

-

To connect to it and access your mailbox, configure your email client as follow :

-
    -
  • Username: example@captainark.net ;
  • -
  • Password: the password you chose for your virtual user ;
  • -
  • IMAP: your server's FQDN, port 993 (SSL/TLS with normal password) ;
  • -
  • SMTP: your server's FQDN, port 465 (SSL/TLS with normal password).
  • -
-

Configuring SpamAssassin

-

The alternatives

-

Next thing we have to do is to configure the actual anti-spam. I tried a few, but I ended up sticking with SpamAssassin. Here's why :

- -

The actual configuration

-

SpamAssassin's configuration is pretty straightforward. First, let's edit the /etc/default/spamassassin file :

-
ENABLED=1
-[...]
-CRON=1
-
- - -

Before the cron runs for the first time, we have to manually update SpamAssassin's ruleset :

-
sa-learn
-
- - -

Next, as usual, let's back up the original configuration file :

-
mv /etc/spamassassin/local.cf /etc/spamassassin/local.cf.orig
-
- - -

Let's create a new /etc/spamassassin/local.cf file with the following content :

-
rewrite_header Subject [SPAM]
-report_safe 0
-required_score 5.0
-use_bayes 1
-bayes_auto_learn 1
-
-whitelist_from *@captainark.net
-
- - -

Next, to have Postfix send incoming emails through SpamAssassin, we have to edit the /etc/postfix/master.cf file. At the very beginning, we have to add a line under the smtp definition :

-
smtp      inet  n       -       -       -       -       smtpd
-  -o content_filter=spamassassin
-
- - -

At the very end of the same file, we have to add the following lines :

-
spamassassin unix -     n       n       -       -       pipe
-  user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
-
- - -

Let's restart SpamAssassin and Postfix :

-
systemctl restart postfix
-systemctl restart spamassassin
-
- - -

That's all for SpamAssassin ! To check if it is working, send yourself an email from another provider. You should see the following headers in it :

-
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
-    myserver.captainark.net
-X-Spam-Level:
-
- - -

Configuring SPF

-

Allowing your server to send emails for your domain

-

SPF (Sender Policy Framework) is a mechanism that confirms that your server's IP is allowed to send emails for your domain. Technically, it is a TXT DNS record which looks something like this :

-
captainark.net IN TXT "v=spf1 mx ~all"
-
- - -

This DNS record lets other mail servers know that hosts that have a MX record for my domain are also allowed to send emails for it.

-

For more information on SPF syntax, you can consult the official documentation.

-

Without a properly configured SPF record, other mail servers might flag your emails as spam or outright drop them.

-

Checking SPF record for inbound mail

-

Now that we have set up our own SPF record, let's configure Postfix to check that other mail servers communicating with us have done the same.

-

First, let's add the two following lines at the end of /etc/postfix-policyd-spf-python/policyd-spf.conf :

-
Header_Type = AR
-Authserv_Id = "<server's FQDN>"
-
- - -

Then, let's edit the /etc/postfix/master.cf file and add the following lines at the end :

-
policy-spf  unix  -       n       n       -       -       spawn
-  user=nobody argv=/usr/bin/policyd-spf
-
- - -

Let's now edit the /etc/postfix/main.cf. In the "smtpd_recipient_restrictions" section, add the "check_policy_service" line as seen below :

-
smtpd_recipient_restrictions =
-[...]
-  reject_unauth_destination,
-  check_policy_service unix:private/policy-spf,
-  permit
-
- - -

We now have to restart postfix :

-
systemctl restart postfix
-
- - -

Our server is now checking other mail server's SPF records.

-

To make sure that it is working, send yourself an email from another provider. You should see the following header in it :

-
Authentication-Results: myserver.captainark.net; spf=pass (sender SPF authorized)
-[...] receiver=example@captainark.net)
-
- - -

Configuring OpenDKIM

-

DKIM (DomainKeys Identified Mail) is a mechanism that validates a domain name identity for an email through cryptographic authentication.

-

While not mandatory, setting up DKIM improves the odds of emails sent from your server not being flagged as spam by other providers.

-

With this configuration, OpenDKIM will also check the key for inbound emails.

-

Software side

-

First, let's backup the original configuration file and create a folder for the configuration files :

-
mv /etc/opendkim.conf /etc/opendkim.conf.orig
-mkdir /etc/opendkim.d
-
- - -

We now have to create a /etc/opendkim.conf file with the following content :

-
AutoRestart             Yes
-AutoRestartRate         10/1h
-UMask                   002
-Syslog                  yes
-SyslogSuccess           Yes
-LogWhy                  Yes
-
-OversignHeaders         From
-AlwaysAddARHeader       yes
-
-Canonicalization        relaxed/simple
-
-ExternalIgnoreList      refile:/etc/opendkim.d/TrustedHosts
-InternalHosts           refile:/etc/opendkim.d/dkim/TrustedHosts
-KeyTable                refile:/etc/opendkim.d/dkim/KeyTable
-SigningTable            refile:/etc/opendkim.d/dkim/SigningTable
-
-Mode                    sv
-PidFile                 /run/opendkim/opendkim.pid
-SignatureAlgorithm      rsa-sha256
-
-UserID                  opendkim:opendkim
-
-Socket                  local:/var/spool/postfix/opendkim/opendkim.sock
-
- - -

Let's then create the necessary folders :

-
mkdir -p /etc/opendkim.d/keys/captainark.net/
-
- - -

Now, we are going to create the /etc/opendkim.d/TrustedHosts file with the following content :

-
localhost
-127.0.0.1
-::1
-captainark.net
-
- - -

This file contains the hosts and domains for which OpenDKIM should sign emails.

-

Next, let's create the /etc/opendkim.d/KeyTable :

-
mail._domainkey.captainark.net captainark.net:mail:/etc/opendkim.d/keys/captainark.net/mail.private
-
- - -

This file tells OpenDKIM which key it should use for each selector.

-

Finally, let's create the /etc/opendkim.d/SigningTable file :

-
*@captainark.net mail._domainkey.captainark.net
-
- - -

This file tells OpenDKIM which selector it should use for each domain.

-

We now have to generate the private/public key pair for our domain :

-
cd /etc/opendkim.d/keys/captainark.net/
-opendkim-genkey -s mail -d captainark.net
-
- - -

This creates two files ; mail.private contains our private key, mail.txt contains our public key.

-

Let's change the permissions on those files :

-
chown -R opendkim: /etc/opendkim.d/keys
-chmod -R 700 /etc/opendkim.d/keys
-chmod 600 /etc/opendkim.d/captainark.net/*
-
- - -

Postfix integration

-

The last thing we have to do is to configure Postfix to communicate with OpenDKIM.

-

First, let's create the necessary folders :

-
mkdir /var/spool/postfix/opendkim
-chown opendkim: /var/spool/postfix/opendkim
-
- - -

We also have to add the postfix user to the opendkim group :

-
useradd -G opendkim postfix
-
- - -

Now, let's edit the /etc/postfix/master.cf file, like so :

-
smtpd_milters = unix:/opendkim/opendkim.sock
-
- - -

We now have to restart OpenDKIM and Postfix :

-
systemctl restart opendkim
-systemctl restart postfix
-
- - -

DNS side

-

For DKIM to work, you have to configure a DNS TXT record in your zone. This record was automatically generated by OpenDKIM in the mail.txt file mentioned earlier :

-
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkJq0CW3tl2XHZ1CN5XdbqRDU7KfXOJ70nlwI09bHmDU63/Yz3J5rl863S0t2ncVHfIudZANj0OaiJe5HRR7WCsjuNIhQFfPFGIWLNClpxqdQVQURI38sAGeyn7Ed/Cor1AiWABzFWzel0kvXILw8K/NTzxaAPeSa9ttwQEgSmowIDAQAB" ; ----- DKIM key mail for captainark.net
-
- - -

All you have to do is to copy and paste this record in your DNS zone file.

-

To make sure that OpenDKIM is working, you can send an empty email to check-auth@verifier.port25.com. You should receive a response with the following content :

-
==========================================================
-Summary of Results
-==========================================================
-SPF check:          pass
-DomainKeys check:   neutral
-DKIM check:         pass
-Sender-ID check:    pass
-SpamAssassin check: ham
-
- - -

Configuring OpenDMARC

-

DMARC (Domain-based Message Authentication, Reporting & Conformance) standardizes SPF and DKIM authentication mechanisms.

-

It lets the owner of a domain name indicate that his email is protected by SPF and/or DKIM and what other providers should do with emails that do not pass those checks.

-

Software side

-

Once again, let's backup the original configuration file :

-
mv /etc/opendmarc.conf /etc/opendmarc.conf.orig
-
- - -

We now have to create a /etc/opendmarc.conf file with the following content :

-
AutoRestart             Yes
-AutoRestartRate         10/1h
-UMask                   0002
-Syslog                  true
-
-AuthservID              "<your server's FQDN>"
-TrustedAuthservIDs      "<your server's FQDN>"
-IgnoreHosts             /etc/opendkim.d/TrustedHosts
-
-RejectFailures          false
-
-UserID                  opendmarc:opendmarc
-PidFile                 /run/opendmarc.pid
-Socket                  local:/var/spool/postfix/opendmarc/opendmarc.sock
-
- - -

Postfix integration

-

The last thing we have to do is to configure Postfix to communicate with OpenDMARC.

-

First, let's create the necessary folders :

-
mkdir /var/spool/postfix/opendmarc
-chown opendmarc: /var/spool/postfix/opendmarc
-
- - -

We also have to add the postfix user to the opendmarc group :

-
useradd -G opendmarc postfix
-
- - -

Now, let's edit the /etc/postfix/master.cf file, like so :

-
smtpd_milters = unix:/opendkim/opendkim.sock, unix:/opendmarc/opendmarc.sock
-
- - -

We now have to restart OpenDMARC and Postfix :

-
systemctl restart opendmarc
-systemctl restart postfix
-
- - -

You should now see the following headers in your incoming emails :

-
Authentication-Results: myserver.captainark.net; dmarc=pass header.from=gmail.com
-
- - -

DNS side

-

DMARC, like SPF and DKIM, is based on DNS TXT records.

-

Here is how I configured it for the captainark.net domain :

-
_dmarc IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@captainark.net; ruf=mailto:postmaster@captainark.net"
-
- - -

This tells other providers to not reject or quarantine emails should a SPF or DKIM check fail, but to send a daily report of those checks to postmaster@captainark.net.

-

For more information on the DMARC syntax, here is an article from Google.

-

Configuring Monit

-

Monit is a daemon that makes sure that other daemons are running. If they crash, it restarts them automatically. Is is not directly related to a mail server per say, but it's pretty easy to set up.

-

First, as always, let's backup the original configuration file :

-
mv /etc/monit/monitrc /etc/monit/monitrc.orig
-
- - -

We now have to create a new /etc/monit/monitrc file with the following content :

-
set daemon 30
-set logfile syslog facility log_daemon
-
-set httpd port 2812 and
-use address localhost
-allow localhost
-
-set mailserver localhost
-with timeout 30 seconds
-using hostname myserver.captainark.net
-
-set mail-format { from: monit@captainark.net }
-
-include /etc/monit/conf.d/*
-
- - -

Then, we are going to create a /etc/monit/conf.d/mail file with the following content :

-
check process postfix
-  with pidfile "/var/spool/postfix/pid/master.pid"
-  start program = "/bin/systemctl start postfix"
-  stop program = "/bin/systemctl stop postfix"
-  alert monit@captainark.net
-  group mail
-
-check process dovecot
-  with pidfile "/run/dovecot/master.pid"
-  start program = "/bin/systemctl start dovecot"
-  stop program = "/bin/systemctl stop dovecot"
-  alert monit@captainark.net
-  group mail
-  depends on postfix
-
-check process spamassassin
-  with pidfile "/run/spamassassin.pid"
-  start program = "/bin/systemctl start spamassassin"
-  stop program = "/bin/systemctl stop spamassassin"
-  alert monit@captainark.net
-  group mail
-  depends on postfix, dovecot
-
-check process opendkim
-  with pidfile "/run/opendkim/opendkim.pid"
-  start program = "/bin/systemctl start opendkim"
-  stop program = "/bin/systemctl stop opendkim"
-  alert monit@captainark.net
-  group mail
-  depends on postfix, dovecot
-
-check process opendmarc
-  with pidfile "/run/opendmarc/opendmarc.pid"
-  start program = "/bin/systemctl start opendmarc"
-  stop program = "/bin/systemctl stop opendmarc"
-  alert monit@captainark.net
-  group mail
-  depends on postfix, dovecot
-
- - -

Let's make sure that permissions on the file are correct :

-
chown root: /etc/monit/conf.d/mail && chmod 600 /etc/monit/conf.d/mail
-
- - -

Then, we have to reload the monit daemon :

-
monit reload
-
- - -

Now, the monit summary command should have the following output :

-
The Monit daemon 5.4 uptime: 3d 0h 41m
-
-Process 'postfix'                   Running
-Process 'dovecot'                   Running
-Process 'spamassassin'              Running
-Process 'opendkim'                  Running
-Process 'opendmarc'                 Running
-
- - -

Configuring Rainloop

-

Rainloop is a web-based email client. I won't go into details on how to configure it in this tutorial ; here's a link to the official documentation.

-

You'll need a web server with PHP 5.3+ to run Rainloop. You do not have to run Rainloop on the same host as your mail server. No database is required.

-

Conclusion

-

We now have a mail server that should be running pretty smoothly. It could still be improved by setting up things such as greylisting or virus detection.

-

If you have found this tutorial useful, if you've found an error in it or if you have any question, please feel free to leave a comment below or to contact me on Twitter.

-

References

-

Here are the tutorials I used to set up my own mail server :

- -
- - -
- -
-

Comments !

-
- - -
-
-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/tags.html b/output/tags.html deleted file mode 100644 index 3dbee0d..0000000 --- a/output/tags.html +++ /dev/null @@ -1,195 +0,0 @@ - - - - - - - - - - Sysadmining. All day. Every day. - Tags - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-

Sysadmining. All day. Every day. - Tags

-
-
-
-
-
- - -
-
-
-

Tags for Sysadmining. All day. Every day.

-
-
- -
- - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/theme/css/bootstrap.css b/output/theme/css/bootstrap.css deleted file mode 100644 index 4165d41..0000000 --- a/output/theme/css/bootstrap.css +++ /dev/null @@ -1,6358 +0,0 @@ -/*! - * Bootstrap v3.3.0 (http://getbootstrap.com) - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ -html { - font-family: sans-serif; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} -body { - margin: 0; -} -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} -audio, -canvas, -progress, -video { - display: inline-block; - vertical-align: baseline; -} -audio:not([controls]) { - display: none; - height: 0; -} -[hidden], -template { - display: none; -} -a { - background-color: transparent; -} -a:active, -a:hover { - outline: 0; -} -abbr[title] { - border-bottom: 1px dotted; -} -b, -strong { - font-weight: bold; -} -dfn { - font-style: italic; -} -h1 { - margin: .67em 0; - font-size: 2em; -} -mark { - color: #000; - background: #ff0; -} -small { - font-size: 80%; -} -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} -sup { - top: -.5em; -} -sub { - bottom: -.25em; -} -img { - border: 0; -} -svg:not(:root) { - overflow: hidden; -} -figure { - margin: 1em 40px; -} -hr { - height: 0; - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; -} -pre { - overflow: auto; -} -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} -button, -input, -optgroup, -select, -textarea { - margin: 0; - font: inherit; - color: inherit; -} -button { - overflow: visible; -} -button, -select { - text-transform: none; -} -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; -} -button[disabled], -html input[disabled] { - cursor: default; -} -button::-moz-focus-inner, -input::-moz-focus-inner { - padding: 0; - border: 0; -} -input { - line-height: normal; -} -input[type="checkbox"], -input[type="radio"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0; -} -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} -input[type="search"] { - -webkit-box-sizing: content-box; - -moz-box-sizing: content-box; - box-sizing: content-box; - -webkit-appearance: textfield; -} -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} -fieldset { - padding: .35em .625em .75em; - margin: 0 2px; - border: 1px solid #c0c0c0; -} -legend { - padding: 0; - border: 0; -} -textarea { - overflow: auto; -} -optgroup { - font-weight: bold; -} -table { - border-spacing: 0; - border-collapse: collapse; -} -td, -th { - padding: 0; -} -/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */ -@media print { - *, - *:before, - *:after { - color: #000 !important; - text-shadow: none !important; - background: transparent !important; - -webkit-box-shadow: none !important; - box-shadow: none !important; - } - a, - a:visited { - text-decoration: underline; - } - a[href]:after { - content: " (" attr(href) ")"; - } - abbr[title]:after { - content: " (" attr(title) ")"; - } - a[href^="#"]:after, - a[href^="javascript:"]:after { - content: ""; - } - pre, - blockquote { - border: 1px solid #999; - - page-break-inside: avoid; - } - thead { - display: table-header-group; - } - tr, - img { - page-break-inside: avoid; - } - img { - max-width: 100% !important; - } - p, - h2, - h3 { - orphans: 3; - widows: 3; - } - h2, - h3 { - page-break-after: avoid; - } - select { - background: #fff !important; - } - .navbar { - display: none; - } - .btn > .caret, - .dropup > .btn > .caret { - border-top-color: #000 !important; - } - .label { - border: 1px solid #000; - } - .table { - border-collapse: collapse !important; - } - .table td, - .table th { - background-color: #fff !important; - } - .table-bordered th, - .table-bordered td { - border: 1px solid #ddd !important; - } -} -@font-face { - font-family: 'Glyphicons Halflings'; - - src: url('../fonts/glyphicons-halflings-regular.eot'); - src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); -} -.glyphicon { - position: relative; - top: 1px; - display: inline-block; - font-family: 'Glyphicons Halflings'; - font-style: normal; - font-weight: normal; - line-height: 1; - - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.glyphicon-asterisk:before { - content: "\2a"; -} -.glyphicon-plus:before { - content: "\2b"; -} -.glyphicon-euro:before, -.glyphicon-eur:before { - content: "\20ac"; -} -.glyphicon-minus:before { - content: "\2212"; -} -.glyphicon-cloud:before { - content: "\2601"; -} -.glyphicon-envelope:before { - content: "\2709"; -} -.glyphicon-pencil:before { - content: "\270f"; -} -.glyphicon-glass:before { - content: "\e001"; -} -.glyphicon-music:before { - content: "\e002"; -} -.glyphicon-search:before { - content: "\e003"; -} -.glyphicon-heart:before { - content: "\e005"; -} -.glyphicon-star:before { - content: "\e006"; -} -.glyphicon-star-empty:before { - content: "\e007"; -} -.glyphicon-user:before { - content: "\e008"; -} -.glyphicon-film:before { - content: "\e009"; -} -.glyphicon-th-large:before { - content: "\e010"; -} -.glyphicon-th:before { - content: "\e011"; -} -.glyphicon-th-list:before { - content: "\e012"; -} -.glyphicon-ok:before { - content: "\e013"; -} -.glyphicon-remove:before { - content: "\e014"; -} -.glyphicon-zoom-in:before { - content: "\e015"; -} -.glyphicon-zoom-out:before { - content: "\e016"; -} -.glyphicon-off:before { - content: "\e017"; -} -.glyphicon-signal:before { - content: "\e018"; -} -.glyphicon-cog:before { - content: "\e019"; -} -.glyphicon-trash:before { - content: "\e020"; -} -.glyphicon-home:before { - content: "\e021"; -} -.glyphicon-file:before { - content: "\e022"; -} -.glyphicon-time:before { - content: "\e023"; -} -.glyphicon-road:before { - content: "\e024"; -} -.glyphicon-download-alt:before { - content: "\e025"; -} -.glyphicon-download:before { - content: "\e026"; -} -.glyphicon-upload:before { - content: "\e027"; -} -.glyphicon-inbox:before { - content: "\e028"; -} -.glyphicon-play-circle:before { - content: "\e029"; -} -.glyphicon-repeat:before { - content: "\e030"; -} -.glyphicon-refresh:before { - content: "\e031"; -} -.glyphicon-list-alt:before { - content: "\e032"; -} -.glyphicon-lock:before { - content: "\e033"; -} -.glyphicon-flag:before { - content: "\e034"; -} -.glyphicon-headphones:before { - content: "\e035"; -} -.glyphicon-volume-off:before { - content: "\e036"; -} -.glyphicon-volume-down:before { - content: "\e037"; -} -.glyphicon-volume-up:before { - content: "\e038"; -} -.glyphicon-qrcode:before { - content: "\e039"; -} -.glyphicon-barcode:before { - content: "\e040"; -} -.glyphicon-tag:before { - content: "\e041"; -} -.glyphicon-tags:before { - content: "\e042"; -} -.glyphicon-book:before { - content: "\e043"; -} -.glyphicon-bookmark:before { - content: "\e044"; -} -.glyphicon-print:before { - content: "\e045"; -} -.glyphicon-camera:before { - content: "\e046"; -} -.glyphicon-font:before { - content: "\e047"; -} -.glyphicon-bold:before { - content: "\e048"; -} -.glyphicon-italic:before { - content: "\e049"; -} -.glyphicon-text-height:before { - content: "\e050"; -} -.glyphicon-text-width:before { - content: "\e051"; -} -.glyphicon-align-left:before { - content: "\e052"; -} -.glyphicon-align-center:before { - content: "\e053"; -} -.glyphicon-align-right:before { - content: "\e054"; -} -.glyphicon-align-justify:before { - content: "\e055"; -} -.glyphicon-list:before { - content: "\e056"; -} -.glyphicon-indent-left:before { - content: "\e057"; -} -.glyphicon-indent-right:before { - content: "\e058"; -} -.glyphicon-facetime-video:before { - content: "\e059"; -} -.glyphicon-picture:before { - content: "\e060"; -} -.glyphicon-map-marker:before { - content: "\e062"; -} -.glyphicon-adjust:before { - content: "\e063"; -} -.glyphicon-tint:before { - content: "\e064"; -} -.glyphicon-edit:before { - content: "\e065"; -} -.glyphicon-share:before { - content: "\e066"; -} -.glyphicon-check:before { - content: "\e067"; -} -.glyphicon-move:before { - content: "\e068"; -} -.glyphicon-step-backward:before { - content: "\e069"; -} -.glyphicon-fast-backward:before { - content: "\e070"; -} -.glyphicon-backward:before { - content: "\e071"; -} -.glyphicon-play:before { - content: "\e072"; -} -.glyphicon-pause:before { - content: "\e073"; -} -.glyphicon-stop:before { - content: "\e074"; -} -.glyphicon-forward:before { - content: "\e075"; -} -.glyphicon-fast-forward:before { - content: "\e076"; -} -.glyphicon-step-forward:before { - content: "\e077"; -} -.glyphicon-eject:before { - content: "\e078"; -} -.glyphicon-chevron-left:before { - content: "\e079"; -} -.glyphicon-chevron-right:before { - content: "\e080"; -} -.glyphicon-plus-sign:before { - content: "\e081"; -} -.glyphicon-minus-sign:before { - content: "\e082"; -} -.glyphicon-remove-sign:before { - content: "\e083"; -} -.glyphicon-ok-sign:before { - content: "\e084"; -} -.glyphicon-question-sign:before { - content: "\e085"; -} -.glyphicon-info-sign:before { - content: "\e086"; -} -.glyphicon-screenshot:before { - content: "\e087"; -} -.glyphicon-remove-circle:before { - content: "\e088"; -} -.glyphicon-ok-circle:before { - content: "\e089"; -} -.glyphicon-ban-circle:before { - content: "\e090"; -} -.glyphicon-arrow-left:before { - content: "\e091"; -} -.glyphicon-arrow-right:before { - content: "\e092"; -} -.glyphicon-arrow-up:before { - content: "\e093"; -} -.glyphicon-arrow-down:before { - content: "\e094"; -} -.glyphicon-share-alt:before { - content: "\e095"; -} -.glyphicon-resize-full:before { - content: "\e096"; -} -.glyphicon-resize-small:before { - content: "\e097"; -} -.glyphicon-exclamation-sign:before { - content: "\e101"; -} -.glyphicon-gift:before { - content: "\e102"; -} -.glyphicon-leaf:before { - content: "\e103"; -} -.glyphicon-fire:before { - content: "\e104"; -} -.glyphicon-eye-open:before { - content: "\e105"; -} -.glyphicon-eye-close:before { - content: "\e106"; -} -.glyphicon-warning-sign:before { - content: "\e107"; -} -.glyphicon-plane:before { - content: "\e108"; -} -.glyphicon-calendar:before { - content: "\e109"; -} -.glyphicon-random:before { - content: "\e110"; -} -.glyphicon-comment:before { - content: "\e111"; -} -.glyphicon-magnet:before { - content: "\e112"; -} -.glyphicon-chevron-up:before { - content: "\e113"; -} -.glyphicon-chevron-down:before { - content: "\e114"; -} -.glyphicon-retweet:before { - content: "\e115"; -} -.glyphicon-shopping-cart:before { - content: "\e116"; -} -.glyphicon-folder-close:before { - content: "\e117"; -} -.glyphicon-folder-open:before { - content: "\e118"; -} -.glyphicon-resize-vertical:before { - content: "\e119"; -} -.glyphicon-resize-horizontal:before { - content: "\e120"; -} -.glyphicon-hdd:before { - content: "\e121"; -} -.glyphicon-bullhorn:before { - content: "\e122"; -} -.glyphicon-bell:before { - content: "\e123"; -} -.glyphicon-certificate:before { - content: "\e124"; -} -.glyphicon-thumbs-up:before { - content: "\e125"; -} -.glyphicon-thumbs-down:before { - content: "\e126"; -} -.glyphicon-hand-right:before { - content: "\e127"; -} -.glyphicon-hand-left:before { - content: "\e128"; -} -.glyphicon-hand-up:before { - content: "\e129"; -} -.glyphicon-hand-down:before { - content: "\e130"; -} -.glyphicon-circle-arrow-right:before { - content: "\e131"; -} -.glyphicon-circle-arrow-left:before { - content: "\e132"; -} -.glyphicon-circle-arrow-up:before { - content: "\e133"; -} -.glyphicon-circle-arrow-down:before { - content: "\e134"; -} -.glyphicon-globe:before { - content: "\e135"; -} -.glyphicon-wrench:before { - content: "\e136"; -} -.glyphicon-tasks:before { - content: "\e137"; -} -.glyphicon-filter:before { - content: "\e138"; -} -.glyphicon-briefcase:before { - content: "\e139"; -} -.glyphicon-fullscreen:before { - content: "\e140"; -} -.glyphicon-dashboard:before { - content: "\e141"; -} -.glyphicon-paperclip:before { - content: "\e142"; -} -.glyphicon-heart-empty:before { - content: "\e143"; -} -.glyphicon-link:before { - content: "\e144"; -} -.glyphicon-phone:before { - content: "\e145"; -} -.glyphicon-pushpin:before { - content: "\e146"; -} -.glyphicon-usd:before { - content: "\e148"; -} -.glyphicon-gbp:before { - content: "\e149"; -} -.glyphicon-sort:before { - content: "\e150"; -} -.glyphicon-sort-by-alphabet:before { - content: "\e151"; -} -.glyphicon-sort-by-alphabet-alt:before { - content: "\e152"; -} -.glyphicon-sort-by-order:before { - content: "\e153"; -} -.glyphicon-sort-by-order-alt:before { - content: "\e154"; -} -.glyphicon-sort-by-attributes:before { - content: "\e155"; -} -.glyphicon-sort-by-attributes-alt:before { - content: "\e156"; -} -.glyphicon-unchecked:before { - content: "\e157"; -} -.glyphicon-expand:before { - content: "\e158"; -} -.glyphicon-collapse-down:before { - content: "\e159"; -} -.glyphicon-collapse-up:before { - content: "\e160"; -} -.glyphicon-log-in:before { - content: "\e161"; -} -.glyphicon-flash:before { - content: "\e162"; -} -.glyphicon-log-out:before { - content: "\e163"; -} -.glyphicon-new-window:before { - content: "\e164"; -} -.glyphicon-record:before { - content: "\e165"; -} -.glyphicon-save:before { - content: "\e166"; -} -.glyphicon-open:before { - content: "\e167"; -} -.glyphicon-saved:before { - content: "\e168"; -} -.glyphicon-import:before { - content: "\e169"; -} -.glyphicon-export:before { - content: "\e170"; -} -.glyphicon-send:before { - content: "\e171"; -} -.glyphicon-floppy-disk:before { - content: "\e172"; -} -.glyphicon-floppy-saved:before { - content: "\e173"; -} -.glyphicon-floppy-remove:before { - content: "\e174"; -} -.glyphicon-floppy-save:before { - content: "\e175"; -} -.glyphicon-floppy-open:before { - content: "\e176"; -} -.glyphicon-credit-card:before { - content: "\e177"; -} -.glyphicon-transfer:before { - content: "\e178"; -} -.glyphicon-cutlery:before { - content: "\e179"; -} -.glyphicon-header:before { - content: "\e180"; -} -.glyphicon-compressed:before { - content: "\e181"; -} -.glyphicon-earphone:before { - content: "\e182"; -} -.glyphicon-phone-alt:before { - content: "\e183"; -} -.glyphicon-tower:before { - content: "\e184"; -} -.glyphicon-stats:before { - content: "\e185"; -} -.glyphicon-sd-video:before { - content: "\e186"; -} -.glyphicon-hd-video:before { - content: "\e187"; -} -.glyphicon-subtitles:before { - content: "\e188"; -} -.glyphicon-sound-stereo:before { - content: "\e189"; -} -.glyphicon-sound-dolby:before { - content: "\e190"; -} -.glyphicon-sound-5-1:before { - content: "\e191"; -} -.glyphicon-sound-6-1:before { - content: "\e192"; -} -.glyphicon-sound-7-1:before { - content: "\e193"; -} -.glyphicon-copyright-mark:before { - content: "\e194"; -} -.glyphicon-registration-mark:before { - content: "\e195"; -} -.glyphicon-cloud-download:before { - content: "\e197"; -} -.glyphicon-cloud-upload:before { - content: "\e198"; -} -.glyphicon-tree-conifer:before { - content: "\e199"; -} -.glyphicon-tree-deciduous:before { - content: "\e200"; -} -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -*:before, -*:after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -html { - font-size: 10px; - - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -} -body { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - line-height: 1.42857143; - color: #333; - background-color: #fff; -} -input, -button, -select, -textarea { - font-family: inherit; - font-size: inherit; - line-height: inherit; -} -a { - color: #428bca; - text-decoration: none; -} -a:hover, -a:focus { - color: #2a6496; - text-decoration: underline; -} -a:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -figure { - margin: 0; -} -img { - vertical-align: middle; -} -.img-responsive, -.thumbnail > img, -.thumbnail a > img, -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - display: block; - max-width: 100%; - height: auto; -} -.img-rounded { - border-radius: 6px; -} -.img-thumbnail { - display: inline-block; - max-width: 100%; - height: auto; - padding: 4px; - line-height: 1.42857143; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - -webkit-transition: all .2s ease-in-out; - -o-transition: all .2s ease-in-out; - transition: all .2s ease-in-out; -} -.img-circle { - border-radius: 50%; -} -hr { - margin-top: 20px; - margin-bottom: 20px; - border: 0; - border-top: 1px solid #eee; -} -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} -.sr-only-focusable:active, -.sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto; -} -h1, -h2, -h3, -h4, -h5, -h6, -.h1, -.h2, -.h3, -.h4, -.h5, -.h6 { - font-family: inherit; - font-weight: 500; - line-height: 1.1; - color: inherit; -} -h1 small, -h2 small, -h3 small, -h4 small, -h5 small, -h6 small, -.h1 small, -.h2 small, -.h3 small, -.h4 small, -.h5 small, -.h6 small, -h1 .small, -h2 .small, -h3 .small, -h4 .small, -h5 .small, -h6 .small, -.h1 .small, -.h2 .small, -.h3 .small, -.h4 .small, -.h5 .small, -.h6 .small { - font-weight: normal; - line-height: 1; - color: #777; -} -h1, -.h1, -h2, -.h2, -h3, -.h3 { - margin-top: 20px; - margin-bottom: 10px; -} -h1 small, -.h1 small, -h2 small, -.h2 small, -h3 small, -.h3 small, -h1 .small, -.h1 .small, -h2 .small, -.h2 .small, -h3 .small, -.h3 .small { - font-size: 65%; -} -h4, -.h4, -h5, -.h5, -h6, -.h6 { - margin-top: 10px; - margin-bottom: 10px; -} -h4 small, -.h4 small, -h5 small, -.h5 small, -h6 small, -.h6 small, -h4 .small, -.h4 .small, -h5 .small, -.h5 .small, -h6 .small, -.h6 .small { - font-size: 75%; -} -h1, -.h1 { - font-size: 36px; -} -h2, -.h2 { - font-size: 30px; -} -h3, -.h3 { - font-size: 24px; -} -h4, -.h4 { - font-size: 18px; -} -h5, -.h5 { - font-size: 14px; -} -h6, -.h6 { - font-size: 12px; -} -p { - margin: 0 0 10px; -} -.lead { - margin-bottom: 20px; - font-size: 16px; - font-weight: 300; - line-height: 1.4; -} -@media (min-width: 768px) { - .lead { - font-size: 21px; - } -} -small, -.small { - font-size: 85%; -} -mark, -.mark { - padding: .2em; - background-color: #fcf8e3; -} -.text-left { - text-align: left; -} -.text-right { - text-align: right; -} -.text-center { - text-align: center; -} -.text-justify { - text-align: justify; -} -.text-nowrap { - white-space: nowrap; -} -.text-lowercase { - text-transform: lowercase; -} -.text-uppercase { - text-transform: uppercase; -} -.text-capitalize { - text-transform: capitalize; -} -.text-muted { - color: #777; -} -.text-primary { - color: #428bca; -} -a.text-primary:hover { - color: #3071a9; -} -.text-success { - color: #3c763d; -} -a.text-success:hover { - color: #2b542c; -} -.text-info { - color: #31708f; -} -a.text-info:hover { - color: #245269; -} -.text-warning { - color: #8a6d3b; -} -a.text-warning:hover { - color: #66512c; -} -.text-danger { - color: #a94442; -} -a.text-danger:hover { - color: #843534; -} -.bg-primary { - color: #fff; - background-color: #428bca; -} -a.bg-primary:hover { - background-color: #3071a9; -} -.bg-success { - background-color: #dff0d8; -} -a.bg-success:hover { - background-color: #c1e2b3; -} -.bg-info { - background-color: #d9edf7; -} -a.bg-info:hover { - background-color: #afd9ee; -} -.bg-warning { - background-color: #fcf8e3; -} -a.bg-warning:hover { - background-color: #f7ecb5; -} -.bg-danger { - background-color: #f2dede; -} -a.bg-danger:hover { - background-color: #e4b9b9; -} -.page-header { - padding-bottom: 9px; - margin: 40px 0 20px; - border-bottom: 1px solid #eee; -} -ul, -ol { - margin-top: 0; - margin-bottom: 10px; -} -ul ul, -ol ul, -ul ol, -ol ol { - margin-bottom: 0; -} -.list-unstyled { - padding-left: 0; - list-style: none; -} -.list-inline { - padding-left: 0; - margin-left: -5px; - list-style: none; -} -.list-inline > li { - display: inline-block; - padding-right: 5px; - padding-left: 5px; -} -dl { - margin-top: 0; - margin-bottom: 20px; -} -dt, -dd { - line-height: 1.42857143; -} -dt { - font-weight: bold; -} -dd { - margin-left: 0; -} -@media (min-width: 768px) { - .dl-horizontal dt { - float: left; - width: 160px; - overflow: hidden; - clear: left; - text-align: right; - text-overflow: ellipsis; - white-space: nowrap; - } - .dl-horizontal dd { - margin-left: 180px; - } -} -abbr[title], -abbr[data-original-title] { - cursor: help; - border-bottom: 1px dotted #777; -} -.initialism { - font-size: 90%; - text-transform: uppercase; -} -blockquote { - padding: 10px 20px; - margin: 0 0 20px; - font-size: 17.5px; - border-left: 5px solid #eee; -} -blockquote p:last-child, -blockquote ul:last-child, -blockquote ol:last-child { - margin-bottom: 0; -} -blockquote footer, -blockquote small, -blockquote .small { - display: block; - font-size: 80%; - line-height: 1.42857143; - color: #777; -} -blockquote footer:before, -blockquote small:before, -blockquote .small:before { - content: '\2014 \00A0'; -} -.blockquote-reverse, -blockquote.pull-right { - padding-right: 15px; - padding-left: 0; - text-align: right; - border-right: 5px solid #eee; - border-left: 0; -} -.blockquote-reverse footer:before, -blockquote.pull-right footer:before, -.blockquote-reverse small:before, -blockquote.pull-right small:before, -.blockquote-reverse .small:before, -blockquote.pull-right .small:before { - content: ''; -} -.blockquote-reverse footer:after, -blockquote.pull-right footer:after, -.blockquote-reverse small:after, -blockquote.pull-right small:after, -.blockquote-reverse .small:after, -blockquote.pull-right .small:after { - content: '\00A0 \2014'; -} -address { - margin-bottom: 20px; - font-style: normal; - line-height: 1.42857143; -} -code, -kbd, -pre, -samp { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; -} -code { - padding: 2px 4px; - font-size: 90%; - color: #c7254e; - background-color: #f9f2f4; - border-radius: 4px; -} -kbd { - padding: 2px 4px; - font-size: 90%; - color: #fff; - background-color: #333; - border-radius: 3px; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); -} -kbd kbd { - padding: 0; - font-size: 100%; - font-weight: bold; - -webkit-box-shadow: none; - box-shadow: none; -} -pre { - display: block; - padding: 9.5px; - margin: 0 0 10px; - font-size: 13px; - line-height: 1.42857143; - color: #333; - word-break: break-all; - word-wrap: break-word; - background-color: #f5f5f5; - border: 1px solid #ccc; - border-radius: 4px; -} -pre code { - padding: 0; - font-size: inherit; - color: inherit; - white-space: pre-wrap; - background-color: transparent; - border-radius: 0; -} -.pre-scrollable { - max-height: 340px; - overflow-y: scroll; -} -.container { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} -@media (min-width: 768px) { - .container { - width: 750px; - } -} -@media (min-width: 992px) { - .container { - width: 970px; - } -} -@media (min-width: 1200px) { - .container { - width: 1170px; - } -} -.container-fluid { - padding-right: 15px; - padding-left: 15px; - margin-right: auto; - margin-left: auto; -} -.row { - margin-right: -15px; - margin-left: -15px; -} -.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { - position: relative; - min-height: 1px; - padding-right: 15px; - padding-left: 15px; -} -.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { - float: left; -} -.col-xs-12 { - width: 100%; -} -.col-xs-11 { - width: 91.66666667%; -} -.col-xs-10 { - width: 83.33333333%; -} -.col-xs-9 { - width: 75%; -} -.col-xs-8 { - width: 66.66666667%; -} -.col-xs-7 { - width: 58.33333333%; -} -.col-xs-6 { - width: 50%; -} -.col-xs-5 { - width: 41.66666667%; -} -.col-xs-4 { - width: 33.33333333%; -} -.col-xs-3 { - width: 25%; -} -.col-xs-2 { - width: 16.66666667%; -} -.col-xs-1 { - width: 8.33333333%; -} -.col-xs-pull-12 { - right: 100%; -} -.col-xs-pull-11 { - right: 91.66666667%; -} -.col-xs-pull-10 { - right: 83.33333333%; -} -.col-xs-pull-9 { - right: 75%; -} -.col-xs-pull-8 { - right: 66.66666667%; -} -.col-xs-pull-7 { - right: 58.33333333%; -} -.col-xs-pull-6 { - right: 50%; -} -.col-xs-pull-5 { - right: 41.66666667%; -} -.col-xs-pull-4 { - right: 33.33333333%; -} -.col-xs-pull-3 { - right: 25%; -} -.col-xs-pull-2 { - right: 16.66666667%; -} -.col-xs-pull-1 { - right: 8.33333333%; -} -.col-xs-pull-0 { - right: auto; -} -.col-xs-push-12 { - left: 100%; -} -.col-xs-push-11 { - left: 91.66666667%; -} -.col-xs-push-10 { - left: 83.33333333%; -} -.col-xs-push-9 { - left: 75%; -} -.col-xs-push-8 { - left: 66.66666667%; -} -.col-xs-push-7 { - left: 58.33333333%; -} -.col-xs-push-6 { - left: 50%; -} -.col-xs-push-5 { - left: 41.66666667%; -} -.col-xs-push-4 { - left: 33.33333333%; -} -.col-xs-push-3 { - left: 25%; -} -.col-xs-push-2 { - left: 16.66666667%; -} -.col-xs-push-1 { - left: 8.33333333%; -} -.col-xs-push-0 { - left: auto; -} -.col-xs-offset-12 { - margin-left: 100%; -} -.col-xs-offset-11 { - margin-left: 91.66666667%; -} -.col-xs-offset-10 { - margin-left: 83.33333333%; -} -.col-xs-offset-9 { - margin-left: 75%; -} -.col-xs-offset-8 { - margin-left: 66.66666667%; -} -.col-xs-offset-7 { - margin-left: 58.33333333%; -} -.col-xs-offset-6 { - margin-left: 50%; -} -.col-xs-offset-5 { - margin-left: 41.66666667%; -} -.col-xs-offset-4 { - margin-left: 33.33333333%; -} -.col-xs-offset-3 { - margin-left: 25%; -} -.col-xs-offset-2 { - margin-left: 16.66666667%; -} -.col-xs-offset-1 { - margin-left: 8.33333333%; -} -.col-xs-offset-0 { - margin-left: 0; -} -@media (min-width: 768px) { - .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { - float: left; - } - .col-sm-12 { - width: 100%; - } - .col-sm-11 { - width: 91.66666667%; - } - .col-sm-10 { - width: 83.33333333%; - } - .col-sm-9 { - width: 75%; - } - .col-sm-8 { - width: 66.66666667%; - } - .col-sm-7 { - width: 58.33333333%; - } - .col-sm-6 { - width: 50%; - } - .col-sm-5 { - width: 41.66666667%; - } - .col-sm-4 { - width: 33.33333333%; - } - .col-sm-3 { - width: 25%; - } - .col-sm-2 { - width: 16.66666667%; - } - .col-sm-1 { - width: 8.33333333%; - } - .col-sm-pull-12 { - right: 100%; - } - .col-sm-pull-11 { - right: 91.66666667%; - } - .col-sm-pull-10 { - right: 83.33333333%; - } - .col-sm-pull-9 { - right: 75%; - } - .col-sm-pull-8 { - right: 66.66666667%; - } - .col-sm-pull-7 { - right: 58.33333333%; - } - .col-sm-pull-6 { - right: 50%; - } - .col-sm-pull-5 { - right: 41.66666667%; - } - .col-sm-pull-4 { - right: 33.33333333%; - } - .col-sm-pull-3 { - right: 25%; - } - .col-sm-pull-2 { - right: 16.66666667%; - } - .col-sm-pull-1 { - right: 8.33333333%; - } - .col-sm-pull-0 { - right: auto; - } - .col-sm-push-12 { - left: 100%; - } - .col-sm-push-11 { - left: 91.66666667%; - } - .col-sm-push-10 { - left: 83.33333333%; - } - .col-sm-push-9 { - left: 75%; - } - .col-sm-push-8 { - left: 66.66666667%; - } - .col-sm-push-7 { - left: 58.33333333%; - } - .col-sm-push-6 { - left: 50%; - } - .col-sm-push-5 { - left: 41.66666667%; - } - .col-sm-push-4 { - left: 33.33333333%; - } - .col-sm-push-3 { - left: 25%; - } - .col-sm-push-2 { - left: 16.66666667%; - } - .col-sm-push-1 { - left: 8.33333333%; - } - .col-sm-push-0 { - left: auto; - } - .col-sm-offset-12 { - margin-left: 100%; - } - .col-sm-offset-11 { - margin-left: 91.66666667%; - } - .col-sm-offset-10 { - margin-left: 83.33333333%; - } - .col-sm-offset-9 { - margin-left: 75%; - } - .col-sm-offset-8 { - margin-left: 66.66666667%; - } - .col-sm-offset-7 { - margin-left: 58.33333333%; - } - .col-sm-offset-6 { - margin-left: 50%; - } - .col-sm-offset-5 { - margin-left: 41.66666667%; - } - .col-sm-offset-4 { - margin-left: 33.33333333%; - } - .col-sm-offset-3 { - margin-left: 25%; - } - .col-sm-offset-2 { - margin-left: 16.66666667%; - } - .col-sm-offset-1 { - margin-left: 8.33333333%; - } - .col-sm-offset-0 { - margin-left: 0; - } -} -@media (min-width: 992px) { - .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { - float: left; - } - .col-md-12 { - width: 100%; - } - .col-md-11 { - width: 91.66666667%; - } - .col-md-10 { - width: 83.33333333%; - } - .col-md-9 { - width: 75%; - } - .col-md-8 { - width: 66.66666667%; - } - .col-md-7 { - width: 58.33333333%; - } - .col-md-6 { - width: 50%; - } - .col-md-5 { - width: 41.66666667%; - } - .col-md-4 { - width: 33.33333333%; - } - .col-md-3 { - width: 25%; - } - .col-md-2 { - width: 16.66666667%; - } - .col-md-1 { - width: 8.33333333%; - } - .col-md-pull-12 { - right: 100%; - } - .col-md-pull-11 { - right: 91.66666667%; - } - .col-md-pull-10 { - right: 83.33333333%; - } - .col-md-pull-9 { - right: 75%; - } - .col-md-pull-8 { - right: 66.66666667%; - } - .col-md-pull-7 { - right: 58.33333333%; - } - .col-md-pull-6 { - right: 50%; - } - .col-md-pull-5 { - right: 41.66666667%; - } - .col-md-pull-4 { - right: 33.33333333%; - } - .col-md-pull-3 { - right: 25%; - } - .col-md-pull-2 { - right: 16.66666667%; - } - .col-md-pull-1 { - right: 8.33333333%; - } - .col-md-pull-0 { - right: auto; - } - .col-md-push-12 { - left: 100%; - } - .col-md-push-11 { - left: 91.66666667%; - } - .col-md-push-10 { - left: 83.33333333%; - } - .col-md-push-9 { - left: 75%; - } - .col-md-push-8 { - left: 66.66666667%; - } - .col-md-push-7 { - left: 58.33333333%; - } - .col-md-push-6 { - left: 50%; - } - .col-md-push-5 { - left: 41.66666667%; - } - .col-md-push-4 { - left: 33.33333333%; - } - .col-md-push-3 { - left: 25%; - } - .col-md-push-2 { - left: 16.66666667%; - } - .col-md-push-1 { - left: 8.33333333%; - } - .col-md-push-0 { - left: auto; - } - .col-md-offset-12 { - margin-left: 100%; - } - .col-md-offset-11 { - margin-left: 91.66666667%; - } - .col-md-offset-10 { - margin-left: 83.33333333%; - } - .col-md-offset-9 { - margin-left: 75%; - } - .col-md-offset-8 { - margin-left: 66.66666667%; - } - .col-md-offset-7 { - margin-left: 58.33333333%; - } - .col-md-offset-6 { - margin-left: 50%; - } - .col-md-offset-5 { - margin-left: 41.66666667%; - } - .col-md-offset-4 { - margin-left: 33.33333333%; - } - .col-md-offset-3 { - margin-left: 25%; - } - .col-md-offset-2 { - margin-left: 16.66666667%; - } - .col-md-offset-1 { - margin-left: 8.33333333%; - } - .col-md-offset-0 { - margin-left: 0; - } -} -@media (min-width: 1200px) { - .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { - float: left; - } - .col-lg-12 { - width: 100%; - } - .col-lg-11 { - width: 91.66666667%; - } - .col-lg-10 { - width: 83.33333333%; - } - .col-lg-9 { - width: 75%; - } - .col-lg-8 { - width: 66.66666667%; - } - .col-lg-7 { - width: 58.33333333%; - } - .col-lg-6 { - width: 50%; - } - .col-lg-5 { - width: 41.66666667%; - } - .col-lg-4 { - width: 33.33333333%; - } - .col-lg-3 { - width: 25%; - } - .col-lg-2 { - width: 16.66666667%; - } - .col-lg-1 { - width: 8.33333333%; - } - .col-lg-pull-12 { - right: 100%; - } - .col-lg-pull-11 { - right: 91.66666667%; - } - .col-lg-pull-10 { - right: 83.33333333%; - } - .col-lg-pull-9 { - right: 75%; - } - .col-lg-pull-8 { - right: 66.66666667%; - } - .col-lg-pull-7 { - right: 58.33333333%; - } - .col-lg-pull-6 { - right: 50%; - } - .col-lg-pull-5 { - right: 41.66666667%; - } - .col-lg-pull-4 { - right: 33.33333333%; - } - .col-lg-pull-3 { - right: 25%; - } - .col-lg-pull-2 { - right: 16.66666667%; - } - .col-lg-pull-1 { - right: 8.33333333%; - } - .col-lg-pull-0 { - right: auto; - } - .col-lg-push-12 { - left: 100%; - } - .col-lg-push-11 { - left: 91.66666667%; - } - .col-lg-push-10 { - left: 83.33333333%; - } - .col-lg-push-9 { - left: 75%; - } - .col-lg-push-8 { - left: 66.66666667%; - } - .col-lg-push-7 { - left: 58.33333333%; - } - .col-lg-push-6 { - left: 50%; - } - .col-lg-push-5 { - left: 41.66666667%; - } - .col-lg-push-4 { - left: 33.33333333%; - } - .col-lg-push-3 { - left: 25%; - } - .col-lg-push-2 { - left: 16.66666667%; - } - .col-lg-push-1 { - left: 8.33333333%; - } - .col-lg-push-0 { - left: auto; - } - .col-lg-offset-12 { - margin-left: 100%; - } - .col-lg-offset-11 { - margin-left: 91.66666667%; - } - .col-lg-offset-10 { - margin-left: 83.33333333%; - } - .col-lg-offset-9 { - margin-left: 75%; - } - .col-lg-offset-8 { - margin-left: 66.66666667%; - } - .col-lg-offset-7 { - margin-left: 58.33333333%; - } - .col-lg-offset-6 { - margin-left: 50%; - } - .col-lg-offset-5 { - margin-left: 41.66666667%; - } - .col-lg-offset-4 { - margin-left: 33.33333333%; - } - .col-lg-offset-3 { - margin-left: 25%; - } - .col-lg-offset-2 { - margin-left: 16.66666667%; - } - .col-lg-offset-1 { - margin-left: 8.33333333%; - } - .col-lg-offset-0 { - margin-left: 0; - } -} -table { - background-color: transparent; -} -caption { - padding-top: 8px; - padding-bottom: 8px; - color: #777; - text-align: left; -} -th { - text-align: left; -} -.table { - width: 100%; - max-width: 100%; - margin-bottom: 20px; -} -.table > thead > tr > th, -.table > tbody > tr > th, -.table > tfoot > tr > th, -.table > thead > tr > td, -.table > tbody > tr > td, -.table > tfoot > tr > td { - padding: 8px; - line-height: 1.42857143; - vertical-align: top; - border-top: 1px solid #ddd; -} -.table > thead > tr > th { - vertical-align: bottom; - border-bottom: 2px solid #ddd; -} -.table > caption + thead > tr:first-child > th, -.table > colgroup + thead > tr:first-child > th, -.table > thead:first-child > tr:first-child > th, -.table > caption + thead > tr:first-child > td, -.table > colgroup + thead > tr:first-child > td, -.table > thead:first-child > tr:first-child > td { - border-top: 0; -} -.table > tbody + tbody { - border-top: 2px solid #ddd; -} -.table .table { - background-color: #fff; -} -.table-condensed > thead > tr > th, -.table-condensed > tbody > tr > th, -.table-condensed > tfoot > tr > th, -.table-condensed > thead > tr > td, -.table-condensed > tbody > tr > td, -.table-condensed > tfoot > tr > td { - padding: 5px; -} -.table-bordered { - border: 1px solid #ddd; -} -.table-bordered > thead > tr > th, -.table-bordered > tbody > tr > th, -.table-bordered > tfoot > tr > th, -.table-bordered > thead > tr > td, -.table-bordered > tbody > tr > td, -.table-bordered > tfoot > tr > td { - border: 1px solid #ddd; -} -.table-bordered > thead > tr > th, -.table-bordered > thead > tr > td { - border-bottom-width: 2px; -} -.table-striped > tbody > tr:nth-child(odd) { - background-color: #f9f9f9; -} -.table-hover > tbody > tr:hover { - background-color: #f5f5f5; -} -table col[class*="col-"] { - position: static; - display: table-column; - float: none; -} -table td[class*="col-"], -table th[class*="col-"] { - position: static; - display: table-cell; - float: none; -} -.table > thead > tr > td.active, -.table > tbody > tr > td.active, -.table > tfoot > tr > td.active, -.table > thead > tr > th.active, -.table > tbody > tr > th.active, -.table > tfoot > tr > th.active, -.table > thead > tr.active > td, -.table > tbody > tr.active > td, -.table > tfoot > tr.active > td, -.table > thead > tr.active > th, -.table > tbody > tr.active > th, -.table > tfoot > tr.active > th { - background-color: #f5f5f5; -} -.table-hover > tbody > tr > td.active:hover, -.table-hover > tbody > tr > th.active:hover, -.table-hover > tbody > tr.active:hover > td, -.table-hover > tbody > tr:hover > .active, -.table-hover > tbody > tr.active:hover > th { - background-color: #e8e8e8; -} -.table > thead > tr > td.success, -.table > tbody > tr > td.success, -.table > tfoot > tr > td.success, -.table > thead > tr > th.success, -.table > tbody > tr > th.success, -.table > tfoot > tr > th.success, -.table > thead > tr.success > td, -.table > tbody > tr.success > td, -.table > tfoot > tr.success > td, -.table > thead > tr.success > th, -.table > tbody > tr.success > th, -.table > tfoot > tr.success > th { - background-color: #dff0d8; -} -.table-hover > tbody > tr > td.success:hover, -.table-hover > tbody > tr > th.success:hover, -.table-hover > tbody > tr.success:hover > td, -.table-hover > tbody > tr:hover > .success, -.table-hover > tbody > tr.success:hover > th { - background-color: #d0e9c6; -} -.table > thead > tr > td.info, -.table > tbody > tr > td.info, -.table > tfoot > tr > td.info, -.table > thead > tr > th.info, -.table > tbody > tr > th.info, -.table > tfoot > tr > th.info, -.table > thead > tr.info > td, -.table > tbody > tr.info > td, -.table > tfoot > tr.info > td, -.table > thead > tr.info > th, -.table > tbody > tr.info > th, -.table > tfoot > tr.info > th { - background-color: #d9edf7; -} -.table-hover > tbody > tr > td.info:hover, -.table-hover > tbody > tr > th.info:hover, -.table-hover > tbody > tr.info:hover > td, -.table-hover > tbody > tr:hover > .info, -.table-hover > tbody > tr.info:hover > th { - background-color: #c4e3f3; -} -.table > thead > tr > td.warning, -.table > tbody > tr > td.warning, -.table > tfoot > tr > td.warning, -.table > thead > tr > th.warning, -.table > tbody > tr > th.warning, -.table > tfoot > tr > th.warning, -.table > thead > tr.warning > td, -.table > tbody > tr.warning > td, -.table > tfoot > tr.warning > td, -.table > thead > tr.warning > th, -.table > tbody > tr.warning > th, -.table > tfoot > tr.warning > th { - background-color: #fcf8e3; -} -.table-hover > tbody > tr > td.warning:hover, -.table-hover > tbody > tr > th.warning:hover, -.table-hover > tbody > tr.warning:hover > td, -.table-hover > tbody > tr:hover > .warning, -.table-hover > tbody > tr.warning:hover > th { - background-color: #faf2cc; -} -.table > thead > tr > td.danger, -.table > tbody > tr > td.danger, -.table > tfoot > tr > td.danger, -.table > thead > tr > th.danger, -.table > tbody > tr > th.danger, -.table > tfoot > tr > th.danger, -.table > thead > tr.danger > td, -.table > tbody > tr.danger > td, -.table > tfoot > tr.danger > td, -.table > thead > tr.danger > th, -.table > tbody > tr.danger > th, -.table > tfoot > tr.danger > th { - background-color: #f2dede; -} -.table-hover > tbody > tr > td.danger:hover, -.table-hover > tbody > tr > th.danger:hover, -.table-hover > tbody > tr.danger:hover > td, -.table-hover > tbody > tr:hover > .danger, -.table-hover > tbody > tr.danger:hover > th { - background-color: #ebcccc; -} -.table-responsive { - min-height: .01%; - overflow-x: auto; -} -@media screen and (max-width: 767px) { - .table-responsive { - width: 100%; - margin-bottom: 15px; - overflow-y: hidden; - -ms-overflow-style: -ms-autohiding-scrollbar; - border: 1px solid #ddd; - } - .table-responsive > .table { - margin-bottom: 0; - } - .table-responsive > .table > thead > tr > th, - .table-responsive > .table > tbody > tr > th, - .table-responsive > .table > tfoot > tr > th, - .table-responsive > .table > thead > tr > td, - .table-responsive > .table > tbody > tr > td, - .table-responsive > .table > tfoot > tr > td { - white-space: nowrap; - } - .table-responsive > .table-bordered { - border: 0; - } - .table-responsive > .table-bordered > thead > tr > th:first-child, - .table-responsive > .table-bordered > tbody > tr > th:first-child, - .table-responsive > .table-bordered > tfoot > tr > th:first-child, - .table-responsive > .table-bordered > thead > tr > td:first-child, - .table-responsive > .table-bordered > tbody > tr > td:first-child, - .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; - } - .table-responsive > .table-bordered > thead > tr > th:last-child, - .table-responsive > .table-bordered > tbody > tr > th:last-child, - .table-responsive > .table-bordered > tfoot > tr > th:last-child, - .table-responsive > .table-bordered > thead > tr > td:last-child, - .table-responsive > .table-bordered > tbody > tr > td:last-child, - .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; - } - .table-responsive > .table-bordered > tbody > tr:last-child > th, - .table-responsive > .table-bordered > tfoot > tr:last-child > th, - .table-responsive > .table-bordered > tbody > tr:last-child > td, - .table-responsive > .table-bordered > tfoot > tr:last-child > td { - border-bottom: 0; - } -} -fieldset { - min-width: 0; - padding: 0; - margin: 0; - border: 0; -} -legend { - display: block; - width: 100%; - padding: 0; - margin-bottom: 20px; - font-size: 21px; - line-height: inherit; - color: #333; - border: 0; - border-bottom: 1px solid #e5e5e5; -} -label { - display: inline-block; - max-width: 100%; - margin-bottom: 5px; - font-weight: bold; -} -input[type="search"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -input[type="radio"], -input[type="checkbox"] { - margin: 4px 0 0; - margin-top: 1px \9; - line-height: normal; -} -input[type="file"] { - display: block; -} -input[type="range"] { - display: block; - width: 100%; -} -select[multiple], -select[size] { - height: auto; -} -input[type="file"]:focus, -input[type="radio"]:focus, -input[type="checkbox"]:focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -output { - display: block; - padding-top: 7px; - font-size: 14px; - line-height: 1.42857143; - color: #555; -} -.form-control { - display: block; - width: 100%; - height: 34px; - padding: 6px 12px; - font-size: 14px; - line-height: 1.42857143; - color: #555; - background-color: #fff; - background-image: none; - border: 1px solid #ccc; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; - -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; - transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; -} -.form-control:focus { - border-color: #66afe9; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6); -} -.form-control::-moz-placeholder { - color: #999; - opacity: 1; -} -.form-control:-ms-input-placeholder { - color: #999; -} -.form-control::-webkit-input-placeholder { - color: #999; -} -.form-control[disabled], -.form-control[readonly], -fieldset[disabled] .form-control { - cursor: not-allowed; - background-color: #eee; - opacity: 1; -} -textarea.form-control { - height: auto; -} -input[type="search"] { - -webkit-appearance: none; -} -input[type="date"], -input[type="time"], -input[type="datetime-local"], -input[type="month"] { - line-height: 34px; - line-height: 1.42857143 \0; -} -input[type="date"].input-sm, -input[type="time"].input-sm, -input[type="datetime-local"].input-sm, -input[type="month"].input-sm { - line-height: 30px; - line-height: 1.5 \0; -} -input[type="date"].input-lg, -input[type="time"].input-lg, -input[type="datetime-local"].input-lg, -input[type="month"].input-lg { - line-height: 46px; - line-height: 1.33 \0; -} -_:-ms-fullscreen, -:root input[type="date"], -_:-ms-fullscreen, -:root input[type="time"], -_:-ms-fullscreen, -:root input[type="datetime-local"], -_:-ms-fullscreen, -:root input[type="month"] { - line-height: 1.42857143; -} -_:-ms-fullscreen.input-sm, -:root input[type="date"].input-sm, -_:-ms-fullscreen.input-sm, -:root input[type="time"].input-sm, -_:-ms-fullscreen.input-sm, -:root input[type="datetime-local"].input-sm, -_:-ms-fullscreen.input-sm, -:root input[type="month"].input-sm { - line-height: 1.5; -} -_:-ms-fullscreen.input-lg, -:root input[type="date"].input-lg, -_:-ms-fullscreen.input-lg, -:root input[type="time"].input-lg, -_:-ms-fullscreen.input-lg, -:root input[type="datetime-local"].input-lg, -_:-ms-fullscreen.input-lg, -:root input[type="month"].input-lg { - line-height: 1.33; -} -.form-group { - margin-bottom: 15px; -} -.radio, -.checkbox { - position: relative; - display: block; - margin-top: 10px; - margin-bottom: 10px; -} -.radio label, -.checkbox label { - min-height: 20px; - padding-left: 20px; - margin-bottom: 0; - font-weight: normal; - cursor: pointer; -} -.radio input[type="radio"], -.radio-inline input[type="radio"], -.checkbox input[type="checkbox"], -.checkbox-inline input[type="checkbox"] { - position: absolute; - margin-top: 4px \9; - margin-left: -20px; -} -.radio + .radio, -.checkbox + .checkbox { - margin-top: -5px; -} -.radio-inline, -.checkbox-inline { - display: inline-block; - padding-left: 20px; - margin-bottom: 0; - font-weight: normal; - vertical-align: middle; - cursor: pointer; -} -.radio-inline + .radio-inline, -.checkbox-inline + .checkbox-inline { - margin-top: 0; - margin-left: 10px; -} -input[type="radio"][disabled], -input[type="checkbox"][disabled], -input[type="radio"].disabled, -input[type="checkbox"].disabled, -fieldset[disabled] input[type="radio"], -fieldset[disabled] input[type="checkbox"] { - cursor: not-allowed; -} -.radio-inline.disabled, -.checkbox-inline.disabled, -fieldset[disabled] .radio-inline, -fieldset[disabled] .checkbox-inline { - cursor: not-allowed; -} -.radio.disabled label, -.checkbox.disabled label, -fieldset[disabled] .radio label, -fieldset[disabled] .checkbox label { - cursor: not-allowed; -} -.form-control-static { - padding-top: 7px; - padding-bottom: 7px; - margin-bottom: 0; -} -.form-control-static.input-lg, -.form-control-static.input-sm { - padding-right: 0; - padding-left: 0; -} -.input-sm, -.form-group-sm .form-control { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -select.input-sm, -select.form-group-sm .form-control { - height: 30px; - line-height: 30px; -} -textarea.input-sm, -textarea.form-group-sm .form-control, -select[multiple].input-sm, -select[multiple].form-group-sm .form-control { - height: auto; -} -.input-lg, -.form-group-lg .form-control { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} -select.input-lg, -select.form-group-lg .form-control { - height: 46px; - line-height: 46px; -} -textarea.input-lg, -textarea.form-group-lg .form-control, -select[multiple].input-lg, -select[multiple].form-group-lg .form-control { - height: auto; -} -.has-feedback { - position: relative; -} -.has-feedback .form-control { - padding-right: 42.5px; -} -.form-control-feedback { - position: absolute; - top: 0; - right: 0; - z-index: 2; - display: block; - width: 34px; - height: 34px; - line-height: 34px; - text-align: center; - pointer-events: none; -} -.input-lg + .form-control-feedback { - width: 46px; - height: 46px; - line-height: 46px; -} -.input-sm + .form-control-feedback { - width: 30px; - height: 30px; - line-height: 30px; -} -.has-success .help-block, -.has-success .control-label, -.has-success .radio, -.has-success .checkbox, -.has-success .radio-inline, -.has-success .checkbox-inline, -.has-success.radio label, -.has-success.checkbox label, -.has-success.radio-inline label, -.has-success.checkbox-inline label { - color: #3c763d; -} -.has-success .form-control { - border-color: #3c763d; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -} -.has-success .form-control:focus { - border-color: #2b542c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; -} -.has-success .input-group-addon { - color: #3c763d; - background-color: #dff0d8; - border-color: #3c763d; -} -.has-success .form-control-feedback { - color: #3c763d; -} -.has-warning .help-block, -.has-warning .control-label, -.has-warning .radio, -.has-warning .checkbox, -.has-warning .radio-inline, -.has-warning .checkbox-inline, -.has-warning.radio label, -.has-warning.checkbox label, -.has-warning.radio-inline label, -.has-warning.checkbox-inline label { - color: #8a6d3b; -} -.has-warning .form-control { - border-color: #8a6d3b; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -} -.has-warning .form-control:focus { - border-color: #66512c; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; -} -.has-warning .input-group-addon { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #8a6d3b; -} -.has-warning .form-control-feedback { - color: #8a6d3b; -} -.has-error .help-block, -.has-error .control-label, -.has-error .radio, -.has-error .checkbox, -.has-error .radio-inline, -.has-error .checkbox-inline, -.has-error.radio label, -.has-error.checkbox label, -.has-error.radio-inline label, -.has-error.checkbox-inline label { - color: #a94442; -} -.has-error .form-control { - border-color: #a94442; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -} -.has-error .form-control:focus { - border-color: #843534; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; -} -.has-error .input-group-addon { - color: #a94442; - background-color: #f2dede; - border-color: #a94442; -} -.has-error .form-control-feedback { - color: #a94442; -} -.has-feedback label ~ .form-control-feedback { - top: 25px; -} -.has-feedback label.sr-only ~ .form-control-feedback { - top: 0; -} -.help-block { - display: block; - margin-top: 5px; - margin-bottom: 10px; - color: #737373; -} -@media (min-width: 768px) { - .form-inline .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .form-inline .form-control-static { - display: inline-block; - } - .form-inline .input-group { - display: inline-table; - vertical-align: middle; - } - .form-inline .input-group .input-group-addon, - .form-inline .input-group .input-group-btn, - .form-inline .input-group .form-control { - width: auto; - } - .form-inline .input-group > .form-control { - width: 100%; - } - .form-inline .control-label { - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .radio, - .form-inline .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle; - } - .form-inline .radio label, - .form-inline .checkbox label { - padding-left: 0; - } - .form-inline .radio input[type="radio"], - .form-inline .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0; - } - .form-inline .has-feedback .form-control-feedback { - top: 0; - } -} -.form-horizontal .radio, -.form-horizontal .checkbox, -.form-horizontal .radio-inline, -.form-horizontal .checkbox-inline { - padding-top: 7px; - margin-top: 0; - margin-bottom: 0; -} -.form-horizontal .radio, -.form-horizontal .checkbox { - min-height: 27px; -} -.form-horizontal .form-group { - margin-right: -15px; - margin-left: -15px; -} -@media (min-width: 768px) { - .form-horizontal .control-label { - padding-top: 7px; - margin-bottom: 0; - text-align: right; - } -} -.form-horizontal .has-feedback .form-control-feedback { - right: 15px; -} -@media (min-width: 768px) { - .form-horizontal .form-group-lg .control-label { - padding-top: 14.3px; - } -} -@media (min-width: 768px) { - .form-horizontal .form-group-sm .control-label { - padding-top: 6px; - } -} -.btn { - display: inline-block; - padding: 6px 12px; - margin-bottom: 0; - font-size: 14px; - font-weight: normal; - line-height: 1.42857143; - text-align: center; - white-space: nowrap; - vertical-align: middle; - -ms-touch-action: manipulation; - touch-action: manipulation; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-image: none; - border: 1px solid transparent; - border-radius: 4px; -} -.btn:focus, -.btn:active:focus, -.btn.active:focus, -.btn.focus, -.btn:active.focus, -.btn.active.focus { - outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} -.btn:hover, -.btn:focus, -.btn.focus { - color: #333; - text-decoration: none; -} -.btn:active, -.btn.active { - background-image: none; - outline: 0; - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); -} -.btn.disabled, -.btn[disabled], -fieldset[disabled] .btn { - pointer-events: none; - cursor: not-allowed; - filter: alpha(opacity=65); - -webkit-box-shadow: none; - box-shadow: none; - opacity: .65; -} -.btn-default { - color: #333; - background-color: #fff; - border-color: #ccc; -} -.btn-default:hover, -.btn-default:focus, -.btn-default.focus, -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - color: #333; - background-color: #e6e6e6; - border-color: #adadad; -} -.btn-default:active, -.btn-default.active, -.open > .dropdown-toggle.btn-default { - background-image: none; -} -.btn-default.disabled, -.btn-default[disabled], -fieldset[disabled] .btn-default, -.btn-default.disabled:hover, -.btn-default[disabled]:hover, -fieldset[disabled] .btn-default:hover, -.btn-default.disabled:focus, -.btn-default[disabled]:focus, -fieldset[disabled] .btn-default:focus, -.btn-default.disabled.focus, -.btn-default[disabled].focus, -fieldset[disabled] .btn-default.focus, -.btn-default.disabled:active, -.btn-default[disabled]:active, -fieldset[disabled] .btn-default:active, -.btn-default.disabled.active, -.btn-default[disabled].active, -fieldset[disabled] .btn-default.active { - background-color: #fff; - border-color: #ccc; -} -.btn-default .badge { - color: #fff; - background-color: #333; -} -.btn-primary { - color: #fff; - background-color: #428bca; - border-color: #357ebd; -} -.btn-primary:hover, -.btn-primary:focus, -.btn-primary.focus, -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - color: #fff; - background-color: #3071a9; - border-color: #285e8e; -} -.btn-primary:active, -.btn-primary.active, -.open > .dropdown-toggle.btn-primary { - background-image: none; -} -.btn-primary.disabled, -.btn-primary[disabled], -fieldset[disabled] .btn-primary, -.btn-primary.disabled:hover, -.btn-primary[disabled]:hover, -fieldset[disabled] .btn-primary:hover, -.btn-primary.disabled:focus, -.btn-primary[disabled]:focus, -fieldset[disabled] .btn-primary:focus, -.btn-primary.disabled.focus, -.btn-primary[disabled].focus, -fieldset[disabled] .btn-primary.focus, -.btn-primary.disabled:active, -.btn-primary[disabled]:active, -fieldset[disabled] .btn-primary:active, -.btn-primary.disabled.active, -.btn-primary[disabled].active, -fieldset[disabled] .btn-primary.active { - background-color: #428bca; - border-color: #357ebd; -} -.btn-primary .badge { - color: #428bca; - background-color: #fff; -} -.btn-success { - color: #fff; - background-color: #5cb85c; - border-color: #4cae4c; -} -.btn-success:hover, -.btn-success:focus, -.btn-success.focus, -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - color: #fff; - background-color: #449d44; - border-color: #398439; -} -.btn-success:active, -.btn-success.active, -.open > .dropdown-toggle.btn-success { - background-image: none; -} -.btn-success.disabled, -.btn-success[disabled], -fieldset[disabled] .btn-success, -.btn-success.disabled:hover, -.btn-success[disabled]:hover, -fieldset[disabled] .btn-success:hover, -.btn-success.disabled:focus, -.btn-success[disabled]:focus, -fieldset[disabled] .btn-success:focus, -.btn-success.disabled.focus, -.btn-success[disabled].focus, -fieldset[disabled] .btn-success.focus, -.btn-success.disabled:active, -.btn-success[disabled]:active, -fieldset[disabled] .btn-success:active, -.btn-success.disabled.active, -.btn-success[disabled].active, -fieldset[disabled] .btn-success.active { - background-color: #5cb85c; - border-color: #4cae4c; -} -.btn-success .badge { - color: #5cb85c; - background-color: #fff; -} -.btn-info { - color: #fff; - background-color: #5bc0de; - border-color: #46b8da; -} -.btn-info:hover, -.btn-info:focus, -.btn-info.focus, -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - color: #fff; - background-color: #31b0d5; - border-color: #269abc; -} -.btn-info:active, -.btn-info.active, -.open > .dropdown-toggle.btn-info { - background-image: none; -} -.btn-info.disabled, -.btn-info[disabled], -fieldset[disabled] .btn-info, -.btn-info.disabled:hover, -.btn-info[disabled]:hover, -fieldset[disabled] .btn-info:hover, -.btn-info.disabled:focus, -.btn-info[disabled]:focus, -fieldset[disabled] .btn-info:focus, -.btn-info.disabled.focus, -.btn-info[disabled].focus, -fieldset[disabled] .btn-info.focus, -.btn-info.disabled:active, -.btn-info[disabled]:active, -fieldset[disabled] .btn-info:active, -.btn-info.disabled.active, -.btn-info[disabled].active, -fieldset[disabled] .btn-info.active { - background-color: #5bc0de; - border-color: #46b8da; -} -.btn-info .badge { - color: #5bc0de; - background-color: #fff; -} -.btn-warning { - color: #fff; - background-color: #f0ad4e; - border-color: #eea236; -} -.btn-warning:hover, -.btn-warning:focus, -.btn-warning.focus, -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - color: #fff; - background-color: #ec971f; - border-color: #d58512; -} -.btn-warning:active, -.btn-warning.active, -.open > .dropdown-toggle.btn-warning { - background-image: none; -} -.btn-warning.disabled, -.btn-warning[disabled], -fieldset[disabled] .btn-warning, -.btn-warning.disabled:hover, -.btn-warning[disabled]:hover, -fieldset[disabled] .btn-warning:hover, -.btn-warning.disabled:focus, -.btn-warning[disabled]:focus, -fieldset[disabled] .btn-warning:focus, -.btn-warning.disabled.focus, -.btn-warning[disabled].focus, -fieldset[disabled] .btn-warning.focus, -.btn-warning.disabled:active, -.btn-warning[disabled]:active, -fieldset[disabled] .btn-warning:active, -.btn-warning.disabled.active, -.btn-warning[disabled].active, -fieldset[disabled] .btn-warning.active { - background-color: #f0ad4e; - border-color: #eea236; -} -.btn-warning .badge { - color: #f0ad4e; - background-color: #fff; -} -.btn-danger { - color: #fff; - background-color: #d9534f; - border-color: #d43f3a; -} -.btn-danger:hover, -.btn-danger:focus, -.btn-danger.focus, -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - color: #fff; - background-color: #c9302c; - border-color: #ac2925; -} -.btn-danger:active, -.btn-danger.active, -.open > .dropdown-toggle.btn-danger { - background-image: none; -} -.btn-danger.disabled, -.btn-danger[disabled], -fieldset[disabled] .btn-danger, -.btn-danger.disabled:hover, -.btn-danger[disabled]:hover, -fieldset[disabled] .btn-danger:hover, -.btn-danger.disabled:focus, -.btn-danger[disabled]:focus, -fieldset[disabled] .btn-danger:focus, -.btn-danger.disabled.focus, -.btn-danger[disabled].focus, -fieldset[disabled] .btn-danger.focus, -.btn-danger.disabled:active, -.btn-danger[disabled]:active, -fieldset[disabled] .btn-danger:active, -.btn-danger.disabled.active, -.btn-danger[disabled].active, -fieldset[disabled] .btn-danger.active { - background-color: #d9534f; - border-color: #d43f3a; -} -.btn-danger .badge { - color: #d9534f; - background-color: #fff; -} -.btn-link { - font-weight: normal; - color: #428bca; - border-radius: 0; -} -.btn-link, -.btn-link:active, -.btn-link.active, -.btn-link[disabled], -fieldset[disabled] .btn-link { - background-color: transparent; - -webkit-box-shadow: none; - box-shadow: none; -} -.btn-link, -.btn-link:hover, -.btn-link:focus, -.btn-link:active { - border-color: transparent; -} -.btn-link:hover, -.btn-link:focus { - color: #2a6496; - text-decoration: underline; - background-color: transparent; -} -.btn-link[disabled]:hover, -fieldset[disabled] .btn-link:hover, -.btn-link[disabled]:focus, -fieldset[disabled] .btn-link:focus { - color: #777; - text-decoration: none; -} -.btn-lg, -.btn-group-lg > .btn { - padding: 10px 16px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} -.btn-sm, -.btn-group-sm > .btn { - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-xs, -.btn-group-xs > .btn { - padding: 1px 5px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -.btn-block { - display: block; - width: 100%; -} -.btn-block + .btn-block { - margin-top: 5px; -} -input[type="submit"].btn-block, -input[type="reset"].btn-block, -input[type="button"].btn-block { - width: 100%; -} -.fade { - opacity: 0; - -webkit-transition: opacity .15s linear; - -o-transition: opacity .15s linear; - transition: opacity .15s linear; -} -.fade.in { - opacity: 1; -} -.collapse { - display: none; - visibility: hidden; -} -.collapse.in { - display: block; - visibility: visible; -} -tr.collapse.in { - display: table-row; -} -tbody.collapse.in { - display: table-row-group; -} -.collapsing { - position: relative; - height: 0; - overflow: hidden; - -webkit-transition-timing-function: ease; - -o-transition-timing-function: ease; - transition-timing-function: ease; - -webkit-transition-duration: .35s; - -o-transition-duration: .35s; - transition-duration: .35s; - -webkit-transition-property: height, visibility; - -o-transition-property: height, visibility; - transition-property: height, visibility; -} -.caret { - display: inline-block; - width: 0; - height: 0; - margin-left: 2px; - vertical-align: middle; - border-top: 4px solid; - border-right: 4px solid transparent; - border-left: 4px solid transparent; -} -.dropdown { - position: relative; -} -.dropdown-toggle:focus { - outline: 0; -} -.dropdown-menu { - position: absolute; - top: 100%; - left: 0; - z-index: 1000; - display: none; - float: left; - min-width: 160px; - padding: 5px 0; - margin: 2px 0 0; - font-size: 14px; - text-align: left; - list-style: none; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, .15); - border-radius: 4px; - -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); - box-shadow: 0 6px 12px rgba(0, 0, 0, .175); -} -.dropdown-menu.pull-right { - right: 0; - left: auto; -} -.dropdown-menu .divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5; -} -.dropdown-menu > li > a { - display: block; - padding: 3px 20px; - clear: both; - font-weight: normal; - line-height: 1.42857143; - color: #333; - white-space: nowrap; -} -.dropdown-menu > li > a:hover, -.dropdown-menu > li > a:focus { - color: #262626; - text-decoration: none; - background-color: #f5f5f5; -} -.dropdown-menu > .active > a, -.dropdown-menu > .active > a:hover, -.dropdown-menu > .active > a:focus { - color: #fff; - text-decoration: none; - background-color: #428bca; - outline: 0; -} -.dropdown-menu > .disabled > a, -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - color: #777; -} -.dropdown-menu > .disabled > a:hover, -.dropdown-menu > .disabled > a:focus { - text-decoration: none; - cursor: not-allowed; - background-color: transparent; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); -} -.open > .dropdown-menu { - display: block; -} -.open > a { - outline: 0; -} -.dropdown-menu-right { - right: 0; - left: auto; -} -.dropdown-menu-left { - right: auto; - left: 0; -} -.dropdown-header { - display: block; - padding: 3px 20px; - font-size: 12px; - line-height: 1.42857143; - color: #777; - white-space: nowrap; -} -.dropdown-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 990; -} -.pull-right > .dropdown-menu { - right: 0; - left: auto; -} -.dropup .caret, -.navbar-fixed-bottom .dropdown .caret { - content: ""; - border-top: 0; - border-bottom: 4px solid; -} -.dropup .dropdown-menu, -.navbar-fixed-bottom .dropdown .dropdown-menu { - top: auto; - bottom: 100%; - margin-bottom: 1px; -} -@media (min-width: 768px) { - .navbar-right .dropdown-menu { - right: 0; - left: auto; - } - .navbar-right .dropdown-menu-left { - right: auto; - left: 0; - } -} -.btn-group, -.btn-group-vertical { - position: relative; - display: inline-block; - vertical-align: middle; -} -.btn-group > .btn, -.btn-group-vertical > .btn { - position: relative; - float: left; -} -.btn-group > .btn:hover, -.btn-group-vertical > .btn:hover, -.btn-group > .btn:focus, -.btn-group-vertical > .btn:focus, -.btn-group > .btn:active, -.btn-group-vertical > .btn:active, -.btn-group > .btn.active, -.btn-group-vertical > .btn.active { - z-index: 2; -} -.btn-group > .btn:focus, -.btn-group-vertical > .btn:focus { - outline: 0; -} -.btn-group .btn + .btn, -.btn-group .btn + .btn-group, -.btn-group .btn-group + .btn, -.btn-group .btn-group + .btn-group { - margin-left: -1px; -} -.btn-toolbar { - margin-left: -5px; -} -.btn-toolbar .btn-group, -.btn-toolbar .input-group { - float: left; -} -.btn-toolbar > .btn, -.btn-toolbar > .btn-group, -.btn-toolbar > .input-group { - margin-left: 5px; -} -.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { - border-radius: 0; -} -.btn-group > .btn:first-child { - margin-left: 0; -} -.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.btn-group > .btn:last-child:not(:first-child), -.btn-group > .dropdown-toggle:not(:first-child) { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group > .btn-group { - float: left; -} -.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} -.btn-group > .btn-group:first-child > .btn:last-child, -.btn-group > .btn-group:first-child > .dropdown-toggle { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.btn-group > .btn-group:last-child > .btn:first-child { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group .dropdown-toggle:active, -.btn-group.open .dropdown-toggle { - outline: 0; -} -.btn-group > .btn + .dropdown-toggle { - padding-right: 8px; - padding-left: 8px; -} -.btn-group > .btn-lg + .dropdown-toggle { - padding-right: 12px; - padding-left: 12px; -} -.btn-group.open .dropdown-toggle { - -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); - box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); -} -.btn-group.open .dropdown-toggle.btn-link { - -webkit-box-shadow: none; - box-shadow: none; -} -.btn .caret { - margin-left: 0; -} -.btn-lg .caret { - border-width: 5px 5px 0; - border-bottom-width: 0; -} -.dropup .btn-lg .caret { - border-width: 0 5px 5px; -} -.btn-group-vertical > .btn, -.btn-group-vertical > .btn-group, -.btn-group-vertical > .btn-group > .btn { - display: block; - float: none; - width: 100%; - max-width: 100%; -} -.btn-group-vertical > .btn-group > .btn { - float: none; -} -.btn-group-vertical > .btn + .btn, -.btn-group-vertical > .btn + .btn-group, -.btn-group-vertical > .btn-group + .btn, -.btn-group-vertical > .btn-group + .btn-group { - margin-top: -1px; - margin-left: 0; -} -.btn-group-vertical > .btn:not(:first-child):not(:last-child) { - border-radius: 0; -} -.btn-group-vertical > .btn:first-child:not(:last-child) { - border-top-right-radius: 4px; - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn:last-child:not(:first-child) { - border-top-left-radius: 0; - border-top-right-radius: 0; - border-bottom-left-radius: 4px; -} -.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { - border-radius: 0; -} -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, -.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { - border-top-left-radius: 0; - border-top-right-radius: 0; -} -.btn-group-justified { - display: table; - width: 100%; - table-layout: fixed; - border-collapse: separate; -} -.btn-group-justified > .btn, -.btn-group-justified > .btn-group { - display: table-cell; - float: none; - width: 1%; -} -.btn-group-justified > .btn-group .btn { - width: 100%; -} -.btn-group-justified > .btn-group .dropdown-menu { - left: auto; -} -[data-toggle="buttons"] > .btn input[type="radio"], -[data-toggle="buttons"] > .btn-group > .btn input[type="radio"], -[data-toggle="buttons"] > .btn input[type="checkbox"], -[data-toggle="buttons"] > .btn-group > .btn input[type="checkbox"] { - position: absolute; - clip: rect(0, 0, 0, 0); - pointer-events: none; -} -.input-group { - position: relative; - display: table; - border-collapse: separate; -} -.input-group[class*="col-"] { - float: none; - padding-right: 0; - padding-left: 0; -} -.input-group .form-control { - position: relative; - z-index: 2; - float: left; - width: 100%; - margin-bottom: 0; -} -.input-group-lg > .form-control, -.input-group-lg > .input-group-addon, -.input-group-lg > .input-group-btn > .btn { - height: 46px; - padding: 10px 16px; - font-size: 18px; - line-height: 1.33; - border-radius: 6px; -} -select.input-group-lg > .form-control, -select.input-group-lg > .input-group-addon, -select.input-group-lg > .input-group-btn > .btn { - height: 46px; - line-height: 46px; -} -textarea.input-group-lg > .form-control, -textarea.input-group-lg > .input-group-addon, -textarea.input-group-lg > .input-group-btn > .btn, -select[multiple].input-group-lg > .form-control, -select[multiple].input-group-lg > .input-group-addon, -select[multiple].input-group-lg > .input-group-btn > .btn { - height: auto; -} -.input-group-sm > .form-control, -.input-group-sm > .input-group-addon, -.input-group-sm > .input-group-btn > .btn { - height: 30px; - padding: 5px 10px; - font-size: 12px; - line-height: 1.5; - border-radius: 3px; -} -select.input-group-sm > .form-control, -select.input-group-sm > .input-group-addon, -select.input-group-sm > .input-group-btn > .btn { - height: 30px; - line-height: 30px; -} -textarea.input-group-sm > .form-control, -textarea.input-group-sm > .input-group-addon, -textarea.input-group-sm > .input-group-btn > .btn, -select[multiple].input-group-sm > .form-control, -select[multiple].input-group-sm > .input-group-addon, -select[multiple].input-group-sm > .input-group-btn > .btn { - height: auto; -} -.input-group-addon, -.input-group-btn, -.input-group .form-control { - display: table-cell; -} -.input-group-addon:not(:first-child):not(:last-child), -.input-group-btn:not(:first-child):not(:last-child), -.input-group .form-control:not(:first-child):not(:last-child) { - border-radius: 0; -} -.input-group-addon, -.input-group-btn { - width: 1%; - white-space: nowrap; - vertical-align: middle; -} -.input-group-addon { - padding: 6px 12px; - font-size: 14px; - font-weight: normal; - line-height: 1; - color: #555; - text-align: center; - background-color: #eee; - border: 1px solid #ccc; - border-radius: 4px; -} -.input-group-addon.input-sm { - padding: 5px 10px; - font-size: 12px; - border-radius: 3px; -} -.input-group-addon.input-lg { - padding: 10px 16px; - font-size: 18px; - border-radius: 6px; -} -.input-group-addon input[type="radio"], -.input-group-addon input[type="checkbox"] { - margin-top: 0; -} -.input-group .form-control:first-child, -.input-group-addon:first-child, -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .btn-group > .btn, -.input-group-btn:first-child > .dropdown-toggle, -.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), -.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.input-group-addon:first-child { - border-right: 0; -} -.input-group .form-control:last-child, -.input-group-addon:last-child, -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .btn-group > .btn, -.input-group-btn:last-child > .dropdown-toggle, -.input-group-btn:first-child > .btn:not(:first-child), -.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} -.input-group-addon:last-child { - border-left: 0; -} -.input-group-btn { - position: relative; - font-size: 0; - white-space: nowrap; -} -.input-group-btn > .btn { - position: relative; -} -.input-group-btn > .btn + .btn { - margin-left: -1px; -} -.input-group-btn > .btn:hover, -.input-group-btn > .btn:focus, -.input-group-btn > .btn:active { - z-index: 2; -} -.input-group-btn:first-child > .btn, -.input-group-btn:first-child > .btn-group { - margin-right: -1px; -} -.input-group-btn:last-child > .btn, -.input-group-btn:last-child > .btn-group { - margin-left: -1px; -} -.nav { - padding-left: 0; - margin-bottom: 0; - list-style: none; -} -.nav > li { - position: relative; - display: block; -} -.nav > li > a { - position: relative; - display: block; - padding: 10px 15px; -} -.nav > li > a:hover, -.nav > li > a:focus { - text-decoration: none; - background-color: #eee; -} -.nav > li.disabled > a { - color: #777; -} -.nav > li.disabled > a:hover, -.nav > li.disabled > a:focus { - color: #777; - text-decoration: none; - cursor: not-allowed; - background-color: transparent; -} -.nav .open > a, -.nav .open > a:hover, -.nav .open > a:focus { - background-color: #eee; - border-color: #428bca; -} -.nav .nav-divider { - height: 1px; - margin: 9px 0; - overflow: hidden; - background-color: #e5e5e5; -} -.nav > li > a > img { - max-width: none; -} -.nav-tabs { - border-bottom: 1px solid #ddd; -} -.nav-tabs > li { - float: left; - margin-bottom: -1px; -} -.nav-tabs > li > a { - margin-right: 2px; - line-height: 1.42857143; - border: 1px solid transparent; - border-radius: 4px 4px 0 0; -} -.nav-tabs > li > a:hover { - border-color: #eee #eee #ddd; -} -.nav-tabs > li.active > a, -.nav-tabs > li.active > a:hover, -.nav-tabs > li.active > a:focus { - color: #555; - cursor: default; - background-color: #fff; - border: 1px solid #ddd; - border-bottom-color: transparent; -} -.nav-tabs.nav-justified { - width: 100%; - border-bottom: 0; -} -.nav-tabs.nav-justified > li { - float: none; -} -.nav-tabs.nav-justified > li > a { - margin-bottom: 5px; - text-align: center; -} -.nav-tabs.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} -@media (min-width: 768px) { - .nav-tabs.nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-tabs.nav-justified > li > a { - margin-bottom: 0; - } -} -.nav-tabs.nav-justified > li > a { - margin-right: 0; - border-radius: 4px; -} -.nav-tabs.nav-justified > .active > a, -.nav-tabs.nav-justified > .active > a:hover, -.nav-tabs.nav-justified > .active > a:focus { - border: 1px solid #ddd; -} -@media (min-width: 768px) { - .nav-tabs.nav-justified > li > a { - border-bottom: 1px solid #ddd; - border-radius: 4px 4px 0 0; - } - .nav-tabs.nav-justified > .active > a, - .nav-tabs.nav-justified > .active > a:hover, - .nav-tabs.nav-justified > .active > a:focus { - border-bottom-color: #fff; - } -} -.nav-pills > li { - float: left; -} -.nav-pills > li > a { - border-radius: 4px; -} -.nav-pills > li + li { - margin-left: 2px; -} -.nav-pills > li.active > a, -.nav-pills > li.active > a:hover, -.nav-pills > li.active > a:focus { - color: #fff; - background-color: #428bca; -} -.nav-stacked > li { - float: none; -} -.nav-stacked > li + li { - margin-top: 2px; - margin-left: 0; -} -.nav-justified { - width: 100%; -} -.nav-justified > li { - float: none; -} -.nav-justified > li > a { - margin-bottom: 5px; - text-align: center; -} -.nav-justified > .dropdown .dropdown-menu { - top: auto; - left: auto; -} -@media (min-width: 768px) { - .nav-justified > li { - display: table-cell; - width: 1%; - } - .nav-justified > li > a { - margin-bottom: 0; - } -} -.nav-tabs-justified { - border-bottom: 0; -} -.nav-tabs-justified > li > a { - margin-right: 0; - border-radius: 4px; -} -.nav-tabs-justified > .active > a, -.nav-tabs-justified > .active > a:hover, -.nav-tabs-justified > .active > a:focus { - border: 1px solid #ddd; -} -@media (min-width: 768px) { - .nav-tabs-justified > li > a { - border-bottom: 1px solid #ddd; - border-radius: 4px 4px 0 0; - } - .nav-tabs-justified > .active > a, - .nav-tabs-justified > .active > a:hover, - .nav-tabs-justified > .active > a:focus { - border-bottom-color: #fff; - } -} -.tab-content > .tab-pane { - display: none; - visibility: hidden; -} -.tab-content > .active { - display: block; - visibility: visible; -} -.nav-tabs .dropdown-menu { - margin-top: -1px; - border-top-left-radius: 0; - border-top-right-radius: 0; -} -.navbar { - position: relative; - min-height: 50px; - margin-bottom: 20px; - border: 1px solid transparent; -} -@media (min-width: 768px) { - .navbar { - border-radius: 4px; - } -} -@media (min-width: 768px) { - .navbar-header { - float: left; - } -} -.navbar-collapse { - padding-right: 15px; - padding-left: 15px; - overflow-x: visible; - -webkit-overflow-scrolling: touch; - border-top: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); -} -.navbar-collapse.in { - overflow-y: auto; -} -@media (min-width: 768px) { - .navbar-collapse { - width: auto; - border-top: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-collapse.collapse { - display: block !important; - height: auto !important; - padding-bottom: 0; - overflow: visible !important; - visibility: visible !important; - } - .navbar-collapse.in { - overflow-y: visible; - } - .navbar-fixed-top .navbar-collapse, - .navbar-static-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - padding-right: 0; - padding-left: 0; - } -} -.navbar-fixed-top .navbar-collapse, -.navbar-fixed-bottom .navbar-collapse { - max-height: 340px; -} -@media (max-device-width: 480px) and (orientation: landscape) { - .navbar-fixed-top .navbar-collapse, - .navbar-fixed-bottom .navbar-collapse { - max-height: 200px; - } -} -.container > .navbar-header, -.container-fluid > .navbar-header, -.container > .navbar-collapse, -.container-fluid > .navbar-collapse { - margin-right: -15px; - margin-left: -15px; -} -@media (min-width: 768px) { - .container > .navbar-header, - .container-fluid > .navbar-header, - .container > .navbar-collapse, - .container-fluid > .navbar-collapse { - margin-right: 0; - margin-left: 0; - } -} -.navbar-static-top { - z-index: 1000; - border-width: 0 0 1px; -} -@media (min-width: 768px) { - .navbar-static-top { - border-radius: 0; - } -} -.navbar-fixed-top, -.navbar-fixed-bottom { - position: fixed; - right: 0; - left: 0; - z-index: 1030; -} -@media (min-width: 768px) { - .navbar-fixed-top, - .navbar-fixed-bottom { - border-radius: 0; - } -} -.navbar-fixed-top { - top: 0; - border-width: 0 0 1px; -} -.navbar-fixed-bottom { - bottom: 0; - margin-bottom: 0; - border-width: 1px 0 0; -} -.navbar-brand { - float: left; - height: 50px; - padding: 15px 15px; - font-size: 18px; - line-height: 20px; -} -.navbar-brand:hover, -.navbar-brand:focus { - text-decoration: none; -} -.navbar-brand > img { - display: block; -} -@media (min-width: 768px) { - .navbar > .container .navbar-brand, - .navbar > .container-fluid .navbar-brand { - margin-left: -15px; - } -} -.navbar-toggle { - position: relative; - float: right; - padding: 9px 10px; - margin-top: 8px; - margin-right: 15px; - margin-bottom: 8px; - background-color: transparent; - background-image: none; - border: 1px solid transparent; - border-radius: 4px; -} -.navbar-toggle:focus { - outline: 0; -} -.navbar-toggle .icon-bar { - display: block; - width: 22px; - height: 2px; - border-radius: 1px; -} -.navbar-toggle .icon-bar + .icon-bar { - margin-top: 4px; -} -@media (min-width: 768px) { - .navbar-toggle { - display: none; - } -} -.navbar-nav { - margin: 7.5px -15px; -} -.navbar-nav > li > a { - padding-top: 10px; - padding-bottom: 10px; - line-height: 20px; -} -@media (max-width: 767px) { - .navbar-nav .open .dropdown-menu { - position: static; - float: none; - width: auto; - margin-top: 0; - background-color: transparent; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } - .navbar-nav .open .dropdown-menu > li > a, - .navbar-nav .open .dropdown-menu .dropdown-header { - padding: 5px 15px 5px 25px; - } - .navbar-nav .open .dropdown-menu > li > a { - line-height: 20px; - } - .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-nav .open .dropdown-menu > li > a:focus { - background-image: none; - } -} -@media (min-width: 768px) { - .navbar-nav { - float: left; - margin: 0; - } - .navbar-nav > li { - float: left; - } - .navbar-nav > li > a { - padding-top: 15px; - padding-bottom: 15px; - } -} -.navbar-form { - padding: 10px 15px; - margin-top: 8px; - margin-right: -15px; - margin-bottom: 8px; - margin-left: -15px; - border-top: 1px solid transparent; - border-bottom: 1px solid transparent; - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); -} -@media (min-width: 768px) { - .navbar-form .form-group { - display: inline-block; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .form-control { - display: inline-block; - width: auto; - vertical-align: middle; - } - .navbar-form .form-control-static { - display: inline-block; - } - .navbar-form .input-group { - display: inline-table; - vertical-align: middle; - } - .navbar-form .input-group .input-group-addon, - .navbar-form .input-group .input-group-btn, - .navbar-form .input-group .form-control { - width: auto; - } - .navbar-form .input-group > .form-control { - width: 100%; - } - .navbar-form .control-label { - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .radio, - .navbar-form .checkbox { - display: inline-block; - margin-top: 0; - margin-bottom: 0; - vertical-align: middle; - } - .navbar-form .radio label, - .navbar-form .checkbox label { - padding-left: 0; - } - .navbar-form .radio input[type="radio"], - .navbar-form .checkbox input[type="checkbox"] { - position: relative; - margin-left: 0; - } - .navbar-form .has-feedback .form-control-feedback { - top: 0; - } -} -@media (max-width: 767px) { - .navbar-form .form-group { - margin-bottom: 5px; - } - .navbar-form .form-group:last-child { - margin-bottom: 0; - } -} -@media (min-width: 768px) { - .navbar-form { - width: auto; - padding-top: 0; - padding-bottom: 0; - margin-right: 0; - margin-left: 0; - border: 0; - -webkit-box-shadow: none; - box-shadow: none; - } -} -.navbar-nav > li > .dropdown-menu { - margin-top: 0; - border-top-left-radius: 0; - border-top-right-radius: 0; -} -.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; -} -.navbar-btn { - margin-top: 8px; - margin-bottom: 8px; -} -.navbar-btn.btn-sm { - margin-top: 10px; - margin-bottom: 10px; -} -.navbar-btn.btn-xs { - margin-top: 14px; - margin-bottom: 14px; -} -.navbar-text { - margin-top: 15px; - margin-bottom: 15px; -} -@media (min-width: 768px) { - .navbar-text { - float: left; - margin-right: 15px; - margin-left: 15px; - } -} -@media (min-width: 768px) { - .navbar-left { - float: left !important; - } - .navbar-right { - float: right !important; - margin-right: -15px; - } - .navbar-right ~ .navbar-right { - margin-right: 0; - } -} -.navbar-default { - background-color: #f8f8f8; - border-color: #e7e7e7; -} -.navbar-default .navbar-brand { - color: #777; -} -.navbar-default .navbar-brand:hover, -.navbar-default .navbar-brand:focus { - color: #5e5e5e; - background-color: transparent; -} -.navbar-default .navbar-text { - color: #777; -} -.navbar-default .navbar-nav > li > a { - color: #777; -} -.navbar-default .navbar-nav > li > a:hover, -.navbar-default .navbar-nav > li > a:focus { - color: #333; - background-color: transparent; -} -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: #555; - background-color: #e7e7e7; -} -.navbar-default .navbar-nav > .disabled > a, -.navbar-default .navbar-nav > .disabled > a:hover, -.navbar-default .navbar-nav > .disabled > a:focus { - color: #ccc; - background-color: transparent; -} -.navbar-default .navbar-toggle { - border-color: #ddd; -} -.navbar-default .navbar-toggle:hover, -.navbar-default .navbar-toggle:focus { - background-color: #ddd; -} -.navbar-default .navbar-toggle .icon-bar { - background-color: #888; -} -.navbar-default .navbar-collapse, -.navbar-default .navbar-form { - border-color: #e7e7e7; -} -.navbar-default .navbar-nav > .open > a, -.navbar-default .navbar-nav > .open > a:hover, -.navbar-default .navbar-nav > .open > a:focus { - color: #555; - background-color: #e7e7e7; -} -@media (max-width: 767px) { - .navbar-default .navbar-nav .open .dropdown-menu > li > a { - color: #777; - } - .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { - color: #333; - background-color: transparent; - } - .navbar-default .navbar-nav .open .dropdown-menu > .active > a, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #555; - background-color: #e7e7e7; - } - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #ccc; - background-color: transparent; - } -} -.navbar-default .navbar-link { - color: #777; -} -.navbar-default .navbar-link:hover { - color: #333; -} -.navbar-default .btn-link { - color: #777; -} -.navbar-default .btn-link:hover, -.navbar-default .btn-link:focus { - color: #333; -} -.navbar-default .btn-link[disabled]:hover, -fieldset[disabled] .navbar-default .btn-link:hover, -.navbar-default .btn-link[disabled]:focus, -fieldset[disabled] .navbar-default .btn-link:focus { - color: #ccc; -} -.navbar-inverse { - background-color: #222; - border-color: #080808; -} -.navbar-inverse .navbar-brand { - color: #9d9d9d; -} -.navbar-inverse .navbar-brand:hover, -.navbar-inverse .navbar-brand:focus { - color: #fff; - background-color: transparent; -} -.navbar-inverse .navbar-text { - color: #9d9d9d; -} -.navbar-inverse .navbar-nav > li > a { - color: #9d9d9d; -} -.navbar-inverse .navbar-nav > li > a:hover, -.navbar-inverse .navbar-nav > li > a:focus { - color: #fff; - background-color: transparent; -} -.navbar-inverse .navbar-nav > .active > a, -.navbar-inverse .navbar-nav > .active > a:hover, -.navbar-inverse .navbar-nav > .active > a:focus { - color: #fff; - background-color: #080808; -} -.navbar-inverse .navbar-nav > .disabled > a, -.navbar-inverse .navbar-nav > .disabled > a:hover, -.navbar-inverse .navbar-nav > .disabled > a:focus { - color: #444; - background-color: transparent; -} -.navbar-inverse .navbar-toggle { - border-color: #333; -} -.navbar-inverse .navbar-toggle:hover, -.navbar-inverse .navbar-toggle:focus { - background-color: #333; -} -.navbar-inverse .navbar-toggle .icon-bar { - background-color: #fff; -} -.navbar-inverse .navbar-collapse, -.navbar-inverse .navbar-form { - border-color: #101010; -} -.navbar-inverse .navbar-nav > .open > a, -.navbar-inverse .navbar-nav > .open > a:hover, -.navbar-inverse .navbar-nav > .open > a:focus { - color: #fff; - background-color: #080808; -} -@media (max-width: 767px) { - .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { - border-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu .divider { - background-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { - color: #9d9d9d; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { - color: #fff; - background-color: transparent; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { - color: #fff; - background-color: #080808; - } - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, - .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { - color: #444; - background-color: transparent; - } -} -.navbar-inverse .navbar-link { - color: #9d9d9d; -} -.navbar-inverse .navbar-link:hover { - color: #fff; -} -.navbar-inverse .btn-link { - color: #9d9d9d; -} -.navbar-inverse .btn-link:hover, -.navbar-inverse .btn-link:focus { - color: #fff; -} -.navbar-inverse .btn-link[disabled]:hover, -fieldset[disabled] .navbar-inverse .btn-link:hover, -.navbar-inverse .btn-link[disabled]:focus, -fieldset[disabled] .navbar-inverse .btn-link:focus { - color: #444; -} -.breadcrumb { - padding: 8px 15px; - margin-bottom: 20px; - list-style: none; - background-color: #f5f5f5; - border-radius: 4px; -} -.breadcrumb > li { - display: inline-block; -} -.breadcrumb > li + li:before { - padding: 0 5px; - color: #ccc; - content: "/\00a0"; -} -.breadcrumb > .active { - color: #777; -} -.pagination { - display: inline-block; - padding-left: 0; - margin: 20px 0; - border-radius: 4px; -} -.pagination > li { - display: inline; -} -.pagination > li > a, -.pagination > li > span { - position: relative; - float: left; - padding: 6px 12px; - margin-left: -1px; - line-height: 1.42857143; - color: #428bca; - text-decoration: none; - background-color: #fff; - border: 1px solid #ddd; -} -.pagination > li:first-child > a, -.pagination > li:first-child > span { - margin-left: 0; - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; -} -.pagination > li:last-child > a, -.pagination > li:last-child > span { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} -.pagination > li > a:hover, -.pagination > li > span:hover, -.pagination > li > a:focus, -.pagination > li > span:focus { - color: #2a6496; - background-color: #eee; - border-color: #ddd; -} -.pagination > .active > a, -.pagination > .active > span, -.pagination > .active > a:hover, -.pagination > .active > span:hover, -.pagination > .active > a:focus, -.pagination > .active > span:focus { - z-index: 2; - color: #fff; - cursor: default; - background-color: #428bca; - border-color: #428bca; -} -.pagination > .disabled > span, -.pagination > .disabled > span:hover, -.pagination > .disabled > span:focus, -.pagination > .disabled > a, -.pagination > .disabled > a:hover, -.pagination > .disabled > a:focus { - color: #777; - cursor: not-allowed; - background-color: #fff; - border-color: #ddd; -} -.pagination-lg > li > a, -.pagination-lg > li > span { - padding: 10px 16px; - font-size: 18px; -} -.pagination-lg > li:first-child > a, -.pagination-lg > li:first-child > span { - border-top-left-radius: 6px; - border-bottom-left-radius: 6px; -} -.pagination-lg > li:last-child > a, -.pagination-lg > li:last-child > span { - border-top-right-radius: 6px; - border-bottom-right-radius: 6px; -} -.pagination-sm > li > a, -.pagination-sm > li > span { - padding: 5px 10px; - font-size: 12px; -} -.pagination-sm > li:first-child > a, -.pagination-sm > li:first-child > span { - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; -} -.pagination-sm > li:last-child > a, -.pagination-sm > li:last-child > span { - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; -} -.pager { - padding-left: 0; - margin: 20px 0; - text-align: center; - list-style: none; -} -.pager li { - display: inline; -} -.pager li > a, -.pager li > span { - display: inline-block; - padding: 5px 14px; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 15px; -} -.pager li > a:hover, -.pager li > a:focus { - text-decoration: none; - background-color: #eee; -} -.pager .next > a, -.pager .next > span { - float: right; -} -.pager .previous > a, -.pager .previous > span { - float: left; -} -.pager .disabled > a, -.pager .disabled > a:hover, -.pager .disabled > a:focus, -.pager .disabled > span { - color: #777; - cursor: not-allowed; - background-color: #fff; -} -.label { - display: inline; - padding: .2em .6em .3em; - font-size: 75%; - font-weight: bold; - line-height: 1; - color: #fff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25em; -} -a.label:hover, -a.label:focus { - color: #fff; - text-decoration: none; - cursor: pointer; -} -.label:empty { - display: none; -} -.btn .label { - position: relative; - top: -1px; -} -.label-default { - background-color: #777; -} -.label-default[href]:hover, -.label-default[href]:focus { - background-color: #5e5e5e; -} -.label-primary { - background-color: #428bca; -} -.label-primary[href]:hover, -.label-primary[href]:focus { - background-color: #3071a9; -} -.label-success { - background-color: #5cb85c; -} -.label-success[href]:hover, -.label-success[href]:focus { - background-color: #449d44; -} -.label-info { - background-color: #5bc0de; -} -.label-info[href]:hover, -.label-info[href]:focus { - background-color: #31b0d5; -} -.label-warning { - background-color: #f0ad4e; -} -.label-warning[href]:hover, -.label-warning[href]:focus { - background-color: #ec971f; -} -.label-danger { - background-color: #d9534f; -} -.label-danger[href]:hover, -.label-danger[href]:focus { - background-color: #c9302c; -} -.badge { - display: inline-block; - min-width: 10px; - padding: 3px 7px; - font-size: 12px; - font-weight: bold; - line-height: 1; - color: #fff; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - background-color: #777; - border-radius: 10px; -} -.badge:empty { - display: none; -} -.btn .badge { - position: relative; - top: -1px; -} -.btn-xs .badge { - top: 0; - padding: 1px 5px; -} -a.badge:hover, -a.badge:focus { - color: #fff; - text-decoration: none; - cursor: pointer; -} -a.list-group-item.active > .badge, -.nav-pills > .active > a > .badge { - color: #428bca; - background-color: #fff; -} -.nav-pills > li > a > .badge { - margin-left: 3px; -} -.jumbotron { - padding: 30px 15px; - margin-bottom: 30px; - color: inherit; - background-color: #eee; -} -.jumbotron h1, -.jumbotron .h1 { - color: inherit; -} -.jumbotron p { - margin-bottom: 15px; - font-size: 21px; - font-weight: 200; -} -.jumbotron > hr { - border-top-color: #d5d5d5; -} -.container .jumbotron, -.container-fluid .jumbotron { - border-radius: 6px; -} -.jumbotron .container { - max-width: 100%; -} -@media screen and (min-width: 768px) { - .jumbotron { - padding: 48px 0; - } - .container .jumbotron { - padding-right: 60px; - padding-left: 60px; - } - .jumbotron h1, - .jumbotron .h1 { - font-size: 63px; - } -} -.thumbnail { - display: block; - padding: 4px; - margin-bottom: 20px; - line-height: 1.42857143; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - -webkit-transition: border .2s ease-in-out; - -o-transition: border .2s ease-in-out; - transition: border .2s ease-in-out; -} -.thumbnail > img, -.thumbnail a > img { - margin-right: auto; - margin-left: auto; -} -a.thumbnail:hover, -a.thumbnail:focus, -a.thumbnail.active { - border-color: #428bca; -} -.thumbnail .caption { - padding: 9px; - color: #333; -} -.alert { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px; -} -.alert h4 { - margin-top: 0; - color: inherit; -} -.alert .alert-link { - font-weight: bold; -} -.alert > p, -.alert > ul { - margin-bottom: 0; -} -.alert > p + p { - margin-top: 5px; -} -.alert-dismissable, -.alert-dismissible { - padding-right: 35px; -} -.alert-dismissable .close, -.alert-dismissible .close { - position: relative; - top: -2px; - right: -21px; - color: inherit; -} -.alert-success { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; -} -.alert-success hr { - border-top-color: #c9e2b3; -} -.alert-success .alert-link { - color: #2b542c; -} -.alert-info { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} -.alert-info hr { - border-top-color: #a6e1ec; -} -.alert-info .alert-link { - color: #245269; -} -.alert-warning { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} -.alert-warning hr { - border-top-color: #f7e1b5; -} -.alert-warning .alert-link { - color: #66512c; -} -.alert-danger { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} -.alert-danger hr { - border-top-color: #e4b9c0; -} -.alert-danger .alert-link { - color: #843534; -} -@-webkit-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@-o-keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -@keyframes progress-bar-stripes { - from { - background-position: 40px 0; - } - to { - background-position: 0 0; - } -} -.progress { - height: 20px; - margin-bottom: 20px; - overflow: hidden; - background-color: #f5f5f5; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); - box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); -} -.progress-bar { - float: left; - width: 0; - height: 100%; - font-size: 12px; - line-height: 20px; - color: #fff; - text-align: center; - background-color: #428bca; - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); - -webkit-transition: width .6s ease; - -o-transition: width .6s ease; - transition: width .6s ease; -} -.progress-striped .progress-bar, -.progress-bar-striped { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - -webkit-background-size: 40px 40px; - background-size: 40px 40px; -} -.progress.active .progress-bar, -.progress-bar.active { - -webkit-animation: progress-bar-stripes 2s linear infinite; - -o-animation: progress-bar-stripes 2s linear infinite; - animation: progress-bar-stripes 2s linear infinite; -} -.progress-bar-success { - background-color: #5cb85c; -} -.progress-striped .progress-bar-success { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.progress-bar-info { - background-color: #5bc0de; -} -.progress-striped .progress-bar-info { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.progress-bar-warning { - background-color: #f0ad4e; -} -.progress-striped .progress-bar-warning { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.progress-bar-danger { - background-color: #d9534f; -} -.progress-striped .progress-bar-danger { - background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); - background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); -} -.media { - margin-top: 15px; -} -.media:first-child { - margin-top: 0; -} -.media-right, -.media > .pull-right { - padding-left: 10px; -} -.media-left, -.media > .pull-left { - padding-right: 10px; -} -.media-left, -.media-right, -.media-body { - display: table-cell; - vertical-align: top; -} -.media-middle { - vertical-align: middle; -} -.media-bottom { - vertical-align: bottom; -} -.media-heading { - margin-top: 0; - margin-bottom: 5px; -} -.media-list { - padding-left: 0; - list-style: none; -} -.list-group { - padding-left: 0; - margin-bottom: 20px; -} -.list-group-item { - position: relative; - display: block; - padding: 10px 15px; - margin-bottom: -1px; - background-color: #fff; - border: 1px solid #ddd; -} -.list-group-item:first-child { - border-top-left-radius: 4px; - border-top-right-radius: 4px; -} -.list-group-item:last-child { - margin-bottom: 0; - border-bottom-right-radius: 4px; - border-bottom-left-radius: 4px; -} -.list-group-item > .badge { - float: right; -} -.list-group-item > .badge + .badge { - margin-right: 5px; -} -a.list-group-item { - color: #555; -} -a.list-group-item .list-group-item-heading { - color: #333; -} -a.list-group-item:hover, -a.list-group-item:focus { - color: #555; - text-decoration: none; - background-color: #f5f5f5; -} -.list-group-item.disabled, -.list-group-item.disabled:hover, -.list-group-item.disabled:focus { - color: #777; - cursor: not-allowed; - background-color: #eee; -} -.list-group-item.disabled .list-group-item-heading, -.list-group-item.disabled:hover .list-group-item-heading, -.list-group-item.disabled:focus .list-group-item-heading { - color: inherit; -} -.list-group-item.disabled .list-group-item-text, -.list-group-item.disabled:hover .list-group-item-text, -.list-group-item.disabled:focus .list-group-item-text { - color: #777; -} -.list-group-item.active, -.list-group-item.active:hover, -.list-group-item.active:focus { - z-index: 2; - color: #fff; - background-color: #428bca; - border-color: #428bca; -} -.list-group-item.active .list-group-item-heading, -.list-group-item.active:hover .list-group-item-heading, -.list-group-item.active:focus .list-group-item-heading, -.list-group-item.active .list-group-item-heading > small, -.list-group-item.active:hover .list-group-item-heading > small, -.list-group-item.active:focus .list-group-item-heading > small, -.list-group-item.active .list-group-item-heading > .small, -.list-group-item.active:hover .list-group-item-heading > .small, -.list-group-item.active:focus .list-group-item-heading > .small { - color: inherit; -} -.list-group-item.active .list-group-item-text, -.list-group-item.active:hover .list-group-item-text, -.list-group-item.active:focus .list-group-item-text { - color: #e1edf7; -} -.list-group-item-success { - color: #3c763d; - background-color: #dff0d8; -} -a.list-group-item-success { - color: #3c763d; -} -a.list-group-item-success .list-group-item-heading { - color: inherit; -} -a.list-group-item-success:hover, -a.list-group-item-success:focus { - color: #3c763d; - background-color: #d0e9c6; -} -a.list-group-item-success.active, -a.list-group-item-success.active:hover, -a.list-group-item-success.active:focus { - color: #fff; - background-color: #3c763d; - border-color: #3c763d; -} -.list-group-item-info { - color: #31708f; - background-color: #d9edf7; -} -a.list-group-item-info { - color: #31708f; -} -a.list-group-item-info .list-group-item-heading { - color: inherit; -} -a.list-group-item-info:hover, -a.list-group-item-info:focus { - color: #31708f; - background-color: #c4e3f3; -} -a.list-group-item-info.active, -a.list-group-item-info.active:hover, -a.list-group-item-info.active:focus { - color: #fff; - background-color: #31708f; - border-color: #31708f; -} -.list-group-item-warning { - color: #8a6d3b; - background-color: #fcf8e3; -} -a.list-group-item-warning { - color: #8a6d3b; -} -a.list-group-item-warning .list-group-item-heading { - color: inherit; -} -a.list-group-item-warning:hover, -a.list-group-item-warning:focus { - color: #8a6d3b; - background-color: #faf2cc; -} -a.list-group-item-warning.active, -a.list-group-item-warning.active:hover, -a.list-group-item-warning.active:focus { - color: #fff; - background-color: #8a6d3b; - border-color: #8a6d3b; -} -.list-group-item-danger { - color: #a94442; - background-color: #f2dede; -} -a.list-group-item-danger { - color: #a94442; -} -a.list-group-item-danger .list-group-item-heading { - color: inherit; -} -a.list-group-item-danger:hover, -a.list-group-item-danger:focus { - color: #a94442; - background-color: #ebcccc; -} -a.list-group-item-danger.active, -a.list-group-item-danger.active:hover, -a.list-group-item-danger.active:focus { - color: #fff; - background-color: #a94442; - border-color: #a94442; -} -.list-group-item-heading { - margin-top: 0; - margin-bottom: 5px; -} -.list-group-item-text { - margin-bottom: 0; - line-height: 1.3; -} -.panel { - margin-bottom: 20px; - background-color: #fff; - border: 1px solid transparent; - border-radius: 4px; - -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: 0 1px 1px rgba(0, 0, 0, .05); -} -.panel-body { - padding: 15px; -} -.panel-heading { - padding: 10px 15px; - border-bottom: 1px solid transparent; - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel-heading > .dropdown .dropdown-toggle { - color: inherit; -} -.panel-title { - margin-top: 0; - margin-bottom: 0; - font-size: 16px; - color: inherit; -} -.panel-title > a { - color: inherit; -} -.panel-footer { - padding: 10px 15px; - background-color: #f5f5f5; - border-top: 1px solid #ddd; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .list-group, -.panel > .panel-collapse > .list-group { - margin-bottom: 0; -} -.panel > .list-group .list-group-item, -.panel > .panel-collapse > .list-group .list-group-item { - border-width: 1px 0; - border-radius: 0; -} -.panel > .list-group:first-child .list-group-item:first-child, -.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child { - border-top: 0; - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel > .list-group:last-child .list-group-item:last-child, -.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { - border-bottom: 0; - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel-heading + .list-group .list-group-item:first-child { - border-top-width: 0; -} -.list-group + .panel-footer { - border-top-width: 0; -} -.panel > .table, -.panel > .table-responsive > .table, -.panel > .panel-collapse > .table { - margin-bottom: 0; -} -.panel > .table caption, -.panel > .table-responsive > .table caption, -.panel > .panel-collapse > .table caption { - padding-right: 15px; - padding-left: 15px; -} -.panel > .table:first-child, -.panel > .table-responsive:first-child > .table:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child { - border-top-left-radius: 3px; - border-top-right-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { - border-top-left-radius: 3px; -} -.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, -.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, -.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, -.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child { - border-top-right-radius: 3px; -} -.panel > .table:last-child, -.panel > .table-responsive:last-child > .table:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { - border-bottom-left-radius: 3px; -} -.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, -.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, -.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, -.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { - border-bottom-right-radius: 3px; -} -.panel > .panel-body + .table, -.panel > .panel-body + .table-responsive, -.panel > .table + .panel-body, -.panel > .table-responsive + .panel-body { - border-top: 1px solid #ddd; -} -.panel > .table > tbody:first-child > tr:first-child th, -.panel > .table > tbody:first-child > tr:first-child td { - border-top: 0; -} -.panel > .table-bordered, -.panel > .table-responsive > .table-bordered { - border: 0; -} -.panel > .table-bordered > thead > tr > th:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, -.panel > .table-bordered > tbody > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, -.panel > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, -.panel > .table-bordered > thead > tr > td:first-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, -.panel > .table-bordered > tbody > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, -.panel > .table-bordered > tfoot > tr > td:first-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { - border-left: 0; -} -.panel > .table-bordered > thead > tr > th:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, -.panel > .table-bordered > tbody > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, -.panel > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, -.panel > .table-bordered > thead > tr > td:last-child, -.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, -.panel > .table-bordered > tbody > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, -.panel > .table-bordered > tfoot > tr > td:last-child, -.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { - border-right: 0; -} -.panel > .table-bordered > thead > tr:first-child > td, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > td, -.panel > .table-bordered > tbody > tr:first-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td, -.panel > .table-bordered > thead > tr:first-child > th, -.panel > .table-responsive > .table-bordered > thead > tr:first-child > th, -.panel > .table-bordered > tbody > tr:first-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th { - border-bottom: 0; -} -.panel > .table-bordered > tbody > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, -.panel > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td, -.panel > .table-bordered > tbody > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, -.panel > .table-bordered > tfoot > tr:last-child > th, -.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th { - border-bottom: 0; -} -.panel > .table-responsive { - margin-bottom: 0; - border: 0; -} -.panel-group { - margin-bottom: 20px; -} -.panel-group .panel { - margin-bottom: 0; - border-radius: 4px; -} -.panel-group .panel + .panel { - margin-top: 5px; -} -.panel-group .panel-heading { - border-bottom: 0; -} -.panel-group .panel-heading + .panel-collapse > .panel-body, -.panel-group .panel-heading + .panel-collapse > .list-group { - border-top: 1px solid #ddd; -} -.panel-group .panel-footer { - border-top: 0; -} -.panel-group .panel-footer + .panel-collapse .panel-body { - border-bottom: 1px solid #ddd; -} -.panel-default { - border-color: #ddd; -} -.panel-default > .panel-heading { - color: #333; - background-color: #f5f5f5; - border-color: #ddd; -} -.panel-default > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #ddd; -} -.panel-default > .panel-heading .badge { - color: #f5f5f5; - background-color: #333; -} -.panel-default > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #ddd; -} -.panel-primary { - border-color: #428bca; -} -.panel-primary > .panel-heading { - color: #fff; - background-color: #428bca; - border-color: #428bca; -} -.panel-primary > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #428bca; -} -.panel-primary > .panel-heading .badge { - color: #428bca; - background-color: #fff; -} -.panel-primary > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #428bca; -} -.panel-success { - border-color: #d6e9c6; -} -.panel-success > .panel-heading { - color: #3c763d; - background-color: #dff0d8; - border-color: #d6e9c6; -} -.panel-success > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #d6e9c6; -} -.panel-success > .panel-heading .badge { - color: #dff0d8; - background-color: #3c763d; -} -.panel-success > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #d6e9c6; -} -.panel-info { - border-color: #bce8f1; -} -.panel-info > .panel-heading { - color: #31708f; - background-color: #d9edf7; - border-color: #bce8f1; -} -.panel-info > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #bce8f1; -} -.panel-info > .panel-heading .badge { - color: #d9edf7; - background-color: #31708f; -} -.panel-info > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #bce8f1; -} -.panel-warning { - border-color: #faebcc; -} -.panel-warning > .panel-heading { - color: #8a6d3b; - background-color: #fcf8e3; - border-color: #faebcc; -} -.panel-warning > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #faebcc; -} -.panel-warning > .panel-heading .badge { - color: #fcf8e3; - background-color: #8a6d3b; -} -.panel-warning > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #faebcc; -} -.panel-danger { - border-color: #ebccd1; -} -.panel-danger > .panel-heading { - color: #a94442; - background-color: #f2dede; - border-color: #ebccd1; -} -.panel-danger > .panel-heading + .panel-collapse > .panel-body { - border-top-color: #ebccd1; -} -.panel-danger > .panel-heading .badge { - color: #f2dede; - background-color: #a94442; -} -.panel-danger > .panel-footer + .panel-collapse > .panel-body { - border-bottom-color: #ebccd1; -} -.embed-responsive { - position: relative; - display: block; - height: 0; - padding: 0; - overflow: hidden; -} -.embed-responsive .embed-responsive-item, -.embed-responsive iframe, -.embed-responsive embed, -.embed-responsive object, -.embed-responsive video { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - border: 0; -} -.embed-responsive.embed-responsive-16by9 { - padding-bottom: 56.25%; -} -.embed-responsive.embed-responsive-4by3 { - padding-bottom: 75%; -} -.well { - min-height: 20px; - padding: 19px; - margin-bottom: 20px; - background-color: #f5f5f5; - border: 1px solid #e3e3e3; - border-radius: 4px; - -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); - box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); -} -.well blockquote { - border-color: #ddd; - border-color: rgba(0, 0, 0, .15); -} -.well-lg { - padding: 24px; - border-radius: 6px; -} -.well-sm { - padding: 9px; - border-radius: 3px; -} -.close { - float: right; - font-size: 21px; - font-weight: bold; - line-height: 1; - color: #000; - text-shadow: 0 1px 0 #fff; - filter: alpha(opacity=20); - opacity: .2; -} -.close:hover, -.close:focus { - color: #000; - text-decoration: none; - cursor: pointer; - filter: alpha(opacity=50); - opacity: .5; -} -button.close { - -webkit-appearance: none; - padding: 0; - cursor: pointer; - background: transparent; - border: 0; -} -.modal-open { - overflow: hidden; -} -.modal { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - z-index: 1040; - display: none; - overflow: hidden; - -webkit-overflow-scrolling: touch; - outline: 0; -} -.modal.fade .modal-dialog { - -webkit-transition: -webkit-transform .3s ease-out; - -o-transition: -o-transform .3s ease-out; - transition: transform .3s ease-out; - -webkit-transform: translate(0, -25%); - -ms-transform: translate(0, -25%); - -o-transform: translate(0, -25%); - transform: translate(0, -25%); -} -.modal.in .modal-dialog { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - -o-transform: translate(0, 0); - transform: translate(0, 0); -} -.modal-open .modal { - overflow-x: hidden; - overflow-y: auto; -} -.modal-dialog { - position: relative; - width: auto; - margin: 10px; -} -.modal-content { - position: relative; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #999; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - outline: 0; - -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); - box-shadow: 0 3px 9px rgba(0, 0, 0, .5); -} -.modal-backdrop { - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - background-color: #000; -} -.modal-backdrop.fade { - filter: alpha(opacity=0); - opacity: 0; -} -.modal-backdrop.in { - filter: alpha(opacity=50); - opacity: .5; -} -.modal-header { - min-height: 16.42857143px; - padding: 15px; - border-bottom: 1px solid #e5e5e5; -} -.modal-header .close { - margin-top: -2px; -} -.modal-title { - margin: 0; - line-height: 1.42857143; -} -.modal-body { - position: relative; - padding: 15px; -} -.modal-footer { - padding: 15px; - text-align: right; - border-top: 1px solid #e5e5e5; -} -.modal-footer .btn + .btn { - margin-bottom: 0; - margin-left: 5px; -} -.modal-footer .btn-group .btn + .btn { - margin-left: -1px; -} -.modal-footer .btn-block + .btn-block { - margin-left: 0; -} -.modal-scrollbar-measure { - position: absolute; - top: -9999px; - width: 50px; - height: 50px; - overflow: scroll; -} -@media (min-width: 768px) { - .modal-dialog { - width: 600px; - margin: 30px auto; - } - .modal-content { - -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); - box-shadow: 0 5px 15px rgba(0, 0, 0, .5); - } - .modal-sm { - width: 300px; - } -} -@media (min-width: 992px) { - .modal-lg { - width: 900px; - } -} -.tooltip { - position: absolute; - z-index: 1070; - display: block; - font-size: 12px; - line-height: 1.4; - visibility: visible; - filter: alpha(opacity=0); - opacity: 0; -} -.tooltip.in { - filter: alpha(opacity=90); - opacity: .9; -} -.tooltip.top { - padding: 5px 0; - margin-top: -3px; -} -.tooltip.right { - padding: 0 5px; - margin-left: 3px; -} -.tooltip.bottom { - padding: 5px 0; - margin-top: 3px; -} -.tooltip.left { - padding: 0 5px; - margin-left: -3px; -} -.tooltip-inner { - max-width: 200px; - padding: 3px 8px; - color: #fff; - text-align: center; - text-decoration: none; - background-color: #000; - border-radius: 4px; -} -.tooltip-arrow { - position: absolute; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.tooltip.top .tooltip-arrow { - bottom: 0; - left: 50%; - margin-left: -5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.top-left .tooltip-arrow { - bottom: 0; - left: 5px; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.top-right .tooltip-arrow { - right: 5px; - bottom: 0; - border-width: 5px 5px 0; - border-top-color: #000; -} -.tooltip.right .tooltip-arrow { - top: 50%; - left: 0; - margin-top: -5px; - border-width: 5px 5px 5px 0; - border-right-color: #000; -} -.tooltip.left .tooltip-arrow { - top: 50%; - right: 0; - margin-top: -5px; - border-width: 5px 0 5px 5px; - border-left-color: #000; -} -.tooltip.bottom .tooltip-arrow { - top: 0; - left: 50%; - margin-left: -5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.tooltip.bottom-left .tooltip-arrow { - top: 0; - left: 5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.tooltip.bottom-right .tooltip-arrow { - top: 0; - right: 5px; - border-width: 0 5px 5px; - border-bottom-color: #000; -} -.popover { - position: absolute; - top: 0; - left: 0; - z-index: 1060; - display: none; - max-width: 276px; - padding: 1px; - font-size: 14px; - font-weight: normal; - line-height: 1.42857143; - text-align: left; - white-space: normal; - background-color: #fff; - -webkit-background-clip: padding-box; - background-clip: padding-box; - border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, .2); - border-radius: 6px; - -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); - box-shadow: 0 5px 10px rgba(0, 0, 0, .2); -} -.popover.top { - margin-top: -10px; -} -.popover.right { - margin-left: 10px; -} -.popover.bottom { - margin-top: 10px; -} -.popover.left { - margin-left: -10px; -} -.popover-title { - padding: 8px 14px; - margin: 0; - font-size: 14px; - background-color: #f7f7f7; - border-bottom: 1px solid #ebebeb; - border-radius: 5px 5px 0 0; -} -.popover-content { - padding: 9px 14px; -} -.popover > .arrow, -.popover > .arrow:after { - position: absolute; - display: block; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; -} -.popover > .arrow { - border-width: 11px; -} -.popover > .arrow:after { - content: ""; - border-width: 10px; -} -.popover.top > .arrow { - bottom: -11px; - left: 50%; - margin-left: -11px; - border-top-color: #999; - border-top-color: rgba(0, 0, 0, .25); - border-bottom-width: 0; -} -.popover.top > .arrow:after { - bottom: 1px; - margin-left: -10px; - content: " "; - border-top-color: #fff; - border-bottom-width: 0; -} -.popover.right > .arrow { - top: 50%; - left: -11px; - margin-top: -11px; - border-right-color: #999; - border-right-color: rgba(0, 0, 0, .25); - border-left-width: 0; -} -.popover.right > .arrow:after { - bottom: -10px; - left: 1px; - content: " "; - border-right-color: #fff; - border-left-width: 0; -} -.popover.bottom > .arrow { - top: -11px; - left: 50%; - margin-left: -11px; - border-top-width: 0; - border-bottom-color: #999; - border-bottom-color: rgba(0, 0, 0, .25); -} -.popover.bottom > .arrow:after { - top: 1px; - margin-left: -10px; - content: " "; - border-top-width: 0; - border-bottom-color: #fff; -} -.popover.left > .arrow { - top: 50%; - right: -11px; - margin-top: -11px; - border-right-width: 0; - border-left-color: #999; - border-left-color: rgba(0, 0, 0, .25); -} -.popover.left > .arrow:after { - right: 1px; - bottom: -10px; - content: " "; - border-right-width: 0; - border-left-color: #fff; -} -.carousel { - position: relative; -} -.carousel-inner { - position: relative; - width: 100%; - overflow: hidden; -} -.carousel-inner > .item { - position: relative; - display: none; - -webkit-transition: .6s ease-in-out left; - -o-transition: .6s ease-in-out left; - transition: .6s ease-in-out left; -} -.carousel-inner > .item > img, -.carousel-inner > .item > a > img { - line-height: 1; -} -@media all and (transform-3d), (-webkit-transform-3d) { - .carousel-inner > .item { - -webkit-transition: -webkit-transform .6s ease-in-out; - -o-transition: -o-transform .6s ease-in-out; - transition: transform .6s ease-in-out; - - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - -webkit-perspective: 1000; - perspective: 1000; - } - .carousel-inner > .item.next, - .carousel-inner > .item.active.right { - left: 0; - -webkit-transform: translate3d(100%, 0, 0); - transform: translate3d(100%, 0, 0); - } - .carousel-inner > .item.prev, - .carousel-inner > .item.active.left { - left: 0; - -webkit-transform: translate3d(-100%, 0, 0); - transform: translate3d(-100%, 0, 0); - } - .carousel-inner > .item.next.left, - .carousel-inner > .item.prev.right, - .carousel-inner > .item.active { - left: 0; - -webkit-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - } -} -.carousel-inner > .active, -.carousel-inner > .next, -.carousel-inner > .prev { - display: block; -} -.carousel-inner > .active { - left: 0; -} -.carousel-inner > .next, -.carousel-inner > .prev { - position: absolute; - top: 0; - width: 100%; -} -.carousel-inner > .next { - left: 100%; -} -.carousel-inner > .prev { - left: -100%; -} -.carousel-inner > .next.left, -.carousel-inner > .prev.right { - left: 0; -} -.carousel-inner > .active.left { - left: -100%; -} -.carousel-inner > .active.right { - left: 100%; -} -.carousel-control { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 15%; - font-size: 20px; - color: #fff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, .6); - filter: alpha(opacity=50); - opacity: .5; -} -.carousel-control.left { - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .5)), to(rgba(0, 0, 0, .0001))); - background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); - background-repeat: repeat-x; -} -.carousel-control.right { - right: 0; - left: auto; - background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); - background-image: -o-linear-gradient(left, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); - background-image: -webkit-gradient(linear, left top, right top, from(rgba(0, 0, 0, .0001)), to(rgba(0, 0, 0, .5))); - background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); - background-repeat: repeat-x; -} -.carousel-control:hover, -.carousel-control:focus { - color: #fff; - text-decoration: none; - filter: alpha(opacity=90); - outline: 0; - opacity: .9; -} -.carousel-control .icon-prev, -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-left, -.carousel-control .glyphicon-chevron-right { - position: absolute; - top: 50%; - z-index: 5; - display: inline-block; -} -.carousel-control .icon-prev, -.carousel-control .glyphicon-chevron-left { - left: 50%; - margin-left: -10px; -} -.carousel-control .icon-next, -.carousel-control .glyphicon-chevron-right { - right: 50%; - margin-right: -10px; -} -.carousel-control .icon-prev, -.carousel-control .icon-next { - width: 20px; - height: 20px; - margin-top: -10px; - font-family: serif; -} -.carousel-control .icon-prev:before { - content: '\2039'; -} -.carousel-control .icon-next:before { - content: '\203a'; -} -.carousel-indicators { - position: absolute; - bottom: 10px; - left: 50%; - z-index: 15; - width: 60%; - padding-left: 0; - margin-left: -30%; - text-align: center; - list-style: none; -} -.carousel-indicators li { - display: inline-block; - width: 10px; - height: 10px; - margin: 1px; - text-indent: -999px; - cursor: pointer; - background-color: #000 \9; - background-color: rgba(0, 0, 0, 0); - border: 1px solid #fff; - border-radius: 10px; -} -.carousel-indicators .active { - width: 12px; - height: 12px; - margin: 0; - background-color: #fff; -} -.carousel-caption { - position: absolute; - right: 15%; - bottom: 20px; - left: 15%; - z-index: 10; - padding-top: 20px; - padding-bottom: 20px; - color: #fff; - text-align: center; - text-shadow: 0 1px 2px rgba(0, 0, 0, .6); -} -.carousel-caption .btn { - text-shadow: none; -} -@media screen and (min-width: 768px) { - .carousel-control .glyphicon-chevron-left, - .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-prev, - .carousel-control .icon-next { - width: 30px; - height: 30px; - margin-top: -15px; - font-size: 30px; - } - .carousel-control .glyphicon-chevron-left, - .carousel-control .icon-prev { - margin-left: -15px; - } - .carousel-control .glyphicon-chevron-right, - .carousel-control .icon-next { - margin-right: -15px; - } - .carousel-caption { - right: 20%; - left: 20%; - padding-bottom: 30px; - } - .carousel-indicators { - bottom: 20px; - } -} -.clearfix:before, -.clearfix:after, -.dl-horizontal dd:before, -.dl-horizontal dd:after, -.container:before, -.container:after, -.container-fluid:before, -.container-fluid:after, -.row:before, -.row:after, -.form-horizontal .form-group:before, -.form-horizontal .form-group:after, -.btn-toolbar:before, -.btn-toolbar:after, -.btn-group-vertical > .btn-group:before, -.btn-group-vertical > .btn-group:after, -.nav:before, -.nav:after, -.navbar:before, -.navbar:after, -.navbar-header:before, -.navbar-header:after, -.navbar-collapse:before, -.navbar-collapse:after, -.pager:before, -.pager:after, -.panel-body:before, -.panel-body:after, -.modal-footer:before, -.modal-footer:after { - display: table; - content: " "; -} -.clearfix:after, -.dl-horizontal dd:after, -.container:after, -.container-fluid:after, -.row:after, -.form-horizontal .form-group:after, -.btn-toolbar:after, -.btn-group-vertical > .btn-group:after, -.nav:after, -.navbar:after, -.navbar-header:after, -.navbar-collapse:after, -.pager:after, -.panel-body:after, -.modal-footer:after { - clear: both; -} -.center-block { - display: block; - margin-right: auto; - margin-left: auto; -} -.pull-right { - float: right !important; -} -.pull-left { - float: left !important; -} -.hide { - display: none !important; -} -.show { - display: block !important; -} -.invisible { - visibility: hidden; -} -.text-hide { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} -.hidden { - display: none !important; - visibility: hidden !important; -} -.affix { - position: fixed; -} -@-ms-viewport { - width: device-width; -} -.visible-xs, -.visible-sm, -.visible-md, -.visible-lg { - display: none !important; -} -.visible-xs-block, -.visible-xs-inline, -.visible-xs-inline-block, -.visible-sm-block, -.visible-sm-inline, -.visible-sm-inline-block, -.visible-md-block, -.visible-md-inline, -.visible-md-inline-block, -.visible-lg-block, -.visible-lg-inline, -.visible-lg-inline-block { - display: none !important; -} -@media (max-width: 767px) { - .visible-xs { - display: block !important; - } - table.visible-xs { - display: table; - } - tr.visible-xs { - display: table-row !important; - } - th.visible-xs, - td.visible-xs { - display: table-cell !important; - } -} -@media (max-width: 767px) { - .visible-xs-block { - display: block !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline { - display: inline !important; - } -} -@media (max-width: 767px) { - .visible-xs-inline-block { - display: inline-block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm { - display: block !important; - } - table.visible-sm { - display: table; - } - tr.visible-sm { - display: table-row !important; - } - th.visible-sm, - td.visible-sm { - display: table-cell !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-block { - display: block !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline { - display: inline !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .visible-sm-inline-block { - display: inline-block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md { - display: block !important; - } - table.visible-md { - display: table; - } - tr.visible-md { - display: table-row !important; - } - th.visible-md, - td.visible-md { - display: table-cell !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-block { - display: block !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline { - display: inline !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .visible-md-inline-block { - display: inline-block !important; - } -} -@media (min-width: 1200px) { - .visible-lg { - display: block !important; - } - table.visible-lg { - display: table; - } - tr.visible-lg { - display: table-row !important; - } - th.visible-lg, - td.visible-lg { - display: table-cell !important; - } -} -@media (min-width: 1200px) { - .visible-lg-block { - display: block !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline { - display: inline !important; - } -} -@media (min-width: 1200px) { - .visible-lg-inline-block { - display: inline-block !important; - } -} -@media (max-width: 767px) { - .hidden-xs { - display: none !important; - } -} -@media (min-width: 768px) and (max-width: 991px) { - .hidden-sm { - display: none !important; - } -} -@media (min-width: 992px) and (max-width: 1199px) { - .hidden-md { - display: none !important; - } -} -@media (min-width: 1200px) { - .hidden-lg { - display: none !important; - } -} -.visible-print { - display: none !important; -} -@media print { - .visible-print { - display: block !important; - } - table.visible-print { - display: table; - } - tr.visible-print { - display: table-row !important; - } - th.visible-print, - td.visible-print { - display: table-cell !important; - } -} -.visible-print-block { - display: none !important; -} -@media print { - .visible-print-block { - display: block !important; - } -} -.visible-print-inline { - display: none !important; -} -@media print { - .visible-print-inline { - display: inline !important; - } -} -.visible-print-inline-block { - display: none !important; -} -@media print { - .visible-print-inline-block { - display: inline-block !important; - } -} -@media print { - .hidden-print { - display: none !important; - } -} -/*# sourceMappingURL=bootstrap.css.map */ diff --git a/output/theme/css/bootstrap.min.css b/output/theme/css/bootstrap.min.css deleted file mode 100644 index 4af8905..0000000 --- a/output/theme/css/bootstrap.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Bootstrap v3.3.0 (http://getbootstrap.com) - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - *//*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0}/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:before,:after{color:#000!important;text-shadow:none!important;background:transparent!important;-webkit-box-shadow:none!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before,.glyphicon-eur:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.42857143;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive,.thumbnail>img,.thumbnail a>img,.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;max-width:100%;height:auto;padding:4px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#777}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}mark,.mark{padding:.2em;background-color:#fcf8e3}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;margin-left:-5px;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.42857143}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;text-align:right;border-right:5px solid #eee;border-left:0}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.42857143}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.25);box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;-webkit-box-shadow:none;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.42857143;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{margin-right:-15px;margin-left:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666667%}.col-xs-10{width:83.33333333%}.col-xs-9{width:75%}.col-xs-8{width:66.66666667%}.col-xs-7{width:58.33333333%}.col-xs-6{width:50%}.col-xs-5{width:41.66666667%}.col-xs-4{width:33.33333333%}.col-xs-3{width:25%}.col-xs-2{width:16.66666667%}.col-xs-1{width:8.33333333%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666667%}.col-xs-pull-10{right:83.33333333%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666667%}.col-xs-pull-7{right:58.33333333%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666667%}.col-xs-pull-4{right:33.33333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.66666667%}.col-xs-pull-1{right:8.33333333%}.col-xs-pull-0{right:auto}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666667%}.col-xs-push-10{left:83.33333333%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666667%}.col-xs-push-7{left:58.33333333%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666667%}.col-xs-push-4{left:33.33333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.66666667%}.col-xs-push-1{left:8.33333333%}.col-xs-push-0{left:auto}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666667%}.col-xs-offset-10{margin-left:83.33333333%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666667%}.col-xs-offset-7{margin-left:58.33333333%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666667%}.col-xs-offset-4{margin-left:33.33333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.66666667%}.col-xs-offset-1{margin-left:8.33333333%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666667%}.col-sm-10{width:83.33333333%}.col-sm-9{width:75%}.col-sm-8{width:66.66666667%}.col-sm-7{width:58.33333333%}.col-sm-6{width:50%}.col-sm-5{width:41.66666667%}.col-sm-4{width:33.33333333%}.col-sm-3{width:25%}.col-sm-2{width:16.66666667%}.col-sm-1{width:8.33333333%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666667%}.col-sm-pull-10{right:83.33333333%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666667%}.col-sm-pull-7{right:58.33333333%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666667%}.col-sm-pull-4{right:33.33333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.66666667%}.col-sm-pull-1{right:8.33333333%}.col-sm-pull-0{right:auto}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666667%}.col-sm-push-10{left:83.33333333%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666667%}.col-sm-push-7{left:58.33333333%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666667%}.col-sm-push-4{left:33.33333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.66666667%}.col-sm-push-1{left:8.33333333%}.col-sm-push-0{left:auto}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666667%}.col-sm-offset-10{margin-left:83.33333333%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666667%}.col-sm-offset-7{margin-left:58.33333333%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666667%}.col-sm-offset-4{margin-left:33.33333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.66666667%}.col-sm-offset-1{margin-left:8.33333333%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666667%}.col-md-10{width:83.33333333%}.col-md-9{width:75%}.col-md-8{width:66.66666667%}.col-md-7{width:58.33333333%}.col-md-6{width:50%}.col-md-5{width:41.66666667%}.col-md-4{width:33.33333333%}.col-md-3{width:25%}.col-md-2{width:16.66666667%}.col-md-1{width:8.33333333%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666667%}.col-md-pull-10{right:83.33333333%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666667%}.col-md-pull-7{right:58.33333333%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666667%}.col-md-pull-4{right:33.33333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.66666667%}.col-md-pull-1{right:8.33333333%}.col-md-pull-0{right:auto}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666667%}.col-md-push-10{left:83.33333333%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666667%}.col-md-push-7{left:58.33333333%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666667%}.col-md-push-4{left:33.33333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.66666667%}.col-md-push-1{left:8.33333333%}.col-md-push-0{left:auto}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666667%}.col-md-offset-10{margin-left:83.33333333%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666667%}.col-md-offset-7{margin-left:58.33333333%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666667%}.col-md-offset-4{margin-left:33.33333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.66666667%}.col-md-offset-1{margin-left:8.33333333%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666667%}.col-lg-10{width:83.33333333%}.col-lg-9{width:75%}.col-lg-8{width:66.66666667%}.col-lg-7{width:58.33333333%}.col-lg-6{width:50%}.col-lg-5{width:41.66666667%}.col-lg-4{width:33.33333333%}.col-lg-3{width:25%}.col-lg-2{width:16.66666667%}.col-lg-1{width:8.33333333%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666667%}.col-lg-pull-10{right:83.33333333%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666667%}.col-lg-pull-7{right:58.33333333%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666667%}.col-lg-pull-4{right:33.33333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.66666667%}.col-lg-pull-1{right:8.33333333%}.col-lg-pull-0{right:auto}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666667%}.col-lg-push-10{left:83.33333333%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666667%}.col-lg-push-7{left:58.33333333%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666667%}.col-lg-push-4{left:33.33333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.66666667%}.col-lg-push-1{left:8.33333333%}.col-lg-push-0{left:auto}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666667%}.col-lg-offset-10{margin-left:83.33333333%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666667%}.col-lg-offset-7{margin-left:58.33333333%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666667%}.col-lg-offset-4{margin-left:33.33333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.66666667%}.col-lg-offset-1{margin-left:8.33333333%}.col-lg-offset-0{margin-left:0}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.42857143;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;display:table-column;float:none}table td[class*=col-],table th[class*=col-]{position:static;display:table-cell;float:none}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{min-height:.01%;overflow-x:auto}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.42857143;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{line-height:34px;line-height:1.42857143 \0}input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px;line-height:1.5 \0}input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px;line-height:1.33 \0}_:-ms-fullscreen,:root input[type=date],_:-ms-fullscreen,:root input[type=time],_:-ms-fullscreen,:root input[type=datetime-local],_:-ms-fullscreen,:root input[type=month]{line-height:1.42857143}_:-ms-fullscreen.input-sm,:root input[type=date].input-sm,_:-ms-fullscreen.input-sm,:root input[type=time].input-sm,_:-ms-fullscreen.input-sm,:root input[type=datetime-local].input-sm,_:-ms-fullscreen.input-sm,:root input[type=month].input-sm{line-height:1.5}_:-ms-fullscreen.input-lg,:root input[type=date].input-lg,_:-ms-fullscreen.input-lg,:root input[type=time].input-lg,_:-ms-fullscreen.input-lg,:root input[type=datetime-local].input-lg,_:-ms-fullscreen.input-lg,:root input[type=month].input-lg{line-height:1.33}.form-group{margin-bottom:15px}.radio,.checkbox{position:relative;display:block;margin-top:10px;margin-bottom:10px}.radio label,.checkbox label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{position:absolute;margin-top:4px \9;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],input[type=radio].disabled,input[type=checkbox].disabled,fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox]{cursor:not-allowed}.radio-inline.disabled,.checkbox-inline.disabled,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.radio.disabled label,.checkbox.disabled label,fieldset[disabled] .radio label,fieldset[disabled] .checkbox label{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0}.form-control-static.input-lg,.form-control-static.input-sm{padding-right:0;padding-left:0}.input-sm,.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm,select.form-group-sm .form-control{height:30px;line-height:30px}textarea.input-sm,textarea.form-group-sm .form-control,select[multiple].input-sm,select[multiple].form-group-sm .form-control{height:auto}.input-lg,.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg,select.form-group-lg .form-control{height:46px;line-height:46px}textarea.input-lg,textarea.form-group-lg .form-control,select[multiple].input-lg,select[multiple].form-group-lg .form-control{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline,.has-success.radio label,.has-success.checkbox label,.has-success.radio-inline label,.has-success.checkbox-inline label{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;background-color:#dff0d8;border-color:#3c763d}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline,.has-warning.radio label,.has-warning.checkbox label,.has-warning.radio-inline label,.has-warning.checkbox-inline label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;background-color:#fcf8e3;border-color:#8a6d3b}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline,.has-error.radio label,.has-error.checkbox label,.has-error.radio-inline label,.has-error.checkbox-inline label{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;background-color:#f2dede;border-color:#a94442}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn,.form-inline .input-group .form-control{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .radio label,.form-inline .checkbox label{padding-left:0}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.form-horizontal .control-label{padding-top:7px;margin-bottom:0;text-align:right}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:14.3px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px}}.btn{display:inline-block;padding:6px 12px;margin-bottom:0;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-image:none;border:1px solid transparent;border-radius:4px}.btn:focus,.btn:active:focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn.active.focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus,.btn.focus{color:#333;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default.focus,.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary.focus,.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#3071a9;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success.focus,.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info.focus,.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning.focus,.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger.focus,.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#428bca;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none;visibility:hidden}.collapse.in{display:block;visibility:visible}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-timing-function:ease;-o-transition-timing-function:ease;transition-timing-function:ease;-webkit-transition-duration:.35s;-o-transition-duration:.35s;transition-duration:.35s;-webkit-transition-property:height,visibility;-o-transition-property:height,visibility;transition-property:height,visibility}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.42857143;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#428bca;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#777}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{right:0;left:auto}.dropdown-menu-left{right:auto;left:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.42857143;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{content:"";border-top:0;border-bottom:4px solid}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{right:auto;left:0}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-top-left-radius:0;border-bottom-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-left-radius:0;border-top-right-radius:0;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-left-radius:0;border-top-right-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=radio],[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-right:0;padding-left:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.42857143;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none;visibility:hidden}.tab-content>.active{display:block;visibility:visible}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{padding-right:15px;padding-left:15px;overflow-x:visible;-webkit-overflow-scrolling:touch;border-top:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1)}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;-webkit-box-shadow:none;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important;visibility:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{max-height:200px}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;height:50px;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{padding:10px 15px;margin-top:8px;margin-right:-15px;margin-bottom:8px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn,.navbar-form .input-group .form-control{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .radio label,.navbar-form .checkbox label{padding-left:0}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#555;background-color:#e7e7e7}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#080808}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:hover,.navbar-inverse .btn-link:focus{color:#fff}.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:hover,.navbar-inverse .btn-link[disabled]:focus,fieldset[disabled] .navbar-inverse .btn-link:focus{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;margin-left:-1px;line-height:1.42857143;color:#428bca;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-top-left-radius:4px;border-bottom-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;cursor:default;background-color:#428bca;border-color:#428bca}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#777;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-top-left-radius:6px;border-bottom-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-top-left-radius:3px;border-bottom-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#777;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}a.label:hover,a.label:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#777}.label-default[href]:hover,.label-default[href]:focus{background-color:#5e5e5e}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px 15px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container .jumbotron,.container-fluid .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding:48px 0}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.42857143;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:border .2s ease-in-out;-o-transition:border .2s ease-in-out;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar,.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;background-size:40px 40px}.progress.active .progress-bar,.progress-bar.active{-webkit-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-left,.media-right,.media-body{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{color:#555;text-decoration:none;background-color:#f5f5f5}.list-group-item.disabled,.list-group-item.disabled:hover,.list-group-item.disabled:focus{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:hover,.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}.list-group-item.active .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>.small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:hover .list-group-item-text,.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.list-group,.panel>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-left-radius:3px;border-top-right-radius:3px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.table,.panel>.table-responsive>.table,.panel>.panel-collapse>.table{margin-bottom:0}.panel>.table caption,.panel>.table-responsive>.table caption,.panel>.panel-collapse>.table caption{padding-right:15px;padding-left:15px}.panel>.table:first-child,.panel>.table-responsive:first-child>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table:last-child,.panel>.table-responsive:last-child>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-group{margin-bottom:20px}.panel-group .panel{margin-bottom:0;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.panel-body,.panel-group .panel-heading+.panel-collapse>.list-group{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#428bca}.panel-primary>.panel-heading .badge{color:#428bca;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive iframe,.embed-responsive embed,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20);opacity:.2}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;filter:alpha(opacity=50);opacity:.5}button.close{-webkit-appearance:none;padding:0;cursor:pointer;background:0 0;border:0}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:hidden;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transition:-webkit-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out;-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);-o-transform:translate(0,-25%);transform:translate(0,-25%)}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);-o-transform:translate(0,0);transform:translate(0,0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background-color:#000}.modal-backdrop.fade{filter:alpha(opacity=0);opacity:0}.modal-backdrop.in{filter:alpha(opacity=50);opacity:.5}.modal-header{min-height:16.43px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857143}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-size:12px;line-height:1.4;visibility:visible;filter:alpha(opacity=0);opacity:0}.tooltip.in{filter:alpha(opacity=90);opacity:.9}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-size:14px;font-weight:400;line-height:1.42857143;text-align:left;white-space:normal;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{content:"";border-width:10px}.popover.top>.arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,.25);border-bottom-width:0}.popover.top>.arrow:after{bottom:1px;margin-left:-10px;content:" ";border-top-color:#fff;border-bottom-width:0}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,.25);border-left-width:0}.popover.right>.arrow:after{bottom:-10px;left:1px;content:" ";border-right-color:#fff;border-left-width:0}.popover.bottom>.arrow{top:-11px;left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25)}.popover.bottom>.arrow:after{top:1px;margin-left:-10px;content:" ";border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{right:1px;bottom:-10px;content:" ";border-right-width:0;border-left-color:#fff}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.next,.carousel-inner>.item.active.right{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.prev,.carousel-inner>.item.active.left{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right,.carousel-inner>.item.active{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);filter:alpha(opacity=50);opacity:.5}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);background-repeat:repeat-x}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);background-repeat:repeat-x}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%;margin-left:-10px}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%;margin-right:-10px}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.dl-horizontal dd:before,.dl-horizontal dd:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{display:table;content:" "}.clearfix:after,.dl-horizontal dd:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,.visible-sm,.visible-md,.visible-lg{display:none!important}.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}} \ No newline at end of file diff --git a/output/theme/css/clean-blog.css b/output/theme/css/clean-blog.css deleted file mode 100644 index f5bed26..0000000 --- a/output/theme/css/clean-blog.css +++ /dev/null @@ -1,410 +0,0 @@ -/*! - * Clean Blog v1.0.0 (http://startbootstrap.com) - * Copyright 2014 Start Bootstrap - * Licensed under Apache 2.0 (https://github.com/IronSummitMedia/startbootstrap/blob/gh-pages/LICENSE) - */ - -body { - font-family: 'Open Sans', 'Lora','Times New Roman',serif; - font-size: 18px; - font-weight: 500; - color: #404040; -} - -p { - line-height: 1.5; - margin: 30px 0; -} -p a { - text-decoration: underline; -} -h1, -h2, -h3, -h4, -h5, -h6 { - font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - font-weight: 800; -} -a { - color: #0085a1; -} -a:hover, -a:focus { - color: #0057a2; -} -a img:hover, -a img:focus { - cursor: zoom-in; -} -blockquote { - color: #808080; - font-style: italic; -} -pre { - background-color: transparent; - font-size: 16px; -} -hr.small { - max-width: 100px; - margin: 15px auto; - border-width: 4px; - border-color: white; -} -.navbar-custom { - position: absolute; - top: 0; - left: 0; - width: 100%; - z-index: 3; - font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; -} -.navbar-custom .navbar-brand { - font-weight: 800; -} -.navbar-custom .nav li a { - text-transform: uppercase; - font-size: 12px; - font-weight: 800; - letter-spacing: 1px; -} -@media only screen and (min-width: 768px) { - .navbar-custom { - background: transparent; - border-bottom: 1px solid transparent; - } - .navbar-custom .navbar-brand { - color: white; - padding: 20px; - } - .navbar-custom .navbar-brand:hover, - .navbar-custom .navbar-brand:focus { - color: rgba(255, 255, 255, 0.8); - } - .navbar-custom .nav li a { - color: white; - padding: 20px; - } - .navbar-custom .nav li a:hover, - .navbar-custom .nav li a:focus { - color: rgba(255, 255, 255, 0.8); - } -} -@media only screen and (min-width: 1170px) { - .navbar-custom { - -webkit-transition: background-color 0.3s; - -moz-transition: background-color 0.3s; - transition: background-color 0.3s; - /* Force Hardware Acceleration in WebKit */ - -webkit-transform: translate3d(0, 0, 0); - -moz-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - -o-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - -webkit-backface-visibility: hidden; - backface-visibility: hidden; - } - .navbar-custom.is-fixed { - /* when the user scrolls down, we hide the header right above the viewport */ - position: fixed; - top: -61px; - background-color: rgba(255, 255, 255, 0.9); - border-bottom: 1px solid #f2f2f2; - -webkit-transition: -webkit-transform 0.3s; - -moz-transition: -moz-transform 0.3s; - transition: transform 0.3s; - } - .navbar-custom.is-fixed .navbar-brand { - color: #404040; - } - .navbar-custom.is-fixed .navbar-brand:hover, - .navbar-custom.is-fixed .navbar-brand:focus { - color: #0085a1; - } - .navbar-custom.is-fixed .nav li a { - color: #404040; - } - .navbar-custom.is-fixed .nav li a:hover, - .navbar-custom.is-fixed .nav li a:focus { - color: #0085a1; - } - .navbar-custom.is-visible { - /* if the user changes the scrolling direction, we show the header */ - -webkit-transform: translate3d(0, 100%, 0); - -moz-transform: translate3d(0, 100%, 0); - -ms-transform: translate3d(0, 100%, 0); - -o-transform: translate3d(0, 100%, 0); - transform: translate3d(0, 100%, 0); - } -} -.intro-header { - background-color: #808080; - background: no-repeat center center; - background-attachment: scroll; - -webkit-background-size: cover; - -moz-background-size: cover; - background-size: cover; - -o-background-size: cover; - margin-bottom: 50px; -} -.intro-header .site-heading, -.intro-header .post-heading, -.intro-header .page-heading { - padding: 100px 0 50px; - color: white; -} -@media only screen and (min-width: 768px) { - .intro-header .site-heading, - .intro-header .post-heading, - .intro-header .page-heading { - padding: 150px 0; - } -} -.intro-header .site-heading, -.intro-header .page-heading { - text-align: center; -} -.intro-header .site-heading h1, -.intro-header .page-heading h1 { - margin-top: 0; - font-size: 50px; -} -.intro-header .site-heading .subheading, -.intro-header .page-heading .subheading { - font-size: 24px; - line-height: 1.1, - display: block; - font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - font-weight: 300; - margin: 10px 0 0; -} -@media only screen and (min-width: 768px) { - .intro-header .site-heading h1, - .intro-header .page-heading h1 { - font-size: 80px; - } -} -.intro-header .post-heading h1 { - font-size: 35px; -} -.intro-header .post-heading .subheading, -.intro-header .post-heading .meta { - line-height: 1.1; - display: block; -} -.intro-header .post-heading .subheading { - font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - font-size: 24px; - margin: 10px 0 30px; - font-weight: 600; -} -.intro-header .post-heading .meta { - font-family: 'Lora', 'Times New Roman', serif; - font-style: italic; - font-weight: 300; - font-size: 20px; -} -.intro-header .post-heading .meta a { - color: white; -} -@media only screen and (min-width: 768px) { - .intro-header .post-heading h1 { - font-size: 55px; - } - .intro-header .post-heading .subheading { - font-size: 30px; - } -} -.post-preview > a { - color: #404040; -} -.post-preview > a:hover, -.post-preview > a:focus { - text-decoration: none; - color: #0085a1; -} -.post-preview > a > .post-title { - font-size: 30px; - margin-top: 30px; - margin-bottom: 10px; -} -.post-preview > a > .post-subtitle { - margin: 0; - font-weight: 300; - margin-bottom: 10px; -} -.post-preview > .post-meta { - color: #808080; - font-size: 18px; - font-style: italic; - margin-top: 0; -} -.post-preview > .post-meta > a { - text-decoration: none; - color: #404040; -} -.post-preview > .post-meta > a:hover, -.post-preview > .post-meta > a:focus { - color: #0085a1; - text-decoration: underline; -} -@media only screen and (min-width: 768px) { - .post-preview > a > .post-title { - font-size: 36px; - } -} -.section-heading { - font-size: 36px; - margin-top: 60px; - font-weight: 700; -} -.caption { - text-align: center; - font-size: 14px; - padding: 10px; - font-style: italic; - margin: 0; - display: block; - border-bottom-right-radius: 5px; - border-bottom-left-radius: 5px; -} -footer { - padding: 50px 0 65px; -} -footer .list-inline { - margin: 0; - padding: 0; -} -footer .copyright { - font-size: 14px; - text-align: center; - margin-bottom: 0; -} -.floating-label-form-group { - font-size: 14px; - position: relative; - margin-bottom: 0; - padding-bottom: 0.5em; - border-bottom: 1px solid #eeeeee; -} -.floating-label-form-group input, -.floating-label-form-group textarea { - z-index: 1; - position: relative; - padding-right: 0; - padding-left: 0; - border: none; - border-radius: 0; - font-size: 1.5em; - background: none; - box-shadow: none !important; - resize: none; -} -.floating-label-form-group label { - display: block; - z-index: 0; - position: relative; - top: 2em; - margin: 0; - font-size: 0.85em; - line-height: 1.764705882em; - vertical-align: middle; - vertical-align: baseline; - opacity: 0; - -webkit-transition: top 0.3s ease,opacity 0.3s ease; - -moz-transition: top 0.3s ease,opacity 0.3s ease; - -ms-transition: top 0.3s ease,opacity 0.3s ease; - transition: top 0.3s ease,opacity 0.3s ease; -} -.floating-label-form-group::not(:first-child) { - padding-left: 14px; - border-left: 1px solid #eeeeee; -} -.floating-label-form-group-with-value label { - top: 0; - opacity: 1; -} -.floating-label-form-group-with-focus label { - color: #0085a1; -} -form .row:first-child .floating-label-form-group { - border-top: 1px solid #eeeeee; -} -.btn { - font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - text-transform: uppercase; - font-size: 14px; - font-weight: 800; - letter-spacing: 1px; - border-radius: 0; - padding: 15px 25px; -} -.btn-lg { - font-size: 16px; - padding: 25px 35px; -} -.btn-default:hover, -.btn-default:focus { - background-color: #0085a1; - border: 1px solid #0085a1; - color: white; -} -.pager { - margin: 20px 0 0; -} -.pager li > a, -.pager li > span { - font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; - text-transform: uppercase; - font-size: 14px; - font-weight: 800; - letter-spacing: 1px; - padding: 15px 25px; - background-color: white; - border-radius: 0; -} -.pager li > a:hover, -.pager li > a:focus { - color: white; - background-color: #0085a1; - border: 1px solid #0085a1; -} -.pager .disabled > a, -.pager .disabled > a:hover, -.pager .disabled > a:focus, -.pager .disabled > span { - color: #808080; - background-color: #404040; - cursor: not-allowed; -} -::-moz-selection { - color: white; - text-shadow: none; - background: #0085a1; -} -::selection { - color: white; - text-shadow: none; - background: #0085a1; -} -img { - max-width: 100%; - height: auto; - width: auto\9; /* ie8 */ -} -img::selection { - color: white; - background: transparent; -} -img::-moz-selection { - color: white; - background: transparent; -} -body { - webkit-tap-highlight-color: #0085a1; -} -.article-summary { - padding-top:10px; - padding-bottom: 10px; -} \ No newline at end of file diff --git a/output/theme/css/clean-blog.min.css b/output/theme/css/clean-blog.min.css deleted file mode 100644 index eca42a4..0000000 --- a/output/theme/css/clean-blog.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Clean Blog v1.0.0 (http://startbootstrap.com) - * Copyright 2014 Start Bootstrap - * Licensed under Apache 2.0 (https://github.com/IronSummitMedia/startbootstrap/blob/gh-pages/LICENSE) - */.caption,.intro-header .page-heading,.intro-header .site-heading,footer .copyright{text-align:center}body{font-family:'Open Sans',Lora,'Times New Roman',serif;font-size:18px;font-weight:500;color:#404040;webkit-tap-highlight-color:#0085a1}.intro-header .page-heading .subheading,.intro-header .post-heading .subheading,.intro-header .site-heading .subheading,.navbar-custom,h1,h2,h3,h4,h5,h6{font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif}p{line-height:1.5;margin:30px 0}p a{text-decoration:underline}h1,h2,h3,h4,h5,h6{font-weight:800}a{color:#0085a1}a:focus,a:hover{color:#0057a2}a img:focus,a img:hover{cursor:zoom-in}blockquote{color:grey;font-style:italic}pre{background-color:transparent;font-size:16px}hr.small{max-width:100px;margin:15px auto;border-width:4px;border-color:#fff}.navbar-custom{position:absolute;top:0;left:0;width:100%;z-index:3}.navbar-custom .navbar-brand{font-weight:800}.navbar-custom .nav li a{text-transform:uppercase;font-size:12px;font-weight:800;letter-spacing:1px}@media only screen and (min-width:768px){.navbar-custom{background:0 0;border-bottom:1px solid transparent}.navbar-custom .navbar-brand{color:#fff;padding:20px}.navbar-custom .navbar-brand:focus,.navbar-custom .navbar-brand:hover{color:rgba(255,255,255,.8)}.navbar-custom .nav li a{color:#fff;padding:20px}.navbar-custom .nav li a:focus,.navbar-custom .nav li a:hover{color:rgba(255,255,255,.8)}}@media only screen and (min-width:1170px){.navbar-custom{-webkit-transition:background-color .3s;-moz-transition:background-color .3s;transition:background-color .3s;-webkit-transform:translate3d(0,0,0);-moz-transform:translate3d(0,0,0);-ms-transform:translate3d(0,0,0);-o-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-webkit-backface-visibility:hidden;backface-visibility:hidden}.navbar-custom.is-fixed{position:fixed;top:-61px;background-color:rgba(255,255,255,.9);border-bottom:1px solid #f2f2f2;-webkit-transition:-webkit-transform .3s;-moz-transition:-moz-transform .3s;transition:transform .3s}.navbar-custom.is-fixed .navbar-brand{color:#404040}.navbar-custom.is-fixed .navbar-brand:focus,.navbar-custom.is-fixed .navbar-brand:hover{color:#0085a1}.navbar-custom.is-fixed .nav li a{color:#404040}.navbar-custom.is-fixed .nav li a:focus,.navbar-custom.is-fixed .nav li a:hover{color:#0085a1}.navbar-custom.is-visible{-webkit-transform:translate3d(0,100%,0);-moz-transform:translate3d(0,100%,0);-ms-transform:translate3d(0,100%,0);-o-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.intro-header{background:center center no-repeat;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-o-background-size:cover;margin-bottom:50px}.intro-header .page-heading,.intro-header .post-heading,.intro-header .site-heading{padding:100px 0 50px;color:#fff}.intro-header .page-heading h1,.intro-header .site-heading h1{margin-top:0;font-size:50px}.intro-header .page-heading .subheading,.intro-header .site-heading .subheading{font-size:24px;line-height:1.1,display: block;font-weight:300;margin:10px 0 0}@media only screen and (min-width:768px){.intro-header .page-heading,.intro-header .post-heading,.intro-header .site-heading{padding:150px 0}.intro-header .page-heading h1,.intro-header .site-heading h1{font-size:80px}}.intro-header .post-heading h1{font-size:35px}.intro-header .post-heading .meta,.intro-header .post-heading .subheading{line-height:1.1;display:block}.intro-header .post-heading .subheading{font-size:24px;margin:10px 0 30px;font-weight:600}.intro-header .post-heading .meta{font-family:Lora,'Times New Roman',serif;font-style:italic;font-weight:300;font-size:20px}.intro-header .post-heading .meta a{color:#fff}@media only screen and (min-width:768px){.intro-header .post-heading h1{font-size:55px}.intro-header .post-heading .subheading{font-size:30px}}.post-preview>a{color:#404040}.post-preview>a:focus,.post-preview>a:hover{text-decoration:none;color:#0085a1}.post-preview>a>.post-title{font-size:30px;margin-top:30px;margin-bottom:10px}.post-preview>a>.post-subtitle{margin:0 0 10px;font-weight:300}.post-preview>.post-meta{color:grey;font-size:18px;font-style:italic;margin-top:0}.post-preview>.post-meta>a{text-decoration:none;color:#404040}.post-preview>.post-meta>a:focus,.post-preview>.post-meta>a:hover{color:#0085a1;text-decoration:underline}@media only screen and (min-width:768px){.post-preview>a>.post-title{font-size:36px}}.section-heading{font-size:36px;margin-top:60px;font-weight:700}.btn,.pager li>a,.pager li>span{font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;text-transform:uppercase;font-weight:800;letter-spacing:1px}.caption{font-size:14px;padding:10px;font-style:italic;margin:0;display:block;border-bottom-right-radius:5px;border-bottom-left-radius:5px}footer{padding:50px 0 65px}footer .list-inline{margin:0;padding:0}footer .copyright{font-size:14px;margin-bottom:0}.floating-label-form-group{font-size:14px;position:relative;margin-bottom:0;padding-bottom:.5em;border-bottom:1px solid #eee}.floating-label-form-group input,.floating-label-form-group textarea{z-index:1;position:relative;padding-right:0;padding-left:0;border:none;border-radius:0;font-size:1.5em;background:0 0;box-shadow:none!important;resize:none}.floating-label-form-group label{display:block;z-index:0;position:relative;top:2em;margin:0;font-size:.85em;line-height:1.764705882em;vertical-align:middle;vertical-align:baseline;opacity:0;-webkit-transition:top .3s ease,opacity .3s ease;-moz-transition:top .3s ease,opacity .3s ease;-ms-transition:top .3s ease,opacity .3s ease;transition:top .3s ease,opacity .3s ease}.floating-label-form-group::not(:first-child){padding-left:14px;border-left:1px solid #eee}.floating-label-form-group-with-value label{top:0;opacity:1}.floating-label-form-group-with-focus label{color:#0085a1}form .row:first-child .floating-label-form-group{border-top:1px solid #eee}.btn{font-size:14px;border-radius:0;padding:15px 25px}.btn-lg{font-size:16px;padding:25px 35px}.btn-default:focus,.btn-default:hover{background-color:#0085a1;border:1px solid #0085a1;color:#fff}.pager{margin:20px 0 0}.pager li>a,.pager li>span{font-size:14px;padding:15px 25px;background-color:#fff;border-radius:0}.pager li>a:focus,.pager li>a:hover{color:#fff;background-color:#0085a1;border:1px solid #0085a1}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:grey;background-color:#404040;cursor:not-allowed}::-moz-selection{color:#fff;text-shadow:none;background:#0085a1}::selection{color:#fff;text-shadow:none;background:#0085a1}img{max-width:100%;height:auto;width:auto\9}img::selection{color:#fff;background:0 0}img::-moz-selection{color:#fff;background:0 0} diff --git a/output/theme/css/code_blocks/darkly.css b/output/theme/css/code_blocks/darkly.css deleted file mode 100644 index 0a272d5..0000000 --- a/output/theme/css/code_blocks/darkly.css +++ /dev/null @@ -1 +0,0 @@ -pre{white-space:pre;overflow:auto;word-wrap:normal;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;padding:20px;background:#343642;color:#C1C2C3}.hll{background-color:#ffc}.gd{color:#2e3436;background-color:#0e1416}.gr{color:#eeeeec;background-color:#c00}.gi{color:#babdb6;background-color:#1f2b2d}.go{color:#2c3032;background-color:#2c3032}.kt{color:#e3e7df}.ni{color:#888a85}.c,.cm,.c1,.cs{color:#8D9684}.err,.g,.l,.n,.x,.p,.ge,.gp,.gs,.gt,.ld,.s,.nc,.nd,.ne,.nl,.nn,.nx,.py,.ow,.w,.sb,.sc,.sd,.s2,.se,.sh,.si,.sx,.sr,.s1,.ss,.bp{color:#C1C2C3}.k,.kc,.kd,.kn,.kp,.kr,.nt{color:#729fcf}.cp,.gh,.gu,.na,.nf{color:#E9A94B}.m,.nb,.no,.mf,.mh,.mi,.mo,.il{color:#8ae234}.o{color:#989DAA}.nv,.vc,.vg,.vi{color:#fff} diff --git a/output/theme/css/code_blocks/github.css b/output/theme/css/code_blocks/github.css deleted file mode 100644 index 68141bc..0000000 --- a/output/theme/css/code_blocks/github.css +++ /dev/null @@ -1 +0,0 @@ -.hll{background-color:#ffc}.c{color:#998;font-style:italic}.err{color:#a61717;background-color:#e3d2d2}.k{color:#000;font-weight:700}.o{color:#000;font-weight:700}.cm{color:#998;font-style:italic}.cp{color:#999;font-weight:700;font-style:italic}.c1{color:#998;font-style:italic}.cs{color:#999;font-weight:700;font-style:italic}.gd{color:#000;background-color:#fdd}.ge{color:#000;font-style:italic}.gr{color:#a00}.gh{color:#999}.gi{color:#000;background-color:#dfd}.go{color:#888}.gp{color:#555}.gs{font-weight:700}.gu{color:#aaa}.gt{color:#a00}.kc{color:#000;font-weight:700}.kd{color:#000;font-weight:700}.kn{color:#000;font-weight:700}.kp{color:#000;font-weight:700}.kr{color:#000;font-weight:700}.kt{color:#458;font-weight:700}.m{color:#099}.s{color:#d01040}.na{color:#008080}.nb{color:#0086B3}.nc{color:#458;font-weight:700}.no{color:#008080}.nd{color:#3c5d5d;font-weight:700}.ni{color:purple}.ne{color:#900;font-weight:700}.nf{color:#900;font-weight:700}.nl{color:#900;font-weight:700}.nn{color:#555}.nt{color:navy}.nv{color:#008080}.ow{color:#000;font-weight:700}.w{color:#bbb}.mf{color:#099}.mh{color:#099}.mi{color:#099}.mo{color:#099}.sb{color:#d01040}.sc{color:#d01040}.sd{color:#d01040}.s2{color:#d01040}.se{color:#d01040}.sh{color:#d01040}.si{color:#d01040}.sx{color:#d01040}.sr{color:#009926}.s1{color:#d01040}.ss{color:#990073}.bp{color:#999}.vc{color:#008080}.vg{color:#008080}.vi{color:#008080}.il{color:#099} diff --git a/output/theme/css/code_blocks/github_jekyll.css b/output/theme/css/code_blocks/github_jekyll.css deleted file mode 100644 index 806253b..0000000 --- a/output/theme/css/code_blocks/github_jekyll.css +++ /dev/null @@ -1 +0,0 @@ -.highlight pre code*{white-space:nowrap}.highlight pre{overflow-x:auto}.highlight pre code{white-space:pre}.highlight pre,pre,.highlight.hll{background-color:#f8f8f8;border:1px solid #ccc;padding:6px 10px;border-radius:3px}.highlight.c{color:#999988;font-style:italic}.highlight.err{color:#a61717;background-color:#e3d2d2}.highlight.k{font-weight:bold}.highlight.o{font-weight:bold}.highlight.cm{color:#999988;font-style:italic}.highlight.cp{color:#999999;font-weight:bold}.highlight.c1{color:#999988;font-style:italic}.highlight.cs{color:#999999;font-weight:bold;font-style:italic}.highlight.gd{color:#000000;background-color:#ffdddd}.highlight.gd.x{color:#000000;background-color:#ffaaaa}.highlight.ge{font-style:italic}.highlight.gr{color:#aa0000}.highlight.gh{color:#999999}.highlight.gi{color:#000000;background-color:#ddffdd}.highlight.gi.x{color:#000000;background-color:#aaffaa}.highlight.go{color:#888888}.highlight.gp{color:#555555}.highlight.gs{font-weight:bold}.highlight.gu{color:#800080;font-weight:bold}.highlight.gt{color:#aa0000}.highlight.kc{font-weight:bold}.highlight.kd{font-weight:bold}.highlight.kn{font-weight:bold}.highlight.kp{font-weight:bold}.highlight.kr{font-weight:bold}.highlight.kt{color:#445588;font-weight:bold}.highlight.m{color:#009999}.highlight.s{color:#dd1144}.highlight.n{color:#333333}.highlight.na{color:teal}.highlight.nb{color:#0086b3}.highlight.nc{color:#445588;font-weight:bold}.highlight.no{color:teal}.highlight.ni{color:purple}.highlight.ne{color:#990000;font-weight:bold}.highlight.nf{color:#990000;font-weight:bold}.highlight.nn{color:#555555}.highlight.nt{color:navy}.highlight.nv{color:teal}.highlight.ow{font-weight:bold}.highlight.w{color:#bbbbbb}.highlight.mf{color:#009999}.highlight.mh{color:#009999}.highlight.mi{color:#009999}.highlight.mo{color:#009999}.highlight.sb{color:#dd1144}.highlight.sc{color:#dd1144}.highlight.sd{color:#dd1144}.highlight.s2{color:#dd1144}.highlight.se{color:#dd1144}.highlight.sh{color:#dd1144}.highlight.si{color:#dd1144}.highlight.sx{color:#dd1144}.highlight.sr{color:#009926}.highlight.s1{color:#dd1144}.highlight.ss{color:#990073}.highlight.bp{color:#999999}.highlight.vc{color:teal}.highlight.vg{color:teal}.highlight.vi{color:teal}.highlight.il{color:#009999}.highlight.gc{color:#999;background-color:#EAF2F5}highlight .gc { color: #999; background-color: #EAF2F5; } diff --git a/output/theme/css/code_blocks/monokai.css b/output/theme/css/code_blocks/monokai.css deleted file mode 100644 index 35ce69d..0000000 --- a/output/theme/css/code_blocks/monokai.css +++ /dev/null @@ -1 +0,0 @@ -pre{white-space:pre;overflow:auto;word-wrap:normal;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;padding:20px;background:#343642;color:#C1C2C3}.hll{background-color:#49483e}.c{color:#75715e}.err{color:#960050;background-color:#1e0010}.k{color:#66d9ef}.l{color:#ae81ff}.n{color:#f8f8f2}.o{color:#f92672}.p{color:#f8f8f2}.cm{color:#75715e}.cp{color:#75715e}.c1{color:#75715e}.cs{color:#75715e}.ge{font-style:italic}.gs{font-weight:700}.kc{color:#66d9ef}.kd{color:#66d9ef}.kn{color:#f92672}.kp{color:#66d9ef}.kr{color:#66d9ef}.kt{color:#66d9ef}.ld{color:#e6db74}.m{color:#ae81ff}.s{color:#e6db74}.na{color:#a6e22e}.nb{color:#f8f8f2}.nc{color:#a6e22e}.no{color:#66d9ef}.nd{color:#a6e22e}.ni{color:#f8f8f2}.ne{color:#a6e22e}.nf{color:#a6e22e}.nl{color:#f8f8f2}.nn{color:#f8f8f2}.nx{color:#a6e22e}.py{color:#f8f8f2}.nt{color:#f92672}.nv{color:#f8f8f2}.ow{color:#f92672}.w{color:#f8f8f2}.mf{color:#ae81ff}.mh{color:#ae81ff}.mi{color:#ae81ff}.mo{color:#ae81ff}.sb{color:#e6db74}.sc{color:#e6db74}.sd{color:#e6db74}.s2{color:#e6db74}.se{color:#ae81ff}.sh{color:#e6db74}.si{color:#e6db74}.sx{color:#e6db74}.sr{color:#e6db74}.s1{color:#e6db74}.ss{color:#e6db74}.bp{color:#f8f8f2}.vc{color:#f8f8f2}.vg{color:#f8f8f2}.vi{color:#f8f8f2}.il{color:#ae81ff}.gu{color:#75715e}.gd{color:#f92672}.gi{color:#a6e22e} diff --git a/output/theme/css/code_blocks/tomorrow.css b/output/theme/css/code_blocks/tomorrow.css deleted file mode 100644 index 8b53e14..0000000 --- a/output/theme/css/code_blocks/tomorrow.css +++ /dev/null @@ -1 +0,0 @@ -pre{background:#fff;color:#4d4d4c}.hll{background-color:#d6d6d6}.c{color:#8e908c}.err{color:#c82829}.k{color:#8959a8}.l{color:#f5871f}.n{color:#4d4d4c}.o{color:#3e999f}.p{color:#4d4d4c}.cm{color:#8e908c}.cp{color:#8e908c}.c1{color:#8e908c}.cs{color:#8e908c}.gd{color:#c82829}.ge{font-style:italic}.gh{color:#4d4d4c;font-weight:700}.gi{color:#718c00}.gp{color:#8e908c;font-weight:700}.gs{font-weight:700}.gu{color:#3e999f;font-weight:700}.kc{color:#8959a8}.kd{color:#8959a8}.kn{color:#3e999f}.kp{color:#8959a8}.kr{color:#8959a8}.kt{color:#eab700}.ld{color:#718c00}.m{color:#f5871f}.s{color:#718c00}.na{color:#4271ae}.nb{color:#4d4d4c}.nc{color:#eab700}.no{color:#c82829}.nd{color:#3e999f}.ni{color:#4d4d4c}.ne{color:#c82829}.nf{color:#4271ae}.nl{color:#4d4d4c}.nn{color:#eab700}.nx{color:#4271ae}.py{color:#4d4d4c}.nt{color:#3e999f}.nv{color:#c82829}.ow{color:#3e999f}.w{color:#4d4d4c}.mf{color:#f5871f}.mh{color:#f5871f}.mi{color:#f5871f}.mo{color:#f5871f}.sb{color:#718c00}.sc{color:#4d4d4c}.sd{color:#8e908c}.s2{color:#718c00}.se{color:#f5871f}.sh{color:#718c00}.si{color:#f5871f}.sx{color:#718c00}.sr{color:#718c00}.s1{color:#718c00}.ss{color:#718c00}.bp{color:#4d4d4c}.vc{color:#c82829}.vg{color:#c82829}.vi{color:#c82829}.il{color:#f5871f} diff --git a/output/theme/css/code_blocks/tomorrow_night.css b/output/theme/css/code_blocks/tomorrow_night.css deleted file mode 100644 index 4eedf07..0000000 --- a/output/theme/css/code_blocks/tomorrow_night.css +++ /dev/null @@ -1 +0,0 @@ -pre{background:#1d1f21;color:#c5c8c6}.hll{background-color:#373b41}.c{color:#969896}.err{color:#c66}.k{color:#b294bb}.l{color:#de935f}.n{color:#c5c8c6}.o{color:#8abeb7}.p{color:#c5c8c6}.cm{color:#969896}.cp{color:#969896}.c1{color:#969896}.cs{color:#969896}.gd{color:#c66}.ge{font-style:italic}.gh{color:#c5c8c6;font-weight:700}.gi{color:#b5bd68}.gp{color:#969896;font-weight:700}.gs{font-weight:700}.gu{color:#8abeb7;font-weight:700}.kc{color:#b294bb}.kd{color:#b294bb}.kn{color:#8abeb7}.kp{color:#b294bb}.kr{color:#b294bb}.kt{color:#f0c674}.ld{color:#b5bd68}.m{color:#de935f}.s{color:#b5bd68}.na{color:#81a2be}.nb{color:#c5c8c6}.nc{color:#f0c674}.no{color:#c66}.nd{color:#8abeb7}.ni{color:#c5c8c6}.ne{color:#c66}.nf{color:#81a2be}.nl{color:#c5c8c6}.nn{color:#f0c674}.nx{color:#81a2be}.py{color:#c5c8c6}.nt{color:#8abeb7}.nv{color:#c66}.ow{color:#8abeb7}.w{color:#c5c8c6}.mf{color:#de935f}.mh{color:#de935f}.mi{color:#de935f}.mo{color:#de935f}.sb{color:#b5bd68}.sc{color:#c5c8c6}.sd{color:#969896}.s2{color:#b5bd68}.se{color:#de935f}.sh{color:#b5bd68}.si{color:#de935f}.sx{color:#b5bd68}.sr{color:#b5bd68}.s1{color:#b5bd68}.ss{color:#b5bd68}.bp{color:#c5c8c6}.vc{color:#c66}.vg{color:#c66}.vi{color:#c66}.il{color:#de935f} diff --git a/output/theme/fonts/glyphicons-halflings-regular.eot b/output/theme/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index 4a4ca86..0000000 Binary files a/output/theme/fonts/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/output/theme/fonts/glyphicons-halflings-regular.svg b/output/theme/fonts/glyphicons-halflings-regular.svg deleted file mode 100644 index 25691af..0000000 --- a/output/theme/fonts/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/output/theme/fonts/glyphicons-halflings-regular.ttf b/output/theme/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 67fa00b..0000000 Binary files a/output/theme/fonts/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/output/theme/fonts/glyphicons-halflings-regular.woff b/output/theme/fonts/glyphicons-halflings-regular.woff deleted file mode 100644 index 8c54182..0000000 Binary files a/output/theme/fonts/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/output/theme/images/about-bg.jpg b/output/theme/images/about-bg.jpg deleted file mode 100644 index af6d4d5..0000000 Binary files a/output/theme/images/about-bg.jpg and /dev/null differ diff --git a/output/theme/images/contact-bg.jpg b/output/theme/images/contact-bg.jpg deleted file mode 100644 index 9bf21a4..0000000 Binary files a/output/theme/images/contact-bg.jpg and /dev/null differ diff --git a/output/theme/images/home-bg.jpg b/output/theme/images/home-bg.jpg deleted file mode 100644 index a4d2108..0000000 Binary files a/output/theme/images/home-bg.jpg and /dev/null differ diff --git a/output/theme/images/post-bg.jpg b/output/theme/images/post-bg.jpg deleted file mode 100644 index 21750a4..0000000 Binary files a/output/theme/images/post-bg.jpg and /dev/null differ diff --git a/output/theme/images/post-sample-image.jpg b/output/theme/images/post-sample-image.jpg deleted file mode 100644 index 3fc4282..0000000 Binary files a/output/theme/images/post-sample-image.jpg and /dev/null differ diff --git a/output/theme/js/bootstrap.js b/output/theme/js/bootstrap.js deleted file mode 100644 index 8dff365..0000000 --- a/output/theme/js/bootstrap.js +++ /dev/null @@ -1,2276 +0,0 @@ -/*! - * Bootstrap v3.3.0 (http://getbootstrap.com) - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -if (typeof jQuery === 'undefined') { - throw new Error('Bootstrap\'s JavaScript requires jQuery') -} - -+function ($) { - var version = $.fn.jquery.split(' ')[0].split('.') - if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { - throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') - } -}(jQuery); - -/* ======================================================================== - * Bootstrap: transition.js v3.3.0 - * http://getbootstrap.com/javascript/#transitions - * ======================================================================== - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) - // ============================================================ - - function transitionEnd() { - var el = document.createElement('bootstrap') - - var transEndEventNames = { - WebkitTransition : 'webkitTransitionEnd', - MozTransition : 'transitionend', - OTransition : 'oTransitionEnd otransitionend', - transition : 'transitionend' - } - - for (var name in transEndEventNames) { - if (el.style[name] !== undefined) { - return { end: transEndEventNames[name] } - } - } - - return false // explicit for ie8 ( ._.) - } - - // http://blog.alexmaccaw.com/css-transitions - $.fn.emulateTransitionEnd = function (duration) { - var called = false - var $el = this - $(this).one('bsTransitionEnd', function () { called = true }) - var callback = function () { if (!called) $($el).trigger($.support.transition.end) } - setTimeout(callback, duration) - return this - } - - $(function () { - $.support.transition = transitionEnd() - - if (!$.support.transition) return - - $.event.special.bsTransitionEnd = { - bindType: $.support.transition.end, - delegateType: $.support.transition.end, - handle: function (e) { - if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) - } - } - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: alert.js v3.3.0 - * http://getbootstrap.com/javascript/#alerts - * ======================================================================== - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // ALERT CLASS DEFINITION - // ====================== - - var dismiss = '[data-dismiss="alert"]' - var Alert = function (el) { - $(el).on('click', dismiss, this.close) - } - - Alert.VERSION = '3.3.0' - - Alert.TRANSITION_DURATION = 150 - - Alert.prototype.close = function (e) { - var $this = $(this) - var selector = $this.attr('data-target') - - if (!selector) { - selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 - } - - var $parent = $(selector) - - if (e) e.preventDefault() - - if (!$parent.length) { - $parent = $this.closest('.alert') - } - - $parent.trigger(e = $.Event('close.bs.alert')) - - if (e.isDefaultPrevented()) return - - $parent.removeClass('in') - - function removeElement() { - // detach from parent, fire event then clean up data - $parent.detach().trigger('closed.bs.alert').remove() - } - - $.support.transition && $parent.hasClass('fade') ? - $parent - .one('bsTransitionEnd', removeElement) - .emulateTransitionEnd(Alert.TRANSITION_DURATION) : - removeElement() - } - - - // ALERT PLUGIN DEFINITION - // ======================= - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.alert') - - if (!data) $this.data('bs.alert', (data = new Alert(this))) - if (typeof option == 'string') data[option].call($this) - }) - } - - var old = $.fn.alert - - $.fn.alert = Plugin - $.fn.alert.Constructor = Alert - - - // ALERT NO CONFLICT - // ================= - - $.fn.alert.noConflict = function () { - $.fn.alert = old - return this - } - - - // ALERT DATA-API - // ============== - - $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: button.js v3.3.0 - * http://getbootstrap.com/javascript/#buttons - * ======================================================================== - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // BUTTON PUBLIC CLASS DEFINITION - // ============================== - - var Button = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Button.DEFAULTS, options) - this.isLoading = false - } - - Button.VERSION = '3.3.0' - - Button.DEFAULTS = { - loadingText: 'loading...' - } - - Button.prototype.setState = function (state) { - var d = 'disabled' - var $el = this.$element - var val = $el.is('input') ? 'val' : 'html' - var data = $el.data() - - state = state + 'Text' - - if (data.resetText == null) $el.data('resetText', $el[val]()) - - // push to event loop to allow forms to submit - setTimeout($.proxy(function () { - $el[val](data[state] == null ? this.options[state] : data[state]) - - if (state == 'loadingText') { - this.isLoading = true - $el.addClass(d).attr(d, d) - } else if (this.isLoading) { - this.isLoading = false - $el.removeClass(d).removeAttr(d) - } - }, this), 0) - } - - Button.prototype.toggle = function () { - var changed = true - var $parent = this.$element.closest('[data-toggle="buttons"]') - - if ($parent.length) { - var $input = this.$element.find('input') - if ($input.prop('type') == 'radio') { - if ($input.prop('checked') && this.$element.hasClass('active')) changed = false - else $parent.find('.active').removeClass('active') - } - if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') - } else { - this.$element.attr('aria-pressed', !this.$element.hasClass('active')) - } - - if (changed) this.$element.toggleClass('active') - } - - - // BUTTON PLUGIN DEFINITION - // ======================== - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.button') - var options = typeof option == 'object' && option - - if (!data) $this.data('bs.button', (data = new Button(this, options))) - - if (option == 'toggle') data.toggle() - else if (option) data.setState(option) - }) - } - - var old = $.fn.button - - $.fn.button = Plugin - $.fn.button.Constructor = Button - - - // BUTTON NO CONFLICT - // ================== - - $.fn.button.noConflict = function () { - $.fn.button = old - return this - } - - - // BUTTON DATA-API - // =============== - - $(document) - .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - Plugin.call($btn, 'toggle') - e.preventDefault() - }) - .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { - $(e.target).closest('.btn').toggleClass('focus', e.type == 'focus') - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: carousel.js v3.3.0 - * http://getbootstrap.com/javascript/#carousel - * ======================================================================== - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // CAROUSEL CLASS DEFINITION - // ========================= - - var Carousel = function (element, options) { - this.$element = $(element) - this.$indicators = this.$element.find('.carousel-indicators') - this.options = options - this.paused = - this.sliding = - this.interval = - this.$active = - this.$items = null - - this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) - - this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element - .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) - .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) - } - - Carousel.VERSION = '3.3.0' - - Carousel.TRANSITION_DURATION = 600 - - Carousel.DEFAULTS = { - interval: 5000, - pause: 'hover', - wrap: true, - keyboard: true - } - - Carousel.prototype.keydown = function (e) { - switch (e.which) { - case 37: this.prev(); break - case 39: this.next(); break - default: return - } - - e.preventDefault() - } - - Carousel.prototype.cycle = function (e) { - e || (this.paused = false) - - this.interval && clearInterval(this.interval) - - this.options.interval - && !this.paused - && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) - - return this - } - - Carousel.prototype.getItemIndex = function (item) { - this.$items = item.parent().children('.item') - return this.$items.index(item || this.$active) - } - - Carousel.prototype.getItemForDirection = function (direction, active) { - var delta = direction == 'prev' ? -1 : 1 - var activeIndex = this.getItemIndex(active) - var itemIndex = (activeIndex + delta) % this.$items.length - return this.$items.eq(itemIndex) - } - - Carousel.prototype.to = function (pos) { - var that = this - var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) - - if (pos > (this.$items.length - 1) || pos < 0) return - - if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" - if (activeIndex == pos) return this.pause().cycle() - - return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) - } - - Carousel.prototype.pause = function (e) { - e || (this.paused = true) - - if (this.$element.find('.next, .prev').length && $.support.transition) { - this.$element.trigger($.support.transition.end) - this.cycle(true) - } - - this.interval = clearInterval(this.interval) - - return this - } - - Carousel.prototype.next = function () { - if (this.sliding) return - return this.slide('next') - } - - Carousel.prototype.prev = function () { - if (this.sliding) return - return this.slide('prev') - } - - Carousel.prototype.slide = function (type, next) { - var $active = this.$element.find('.item.active') - var $next = next || this.getItemForDirection(type, $active) - var isCycling = this.interval - var direction = type == 'next' ? 'left' : 'right' - var fallback = type == 'next' ? 'first' : 'last' - var that = this - - if (!$next.length) { - if (!this.options.wrap) return - $next = this.$element.find('.item')[fallback]() - } - - if ($next.hasClass('active')) return (this.sliding = false) - - var relatedTarget = $next[0] - var slideEvent = $.Event('slide.bs.carousel', { - relatedTarget: relatedTarget, - direction: direction - }) - this.$element.trigger(slideEvent) - if (slideEvent.isDefaultPrevented()) return - - this.sliding = true - - isCycling && this.pause() - - if (this.$indicators.length) { - this.$indicators.find('.active').removeClass('active') - var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) - $nextIndicator && $nextIndicator.addClass('active') - } - - var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" - if ($.support.transition && this.$element.hasClass('slide')) { - $next.addClass(type) - $next[0].offsetWidth // force reflow - $active.addClass(direction) - $next.addClass(direction) - $active - .one('bsTransitionEnd', function () { - $next.removeClass([type, direction].join(' ')).addClass('active') - $active.removeClass(['active', direction].join(' ')) - that.sliding = false - setTimeout(function () { - that.$element.trigger(slidEvent) - }, 0) - }) - .emulateTransitionEnd(Carousel.TRANSITION_DURATION) - } else { - $active.removeClass('active') - $next.addClass('active') - this.sliding = false - this.$element.trigger(slidEvent) - } - - isCycling && this.cycle() - - return this - } - - - // CAROUSEL PLUGIN DEFINITION - // ========================== - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.carousel') - var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) - var action = typeof option == 'string' ? option : options.slide - - if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) - if (typeof option == 'number') data.to(option) - else if (action) data[action]() - else if (options.interval) data.pause().cycle() - }) - } - - var old = $.fn.carousel - - $.fn.carousel = Plugin - $.fn.carousel.Constructor = Carousel - - - // CAROUSEL NO CONFLICT - // ==================== - - $.fn.carousel.noConflict = function () { - $.fn.carousel = old - return this - } - - - // CAROUSEL DATA-API - // ================= - - var clickHandler = function (e) { - var href - var $this = $(this) - var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 - if (!$target.hasClass('carousel')) return - var options = $.extend({}, $target.data(), $this.data()) - var slideIndex = $this.attr('data-slide-to') - if (slideIndex) options.interval = false - - Plugin.call($target, options) - - if (slideIndex) { - $target.data('bs.carousel').to(slideIndex) - } - - e.preventDefault() - } - - $(document) - .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) - .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) - - $(window).on('load', function () { - $('[data-ride="carousel"]').each(function () { - var $carousel = $(this) - Plugin.call($carousel, $carousel.data()) - }) - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: collapse.js v3.3.0 - * http://getbootstrap.com/javascript/#collapse - * ======================================================================== - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // COLLAPSE PUBLIC CLASS DEFINITION - // ================================ - - var Collapse = function (element, options) { - this.$element = $(element) - this.options = $.extend({}, Collapse.DEFAULTS, options) - this.$trigger = $(this.options.trigger).filter('[href="#' + element.id + '"], [data-target="#' + element.id + '"]') - this.transitioning = null - - if (this.options.parent) { - this.$parent = this.getParent() - } else { - this.addAriaAndCollapsedClass(this.$element, this.$trigger) - } - - if (this.options.toggle) this.toggle() - } - - Collapse.VERSION = '3.3.0' - - Collapse.TRANSITION_DURATION = 350 - - Collapse.DEFAULTS = { - toggle: true, - trigger: '[data-toggle="collapse"]' - } - - Collapse.prototype.dimension = function () { - var hasWidth = this.$element.hasClass('width') - return hasWidth ? 'width' : 'height' - } - - Collapse.prototype.show = function () { - if (this.transitioning || this.$element.hasClass('in')) return - - var activesData - var actives = this.$parent && this.$parent.find('> .panel').children('.in, .collapsing') - - if (actives && actives.length) { - activesData = actives.data('bs.collapse') - if (activesData && activesData.transitioning) return - } - - var startEvent = $.Event('show.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return - - if (actives && actives.length) { - Plugin.call(actives, 'hide') - activesData || actives.data('bs.collapse', null) - } - - var dimension = this.dimension() - - this.$element - .removeClass('collapse') - .addClass('collapsing')[dimension](0) - .attr('aria-expanded', true) - - this.$trigger - .removeClass('collapsed') - .attr('aria-expanded', true) - - this.transitioning = 1 - - var complete = function () { - this.$element - .removeClass('collapsing') - .addClass('collapse in')[dimension]('') - this.transitioning = 0 - this.$element - .trigger('shown.bs.collapse') - } - - if (!$.support.transition) return complete.call(this) - - var scrollSize = $.camelCase(['scroll', dimension].join('-')) - - this.$element - .one('bsTransitionEnd', $.proxy(complete, this)) - .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) - } - - Collapse.prototype.hide = function () { - if (this.transitioning || !this.$element.hasClass('in')) return - - var startEvent = $.Event('hide.bs.collapse') - this.$element.trigger(startEvent) - if (startEvent.isDefaultPrevented()) return - - var dimension = this.dimension() - - this.$element[dimension](this.$element[dimension]())[0].offsetHeight - - this.$element - .addClass('collapsing') - .removeClass('collapse in') - .attr('aria-expanded', false) - - this.$trigger - .addClass('collapsed') - .attr('aria-expanded', false) - - this.transitioning = 1 - - var complete = function () { - this.transitioning = 0 - this.$element - .removeClass('collapsing') - .addClass('collapse') - .trigger('hidden.bs.collapse') - } - - if (!$.support.transition) return complete.call(this) - - this.$element - [dimension](0) - .one('bsTransitionEnd', $.proxy(complete, this)) - .emulateTransitionEnd(Collapse.TRANSITION_DURATION) - } - - Collapse.prototype.toggle = function () { - this[this.$element.hasClass('in') ? 'hide' : 'show']() - } - - Collapse.prototype.getParent = function () { - return $(this.options.parent) - .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') - .each($.proxy(function (i, element) { - var $element = $(element) - this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) - }, this)) - .end() - } - - Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { - var isOpen = $element.hasClass('in') - - $element.attr('aria-expanded', isOpen) - $trigger - .toggleClass('collapsed', !isOpen) - .attr('aria-expanded', isOpen) - } - - function getTargetFromTrigger($trigger) { - var href - var target = $trigger.attr('data-target') - || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 - - return $(target) - } - - - // COLLAPSE PLUGIN DEFINITION - // ========================== - - function Plugin(option) { - return this.each(function () { - var $this = $(this) - var data = $this.data('bs.collapse') - var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) - - if (!data && options.toggle && option == 'show') options.toggle = false - if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) - if (typeof option == 'string') data[option]() - }) - } - - var old = $.fn.collapse - - $.fn.collapse = Plugin - $.fn.collapse.Constructor = Collapse - - - // COLLAPSE NO CONFLICT - // ==================== - - $.fn.collapse.noConflict = function () { - $.fn.collapse = old - return this - } - - - // COLLAPSE DATA-API - // ================= - - $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { - var $this = $(this) - - if (!$this.attr('data-target')) e.preventDefault() - - var $target = getTargetFromTrigger($this) - var data = $target.data('bs.collapse') - var option = data ? 'toggle' : $.extend({}, $this.data(), { trigger: this }) - - Plugin.call($target, option) - }) - -}(jQuery); - -/* ======================================================================== - * Bootstrap: dropdown.js v3.3.0 - * http://getbootstrap.com/javascript/#dropdowns - * ======================================================================== - * Copyright 2011-2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - * ======================================================================== */ - - -+function ($) { - 'use strict'; - - // DROPDOWN CLASS DEFINITION - // ========================= - - var backdrop = '.dropdown-backdrop' - var toggle = '[data-toggle="dropdown"]' - var Dropdown = function (element) { - $(element).on('click.bs.dropdown', this.toggle) - } - - Dropdown.VERSION = '3.3.0' - - Dropdown.prototype.toggle = function (e) { - var $this = $(this) - - if ($this.is('.disabled, :disabled')) return - - var $parent = getParent($this) - var isActive = $parent.hasClass('open') - - clearMenus() - - if (!isActive) { - if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { - // if mobile we use a backdrop because click events don't delegate - $('