2. open your browser and visit http://127.0.0.1:24680
+========== VentoyPlugson.sh ===============
+1. sudo sh VentoyPlugson.sh
+2. open your browser and visit http://127.0.0.1:24681
+
+
========= VentoyGUI ===================
VentoyGUI is native GUI program for Linux (GTK/QT)
1. Just double-click the file (e.g. VentoyGUI.x86_64)
date >> ./log.txt
#decompress tool
-if [ -f ./tool/$TOOLDIR/ash ]; then
- echo "no need to decompress tools" >> ./log.txt
-else
- cd ./tool/$TOOLDIR
-
+echo "decompress tools" >> ./log.txt
+cd ./tool/$TOOLDIR
+
+ls *.xz > /dev/null 2>&1
+if [ $? -eq 0 ]; then
[ -f ./xzcat ] && chmod +x ./xzcat
-
+
for file in $(ls *.xz); do
+ echo "decompress $file" >> ./log.txt
xzcat $file > ${file%.xz}
[ -f ./${file%.xz} ] && chmod +x ./${file%.xz}
[ -f ./$file ] && rm -f ./$file
done
- cd ../../
-
- chmod +x -R ./tool/$TOOLDIR
fi
+cd ../../
+chmod +x -R ./tool/$TOOLDIR
+
+
if [ -f /bin/bash ]; then
/bin/bash ./tool/VentoyWorker.sh $*
else
--- /dev/null
+#!/bin/sh
+
+. ./tool/ventoy_lib.sh
+
+print_usage() {
+ echo 'Usage: sudo sh VentoyPlugson.sh [OPTION] /dev/sdX'
+ echo ' OPTION: (optional)'
+ echo ' -H x.x.x.x http server IP address (default is 127.0.0.1)'
+ echo ' -P PORT http server PORT (default is 24681)'
+ echo ' -h print this help'
+ echo ''
+}
+
+uid=$(id -u)
+if [ $uid -ne 0 ]; then
+ echo "Please use sudo or run the script as root."
+ exit 1
+fi
+
+
+OLDDIR=$(pwd)
+
+machine=$(uname -m)
+if echo $machine | egrep -q 'aarch64|arm64'; then
+ TOOLDIR=aarch64
+elif echo $machine | egrep -q 'x86_64|amd64'; then
+ TOOLDIR=x86_64
+elif echo $machine | egrep -q 'mips64'; then
+ TOOLDIR=mips64el
+elif echo $machine | egrep -q 'i[3-6]86'; then
+ TOOLDIR=i386
+else
+ echo "Unsupported machine type $machine"
+ exit 1
+fi
+
+
+if ! [ -f "$OLDDIR/tool/plugson.tar.xz" ]; then
+ echo "Please run under the correct directory!"
+ exit 1
+fi
+
+echo "############# VentoyPlugson $* [$TOOLDIR] ################" >> ./VentoyPlugson.log
+date >> ./VentoyPlugson.log
+
+echo "decompress tools" >> ./VentoyPlugson.log
+cd ./tool/$TOOLDIR
+
+ls *.xz > /dev/null 2>&1
+if [ $? -eq 0 ]; then
+ [ -f ./xzcat ] && chmod +x ./xzcat
+
+ for file in $(ls *.xz); do
+ echo "decompress $file" >> ./VentoyPlugson.log
+ xzcat $file > ${file%.xz}
+ [ -f ./${file%.xz} ] && chmod +x ./${file%.xz}
+ [ -f ./$file ] && rm -f ./$file
+ done
+fi
+
+cd ../../
+chmod +x -R ./tool/$TOOLDIR
+
+if ! [ -f "$OLDDIR/tool/$TOOLDIR/Plugson" ]; then
+ echo "$OLDDIR/tool/$TOOLDIR/Plugson does not exist!"
+ exit 1
+fi
+
+
+PATH=./tool/$TOOLDIR:$PATH
+
+HOST="127.0.0.1"
+PORT=24681
+
+while [ -n "$1" ]; do
+ if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
+ print_usage
+ exit 0
+ elif [ "$1" = "-H" ]; then
+ shift
+ if echo $1 | grep -q '[0-9]*\.[0-9]*\.[0-9]*\.[0-9]*'; then
+ HOST="$1"
+ else
+ echo "Invalid host $1"
+ exit 1
+ fi
+ elif [ "$1" = "-P" ]; then
+ shift
+ if [ $1 -gt 0 -a $1 -le 65535 ]; then
+ PORT="$1"
+ else
+ echo "Invalid port $1"
+ exit 1
+ fi
+ else
+ DISK=$1
+ fi
+
+ shift
+done
+
+if [ -z "$DISK" ]; then
+ print_usage
+ exit 0
+fi
+
+if ps -ef | grep "tool/$TOOLDIR/Plugson.*$HOST.*$PORT" | grep -q -v grep; then
+ echo "Another ventoy server is running now, please close it first."
+ exit 1
+fi
+
+if echo $DISK | grep -q "[a-z]d[a-z][1-9]"; then
+ DISK=${DISK:0:-1}
+fi
+
+if echo $DISK | egrep -q "/dev/nvme|/dev/mmcblk/dev/nbd"; then
+ if echo $DISK | grep -q "p[1-9]$"; then
+ DISK=${DISK:0:-2}
+ fi
+fi
+
+
+if [ ! -b "$DISK" ]; then
+ echo "$DISK does NOT exist."
+ exit 1
+fi
+
+
+version=$(get_disk_ventoy_version $DISK)
+if [ $? -eq 0 ]; then
+ echo "Ventoy version in Disk: $version"
+
+ vtPart1Type=$(dd if=$DISK bs=1 count=1 skip=450 status=none | hexdump -n1 -e '1/1 "%02X"')
+ if [ "$vtPart1Type" = "EE" ]; then
+ echo "Disk Partition Style : GPT"
+ partstyle=1
+ else
+ echo "Disk Partition Style : MBR"
+ partstyle=0
+ fi
+
+ if check_disk_secure_boot $DISK; then
+ echo "Secure Boot Support : YES"
+ secureboot=1
+ else
+ echo "Secure Boot Support : NO"
+ secureboot=0
+ fi
+else
+ echo "$DISK is NOT Ventoy disk."
+ exit 1
+fi
+
+PART1=$(get_disk_part_name $DISK 1)
+
+if grep -q "^$PART1 " /proc/mounts; then
+ mtpnt=$(grep "^$PART1 " /proc/mounts | awk '{print $2}')
+ fstype=$(grep "^$PART1 " /proc/mounts | awk '{print $3}')
+
+ if echo $fstype | grep -q -i 'fuse'; then
+ if hexdump -C -n 16 $PART1 | grep -q -i "EXFAT"; then
+ fstype="exFAT"
+ elif hexdump -C -n 16 $PART1 | grep -q -i "NTFS"; then
+ fstype="NTFS"
+ fi
+ fi
+
+ echo "$PART1 is mounted at $mtpnt $fstype"
+else
+ echo "$PART1 is NOT mounted, please mount it first!"
+ exit 1
+fi
+
+if [ -d "$mtpnt/ventoy" ]; then
+ echo "ventoy directory exist OK"
+else
+ echo "create ventoy directory"
+ mkdir -p "$mtpnt/ventoy"
+ if [ -d "$mtpnt/ventoy" ]; then
+ chmod -R 0755 "$mtpnt/ventoy"
+ else
+ echo "Failed to create directory $mtpnt/ventoy"
+ exit 1
+ fi
+fi
+
+
+#change current directory to Ventoy disk
+cd "$mtpnt"
+LANG=en_US $OLDDIR/tool/$TOOLDIR/Plugson "$HOST" "$PORT" "$OLDDIR" "$DISK" $version "$fstype" $partstyle $secureboot &
+wID=$!
+sleep 1
+
+if [ -f /proc/$wID/maps ]; then
+ echo ""
+ echo "==============================================================="
+ if [ "$LANG" = "zh_CN.UTF-8" ]; then
+ echo " Ventoy Plugson Server 已经启动 ..."
+ echo " 请打开浏览器,访问 http://${HOST}:${PORT}"
+ else
+ echo " Ventoy Plugson Server is running ..."
+ echo " Please open your browser and visit http://${HOST}:${PORT}"
+ fi
+ echo "==============================================================="
+ echo ""
+ echo "################## Press Ctrl + C to exit #####################"
+ echo ""
+
+ wait $wID
+fi
+
+
+if [ -n "$OLDDIR" ]; then
+ CURDIR=$(pwd)
+ if [ "$CURDIR" != "$OLDDIR" ]; then
+ cd "$OLDDIR"
+ fi
+fi
sh build.sh
cd -
+cd ../Plugson
+sh build.sh
+sh pack.sh
+cd -
+
LOOP=$(losetup -f)
rm -f $tmpdir/ENROLL_THIS_KEY_IN_MOKMANAGER.cer
cp $OPT Ventoy2Disk.sh $tmpdir/
cp $OPT VentoyWeb.sh $tmpdir/
+cp $OPT VentoyPlugson.sh $tmpdir/
cp $OPT VentoyGUI* $tmpdir/
cp $OPT ExtendPersistentImg.sh $tmpdir/
dos2unix -q $tmpdir/Ventoy2Disk.sh
dos2unix -q $tmpdir/VentoyWeb.sh
+dos2unix -q $tmpdir/VentoyPlugson.sh
dos2unix -q $tmpdir/CreatePersistentImg.sh
find $tmpdir/ -type f -exec chmod 644 "{}" +
chmod +x $tmpdir/Ventoy2Disk.sh
chmod +x $tmpdir/VentoyWeb.sh
+chmod +x $tmpdir/VentoyPlugson.sh
chmod +x $tmpdir/VentoyGUI*
cp $OPT $LANG_DIR/languages.json $tmpdir/tool/
rm -f ventoy-${curver}-windows.zip
cp $OPT Ventoy2Disk.exe $tmpdir/
+cp $OPT VentoyPlugson.exe $tmpdir/
cp $OPT FOR_X64_ARM.txt $tmpdir/
mkdir -p $tmpdir/altexe
cp $OPT Ventoy2Disk_*.exe $tmpdir/altexe/
--- /dev/null
+#!/bin/bash
+
+if [ "$1" = "sim" ]; then
+ exopt="-DVENTOY_SIM"
+fi
+
+build_func() {
+ libsuffix=$2
+ toolDir=$3
+
+ XXFLAG='-std=gnu99 -D_FILE_OFFSET_BITS=64'
+ XXLIB=""
+
+ echo "CC=$1 libsuffix=$libsuffix toolDir=$toolDir"
+
+ echo "CC civetweb.o"
+ $1 $XXFLAG -c -Wall -Wextra -Wshadow -Wformat-security -Winit-self \
+ -Wmissing-prototypes -O2 -DLINUX \
+ -I./src/Lib/libhttp/include \
+ -DNDEBUG -DNO_CGI -DNO_CACHING -DNO_SSL -DSQLITE_DISABLE_LFS -DSSL_ALREADY_INITIALIZED \
+ -DUSE_STACK_SIZE=102400 -DNDEBUG -fPIC \
+ ./src/Lib/libhttp/include/civetweb.c \
+ -o ./civetweb.o
+
+ echo "CC plugson.o"
+ $1 $XXFLAG -O2 $exopt -Wall -Wno-unused-function -DSTATIC=static -DINIT= \
+ -I./src \
+ -I./src/Core \
+ -I./src/Web \
+ -I./src/Include \
+ -I./src/Lib/libhttp/include \
+ -I./src/Lib/fat_io_lib/include \
+ -I./src/Lib/xz-embedded/linux/include \
+ -I./src/Lib/xz-embedded/linux/include/linux \
+ -I./src/Lib/xz-embedded/userspace \
+ -I ./src/Lib/exfat/src/libexfat \
+ -I ./src/Lib/exfat/src/mkfs \
+ -I ./src/Lib/fat_io_lib \
+ \
+ -L ./src/Lib/fat_io_lib/lib \
+ src/main_linux.c \
+ src/Core/ventoy_crc32.c \
+ src/Core/ventoy_disk.c \
+ src/Core/ventoy_disk_linux.c \
+ src/Core/ventoy_json.c \
+ src/Core/ventoy_log.c \
+ src/Core/ventoy_md5.c \
+ src/Core/ventoy_util.c \
+ src/Core/ventoy_util_linux.c \
+ src/Web/*.c \
+ src/Lib/xz-embedded/linux/lib/decompress_unxz.c \
+ src/Lib/fat_io_lib/*.c \
+ $XXLIB \
+ -l pthread \
+ ./civetweb.o \
+ -o Plugson$libsuffix
+
+ rm -f *.o
+
+ if [ "$libsuffix" = "aa64" ]; then
+ aarch64-linux-gnu-strip Plugson$libsuffix
+ elif [ "$libsuffix" = "m64e" ]; then
+ mips-linux-gnu-strip Plugson$libsuffix
+ else
+ strip Plugson$libsuffix
+ fi
+
+ rm -f ../INSTALL/tool/$toolDir/Plugson
+ cp -a Plugson$libsuffix ../INSTALL/tool/$toolDir/Plugson
+
+}
+
+build_func "gcc" '64' 'x86_64'
+
+build_func "gcc -m32" '32' 'i386'
+build_func "aarch64-linux-gnu-gcc" 'aa64' 'aarch64'
+build_func "mips-linux-gnu-gcc -mips64r2 -mabi=64" 'm64e' 'mips64el'
+
+
--- /dev/null
+#!/bin/sh
+
+output_hex_u32() {
+ hexval=$(printf '%08x' $1)
+ hex_B0=${hexval:0:2}
+ hex_B1=${hexval:2:2}
+ hex_B2=${hexval:4:2}
+ hex_B3=${hexval:6:2}
+ echo -en "\x$hex_B3\x$hex_B2\x$hex_B1\x$hex_B0"
+}
+
+if [ -n "$PKG_DATE" ]; then
+ plugson_verion=$PKG_DATE
+else
+ plugson_verion=$(date '+%Y%m%d %H:%M:%S')
+fi
+
+sed "s#.*plugson_build_date.*# <b id=\"plugson_build_date\">$plugson_verion</b>#" -i ./www/index.html
+
+if [ ! -f ./vs/VentoyPlugson/Release/VentoyPlugson.exe ]; then
+ echo "NO VentoyPlugson.exe found"
+ exit 1
+fi
+
+if [ -f ./www.tar.xz ]; then
+ rm -f ./www.tar.xz
+fi
+
+echo -n "$plugson_verion" > ./www/buildtime
+
+tar cf www.tar www
+xz --check=crc32 www.tar
+
+xzdec=$(stat -c '%s' ./www.tar.xz)
+echo xzdec=$xzdec
+
+output_hex_u32 0x54535251 > ex.bin
+output_hex_u32 $xzdec >> ex.bin
+output_hex_u32 0xa4a3a2a1 >> ex.bin
+
+cat ./vs/VentoyPlugson/Release/VentoyPlugson.exe ./www.tar.xz ex.bin > VentoyPlugson.exe
+rm -f ./ex.bin
+
+rm -f ../INSTALL/VentoyPlugson.exe
+cp -a ./VentoyPlugson.exe ../INSTALL/VentoyPlugson.exe
+
+rm -f ../INSTALL/tool/plugson.tar.xz
+mv ./www.tar.xz ../INSTALL/tool/plugson.tar.xz
+
+echo ""
+echo "========= SUCCESS ==========="
+echo ""
+
+
--- /dev/null
+/******************************************************************************
+ * crc32.c ---- ventoy crc32
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#if defined(_MSC_VER) || defined(WIN32)
+#include <Windows.h>
+#define uint32_t UINT32
+#else
+#include <unistd.h>
+#endif
+
+static uint32_t g_crc_table[256] = {
+ 0x00000000,
+ 0x77073096,
+ 0xEE0E612C,
+ 0x990951BA,
+ 0x076DC419,
+ 0x706AF48F,
+ 0xE963A535,
+ 0x9E6495A3,
+ 0x0EDB8832,
+ 0x79DCB8A4,
+ 0xE0D5E91E,
+ 0x97D2D988,
+ 0x09B64C2B,
+ 0x7EB17CBD,
+ 0xE7B82D07,
+ 0x90BF1D91,
+ 0x1DB71064,
+ 0x6AB020F2,
+ 0xF3B97148,
+ 0x84BE41DE,
+ 0x1ADAD47D,
+ 0x6DDDE4EB,
+ 0xF4D4B551,
+ 0x83D385C7,
+ 0x136C9856,
+ 0x646BA8C0,
+ 0xFD62F97A,
+ 0x8A65C9EC,
+ 0x14015C4F,
+ 0x63066CD9,
+ 0xFA0F3D63,
+ 0x8D080DF5,
+ 0x3B6E20C8,
+ 0x4C69105E,
+ 0xD56041E4,
+ 0xA2677172,
+ 0x3C03E4D1,
+ 0x4B04D447,
+ 0xD20D85FD,
+ 0xA50AB56B,
+ 0x35B5A8FA,
+ 0x42B2986C,
+ 0xDBBBC9D6,
+ 0xACBCF940,
+ 0x32D86CE3,
+ 0x45DF5C75,
+ 0xDCD60DCF,
+ 0xABD13D59,
+ 0x26D930AC,
+ 0x51DE003A,
+ 0xC8D75180,
+ 0xBFD06116,
+ 0x21B4F4B5,
+ 0x56B3C423,
+ 0xCFBA9599,
+ 0xB8BDA50F,
+ 0x2802B89E,
+ 0x5F058808,
+ 0xC60CD9B2,
+ 0xB10BE924,
+ 0x2F6F7C87,
+ 0x58684C11,
+ 0xC1611DAB,
+ 0xB6662D3D,
+ 0x76DC4190,
+ 0x01DB7106,
+ 0x98D220BC,
+ 0xEFD5102A,
+ 0x71B18589,
+ 0x06B6B51F,
+ 0x9FBFE4A5,
+ 0xE8B8D433,
+ 0x7807C9A2,
+ 0x0F00F934,
+ 0x9609A88E,
+ 0xE10E9818,
+ 0x7F6A0DBB,
+ 0x086D3D2D,
+ 0x91646C97,
+ 0xE6635C01,
+ 0x6B6B51F4,
+ 0x1C6C6162,
+ 0x856530D8,
+ 0xF262004E,
+ 0x6C0695ED,
+ 0x1B01A57B,
+ 0x8208F4C1,
+ 0xF50FC457,
+ 0x65B0D9C6,
+ 0x12B7E950,
+ 0x8BBEB8EA,
+ 0xFCB9887C,
+ 0x62DD1DDF,
+ 0x15DA2D49,
+ 0x8CD37CF3,
+ 0xFBD44C65,
+ 0x4DB26158,
+ 0x3AB551CE,
+ 0xA3BC0074,
+ 0xD4BB30E2,
+ 0x4ADFA541,
+ 0x3DD895D7,
+ 0xA4D1C46D,
+ 0xD3D6F4FB,
+ 0x4369E96A,
+ 0x346ED9FC,
+ 0xAD678846,
+ 0xDA60B8D0,
+ 0x44042D73,
+ 0x33031DE5,
+ 0xAA0A4C5F,
+ 0xDD0D7CC9,
+ 0x5005713C,
+ 0x270241AA,
+ 0xBE0B1010,
+ 0xC90C2086,
+ 0x5768B525,
+ 0x206F85B3,
+ 0xB966D409,
+ 0xCE61E49F,
+ 0x5EDEF90E,
+ 0x29D9C998,
+ 0xB0D09822,
+ 0xC7D7A8B4,
+ 0x59B33D17,
+ 0x2EB40D81,
+ 0xB7BD5C3B,
+ 0xC0BA6CAD,
+ 0xEDB88320,
+ 0x9ABFB3B6,
+ 0x03B6E20C,
+ 0x74B1D29A,
+ 0xEAD54739,
+ 0x9DD277AF,
+ 0x04DB2615,
+ 0x73DC1683,
+ 0xE3630B12,
+ 0x94643B84,
+ 0x0D6D6A3E,
+ 0x7A6A5AA8,
+ 0xE40ECF0B,
+ 0x9309FF9D,
+ 0x0A00AE27,
+ 0x7D079EB1,
+ 0xF00F9344,
+ 0x8708A3D2,
+ 0x1E01F268,
+ 0x6906C2FE,
+ 0xF762575D,
+ 0x806567CB,
+ 0x196C3671,
+ 0x6E6B06E7,
+ 0xFED41B76,
+ 0x89D32BE0,
+ 0x10DA7A5A,
+ 0x67DD4ACC,
+ 0xF9B9DF6F,
+ 0x8EBEEFF9,
+ 0x17B7BE43,
+ 0x60B08ED5,
+ 0xD6D6A3E8,
+ 0xA1D1937E,
+ 0x38D8C2C4,
+ 0x4FDFF252,
+ 0xD1BB67F1,
+ 0xA6BC5767,
+ 0x3FB506DD,
+ 0x48B2364B,
+ 0xD80D2BDA,
+ 0xAF0A1B4C,
+ 0x36034AF6,
+ 0x41047A60,
+ 0xDF60EFC3,
+ 0xA867DF55,
+ 0x316E8EEF,
+ 0x4669BE79,
+ 0xCB61B38C,
+ 0xBC66831A,
+ 0x256FD2A0,
+ 0x5268E236,
+ 0xCC0C7795,
+ 0xBB0B4703,
+ 0x220216B9,
+ 0x5505262F,
+ 0xC5BA3BBE,
+ 0xB2BD0B28,
+ 0x2BB45A92,
+ 0x5CB36A04,
+ 0xC2D7FFA7,
+ 0xB5D0CF31,
+ 0x2CD99E8B,
+ 0x5BDEAE1D,
+ 0x9B64C2B0,
+ 0xEC63F226,
+ 0x756AA39C,
+ 0x026D930A,
+ 0x9C0906A9,
+ 0xEB0E363F,
+ 0x72076785,
+ 0x05005713,
+ 0x95BF4A82,
+ 0xE2B87A14,
+ 0x7BB12BAE,
+ 0x0CB61B38,
+ 0x92D28E9B,
+ 0xE5D5BE0D,
+ 0x7CDCEFB7,
+ 0x0BDBDF21,
+ 0x86D3D2D4,
+ 0xF1D4E242,
+ 0x68DDB3F8,
+ 0x1FDA836E,
+ 0x81BE16CD,
+ 0xF6B9265B,
+ 0x6FB077E1,
+ 0x18B74777,
+ 0x88085AE6,
+ 0xFF0F6A70,
+ 0x66063BCA,
+ 0x11010B5C,
+ 0x8F659EFF,
+ 0xF862AE69,
+ 0x616BFFD3,
+ 0x166CCF45,
+ 0xA00AE278,
+ 0xD70DD2EE,
+ 0x4E048354,
+ 0x3903B3C2,
+ 0xA7672661,
+ 0xD06016F7,
+ 0x4969474D,
+ 0x3E6E77DB,
+ 0xAED16A4A,
+ 0xD9D65ADC,
+ 0x40DF0B66,
+ 0x37D83BF0,
+ 0xA9BCAE53,
+ 0xDEBB9EC5,
+ 0x47B2CF7F,
+ 0x30B5FFE9,
+ 0xBDBDF21C,
+ 0xCABAC28A,
+ 0x53B39330,
+ 0x24B4A3A6,
+ 0xBAD03605,
+ 0xCDD70693,
+ 0x54DE5729,
+ 0x23D967BF,
+ 0xB3667A2E,
+ 0xC4614AB8,
+ 0x5D681B02,
+ 0x2A6F2B94,
+ 0xB40BBE37,
+ 0xC30C8EA1,
+ 0x5A05DF1B,
+ 0x2D02EF8D
+};
+
+uint32_t ventoy_crc32(void *Buffer, uint32_t Length)
+{
+ uint32_t i;
+ uint8_t *Ptr = Buffer;
+ uint32_t Crc = 0xFFFFFFFF;
+
+ for (i = 0; i < Length; i++, Ptr++)
+ {
+ Crc = (Crc >> 8) ^ g_crc_table[(uint8_t) Crc ^ *Ptr];
+ }
+
+ return Crc ^ 0xffffffff;
+}
+
--- /dev/null
+/******************************************************************************
+ * ventoy_define.h
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __VENTOY_DEFINE_H__
+#define __VENTOY_DEFINE_H__
+
+#if defined(_MSC_VER) || defined(WIN32)
+#include <windows.h>
+#include <stdint.h>
+#else
+#include <stdint.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <time.h>
+#include <linux/limits.h>
+#endif
+
+#define LOG_FILE "VentoyPlugson.log"
+
+#define SIZE_1MB 1048576
+#define SIZE_1GB 1073741824
+#define JSON_BUF_MAX (8 * SIZE_1MB)
+#define TAR_BUF_MAX (8 * SIZE_1MB)
+
+#define VTOYIMG_PART_START_BYTES (1024 * 1024)
+#define VTOYIMG_PART_START_SECTOR 2048
+
+#define VTOYEFI_PART_BYTES (32 * 1024 * 1024)
+#define VTOYEFI_PART_SECTORS 65536
+
+
+#pragma pack(1)
+
+typedef struct vtoy_guid
+{
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
+}vtoy_guid;
+
+typedef struct PART_TABLE
+{
+ uint8_t Active; // 0x00 0x80
+
+ uint8_t StartHead;
+ uint16_t StartSector : 6;
+ uint16_t StartCylinder : 10;
+
+ uint8_t FsFlag;
+
+ uint8_t EndHead;
+ uint16_t EndSector : 6;
+ uint16_t EndCylinder : 10;
+
+ uint32_t StartSectorId;
+ uint32_t SectorCount;
+}PART_TABLE;
+
+typedef struct MBR_HEAD
+{
+ uint8_t BootCode[446];
+ PART_TABLE PartTbl[4];
+ uint8_t Byte55;
+ uint8_t ByteAA;
+}MBR_HEAD;
+
+typedef struct VTOY_GPT_HDR
+{
+ char Signature[8]; /* EFI PART */
+ uint8_t Version[4];
+ uint32_t Length;
+ uint32_t Crc;
+ uint8_t Reserved1[4];
+ uint64_t EfiStartLBA;
+ uint64_t EfiBackupLBA;
+ uint64_t PartAreaStartLBA;
+ uint64_t PartAreaEndLBA;
+ vtoy_guid DiskGuid;
+ uint64_t PartTblStartLBA;
+ uint32_t PartTblTotNum;
+ uint32_t PartTblEntryLen;
+ uint32_t PartTblCrc;
+ uint8_t Reserved2[420];
+}VTOY_GPT_HDR;
+
+typedef struct VTOY_GPT_PART_TBL
+{
+ vtoy_guid PartType;
+ vtoy_guid PartGuid;
+ uint64_t StartLBA;
+ uint64_t LastLBA;
+ uint64_t Attr;
+ uint16_t Name[36];
+}VTOY_GPT_PART_TBL;
+
+typedef struct VTOY_GPT_INFO
+{
+ MBR_HEAD MBR;
+ VTOY_GPT_HDR Head;
+ VTOY_GPT_PART_TBL PartTbl[128];
+}VTOY_GPT_INFO;
+#pragma pack()
+
+
+#define MBR_PART_STYLE 0
+#define GPT_PART_STYLE 1
+
+#pragma pack(1)
+typedef struct ventoy_guid
+{
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
+}ventoy_guid;
+#pragma pack()
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define VLOG_LOG 1
+#define VLOG_DEBUG 2
+
+#define ulong unsigned long
+#define _ll long long
+#define _ull unsigned long long
+
+#if defined(_MSC_VER) || defined(WIN32)
+#define strlcpy(dst, src) strcpy_s(dst, sizeof(dst), src)
+#define scnprintf(dst, len, fmt, ...) sprintf_s(dst, len, fmt, ##__VA_ARGS__)
+
+#define vlog(fmt, ...) ventoy_syslog(VLOG_LOG, fmt, ##__VA_ARGS__)
+#define vdebug(fmt, ...) ventoy_syslog(VLOG_DEBUG, fmt, ##__VA_ARGS__)
+
+#define localtime_r(a,b) localtime_s(b,a)
+
+#define LASTERR GetLastError()
+
+#define CHECK_CLOSE_HANDLE(Handle) \
+{\
+ if (Handle != INVALID_HANDLE_VALUE) \
+ {\
+ CloseHandle(Handle); \
+ Handle = INVALID_HANDLE_VALUE; \
+ }\
+}
+
+#else
+#define strlcpy(dst, src) strncpy(dst, src, sizeof(dst) - 1)
+#define scnprintf(dst, len, fmt, args...) snprintf(dst, len, fmt, ##args)
+
+#define vlog(fmt, args...) ventoy_syslog(VLOG_LOG, fmt, ##args)
+#define vdebug(fmt, args...) ventoy_syslog(VLOG_DEBUG, fmt, ##args)
+
+#define MAX_PATH PATH_MAX
+
+#endif
+
+#define CHECK_FREE(p) \
+{\
+ if (p)\
+ {\
+ free(p); \
+ (p) = NULL; \
+ }\
+}
+
+void ventoy_syslog(int level, const char *Fmt, ...);
+void ventoy_set_loglevel(int level);
+uint32_t ventoy_crc32(void *Buffer, uint32_t Length);
+
+
+#if defined(_MSC_VER) || defined(WIN32)
+static __inline void * zalloc(size_t n)
+#else
+static inline void * zalloc(size_t n)
+#endif
+{
+ void *p = malloc(n);
+ if (p) memset(p, 0, n);
+ return p;
+}
+
+
+#endif /* __VENTOY_DEFINE_H__ */
+
--- /dev/null
+/******************************************************************************
+ * ventoy_disk.c ---- ventoy disk
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+
--- /dev/null
+/******************************************************************************
+ * ventoy_disk.h
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __VENTOY_DISK_H__
+#define __VENTOY_DISK_H__
+
+#define MAX_DISK 256
+typedef struct ventoy_disk
+{
+ char devname[64];
+
+ int pathcase;
+ char cur_fsname[64];
+ char cur_capacity[64];
+ char cur_model[256];
+ char cur_ventoy_ver[64];
+ int cur_secureboot;
+ int cur_part_style;
+
+}ventoy_disk;
+
+#if defined(_MSC_VER) || defined(WIN32)
+
+
+
+#else
+
+typedef enum
+{
+ VTOY_DEVICE_UNKNOWN = 0,
+ VTOY_DEVICE_SCSI,
+ VTOY_DEVICE_USB,
+ VTOY_DEVICE_IDE,
+ VTOY_DEVICE_DAC960,
+ VTOY_DEVICE_CPQARRAY,
+ VTOY_DEVICE_FILE,
+ VTOY_DEVICE_ATARAID,
+ VTOY_DEVICE_I2O,
+ VTOY_DEVICE_UBD,
+ VTOY_DEVICE_DASD,
+ VTOY_DEVICE_VIODASD,
+ VTOY_DEVICE_SX8,
+ VTOY_DEVICE_DM,
+ VTOY_DEVICE_XVD,
+ VTOY_DEVICE_SDMMC,
+ VTOY_DEVICE_VIRTBLK,
+ VTOY_DEVICE_AOE,
+ VTOY_DEVICE_MD,
+ VTOY_DEVICE_LOOP,
+ VTOY_DEVICE_NVME,
+ VTOY_DEVICE_RAM,
+ VTOY_DEVICE_PMEM,
+
+ VTOY_DEVICE_END
+}ventoy_dev_type;
+
+/* from <linux/major.h> */
+#define IDE0_MAJOR 3
+#define IDE1_MAJOR 22
+#define IDE2_MAJOR 33
+#define IDE3_MAJOR 34
+#define IDE4_MAJOR 56
+#define IDE5_MAJOR 57
+#define SCSI_CDROM_MAJOR 11
+#define SCSI_DISK0_MAJOR 8
+#define SCSI_DISK1_MAJOR 65
+#define SCSI_DISK2_MAJOR 66
+#define SCSI_DISK3_MAJOR 67
+#define SCSI_DISK4_MAJOR 68
+#define SCSI_DISK5_MAJOR 69
+#define SCSI_DISK6_MAJOR 70
+#define SCSI_DISK7_MAJOR 71
+#define SCSI_DISK8_MAJOR 128
+#define SCSI_DISK9_MAJOR 129
+#define SCSI_DISK10_MAJOR 130
+#define SCSI_DISK11_MAJOR 131
+#define SCSI_DISK12_MAJOR 132
+#define SCSI_DISK13_MAJOR 133
+#define SCSI_DISK14_MAJOR 134
+#define SCSI_DISK15_MAJOR 135
+#define COMPAQ_SMART2_MAJOR 72
+#define COMPAQ_SMART2_MAJOR1 73
+#define COMPAQ_SMART2_MAJOR2 74
+#define COMPAQ_SMART2_MAJOR3 75
+#define COMPAQ_SMART2_MAJOR4 76
+#define COMPAQ_SMART2_MAJOR5 77
+#define COMPAQ_SMART2_MAJOR6 78
+#define COMPAQ_SMART2_MAJOR7 79
+#define COMPAQ_SMART_MAJOR 104
+#define COMPAQ_SMART_MAJOR1 105
+#define COMPAQ_SMART_MAJOR2 106
+#define COMPAQ_SMART_MAJOR3 107
+#define COMPAQ_SMART_MAJOR4 108
+#define COMPAQ_SMART_MAJOR5 109
+#define COMPAQ_SMART_MAJOR6 110
+#define COMPAQ_SMART_MAJOR7 111
+#define DAC960_MAJOR 48
+#define ATARAID_MAJOR 114
+#define I2O_MAJOR1 80
+#define I2O_MAJOR2 81
+#define I2O_MAJOR3 82
+#define I2O_MAJOR4 83
+#define I2O_MAJOR5 84
+#define I2O_MAJOR6 85
+#define I2O_MAJOR7 86
+#define I2O_MAJOR8 87
+#define UBD_MAJOR 98
+#define DASD_MAJOR 94
+#define VIODASD_MAJOR 112
+#define AOE_MAJOR 152
+#define SX8_MAJOR1 160
+#define SX8_MAJOR2 161
+#define XVD_MAJOR 202
+#define SDMMC_MAJOR 179
+#define LOOP_MAJOR 7
+#define MD_MAJOR 9
+#define BLKEXT_MAJOR 259
+#define RAM_MAJOR 1
+
+#define SCSI_BLK_MAJOR(M) ( \
+ (M) == SCSI_DISK0_MAJOR \
+ || (M) == SCSI_CDROM_MAJOR \
+ || ((M) >= SCSI_DISK1_MAJOR && (M) <= SCSI_DISK7_MAJOR) \
+ || ((M) >= SCSI_DISK8_MAJOR && (M) <= SCSI_DISK15_MAJOR))
+
+#define IDE_BLK_MAJOR(M) \
+ ((M) == IDE0_MAJOR || \
+ (M) == IDE1_MAJOR || \
+ (M) == IDE2_MAJOR || \
+ (M) == IDE3_MAJOR || \
+ (M) == IDE4_MAJOR || \
+ (M) == IDE5_MAJOR)
+
+#define SX8_BLK_MAJOR(M) ((M) >= SX8_MAJOR1 && (M) <= SX8_MAJOR2)
+#define I2O_BLK_MAJOR(M) ((M) >= I2O_MAJOR1 && (M) <= I2O_MAJOR8)
+#define CPQARRAY_BLK_MAJOR(M) \
+ (((M) >= COMPAQ_SMART2_MAJOR && (M) <= COMPAQ_SMART2_MAJOR7) || \
+ (COMPAQ_SMART_MAJOR <= (M) && (M) <= COMPAQ_SMART_MAJOR7))
+
+#endif
+
+int ventoy_disk_init(void);
+void ventoy_disk_exit(void);
+int ventoy_get_disk_info(char **argv);
+const ventoy_disk * ventoy_get_disk_list(int *num);
+const ventoy_disk * ventoy_get_disk_node(int id);
+int CheckRuntimeEnvironment(char Letter, ventoy_disk *disk);
+
+#endif /* __VENTOY_DISK_H__ */
+
--- /dev/null
+/******************************************************************************
+ * ventoy_disk.c ---- ventoy disk
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/fs.h>
+#include <dirent.h>
+#include <time.h>
+#include <ventoy_define.h>
+#include <ventoy_disk.h>
+#include <ventoy_util.h>
+#include <fat_filelib.h>
+
+static int g_fatlib_media_fd = 0;
+static uint64_t g_fatlib_media_offset = 0;
+
+static const char *g_ventoy_dev_type_str[VTOY_DEVICE_END] =
+{
+ "unknown", "scsi", "USB", "ide", "dac960",
+ "cpqarray", "file", "ataraid", "i2o",
+ "ubd", "dasd", "viodasd", "sx8", "dm",
+ "xvd", "sd/mmc", "virtblk", "aoe",
+ "md", "loopback", "nvme", "brd", "pmem"
+};
+
+static const char * ventoy_get_dev_type_name(ventoy_dev_type type)
+{
+ return (type < VTOY_DEVICE_END) ? g_ventoy_dev_type_str[type] : "unknown";
+}
+
+static int ventoy_check_blk_major(int major, const char *type)
+{
+ int flag = 0;
+ int valid = 0;
+ int devnum = 0;
+ int len = 0;
+ char line[64];
+ char *pos = NULL;
+ FILE *fp = NULL;
+
+ fp = fopen("/proc/devices", "r");
+ if (!fp)
+ {
+ return 0;
+ }
+
+ len = (int)strlen(type);
+ while (fgets(line, sizeof(line), fp))
+ {
+ if (flag)
+ {
+ pos = strchr(line, ' ');
+ if (pos)
+ {
+ devnum = (int)strtol(line, NULL, 10);
+ if (devnum == major)
+ {
+ if (strncmp(pos + 1, type, len) == 0)
+ {
+ valid = 1;
+ }
+ break;
+ }
+ }
+ }
+ else if (strncmp(line, "Block devices:", 14) == 0)
+ {
+ flag = 1;
+ }
+ }
+
+ fclose(fp);
+ return valid;
+}
+
+static int ventoy_get_disk_devnum(const char *name, int *major, int* minor)
+{
+ int rc;
+ char *pos;
+ char devnum[16] = {0};
+
+ rc = ventoy_get_sys_file_line(devnum, sizeof(devnum), "/sys/block/%s/dev", name);
+ if (rc)
+ {
+ return 1;
+ }
+
+ pos = strstr(devnum, ":");
+ if (!pos)
+ {
+ return 1;
+ }
+
+ *major = (int)strtol(devnum, NULL, 10);
+ *minor = (int)strtol(pos + 1, NULL, 10);
+
+ return 0;
+}
+
+static ventoy_dev_type ventoy_get_dev_type(const char *name, int major, int minor)
+{
+ int rc;
+ char syspath[128];
+ char dstpath[256];
+
+ memset(syspath, 0, sizeof(syspath));
+ memset(dstpath, 0, sizeof(dstpath));
+
+ scnprintf(syspath, sizeof(syspath), "/sys/block/%s", name);
+ rc = readlink(syspath, dstpath, sizeof(dstpath) - 1);
+ if (rc > 0 && strstr(dstpath, "/usb"))
+ {
+ return VTOY_DEVICE_USB;
+ }
+
+ if (SCSI_BLK_MAJOR(major) && (minor % 0x10 == 0))
+ {
+ return VTOY_DEVICE_SCSI;
+ }
+ else if (IDE_BLK_MAJOR(major) && (minor % 0x40 == 0))
+ {
+ return VTOY_DEVICE_IDE;
+ }
+ else if (major == DAC960_MAJOR && (minor % 0x8 == 0))
+ {
+ return VTOY_DEVICE_DAC960;
+ }
+ else if (major == ATARAID_MAJOR && (minor % 0x10 == 0))
+ {
+ return VTOY_DEVICE_ATARAID;
+ }
+ else if (major == AOE_MAJOR && (minor % 0x10 == 0))
+ {
+ return VTOY_DEVICE_AOE;
+ }
+ else if (major == DASD_MAJOR && (minor % 0x4 == 0))
+ {
+ return VTOY_DEVICE_DASD;
+ }
+ else if (major == VIODASD_MAJOR && (minor % 0x8 == 0))
+ {
+ return VTOY_DEVICE_VIODASD;
+ }
+ else if (SX8_BLK_MAJOR(major) && (minor % 0x20 == 0))
+ {
+ return VTOY_DEVICE_SX8;
+ }
+ else if (I2O_BLK_MAJOR(major) && (minor % 0x10 == 0))
+ {
+ return VTOY_DEVICE_I2O;
+ }
+ else if (CPQARRAY_BLK_MAJOR(major) && (minor % 0x10 == 0))
+ {
+ return VTOY_DEVICE_CPQARRAY;
+ }
+ else if (UBD_MAJOR == major && (minor % 0x10 == 0))
+ {
+ return VTOY_DEVICE_UBD;
+ }
+ else if (XVD_MAJOR == major && (minor % 0x10 == 0))
+ {
+ return VTOY_DEVICE_XVD;
+ }
+ else if (SDMMC_MAJOR == major && (minor % 0x8 == 0))
+ {
+ return VTOY_DEVICE_SDMMC;
+ }
+ else if (ventoy_check_blk_major(major, "virtblk"))
+ {
+ return VTOY_DEVICE_VIRTBLK;
+ }
+ else if (major == LOOP_MAJOR)
+ {
+ return VTOY_DEVICE_LOOP;
+ }
+ else if (major == MD_MAJOR)
+ {
+ return VTOY_DEVICE_MD;
+ }
+ else if (major == RAM_MAJOR)
+ {
+ return VTOY_DEVICE_RAM;
+ }
+ else if (strstr(name, "nvme") && ventoy_check_blk_major(major, "blkext"))
+ {
+ return VTOY_DEVICE_NVME;
+ }
+ else if (strstr(name, "pmem") && ventoy_check_blk_major(major, "blkext"))
+ {
+ return VTOY_DEVICE_PMEM;
+ }
+
+ return VTOY_DEVICE_END;
+}
+
+static int ventoy_is_possible_blkdev(const char *name)
+{
+ if (name[0] == '.')
+ {
+ return 0;
+ }
+
+ /* /dev/ramX */
+ if (name[0] == 'r' && name[1] == 'a' && name[2] == 'm')
+ {
+ return 0;
+ }
+
+ /* /dev/zramX */
+ if (name[0] == 'z' && name[1] == 'r' && name[2] == 'a' && name[3] == 'm')
+ {
+ return 0;
+ }
+
+ /* /dev/loopX */
+ if (name[0] == 'l' && name[1] == 'o' && name[2] == 'o' && name[3] == 'p')
+ {
+ return 0;
+ }
+
+ /* /dev/dm-X */
+ if (name[0] == 'd' && name[1] == 'm' && name[2] == '-' && isdigit(name[3]))
+ {
+ return 0;
+ }
+
+ /* /dev/srX */
+ if (name[0] == 's' && name[1] == 'r' && isdigit(name[2]))
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+uint64_t ventoy_get_disk_size_in_byte(const char *disk)
+{
+ int fd;
+ int rc;
+ unsigned long long size = 0;
+ char diskpath[256] = {0};
+ char sizebuf[64] = {0};
+
+ // Try 1: get size from sysfs
+ scnprintf(diskpath, sizeof(diskpath) - 1, "/sys/block/%s/size", disk);
+ if (access(diskpath, F_OK) >= 0)
+ {
+ vdebug("get disk size from sysfs for %s\n", disk);
+
+ fd = open(diskpath, O_RDONLY | O_BINARY);
+ if (fd >= 0)
+ {
+ read(fd, sizebuf, sizeof(sizebuf));
+ size = strtoull(sizebuf, NULL, 10);
+ close(fd);
+ return (uint64_t)(size * 512);
+ }
+ }
+ else
+ {
+ vdebug("%s not exist \n", diskpath);
+ }
+
+ // Try 2: get size from ioctl
+ scnprintf(diskpath, sizeof(diskpath) - 1, "/dev/%s", disk);
+ fd = open(diskpath, O_RDONLY);
+ if (fd >= 0)
+ {
+ vdebug("get disk size from ioctl for %s\n", disk);
+ rc = ioctl(fd, BLKGETSIZE64, &size);
+ if (rc == -1)
+ {
+ size = 0;
+ vdebug("failed to ioctl %d\n", rc);
+ }
+ close(fd);
+ }
+ else
+ {
+ vdebug("failed to open %s %d\n", diskpath, errno);
+ }
+
+ vdebug("disk %s size %llu bytes\n", disk, size);
+ return size;
+}
+
+int ventoy_get_disk_vendor(const char *name, char *vendorbuf, int bufsize)
+{
+ return ventoy_get_sys_file_line(vendorbuf, bufsize, "/sys/block/%s/device/vendor", name);
+}
+
+int ventoy_get_disk_model(const char *name, char *modelbuf, int bufsize)
+{
+ return ventoy_get_sys_file_line(modelbuf, bufsize, "/sys/block/%s/device/model", name);
+}
+
+static int fatlib_media_sector_read(uint32 sector, uint8 *buffer, uint32 sector_count)
+{
+ lseek(g_fatlib_media_fd, (sector + g_fatlib_media_offset) * 512ULL, SEEK_SET);
+ read(g_fatlib_media_fd, buffer, sector_count * 512);
+
+ return 1;
+}
+
+static int fatlib_is_secure_boot_enable(void)
+{
+ void *flfile = NULL;
+
+ flfile = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
+ if (flfile)
+ {
+ vlog("/EFI/BOOT/grubx64_real.efi find, secure boot in enabled\n");
+ fl_fclose(flfile);
+ return 1;
+ }
+ else
+ {
+ vlog("/EFI/BOOT/grubx64_real.efi not exist\n");
+ }
+
+ return 0;
+}
+
+static int fatlib_get_ventoy_version(char *verbuf, int bufsize)
+{
+ int rc = 1;
+ int size = 0;
+ char *buf = NULL;
+ char *pos = NULL;
+ char *end = NULL;
+ void *flfile = NULL;
+
+ flfile = fl_fopen("/grub/grub.cfg", "rb");
+ if (flfile)
+ {
+ fl_fseek(flfile, 0, SEEK_END);
+ size = (int)fl_ftell(flfile);
+
+ fl_fseek(flfile, 0, SEEK_SET);
+
+ buf = malloc(size + 1);
+ if (buf)
+ {
+ fl_fread(buf, 1, size, flfile);
+ buf[size] = 0;
+
+ pos = strstr(buf, "VENTOY_VERSION=");
+ if (pos)
+ {
+ pos += strlen("VENTOY_VERSION=");
+ if (*pos == '"')
+ {
+ pos++;
+ }
+
+ end = pos;
+ while (*end != 0 && *end != '"' && *end != '\r' && *end != '\n')
+ {
+ end++;
+ }
+
+ *end = 0;
+
+ scnprintf(verbuf, bufsize - 1, "%s", pos);
+ rc = 0;
+ }
+ free(buf);
+ }
+
+ fl_fclose(flfile);
+ }
+ else
+ {
+ vdebug("No grub.cfg found\n");
+ }
+
+ return rc;
+}
+
+/* <BEGIN>: Deleted by longpanda, 20211028 PN:XX LABEL:XX */
+#if 0
+int ventoy_get_vtoy_data(ventoy_disk *info, int *ppartstyle)
+{
+ int i;
+ int fd;
+ int len;
+ int rc = 1;
+ int ret = 1;
+ int part_style;
+ uint64_t part1_start_sector;
+ uint64_t part1_sector_count;
+ uint64_t part2_start_sector;
+ uint64_t part2_sector_count;
+ uint64_t preserved_space;
+ char name[64] = {0};
+ disk_ventoy_data *vtoy = NULL;
+ VTOY_GPT_INFO *gpt = NULL;
+
+ vtoy = &(info->vtoydata);
+ gpt = &(vtoy->gptinfo);
+ memset(vtoy, 0, sizeof(disk_ventoy_data));
+
+ vdebug("ventoy_get_vtoy_data %s\n", info->disk_path);
+
+ if (info->size_in_byte < (2 * VTOYEFI_PART_BYTES))
+ {
+ vdebug("disk %s is too small %llu\n", info->disk_path, (_ull)info->size_in_byte);
+ return 1;
+ }
+
+ fd = open(info->disk_path, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ {
+ vdebug("failed to open %s %d\n", info->disk_path, errno);
+ return 1;
+ }
+
+ len = (int)read(fd, &(vtoy->gptinfo), sizeof(VTOY_GPT_INFO));
+ if (len != sizeof(VTOY_GPT_INFO))
+ {
+ vdebug("failed to read %s %d\n", info->disk_path, errno);
+ goto end;
+ }
+
+ if (gpt->MBR.Byte55 != 0x55 || gpt->MBR.ByteAA != 0xAA)
+ {
+ vdebug("Invalid mbr magic 0x%x 0x%x\n", gpt->MBR.Byte55, gpt->MBR.ByteAA);
+ goto end;
+ }
+
+ if (gpt->MBR.PartTbl[0].FsFlag == 0xEE && strncmp(gpt->Head.Signature, "EFI PART", 8) == 0)
+ {
+ part_style = GPT_PART_STYLE;
+ if (ppartstyle)
+ {
+ *ppartstyle = part_style;
+ }
+
+ if (gpt->PartTbl[0].StartLBA == 0 || gpt->PartTbl[1].StartLBA == 0)
+ {
+ vdebug("NO ventoy efi part layout <%llu %llu>\n",
+ (_ull)gpt->PartTbl[0].StartLBA,
+ (_ull)gpt->PartTbl[1].StartLBA);
+ goto end;
+ }
+
+ for (i = 0; i < 36; i++)
+ {
+ name[i] = (char)(gpt->PartTbl[1].Name[i]);
+ }
+ if (strcmp(name, "VTOYEFI"))
+ {
+ vdebug("Invalid efi part2 name <%s>\n", name);
+ goto end;
+ }
+
+ part1_start_sector = gpt->PartTbl[0].StartLBA;
+ part1_sector_count = gpt->PartTbl[0].LastLBA - part1_start_sector + 1;
+ part2_start_sector = gpt->PartTbl[1].StartLBA;
+ part2_sector_count = gpt->PartTbl[1].LastLBA - part2_start_sector + 1;
+
+ preserved_space = info->size_in_byte - (part2_start_sector + part2_sector_count + 33) * 512;
+ }
+ else
+ {
+ part_style = MBR_PART_STYLE;
+ if (ppartstyle)
+ {
+ *ppartstyle = part_style;
+ }
+
+ part1_start_sector = gpt->MBR.PartTbl[0].StartSectorId;
+ part1_sector_count = gpt->MBR.PartTbl[0].SectorCount;
+ part2_start_sector = gpt->MBR.PartTbl[1].StartSectorId;
+ part2_sector_count = gpt->MBR.PartTbl[1].SectorCount;
+
+ preserved_space = info->size_in_byte - (part2_start_sector + part2_sector_count) * 512;
+ }
+
+ if (part1_start_sector != VTOYIMG_PART_START_SECTOR ||
+ part2_sector_count != VTOYEFI_PART_SECTORS ||
+ (part1_start_sector + part1_sector_count) != part2_start_sector)
+ {
+ vdebug("Not valid ventoy partition layout [%llu %llu] [%llu %llu]\n",
+ part1_start_sector, part1_sector_count, part2_start_sector, part2_sector_count);
+ goto end;
+ }
+
+ vdebug("ventoy partition layout check OK: [%llu %llu] [%llu %llu]\n",
+ part1_start_sector, part1_sector_count, part2_start_sector, part2_sector_count);
+
+ vtoy->ventoy_valid = 1;
+
+ vdebug("now check secure boot for %s ...\n", info->disk_path);
+
+ g_fatlib_media_fd = fd;
+ g_fatlib_media_offset = part2_start_sector;
+ fl_init();
+
+ if (0 == fl_attach_media(fatlib_media_sector_read, NULL))
+ {
+ ret = fatlib_get_ventoy_version(vtoy->ventoy_ver, sizeof(vtoy->ventoy_ver));
+ if (ret == 0 && vtoy->ventoy_ver[0])
+ {
+ vtoy->secure_boot_flag = fatlib_is_secure_boot_enable();
+ }
+ else
+ {
+ vdebug("fatlib_get_ventoy_version failed %d\n", ret);
+ }
+ }
+ else
+ {
+ vdebug("fl_attach_media failed\n");
+ }
+
+ fl_shutdown();
+ g_fatlib_media_fd = -1;
+ g_fatlib_media_offset = 0;
+
+ if (vtoy->ventoy_ver[0] == 0)
+ {
+ vtoy->ventoy_ver[0] = '?';
+ }
+
+ if (0 == vtoy->ventoy_valid)
+ {
+ goto end;
+ }
+
+ lseek(fd, 2040 * 512, SEEK_SET);
+ read(fd, vtoy->rsvdata, sizeof(vtoy->rsvdata));
+
+ vtoy->preserved_space = preserved_space;
+ vtoy->partition_style = part_style;
+ vtoy->part2_start_sector = part2_start_sector;
+
+ rc = 0;
+end:
+ vtoy_safe_close_fd(fd);
+ return rc;
+}
+#endif /* #if 0 */
+/* <END> : Deleted by longpanda, 20211028 PN:XX LABEL:XX */
+
+
+int ventoy_get_disk_info(char **argv)
+{
+ uint64_t size;
+ char vendor[128];
+ char model[128];
+ char *disk = argv[4];
+
+ if (strncmp(argv[4], "/dev/", 4) == 0)
+ {
+ disk += 4;
+ }
+ ventoy_get_disk_vendor(disk, vendor, sizeof(vendor));
+ ventoy_get_disk_model(disk, model, sizeof(model));
+
+ scnprintf(g_sysinfo.cur_model, sizeof(g_sysinfo.cur_model), "%s %s [%s]", vendor, model, argv[4]);
+ strlcpy(g_sysinfo.cur_ventoy_ver, argv[5]);
+ strlcpy(g_sysinfo.cur_fsname, argv[6]);
+ g_sysinfo.cur_part_style = (int)strtol(argv[7], NULL, 10);
+ g_sysinfo.cur_secureboot = (int)strtol(argv[8], NULL, 10);
+
+ size = ventoy_get_disk_size_in_byte(disk);
+ scnprintf(g_sysinfo.cur_capacity, sizeof(g_sysinfo.cur_capacity), "%dGB", (int)ventoy_get_human_readable_gb(size));
+
+ return 0;
+}
+
+int ventoy_disk_init(void)
+{
+ return 0;
+}
+
+void ventoy_disk_exit(void)
+{
+}
+
+
--- /dev/null
+/******************************************************************************
+ * ventoy_disk.c ---- ventoy disk
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <windows.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <time.h>
+#include <ventoy_define.h>
+#include <ventoy_disk.h>
+#include <ventoy_util.h>
+#include <fat_filelib.h>
+
+static int g_disk_num = 0;
+ventoy_disk *g_disk_list = NULL;
+
+int ventoy_disk_init(void)
+{
+ char Letter = 'A';
+ DWORD Drives = GetLogicalDrives();
+
+ vlog("ventoy disk init ...\n");
+
+ g_disk_list = zalloc(sizeof(ventoy_disk) * MAX_DISK);
+
+ while (Drives)
+ {
+ if (Drives & 0x01)
+ {
+ if (CheckRuntimeEnvironment(Letter, g_disk_list + g_disk_num) == 0)
+ {
+ g_disk_list[g_disk_num].devname[0] = Letter;
+ g_disk_num++;
+ vlog("%C: is ventoy disk\n", Letter);
+ }
+ else
+ {
+ memset(g_disk_list + g_disk_num, 0, sizeof(ventoy_disk));
+ vlog("%C: is NOT ventoy disk\n", Letter);
+ }
+ }
+
+ Letter++;
+ Drives >>= 1;
+ }
+
+ return 0;
+}
+
+void ventoy_disk_exit(void)
+{
+ vlog("ventoy disk exit ...\n");
+
+ check_free(g_disk_list);
+ g_disk_list = NULL;
+ g_disk_num = 0;
+}
+
+const ventoy_disk * ventoy_get_disk_list(int *num)
+{
+ *num = g_disk_num;
+ return g_disk_list;
+}
+
+const ventoy_disk * ventoy_get_disk_node(int id)
+{
+ if (id >= 0 && id < g_disk_num)
+ {
+ return g_disk_list + id;
+ }
+
+ return NULL;
+}
+
--- /dev/null
+/******************************************************************************\r
+ * ventoy_json.c\r
+ *\r
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License as\r
+ * published by the Free Software Foundation; either version 3 of the\r
+ * License, or (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ * General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <stdint.h>\r
+#include <string.h>\r
+#include <stdarg.h>\r
+#include <errno.h>\r
+#if defined(_MSC_VER) || defined(WIN32)\r
+#else\r
+#include <unistd.h>\r
+#include <sys/types.h>\r
+#include <linux/limits.h>\r
+#endif\r
+#include <ventoy_define.h>\r
+#include <ventoy_util.h>\r
+#include <ventoy_json.h>\r
+\r
+static void vtoy_json_free(VTOY_JSON *pstJsonHead)\r
+{\r
+ VTOY_JSON *pstNext = NULL;\r
+\r
+ while (NULL != pstJsonHead)\r
+ {\r
+ pstNext = pstJsonHead->pstNext;\r
+ if ((pstJsonHead->enDataType < JSON_TYPE_BUTT) && (NULL != pstJsonHead->pstChild))\r
+ {\r
+ vtoy_json_free(pstJsonHead->pstChild);\r
+ }\r
+\r
+ free(pstJsonHead);\r
+ pstJsonHead = pstNext;\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+static char *vtoy_json_skip(const char *pcData)\r
+{\r
+ while ((NULL != pcData) && ('\0' != *pcData) && (*pcData <= 32))\r
+ {\r
+ pcData++;\r
+ }\r
+\r
+ return (char *)pcData;\r
+}\r
+\r
+VTOY_JSON *vtoy_json_find_item\r
+(\r
+ VTOY_JSON *pstJson,\r
+ JSON_TYPE enDataType,\r
+ const char *szKey\r
+)\r
+{\r
+ while (NULL != pstJson)\r
+ {\r
+ if ((enDataType == pstJson->enDataType) && \r
+ (0 == strcmp(szKey, pstJson->pcName)))\r
+ {\r
+ return pstJson;\r
+ }\r
+ pstJson = pstJson->pstNext;\r
+ }\r
+ \r
+ return NULL;\r
+}\r
+\r
+static int vtoy_json_parse_number\r
+(\r
+ VTOY_JSON *pstJson, \r
+ const char *pcData,\r
+ const char **ppcEnd\r
+)\r
+{\r
+ unsigned long Value;\r
+\r
+ Value = strtoul(pcData, (char **)ppcEnd, 10);\r
+ if (*ppcEnd == pcData)\r
+ {\r
+ vdebug("Failed to parse json number %s.\n", pcData);\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pstJson->enDataType = JSON_TYPE_NUMBER;\r
+ pstJson->unData.lValue = Value;\r
+ \r
+ return JSON_SUCCESS;\r
+}\r
+\r
+static int vtoy_json_parse_string\r
+(\r
+ char *pcNewStart,\r
+ char *pcRawStart,\r
+ VTOY_JSON *pstJson, \r
+ const char *pcData,\r
+ const char **ppcEnd\r
+)\r
+{\r
+ uint32_t uiLen = 0;\r
+ const char *pcPos = NULL;\r
+ const char *pcTmp = pcData + 1;\r
+ \r
+ *ppcEnd = pcData;\r
+\r
+ if ('\"' != *pcData)\r
+ {\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pcPos = strchr(pcTmp, '\"');\r
+ if ((NULL == pcPos) || (pcPos < pcTmp))\r
+ {\r
+ vdebug("Invalid string %s.\n", pcData);\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ if (*(pcPos - 1) == '\\')\r
+ {\r
+ for (pcPos++; *pcPos; pcPos++)\r
+ {\r
+ if (*pcPos == '"' && *(pcPos - 1) != '\\')\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if (*pcPos == 0 || pcPos < pcTmp)\r
+ {\r
+ vdebug("Invalid quotes string %s.", pcData);\r
+ return JSON_FAILED;\r
+ }\r
+ }\r
+\r
+ *ppcEnd = pcPos + 1;\r
+ uiLen = (uint32_t)(unsigned long)(pcPos - pcTmp); \r
+ \r
+ pstJson->enDataType = JSON_TYPE_STRING;\r
+ pstJson->unData.pcStrVal = pcNewStart + (pcTmp - pcRawStart);\r
+ pstJson->unData.pcStrVal[uiLen] = '\0';\r
+ \r
+ return JSON_SUCCESS;\r
+}\r
+\r
+static int vtoy_json_parse_array\r
+(\r
+ char *pcNewStart,\r
+ char *pcRawStart,\r
+ VTOY_JSON *pstJson, \r
+ const char *pcData,\r
+ const char **ppcEnd\r
+)\r
+{\r
+ int Ret = JSON_SUCCESS;\r
+ VTOY_JSON *pstJsonChild = NULL;\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ const char *pcTmp = pcData + 1;\r
+\r
+ *ppcEnd = pcData;\r
+ pstJson->enDataType = JSON_TYPE_ARRAY;\r
+\r
+ if ('[' != *pcData)\r
+ {\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pcTmp = vtoy_json_skip(pcTmp);\r
+\r
+ if (']' == *pcTmp)\r
+ {\r
+ *ppcEnd = pcTmp + 1;\r
+ return JSON_SUCCESS;\r
+ }\r
+\r
+ JSON_NEW_ITEM(pstJson->pstChild, JSON_FAILED);\r
+\r
+ Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJson->pstChild, pcTmp, ppcEnd);\r
+ if (JSON_SUCCESS != Ret)\r
+ {\r
+ vdebug("Failed to parse array child.\n");\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pstJsonChild = pstJson->pstChild;\r
+ pcTmp = vtoy_json_skip(*ppcEnd);\r
+ while ((NULL != pcTmp) && (',' == *pcTmp))\r
+ {\r
+ JSON_NEW_ITEM(pstJsonItem, JSON_FAILED);\r
+ pstJsonChild->pstNext = pstJsonItem;\r
+ pstJsonItem->pstPrev = pstJsonChild;\r
+ pstJsonChild = pstJsonItem;\r
+\r
+ Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);\r
+ if (JSON_SUCCESS != Ret)\r
+ {\r
+ vdebug("Failed to parse array child.\n");\r
+ return JSON_FAILED;\r
+ }\r
+ pcTmp = vtoy_json_skip(*ppcEnd);\r
+ }\r
+\r
+ if ((NULL != pcTmp) && (']' == *pcTmp))\r
+ {\r
+ *ppcEnd = pcTmp + 1;\r
+ return JSON_SUCCESS;\r
+ }\r
+ else\r
+ {\r
+ *ppcEnd = pcTmp;\r
+ return JSON_FAILED;\r
+ }\r
+}\r
+\r
+static int vtoy_json_parse_object\r
+(\r
+ char *pcNewStart,\r
+ char *pcRawStart,\r
+ VTOY_JSON *pstJson, \r
+ const char *pcData,\r
+ const char **ppcEnd\r
+)\r
+{\r
+ int Ret = JSON_SUCCESS;\r
+ VTOY_JSON *pstJsonChild = NULL;\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ const char *pcTmp = pcData + 1;\r
+\r
+ *ppcEnd = pcData;\r
+ pstJson->enDataType = JSON_TYPE_OBJECT;\r
+\r
+ if ('{' != *pcData)\r
+ {\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pcTmp = vtoy_json_skip(pcTmp);\r
+ if ('}' == *pcTmp)\r
+ {\r
+ *ppcEnd = pcTmp + 1;\r
+ return JSON_SUCCESS;\r
+ }\r
+\r
+ JSON_NEW_ITEM(pstJson->pstChild, JSON_FAILED);\r
+\r
+ Ret = vtoy_json_parse_string(pcNewStart, pcRawStart, pstJson->pstChild, pcTmp, ppcEnd);\r
+ if (JSON_SUCCESS != Ret)\r
+ {\r
+ vdebug("Failed to parse array child.\n");\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pstJsonChild = pstJson->pstChild;\r
+ pstJsonChild->pcName = pstJsonChild->unData.pcStrVal;\r
+ pstJsonChild->unData.pcStrVal = NULL;\r
+\r
+ pcTmp = vtoy_json_skip(*ppcEnd);\r
+ if ((NULL == pcTmp) || (':' != *pcTmp))\r
+ {\r
+ *ppcEnd = pcTmp;\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);\r
+ if (JSON_SUCCESS != Ret)\r
+ {\r
+ vdebug("Failed to parse array child.\n");\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pcTmp = vtoy_json_skip(*ppcEnd);\r
+ while ((NULL != pcTmp) && (',' == *pcTmp))\r
+ {\r
+ JSON_NEW_ITEM(pstJsonItem, JSON_FAILED);\r
+ pstJsonChild->pstNext = pstJsonItem;\r
+ pstJsonItem->pstPrev = pstJsonChild;\r
+ pstJsonChild = pstJsonItem;\r
+\r
+ Ret = vtoy_json_parse_string(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);\r
+ if (JSON_SUCCESS != Ret)\r
+ {\r
+ vdebug("Failed to parse array child.\n");\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pcTmp = vtoy_json_skip(*ppcEnd);\r
+ pstJsonChild->pcName = pstJsonChild->unData.pcStrVal;\r
+ pstJsonChild->unData.pcStrVal = NULL;\r
+ if ((NULL == pcTmp) || (':' != *pcTmp))\r
+ {\r
+ *ppcEnd = pcTmp;\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ Ret = vtoy_json_parse_value(pcNewStart, pcRawStart, pstJsonChild, vtoy_json_skip(pcTmp + 1), ppcEnd);\r
+ if (JSON_SUCCESS != Ret)\r
+ {\r
+ vdebug("Failed to parse array child.\n");\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ pcTmp = vtoy_json_skip(*ppcEnd);\r
+ }\r
+\r
+ if ((NULL != pcTmp) && ('}' == *pcTmp))\r
+ {\r
+ *ppcEnd = pcTmp + 1;\r
+ return JSON_SUCCESS;\r
+ }\r
+ else\r
+ {\r
+ *ppcEnd = pcTmp;\r
+ return JSON_FAILED;\r
+ }\r
+}\r
+\r
+int vtoy_json_parse_value\r
+(\r
+ char *pcNewStart,\r
+ char *pcRawStart,\r
+ VTOY_JSON *pstJson, \r
+ const char *pcData,\r
+ const char **ppcEnd\r
+)\r
+{\r
+ pcData = vtoy_json_skip(pcData);\r
+ \r
+ switch (*pcData)\r
+ {\r
+ case 'n':\r
+ {\r
+ if (0 == strncmp(pcData, "null", 4))\r
+ {\r
+ pstJson->enDataType = JSON_TYPE_NULL;\r
+ *ppcEnd = pcData + 4;\r
+ return JSON_SUCCESS;\r
+ }\r
+ break;\r
+ }\r
+ case 'f':\r
+ {\r
+ if (0 == strncmp(pcData, "false", 5))\r
+ {\r
+ pstJson->enDataType = JSON_TYPE_BOOL;\r
+ pstJson->unData.lValue = 0;\r
+ *ppcEnd = pcData + 5;\r
+ return JSON_SUCCESS;\r
+ }\r
+ break;\r
+ }\r
+ case 't':\r
+ {\r
+ if (0 == strncmp(pcData, "true", 4))\r
+ {\r
+ pstJson->enDataType = JSON_TYPE_BOOL;\r
+ pstJson->unData.lValue = 1;\r
+ *ppcEnd = pcData + 4;\r
+ return JSON_SUCCESS;\r
+ }\r
+ break;\r
+ }\r
+ case '\"':\r
+ {\r
+ return vtoy_json_parse_string(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);\r
+ }\r
+ case '[':\r
+ {\r
+ return vtoy_json_parse_array(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);\r
+ }\r
+ case '{':\r
+ {\r
+ return vtoy_json_parse_object(pcNewStart, pcRawStart, pstJson, pcData, ppcEnd);\r
+ }\r
+ case '-':\r
+ {\r
+ return vtoy_json_parse_number(pstJson, pcData, ppcEnd);\r
+ }\r
+ default :\r
+ {\r
+ if (*pcData >= '0' && *pcData <= '9')\r
+ {\r
+ return vtoy_json_parse_number(pstJson, pcData, ppcEnd);\r
+ }\r
+ }\r
+ }\r
+\r
+ *ppcEnd = pcData;\r
+ vdebug("Invalid json data %u.\n", (uint8_t)(*pcData));\r
+ return JSON_FAILED;\r
+}\r
+\r
+VTOY_JSON * vtoy_json_create(void)\r
+{\r
+ VTOY_JSON *pstJson = NULL;\r
+\r
+ pstJson = (VTOY_JSON *)zalloc(sizeof(VTOY_JSON));\r
+ if (NULL == pstJson)\r
+ {\r
+ return NULL;\r
+ }\r
+ \r
+ return pstJson;\r
+}\r
+\r
+int vtoy_json_parse(VTOY_JSON *pstJson, const char *szJsonData)\r
+{\r
+ uint32_t uiMemSize = 0;\r
+ int Ret = JSON_SUCCESS;\r
+ char *pcNewBuf = NULL;\r
+ const char *pcEnd = NULL;\r
+\r
+ uiMemSize = strlen(szJsonData) + 1;\r
+ pcNewBuf = (char *)malloc(uiMemSize);\r
+ if (NULL == pcNewBuf)\r
+ {\r
+ vdebug("Failed to alloc new buf.\n");\r
+ return JSON_FAILED;\r
+ }\r
+ memcpy(pcNewBuf, szJsonData, uiMemSize);\r
+ pcNewBuf[uiMemSize - 1] = 0;\r
+\r
+ Ret = vtoy_json_parse_value(pcNewBuf, (char *)szJsonData, pstJson, szJsonData, &pcEnd);\r
+ if (JSON_SUCCESS != Ret)\r
+ {\r
+ vdebug("Failed to parse json data start=%p, end=%p.\n", szJsonData, pcEnd);\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_parse_ex(VTOY_JSON *pstJson, const char *szJsonData, int szLen)\r
+{\r
+ uint32_t uiMemSize = 0;\r
+ int Ret = JSON_SUCCESS;\r
+ char *pcNewBuf = NULL;\r
+ const char *pcEnd = NULL;\r
+\r
+ uiMemSize = (uint32_t)szLen;\r
+ pcNewBuf = (char *)malloc(uiMemSize + 1);\r
+ if (NULL == pcNewBuf)\r
+ {\r
+ vdebug("Failed to alloc new buf.\n");\r
+ return JSON_FAILED;\r
+ }\r
+ memcpy(pcNewBuf, szJsonData, szLen);\r
+ pcNewBuf[uiMemSize] = 0;\r
+\r
+ Ret = vtoy_json_parse_value(pcNewBuf, (char *)szJsonData, pstJson, szJsonData, &pcEnd);\r
+ if (JSON_SUCCESS != Ret)\r
+ {\r
+ vdebug("Failed to parse json data start=%p, end=%p\n", szJsonData, pcEnd);\r
+ return JSON_FAILED;\r
+ }\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_scan_parse\r
+(\r
+ const VTOY_JSON *pstJson,\r
+ uint32_t uiParseNum,\r
+ VTOY_JSON_PARSE_S *pstJsonParse\r
+)\r
+{ \r
+ uint32_t i = 0;\r
+ const VTOY_JSON *pstJsonCur = NULL;\r
+ VTOY_JSON_PARSE_S *pstCurParse = NULL;\r
+\r
+ for (pstJsonCur = pstJson; NULL != pstJsonCur; pstJsonCur = pstJsonCur->pstNext)\r
+ {\r
+ if ((JSON_TYPE_OBJECT == pstJsonCur->enDataType) ||\r
+ (JSON_TYPE_ARRAY == pstJsonCur->enDataType))\r
+ {\r
+ continue;\r
+ }\r
+\r
+ for (i = 0, pstCurParse = NULL; i < uiParseNum; i++)\r
+ {\r
+ if (0 == strcmp(pstJsonParse[i].pcKey, pstJsonCur->pcName))\r
+ { \r
+ pstCurParse = pstJsonParse + i;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (NULL == pstCurParse)\r
+ {\r
+ continue;\r
+ }\r
+ \r
+ switch (pstJsonCur->enDataType)\r
+ {\r
+ case JSON_TYPE_NUMBER:\r
+ {\r
+ if (sizeof(uint32_t) == pstCurParse->uiBufSize)\r
+ {\r
+ *(uint32_t *)(pstCurParse->pDataBuf) = (uint32_t)pstJsonCur->unData.lValue;\r
+ }\r
+ else if (sizeof(uint16_t) == pstCurParse->uiBufSize)\r
+ {\r
+ *(uint16_t *)(pstCurParse->pDataBuf) = (uint16_t)pstJsonCur->unData.lValue;\r
+ }\r
+ else if (sizeof(uint8_t) == pstCurParse->uiBufSize)\r
+ {\r
+ *(uint8_t *)(pstCurParse->pDataBuf) = (uint8_t)pstJsonCur->unData.lValue;\r
+ }\r
+ else if ((pstCurParse->uiBufSize > sizeof(uint64_t)))\r
+ {\r
+ scnprintf((char *)pstCurParse->pDataBuf, pstCurParse->uiBufSize, "%llu", \r
+ (unsigned long long)(pstJsonCur->unData.lValue));\r
+ }\r
+ else\r
+ {\r
+ vdebug("Invalid number data buf size %u.\n", pstCurParse->uiBufSize);\r
+ }\r
+ break;\r
+ }\r
+ case JSON_TYPE_STRING:\r
+ {\r
+ scnprintf((char *)pstCurParse->pDataBuf, pstCurParse->uiBufSize, "%s", pstJsonCur->unData.pcStrVal);\r
+ break;\r
+ }\r
+ case JSON_TYPE_BOOL:\r
+ {\r
+ *(uint8_t *)(pstCurParse->pDataBuf) = (pstJsonCur->unData.lValue) > 0 ? 1 : 0;\r
+ break;\r
+ }\r
+ default :\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_scan_array\r
+(\r
+ VTOY_JSON *pstJson, \r
+ const char *szKey, \r
+ VTOY_JSON **ppstArrayItem\r
+)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ \r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_ARRAY, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ vdebug("Key %s is not found in json data.\n", szKey);\r
+ return JSON_NOT_FOUND;\r
+ }\r
+\r
+ *ppstArrayItem = pstJsonItem;\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_scan_array_ex\r
+(\r
+ VTOY_JSON *pstJson, \r
+ const char *szKey, \r
+ VTOY_JSON **ppstArrayItem\r
+)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ \r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_ARRAY, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ vdebug("Key %s is not found in json data.\n", szKey);\r
+ return JSON_NOT_FOUND;\r
+ }\r
+ \r
+ *ppstArrayItem = pstJsonItem->pstChild;\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_scan_object\r
+(\r
+ VTOY_JSON *pstJson, \r
+ const char *szKey, \r
+ VTOY_JSON **ppstObjectItem\r
+)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+\r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_OBJECT, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ vdebug("Key %s is not found in json data.\n", szKey);\r
+ return JSON_NOT_FOUND;\r
+ }\r
+\r
+ *ppstObjectItem = pstJsonItem;\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_get_int\r
+(\r
+ VTOY_JSON *pstJson, \r
+ const char *szKey, \r
+ int *piValue\r
+)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ \r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ //vdebug("Key %s is not found in json data.\n", szKey);\r
+ return JSON_NOT_FOUND;\r
+ }\r
+\r
+ *piValue = (int)pstJsonItem->unData.lValue;\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_get_uint\r
+(\r
+ VTOY_JSON *pstJson, \r
+ const char *szKey, \r
+ uint32_t *puiValue\r
+)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ \r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ vdebug("Key %s is not found in json data.\n", szKey);\r
+ return JSON_NOT_FOUND;\r
+ }\r
+\r
+ *puiValue = (uint32_t)pstJsonItem->unData.lValue;\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_get_uint64\r
+(\r
+ VTOY_JSON *pstJson, \r
+ const char *szKey, \r
+ uint64_t *pui64Value\r
+)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ \r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_NUMBER, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ vdebug("Key %s is not found in json data.\n", szKey);\r
+ return JSON_NOT_FOUND;\r
+ }\r
+\r
+ *pui64Value = (uint64_t)pstJsonItem->unData.lValue;\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_get_bool\r
+(\r
+ VTOY_JSON *pstJson,\r
+ const char *szKey, \r
+ uint8_t *pbValue\r
+)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ \r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_BOOL, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ vdebug("Key %s is not found in json data.\n", szKey);\r
+ return JSON_NOT_FOUND;\r
+ }\r
+\r
+ *pbValue = pstJsonItem->unData.lValue > 0 ? 1 : 0;\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_get_string\r
+(\r
+ VTOY_JSON *pstJson, \r
+ const char *szKey, \r
+ uint32_t uiBufLen,\r
+ char *pcBuf\r
+)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+ \r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_STRING, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ //vdebug("Key %s is not found in json data.\n", szKey);\r
+ return JSON_NOT_FOUND;\r
+ }\r
+\r
+ scnprintf(pcBuf, uiBufLen, "%s", pstJsonItem->unData.pcStrVal);\r
+\r
+ return JSON_SUCCESS;\r
+}\r
+\r
+const char * vtoy_json_get_string_ex(VTOY_JSON *pstJson, const char *szKey)\r
+{\r
+ VTOY_JSON *pstJsonItem = NULL;\r
+\r
+ if ((NULL == pstJson) || (NULL == szKey))\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ pstJsonItem = vtoy_json_find_item(pstJson, JSON_TYPE_STRING, szKey);\r
+ if (NULL == pstJsonItem)\r
+ {\r
+ //vdebug("Key %s is not found in json data.\n", szKey);\r
+ return NULL;\r
+ }\r
+\r
+ return pstJsonItem->unData.pcStrVal;\r
+}\r
+\r
+int vtoy_json_destroy(VTOY_JSON *pstJson)\r
+{\r
+ if (NULL == pstJson)\r
+ { \r
+ return JSON_SUCCESS;\r
+ }\r
+\r
+ if (NULL != pstJson->pstChild)\r
+ {\r
+ vtoy_json_free(pstJson->pstChild);\r
+ }\r
+\r
+ if (NULL != pstJson->pstNext)\r
+ {\r
+ vtoy_json_free(pstJson->pstNext);\r
+ }\r
+\r
+ free(pstJson);\r
+ \r
+ return JSON_SUCCESS;\r
+}\r
+\r
+int vtoy_json_escape_string(char *buf, int buflen, const char *str, int newline)\r
+{\r
+ char last = 0;\r
+ int count = 0;\r
+\r
+ *buf++ = '"';\r
+ count++;\r
+\r
+ while (*str)\r
+ {\r
+ if (*str == '"' && last != '\\')\r
+ {\r
+ *buf = '\\';\r
+ count++;\r
+ buf++;\r
+ }\r
+ \r
+ *buf = *str;\r
+ count++;\r
+ buf++;\r
+\r
+ last = *str;\r
+ str++;\r
+ }\r
+\r
+ *buf++ = '"';\r
+ count++;\r
+ \r
+ *buf++ = ',';\r
+ count++;\r
+\r
+ if (newline)\r
+ {\r
+ *buf++ = '\n';\r
+ count++; \r
+ }\r
+\r
+ return count;\r
+}\r
--- /dev/null
+/******************************************************************************
+ * ventoy_json.h
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __VENTOY_JSON_H__
+#define __VENTOY_JSON_H__
+
+#define JSON_NEW_ITEM(pstJson, ret) \
+{ \
+ (pstJson) = (VTOY_JSON *)zalloc(sizeof(VTOY_JSON)); \
+ if (NULL == (pstJson)) \
+ { \
+ vdebug("Failed to alloc memory for json."); \
+ return (ret); \
+ } \
+}
+
+#if defined(_MSC_VER) || defined(WIN32)
+#define ssprintf(curpos, buf, len, fmt, ...) \
+ curpos += scnprintf(buf + curpos, len - curpos, fmt, ##__VA_ARGS__)
+
+#define VTOY_JSON_IS_SKIPABLE(c) (((c) <= 32) ? 1 : 0)
+
+#define VTOY_JSON_PRINT_PREFIX(uiDepth, ...) \
+{ \
+ uint32_t _uiLoop = 0; \
+ for (_uiLoop = 0; _uiLoop < (uiDepth); _uiLoop++) \
+ { \
+ ssprintf(uiCurPos, pcBuf, uiBufLen, " "); \
+ } \
+ ssprintf(uiCurPos, pcBuf, uiBufLen, ##__VA_ARGS__); \
+}
+#else
+
+#define ssprintf(curpos, buf, len, fmt, args...) \
+ curpos += scnprintf(buf + curpos, len - curpos, fmt, ##args)
+
+#define VTOY_JSON_IS_SKIPABLE(c) (((c) <= 32) ? 1 : 0)
+
+#define VTOY_JSON_PRINT_PREFIX(uiDepth, args...) \
+{ \
+ uint32_t _uiLoop = 0; \
+ for (_uiLoop = 0; _uiLoop < (uiDepth); _uiLoop++) \
+ { \
+ ssprintf(uiCurPos, pcBuf, uiBufLen, " "); \
+ } \
+ ssprintf(uiCurPos, pcBuf, uiBufLen, ##args); \
+}
+#endif
+
+
+#define VTOY_JSON_SUCCESS_RET "{ \"result\" : \"success\" }"
+#define VTOY_JSON_FAILED_RET "{ \"result\" : \"failed\" }"
+#define VTOY_JSON_INVALID_RET "{ \"result\" : \"invalidfmt\" }"
+#define VTOY_JSON_TOKEN_ERR_RET "{ \"result\" : \"tokenerror\" }"
+#define VTOY_JSON_EXIST_RET "{ \"result\" : \"exist\" }"
+#define VTOY_JSON_TIMEOUT_RET "{ \"result\" : \"timeout\" }"
+#define VTOY_JSON_BUSY_RET "{ \"result\" : \"busy\" }"
+#define VTOY_JSON_INUSE_RET "{ \"result\" : \"inuse\" }"
+#define VTOY_JSON_NOTFOUND_RET "{ \"result\" : \"notfound\" }"
+#define VTOY_JSON_NOTRUNNING_RET "{ \"result\" : \"notrunning\" }"
+#define VTOY_JSON_NOT_READY_RET "{ \"result\" : \"notready\" }"
+#define VTOY_JSON_NOT_SUPPORT_RET "{ \"result\" : \"notsupport\" }"
+#define VTOY_JSON_MBR_2TB_RET "{ \"result\" : \"mbr2tb\" }"
+#define VTOY_JSON_INVALID_RSV_RET "{ \"result\" : \"reserve_invalid\" }"
+#define VTOY_JSON_FILE_NOT_FOUND_RET "{ \"result\" : \"file_not_found\" }"
+
+typedef enum tagJSON_TYPE
+{
+ JSON_TYPE_NUMBER = 0,
+ JSON_TYPE_STRING,
+ JSON_TYPE_BOOL,
+ JSON_TYPE_ARRAY,
+ JSON_TYPE_OBJECT,
+ JSON_TYPE_NULL,
+ JSON_TYPE_BUTT
+}JSON_TYPE;
+
+typedef struct tagVTOY_JSON
+{
+ struct tagVTOY_JSON *pstPrev;
+ struct tagVTOY_JSON *pstNext;
+ struct tagVTOY_JSON *pstChild;
+
+ JSON_TYPE enDataType;
+ union
+ {
+ char *pcStrVal;
+ int iNumVal;
+ uint64_t lValue;
+ }unData;
+
+ char *pcName;
+}VTOY_JSON;
+
+#define VTOY_JSON_FMT_BEGIN(uiCurPos, pcBuf, uiBufLen) \
+{\
+ uint32_t __uiCurPos = (uiCurPos);\
+ uint32_t __uiBufLen = (uiBufLen);\
+ char *__pcBuf = (pcBuf);
+
+#define VTOY_JSON_FMT_END(uiCurPos) \
+ (uiCurPos) = __uiCurPos;\
+}
+
+#define VTOY_JSON_FMT_OBJ_BEGIN() ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "{")
+#define VTOY_JSON_FMT_OBJ_BEGIN_L(P) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s{", P)
+#define VTOY_JSON_FMT_OBJ_BEGIN_N() ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "{\n")
+#define VTOY_JSON_FMT_OBJ_BEGIN_LN(P) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s{\n", P)
+
+#define VTOY_JSON_FMT_OBJ_END() \
+{\
+ if (',' == *(__pcBuf + (__uiCurPos - 1)))\
+ {\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "}");\
+}
+
+#define VTOY_JSON_FMT_OBJ_ENDEX() \
+{\
+ if (',' == *(__pcBuf + (__uiCurPos - 1)))\
+ {\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "},");\
+}
+
+
+
+#define VTOY_JSON_FMT_KEY(Key) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\":", (Key))
+#define VTOY_JSON_FMT_KEY_L(P, Key) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\":", P, (Key))
+
+
+#define VTOY_JSON_FMT_ITEM(Item) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\",", (Item))
+#define VTOY_JSON_FMT_ITEM_L(P, Item) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\",", P, (Item))
+#define VTOY_JSON_FMT_ITEM_LN(P, Item) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\",\n", P, (Item))
+#define VTOY_JSON_FMT_ITEM_PATH_LN(P, Item) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\",\n", P, ventoy_real_path(Item))
+
+#define VTOY_JSON_FMT_COMA() ssprintf(__uiCurPos, __pcBuf, __uiBufLen, ",")
+#define VTOY_JSON_FMT_COMA_N(cnt) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, ",\n")
+#define VTOY_JSON_FMT_COMA_N_CNT(cnt) if ((cnt) > 0) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, ",\n")
+
+
+#define VTOY_JSON_FMT_APPEND_BEGIN() \
+{ \
+ if ('}' == *(__pcBuf + (__uiCurPos - 1)))\
+ {\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, ",");\
+}
+
+#define VTOY_JSON_FMT_APPEND_END() \
+{ \
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "}");\
+}
+
+#define VTOY_JSON_FMT_ARY_BEGIN() ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "[")
+#define VTOY_JSON_FMT_ARY_BEGIN_N() ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "[\n")
+
+#define VTOY_JSON_FMT_ARY_END() \
+{\
+ if (',' == *(__pcBuf + (__uiCurPos - 1)))\
+ {\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "]");\
+}
+#define VTOY_JSON_FMT_ARY_ENDEX() \
+{\
+ if (',' == *(__pcBuf + (__uiCurPos - 1)))\
+ {\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "],");\
+}
+
+
+
+#define VTOY_JSON_FMT_OBJ_END_L(P) \
+{\
+ if ('\n' == *(__pcBuf + (__uiCurPos - 1)) && ',' == *(__pcBuf + (__uiCurPos - 2)))\
+ {\
+ *(__pcBuf + (__uiCurPos - 2)) = '\n';\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s}%s", P);\
+}
+#define VTOY_JSON_FMT_OBJ_ENDEX_L(P) \
+{\
+ if ('\n' == *(__pcBuf + (__uiCurPos - 1)) && ',' == *(__pcBuf + (__uiCurPos - 2)))\
+ {\
+ *(__pcBuf + (__uiCurPos - 2)) = '\n';\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s},%s", P);\
+}
+
+#define VTOY_JSON_FMT_OBJ_END_LN(P) \
+{\
+ if ('\n' == *(__pcBuf + (__uiCurPos - 1)) && ',' == *(__pcBuf + (__uiCurPos - 2)))\
+ {\
+ *(__pcBuf + (__uiCurPos - 2)) = '\n';\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s}\n", P);\
+}
+#define VTOY_JSON_FMT_OBJ_ENDEX_LN(P) \
+{\
+ if ('\n' == *(__pcBuf + (__uiCurPos - 1)) && ',' == *(__pcBuf + (__uiCurPos - 2)))\
+ {\
+ *(__pcBuf + (__uiCurPos - 2)) = '\n';\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s},\n", P);\
+}
+
+
+
+
+#define VTOY_JSON_FMT_ARY_END_L(P) \
+{\
+ if ('\n' == *(__pcBuf + (__uiCurPos - 1)) && ',' == *(__pcBuf + (__uiCurPos - 2)))\
+ {\
+ *(__pcBuf + (__uiCurPos - 2)) = '\n';\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s]", P);\
+}
+
+#define VTOY_JSON_FMT_ARY_END_LN(P) \
+{\
+ if ('\n' == *(__pcBuf + (__uiCurPos - 1)) && ',' == *(__pcBuf + (__uiCurPos - 2)))\
+ {\
+ *(__pcBuf + (__uiCurPos - 2)) = '\n';\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s]\n", P);\
+}
+
+#define VTOY_JSON_FMT_ARY_ENDEX_L(P) \
+{\
+ if ('\n' == *(__pcBuf + (__uiCurPos - 1)) && ',' == *(__pcBuf + (__uiCurPos - 2)))\
+ {\
+ *(__pcBuf + (__uiCurPos - 2)) = '\n';\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s],", P);\
+}
+
+
+#define VTOY_JSON_FMT_ARY_ENDEX_LN(P) \
+{\
+ if ('\n' == *(__pcBuf + (__uiCurPos - 1)) && ',' == *(__pcBuf + (__uiCurPos - 2)))\
+ {\
+ *(__pcBuf + (__uiCurPos - 2)) = '\n';\
+ __uiCurPos -= 1;\
+ }\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s],\n", P);\
+}
+
+
+
+
+#define VTOY_JSON_FMT_UINT64(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %llu,", Key, (_ull)Val)
+
+#define VTOY_JSON_FMT_ULONG(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %lu,", Key, Val)
+#define VTOY_JSON_FMT_LONG(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %ld,", Key, Val)
+
+#define VTOY_JSON_FMT_UINT(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %u,", Key, Val)
+#define VTOY_JSON_FMT_UINT_N(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %u,\n", Key, Val)
+#define VTOY_JSON_FMT_UINT_L(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": %u,", P, Key, Val)
+#define VTOY_JSON_FMT_UINT_LN(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": %u,\n", P, Key, Val)
+
+
+#define VTOY_JSON_FMT_STRUINT(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": \"%u\",", Key, Val)
+#define VTOY_JSON_FMT_STRUINT_N(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": \"%u\",\n", Key, Val)
+#define VTOY_JSON_FMT_STRUINT_L(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": \"%u\",", P, Key, Val)
+#define VTOY_JSON_FMT_STRUINT_LN(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": \"%u\",\n", P, Key, Val)
+
+#define VTOY_JSON_FMT_STRSINT(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": \"%d\",", Key, Val)
+#define VTOY_JSON_FMT_STRSINT_N(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": \"%d\",\n", Key, Val)
+#define VTOY_JSON_FMT_STRSINT_L(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": \"%d\",", P, Key, Val)
+#define VTOY_JSON_FMT_STRSINT_LN(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": \"%d\",\n", P, Key, Val)
+
+#define VTOY_JSON_FMT_CTRL_INT(Prefix, Key, Field) \
+ if (def->Field != data->Field) \
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s{ \"%s\": \"%d\" },\n", Prefix, Key, data->Field)
+
+#define VTOY_JSON_FMT_CTRL_STRN(P, Key, Field) \
+ if (strcmp(def->Field, data->Field)) \
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s{ \"%s\": \"%s\" },\n", P, Key, data->Field)
+
+#define VTOY_JSON_FMT_CTRL_STRN_STR(P, Key, ptr) \
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s{ \"%s\": \"%s\" },\n", P, Key, ptr)
+
+#define VTOY_JSON_FMT_CTRL_PUB_STRN(P, Key, Field) \
+ if (strcmp(def->Field, g_pub_path)) \
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s{ \"%s\": \"%s\" },\n", P, Key, g_pub_path)
+
+
+#define VTOY_JSON_FMT_DIFF_STRN(P, Key, Field) \
+ if (strcmp(def->Field, data->Field)) \
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": \"%s\",\n", P, Key, data->Field)
+
+
+#define VTOY_JSON_FMT_STRINT64(Key, Val) \
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": \"%llu\",", Key, Val)
+
+#define VTOY_JSON_FMT_SINT(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %d,", Key, Val)
+#define VTOY_JSON_FMT_SINT_N(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %d,\n", Key, Val)
+#define VTOY_JSON_FMT_SINT_L(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": %d,", P, Key, Val)
+#define VTOY_JSON_FMT_SINT_LN(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": %d,\n", P, Key, Val)
+
+#define VTOY_JSON_FMT_DUBL(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %.1lf,", Key, Val)
+#define VTOY_JSON_FMT_DUBL2(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": %10.02lf,", Key, Val)
+
+#define VTOY_JSON_FMT_STRN(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": \"%s\",", Key, Val)
+#define VTOY_JSON_FMT_STRN_N(Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": \"%s\",\n", Key, Val)
+#define VTOY_JSON_FMT_STRN_L(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": \"%s\",", P, Key, Val)
+#define VTOY_JSON_FMT_STRN_LN(P, Key, Val) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": \"%s\",\n", P, Key, Val)
+#define VTOY_JSON_FMT_STRN_PATH_LN(P, Key, Val) \
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": \"%s\",\n", P, Key, ventoy_real_path(Val))
+
+int vtoy_json_escape_string(char *buf, int buflen, const char *str, int newline);
+
+#define VTOY_JSON_FMT_STRN_EX_LN(P, Key, Val) \
+{\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "%s\"%s\": ", P, Key);\
+ __uiCurPos += vtoy_json_escape_string(__pcBuf + __uiCurPos, __uiBufLen - __uiCurPos, Val, 1);\
+}
+
+
+#define VTOY_JSON_FMT_NULL(Key) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": null,", Key)
+
+#define VTOY_JSON_FMT_TRUE(Key) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": true,", (Key))
+#define VTOY_JSON_FMT_FALSE(Key) ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": false,", (Key))
+
+#define VTOY_JSON_FMT_BOOL(Key, Val) \
+{\
+ if (0 == (Val))\
+ {\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": false,", (Key));\
+ }\
+ else \
+ {\
+ ssprintf(__uiCurPos, __pcBuf, __uiBufLen, "\"%s\": true,", (Key));\
+ }\
+}
+
+typedef struct tagVTOY_JSON_PARSE
+{
+ char *pcKey;
+ void *pDataBuf;
+ uint32_t uiBufSize;
+}VTOY_JSON_PARSE_S;
+
+#define JSON_SUCCESS 0
+#define JSON_FAILED 1
+#define JSON_NOT_FOUND 2
+
+int vtoy_json_parse_value
+(
+ char *pcNewStart,
+ char *pcRawStart,
+ VTOY_JSON *pstJson,
+ const char *pcData,
+ const char **ppcEnd
+);
+VTOY_JSON * vtoy_json_create(void);
+int vtoy_json_parse(VTOY_JSON *pstJson, const char *szJsonData);
+int vtoy_json_parse_ex(VTOY_JSON *pstJson, const char *szJsonData, int szLen);
+int vtoy_json_destroy(VTOY_JSON *pstJson);
+VTOY_JSON *vtoy_json_find_item
+(
+ VTOY_JSON *pstJson,
+ JSON_TYPE enDataType,
+ const char *szKey
+);
+int vtoy_json_scan_parse
+(
+ const VTOY_JSON *pstJson,
+ uint32_t uiParseNum,
+ VTOY_JSON_PARSE_S *pstJsonParse
+);
+int vtoy_json_get_int
+(
+ VTOY_JSON *pstJson,
+ const char *szKey,
+ int *piValue
+);
+int vtoy_json_get_uint
+(
+ VTOY_JSON *pstJson,
+ const char *szKey,
+ uint32_t *puiValue
+);
+int vtoy_json_get_uint64
+(
+ VTOY_JSON *pstJson,
+ const char *szKey,
+ uint64_t *pui64Value
+);
+int vtoy_json_get_bool
+(
+ VTOY_JSON *pstJson,
+ const char *szKey,
+ uint8_t *pbValue
+);
+int vtoy_json_get_string
+(
+ VTOY_JSON *pstJson,
+ const char *szKey,
+ uint32_t uiBufLen,
+ char *pcBuf
+);
+const char * vtoy_json_get_string_ex(VTOY_JSON *pstJson, const char *szKey);
+
+#endif /* __VENTOY_JSON_H__ */
+
--- /dev/null
+/******************************************************************************
+ * ventoy_log.c ---- ventoy log
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <ventoy_define.h>
+#include <ventoy_util.h>
+
+extern char g_log_file[MAX_PATH];
+static int g_ventoy_log_level = VLOG_DEBUG;
+static pthread_mutex_t g_log_mutex;
+
+int ventoy_log_init(void)
+{
+ if (ventoy_get_file_size(g_log_file) >= SIZE_1MB)
+ {
+ #if defined(_MSC_VER) || defined(WIN32)
+ DeleteFileA(g_log_file);
+ #else
+ remove(g_log_file);
+ #endif
+ }
+
+ pthread_mutex_init(&g_log_mutex, NULL);
+ return 0;
+}
+
+void ventoy_log_exit(void)
+{
+ pthread_mutex_destroy(&g_log_mutex);
+}
+
+void ventoy_set_loglevel(int level)
+{
+ g_ventoy_log_level = level;
+}
+
+
+
+void ventoy_syslog_printf(const char *Fmt, ...)
+{
+ char log[512];
+ va_list arg;
+ time_t stamp;
+ struct tm ttm;
+ FILE *fp;
+
+ time(&stamp);
+ localtime_r(&stamp, &ttm);
+
+ va_start(arg, Fmt);
+#if defined(_MSC_VER) || defined(WIN32)
+ vsnprintf_s(log, 512, _TRUNCATE, Fmt, arg);
+#else
+ vsnprintf(log, 512, Fmt, arg);
+#endif
+ va_end(arg);
+
+ pthread_mutex_lock(&g_log_mutex);
+
+#if defined(_MSC_VER) || defined(WIN32)
+ fopen_s(&fp, g_log_file, "a+");
+#else
+ fp = fopen(g_log_file, "a+");
+#endif
+
+ if (fp)
+ {
+ fprintf(fp, "[%04u/%02u/%02u %02u:%02u:%02u] %s",
+ ttm.tm_year, ttm.tm_mon + 1, ttm.tm_mday,
+ ttm.tm_hour, ttm.tm_min, ttm.tm_sec,
+ log);
+ fclose(fp);
+
+ #ifdef VENTOY_SIM
+ printf("[%04u/%02u/%02u %02u:%02u:%02u] %s",
+ ttm.tm_year, ttm.tm_mon + 1, ttm.tm_mday,
+ ttm.tm_hour, ttm.tm_min, ttm.tm_sec,
+ log);
+ #endif
+ }
+ pthread_mutex_unlock(&g_log_mutex);
+}
+
+void ventoy_syslog(int level, const char *Fmt, ...)
+{
+ char log[512];
+ va_list arg;
+ time_t stamp;
+ struct tm ttm;
+ FILE *fp;
+
+ if (level > g_ventoy_log_level)
+ {
+ return;
+ }
+
+ time(&stamp);
+ localtime_r(&stamp, &ttm);
+
+ va_start(arg, Fmt);
+#if defined(_MSC_VER) || defined(WIN32)
+ vsnprintf_s(log, 512, _TRUNCATE, Fmt, arg);
+#else
+ vsnprintf(log, 512, Fmt, arg);
+#endif
+ va_end(arg);
+
+ pthread_mutex_lock(&g_log_mutex);
+#if defined(_MSC_VER) || defined(WIN32)
+ fopen_s(&fp, g_log_file, "a+");
+#else
+ fp = fopen(g_log_file, "a+");
+#endif
+ if (fp)
+ {
+ fprintf(fp, "[%04u/%02u/%02u %02u:%02u:%02u] %s",
+ ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_mday,
+ ttm.tm_hour, ttm.tm_min, ttm.tm_sec,
+ log);
+ fclose(fp);
+
+ #ifdef VENTOY_SIM
+ printf("[%04u/%02u/%02u %02u:%02u:%02u] %s",
+ ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_mday,
+ ttm.tm_hour, ttm.tm_min, ttm.tm_sec,
+ log);
+ #endif
+ }
+ pthread_mutex_unlock(&g_log_mutex);
+}
+
--- /dev/null
+/******************************************************************************
+ * ventoy_md5.c ---- ventoy md5
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+const static uint32_t k[64] =
+{
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+const static uint32_t r[] =
+{
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+};
+
+#define LEFTROTATE(x, c) (((x) << (c)) | ((x) >> (32 - (c))))
+#define to_bytes(val, bytes) *((uint32_t *)(bytes)) = (val)
+
+#define ROTATE_CALC() \
+{\
+ temp = d; \
+ d = c; \
+ c = b; \
+ b = b + LEFTROTATE((a + f + k[i] + w[g]), r[i]); \
+ a = temp; \
+}
+
+void ventoy_md5(const void *data, uint32_t len, uint8_t *md5)
+{
+ uint32_t h0, h1, h2, h3;
+ uint32_t w[16];
+ uint32_t a, b, c, d, i, f, g, temp;
+ uint32_t offset, mod, delta;
+ uint8_t postbuf[128] = {0};
+
+ // Initialize variables - simple count in nibbles:
+ h0 = 0x67452301;
+ h1 = 0xefcdab89;
+ h2 = 0x98badcfe;
+ h3 = 0x10325476;
+
+ //Pre-processing:
+ //append "1" bit to message
+ //append "0" bits until message length in bits ¡Ô 448 (mod 512)
+ //append length mod (2^64) to message
+
+ mod = len % 64;
+ if (mod)
+ {
+ memcpy(postbuf, (const uint8_t *)data + len - mod, mod);
+ }
+
+ postbuf[mod] = 0x80;
+ if (mod < 56)
+ {
+ to_bytes(len * 8, postbuf + 56);
+ to_bytes(len >> 29, postbuf + 60);
+ delta = 64;
+ }
+ else
+ {
+ to_bytes(len * 8, postbuf + 120);
+ to_bytes(len >> 29, postbuf + 124);
+ delta = 128;
+ }
+
+ len -= mod;
+
+ for (offset = 0; offset < len + delta; offset += 64)
+ {
+ if (offset < len)
+ {
+ memcpy(w, (const uint8_t *)data + offset, 64);
+ }
+ else
+ {
+ memcpy(w, postbuf + offset - len, 64);
+ }
+
+ // Initialize hash value for this chunk:
+ a = h0;
+ b = h1;
+ c = h2;
+ d = h3;
+
+ // Main loop:
+ for (i = 0; i < 16; i++)
+ {
+ f = (b & c) | ((~b) & d);
+ g = i;
+ ROTATE_CALC();
+ }
+
+ for (i = 16; i < 32; i++)
+ {
+ f = (d & b) | ((~d) & c);
+ g = (5 * i + 1) % 16;
+ ROTATE_CALC();
+ }
+
+ for (i = 32; i < 48; i++)
+ {
+ f = b ^ c ^ d;
+ g = (3 * i + 5) % 16;
+ ROTATE_CALC();
+ }
+
+ for (i = 48; i < 64; i++)
+ {
+ f = c ^ (b | (~d));
+ g = (7 * i) % 16;
+ ROTATE_CALC();
+ }
+
+ // Add this chunk's hash to result so far:
+ h0 += a;
+ h1 += b;
+ h2 += c;
+ h3 += d;
+ }
+
+ //var char md5[16] := h0 append h1 append h2 append h3 //(Output is in little-endian)
+ to_bytes(h0, md5);
+ to_bytes(h1, md5 + 4);
+ to_bytes(h2, md5 + 8);
+ to_bytes(h3, md5 + 12);
+}
+
--- /dev/null
+/******************************************************************************
+ * ventoy_util.c ---- ventoy util
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <ventoy_define.h>
+#include <ventoy_util.h>
+
+
+static int g_tar_filenum = 0;
+static char *g_tar_buffer = NULL;
+static ventoy_file *g_tar_filelist = NULL;
+
+SYSINFO g_sysinfo;
+
+unsigned char *g_unxz_buffer = NULL;
+int g_unxz_len = 0;
+
+void unxz_error(char *x)
+{
+ vlog("%s\n", x);
+}
+
+int unxz_flush(void *src, unsigned int size)
+{
+ memcpy(g_unxz_buffer + g_unxz_len, src, size);
+ g_unxz_len += (int)size;
+
+ return (int)size;
+}
+
+
+uint64_t ventoy_get_human_readable_gb(uint64_t SizeBytes)
+{
+ int i;
+ int Pow2 = 1;
+ double Delta;
+ double GB = SizeBytes * 1.0 / 1000 / 1000 / 1000;
+
+ if ((SizeBytes % SIZE_1GB) == 0)
+ {
+ return (uint64_t)(SizeBytes / SIZE_1GB);
+ }
+
+ for (i = 0; i < 12; i++)
+ {
+ if (Pow2 > GB)
+ {
+ Delta = (Pow2 - GB) / Pow2;
+ }
+ else
+ {
+ Delta = (GB - Pow2) / Pow2;
+ }
+
+ if (Delta < 0.05)
+ {
+ return Pow2;
+ }
+
+ Pow2 <<= 1;
+ }
+
+ return (uint64_t)GB;
+}
+
+int ventoy_read_file_to_buf(const char *FileName, int ExtLen, void **Bufer, int *BufLen)
+{
+ int FileSize;
+ FILE *fp = NULL;
+ void *Data = NULL;
+
+#if defined(_MSC_VER) || defined(WIN32)
+ fopen_s(&fp, FileName, "rb");
+#else
+ fp = fopen(FileName, "rb");
+#endif
+ if (fp == NULL)
+ {
+ vlog("Failed to open file %s", FileName);
+ return 1;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ FileSize = (int)ftell(fp);
+
+ Data = malloc(FileSize + ExtLen);
+ if (!Data)
+ {
+ fclose(fp);
+ return 1;
+ }
+
+ fseek(fp, 0, SEEK_SET);
+ fread(Data, 1, FileSize, fp);
+
+ fclose(fp);
+
+ *Bufer = Data;
+ *BufLen = FileSize;
+
+ return 0;
+}
+
+ventoy_file * ventoy_tar_find_file(const char *path)
+{
+ int i;
+ int len;
+ ventoy_file *node = g_tar_filelist;
+
+ len = (int)strlen(path);
+
+ for (i = 0; i < g_tar_filenum; i++, node++)
+ {
+ if (node->pathlen == len && memcmp(node->path, path, len) == 0)
+ {
+ return node;
+ }
+
+ if (node->pathlen > len)
+ {
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+
+int ventoy_www_init(void)
+{
+ int i = 0;
+ int j = 0;
+ int size = 0;
+ int tarsize = 0;
+ int offset = 0;
+ ventoy_file *node = NULL;
+ ventoy_file *node2 = NULL;
+ VENTOY_TAR_HEAD *pHead = NULL;
+ ventoy_file tmpnode;
+
+ if (!g_tar_filelist)
+ {
+ g_tar_filelist = malloc(VENTOY_FILE_MAX * sizeof(ventoy_file));
+ g_tar_buffer = malloc(TAR_BUF_MAX);
+ g_tar_filenum = 0;
+ }
+
+ if ((!g_tar_filelist) || (!g_tar_buffer))
+ {
+ return 1;
+ }
+
+ if (ventoy_decompress_tar(g_tar_buffer, TAR_BUF_MAX, &tarsize))
+ {
+ return 1;
+ }
+
+ pHead = (VENTOY_TAR_HEAD *)g_tar_buffer;
+ node = g_tar_filelist;
+
+ while (g_tar_filenum < VENTOY_FILE_MAX && size < tarsize && memcmp(pHead->magic, TMAGIC, 5) == 0)
+ {
+ if (pHead->typeflag == REGTYPE)
+ {
+ node->size = (int)strtol(pHead->size, NULL, 8);
+ node->pathlen = (int)scnprintf(node->path, MAX_PATH, "%s", pHead->name);
+ node->addr = pHead + 1;
+
+ if (node->pathlen == 13 && strcmp(pHead->name, "www/buildtime") == 0)
+ {
+ scnprintf(g_sysinfo.buildtime, sizeof(g_sysinfo.buildtime), "%s", (char *)node->addr);
+ vlog("Plugson buildtime %s\n", g_sysinfo.buildtime);
+ }
+
+ offset = 512 + VENTOY_UP_ALIGN(node->size, 512);
+
+ node++;
+ g_tar_filenum++;
+ }
+ else
+ {
+ offset = 512;
+ }
+
+ pHead = (VENTOY_TAR_HEAD *)((char *)pHead + offset);
+ size += offset;
+ }
+
+
+ //sort
+ for (i = 0; i < g_tar_filenum; i++)
+ for (j = i + 1; j < g_tar_filenum; j++)
+ {
+ node = g_tar_filelist + i;
+ node2 = g_tar_filelist + j;
+
+ if (node->pathlen > node2->pathlen)
+ {
+ memcpy(&tmpnode, node, sizeof(ventoy_file));
+ memcpy(node, node2, sizeof(ventoy_file));
+ memcpy(node2, &tmpnode, sizeof(ventoy_file));
+ }
+ }
+
+ vlog("Total extract %d files from tar file.\n", g_tar_filenum);
+
+ return 0;
+}
+
+void ventoy_www_exit(void)
+{
+ check_free(g_tar_filelist);
+ check_free(g_tar_buffer);
+ g_tar_filelist = NULL;
+ g_tar_buffer = NULL;
+ g_tar_filenum = 0;
+}
+
+
+void ventoy_get_json_path(char *path, char *backup)
+{
+#if defined(_MSC_VER) || defined(WIN32)
+ scnprintf(path, 64, "%C:\\ventoy\\ventoy.json", g_cur_dir[0]);
+if (backup)
+{
+ scnprintf(backup, 64, "%C:\\ventoy\\ventoy_backup.json", g_cur_dir[0]);
+}
+#else
+ scnprintf(path, 64, "%s/ventoy/ventoy.json", g_cur_dir);
+if (backup)
+{
+ scnprintf(backup, 64, "%s/ventoy/ventoy_backup.json", g_cur_dir);
+}
+
+#endif
+}
+
+
--- /dev/null
+/******************************************************************************
+ * ventoy_util.h
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __VENTOY_UTIL_H__
+#define __VENTOY_UTIL_H__
+
+#define check_free(p) if (p) free(p)
+#define vtoy_safe_close_fd(fd) \
+{\
+ if ((fd) >= 0) \
+ { \
+ close(fd); \
+ (fd) = -1; \
+ }\
+}
+
+extern char g_cur_dir[MAX_PATH];
+extern char g_ventoy_dir[MAX_PATH];
+
+#if defined(_MSC_VER) || defined(WIN32)
+
+typedef HANDLE pthread_mutex_t;
+
+static __inline int pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
+{
+ (void)unused;
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ return *mutex == NULL ? -1 : 0;
+}
+
+static __inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ return CloseHandle(*mutex) == 0 ? -1 : 0;
+}
+
+static __inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ return ReleaseMutex(*mutex) == 0 ? -1 : 0;
+}
+
+static __inline int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
+}
+
+int ventoy_path_case(char *path, int slash);
+
+#else
+int ventoy_get_sys_file_line(char *buffer, int buflen, const char *fmt, ...);
+
+#define UINT8 uint8_t
+#define UINT16 uint16_t
+#define UINT32 uint32_t
+#define UINT64 uint64_t
+
+static inline int ventoy_path_case(char *path, int slash)
+{
+ (void)path;
+ (void)slash;
+ return 0;
+}
+#endif
+
+
+#define LANGUAGE_EN 0
+#define LANGUAGE_CN 1
+
+typedef struct SYSINFO
+{
+ char buildtime[128];
+ int syntax_error;
+
+ int language;
+ int pathcase;
+ char cur_fsname[64];
+ char cur_capacity[64];
+ char cur_model[256];
+ char cur_ventoy_ver[64];
+ int cur_secureboot;
+ int cur_part_style;
+
+ char ip[32];
+ char port[16];
+}SYSINFO;
+
+extern SYSINFO g_sysinfo;
+
+
+
+
+#define TMAGIC "ustar"
+
+#define REGTYPE '0'
+#define AREGTYPE '\0'
+#define LNKTYPE '1'
+#define CHRTYPE '3'
+#define BLKTYPE '4'
+#define DIRTYPE '5'
+#define FIFOTYPE '6'
+#define CONTTYPE '7'
+
+#pragma pack(1)
+
+typedef struct tag_tar_head
+{
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char typeflag;
+ char linkname[100];
+ char magic[6];
+ char version[2];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char prefix[155];
+ char padding[12];
+}VENTOY_TAR_HEAD;
+
+
+
+typedef struct VENTOY_MAGIC
+{
+ uint32_t magic1; // 0x51 0x52 0x53 0x54
+ uint32_t xzlen; //
+ uint32_t magic2; // 0xa1 0xa2 0xa3 0xa4
+}VENTOY_MAGIC;
+
+
+
+#pragma pack()
+
+#define VENTOY_UP_ALIGN(N, align) (((N) + ((align) - 1)) / (align) * (align))
+#define VENTOY_FILE_MAX 2048
+
+
+#if defined(_MSC_VER) || defined(WIN32)
+#define million_sleep(a) Sleep(a)
+#else
+#define million_sleep(a) usleep((a) * 1000)
+#endif
+
+
+typedef struct ventoy_file
+{
+ int size;
+ char path[MAX_PATH];
+ int pathlen;
+ void *addr;
+}ventoy_file;
+
+
+
+int ventoy_is_file_exist(const char *fmt, ...);
+int ventoy_is_directory_exist(const char *fmt, ...);
+void ventoy_gen_preudo_uuid(void *uuid);
+uint64_t ventoy_get_human_readable_gb(uint64_t SizeBytes);
+void ventoy_md5(const void *data, uint32_t len, uint8_t *md5);
+int ventoy_is_disk_mounted(const char *devpath);
+int unxz(unsigned char *in, int in_size,
+ int (*fill)(void *dest, unsigned int size),
+ int (*flush)(void *src, unsigned int size),
+ unsigned char *out, int *in_used,
+ void (*error)(char *x));
+int ventoy_read_file_to_buf(const char *FileName, int ExtLen, void **Bufer, int *BufLen);
+int ventoy_write_buf_to_file(const char *FileName, void *Bufer, int BufLen);
+const char * ventoy_get_os_language(void);
+int ventoy_get_file_size(const char *file);
+int ventoy_www_init(void);
+void ventoy_www_exit(void);
+int ventoy_decompress_tar(char *tarbuf, int buflen, int *tarsize);
+ventoy_file * ventoy_tar_find_file(const char *path);
+void ventoy_get_json_path(char *path, char *backup);
+int ventoy_copy_file(const char *a, const char *b);
+
+typedef int (*ventoy_http_writeback_pf)(void);
+
+int ventoy_start_writeback_thread(ventoy_http_writeback_pf callback);
+void ventoy_stop_writeback_thread(void);
+void ventoy_set_writeback_event(void);
+
+
+extern unsigned char *g_unxz_buffer;
+extern int g_unxz_len;
+void unxz_error(char *x);
+int unxz_flush(void *src, unsigned int size);
+
+#endif /* __VENTOY_UTIL_H__ */
+
--- /dev/null
+/******************************************************************************
+ * ventoy_util_linux.c ---- ventoy util
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+#include <dirent.h>
+#include <time.h>
+#include <ventoy_define.h>
+#include <ventoy_util.h>
+
+void ventoy_gen_preudo_uuid(void *uuid)
+{
+ int i;
+ int fd;
+
+ fd = open("/dev/urandom", O_RDONLY | O_BINARY);
+ if (fd < 0)
+ {
+ srand(time(NULL));
+ for (i = 0; i < 8; i++)
+ {
+ *((uint16_t *)uuid + i) = (uint16_t)(rand() & 0xFFFF);
+ }
+ }
+ else
+ {
+ read(fd, uuid, 16);
+ close(fd);
+ }
+}
+
+int ventoy_get_sys_file_line(char *buffer, int buflen, const char *fmt, ...)
+{
+ int len;
+ char c;
+ char path[256];
+ va_list arg;
+
+ va_start(arg, fmt);
+ vsnprintf(path, 256, fmt, arg);
+ va_end(arg);
+
+ if (access(path, F_OK) >= 0)
+ {
+ FILE *fp = fopen(path, "r");
+ memset(buffer, 0, buflen);
+ len = (int)fread(buffer, 1, buflen - 1, fp);
+ fclose(fp);
+
+ while (len > 0)
+ {
+ c = buffer[len - 1];
+ if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
+ {
+ buffer[len - 1] = 0;
+ len--;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return 0;
+ }
+ else
+ {
+ vdebug("%s not exist \n", path);
+ return 1;
+ }
+}
+
+int ventoy_is_disk_mounted(const char *devpath)
+{
+ int len;
+ int mount = 0;
+ char line[512];
+ FILE *fp = NULL;
+
+ fp = fopen("/proc/mounts", "r");
+ if (!fp)
+ {
+ return 0;
+ }
+
+ len = (int)strlen(devpath);
+ while (fgets(line, sizeof(line), fp))
+ {
+ if (strncmp(line, devpath, len) == 0)
+ {
+ mount = 1;
+ vdebug("%s mounted <%s>\n", devpath, line);
+ goto end;
+ }
+ }
+
+end:
+ fclose(fp);
+ return mount;
+}
+
+const char * ventoy_get_os_language(void)
+{
+ const char *env = getenv("LANG");
+
+ if (env && strncasecmp(env, "zh_CN", 5) == 0)
+ {
+ return "cn";
+ }
+ else
+ {
+ return "en";
+ }
+}
+
+int ventoy_is_file_exist(const char *fmt, ...)
+{
+ va_list ap;
+ struct stat sb;
+ char fullpath[MAX_PATH];
+
+ va_start (ap, fmt);
+ vsnprintf(fullpath, MAX_PATH, fmt, ap);
+ va_end (ap);
+
+ if (stat(fullpath, &sb))
+ {
+ return 0;
+ }
+
+ if (S_ISREG(sb.st_mode))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+int ventoy_is_directory_exist(const char *fmt, ...)
+{
+ va_list ap;
+ struct stat sb;
+ char fullpath[MAX_PATH];
+
+ va_start (ap, fmt);
+ vsnprintf(fullpath, MAX_PATH, fmt, ap);
+ va_end (ap);
+
+ if (stat(fullpath, &sb))
+ {
+ return 0;
+ }
+
+ if (S_ISDIR(sb.st_mode))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+int ventoy_get_file_size(const char *file)
+{
+ int Size = -1;
+ struct stat stStat;
+
+ if (stat(file, &stStat) >= 0)
+ {
+ Size = (int)(stStat.st_size);
+ }
+
+ return Size;
+}
+
+
+int ventoy_write_buf_to_file(const char *FileName, void *Bufer, int BufLen)
+{
+ int fd;
+ int rc;
+ ssize_t size;
+
+ fd = open(FileName, O_CREAT | O_RDWR | O_TRUNC, 0755);
+ if (fd < 0)
+ {
+ vlog("Failed to open file %s %d\n", FileName, errno);
+ return 1;
+ }
+
+ rc = fchmod(fd, 0755);
+ if (rc)
+ {
+ vlog("Failed to chmod <%s> %d\n", FileName, errno);
+ }
+
+ size = write(fd, Bufer, BufLen);
+ if ((int)size != BufLen)
+ {
+ close(fd);
+ vlog("write file %s failed %d err:%d\n", FileName, (int)size, errno);
+ return 1;
+ }
+
+ fsync(fd);
+ close(fd);
+
+ return 0;
+}
+
+int ventoy_decompress_tar(char *tarbuf, int buflen, int *tarsize)
+{
+ int rc = 1;
+ int inused = 0;
+ int BufLen = 0;
+ unsigned char *buffer = NULL;
+ char tarxz[MAX_PATH];
+
+ scnprintf(tarxz, sizeof(tarxz), "%s/tool/plugson.tar.xz", g_ventoy_dir);
+ if (ventoy_read_file_to_buf(tarxz, 0, (void **)&buffer, &BufLen))
+ {
+ vlog("Failed to read file <%s>\n", tarxz);
+ return 1;
+ }
+
+ g_unxz_buffer = (unsigned char *)tarbuf;
+ g_unxz_len = 0;
+
+ unxz(buffer, BufLen, NULL, unxz_flush, NULL, &inused, unxz_error);
+ vlog("xzlen:%u rawdata size:%d\n", BufLen, g_unxz_len);
+
+ if (inused != BufLen)
+ {
+ vlog("Failed to unxz data %d %d\n", inused, BufLen);
+ rc = 1;
+ }
+ else
+ {
+ *tarsize = g_unxz_len;
+ rc = 0;
+ }
+
+ free(buffer);
+
+ return rc;
+}
+
+static volatile int g_thread_stop = 0;
+static pthread_t g_writeback_thread;
+static pthread_mutex_t g_writeback_mutex;
+static pthread_cond_t g_writeback_cond;
+static void * ventoy_local_thread_run(void* data)
+{
+ ventoy_http_writeback_pf callback = (ventoy_http_writeback_pf)data;
+
+ while (1)
+ {
+ pthread_mutex_lock(&g_writeback_mutex);
+ pthread_cond_wait(&g_writeback_cond, &g_writeback_mutex);
+
+ if (g_thread_stop)
+ {
+ pthread_mutex_unlock(&g_writeback_mutex);
+ break;
+ }
+ else
+ {
+ callback();
+ pthread_mutex_unlock(&g_writeback_mutex);
+ }
+ }
+
+ return NULL;
+}
+
+void ventoy_set_writeback_event(void)
+{
+ pthread_cond_signal(&g_writeback_cond);
+}
+
+int ventoy_start_writeback_thread(ventoy_http_writeback_pf callback)
+{
+ g_thread_stop = 0;
+ pthread_mutex_init(&g_writeback_mutex, NULL);
+ pthread_cond_init(&g_writeback_cond, NULL);
+
+ pthread_create(&g_writeback_thread, NULL, ventoy_local_thread_run, callback);
+
+ return 0;
+}
+
+void ventoy_stop_writeback_thread(void)
+{
+ g_thread_stop = 1;
+ pthread_cond_signal(&g_writeback_cond);
+
+ pthread_join(g_writeback_thread, NULL);
+
+
+ pthread_cond_destroy(&g_writeback_cond);
+ pthread_mutex_destroy(&g_writeback_mutex);
+}
+
+
+int ventoy_copy_file(const char *a, const char *b)
+{
+ int len = 0;
+ char *buf = NULL;
+
+ if (0 == ventoy_read_file_to_buf(a, 0, (void **)&buf, &len))
+ {
+ ventoy_write_buf_to_file(b, buf, len);
+ free(buf);
+ }
+
+ return 0;
+}
+
--- /dev/null
+/******************************************************************************
+ * ventoy_util.c ---- ventoy util
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <ventoy_define.h>
+#include <ventoy_util.h>
+#include <ventoy_disk.h>
+#include "fat_filelib.h"
+
+static void TrimString(CHAR *String)
+{
+ CHAR *Pos1 = String;
+ CHAR *Pos2 = String;
+ size_t Len = strlen(String);
+
+ while (Len > 0)
+ {
+ if (String[Len - 1] != ' ' && String[Len - 1] != '\t')
+ {
+ break;
+ }
+ String[Len - 1] = 0;
+ Len--;
+ }
+
+ while (*Pos1 == ' ' || *Pos1 == '\t')
+ {
+ Pos1++;
+ }
+
+ while (*Pos1)
+ {
+ *Pos2++ = *Pos1++;
+ }
+ *Pos2++ = 0;
+
+ return;
+}
+
+void ventoy_gen_preudo_uuid(void *uuid)
+{
+ CoCreateGuid((GUID *)uuid);
+}
+
+static int IsUTF8Encode(const char *src)
+{
+ int i;
+ const UCHAR *Byte = (const UCHAR *)src;
+
+ for (i = 0; i < MAX_PATH && Byte[i]; i++)
+ {
+ if (Byte[i] > 127)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int Utf8ToUtf16(const char* src, WCHAR * dst)
+{
+ return MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, MAX_PATH * sizeof(WCHAR));
+}
+
+static int Utf16ToUtf8(const WCHAR* src, CHAR * dst)
+{
+ int size = WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, MAX_PATH, NULL, 0);
+ dst[size] = 0;
+ return size;
+}
+
+
+int ventoy_path_case(char *path, int slash)
+{
+ int i;
+ int j = 0;
+ int count = 0;
+ int isUTF8 = 0;
+ BOOL bRet;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ WCHAR Buffer[MAX_PATH + 16];
+ WCHAR FilePathW[MAX_PATH];
+ CHAR FilePathA[MAX_PATH];
+ FILE_NAME_INFO *pInfo = NULL;
+
+ if (g_sysinfo.pathcase == 0)
+ {
+ return 0;
+ }
+
+ if (path == NULL || path[0] == '/' || path[0] == '\\')
+ {
+ return 0;
+ }
+
+ isUTF8 = IsUTF8Encode(path);
+ if (isUTF8)
+ {
+ Utf8ToUtf16(path, FilePathW);
+ handle = CreateFileW(FilePathW, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+ }
+ else
+ {
+ handle = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+ }
+
+ if (handle != INVALID_HANDLE_VALUE)
+ {
+ bRet = GetFileInformationByHandleEx(handle, FileNameInfo, Buffer, sizeof(Buffer));
+ if (bRet)
+ {
+ pInfo = (FILE_NAME_INFO *)Buffer;
+
+ if (slash)
+ {
+ for (i = 0; i < (int)(pInfo->FileNameLength / sizeof(WCHAR)); i++)
+ {
+ if (pInfo->FileName[i] == L'\\')
+ {
+ pInfo->FileName[i] = L'/';
+ }
+ }
+ }
+
+ pInfo->FileName[(pInfo->FileNameLength / sizeof(WCHAR))] = 0;
+
+ memset(FilePathA, 0, sizeof(FilePathA));
+ Utf16ToUtf8(pInfo->FileName, FilePathA);
+
+ if (FilePathA[1] == ':')
+ {
+ j = 3;
+ }
+ else
+ {
+ j = 1;
+ }
+
+ for (i = 0; i < MAX_PATH && j < MAX_PATH; i++, j++)
+ {
+ if (FilePathA[j] == 0)
+ {
+ break;
+ }
+
+ if (path[i] != FilePathA[j])
+ {
+ path[i] = FilePathA[j];
+ count++;
+ }
+ }
+ }
+
+ CHECK_CLOSE_HANDLE(handle);
+ }
+
+ return count;
+}
+
+
+
+int ventoy_is_directory_exist(const char *Fmt, ...)
+{
+ va_list Arg;
+ DWORD Attr;
+ int UTF8 = 0;
+ CHAR FilePathA[MAX_PATH];
+ WCHAR FilePathW[MAX_PATH];
+
+ va_start(Arg, Fmt);
+ vsnprintf_s(FilePathA, sizeof(FilePathA), sizeof(FilePathA), Fmt, Arg);
+ va_end(Arg);
+
+ UTF8 = IsUTF8Encode(FilePathA);
+
+ if (UTF8)
+ {
+ Utf8ToUtf16(FilePathA, FilePathW);
+ Attr = GetFileAttributesW(FilePathW);
+ }
+ else
+ {
+ Attr = GetFileAttributesA(FilePathA);
+ }
+
+ if (Attr != INVALID_FILE_ATTRIBUTES && (Attr & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int ventoy_is_file_exist(const char *Fmt, ...)
+{
+ va_list Arg;
+ HANDLE hFile;
+ DWORD Attr;
+ int UTF8 = 0;
+ CHAR FilePathA[MAX_PATH];
+ WCHAR FilePathW[MAX_PATH];
+
+ va_start(Arg, Fmt);
+ vsnprintf_s(FilePathA, sizeof(FilePathA), sizeof(FilePathA), Fmt, Arg);
+ va_end(Arg);
+
+ UTF8 = IsUTF8Encode(FilePathA);
+ if (UTF8)
+ {
+ Utf8ToUtf16(FilePathA, FilePathW);
+ hFile = CreateFileW(FilePathW, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ Attr = GetFileAttributesW(FilePathW);
+ }
+ else
+ {
+ hFile = CreateFileA(FilePathA, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
+ Attr = GetFileAttributesA(FilePathA);
+ }
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ return 0;
+ }
+ CloseHandle(hFile);
+
+ if (Attr & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+const char * ventoy_get_os_language(void)
+{
+ if (GetUserDefaultUILanguage() == 0x0804)
+ {
+ return "cn";
+ }
+ else
+ {
+ return "en";
+ }
+}
+
+
+int GetPhyDriveByLogicalDrive(int DriveLetter, UINT64 *Offset)
+{
+ BOOL Ret;
+ DWORD dwSize;
+ HANDLE Handle;
+ VOLUME_DISK_EXTENTS DiskExtents;
+ CHAR PhyPath[128];
+
+ scnprintf(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", (CHAR)DriveLetter);
+
+ Handle = CreateFileA(PhyPath, 0, 0, 0, OPEN_EXISTING, 0, 0);
+ if (Handle == INVALID_HANDLE_VALUE)
+ {
+ vlog("CreateFileA %s failed %u\n", PhyPath, LASTERR);
+ return -1;
+ }
+
+ Ret = DeviceIoControl(Handle,
+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+ NULL,
+ 0,
+ &DiskExtents,
+ (DWORD)(sizeof(DiskExtents)),
+ (LPDWORD)&dwSize,
+ NULL);
+
+ if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
+ {
+ vlog("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTSfailed %u\n", LASTERR);
+ CHECK_CLOSE_HANDLE(Handle);
+ return -1;
+ }
+ CHECK_CLOSE_HANDLE(Handle);
+
+ if (Offset)
+ {
+ *Offset = (UINT64)(DiskExtents.Extents[0].StartingOffset.QuadPart);
+ }
+
+ return (int)DiskExtents.Extents[0].DiskNumber;
+}
+
+int GetPhyDriveInfo(int PhyDrive, UINT64 *Size, CHAR *Vendor, CHAR *Product)
+{
+ int ret = 1;
+ BOOL bRet;
+ DWORD dwBytes;
+ CHAR Drive[64];
+ HANDLE Handle = INVALID_HANDLE_VALUE;
+ GET_LENGTH_INFORMATION LengthInfo;
+ STORAGE_PROPERTY_QUERY Query;
+ STORAGE_DESCRIPTOR_HEADER DevDescHeader;
+ STORAGE_DEVICE_DESCRIPTOR *pDevDesc = NULL;
+
+ sprintf_s(Drive, sizeof(Drive), "\\\\.\\PhysicalDrive%d", PhyDrive);
+ Handle = CreateFileA(Drive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (Handle == INVALID_HANDLE_VALUE)
+ {
+ vlog("CreateFileA %s failed %u\n", Drive, LASTERR);
+ goto out;
+ }
+
+
+ bRet = DeviceIoControl(Handle,
+ IOCTL_DISK_GET_LENGTH_INFO, NULL,
+ 0,
+ &LengthInfo,
+ sizeof(LengthInfo),
+ &dwBytes,
+ NULL);
+ if (!bRet)
+ {
+ vlog("IOCTL_DISK_GET_LENGTH_INFO failed %u\n", LASTERR);
+ return 1;
+ }
+
+ if (Size)
+ {
+ *Size = (UINT64)LengthInfo.Length.QuadPart;
+ }
+
+ Query.PropertyId = StorageDeviceProperty;
+ Query.QueryType = PropertyStandardQuery;
+
+ bRet = DeviceIoControl(Handle,
+ IOCTL_STORAGE_QUERY_PROPERTY,
+ &Query,
+ sizeof(Query),
+ &DevDescHeader,
+ sizeof(STORAGE_DESCRIPTOR_HEADER),
+ &dwBytes,
+ NULL);
+ if (!bRet)
+ {
+ vlog("IOCTL_STORAGE_QUERY_PROPERTY failed %u\n", LASTERR);
+ goto out;
+ }
+
+ if (DevDescHeader.Size < sizeof(STORAGE_DEVICE_DESCRIPTOR))
+ {
+ vlog("DevDescHeader.size invalid %u\n", DevDescHeader.Size);
+ goto out;
+ }
+
+ pDevDesc = (STORAGE_DEVICE_DESCRIPTOR *)malloc(DevDescHeader.Size);
+ if (!pDevDesc)
+ {
+ vlog("malloc failed\n");
+ goto out;
+ }
+
+ bRet = DeviceIoControl(Handle,
+ IOCTL_STORAGE_QUERY_PROPERTY,
+ &Query,
+ sizeof(Query),
+ pDevDesc,
+ DevDescHeader.Size,
+ &dwBytes,
+ NULL);
+ if (!bRet)
+ {
+ vlog("IOCTL_STORAGE_QUERY_PROPERTY failed %u\n", LASTERR);
+ goto out;
+ }
+
+ if (pDevDesc->VendorIdOffset && Vendor)
+ {
+ strcpy_s(Vendor, 128, (char *)pDevDesc + pDevDesc->VendorIdOffset);
+ TrimString(Vendor);
+ }
+
+ if (pDevDesc->ProductIdOffset && Product)
+ {
+ strcpy_s(Product, 128, (char *)pDevDesc + pDevDesc->ProductIdOffset);
+ TrimString(Product);
+ }
+
+ ret = 0;
+
+out:
+ CHECK_FREE(pDevDesc);
+ CHECK_CLOSE_HANDLE(Handle);
+ return ret;
+}
+
+
+int ventoy_get_file_size(const char *file)
+{
+ int Size = -1;
+ HANDLE hFile;
+
+ hFile = CreateFileA(file, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ Size = (int)GetFileSize(hFile, NULL);
+ CHECK_CLOSE_HANDLE(hFile);
+ }
+
+ return Size;
+}
+
+
+static HANDLE g_FatPhyDrive;
+static UINT64 g_Part2StartSec;
+
+const CHAR* ParseVentoyVersionFromString(CHAR *Buf)
+{
+ CHAR *Pos = NULL;
+ CHAR *End = NULL;
+ static CHAR LocalVersion[64] = { 0 };
+
+ Pos = strstr(Buf, "VENTOY_VERSION=");
+ if (Pos)
+ {
+ Pos += strlen("VENTOY_VERSION=");
+ if (*Pos == '"')
+ {
+ Pos++;
+ }
+
+ End = Pos;
+ while (*End != 0 && *End != '"' && *End != '\r' && *End != '\n')
+ {
+ End++;
+ }
+
+ *End = 0;
+
+ sprintf_s(LocalVersion, sizeof(LocalVersion), "%s", Pos);
+ return LocalVersion;
+ }
+
+ return "";
+}
+static int GetVentoyVersionFromFatFile(CHAR *VerBuf, size_t BufLen)
+{
+ int rc = 1;
+ int size = 0;
+ char *buf = NULL;
+ void *flfile = NULL;
+
+ flfile = fl_fopen("/grub/grub.cfg", "rb");
+ if (flfile)
+ {
+ fl_fseek(flfile, 0, SEEK_END);
+ size = (int)fl_ftell(flfile);
+
+ fl_fseek(flfile, 0, SEEK_SET);
+
+ buf = (char *)malloc(size + 1);
+ if (buf)
+ {
+ fl_fread(buf, 1, size, flfile);
+ buf[size] = 0;
+
+ rc = 0;
+ sprintf_s(VerBuf, BufLen, "%s", ParseVentoyVersionFromString(buf));
+ free(buf);
+ }
+
+ fl_fclose(flfile);
+ }
+
+ return rc;
+}
+
+static int VentoyFatDiskRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
+{
+ DWORD dwSize;
+ BOOL bRet;
+ DWORD ReadSize;
+ LARGE_INTEGER liCurrentPosition;
+
+ liCurrentPosition.QuadPart = Sector + g_Part2StartSec;
+ liCurrentPosition.QuadPart *= 512;
+ SetFilePointerEx(g_FatPhyDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);
+
+ ReadSize = (DWORD)(SectorCount * 512);
+
+ bRet = ReadFile(g_FatPhyDrive, Buffer, ReadSize, &dwSize, NULL);
+ if (bRet == FALSE || dwSize != ReadSize)
+ {
+
+ }
+
+ return 1;
+}
+
+static int GetVentoyVersion(int PhyDrive, ventoy_disk *disk)
+{
+ int ret = 1;
+ BOOL bRet;
+ DWORD dwBytes;
+ UINT64 Part2Offset;
+ HANDLE Handle = INVALID_HANDLE_VALUE;
+ VTOY_GPT_INFO *pGPT = NULL;
+ CHAR Drive[64];
+ void *flfile = NULL;
+ UCHAR MbrData[] =
+ {
+ 0xEB, 0x63, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x56, 0x54, 0x00, 0x47, 0x65, 0x00, 0x48, 0x44, 0x00, 0x52, 0x64, 0x00, 0x20, 0x45, 0x72, 0x0D,
+ };
+
+ sprintf_s(Drive, sizeof(Drive), "\\\\.\\PhysicalDrive%d", PhyDrive);
+ Handle = CreateFileA(Drive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if (Handle == INVALID_HANDLE_VALUE)
+ {
+ vlog("CreateFileA %s failed %u\n", Drive, LASTERR);
+ goto out;
+ }
+
+ pGPT = zalloc(sizeof(VTOY_GPT_INFO));
+ if (!pGPT)
+ {
+ goto out;
+ }
+
+ bRet = ReadFile(Handle, pGPT, sizeof(VTOY_GPT_INFO), &dwBytes, NULL);
+ if (!bRet || dwBytes != sizeof(VTOY_GPT_INFO))
+ {
+ vlog("ReadFile failed %u\n", LASTERR);
+ goto out;
+ }
+
+ if (memcmp(pGPT->MBR.BootCode, MbrData, 0x30) || memcmp(pGPT->MBR.BootCode + 0x190, MbrData + 0x30, 0x10))
+ {
+ vlog("Invalid MBR Code %u\n", LASTERR);
+ goto out;
+ }
+
+ if (pGPT->MBR.PartTbl[0].FsFlag == 0xEE)
+ {
+ if (memcmp(pGPT->Head.Signature, "EFI PART", 8))
+ {
+ vlog("Invalid GPT Signature\n");
+ goto out;
+ }
+
+ Part2Offset = pGPT->PartTbl[1].StartLBA;
+ disk->cur_part_style = 1;
+ }
+ else
+ {
+ Part2Offset = pGPT->MBR.PartTbl[1].StartSectorId;
+ disk->cur_part_style = 0;
+ }
+
+
+ g_FatPhyDrive = Handle;
+ g_Part2StartSec = Part2Offset;
+
+ fl_init();
+
+ if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
+ {
+ ret = GetVentoyVersionFromFatFile(disk->cur_ventoy_ver, sizeof(disk->cur_ventoy_ver));
+ if (ret == 0)
+ {
+ flfile = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
+ if (flfile)
+ {
+ disk->cur_secureboot = 1;
+ fl_fclose(flfile);
+ }
+ }
+ }
+
+ fl_shutdown();
+
+out:
+ CHECK_FREE(pGPT);
+ CHECK_CLOSE_HANDLE(Handle);
+ return ret;
+}
+
+int CheckRuntimeEnvironment(char Letter, ventoy_disk *disk)
+{
+ int PhyDrive;
+ UINT64 Offset = 0;
+ char Drive[32];
+ DWORD FsFlag;
+ CHAR Vendor[128] = { 0 };
+ CHAR Product[128] = { 0 };
+ CHAR FsName[MAX_PATH];
+
+ PhyDrive = GetPhyDriveByLogicalDrive(Letter, &Offset);
+ if (PhyDrive < 0)
+ {
+ vlog("GetPhyDriveByLogicalDrive failed %d %llu\n", PhyDrive, (ULONGLONG)Offset);
+ return 1;
+ }
+ if (Offset != 1048576)
+ {
+ vlog("Partition offset is NOT 1MB. This is NOT ventoy image partition (%llu)\n", (ULONGLONG)Offset);
+ return 1;
+ }
+
+ if (GetPhyDriveInfo(PhyDrive, &Offset, Vendor, Product) != 0)
+ {
+ vlog("GetPhyDriveInfo failed\n");
+ return 1;
+ }
+
+ sprintf_s(disk->cur_capacity, sizeof(disk->cur_capacity), "%dGB", (int)ventoy_get_human_readable_gb(Offset));
+ sprintf_s(disk->cur_model, sizeof(disk->cur_model), "%s %s", Vendor, Product);
+
+ scnprintf(Drive, sizeof(Drive), "%C:\\", Letter);
+ if (0 == GetVolumeInformationA(Drive, NULL, 0, NULL, NULL, &FsFlag, FsName, MAX_PATH))
+ {
+ vlog("GetVolumeInformationA failed %u\n", LASTERR);
+ return 1;
+ }
+
+ if (_stricmp(FsName, "NTFS") == 0)
+ {
+ disk->pathcase = 1;
+ }
+
+ strlcpy(disk->cur_fsname, FsName);
+
+ if (GetVentoyVersion(PhyDrive, disk) != 0)
+ {
+ vlog("GetVentoyVersion failed %u\n", LASTERR);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_write_buf_to_file(const char *FileName, void *Bufer, int BufLen)
+{
+ BOOL bRet;
+ DWORD dwBytes;
+ HANDLE hFile;
+
+ hFile = CreateFileA(FileName, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ vlog("CreateFile %s failed %u\n", FileName, LASTERR);
+ return 1;
+ }
+
+ bRet = WriteFile(hFile, Bufer, (DWORD)BufLen, &dwBytes, NULL);
+
+ if ((!bRet) || ((DWORD)BufLen != dwBytes))
+ {
+ vlog("Failed to write file <%s> %u err:%u", FileName, dwBytes, LASTERR);
+ CloseHandle(hFile);
+ return 1;
+ }
+
+ FlushFileBuffers(hFile);
+ CloseHandle(hFile);
+
+ return 0;
+}
+
+int ventoy_decompress_tar(char *tarbuf, int buflen, int *tarsize)
+{
+ int rc = 1;
+ int inused;
+ HANDLE hFile;
+ DWORD dwSize;
+ DWORD dwRead;
+ WCHAR FullPath[MAX_PATH];
+ BYTE *buffer;
+ VENTOY_MAGIC Magic;
+
+ GetModuleFileNameW(NULL, FullPath, MAX_PATH);
+ hFile = CreateFileW(FullPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ vlog("Failed to open self %u\n", LASTERR);
+ return 1;
+ }
+
+ dwSize = GetFileSize(hFile, NULL);
+ if (dwSize == INVALID_FILE_SIZE)
+ {
+ vlog("Invalid self exe size %u\n", LASTERR);
+ CHECK_CLOSE_HANDLE(hFile);
+ return 1;
+ }
+
+ buffer = malloc(dwSize);
+ if (!buffer)
+ {
+ vlog("Failed to malloc %u\n", dwSize);
+ CHECK_CLOSE_HANDLE(hFile);
+ return 1;
+ }
+ ReadFile(hFile, buffer, dwSize, &dwRead, NULL);
+
+ memcpy(&Magic, buffer + dwSize - sizeof(Magic), sizeof(Magic));
+ if (Magic.magic1 == 0x54535251 && Magic.magic2 == 0xa4a3a2a1)
+ {
+ g_unxz_buffer = (UCHAR *)tarbuf;
+ g_unxz_len = 0;
+
+ unxz(buffer + dwSize - Magic.xzlen - sizeof(Magic), Magic.xzlen, NULL, unxz_flush, NULL, &inused, unxz_error);
+ vlog("bigexe:%u xzlen:%u rawdata size:%d\n", dwSize, Magic.xzlen, g_unxz_len);
+
+ if (inused != Magic.xzlen)
+ {
+ vlog("Failed to unxz www %d\n", inused);
+ rc = 1;
+ }
+ else
+ {
+ *tarsize = g_unxz_len;
+ rc = 0;
+ }
+ }
+ else
+ {
+ vlog("Invalid magic 0x%x 0x%x\n", Magic.magic1, Magic.magic2);
+ rc = 1;
+ }
+
+ free(buffer);
+ CHECK_CLOSE_HANDLE(hFile);
+
+ return rc;
+}
+
+
+static volatile int g_thread_stop = 0;
+static HANDLE g_writeback_thread;
+static HANDLE g_writeback_event;
+
+DWORD WINAPI ventoy_local_thread_run(LPVOID lpParameter)
+{
+ ventoy_http_writeback_pf callback = (ventoy_http_writeback_pf)lpParameter;
+
+ while (1)
+ {
+ WaitForSingleObject(g_writeback_event, INFINITE);
+ if (g_thread_stop)
+ {
+ break;
+ }
+ else
+ {
+ callback();
+ }
+ }
+
+ return 0;
+}
+
+
+void ventoy_set_writeback_event(void)
+{
+ SetEvent(g_writeback_event);
+}
+
+
+int ventoy_start_writeback_thread(ventoy_http_writeback_pf callback)
+{
+ g_thread_stop = 0;
+ g_writeback_event = CreateEventA(NULL, FALSE, FALSE, "VTOYWRBK");
+ g_writeback_thread = CreateThread(NULL, 0, ventoy_local_thread_run, callback, 0, NULL);
+
+ return 0;
+}
+
+
+void ventoy_stop_writeback_thread(void)
+{
+ g_thread_stop = 1;
+ ventoy_set_writeback_event();
+
+ WaitForSingleObject(g_writeback_thread, INFINITE);
+
+ CHECK_CLOSE_HANDLE(g_writeback_thread);
+ CHECK_CLOSE_HANDLE(g_writeback_event);
+}
+
+
+int ventoy_copy_file(const char *a, const char *b)
+{
+ CopyFileA(a, b, FALSE);
+ return 0;
+}
+
--- /dev/null
+File IO Lib API\r
+-=-=-=-=-=-=-=-=-\r
+\r
+void fl_init(void)\r
+\r
+ Called to initialize FAT IO library.\r
+ This should be called prior to any other functions.\r
+\r
+void fl_attach_locks(void (*lock)(void), void (*unlock)(void))\r
+\r
+ [Optional] File system thread safety locking functions.\r
+ For thread safe operation, you should provide lock() and unlock() functions.\r
+ Note that locking primitive used must support recursive locking, i.e lock() called within an already \91locked\92 region.\r
+\r
+int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr)\r
+\r
+ This function is used to attach system specific disk/media access functions. \r
+ This should be done subsequent to calling fl_init() and fl_attach_locks() (if locking required).\r
+\r
+void fl_shutdown(void)\r
+\r
+ Shutdown the FAT IO library. This purges any un-saved data back to disk.\r
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE\r
+ Version 2, June 1991\r
+\r
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.\r
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+ Preamble\r
+\r
+ The licenses for most software are designed to take away your\r
+freedom to share and change it. By contrast, the GNU General Public\r
+License is intended to guarantee your freedom to share and change free\r
+software--to make sure the software is free for all its users. This\r
+General Public License applies to most of the Free Software\r
+Foundation's software and to any other program whose authors commit to\r
+using it. (Some other Free Software Foundation software is covered by\r
+the GNU Library General Public License instead.) You can apply it to\r
+your programs, too.\r
+\r
+ When we speak of free software, we are referring to freedom, not\r
+price. Our General Public Licenses are designed to make sure that you\r
+have the freedom to distribute copies of free software (and charge for\r
+this service if you wish), that you receive source code or can get it\r
+if you want it, that you can change the software or use pieces of it\r
+in new free programs; and that you know you can do these things.\r
+\r
+ To protect your rights, we need to make restrictions that forbid\r
+anyone to deny you these rights or to ask you to surrender the rights.\r
+These restrictions translate to certain responsibilities for you if you\r
+distribute copies of the software, or if you modify it.\r
+\r
+ For example, if you distribute copies of such a program, whether\r
+gratis or for a fee, you must give the recipients all the rights that\r
+you have. You must make sure that they, too, receive or can get the\r
+source code. And you must show them these terms so they know their\r
+rights.\r
+\r
+ We protect your rights with two steps: (1) copyright the software, and\r
+(2) offer you this license which gives you legal permission to copy,\r
+distribute and/or modify the software.\r
+\r
+ Also, for each author's protection and ours, we want to make certain\r
+that everyone understands that there is no warranty for this free\r
+software. If the software is modified by someone else and passed on, we\r
+want its recipients to know that what they have is not the original, so\r
+that any problems introduced by others will not reflect on the original\r
+authors' reputations.\r
+\r
+ Finally, any free program is threatened constantly by software\r
+patents. We wish to avoid the danger that redistributors of a free\r
+program will individually obtain patent licenses, in effect making the\r
+program proprietary. To prevent this, we have made it clear that any\r
+patent must be licensed for everyone's free use or not licensed at all.\r
+\r
+ The precise terms and conditions for copying, distribution and\r
+modification follow.\r
+\r
+\r
+ GNU GENERAL PUBLIC LICENSE\r
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r
+\r
+ 0. This License applies to any program or other work which contains\r
+a notice placed by the copyright holder saying it may be distributed\r
+under the terms of this General Public License. The "Program", below,\r
+refers to any such program or work, and a "work based on the Program"\r
+means either the Program or any derivative work under copyright law:\r
+that is to say, a work containing the Program or a portion of it,\r
+either verbatim or with modifications and/or translated into another\r
+language. (Hereinafter, translation is included without limitation in\r
+the term "modification".) Each licensee is addressed as "you".\r
+\r
+Activities other than copying, distribution and modification are not\r
+covered by this License; they are outside its scope. The act of\r
+running the Program is not restricted, and the output from the Program\r
+is covered only if its contents constitute a work based on the\r
+Program (independent of having been made by running the Program).\r
+Whether that is true depends on what the Program does.\r
+\r
+ 1. You may copy and distribute verbatim copies of the Program's\r
+source code as you receive it, in any medium, provided that you\r
+conspicuously and appropriately publish on each copy an appropriate\r
+copyright notice and disclaimer of warranty; keep intact all the\r
+notices that refer to this License and to the absence of any warranty;\r
+and give any other recipients of the Program a copy of this License\r
+along with the Program.\r
+\r
+You may charge a fee for the physical act of transferring a copy, and\r
+you may at your option offer warranty protection in exchange for a fee.\r
+\r
+ 2. You may modify your copy or copies of the Program or any portion\r
+of it, thus forming a work based on the Program, and copy and\r
+distribute such modifications or work under the terms of Section 1\r
+above, provided that you also meet all of these conditions:\r
+\r
+ a) You must cause the modified files to carry prominent notices\r
+ stating that you changed the files and the date of any change.\r
+\r
+ b) You must cause any work that you distribute or publish, that in\r
+ whole or in part contains or is derived from the Program or any\r
+ part thereof, to be licensed as a whole at no charge to all third\r
+ parties under the terms of this License.\r
+\r
+ c) If the modified program normally reads commands interactively\r
+ when run, you must cause it, when started running for such\r
+ interactive use in the most ordinary way, to print or display an\r
+ announcement including an appropriate copyright notice and a\r
+ notice that there is no warranty (or else, saying that you provide\r
+ a warranty) and that users may redistribute the program under\r
+ these conditions, and telling the user how to view a copy of this\r
+ License. (Exception: if the Program itself is interactive but\r
+ does not normally print such an announcement, your work based on\r
+ the Program is not required to print an announcement.)\r
+\r
+\r
+These requirements apply to the modified work as a whole. If\r
+identifiable sections of that work are not derived from the Program,\r
+and can be reasonably considered independent and separate works in\r
+themselves, then this License, and its terms, do not apply to those\r
+sections when you distribute them as separate works. But when you\r
+distribute the same sections as part of a whole which is a work based\r
+on the Program, the distribution of the whole must be on the terms of\r
+this License, whose permissions for other licensees extend to the\r
+entire whole, and thus to each and every part regardless of who wrote it.\r
+\r
+Thus, it is not the intent of this section to claim rights or contest\r
+your rights to work written entirely by you; rather, the intent is to\r
+exercise the right to control the distribution of derivative or\r
+collective works based on the Program.\r
+\r
+In addition, mere aggregation of another work not based on the Program\r
+with the Program (or with a work based on the Program) on a volume of\r
+a storage or distribution medium does not bring the other work under\r
+the scope of this License.\r
+\r
+ 3. You may copy and distribute the Program (or a work based on it,\r
+under Section 2) in object code or executable form under the terms of\r
+Sections 1 and 2 above provided that you also do one of the following:\r
+\r
+ a) Accompany it with the complete corresponding machine-readable\r
+ source code, which must be distributed under the terms of Sections\r
+ 1 and 2 above on a medium customarily used for software interchange; or,\r
+\r
+ b) Accompany it with a written offer, valid for at least three\r
+ years, to give any third party, for a charge no more than your\r
+ cost of physically performing source distribution, a complete\r
+ machine-readable copy of the corresponding source code, to be\r
+ distributed under the terms of Sections 1 and 2 above on a medium\r
+ customarily used for software interchange; or,\r
+\r
+ c) Accompany it with the information you received as to the offer\r
+ to distribute corresponding source code. (This alternative is\r
+ allowed only for noncommercial distribution and only if you\r
+ received the program in object code or executable form with such\r
+ an offer, in accord with Subsection b above.)\r
+\r
+The source code for a work means the preferred form of the work for\r
+making modifications to it. For an executable work, complete source\r
+code means all the source code for all modules it contains, plus any\r
+associated interface definition files, plus the scripts used to\r
+control compilation and installation of the executable. However, as a\r
+special exception, the source code distributed need not include\r
+anything that is normally distributed (in either source or binary\r
+form) with the major components (compiler, kernel, and so on) of the\r
+operating system on which the executable runs, unless that component\r
+itself accompanies the executable.\r
+\r
+If distribution of executable or object code is made by offering\r
+access to copy from a designated place, then offering equivalent\r
+access to copy the source code from the same place counts as\r
+distribution of the source code, even though third parties are not\r
+compelled to copy the source along with the object code.\r
+\r
+\r
+ 4. You may not copy, modify, sublicense, or distribute the Program\r
+except as expressly provided under this License. Any attempt\r
+otherwise to copy, modify, sublicense or distribute the Program is\r
+void, and will automatically terminate your rights under this License.\r
+However, parties who have received copies, or rights, from you under\r
+this License will not have their licenses terminated so long as such\r
+parties remain in full compliance.\r
+\r
+ 5. You are not required to accept this License, since you have not\r
+signed it. However, nothing else grants you permission to modify or\r
+distribute the Program or its derivative works. These actions are\r
+prohibited by law if you do not accept this License. Therefore, by\r
+modifying or distributing the Program (or any work based on the\r
+Program), you indicate your acceptance of this License to do so, and\r
+all its terms and conditions for copying, distributing or modifying\r
+the Program or works based on it.\r
+\r
+ 6. Each time you redistribute the Program (or any work based on the\r
+Program), the recipient automatically receives a license from the\r
+original licensor to copy, distribute or modify the Program subject to\r
+these terms and conditions. You may not impose any further\r
+restrictions on the recipients' exercise of the rights granted herein.\r
+You are not responsible for enforcing compliance by third parties to\r
+this License.\r
+\r
+ 7. If, as a consequence of a court judgment or allegation of patent\r
+infringement or for any other reason (not limited to patent issues),\r
+conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License. If you cannot\r
+distribute so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you\r
+may not distribute the Program at all. For example, if a patent\r
+license would not permit royalty-free redistribution of the Program by\r
+all those who receive copies directly or indirectly through you, then\r
+the only way you could satisfy both it and this License would be to\r
+refrain entirely from distribution of the Program.\r
+\r
+If any portion of this section is held invalid or unenforceable under\r
+any particular circumstance, the balance of the section is intended to\r
+apply and the section as a whole is intended to apply in other\r
+circumstances.\r
+\r
+It is not the purpose of this section to induce you to infringe any\r
+patents or other property right claims or to contest validity of any\r
+such claims; this section has the sole purpose of protecting the\r
+integrity of the free software distribution system, which is\r
+implemented by public license practices. Many people have made\r
+generous contributions to the wide range of software distributed\r
+through that system in reliance on consistent application of that\r
+system; it is up to the author/donor to decide if he or she is willing\r
+to distribute software through any other system and a licensee cannot\r
+impose that choice.\r
+\r
+This section is intended to make thoroughly clear what is believed to\r
+be a consequence of the rest of this License.\r
+\r
+\r
+ 8. If the distribution and/or use of the Program is restricted in\r
+certain countries either by patents or by copyrighted interfaces, the\r
+original copyright holder who places the Program under this License\r
+may add an explicit geographical distribution limitation excluding\r
+those countries, so that distribution is permitted only in or among\r
+countries not thus excluded. In such case, this License incorporates\r
+the limitation as if written in the body of this License.\r
+\r
+ 9. The Free Software Foundation may publish revised and/or new versions\r
+of the General Public License from time to time. Such new versions will\r
+be similar in spirit to the present version, but may differ in detail to\r
+address new problems or concerns.\r
+\r
+Each version is given a distinguishing version number. If the Program\r
+specifies a version number of this License which applies to it and "any\r
+later version", you have the option of following the terms and conditions\r
+either of that version or of any later version published by the Free\r
+Software Foundation. If the Program does not specify a version number of\r
+this License, you may choose any version ever published by the Free Software\r
+Foundation.\r
+\r
+ 10. If you wish to incorporate parts of the Program into other free\r
+programs whose distribution conditions are different, write to the author\r
+to ask for permission. For software which is copyrighted by the Free\r
+Software Foundation, write to the Free Software Foundation; we sometimes\r
+make exceptions for this. Our decision will be guided by the two goals\r
+of preserving the free status of all derivatives of our free software and\r
+of promoting the sharing and reuse of software generally.\r
+\r
+ NO WARRANTY\r
+\r
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\r
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\r
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\r
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\r
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\r
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\r
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\r
+REPAIR OR CORRECTION.\r
+\r
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\r
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\r
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\r
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\r
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\r
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\r
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\r
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\r
+POSSIBILITY OF SUCH DAMAGES.\r
+\r
+ END OF TERMS AND CONDITIONS\r
+\r
+\r
+ How to Apply These Terms to Your New Programs\r
+\r
+ If you develop a new program, and you want it to be of the greatest\r
+possible use to the public, the best way to achieve this is to make it\r
+free software which everyone can redistribute and change under these terms.\r
+\r
+ To do so, attach the following notices to the program. It is safest\r
+to attach them to the start of each source file to most effectively\r
+convey the exclusion of warranty; and each file should have at least\r
+the "copyright" line and a pointer to where the full notice is found.\r
+\r
+ <one line to give the program's name and a brief idea of what it does.>\r
+ Copyright (C) <year> <name of author>\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+If the program is interactive, make it output a short notice like this\r
+when it starts in an interactive mode:\r
+\r
+ Gnomovision version 69, Copyright (C) year name of author\r
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\r
+ This is free software, and you are welcome to redistribute it\r
+ under certain conditions; type `show c' for details.\r
+\r
+The hypothetical commands `show w' and `show c' should show the appropriate\r
+parts of the General Public License. Of course, the commands you use may\r
+be called something other than `show w' and `show c'; they could even be\r
+mouse-clicks or menu items--whatever suits your program.\r
+\r
+You should also get your employer (if you work as a programmer) or your\r
+school, if any, to sign a "copyright disclaimer" for the program, if\r
+necessary. Here is a sample; alter the names:\r
+\r
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program\r
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.\r
+\r
+ <signature of Ty Coon>, 1 April 1989\r
+ Ty Coon, President of Vice\r
+\r
+This General Public License does not permit incorporating your program into\r
+proprietary programs. If your program is a subroutine library, you may\r
+consider it more useful to permit linking proprietary applications with the\r
+library. If this is what you want to do, use the GNU Library General\r
+Public License instead of this License.\r
--- /dev/null
+File IO Lib Options\r
+-=-=-=-=-=-=-=-=-=-\r
+\r
+See defines in fat_opts.h:\r
+\r
+FATFS_IS_LITTLE_ENDIAN [1/0]\r
+ Which endian is your system? Set to 1 for little endian, 0 for big endian.\r
+\r
+FATFS_MAX_LONG_FILENAME [260]\r
+ By default, 260 characters (max LFN length). Increase this to support greater path depths.\r
+\r
+FATFS_MAX_OPEN_FILES \r
+ The more files you wish to have concurrently open, the greater this number should be.\r
+ This increases the number of FL_FILE file structures in the library, each of these is around 1K in size (assuming 512 byte sectors).\r
+\r
+FAT_BUFFER_SECTORS\r
+ Minimum is 1, more increases performance.\r
+ This defines how many FAT sectors can be buffered per FAT_BUFFER entry.\r
+\r
+FAT_BUFFERS\r
+ Minimum is 1, more increases performance.\r
+ This defines how many FAT buffer entries are available.\r
+ Memory usage is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE\r
+\r
+FATFS_INC_WRITE_SUPPORT\r
+ Support file write functionality.\r
+\r
+FAT_SECTOR_SIZE\r
+ Sector size used by buffers. Most likely to be 512 bytes (standard for ATA/IDE).\r
+\r
+FAT_PRINTF\r
+ A define that allows the File IO library to print to console/stdout. \r
+ Provide your own printf function if printf not available.\r
+\r
+FAT_CLUSTER_CACHE_ENTRIES\r
+ Size of cluster chain cache (can be undefined if not required).\r
+ Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2\r
+ Improves access speed considerably.\r
+\r
+FATFS_INC_LFN_SUPPORT [1/0]\r
+ Enable/Disable support for long filenames.\r
+\r
+FATFS_DIR_LIST_SUPPORT [1/0]\r
+ Include support for directory listing.\r
+\r
+FATFS_INC_TIME_DATE_SUPPORT [1/0]\r
+ Use time/date functions provided by time.h to update creation & modification timestamps.\r
+\r
+FATFS_INC_FORMAT_SUPPORT\r
+ Include support for formatting disks (FAT16 only).\r
+\r
+FAT_PRINTF_NOINC_STDIO\r
+ Disable use of printf & inclusion of stdio.h\r
--- /dev/null
+Revision History\r
+-=-=-=-=-=-=-=-=-\r
+v2.6.11 - Fix compilation with GCC on 64-bit machines\r
+v2.6.10 - Added support for FAT32 format.\r
+V2.6.9 - Added support for time & date handling.\r
+V2.6.8 - Fixed error with FSINFO sector write.\r
+V2.6.7 - Added fgets().\r
+ Fixed C warnings, removed dependancy on some string.h functions.\r
+V2.6.6 \96 Massive read + write performance improvements.\r
+V2.6.5 \96 Bug fixes for big endian systems.\r
+V2.6.4 \96 Further bug fixes and performance improvements for write operations.\r
+V2.6.3 \96 Peformance improvements, FAT16 formatting support. Various bug fixes.\r
+V2.6 - Basic support for FAT16 added (18-04-10).\r
+V2.5 - Code cleaned up. Many bugs fixed. Thread safety functions added.\r
+V2.x - Write support added as well as better stdio like API.\r
+V1.0 - Rewrite of all code to enable multiple files to be opened and provides a \r
+ better file API.\r
+ Also better string matching, and generally better C code than origonal \r
+ version.\r
+V0.1c - Fetch_ID_Max_LBA() function added to retrieve Drive infomation and stoping \r
+ the drive reads from addressing a sector that is out of range.\r
+V0.1b - fopen(), fgetc(), fopenDIR() using new software stack for IDE and FAT32 \r
+ access.\r
+V0.1a - First release (27/12/03); fopen(), fgetc() unbuffered reads.\r
--- /dev/null
+FAT File IO Library License\r
+-=-=-=-=-=-=-=-=-=-=-=-=-=-\r
+\r
+This versions license: GPL\r
+\r
+If you include GPL software in your project, you must release the source code of that project too.\r
+\r
+If you would like a version with a more permissive license for use in closed source commercial applications please contact me for details.\r
+\r
+Email: admin@ultra-embedded.com\r
--- /dev/null
+Media Access API\r
+-=-=-=-=-=-=-=-=-\r
+\r
+int media_read(uint32 sector, uint8 *buffer, uint32 sector_count)\r
+\r
+Params:\r
+ Sector: 32-bit sector number\r
+ Buffer: Target buffer to read n sectors of data into.\r
+ Sector_count: Number of sectors to read.\r
+\r
+Return: \r
+ int, 1 = success, 0 = failure.\r
+\r
+Description:\r
+ Application/target specific disk/media read function.\r
+ Sector number (sectors are usually 512 byte pages) to read.\r
+\r
+Media Write API\r
+\r
+int media_write(uint32 sector, uint8 *buffer, uint32 sector_count)\r
+\r
+Params:\r
+ Sector: 32-bit sector number\r
+ Buffer: Target buffer to write n sectors of data from.\r
+ Sector_count: Number of sectors to write.\r
+\r
+Return: \r
+ int, 1 = success, 0 = failure.\r
+\r
+Description:\r
+ Application/target specific disk/media write function.\r
+ Sector number (sectors are usually 512 byte pages) to write to.\r
+\r
+File IO Library Linkage\r
+ Use the following API to attach the media IO functions to the File IO library.\r
+\r
+ int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr)\r
+\r
+\r
+\r
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+// FAT16/32 File IO Library\r
+// V2.6\r
+// Ultra-Embedded.com\r
+// Copyright 2003 - 2012\r
+//\r
+// Email: admin@ultra-embedded.com\r
+//\r
+// License: GPL\r
+// If you would like a version with a more permissive license for use in\r
+// closed source commercial applications please contact me for details.\r
+//-----------------------------------------------------------------------------\r
+//\r
+// This file is part of FAT File IO Library.\r
+//\r
+// FAT File IO Library is free software; you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation; either version 2 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// FAT File IO Library is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with FAT File IO Library; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+#include <string.h>\r
+#include "fat_defs.h"\r
+#include "fat_access.h"\r
+#include "fat_table.h"\r
+#include "fat_write.h"\r
+#include "fat_string.h"\r
+#include "fat_misc.h"\r
+\r
+//-----------------------------------------------------------------------------\r
+// fatfs_init: Load FAT Parameters\r
+//-----------------------------------------------------------------------------\r
+int fatfs_init(struct fatfs *fs)\r
+{\r
+ uint8 num_of_fats;\r
+ uint16 reserved_sectors;\r
+ uint32 FATSz;\r
+ uint32 root_dir_sectors;\r
+ uint32 total_sectors;\r
+ uint32 data_sectors;\r
+ uint32 count_of_clusters;\r
+ uint8 valid_partition = 0;\r
+\r
+ fs->currentsector.address = FAT32_INVALID_CLUSTER;\r
+ fs->currentsector.dirty = 0;\r
+\r
+ fs->next_free_cluster = 0; // Invalid\r
+\r
+ fatfs_fat_init(fs);\r
+\r
+ // Make sure we have a read function (write function is optional)\r
+ if (!fs->disk_io.read_media)\r
+ return FAT_INIT_MEDIA_ACCESS_ERROR;\r
+\r
+ // MBR: Sector 0 on the disk\r
+ // NOTE: Some removeable media does not have this.\r
+\r
+ // Load MBR (LBA 0) into the 512 byte buffer\r
+ if (!fs->disk_io.read_media(0, fs->currentsector.sector, 1))\r
+ return FAT_INIT_MEDIA_ACCESS_ERROR;\r
+\r
+ // Make Sure 0x55 and 0xAA are at end of sector\r
+ // (this should be the case regardless of the MBR or boot sector)\r
+ if (fs->currentsector.sector[SIGNATURE_POSITION] != 0x55 || fs->currentsector.sector[SIGNATURE_POSITION+1] != 0xAA)\r
+ return FAT_INIT_INVALID_SIGNATURE;\r
+\r
+ // Now check again using the access function to prove endian conversion function\r
+ if (GET_16BIT_WORD(fs->currentsector.sector, SIGNATURE_POSITION) != SIGNATURE_VALUE)\r
+ return FAT_INIT_ENDIAN_ERROR;\r
+\r
+ // Verify packed structures\r
+ if (sizeof(struct fat_dir_entry) != FAT_DIR_ENTRY_SIZE)\r
+ return FAT_INIT_STRUCT_PACKING;\r
+\r
+ // Check the partition type code\r
+ switch(fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION])\r
+ {\r
+ case 0x0B:\r
+ case 0x06:\r
+ case 0x0C:\r
+ case 0x0E:\r
+ case 0x0F:\r
+ case 0x05:\r
+ valid_partition = 1;\r
+ break;\r
+ case 0x00:\r
+ valid_partition = 0;\r
+ break;\r
+ default:\r
+ if (fs->currentsector.sector[PARTITION1_TYPECODE_LOCATION] <= 0x06)\r
+ valid_partition = 1;\r
+ break;\r
+ }\r
+\r
+ // Read LBA Begin for the file system\r
+ if (valid_partition)\r
+ fs->lba_begin = GET_32BIT_WORD(fs->currentsector.sector, PARTITION1_LBA_BEGIN_LOCATION);\r
+ // Else possibly MBR less disk\r
+ else\r
+ fs->lba_begin = 0;\r
+\r
+ // Load Volume 1 table into sector buffer\r
+ // (We may already have this in the buffer if MBR less drive!)\r
+ if (!fs->disk_io.read_media(fs->lba_begin, fs->currentsector.sector, 1))\r
+ return FAT_INIT_MEDIA_ACCESS_ERROR;\r
+\r
+ // Make sure there are 512 bytes per cluster\r
+ if (GET_16BIT_WORD(fs->currentsector.sector, 0x0B) != FAT_SECTOR_SIZE)\r
+ return FAT_INIT_INVALID_SECTOR_SIZE;\r
+\r
+ // Load Parameters of FAT partition\r
+ fs->sectors_per_cluster = fs->currentsector.sector[BPB_SECPERCLUS];\r
+ reserved_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_RSVDSECCNT);\r
+ num_of_fats = fs->currentsector.sector[BPB_NUMFATS];\r
+ fs->root_entry_count = GET_16BIT_WORD(fs->currentsector.sector, BPB_ROOTENTCNT);\r
+\r
+ if(GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16) != 0)\r
+ fs->fat_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16);\r
+ else\r
+ fs->fat_sectors = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_FATSZ32);\r
+\r
+ // For FAT32 (which this may be)\r
+ fs->rootdir_first_cluster = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_ROOTCLUS);\r
+ fs->fs_info_sector = GET_16BIT_WORD(fs->currentsector.sector, BPB_FAT32_FSINFO);\r
+\r
+ // For FAT16 (which this may be), rootdir_first_cluster is actuall rootdir_first_sector\r
+ fs->rootdir_first_sector = reserved_sectors + (num_of_fats * fs->fat_sectors);\r
+ fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;\r
+\r
+ // First FAT LBA address\r
+ fs->fat_begin_lba = fs->lba_begin + reserved_sectors;\r
+\r
+ // The address of the first data cluster on this volume\r
+ fs->cluster_begin_lba = fs->fat_begin_lba + (num_of_fats * fs->fat_sectors);\r
+\r
+ if (GET_16BIT_WORD(fs->currentsector.sector, 0x1FE) != 0xAA55) // This signature should be AA55\r
+ return FAT_INIT_INVALID_SIGNATURE;\r
+\r
+ // Calculate the root dir sectors\r
+ root_dir_sectors = ((GET_16BIT_WORD(fs->currentsector.sector, BPB_ROOTENTCNT) * 32) + (GET_16BIT_WORD(fs->currentsector.sector, BPB_BYTSPERSEC) - 1)) / GET_16BIT_WORD(fs->currentsector.sector, BPB_BYTSPERSEC);\r
+\r
+ if(GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16) != 0)\r
+ FATSz = GET_16BIT_WORD(fs->currentsector.sector, BPB_FATSZ16);\r
+ else\r
+ FATSz = GET_32BIT_WORD(fs->currentsector.sector, BPB_FAT32_FATSZ32);\r
+\r
+ if(GET_16BIT_WORD(fs->currentsector.sector, BPB_TOTSEC16) != 0)\r
+ total_sectors = GET_16BIT_WORD(fs->currentsector.sector, BPB_TOTSEC16);\r
+ else\r
+ total_sectors = GET_32BIT_WORD(fs->currentsector.sector, BPB_TOTSEC32);\r
+\r
+ data_sectors = total_sectors - (GET_16BIT_WORD(fs->currentsector.sector, BPB_RSVDSECCNT) + (fs->currentsector.sector[BPB_NUMFATS] * FATSz) + root_dir_sectors);\r
+\r
+ // Find out which version of FAT this is...\r
+ if (fs->sectors_per_cluster != 0)\r
+ {\r
+ count_of_clusters = data_sectors / fs->sectors_per_cluster;\r
+\r
+ if(count_of_clusters < 4085)\r
+ // Volume is FAT12\r
+ return FAT_INIT_WRONG_FILESYS_TYPE;\r
+ else if(count_of_clusters < 65525)\r
+ {\r
+ // Clear this FAT32 specific param\r
+ fs->rootdir_first_cluster = 0;\r
+\r
+ // Volume is FAT16\r
+ fs->fat_type = FAT_TYPE_16;\r
+ return FAT_INIT_OK;\r
+ }\r
+ else\r
+ {\r
+ // Volume is FAT32\r
+ fs->fat_type = FAT_TYPE_32;\r
+ return FAT_INIT_OK;\r
+ }\r
+ }\r
+ else\r
+ return FAT_INIT_WRONG_FILESYS_TYPE;\r
+}\r
+//-----------------------------------------------------------------------------\r
+// fatfs_lba_of_cluster: This function converts a cluster number into a sector /\r
+// LBA number.\r
+//-----------------------------------------------------------------------------\r
+uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number)\r
+{\r
+ if (fs->fat_type == FAT_TYPE_16)\r
+ return (fs->cluster_begin_lba + (fs->root_entry_count * 32 / FAT_SECTOR_SIZE) + ((Cluster_Number-2) * fs->sectors_per_cluster));\r
+ else\r
+ return ((fs->cluster_begin_lba + ((Cluster_Number-2)*fs->sectors_per_cluster)));\r
+}\r
+//-----------------------------------------------------------------------------\r
+// fatfs_sector_read:\r
+//-----------------------------------------------------------------------------\r
+int fatfs_sector_read(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count)\r
+{\r
+ return fs->disk_io.read_media(lba, target, count);\r
+}\r
+//-----------------------------------------------------------------------------\r
+// fatfs_sector_write:\r
+//-----------------------------------------------------------------------------\r
+int fatfs_sector_write(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count)\r
+{\r
+ return fs->disk_io.write_media(lba, target, count);\r
+}\r
+//-----------------------------------------------------------------------------\r
+// fatfs_sector_reader: From the provided startcluster and sector offset\r
+// Returns True if success, returns False if not (including if read out of range)\r
+//-----------------------------------------------------------------------------\r
+int fatfs_sector_reader(struct fatfs *fs, uint32 start_cluster, uint32 offset, uint8 *target)\r
+{\r
+ uint32 sector_to_read = 0;\r
+ uint32 cluster_to_read = 0;\r
+ uint32 cluster_chain = 0;\r
+ uint32 i;\r
+ uint32 lba;\r
+\r
+ // FAT16 Root directory\r
+ if (fs->fat_type == FAT_TYPE_16 && start_cluster == 0)\r
+ {\r
+ if (offset < fs->rootdir_sectors)\r
+ lba = fs->lba_begin + fs->rootdir_first_sector + offset;\r
+ else\r
+ return 0;\r
+ }\r
+ // FAT16/32 Other\r
+ else\r
+ {\r
+ // Set start of cluster chain to initial value\r
+ cluster_chain = start_cluster;\r
+\r
+ // Find parameters\r
+ cluster_to_read = offset / fs->sectors_per_cluster;\r
+ sector_to_read = offset - (cluster_to_read*fs->sectors_per_cluster);\r
+\r
+ // Follow chain to find cluster to read\r
+ for (i=0; i<cluster_to_read; i++)\r
+ cluster_chain = fatfs_find_next_cluster(fs, cluster_chain);\r
+\r
+ // If end of cluster chain then return false\r
+ if (cluster_chain == FAT32_LAST_CLUSTER)\r
+ return 0;\r
+\r
+ // Calculate sector address\r
+ lba = fatfs_lba_of_cluster(fs, cluster_chain)+sector_to_read;\r
+ }\r
+\r
+ // User provided target array\r
+ if (target)\r
+ return fs->disk_io.read_media(lba, target, 1);\r
+ // Else read sector if not already loaded\r
+ else if (lba != fs->currentsector.address)\r
+ {\r
+ fs->currentsector.address = lba;\r
+ return fs->disk_io.read_media(fs->currentsector.address, fs->currentsector.sector, 1);\r
+ }\r
+ else\r
+ return 1;\r
+}\r
+//-----------------------------------------------------------------------------\r
+// fatfs_read_sector: Read from the provided cluster and sector offset\r
+// Returns True if success, returns False if not\r
+//-----------------------------------------------------------------------------\r
+int fatfs_read_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)\r
+{\r
+ // FAT16 Root directory\r
+ if (fs->fat_type == FAT_TYPE_16 && cluster == 0)\r
+ {\r
+ uint32 lba;\r
+\r
+ // In FAT16, there are a limited amount of sectors in root dir!\r
+ if (sector < fs->rootdir_sectors)\r
+ lba = fs->lba_begin + fs->rootdir_first_sector + sector;\r
+ else\r
+ return 0;\r
+\r
+ // User target buffer passed in\r
+ if (target)\r
+ {\r
+ // Read from disk\r
+ return fs->disk_io.read_media(lba, target, 1);\r
+ }\r
+ else\r
+ {\r
+ // Calculate read address\r
+ fs->currentsector.address = lba;\r
+\r
+ // Read from disk\r
+ return fs->disk_io.read_media(fs->currentsector.address, fs->currentsector.sector, 1);\r
+ }\r
+ }\r
+ // FAT16/32 Other\r
+ else\r
+ {\r
+ // User target buffer passed in\r
+ if (target)\r
+ {\r
+ // Calculate read address\r
+ uint32 lba = fatfs_lba_of_cluster(fs, cluster) + sector;\r
+\r
+ // Read from disk\r
+ return fs->disk_io.read_media(lba, target, 1);\r
+ }\r
+ else\r
+ {\r
+ // Calculate write address\r
+ fs->currentsector.address = fatfs_lba_of_cluster(fs, cluster)+sector;\r
+\r
+ // Read from disk\r
+ return fs->disk_io.read_media(fs->currentsector.address, fs->currentsector.sector, 1);\r
+ }\r
+ }\r
+}\r
+//-----------------------------------------------------------------------------\r
+// fatfs_write_sector: Write to the provided cluster and sector offset\r
+// Returns True if success, returns False if not\r
+//-----------------------------------------------------------------------------\r
+#if FATFS_INC_WRITE_SUPPORT\r
+int fatfs_write_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target)\r
+{\r
+ // No write access?\r
+ if (!fs->disk_io.write_media)\r
+ return 0;\r
+\r
+ // FAT16 Root directory\r
+ if (fs->fat_type == FAT_TYPE_16 && cluster == 0)\r
+ {\r
+ uint32 lba;\r
+\r
+ // In FAT16 we cannot extend the root dir!\r
+ if (sector < fs->rootdir_sectors)\r
+ lba = fs->lba_begin + fs->rootdir_first_sector + sector;\r
+ else\r
+ return 0;\r
+\r
+ // User target buffer passed in\r
+ if (target)\r
+ {\r
+ // Write to disk\r
+ return fs->disk_io.write_media(lba, target, 1);\r
+ }\r
+ else\r
+ {\r
+ // Calculate write address\r
+ fs->currentsector.address = lba;\r
+\r
+ // Write to disk\r
+ return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);\r
+ }\r
+ }\r
+ // FAT16/32 Other\r
+ else\r
+ {\r
+ // User target buffer passed in\r
+ if (target)\r
+ {\r
+ // Calculate write address\r
+ uint32 lba = fatfs_lba_of_cluster(fs, cluster) + sector;\r
+\r
+ // Write to disk\r
+ return fs->disk_io.write_media(lba, target, 1);\r
+ }\r
+ else\r
+ {\r
+ // Calculate write address\r
+ fs->currentsector.address = fatfs_lba_of_cluster(fs, cluster)+sector;\r
+\r
+ // Write to disk\r
+ return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);\r
+ }\r
+ }\r
+}\r
+#endif\r
+//-----------------------------------------------------------------------------\r
+// fatfs_show_details: Show the details about the filesystem\r
+//-----------------------------------------------------------------------------\r
+void fatfs_show_details(struct fatfs *fs)\r
+{\r
+ FAT_PRINTF(("FAT details:\r\n"));\r
+ FAT_PRINTF((" Type =%s", (fs->fat_type == FAT_TYPE_32) ? "FAT32": "FAT16"));\r
+ FAT_PRINTF((" Root Dir First Cluster = %x\r\n", fs->rootdir_first_cluster));\r
+ FAT_PRINTF((" FAT Begin LBA = 0x%x\r\n",fs->fat_begin_lba));\r
+ FAT_PRINTF((" Cluster Begin LBA = 0x%x\r\n",fs->cluster_begin_lba));\r
+ FAT_PRINTF((" Sectors Per Cluster = %d\r\n", fs->sectors_per_cluster));\r
+}\r
+//-----------------------------------------------------------------------------\r
+// fatfs_get_root_cluster: Get the root dir cluster\r
+//-----------------------------------------------------------------------------\r
+uint32 fatfs_get_root_cluster(struct fatfs *fs)\r
+{\r
+ // NOTE: On FAT16 this will be 0 which has a special meaning...\r
+ return fs->rootdir_first_cluster;\r
+}\r
+//-------------------------------------------------------------\r
+// fatfs_get_file_entry: Find the file entry for a filename\r
+//-------------------------------------------------------------\r
+uint32 fatfs_get_file_entry(struct fatfs *fs, uint32 Cluster, char *name_to_find, struct fat_dir_entry *sfEntry)\r
+{\r
+ uint8 item=0;\r
+ uint16 recordoffset = 0;\r
+ uint8 i=0;\r
+ int x=0;\r
+ char *long_filename = NULL;\r
+ char short_filename[13];\r
+ struct lfn_cache lfn;\r
+ int dotRequired = 0;\r
+ struct fat_dir_entry *directoryEntry;\r
+\r
+ fatfs_lfn_cache_init(&lfn, 1);\r
+\r
+ // Main cluster following loop\r
+ while (1)\r
+ {\r
+ // Read sector\r
+ if (fatfs_sector_reader(fs, Cluster, x++, 0)) // If sector read was successfull\r
+ {\r
+ // Analyse Sector\r
+ for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)\r
+ {\r
+ // Create the multiplier for sector access\r
+ recordoffset = FAT_DIR_ENTRY_SIZE * item;\r
+\r
+ // Overlay directory entry over buffer\r
+ directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);\r
+\r
+#if FATFS_INC_LFN_SUPPORT\r
+ // Long File Name Text Found\r
+ if (fatfs_entry_lfn_text(directoryEntry) )\r
+ fatfs_lfn_cache_entry(&lfn, fs->currentsector.sector+recordoffset);\r
+\r
+ // If Invalid record found delete any long file name information collated\r
+ else if (fatfs_entry_lfn_invalid(directoryEntry) )\r
+ fatfs_lfn_cache_init(&lfn, 0);\r
+\r
+ // Normal SFN Entry and Long text exists\r
+ else if (fatfs_entry_lfn_exists(&lfn, directoryEntry) )\r
+ {\r
+ long_filename = fatfs_lfn_cache_get(&lfn);\r
+\r
+ // Compare names to see if they match\r
+ if (fatfs_compare_names(long_filename, name_to_find))\r
+ {\r
+ memcpy(sfEntry,directoryEntry,sizeof(struct fat_dir_entry));\r
+ return 1;\r
+ }\r
+\r
+ fatfs_lfn_cache_init(&lfn, 0);\r
+ }\r
+ else\r
+#endif\r
+ // Normal Entry, only 8.3 Text\r
+ if (fatfs_entry_sfn_only(directoryEntry) )\r
+ {\r
+ memset(short_filename, 0, sizeof(short_filename));\r
+\r
+ // Copy name to string\r
+ for (i=0; i<8; i++)\r
+ short_filename[i] = directoryEntry->Name[i];\r
+\r
+ // Extension\r
+ dotRequired = 0;\r
+ for (i=8; i<11; i++)\r
+ {\r
+ short_filename[i+1] = directoryEntry->Name[i];\r
+ if (directoryEntry->Name[i] != ' ')\r
+ dotRequired = 1;\r
+ }\r
+\r
+ // Dot only required if extension present\r
+ if (dotRequired)\r
+ {\r
+ // If not . or .. entry\r
+ if (short_filename[0]!='.')\r
+ short_filename[8] = '.';\r
+ else\r
+ short_filename[8] = ' ';\r
+ }\r
+ else\r
+ short_filename[8] = ' ';\r
+\r
+ // Compare names to see if they match\r
+ if (fatfs_compare_names(short_filename, name_to_find))\r
+ {\r
+ memcpy(sfEntry,directoryEntry,sizeof(struct fat_dir_entry));\r
+ return 1;\r
+ }\r
+\r
+ fatfs_lfn_cache_init(&lfn, 0);\r
+ }\r
+ } // End of if\r
+ }\r
+ else\r
+ break;\r
+ } // End of while loop\r
+\r
+ return 0;\r
+}\r
+//-------------------------------------------------------------\r
+// fatfs_sfn_exists: Check if a short filename exists.\r
+// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY\r
+//-------------------------------------------------------------\r
+#if FATFS_INC_WRITE_SUPPORT\r
+int fatfs_sfn_exists(struct fatfs *fs, uint32 Cluster, char *shortname)\r
+{\r
+ uint8 item=0;\r
+ uint16 recordoffset = 0;\r
+ int x=0;\r
+ struct fat_dir_entry *directoryEntry;\r
+\r
+ // Main cluster following loop\r
+ while (1)\r
+ {\r
+ // Read sector\r
+ if (fatfs_sector_reader(fs, Cluster, x++, 0)) // If sector read was successfull\r
+ {\r
+ // Analyse Sector\r
+ for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)\r
+ {\r
+ // Create the multiplier for sector access\r
+ recordoffset = FAT_DIR_ENTRY_SIZE * item;\r
+\r
+ // Overlay directory entry over buffer\r
+ directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);\r
+\r
+#if FATFS_INC_LFN_SUPPORT\r
+ // Long File Name Text Found\r
+ if (fatfs_entry_lfn_text(directoryEntry) )\r
+ ;\r
+\r
+ // If Invalid record found delete any long file name information collated\r
+ else if (fatfs_entry_lfn_invalid(directoryEntry) )\r
+ ;\r
+ else\r
+#endif\r
+ // Normal Entry, only 8.3 Text\r
+ if (fatfs_entry_sfn_only(directoryEntry) )\r
+ {\r
+ if (strncmp((const char*)directoryEntry->Name, shortname, 11)==0)\r
+ return 1;\r
+ }\r
+ } // End of if\r
+ }\r
+ else\r
+ break;\r
+ } // End of while loop\r
+\r
+ return 0;\r
+}\r
+#endif\r
+//-------------------------------------------------------------\r
+// fatfs_update_timestamps: Update date/time details\r
+//-------------------------------------------------------------\r
+#if FATFS_INC_TIME_DATE_SUPPORT\r
+int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access)\r
+{\r
+ time_t time_now;\r
+ struct tm * time_info;\r
+ uint16 fat_time;\r
+ uint16 fat_date;\r
+\r
+ // Get system time\r
+ time(&time_now);\r
+\r
+ // Convert to local time\r
+ time_info = localtime(&time_now);\r
+\r
+ // Convert time to FAT format\r
+ fat_time = fatfs_convert_to_fat_time(time_info->tm_hour, time_info->tm_min, time_info->tm_sec);\r
+\r
+ // Convert date to FAT format\r
+ fat_date = fatfs_convert_to_fat_date(time_info->tm_mday, time_info->tm_mon + 1, time_info->tm_year + 1900);\r
+\r
+ // Update requested fields\r
+ if (create)\r
+ {\r
+ directoryEntry->CrtTime[1] = fat_time >> 8;\r
+ directoryEntry->CrtTime[0] = fat_time >> 0;\r
+ directoryEntry->CrtDate[1] = fat_date >> 8;\r
+ directoryEntry->CrtDate[0] = fat_date >> 0;\r
+ }\r
+\r
+ if (modify)\r
+ {\r
+ directoryEntry->WrtTime[1] = fat_time >> 8;\r
+ directoryEntry->WrtTime[0] = fat_time >> 0;\r
+ directoryEntry->WrtDate[1] = fat_date >> 8;\r
+ directoryEntry->WrtDate[0] = fat_date >> 0;\r
+ }\r
+\r
+ if (access)\r
+ {\r
+ directoryEntry->LstAccDate[1] = fat_time >> 8;\r
+ directoryEntry->LstAccDate[0] = fat_time >> 0;\r
+ directoryEntry->LstAccDate[1] = fat_date >> 8;\r
+ directoryEntry->LstAccDate[0] = fat_date >> 0;\r
+ }\r
+\r
+ return 1;\r
+}\r
+#endif\r
+//-------------------------------------------------------------\r
+// fatfs_update_file_length: Find a SFN entry and update it\r
+// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY\r
+//-------------------------------------------------------------\r
+#if FATFS_INC_WRITE_SUPPORT\r
+int fatfs_update_file_length(struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength)\r
+{\r
+ uint8 item=0;\r
+ uint16 recordoffset = 0;\r
+ int x=0;\r
+ struct fat_dir_entry *directoryEntry;\r
+\r
+ // No write access?\r
+ if (!fs->disk_io.write_media)\r
+ return 0;\r
+\r
+ // Main cluster following loop\r
+ while (1)\r
+ {\r
+ // Read sector\r
+ if (fatfs_sector_reader(fs, Cluster, x++, 0)) // If sector read was successfull\r
+ {\r
+ // Analyse Sector\r
+ for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)\r
+ {\r
+ // Create the multiplier for sector access\r
+ recordoffset = FAT_DIR_ENTRY_SIZE * item;\r
+\r
+ // Overlay directory entry over buffer\r
+ directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);\r
+\r
+#if FATFS_INC_LFN_SUPPORT\r
+ // Long File Name Text Found\r
+ if (fatfs_entry_lfn_text(directoryEntry) )\r
+ ;\r
+\r
+ // If Invalid record found delete any long file name information collated\r
+ else if (fatfs_entry_lfn_invalid(directoryEntry) )\r
+ ;\r
+\r
+ // Normal Entry, only 8.3 Text\r
+ else\r
+#endif\r
+ if (fatfs_entry_sfn_only(directoryEntry) )\r
+ {\r
+ if (strncmp((const char*)directoryEntry->Name, shortname, 11)==0)\r
+ {\r
+ directoryEntry->FileSize = FAT_HTONL(fileLength);\r
+\r
+#if FATFS_INC_TIME_DATE_SUPPORT\r
+ // Update access / modify time & date\r
+ fatfs_update_timestamps(directoryEntry, 0, 1, 1);\r
+#endif\r
+\r
+ // Update sfn entry\r
+ memcpy((uint8*)(fs->currentsector.sector+recordoffset), (uint8*)directoryEntry, sizeof(struct fat_dir_entry));\r
+\r
+ // Write sector back\r
+ return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);\r
+ }\r
+ }\r
+ } // End of if\r
+ }\r
+ else\r
+ break;\r
+ } // End of while loop\r
+\r
+ return 0;\r
+}\r
+#endif\r
+//-------------------------------------------------------------\r
+// fatfs_mark_file_deleted: Find a SFN entry and mark if as deleted\r
+// NOTE: shortname is XXXXXXXXYYY not XXXXXXXX.YYY\r
+//-------------------------------------------------------------\r
+#if FATFS_INC_WRITE_SUPPORT\r
+int fatfs_mark_file_deleted(struct fatfs *fs, uint32 Cluster, char *shortname)\r
+{\r
+ uint8 item=0;\r
+ uint16 recordoffset = 0;\r
+ int x=0;\r
+ struct fat_dir_entry *directoryEntry;\r
+\r
+ // No write access?\r
+ if (!fs->disk_io.write_media)\r
+ return 0;\r
+\r
+ // Main cluster following loop\r
+ while (1)\r
+ {\r
+ // Read sector\r
+ if (fatfs_sector_reader(fs, Cluster, x++, 0)) // If sector read was successfull\r
+ {\r
+ // Analyse Sector\r
+ for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)\r
+ {\r
+ // Create the multiplier for sector access\r
+ recordoffset = FAT_DIR_ENTRY_SIZE * item;\r
+\r
+ // Overlay directory entry over buffer\r
+ directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);\r
+\r
+#if FATFS_INC_LFN_SUPPORT\r
+ // Long File Name Text Found\r
+ if (fatfs_entry_lfn_text(directoryEntry) )\r
+ ;\r
+\r
+ // If Invalid record found delete any long file name information collated\r
+ else if (fatfs_entry_lfn_invalid(directoryEntry) )\r
+ ;\r
+\r
+ // Normal Entry, only 8.3 Text\r
+ else\r
+#endif\r
+ if (fatfs_entry_sfn_only(directoryEntry) )\r
+ {\r
+ if (strncmp((const char *)directoryEntry->Name, shortname, 11)==0)\r
+ {\r
+ // Mark as deleted\r
+ directoryEntry->Name[0] = FILE_HEADER_DELETED;\r
+\r
+#if FATFS_INC_TIME_DATE_SUPPORT\r
+ // Update access / modify time & date\r
+ fatfs_update_timestamps(directoryEntry, 0, 1, 1);\r
+#endif\r
+\r
+ // Update sfn entry\r
+ memcpy((uint8*)(fs->currentsector.sector+recordoffset), (uint8*)directoryEntry, sizeof(struct fat_dir_entry));\r
+\r
+ // Write sector back\r
+ return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);\r
+ }\r
+ }\r
+ } // End of if\r
+ }\r
+ else\r
+ break;\r
+ } // End of while loop\r
+\r
+ return 0;\r
+}\r
+#endif\r
+//-----------------------------------------------------------------------------\r
+// fatfs_list_directory_start: Initialise a directory listing procedure\r
+//-----------------------------------------------------------------------------\r
+#if FATFS_DIR_LIST_SUPPORT\r
+void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster)\r
+{\r
+ dirls->cluster = StartCluster;\r
+ dirls->sector = 0;\r
+ dirls->offset = 0;\r
+}\r
+#endif\r
+//-----------------------------------------------------------------------------\r
+// fatfs_list_directory_next: Get the next entry in the directory.\r
+// Returns: 1 = found, 0 = end of listing\r
+//-----------------------------------------------------------------------------\r
+#if FATFS_DIR_LIST_SUPPORT\r
+int fatfs_list_directory_next(struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry)\r
+{\r
+ uint8 i,item;\r
+ uint16 recordoffset;\r
+ struct fat_dir_entry *directoryEntry;\r
+ char *long_filename = NULL;\r
+ char short_filename[13];\r
+ struct lfn_cache lfn;\r
+ int dotRequired = 0;\r
+ int result = 0;\r
+\r
+ // Initialise LFN cache first\r
+ fatfs_lfn_cache_init(&lfn, 0);\r
+\r
+ while (1)\r
+ {\r
+ // If data read OK\r
+ if (fatfs_sector_reader(fs, dirls->cluster, dirls->sector, 0))\r
+ {\r
+ // Maximum of 16 directory entries\r
+ for (item = dirls->offset; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)\r
+ {\r
+ // Increase directory offset\r
+ recordoffset = FAT_DIR_ENTRY_SIZE * item;\r
+\r
+ // Overlay directory entry over buffer\r
+ directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);\r
+\r
+#if FATFS_INC_LFN_SUPPORT\r
+ // Long File Name Text Found\r
+ if ( fatfs_entry_lfn_text(directoryEntry) )\r
+ fatfs_lfn_cache_entry(&lfn, fs->currentsector.sector+recordoffset);\r
+\r
+ // If Invalid record found delete any long file name information collated\r
+ else if ( fatfs_entry_lfn_invalid(directoryEntry) )\r
+ fatfs_lfn_cache_init(&lfn, 0);\r
+\r
+ // Normal SFN Entry and Long text exists\r
+ else if (fatfs_entry_lfn_exists(&lfn, directoryEntry) )\r
+ {\r
+ // Get text\r
+ long_filename = fatfs_lfn_cache_get(&lfn);\r
+ #if defined(_MSC_VER) || defined(WIN32)\r
+ strcpy_s(entry->filename, FATFS_MAX_LONG_FILENAME - 1, long_filename);\r
+ #else\r
+ strncpy(entry->filename, long_filename, FATFS_MAX_LONG_FILENAME - 1);\r
+ #endif\r
+ if (fatfs_entry_is_dir(directoryEntry))\r
+ entry->is_dir = 1;\r
+ else\r
+ entry->is_dir = 0;\r
+\r
+#if FATFS_INC_TIME_DATE_SUPPORT\r
+ // Get time / dates\r
+ entry->create_time = ((uint16)directoryEntry->CrtTime[1] << 8) | directoryEntry->CrtTime[0];\r
+ entry->create_date = ((uint16)directoryEntry->CrtDate[1] << 8) | directoryEntry->CrtDate[0];\r
+ entry->access_date = ((uint16)directoryEntry->LstAccDate[1] << 8) | directoryEntry->LstAccDate[0];\r
+ entry->write_time = ((uint16)directoryEntry->WrtTime[1] << 8) | directoryEntry->WrtTime[0];\r
+ entry->write_date = ((uint16)directoryEntry->WrtDate[1] << 8) | directoryEntry->WrtDate[0];\r
+#endif\r
+\r
+ entry->size = FAT_HTONL(directoryEntry->FileSize);\r
+ entry->cluster = (FAT_HTONS(directoryEntry->FstClusHI)<<16) | FAT_HTONS(directoryEntry->FstClusLO);\r
+\r
+ // Next starting position\r
+ dirls->offset = item + 1;\r
+ result = 1;\r
+ return 1;\r
+ }\r
+ // Normal Entry, only 8.3 Text\r
+ else\r
+#endif\r
+ if ( fatfs_entry_sfn_only(directoryEntry) )\r
+ {\r
+ fatfs_lfn_cache_init(&lfn, 0);\r
+\r
+ memset(short_filename, 0, sizeof(short_filename));\r
+\r
+ // Copy name to string\r
+ for (i=0; i<8; i++)\r
+ short_filename[i] = directoryEntry->Name[i];\r
+\r
+ // Extension\r
+ dotRequired = 0;\r
+ for (i=8; i<11; i++)\r
+ {\r
+ short_filename[i+1] = directoryEntry->Name[i];\r
+ if (directoryEntry->Name[i] != ' ')\r
+ dotRequired = 1;\r
+ }\r
+\r
+ // Dot only required if extension present\r
+ if (dotRequired)\r
+ {\r
+ // If not . or .. entry\r
+ if (short_filename[0]!='.')\r
+ short_filename[8] = '.';\r
+ else\r
+ short_filename[8] = ' ';\r
+ }\r
+ else\r
+ short_filename[8] = ' ';\r
+\r
+ fatfs_get_sfn_display_name(entry->filename, short_filename);\r
+\r
+ if (fatfs_entry_is_dir(directoryEntry))\r
+ entry->is_dir = 1;\r
+ else\r
+ entry->is_dir = 0;\r
+\r
+#if FATFS_INC_TIME_DATE_SUPPORT\r
+ // Get time / dates\r
+ entry->create_time = ((uint16)directoryEntry->CrtTime[1] << 8) | directoryEntry->CrtTime[0];\r
+ entry->create_date = ((uint16)directoryEntry->CrtDate[1] << 8) | directoryEntry->CrtDate[0];\r
+ entry->access_date = ((uint16)directoryEntry->LstAccDate[1] << 8) | directoryEntry->LstAccDate[0];\r
+ entry->write_time = ((uint16)directoryEntry->WrtTime[1] << 8) | directoryEntry->WrtTime[0];\r
+ entry->write_date = ((uint16)directoryEntry->WrtDate[1] << 8) | directoryEntry->WrtDate[0];\r
+#endif\r
+\r
+ entry->size = FAT_HTONL(directoryEntry->FileSize);\r
+ entry->cluster = (FAT_HTONS(directoryEntry->FstClusHI)<<16) | FAT_HTONS(directoryEntry->FstClusLO);\r
+\r
+ // Next starting position\r
+ dirls->offset = item + 1;\r
+ result = 1;\r
+ return 1;\r
+ }\r
+ }// end of for\r
+\r
+ // If reached end of the dir move onto next sector\r
+ dirls->sector++;\r
+ dirls->offset = 0;\r
+ }\r
+ else\r
+ break;\r
+ }\r
+\r
+ return result;\r
+}\r
+#endif\r
--- /dev/null
+#ifndef __FAT_ACCESS_H__
+#define __FAT_ACCESS_H__
+
+#include "fat_defs.h"
+#include "fat_opts.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------------------
+#define FAT_INIT_OK 0
+#define FAT_INIT_MEDIA_ACCESS_ERROR (-1)
+#define FAT_INIT_INVALID_SECTOR_SIZE (-2)
+#define FAT_INIT_INVALID_SIGNATURE (-3)
+#define FAT_INIT_ENDIAN_ERROR (-4)
+#define FAT_INIT_WRONG_FILESYS_TYPE (-5)
+#define FAT_INIT_WRONG_PARTITION_TYPE (-6)
+#define FAT_INIT_STRUCT_PACKING (-7)
+
+#define FAT_DIR_ENTRIES_PER_SECTOR (FAT_SECTOR_SIZE / FAT_DIR_ENTRY_SIZE)
+
+//-----------------------------------------------------------------------------
+// Function Pointers
+//-----------------------------------------------------------------------------
+typedef int (*fn_diskio_read) (uint32 sector, uint8 *buffer, uint32 sector_count);
+typedef int (*fn_diskio_write)(uint32 sector, uint8 *buffer, uint32 sector_count);
+
+//-----------------------------------------------------------------------------
+// Structures
+//-----------------------------------------------------------------------------
+struct disk_if
+{
+ // User supplied function pointers for disk IO
+ fn_diskio_read read_media;
+ fn_diskio_write write_media;
+};
+
+// Forward declaration
+struct fat_buffer;
+
+struct fat_buffer
+{
+ uint8 sector[FAT_SECTOR_SIZE * FAT_BUFFER_SECTORS];
+ uint32 address;
+ int dirty;
+ uint8 * ptr;
+
+ // Next in chain of sector buffers
+ struct fat_buffer *next;
+};
+
+typedef enum eFatType
+{
+ FAT_TYPE_16,
+ FAT_TYPE_32
+} tFatType;
+
+struct fatfs
+{
+ // Filesystem globals
+ uint8 sectors_per_cluster;
+ uint32 cluster_begin_lba;
+ uint32 rootdir_first_cluster;
+ uint32 rootdir_first_sector;
+ uint32 rootdir_sectors;
+ uint32 fat_begin_lba;
+ uint16 fs_info_sector;
+ uint32 lba_begin;
+ uint32 fat_sectors;
+ uint32 next_free_cluster;
+ uint16 root_entry_count;
+ uint16 reserved_sectors;
+ uint8 num_of_fats;
+ tFatType fat_type;
+
+ // Disk/Media API
+ struct disk_if disk_io;
+
+ // [Optional] Thread Safety
+ void (*fl_lock)(void);
+ void (*fl_unlock)(void);
+
+ // Working buffer
+ struct fat_buffer currentsector;
+
+ // FAT Buffer
+ struct fat_buffer *fat_buffer_head;
+ struct fat_buffer fat_buffers[FAT_BUFFERS];
+};
+
+struct fs_dir_list_status
+{
+ uint32 sector;
+ uint32 cluster;
+ uint8 offset;
+};
+
+struct fs_dir_ent
+{
+ char filename[FATFS_MAX_LONG_FILENAME];
+ uint8 is_dir;
+ uint32 cluster;
+ uint32 size;
+
+#if FATFS_INC_TIME_DATE_SUPPORT
+ uint16 access_date;
+ uint16 write_time;
+ uint16 write_date;
+ uint16 create_date;
+ uint16 create_time;
+#endif
+};
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+int fatfs_init(struct fatfs *fs);
+uint32 fatfs_lba_of_cluster(struct fatfs *fs, uint32 Cluster_Number);
+int fatfs_sector_reader(struct fatfs *fs, uint32 Startcluster, uint32 offset, uint8 *target);
+int fatfs_sector_read(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
+int fatfs_sector_write(struct fatfs *fs, uint32 lba, uint8 *target, uint32 count);
+int fatfs_read_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
+int fatfs_write_sector(struct fatfs *fs, uint32 cluster, uint32 sector, uint8 *target);
+void fatfs_show_details(struct fatfs *fs);
+uint32 fatfs_get_root_cluster(struct fatfs *fs);
+uint32 fatfs_get_file_entry(struct fatfs *fs, uint32 Cluster, char *nametofind, struct fat_dir_entry *sfEntry);
+int fatfs_sfn_exists(struct fatfs *fs, uint32 Cluster, char *shortname);
+int fatfs_update_file_length(struct fatfs *fs, uint32 Cluster, char *shortname, uint32 fileLength);
+int fatfs_mark_file_deleted(struct fatfs *fs, uint32 Cluster, char *shortname);
+void fatfs_list_directory_start(struct fatfs *fs, struct fs_dir_list_status *dirls, uint32 StartCluster);
+int fatfs_list_directory_next(struct fatfs *fs, struct fs_dir_list_status *dirls, struct fs_dir_ent *entry);
+int fatfs_update_timestamps(struct fat_dir_entry *directoryEntry, int create, int modify, int access);
+
+#endif
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+// FAT16/32 File IO Library\r
+// V2.6\r
+// Ultra-Embedded.com\r
+// Copyright 2003 - 2012\r
+//\r
+// Email: admin@ultra-embedded.com\r
+//\r
+// License: GPL\r
+// If you would like a version with a more permissive license for use in\r
+// closed source commercial applications please contact me for details.\r
+//-----------------------------------------------------------------------------\r
+//\r
+// This file is part of FAT File IO Library.\r
+//\r
+// FAT File IO Library is free software; you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation; either version 2 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// FAT File IO Library is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with FAT File IO Library; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+#include <string.h>
+#include "fat_cache.h"
+
+// Per file cluster chain caching used to improve performance.
+// This does not have to be enabled for architectures with low
+// memory space.
+
+//-----------------------------------------------------------------------------
+// fatfs_cache_init:
+//-----------------------------------------------------------------------------
+int fatfs_cache_init(struct fatfs *fs, FL_FILE *file)
+{
+#ifdef FAT_CLUSTER_CACHE_ENTRIES
+ int i;
+
+ for (i=0;i<FAT_CLUSTER_CACHE_ENTRIES;i++)
+ {
+ file->cluster_cache_idx[i] = 0xFFFFFFFF; // Not used
+ file->cluster_cache_data[i] = 0;
+ }
+#endif
+
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_cache_get_next_cluster:
+//-----------------------------------------------------------------------------
+int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster)
+{
+#ifdef FAT_CLUSTER_CACHE_ENTRIES
+ uint32 slot = clusterIdx % FAT_CLUSTER_CACHE_ENTRIES;
+
+ if (file->cluster_cache_idx[slot] == clusterIdx)
+ {
+ *pNextCluster = file->cluster_cache_data[slot];
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_cache_set_next_cluster:
+//-----------------------------------------------------------------------------
+int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster)
+{
+#ifdef FAT_CLUSTER_CACHE_ENTRIES
+ uint32 slot = clusterIdx % FAT_CLUSTER_CACHE_ENTRIES;
+
+ if (file->cluster_cache_idx[slot] == clusterIdx)
+ file->cluster_cache_data[slot] = nextCluster;
+ else
+ {
+ file->cluster_cache_idx[slot] = clusterIdx;
+ file->cluster_cache_data[slot] = nextCluster;
+ }
+#endif
+
+ return 1;
+}
--- /dev/null
+#ifndef __FAT_CACHE_H__
+#define __FAT_CACHE_H__
+
+#include "fat_filelib.h"
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+int fatfs_cache_init(struct fatfs *fs, FL_FILE *file);
+int fatfs_cache_get_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 *pNextCluster);
+int fatfs_cache_set_next_cluster(struct fatfs *fs, FL_FILE *file, uint32 clusterIdx, uint32 nextCluster);
+
+#endif
--- /dev/null
+#ifndef __FAT_DEFS_H__
+#define __FAT_DEFS_H__
+
+#include "fat_opts.h"
+#include "fat_types.h"
+
+//-----------------------------------------------------------------------------
+// FAT32 Offsets
+// Name Offset
+//-----------------------------------------------------------------------------
+
+// Boot Sector
+#define BS_JMPBOOT 0 // Length = 3
+#define BS_OEMNAME 3 // Length = 8
+#define BPB_BYTSPERSEC 11 // Length = 2
+#define BPB_SECPERCLUS 13 // Length = 1
+#define BPB_RSVDSECCNT 14 // Length = 2
+#define BPB_NUMFATS 16 // Length = 1
+#define BPB_ROOTENTCNT 17 // Length = 2
+#define BPB_TOTSEC16 19 // Length = 2
+#define BPB_MEDIA 21 // Length = 1
+#define BPB_FATSZ16 22 // Length = 2
+#define BPB_SECPERTRK 24 // Length = 2
+#define BPB_NUMHEADS 26 // Length = 2
+#define BPB_HIDDSEC 28 // Length = 4
+#define BPB_TOTSEC32 32 // Length = 4
+
+// FAT 12/16
+#define BS_FAT_DRVNUM 36 // Length = 1
+#define BS_FAT_BOOTSIG 38 // Length = 1
+#define BS_FAT_VOLID 39 // Length = 4
+#define BS_FAT_VOLLAB 43 // Length = 11
+#define BS_FAT_FILSYSTYPE 54 // Length = 8
+
+// FAT 32
+#define BPB_FAT32_FATSZ32 36 // Length = 4
+#define BPB_FAT32_EXTFLAGS 40 // Length = 2
+#define BPB_FAT32_FSVER 42 // Length = 2
+#define BPB_FAT32_ROOTCLUS 44 // Length = 4
+#define BPB_FAT32_FSINFO 48 // Length = 2
+#define BPB_FAT32_BKBOOTSEC 50 // Length = 2
+#define BS_FAT32_DRVNUM 64 // Length = 1
+#define BS_FAT32_BOOTSIG 66 // Length = 1
+#define BS_FAT32_VOLID 67 // Length = 4
+#define BS_FAT32_VOLLAB 71 // Length = 11
+#define BS_FAT32_FILSYSTYPE 82 // Length = 8
+
+//-----------------------------------------------------------------------------
+// FAT Types
+//-----------------------------------------------------------------------------
+#define FAT_TYPE_FAT12 1
+#define FAT_TYPE_FAT16 2
+#define FAT_TYPE_FAT32 3
+
+//-----------------------------------------------------------------------------
+// FAT32 Specific Statics
+//-----------------------------------------------------------------------------
+#define SIGNATURE_POSITION 510
+#define SIGNATURE_VALUE 0xAA55
+#define PARTITION1_TYPECODE_LOCATION 450
+#define FAT32_TYPECODE1 0x0B
+#define FAT32_TYPECODE2 0x0C
+#define PARTITION1_LBA_BEGIN_LOCATION 454
+#define PARTITION1_SIZE_LOCATION 458
+
+#define FAT_DIR_ENTRY_SIZE 32
+#define FAT_SFN_SIZE_FULL 11
+#define FAT_SFN_SIZE_PARTIAL 8
+
+//-----------------------------------------------------------------------------
+// FAT32 File Attributes and Types
+//-----------------------------------------------------------------------------
+#define FILE_ATTR_READ_ONLY 0x01
+#define FILE_ATTR_HIDDEN 0x02
+#define FILE_ATTR_SYSTEM 0x04
+#define FILE_ATTR_SYSHID 0x06
+#define FILE_ATTR_VOLUME_ID 0x08
+#define FILE_ATTR_DIRECTORY 0x10
+#define FILE_ATTR_ARCHIVE 0x20
+#define FILE_ATTR_LFN_TEXT 0x0F
+#define FILE_HEADER_BLANK 0x00
+#define FILE_HEADER_DELETED 0xE5
+#define FILE_TYPE_DIR 0x10
+#define FILE_TYPE_FILE 0x20
+
+//-----------------------------------------------------------------------------
+// Time / Date details
+//-----------------------------------------------------------------------------
+#define FAT_TIME_HOURS_SHIFT 11
+#define FAT_TIME_HOURS_MASK 0x1F
+#define FAT_TIME_MINUTES_SHIFT 5
+#define FAT_TIME_MINUTES_MASK 0x3F
+#define FAT_TIME_SECONDS_SHIFT 0
+#define FAT_TIME_SECONDS_MASK 0x1F
+#define FAT_TIME_SECONDS_SCALE 2
+#define FAT_DATE_YEAR_SHIFT 9
+#define FAT_DATE_YEAR_MASK 0x7F
+#define FAT_DATE_MONTH_SHIFT 5
+#define FAT_DATE_MONTH_MASK 0xF
+#define FAT_DATE_DAY_SHIFT 0
+#define FAT_DATE_DAY_MASK 0x1F
+#define FAT_DATE_YEAR_OFFSET 1980
+
+//-----------------------------------------------------------------------------
+// Other Defines
+//-----------------------------------------------------------------------------
+#define FAT32_LAST_CLUSTER 0xFFFFFFFF
+#define FAT32_INVALID_CLUSTER 0xFFFFFFFF
+
+STRUCT_PACK_BEGIN
+struct fat_dir_entry STRUCT_PACK
+{
+ uint8 Name[11];
+ uint8 Attr;
+ uint8 NTRes;
+ uint8 CrtTimeTenth;
+ uint8 CrtTime[2];
+ uint8 CrtDate[2];
+ uint8 LstAccDate[2];
+ uint16 FstClusHI;
+ uint8 WrtTime[2];
+ uint8 WrtDate[2];
+ uint16 FstClusLO;
+ uint32 FileSize;
+} STRUCT_PACKED;
+STRUCT_PACK_END
+
+#endif
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+// FAT16/32 File IO Library\r
+// V2.6\r
+// Ultra-Embedded.com\r
+// Copyright 2003 - 2012\r
+//\r
+// Email: admin@ultra-embedded.com\r
+//\r
+// License: GPL\r
+// If you would like a version with a more permissive license for use in\r
+// closed source commercial applications please contact me for details.\r
+//-----------------------------------------------------------------------------\r
+//\r
+// This file is part of FAT File IO Library.\r
+//\r
+// FAT File IO Library is free software; you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation; either version 2 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// FAT File IO Library is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with FAT File IO Library; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+#include <stdlib.h>
+#include <string.h>
+#include "fat_defs.h"
+#include "fat_access.h"
+#include "fat_table.h"
+#include "fat_write.h"
+#include "fat_misc.h"
+#include "fat_string.h"
+#include "fat_filelib.h"
+#include "fat_cache.h"
+
+//-----------------------------------------------------------------------------
+// Locals
+//-----------------------------------------------------------------------------
+static FL_FILE _files[FATFS_MAX_OPEN_FILES];
+static int _filelib_init = 0;
+static int _filelib_valid = 0;
+static struct fatfs _fs;
+static struct fat_list _open_file_list;
+static struct fat_list _free_file_list;
+
+//-----------------------------------------------------------------------------
+// Macros
+//-----------------------------------------------------------------------------
+
+// Macro for checking if file lib is initialised
+#define CHECK_FL_INIT() { if (_filelib_init==0) fl_init(); }
+
+#define FL_LOCK(a) do { if ((a)->fl_lock) (a)->fl_lock(); } while (0)
+#define FL_UNLOCK(a) do { if ((a)->fl_unlock) (a)->fl_unlock(); } while (0)
+
+//-----------------------------------------------------------------------------
+// Local Functions
+//-----------------------------------------------------------------------------
+static void _fl_init();
+
+//-----------------------------------------------------------------------------
+// _allocate_file: Find a slot in the open files buffer for a new file
+//-----------------------------------------------------------------------------
+static FL_FILE* _allocate_file(void)
+{
+ // Allocate free file
+ struct fat_node *node = fat_list_pop_head(&_free_file_list);
+
+ // Add to open list
+ if (node)
+ fat_list_insert_last(&_open_file_list, node);
+
+ return fat_list_entry(node, FL_FILE, list_node);
+}
+//-----------------------------------------------------------------------------
+// _check_file_open: Returns true if the file is already open
+//-----------------------------------------------------------------------------
+static int _check_file_open(FL_FILE* file)
+{
+ struct fat_node *node;
+
+ // Compare open files
+ fat_list_for_each(&_open_file_list, node)
+ {
+ FL_FILE* openFile = fat_list_entry(node, FL_FILE, list_node);
+
+ // If not the current file
+ if (openFile != file)
+ {
+ // Compare path and name
+ if ( (fatfs_compare_names(openFile->path,file->path)) && (fatfs_compare_names(openFile->filename,file->filename)) )
+ return 1;
+ }
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// _free_file: Free open file handle
+//-----------------------------------------------------------------------------
+static void _free_file(FL_FILE* file)
+{
+ // Remove from open list
+ fat_list_remove(&_open_file_list, &file->list_node);
+
+ // Add to free list
+ fat_list_insert_last(&_free_file_list, &file->list_node);
+}
+
+//-----------------------------------------------------------------------------
+// Low Level
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// _open_directory: Cycle through path string to find the start cluster
+// address of the highest subdir.
+//-----------------------------------------------------------------------------
+static int _open_directory(char *path, uint32 *pathCluster)
+{
+ int levels;
+ int sublevel;
+ char currentfolder[FATFS_MAX_LONG_FILENAME];
+ struct fat_dir_entry sfEntry;
+ uint32 startcluster;
+
+ // Set starting cluster to root cluster
+ startcluster = fatfs_get_root_cluster(&_fs);
+
+ // Find number of levels
+ levels = fatfs_total_path_levels(path);
+
+ // Cycle through each level and get the start sector
+ for (sublevel=0;sublevel<(levels+1);sublevel++)
+ {
+ if (fatfs_get_substring(path, sublevel, currentfolder, sizeof(currentfolder)) == -1)
+ return 0;
+
+ // Find clusteraddress for folder (currentfolder)
+ if (fatfs_get_file_entry(&_fs, startcluster, currentfolder,&sfEntry))
+ {
+ // Check entry is folder
+ if (fatfs_entry_is_dir(&sfEntry))
+ startcluster = ((FAT_HTONS((uint32)sfEntry.FstClusHI))<<16) + FAT_HTONS(sfEntry.FstClusLO);
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+
+ *pathCluster = startcluster;
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// _create_directory: Cycle through path string and create the end directory
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+static int _create_directory(char *path)
+{
+ FL_FILE* file;
+ struct fat_dir_entry sfEntry;
+ char shortFilename[FAT_SFN_SIZE_FULL];
+ int tailNum = 0;
+ int i;
+
+ // Allocate a new file handle
+ file = _allocate_file();
+ if (!file)
+ return 0;
+
+ // Clear filename
+ memset(file->path, '\0', sizeof(file->path));
+ memset(file->filename, '\0', sizeof(file->filename));
+
+ // Split full path into filename and directory path
+ if (fatfs_split_path((char*)path, file->path, sizeof(file->path), file->filename, sizeof(file->filename)) == -1)
+ {
+ _free_file(file);
+ return 0;
+ }
+
+ // Check if file already open
+ if (_check_file_open(file))
+ {
+ _free_file(file);
+ return 0;
+ }
+
+ // If file is in the root dir
+ if (file->path[0] == 0)
+ file->parentcluster = fatfs_get_root_cluster(&_fs);
+ else
+ {
+ // Find parent directory start cluster
+ if (!_open_directory(file->path, &file->parentcluster))
+ {
+ _free_file(file);
+ return 0;
+ }
+ }
+
+ // Check if same filename exists in directory
+ if (fatfs_get_file_entry(&_fs, file->parentcluster, file->filename,&sfEntry) == 1)
+ {
+ _free_file(file);
+ return 0;
+ }
+
+ file->startcluster = 0;
+
+ // Create the file space for the folder (at least one clusters worth!)
+ if (!fatfs_allocate_free_space(&_fs, 1, &file->startcluster, 1))
+ {
+ _free_file(file);
+ return 0;
+ }
+
+ // Erase new directory cluster
+ memset(file->file_data_sector, 0x00, FAT_SECTOR_SIZE);
+ for (i=0;i<_fs.sectors_per_cluster;i++)
+ {
+ if (!fatfs_write_sector(&_fs, file->startcluster, i, file->file_data_sector))
+ {
+ _free_file(file);
+ return 0;
+ }
+ }
+
+#if FATFS_INC_LFN_SUPPORT
+
+ // Generate a short filename & tail
+ tailNum = 0;
+ do
+ {
+ // Create a standard short filename (without tail)
+ fatfs_lfn_create_sfn(shortFilename, file->filename);
+
+ // If second hit or more, generate a ~n tail
+ if (tailNum != 0)
+ fatfs_lfn_generate_tail((char*)file->shortfilename, shortFilename, tailNum);
+ // Try with no tail if first entry
+ else
+ memcpy(file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
+
+ // Check if entry exists already or not
+ if (fatfs_sfn_exists(&_fs, file->parentcluster, (char*)file->shortfilename) == 0)
+ break;
+
+ tailNum++;
+ }
+ while (tailNum < 9999);
+
+ // We reached the max number of duplicate short file names (unlikely!)
+ if (tailNum == 9999)
+ {
+ // Delete allocated space
+ fatfs_free_cluster_chain(&_fs, file->startcluster);
+
+ _free_file(file);
+ return 0;
+ }
+#else
+ // Create a standard short filename (without tail)
+ if (!fatfs_lfn_create_sfn(shortFilename, file->filename))
+ {
+ // Delete allocated space
+ fatfs_free_cluster_chain(&_fs, file->startcluster);
+
+ _free_file(file);
+ return 0;
+ }
+
+ // Copy to SFN space
+ memcpy(file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
+
+ // Check if entry exists already
+ if (fatfs_sfn_exists(&_fs, file->parentcluster, (char*)file->shortfilename))
+ {
+ // Delete allocated space
+ fatfs_free_cluster_chain(&_fs, file->startcluster);
+
+ _free_file(file);
+ return 0;
+ }
+#endif
+
+ // Add file to disk
+ if (!fatfs_add_file_entry(&_fs, file->parentcluster, (char*)file->filename, (char*)file->shortfilename, file->startcluster, 0, 1))
+ {
+ // Delete allocated space
+ fatfs_free_cluster_chain(&_fs, file->startcluster);
+
+ _free_file(file);
+ return 0;
+ }
+
+ // General
+ file->filelength = 0;
+ file->bytenum = 0;
+ file->file_data_address = 0xFFFFFFFF;
+ file->file_data_dirty = 0;
+ file->filelength_changed = 0;
+
+ // Quick lookup for next link in the chain
+ file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
+ file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
+
+ fatfs_fat_purge(&_fs);
+
+ _free_file(file);
+ return 1;
+}
+#endif
+//-----------------------------------------------------------------------------
+// _open_file: Open a file for reading
+//-----------------------------------------------------------------------------
+static FL_FILE* _open_file(const char *path)
+{
+ FL_FILE* file;
+ struct fat_dir_entry sfEntry;
+
+ // Allocate a new file handle
+ file = _allocate_file();
+ if (!file)
+ return NULL;
+
+ // Clear filename
+ memset(file->path, '\0', sizeof(file->path));
+ memset(file->filename, '\0', sizeof(file->filename));
+
+ // Split full path into filename and directory path
+ if (fatfs_split_path((char*)path, file->path, sizeof(file->path), file->filename, sizeof(file->filename)) == -1)
+ {
+ _free_file(file);
+ return NULL;
+ }
+
+ // Check if file already open
+ if (_check_file_open(file))
+ {
+ _free_file(file);
+ return NULL;
+ }
+
+ // If file is in the root dir
+ if (file->path[0]==0)
+ file->parentcluster = fatfs_get_root_cluster(&_fs);
+ else
+ {
+ // Find parent directory start cluster
+ if (!_open_directory(file->path, &file->parentcluster))
+ {
+ _free_file(file);
+ return NULL;
+ }
+ }
+
+ // Using dir cluster address search for filename
+ if (fatfs_get_file_entry(&_fs, file->parentcluster, file->filename,&sfEntry))
+ // Make sure entry is file not dir!
+ if (fatfs_entry_is_file(&sfEntry))
+ {
+ // Initialise file details
+ memcpy(file->shortfilename, sfEntry.Name, FAT_SFN_SIZE_FULL);
+ file->filelength = FAT_HTONL(sfEntry.FileSize);
+ file->bytenum = 0;
+ file->startcluster = ((FAT_HTONS((uint32)sfEntry.FstClusHI))<<16) + FAT_HTONS(sfEntry.FstClusLO);
+ file->file_data_address = 0xFFFFFFFF;
+ file->file_data_dirty = 0;
+ file->filelength_changed = 0;
+
+ // Quick lookup for next link in the chain
+ file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
+ file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
+
+ fatfs_cache_init(&_fs, file);
+
+ fatfs_fat_purge(&_fs);
+
+ return file;
+ }
+
+ _free_file(file);
+ return NULL;
+}
+//-----------------------------------------------------------------------------
+// _create_file: Create a new file
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+static FL_FILE* _create_file(const char *filename)
+{
+ FL_FILE* file;
+ struct fat_dir_entry sfEntry;
+ char shortFilename[FAT_SFN_SIZE_FULL];
+ int tailNum = 0;
+
+ // No write access?
+ if (!_fs.disk_io.write_media)
+ return NULL;
+
+ // Allocate a new file handle
+ file = _allocate_file();
+ if (!file)
+ return NULL;
+
+ // Clear filename
+ memset(file->path, '\0', sizeof(file->path));
+ memset(file->filename, '\0', sizeof(file->filename));
+
+ // Split full path into filename and directory path
+ if (fatfs_split_path((char*)filename, file->path, sizeof(file->path), file->filename, sizeof(file->filename)) == -1)
+ {
+ _free_file(file);
+ return NULL;
+ }
+
+ // Check if file already open
+ if (_check_file_open(file))
+ {
+ _free_file(file);
+ return NULL;
+ }
+
+ // If file is in the root dir
+ if (file->path[0] == 0)
+ file->parentcluster = fatfs_get_root_cluster(&_fs);
+ else
+ {
+ // Find parent directory start cluster
+ if (!_open_directory(file->path, &file->parentcluster))
+ {
+ _free_file(file);
+ return NULL;
+ }
+ }
+
+ // Check if same filename exists in directory
+ if (fatfs_get_file_entry(&_fs, file->parentcluster, file->filename,&sfEntry) == 1)
+ {
+ _free_file(file);
+ return NULL;
+ }
+
+ file->startcluster = 0;
+
+ // Create the file space for the file (at least one clusters worth!)
+ if (!fatfs_allocate_free_space(&_fs, 1, &file->startcluster, 1))
+ {
+ _free_file(file);
+ return NULL;
+ }
+
+#if FATFS_INC_LFN_SUPPORT
+ // Generate a short filename & tail
+ tailNum = 0;
+ do
+ {
+ // Create a standard short filename (without tail)
+ fatfs_lfn_create_sfn(shortFilename, file->filename);
+
+ // If second hit or more, generate a ~n tail
+ if (tailNum != 0)
+ fatfs_lfn_generate_tail((char*)file->shortfilename, shortFilename, tailNum);
+ // Try with no tail if first entry
+ else
+ memcpy(file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
+
+ // Check if entry exists already or not
+ if (fatfs_sfn_exists(&_fs, file->parentcluster, (char*)file->shortfilename) == 0)
+ break;
+
+ tailNum++;
+ }
+ while (tailNum < 9999);
+
+ // We reached the max number of duplicate short file names (unlikely!)
+ if (tailNum == 9999)
+ {
+ // Delete allocated space
+ fatfs_free_cluster_chain(&_fs, file->startcluster);
+
+ _free_file(file);
+ return NULL;
+ }
+#else
+ // Create a standard short filename (without tail)
+ if (!fatfs_lfn_create_sfn(shortFilename, file->filename))
+ {
+ // Delete allocated space
+ fatfs_free_cluster_chain(&_fs, file->startcluster);
+
+ _free_file(file);
+ return NULL;
+ }
+
+ // Copy to SFN space
+ memcpy(file->shortfilename, shortFilename, FAT_SFN_SIZE_FULL);
+
+ // Check if entry exists already
+ if (fatfs_sfn_exists(&_fs, file->parentcluster, (char*)file->shortfilename))
+ {
+ // Delete allocated space
+ fatfs_free_cluster_chain(&_fs, file->startcluster);
+
+ _free_file(file);
+ return NULL;
+ }
+#endif
+
+ // Add file to disk
+ if (!fatfs_add_file_entry(&_fs, file->parentcluster, (char*)file->filename, (char*)file->shortfilename, file->startcluster, 0, 0))
+ {
+ // Delete allocated space
+ fatfs_free_cluster_chain(&_fs, file->startcluster);
+
+ _free_file(file);
+ return NULL;
+ }
+
+ // General
+ file->filelength = 0;
+ file->bytenum = 0;
+ file->file_data_address = 0xFFFFFFFF;
+ file->file_data_dirty = 0;
+ file->filelength_changed = 0;
+
+ // Quick lookup for next link in the chain
+ file->last_fat_lookup.ClusterIdx = 0xFFFFFFFF;
+ file->last_fat_lookup.CurrentCluster = 0xFFFFFFFF;
+
+ fatfs_cache_init(&_fs, file);
+
+ fatfs_fat_purge(&_fs);
+
+ return file;
+}
+#endif
+//-----------------------------------------------------------------------------
+// _read_sectors: Read sector(s) from disk to file
+//-----------------------------------------------------------------------------
+static uint32 _read_sectors(FL_FILE* file, uint32 offset, uint8 *buffer, uint32 count)
+{
+ uint32 Sector = 0;
+ uint32 ClusterIdx = 0;
+ uint32 Cluster = 0;
+ uint32 i;
+ uint32 lba;
+
+ // Find cluster index within file & sector with cluster
+ ClusterIdx = offset / _fs.sectors_per_cluster;
+ Sector = offset - (ClusterIdx * _fs.sectors_per_cluster);
+
+ // Limit number of sectors read to the number remaining in this cluster
+ if ((Sector + count) > _fs.sectors_per_cluster)
+ count = _fs.sectors_per_cluster - Sector;
+
+ // Quick lookup for next link in the chain
+ if (ClusterIdx == file->last_fat_lookup.ClusterIdx)
+ Cluster = file->last_fat_lookup.CurrentCluster;
+ // Else walk the chain
+ else
+ {
+ // Starting from last recorded cluster?
+ if (ClusterIdx && ClusterIdx == file->last_fat_lookup.ClusterIdx + 1)
+ {
+ i = file->last_fat_lookup.ClusterIdx;
+ Cluster = file->last_fat_lookup.CurrentCluster;
+ }
+ // Start searching from the beginning..
+ else
+ {
+ // Set start of cluster chain to initial value
+ i = 0;
+ Cluster = file->startcluster;
+ }
+
+ // Follow chain to find cluster to read
+ for ( ;i<ClusterIdx; i++)
+ {
+ uint32 nextCluster;
+
+ // Does the entry exist in the cache?
+ if (!fatfs_cache_get_next_cluster(&_fs, file, i, &nextCluster))
+ {
+ // Scan file linked list to find next entry
+ nextCluster = fatfs_find_next_cluster(&_fs, Cluster);
+
+ // Push entry into cache
+ fatfs_cache_set_next_cluster(&_fs, file, i, nextCluster);
+ }
+
+ Cluster = nextCluster;
+ }
+
+ // Record current cluster lookup details (if valid)
+ if (Cluster != FAT32_LAST_CLUSTER)
+ {
+ file->last_fat_lookup.CurrentCluster = Cluster;
+ file->last_fat_lookup.ClusterIdx = ClusterIdx;
+ }
+ }
+
+ // If end of cluster chain then return false
+ if (Cluster == FAT32_LAST_CLUSTER)
+ return 0;
+
+ // Calculate sector address
+ lba = fatfs_lba_of_cluster(&_fs, Cluster) + Sector;
+
+ // Read sector of file
+ if (fatfs_sector_read(&_fs, lba, buffer, count))
+ return count;
+ else
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// External API
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// fl_init: Initialise library
+//-----------------------------------------------------------------------------
+void fl_init(void)
+{
+ int i;
+
+ fat_list_init(&_free_file_list);
+ fat_list_init(&_open_file_list);
+
+ // Add all file objects to free list
+ for (i=0;i<FATFS_MAX_OPEN_FILES;i++)
+ fat_list_insert_last(&_free_file_list, &_files[i].list_node);
+
+ _filelib_init = 1;
+}
+//-----------------------------------------------------------------------------
+// fl_attach_locks:
+//-----------------------------------------------------------------------------
+void fl_attach_locks(void (*lock)(void), void (*unlock)(void))
+{
+ _fs.fl_lock = lock;
+ _fs.fl_unlock = unlock;
+}
+//-----------------------------------------------------------------------------
+// fl_attach_media:
+//-----------------------------------------------------------------------------
+int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr)
+{
+ int res;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ _fs.disk_io.read_media = rd;
+ _fs.disk_io.write_media = wr;
+
+ // Initialise FAT parameters
+ if ((res = fatfs_init(&_fs)) != FAT_INIT_OK)
+ {
+ FAT_PRINTF(("FAT_FS: Error could not load FAT details (%d)!\r\n", res));
+ return res;
+ }
+
+ _filelib_valid = 1;
+ return FAT_INIT_OK;
+}
+//-----------------------------------------------------------------------------
+// fl_shutdown: Call before shutting down system
+//-----------------------------------------------------------------------------
+void fl_shutdown(void)
+{
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ FL_LOCK(&_fs);
+ fatfs_fat_purge(&_fs);
+ FL_UNLOCK(&_fs);
+}
+//-----------------------------------------------------------------------------
+// fopen: Open or Create a file for reading or writing
+//-----------------------------------------------------------------------------
+void* fl_fopen(const char *path, const char *mode)
+{
+ int i;
+ FL_FILE* file;
+ uint8 flags = 0;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ if (!_filelib_valid)
+ return NULL;
+
+ if (!path || !mode)
+ return NULL;
+
+ // Supported Modes:
+ // "r" Open a file for reading.
+ // The file must exist.
+ // "w" Create an empty file for writing.
+ // If a file with the same name already exists its content is erased and the file is treated as a new empty file.
+ // "a" Append to a file.
+ // Writing operations append data at the end of the file.
+ // The file is created if it does not exist.
+ // "r+" Open a file for update both reading and writing.
+ // The file must exist.
+ // "w+" Create an empty file for both reading and writing.
+ // If a file with the same name already exists its content is erased and the file is treated as a new empty file.
+ // "a+" Open a file for reading and appending.
+ // All writing operations are performed at the end of the file, protecting the previous content to be overwritten.
+ // You can reposition (fseek, rewind) the internal pointer to anywhere in the file for reading, but writing operations
+ // will move it back to the end of file.
+ // The file is created if it does not exist.
+
+ for (i=0;i<(int)strlen(mode);i++)
+ {
+ switch (mode[i])
+ {
+ case 'r':
+ case 'R':
+ flags |= FILE_READ;
+ break;
+ case 'w':
+ case 'W':
+ flags |= FILE_WRITE;
+ flags |= FILE_ERASE;
+ flags |= FILE_CREATE;
+ break;
+ case 'a':
+ case 'A':
+ flags |= FILE_WRITE;
+ flags |= FILE_APPEND;
+ flags |= FILE_CREATE;
+ break;
+ case '+':
+ if (flags & FILE_READ)
+ flags |= FILE_WRITE;
+ else if (flags & FILE_WRITE)
+ {
+ flags |= FILE_READ;
+ flags |= FILE_ERASE;
+ flags |= FILE_CREATE;
+ }
+ else if (flags & FILE_APPEND)
+ {
+ flags |= FILE_READ;
+ flags |= FILE_WRITE;
+ flags |= FILE_APPEND;
+ flags |= FILE_CREATE;
+ }
+ break;
+ case 'b':
+ case 'B':
+ flags |= FILE_BINARY;
+ break;
+ }
+ }
+
+ file = NULL;
+
+#if FATFS_INC_WRITE_SUPPORT == 0
+ // No write support!
+ flags &= ~(FILE_CREATE | FILE_WRITE | FILE_APPEND);
+#endif
+
+ // No write access - remove write/modify flags
+ if (!_fs.disk_io.write_media)
+ flags &= ~(FILE_CREATE | FILE_WRITE | FILE_APPEND);
+
+ FL_LOCK(&_fs);
+
+ // Read
+ if (flags & FILE_READ)
+ file = _open_file(path);
+
+ // Create New
+#if FATFS_INC_WRITE_SUPPORT
+ if (!file && (flags & FILE_CREATE))
+ file = _create_file(path);
+#endif
+
+ // Write Existing (and not open due to read or create)
+ if (!(flags & FILE_READ))
+ if ((flags & FILE_CREATE) && !file)
+ if (flags & (FILE_WRITE | FILE_APPEND))
+ file = _open_file(path);
+
+ if (file)
+ file->flags = flags;
+
+ FL_UNLOCK(&_fs);
+ return file;
+}
+//-----------------------------------------------------------------------------
+// _write_sectors: Write sector(s) to disk
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+static uint32 _write_sectors(FL_FILE* file, uint32 offset, uint8 *buf, uint32 count)
+{
+ uint32 SectorNumber = 0;
+ uint32 ClusterIdx = 0;
+ uint32 Cluster = 0;
+ uint32 LastCluster = FAT32_LAST_CLUSTER;
+ uint32 i;
+ uint32 lba;
+ uint32 TotalWriteCount = count;
+
+ // Find values for Cluster index & sector within cluster
+ ClusterIdx = offset / _fs.sectors_per_cluster;
+ SectorNumber = offset - (ClusterIdx * _fs.sectors_per_cluster);
+
+ // Limit number of sectors written to the number remaining in this cluster
+ if ((SectorNumber + count) > _fs.sectors_per_cluster)
+ count = _fs.sectors_per_cluster - SectorNumber;
+
+ // Quick lookup for next link in the chain
+ if (ClusterIdx == file->last_fat_lookup.ClusterIdx)
+ Cluster = file->last_fat_lookup.CurrentCluster;
+ // Else walk the chain
+ else
+ {
+ // Starting from last recorded cluster?
+ if (ClusterIdx && ClusterIdx == file->last_fat_lookup.ClusterIdx + 1)
+ {
+ i = file->last_fat_lookup.ClusterIdx;
+ Cluster = file->last_fat_lookup.CurrentCluster;
+ }
+ // Start searching from the beginning..
+ else
+ {
+ // Set start of cluster chain to initial value
+ i = 0;
+ Cluster = file->startcluster;
+ }
+
+ // Follow chain to find cluster to read
+ for ( ;i<ClusterIdx; i++)
+ {
+ uint32 nextCluster;
+
+ // Does the entry exist in the cache?
+ if (!fatfs_cache_get_next_cluster(&_fs, file, i, &nextCluster))
+ {
+ // Scan file linked list to find next entry
+ nextCluster = fatfs_find_next_cluster(&_fs, Cluster);
+
+ // Push entry into cache
+ fatfs_cache_set_next_cluster(&_fs, file, i, nextCluster);
+ }
+
+ LastCluster = Cluster;
+ Cluster = nextCluster;
+
+ // Dont keep following a dead end
+ if (Cluster == FAT32_LAST_CLUSTER)
+ break;
+ }
+
+ // If we have reached the end of the chain, allocate more!
+ if (Cluster == FAT32_LAST_CLUSTER)
+ {
+ // Add some more cluster(s) to the last good cluster chain
+ if (!fatfs_add_free_space(&_fs, &LastCluster, (TotalWriteCount + _fs.sectors_per_cluster -1) / _fs.sectors_per_cluster))
+ return 0;
+
+ Cluster = LastCluster;
+ }
+
+ // Record current cluster lookup details
+ file->last_fat_lookup.CurrentCluster = Cluster;
+ file->last_fat_lookup.ClusterIdx = ClusterIdx;
+ }
+
+ // Calculate write address
+ lba = fatfs_lba_of_cluster(&_fs, Cluster) + SectorNumber;
+
+ if (fatfs_sector_write(&_fs, lba, buf, count))
+ return count;
+ else
+ return 0;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_fflush: Flush un-written data to the file
+//-----------------------------------------------------------------------------
+int fl_fflush(void *f)
+{
+#if FATFS_INC_WRITE_SUPPORT
+ FL_FILE *file = (FL_FILE *)f;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ if (file)
+ {
+ FL_LOCK(&_fs);
+
+ // If some write data still in buffer
+ if (file->file_data_dirty)
+ {
+ // Write back current sector before loading next
+ if (_write_sectors(file, file->file_data_address, file->file_data_sector, 1))
+ file->file_data_dirty = 0;
+ }
+
+ FL_UNLOCK(&_fs);
+ }
+#endif
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fl_fclose: Close an open file
+//-----------------------------------------------------------------------------
+void fl_fclose(void *f)
+{
+ FL_FILE *file = (FL_FILE *)f;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ if (file)
+ {
+ FL_LOCK(&_fs);
+
+ // Flush un-written data to file
+ fl_fflush(f);
+
+ // File size changed?
+ if (file->filelength_changed)
+ {
+#if FATFS_INC_WRITE_SUPPORT
+ // Update filesize in directory
+ fatfs_update_file_length(&_fs, file->parentcluster, (char*)file->shortfilename, file->filelength);
+#endif
+ file->filelength_changed = 0;
+ }
+
+ file->bytenum = 0;
+ file->filelength = 0;
+ file->startcluster = 0;
+ file->file_data_address = 0xFFFFFFFF;
+ file->file_data_dirty = 0;
+ file->filelength_changed = 0;
+
+ // Free file handle
+ _free_file(file);
+
+ fatfs_fat_purge(&_fs);
+
+ FL_UNLOCK(&_fs);
+ }
+}
+//-----------------------------------------------------------------------------
+// fl_fgetc: Get a character in the stream
+//-----------------------------------------------------------------------------
+int fl_fgetc(void *f)
+{
+ int res;
+ uint8 data = 0;
+
+ res = fl_fread(&data, 1, 1, f);
+ if (res == 1)
+ return (int)data;
+ else
+ return res;
+}
+//-----------------------------------------------------------------------------
+// fl_fgets: Get a string from a stream
+//-----------------------------------------------------------------------------
+char *fl_fgets(char *s, int n, void *f)
+{
+ int idx = 0;
+
+ // Space for null terminator?
+ if (n > 0)
+ {
+ // While space (+space for null terminator)
+ while (idx < (n-1))
+ {
+ int ch = fl_fgetc(f);
+
+ // EOF / Error?
+ if (ch < 0)
+ break;
+
+ // Store character read from stream
+ s[idx++] = (char)ch;
+
+ // End of line?
+ if (ch == '\n')
+ break;
+ }
+
+ if (idx > 0)
+ s[idx] = '\0';
+ }
+
+ return (idx > 0) ? s : 0;
+}
+//-----------------------------------------------------------------------------
+// fl_fread: Read a block of data from the file
+//-----------------------------------------------------------------------------
+int fl_fread(void * buffer, int size, int length, void *f )
+{
+ uint32 sector;
+ uint32 offset;
+ int copyCount;
+ int count = size * length;
+ int bytesRead = 0;
+
+ FL_FILE *file = (FL_FILE *)f;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ if (buffer==NULL || file==NULL)
+ return -1;
+
+ // No read permissions
+ if (!(file->flags & FILE_READ))
+ return -1;
+
+ // Nothing to be done
+ if (!count)
+ return 0;
+
+ // Check if read starts past end of file
+ if (file->bytenum >= file->filelength)
+ return -1;
+
+ // Limit to file size
+ if ( (file->bytenum + count) > file->filelength )
+ count = file->filelength - file->bytenum;
+
+ // Calculate start sector
+ sector = file->bytenum / FAT_SECTOR_SIZE;
+
+ // Offset to start copying data from first sector
+ offset = file->bytenum % FAT_SECTOR_SIZE;
+
+ while (bytesRead < count)
+ {
+ // Read whole sector, read from media directly into target buffer
+ if ((offset == 0) && ((count - bytesRead) >= FAT_SECTOR_SIZE))
+ {
+ // Read as many sectors as possible into target buffer
+ uint32 sectorsRead = _read_sectors(file, sector, (uint8*)((uint8*)buffer + bytesRead), (count - bytesRead) / FAT_SECTOR_SIZE);
+ if (sectorsRead)
+ {
+ // We have upto one sector to copy
+ copyCount = FAT_SECTOR_SIZE * sectorsRead;
+
+ // Move onto next sector and reset copy offset
+ sector+= sectorsRead;
+ offset = 0;
+ }
+ else
+ break;
+ }
+ else
+ {
+ // Do we need to re-read the sector?
+ if (file->file_data_address != sector)
+ {
+ // Flush un-written data to file
+ if (file->file_data_dirty)
+ fl_fflush(file);
+
+ // Get LBA of sector offset within file
+ if (!_read_sectors(file, sector, file->file_data_sector, 1))
+ // Read failed - out of range (probably)
+ break;
+
+ file->file_data_address = sector;
+ file->file_data_dirty = 0;
+ }
+
+ // We have upto one sector to copy
+ copyCount = FAT_SECTOR_SIZE - offset;
+
+ // Only require some of this sector?
+ if (copyCount > (count - bytesRead))
+ copyCount = (count - bytesRead);
+
+ // Copy to application buffer
+ memcpy( (uint8*)((uint8*)buffer + bytesRead), (uint8*)(file->file_data_sector + offset), copyCount);
+
+ // Move onto next sector and reset copy offset
+ sector++;
+ offset = 0;
+ }
+
+ // Increase total read count
+ bytesRead += copyCount;
+
+ // Increment file pointer
+ file->bytenum += copyCount;
+ }
+
+ return bytesRead;
+}
+//-----------------------------------------------------------------------------
+// fl_fseek: Seek to a specific place in the file
+//-----------------------------------------------------------------------------
+int fl_fseek( void *f, long offset, int origin )
+{
+ FL_FILE *file = (FL_FILE *)f;
+ int res = -1;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ if (!file)
+ return -1;
+
+ if (origin == SEEK_END && offset != 0)
+ return -1;
+
+ FL_LOCK(&_fs);
+
+ // Invalidate file buffer
+ file->file_data_address = 0xFFFFFFFF;
+ file->file_data_dirty = 0;
+
+ if (origin == SEEK_SET)
+ {
+ file->bytenum = (uint32)offset;
+
+ if (file->bytenum > file->filelength)
+ file->bytenum = file->filelength;
+
+ res = 0;
+ }
+ else if (origin == SEEK_CUR)
+ {
+ // Positive shift
+ if (offset >= 0)
+ {
+ file->bytenum += offset;
+
+ if (file->bytenum > file->filelength)
+ file->bytenum = file->filelength;
+ }
+ // Negative shift
+ else
+ {
+ // Make shift positive
+ offset = -offset;
+
+ // Limit to negative shift to start of file
+ if ((uint32)offset > file->bytenum)
+ file->bytenum = 0;
+ else
+ file->bytenum-= offset;
+ }
+
+ res = 0;
+ }
+ else if (origin == SEEK_END)
+ {
+ file->bytenum = file->filelength;
+ res = 0;
+ }
+ else
+ res = -1;
+
+ FL_UNLOCK(&_fs);
+
+ return res;
+}
+//-----------------------------------------------------------------------------
+// fl_fgetpos: Get the current file position
+//-----------------------------------------------------------------------------
+int fl_fgetpos(void *f , uint32 * position)
+{
+ FL_FILE *file = (FL_FILE *)f;
+
+ if (!file)
+ return -1;
+
+ FL_LOCK(&_fs);
+
+ // Get position
+ *position = file->bytenum;
+
+ FL_UNLOCK(&_fs);
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fl_ftell: Get the current file position
+//-----------------------------------------------------------------------------
+long fl_ftell(void *f)
+{
+ uint32 pos = 0;
+
+ fl_fgetpos(f, &pos);
+
+ return (long)pos;
+}
+//-----------------------------------------------------------------------------
+// fl_feof: Is the file pointer at the end of the stream?
+//-----------------------------------------------------------------------------
+int fl_feof(void *f)
+{
+ FL_FILE *file = (FL_FILE *)f;
+ int res;
+
+ if (!file)
+ return -1;
+
+ FL_LOCK(&_fs);
+
+ if (file->bytenum == file->filelength)
+ res = EOF;
+ else
+ res = 0;
+
+ FL_UNLOCK(&_fs);
+
+ return res;
+}
+//-----------------------------------------------------------------------------
+// fl_fputc: Write a character to the stream
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fl_fputc(int c, void *f)
+{
+ uint8 data = (uint8)c;
+ int res;
+
+ res = fl_fwrite(&data, 1, 1, f);
+ if (res == 1)
+ return c;
+ else
+ return res;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_fwrite: Write a block of data to the stream
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fl_fwrite(const void * data, int size, int count, void *f )
+{
+ FL_FILE *file = (FL_FILE *)f;
+ uint32 sector;
+ uint32 offset;
+ uint32 length = (size*count);
+ uint8 *buffer = (uint8 *)data;
+ uint32 bytesWritten = 0;
+ uint32 copyCount;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ if (!file)
+ return -1;
+
+ FL_LOCK(&_fs);
+
+ // No write permissions
+ if (!(file->flags & FILE_WRITE))
+ {
+ FL_UNLOCK(&_fs);
+ return -1;
+ }
+
+ // Append writes to end of file
+ if (file->flags & FILE_APPEND)
+ file->bytenum = file->filelength;
+ // Else write to current position
+
+ // Calculate start sector
+ sector = file->bytenum / FAT_SECTOR_SIZE;
+
+ // Offset to start copying data from first sector
+ offset = file->bytenum % FAT_SECTOR_SIZE;
+
+ while (bytesWritten < length)
+ {
+ // Whole sector or more to be written?
+ if ((offset == 0) && ((length - bytesWritten) >= FAT_SECTOR_SIZE))
+ {
+ uint32 sectorsWrote;
+
+ // Buffered sector, flush back to disk
+ if (file->file_data_address != 0xFFFFFFFF)
+ {
+ // Flush un-written data to file
+ if (file->file_data_dirty)
+ fl_fflush(file);
+
+ file->file_data_address = 0xFFFFFFFF;
+ file->file_data_dirty = 0;
+ }
+
+ // Write as many sectors as possible
+ sectorsWrote = _write_sectors(file, sector, (uint8*)(buffer + bytesWritten), (length - bytesWritten) / FAT_SECTOR_SIZE);
+ copyCount = FAT_SECTOR_SIZE * sectorsWrote;
+
+ // Increase total read count
+ bytesWritten += copyCount;
+
+ // Increment file pointer
+ file->bytenum += copyCount;
+
+ // Move onto next sector and reset copy offset
+ sector+= sectorsWrote;
+ offset = 0;
+
+ if (!sectorsWrote)
+ break;
+ }
+ else
+ {
+ // We have upto one sector to copy
+ copyCount = FAT_SECTOR_SIZE - offset;
+
+ // Only require some of this sector?
+ if (copyCount > (length - bytesWritten))
+ copyCount = (length - bytesWritten);
+
+ // Do we need to read a new sector?
+ if (file->file_data_address != sector)
+ {
+ // Flush un-written data to file
+ if (file->file_data_dirty)
+ fl_fflush(file);
+
+ // If we plan to overwrite the whole sector, we don't need to read it first!
+ if (copyCount != FAT_SECTOR_SIZE)
+ {
+ // NOTE: This does not have succeed; if last sector of file
+ // reached, no valid data will be read in, but write will
+ // allocate some more space for new data.
+
+ // Get LBA of sector offset within file
+ if (!_read_sectors(file, sector, file->file_data_sector, 1))
+ memset(file->file_data_sector, 0x00, FAT_SECTOR_SIZE);
+ }
+
+ file->file_data_address = sector;
+ file->file_data_dirty = 0;
+ }
+
+ // Copy from application buffer into sector buffer
+ memcpy((uint8*)(file->file_data_sector + offset), (uint8*)(buffer + bytesWritten), copyCount);
+
+ // Mark buffer as dirty
+ file->file_data_dirty = 1;
+
+ // Increase total read count
+ bytesWritten += copyCount;
+
+ // Increment file pointer
+ file->bytenum += copyCount;
+
+ // Move onto next sector and reset copy offset
+ sector++;
+ offset = 0;
+ }
+ }
+
+ // Write increased extent of the file?
+ if (file->bytenum > file->filelength)
+ {
+ // Increase file size to new point
+ file->filelength = file->bytenum;
+
+ // We are changing the file length and this
+ // will need to be writen back at some point
+ file->filelength_changed = 1;
+ }
+
+#if FATFS_INC_TIME_DATE_SUPPORT
+ // If time & date support is enabled, always force directory entry to be
+ // written in-order to update file modify / access time & date.
+ file->filelength_changed = 1;
+#endif
+
+ FL_UNLOCK(&_fs);
+
+ return (size*count);
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_fputs: Write a character string to the stream
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fl_fputs(const char * str, void *f)
+{
+ int len = (int)strlen(str);
+ int res = fl_fwrite(str, 1, len, f);
+
+ if (res == len)
+ return len;
+ else
+ return res;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_remove: Remove a file from the filesystem
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fl_remove( const char * filename )
+{
+ FL_FILE* file;
+ int res = -1;
+
+ FL_LOCK(&_fs);
+
+ // Use read_file as this will check if the file is already open!
+ file = fl_fopen((char*)filename, "r");
+ if (file)
+ {
+ // Delete allocated space
+ if (fatfs_free_cluster_chain(&_fs, file->startcluster))
+ {
+ // Remove directory entries
+ if (fatfs_mark_file_deleted(&_fs, file->parentcluster, (char*)file->shortfilename))
+ {
+ // Close the file handle (this should not write anything to the file
+ // as we have not changed the file since opening it!)
+ fl_fclose(file);
+
+ res = 0;
+ }
+ }
+ }
+
+ FL_UNLOCK(&_fs);
+
+ return res;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_createdirectory: Create a directory based on a path
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fl_createdirectory(const char *path)
+{
+ int res;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ FL_LOCK(&_fs);
+ res =_create_directory((char*)path);
+ FL_UNLOCK(&_fs);
+
+ return res;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_listdirectory: List a directory based on a path
+//-----------------------------------------------------------------------------
+#if FATFS_DIR_LIST_SUPPORT
+void fl_listdirectory(const char *path)
+{
+ FL_DIR dirstat;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ FL_LOCK(&_fs);
+
+ FAT_PRINTF(("\r\nDirectory %s\r\n", path));
+
+ if (fl_opendir(path, &dirstat))
+ {
+ struct fs_dir_ent dirent;
+
+ while (fl_readdir(&dirstat, &dirent) == 0)
+ {
+#if FATFS_INC_TIME_DATE_SUPPORT
+ int d,m,y,h,mn,s;
+ fatfs_convert_from_fat_time(dirent.write_time, &h,&m,&s);
+ fatfs_convert_from_fat_date(dirent.write_date, &d,&mn,&y);
+ FAT_PRINTF(("%02d/%02d/%04d %02d:%02d ", d,mn,y,h,m));
+#endif
+
+ if (dirent.is_dir)
+ {
+ FAT_PRINTF(("%s <DIR>\r\n", dirent.filename));
+ }
+ else
+ {
+ FAT_PRINTF(("%s [%d bytes]\r\n", dirent.filename, dirent.size));
+ }
+ }
+
+ fl_closedir(&dirstat);
+ }
+
+ FL_UNLOCK(&_fs);
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_opendir: Opens a directory for listing
+//-----------------------------------------------------------------------------
+#if FATFS_DIR_LIST_SUPPORT
+FL_DIR* fl_opendir(const char* path, FL_DIR *dir)
+{
+ int levels;
+ int res = 1;
+ uint32 cluster = FAT32_INVALID_CLUSTER;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ FL_LOCK(&_fs);
+
+ levels = fatfs_total_path_levels((char*)path) + 1;
+
+ // If path is in the root dir
+ if (levels == 0)
+ cluster = fatfs_get_root_cluster(&_fs);
+ // Find parent directory start cluster
+ else
+ res = _open_directory((char*)path, &cluster);
+
+ if (res)
+ fatfs_list_directory_start(&_fs, dir, cluster);
+
+ FL_UNLOCK(&_fs);
+
+ return cluster != FAT32_INVALID_CLUSTER ? dir : 0;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_readdir: Get next item in directory
+//-----------------------------------------------------------------------------
+#if FATFS_DIR_LIST_SUPPORT
+int fl_readdir(FL_DIR *dirls, fl_dirent *entry)
+{
+ int res = 0;
+
+ // If first call to library, initialise
+ CHECK_FL_INIT();
+
+ FL_LOCK(&_fs);
+
+ res = fatfs_list_directory_next(&_fs, dirls, entry);
+
+ FL_UNLOCK(&_fs);
+
+ return res ? 0 : -1;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_closedir: Close directory after listing
+//-----------------------------------------------------------------------------
+#if FATFS_DIR_LIST_SUPPORT
+int fl_closedir(FL_DIR* dir)
+{
+ // Not used
+ return 0;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_is_dir: Is this a directory?
+//-----------------------------------------------------------------------------
+#if FATFS_DIR_LIST_SUPPORT
+int fl_is_dir(const char *path)
+{
+ int res = 0;
+ FL_DIR dir;
+
+ if (fl_opendir(path, &dir))
+ {
+ res = 1;
+ fl_closedir(&dir);
+ }
+
+ return res;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fl_format: Format a partition with either FAT16 or FAT32 based on size
+//-----------------------------------------------------------------------------
+#if FATFS_INC_FORMAT_SUPPORT
+int fl_format(uint32 volume_sectors, const char *name)
+{
+ return fatfs_format(&_fs, volume_sectors, name);
+}
+#endif /*FATFS_INC_FORMAT_SUPPORT*/
+//-----------------------------------------------------------------------------
+// fl_get_fs:
+//-----------------------------------------------------------------------------
+#ifdef FATFS_INC_TEST_HOOKS
+struct fatfs* fl_get_fs(void)
+{
+ return &_fs;
+}
+#endif
--- /dev/null
+#ifndef __FAT_FILELIB_H__
+#define __FAT_FILELIB_H__
+
+#include "fat_opts.h"
+#include "fat_access.h"
+#include "fat_list.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------------------
+#ifndef SEEK_CUR
+ #define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+ #define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+ #define SEEK_SET 0
+#endif
+
+#ifndef EOF
+ #define EOF (-1)
+#endif
+
+//-----------------------------------------------------------------------------
+// Structures
+//-----------------------------------------------------------------------------
+struct sFL_FILE;
+
+struct cluster_lookup
+{
+ uint32 ClusterIdx;
+ uint32 CurrentCluster;
+};
+
+typedef struct sFL_FILE
+{
+ uint32 parentcluster;
+ uint32 startcluster;
+ uint32 bytenum;
+ uint32 filelength;
+ int filelength_changed;
+ char path[FATFS_MAX_LONG_FILENAME];
+ char filename[FATFS_MAX_LONG_FILENAME];
+ uint8 shortfilename[11];
+
+#ifdef FAT_CLUSTER_CACHE_ENTRIES
+ uint32 cluster_cache_idx[FAT_CLUSTER_CACHE_ENTRIES];
+ uint32 cluster_cache_data[FAT_CLUSTER_CACHE_ENTRIES];
+#endif
+
+ // Cluster Lookup
+ struct cluster_lookup last_fat_lookup;
+
+ // Read/Write sector buffer
+ uint8 file_data_sector[FAT_SECTOR_SIZE];
+ uint32 file_data_address;
+ int file_data_dirty;
+
+ // File fopen flags
+ uint8 flags;
+#define FILE_READ (1 << 0)
+#define FILE_WRITE (1 << 1)
+#define FILE_APPEND (1 << 2)
+#define FILE_BINARY (1 << 3)
+#define FILE_ERASE (1 << 4)
+#define FILE_CREATE (1 << 5)
+
+ struct fat_node list_node;
+} FL_FILE;
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+
+// External
+void fl_init(void);
+void fl_attach_locks(void (*lock)(void), void (*unlock)(void));
+int fl_attach_media(fn_diskio_read rd, fn_diskio_write wr);
+void fl_shutdown(void);
+
+// Standard API
+void* fl_fopen(const char *path, const char *modifiers);
+void fl_fclose(void *file);
+int fl_fflush(void *file);
+int fl_fgetc(void *file);
+char * fl_fgets(char *s, int n, void *f);
+int fl_fputc(int c, void *file);
+int fl_fputs(const char * str, void *file);
+int fl_fwrite(const void * data, int size, int count, void *file );
+int fl_fread(void * data, int size, int count, void *file );
+int fl_fseek(void *file , long offset , int origin );
+int fl_fgetpos(void *file , uint32 * position);
+long fl_ftell(void *f);
+int fl_feof(void *f);
+int fl_remove(const char * filename);
+
+// Equivelant dirent.h
+typedef struct fs_dir_list_status FL_DIR;
+typedef struct fs_dir_ent fl_dirent;
+
+FL_DIR* fl_opendir(const char* path, FL_DIR *dir);
+int fl_readdir(FL_DIR *dirls, fl_dirent *entry);
+int fl_closedir(FL_DIR* dir);
+
+// Extensions
+void fl_listdirectory(const char *path);
+int fl_createdirectory(const char *path);
+int fl_is_dir(const char *path);
+
+int fl_format(uint32 volume_sectors, const char *name);
+
+// Test hooks
+#ifdef FATFS_INC_TEST_HOOKS
+struct fatfs* fl_get_fs(void);
+#endif
+
+//-----------------------------------------------------------------------------
+// Stdio file I/O names
+//-----------------------------------------------------------------------------
+#ifdef USE_FILELIB_STDIO_COMPAT_NAMES
+
+#define FILE FL_FILE
+
+#define fopen(a,b) fl_fopen(a, b)
+#define fclose(a) fl_fclose(a)
+#define fflush(a) fl_fflush(a)
+#define fgetc(a) fl_fgetc(a)
+#define fgets(a,b,c) fl_fgets(a, b, c)
+#define fputc(a,b) fl_fputc(a, b)
+#define fputs(a,b) fl_fputs(a, b)
+#define fwrite(a,b,c,d) fl_fwrite(a, b, c, d)
+#define fread(a,b,c,d) fl_fread(a, b, c, d)
+#define fseek(a,b,c) fl_fseek(a, b, c)
+#define fgetpos(a,b) fl_fgetpos(a, b)
+#define ftell(a) fl_ftell(a)
+#define feof(a) fl_feof(a)
+#define remove(a) fl_remove(a)
+#define mkdir(a) fl_createdirectory(a)
+#define rmdir(a) 0
+
+#endif
+
+#endif
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+// FAT16/32 File IO Library\r
+// V2.6\r
+// Ultra-Embedded.com\r
+// Copyright 2003 - 2012\r
+//\r
+// Email: admin@ultra-embedded.com\r
+//\r
+// License: GPL\r
+// If you would like a version with a more permissive license for use in\r
+// closed source commercial applications please contact me for details.\r
+//-----------------------------------------------------------------------------\r
+//\r
+// This file is part of FAT File IO Library.\r
+//\r
+// FAT File IO Library is free software; you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation; either version 2 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// FAT File IO Library is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with FAT File IO Library; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+#include <string.h>
+#include "fat_defs.h"
+#include "fat_access.h"
+#include "fat_table.h"
+#include "fat_write.h"
+#include "fat_string.h"
+#include "fat_misc.h"
+#include "fat_format.h"
+
+#if FATFS_INC_FORMAT_SUPPORT
+
+//-----------------------------------------------------------------------------
+// Tables
+//-----------------------------------------------------------------------------
+struct sec_per_clus_table
+{
+ uint32 sectors;
+ uint8 sectors_per_cluster;
+};
+
+struct sec_per_clus_table _cluster_size_table16[] =
+{
+ { 32680, 2}, // 16MB - 1K
+ { 262144, 4}, // 128MB - 2K
+ { 524288, 8}, // 256MB - 4K
+ { 1048576, 16}, // 512MB - 8K
+ { 2097152, 32}, // 1GB - 16K
+ { 4194304, 64}, // 2GB - 32K
+ { 8388608, 128},// 2GB - 64K [Warning only supported by Windows XP onwards]
+ { 0 , 0 } // Invalid
+};
+
+struct sec_per_clus_table _cluster_size_table32[] =
+{
+ { 532480, 1}, // 260MB - 512b
+ { 16777216, 8}, // 8GB - 4K
+ { 33554432, 16}, // 16GB - 8K
+ { 67108864, 32}, // 32GB - 16K
+ { 0xFFFFFFFF, 64},// >32GB - 32K
+ { 0 , 0 } // Invalid
+};
+
+//-----------------------------------------------------------------------------
+// fatfs_calc_cluster_size: Calculate what cluster size should be used
+//-----------------------------------------------------------------------------
+static uint8 fatfs_calc_cluster_size(uint32 sectors, int is_fat32)
+{
+ int i;
+
+ if (!is_fat32)
+ {
+ for (i=0; _cluster_size_table16[i].sectors_per_cluster != 0;i++)
+ if (sectors <= _cluster_size_table16[i].sectors)
+ return _cluster_size_table16[i].sectors_per_cluster;
+ }
+ else
+ {
+ for (i=0; _cluster_size_table32[i].sectors_per_cluster != 0;i++)
+ if (sectors <= _cluster_size_table32[i].sectors)
+ return _cluster_size_table32[i].sectors_per_cluster;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_erase_sectors: Erase a number of sectors
+//-----------------------------------------------------------------------------
+static int fatfs_erase_sectors(struct fatfs *fs, uint32 lba, int count)
+{
+ int i;
+
+ // Zero sector first
+ memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
+
+ for (i=0;i<count;i++)
+ if (!fs->disk_io.write_media(lba + i, fs->currentsector.sector, 1))
+ return 0;
+
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_create_boot_sector: Create the boot sector
+//-----------------------------------------------------------------------------
+static int fatfs_create_boot_sector(struct fatfs *fs, uint32 boot_sector_lba, uint32 vol_sectors, const char *name, int is_fat32)
+{
+ uint32 total_clusters;
+ int i;
+
+ // Zero sector initially
+ memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
+
+ // OEM Name & Jump Code
+ fs->currentsector.sector[0] = 0xEB;
+ fs->currentsector.sector[1] = 0x3C;
+ fs->currentsector.sector[2] = 0x90;
+ fs->currentsector.sector[3] = 0x4D;
+ fs->currentsector.sector[4] = 0x53;
+ fs->currentsector.sector[5] = 0x44;
+ fs->currentsector.sector[6] = 0x4F;
+ fs->currentsector.sector[7] = 0x53;
+ fs->currentsector.sector[8] = 0x35;
+ fs->currentsector.sector[9] = 0x2E;
+ fs->currentsector.sector[10] = 0x30;
+
+ // Bytes per sector
+ fs->currentsector.sector[11] = (FAT_SECTOR_SIZE >> 0) & 0xFF;
+ fs->currentsector.sector[12] = (FAT_SECTOR_SIZE >> 8) & 0xFF;
+
+ // Get sectors per cluster size for the disk
+ fs->sectors_per_cluster = fatfs_calc_cluster_size(vol_sectors, is_fat32);
+ if (!fs->sectors_per_cluster)
+ return 0; // Invalid disk size
+
+ // Sectors per cluster
+ fs->currentsector.sector[13] = fs->sectors_per_cluster;
+
+ // Reserved Sectors
+ if (!is_fat32)
+ fs->reserved_sectors = 8;
+ else
+ fs->reserved_sectors = 32;
+ fs->currentsector.sector[14] = (fs->reserved_sectors >> 0) & 0xFF;
+ fs->currentsector.sector[15] = (fs->reserved_sectors >> 8) & 0xFF;
+
+ // Number of FATS
+ fs->num_of_fats = 2;
+ fs->currentsector.sector[16] = fs->num_of_fats;
+
+ // Max entries in root dir (FAT16 only)
+ if (!is_fat32)
+ {
+ fs->root_entry_count = 512;
+ fs->currentsector.sector[17] = (fs->root_entry_count >> 0) & 0xFF;
+ fs->currentsector.sector[18] = (fs->root_entry_count >> 8) & 0xFF;
+ }
+ else
+ {
+ fs->root_entry_count = 0;
+ fs->currentsector.sector[17] = 0;
+ fs->currentsector.sector[18] = 0;
+ }
+
+ // [FAT16] Total sectors (use FAT32 count instead)
+ fs->currentsector.sector[19] = 0x00;
+ fs->currentsector.sector[20] = 0x00;
+
+ // Media type
+ fs->currentsector.sector[21] = 0xF8;
+
+
+ // FAT16 BS Details
+ if (!is_fat32)
+ {
+ // Count of sectors used by the FAT table (FAT16 only)
+ total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
+ fs->fat_sectors = (total_clusters/(FAT_SECTOR_SIZE/2)) + 1;
+ fs->currentsector.sector[22] = (uint8)((fs->fat_sectors >> 0) & 0xFF);
+ fs->currentsector.sector[23] = (uint8)((fs->fat_sectors >> 8) & 0xFF);
+
+ // Sectors per track
+ fs->currentsector.sector[24] = 0x00;
+ fs->currentsector.sector[25] = 0x00;
+
+ // Heads
+ fs->currentsector.sector[26] = 0x00;
+ fs->currentsector.sector[27] = 0x00;
+
+ // Hidden sectors
+ fs->currentsector.sector[28] = 0x20;
+ fs->currentsector.sector[29] = 0x00;
+ fs->currentsector.sector[30] = 0x00;
+ fs->currentsector.sector[31] = 0x00;
+
+ // Total sectors for this volume
+ fs->currentsector.sector[32] = (uint8)((vol_sectors>>0)&0xFF);
+ fs->currentsector.sector[33] = (uint8)((vol_sectors>>8)&0xFF);
+ fs->currentsector.sector[34] = (uint8)((vol_sectors>>16)&0xFF);
+ fs->currentsector.sector[35] = (uint8)((vol_sectors>>24)&0xFF);
+
+ // Drive number
+ fs->currentsector.sector[36] = 0x00;
+
+ // Reserved
+ fs->currentsector.sector[37] = 0x00;
+
+ // Boot signature
+ fs->currentsector.sector[38] = 0x29;
+
+ // Volume ID
+ fs->currentsector.sector[39] = 0x12;
+ fs->currentsector.sector[40] = 0x34;
+ fs->currentsector.sector[41] = 0x56;
+ fs->currentsector.sector[42] = 0x78;
+
+ // Volume name
+ for (i=0;i<11;i++)
+ {
+ if (i < (int)strlen(name))
+ fs->currentsector.sector[i+43] = name[i];
+ else
+ fs->currentsector.sector[i+43] = ' ';
+ }
+
+ // File sys type
+ fs->currentsector.sector[54] = 'F';
+ fs->currentsector.sector[55] = 'A';
+ fs->currentsector.sector[56] = 'T';
+ fs->currentsector.sector[57] = '1';
+ fs->currentsector.sector[58] = '6';
+ fs->currentsector.sector[59] = ' ';
+ fs->currentsector.sector[60] = ' ';
+ fs->currentsector.sector[61] = ' ';
+
+ // Signature
+ fs->currentsector.sector[510] = 0x55;
+ fs->currentsector.sector[511] = 0xAA;
+ }
+ // FAT32 BS Details
+ else
+ {
+ // Count of sectors used by the FAT table (FAT16 only)
+ fs->currentsector.sector[22] = 0;
+ fs->currentsector.sector[23] = 0;
+
+ // Sectors per track (default)
+ fs->currentsector.sector[24] = 0x3F;
+ fs->currentsector.sector[25] = 0x00;
+
+ // Heads (default)
+ fs->currentsector.sector[26] = 0xFF;
+ fs->currentsector.sector[27] = 0x00;
+
+ // Hidden sectors
+ fs->currentsector.sector[28] = 0x00;
+ fs->currentsector.sector[29] = 0x00;
+ fs->currentsector.sector[30] = 0x00;
+ fs->currentsector.sector[31] = 0x00;
+
+ // Total sectors for this volume
+ fs->currentsector.sector[32] = (uint8)((vol_sectors>>0)&0xFF);
+ fs->currentsector.sector[33] = (uint8)((vol_sectors>>8)&0xFF);
+ fs->currentsector.sector[34] = (uint8)((vol_sectors>>16)&0xFF);
+ fs->currentsector.sector[35] = (uint8)((vol_sectors>>24)&0xFF);
+
+ total_clusters = (vol_sectors / fs->sectors_per_cluster) + 1;
+ fs->fat_sectors = (total_clusters/(FAT_SECTOR_SIZE/4)) + 1;
+
+ // BPB_FATSz32
+ fs->currentsector.sector[36] = (uint8)((fs->fat_sectors>>0)&0xFF);
+ fs->currentsector.sector[37] = (uint8)((fs->fat_sectors>>8)&0xFF);
+ fs->currentsector.sector[38] = (uint8)((fs->fat_sectors>>16)&0xFF);
+ fs->currentsector.sector[39] = (uint8)((fs->fat_sectors>>24)&0xFF);
+
+ // BPB_ExtFlags
+ fs->currentsector.sector[40] = 0;
+ fs->currentsector.sector[41] = 0;
+
+ // BPB_FSVer
+ fs->currentsector.sector[42] = 0;
+ fs->currentsector.sector[43] = 0;
+
+ // BPB_RootClus
+ fs->currentsector.sector[44] = (uint8)((fs->rootdir_first_cluster>>0)&0xFF);
+ fs->currentsector.sector[45] = (uint8)((fs->rootdir_first_cluster>>8)&0xFF);
+ fs->currentsector.sector[46] = (uint8)((fs->rootdir_first_cluster>>16)&0xFF);
+ fs->currentsector.sector[47] = (uint8)((fs->rootdir_first_cluster>>24)&0xFF);
+
+ // BPB_FSInfo
+ fs->currentsector.sector[48] = (uint8)((fs->fs_info_sector>>0)&0xFF);
+ fs->currentsector.sector[49] = (uint8)((fs->fs_info_sector>>8)&0xFF);
+
+ // BPB_BkBootSec
+ fs->currentsector.sector[50] = 6;
+ fs->currentsector.sector[51] = 0;
+
+ // Drive number
+ fs->currentsector.sector[64] = 0x00;
+
+ // Boot signature
+ fs->currentsector.sector[66] = 0x29;
+
+ // Volume ID
+ fs->currentsector.sector[67] = 0x12;
+ fs->currentsector.sector[68] = 0x34;
+ fs->currentsector.sector[69] = 0x56;
+ fs->currentsector.sector[70] = 0x78;
+
+ // Volume name
+ for (i=0;i<11;i++)
+ {
+ if (i < (int)strlen(name))
+ fs->currentsector.sector[i+71] = name[i];
+ else
+ fs->currentsector.sector[i+71] = ' ';
+ }
+
+ // File sys type
+ fs->currentsector.sector[82] = 'F';
+ fs->currentsector.sector[83] = 'A';
+ fs->currentsector.sector[84] = 'T';
+ fs->currentsector.sector[85] = '3';
+ fs->currentsector.sector[86] = '2';
+ fs->currentsector.sector[87] = ' ';
+ fs->currentsector.sector[88] = ' ';
+ fs->currentsector.sector[89] = ' ';
+
+ // Signature
+ fs->currentsector.sector[510] = 0x55;
+ fs->currentsector.sector[511] = 0xAA;
+ }
+
+ if (fs->disk_io.write_media(boot_sector_lba, fs->currentsector.sector, 1))
+ return 1;
+ else
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_create_fsinfo_sector: Create the FSInfo sector (FAT32)
+//-----------------------------------------------------------------------------
+static int fatfs_create_fsinfo_sector(struct fatfs *fs, uint32 sector_lba)
+{
+ // Zero sector initially
+ memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
+
+ // FSI_LeadSig
+ fs->currentsector.sector[0] = 0x52;
+ fs->currentsector.sector[1] = 0x52;
+ fs->currentsector.sector[2] = 0x61;
+ fs->currentsector.sector[3] = 0x41;
+
+ // FSI_StrucSig
+ fs->currentsector.sector[484] = 0x72;
+ fs->currentsector.sector[485] = 0x72;
+ fs->currentsector.sector[486] = 0x41;
+ fs->currentsector.sector[487] = 0x61;
+
+ // FSI_Free_Count
+ fs->currentsector.sector[488] = 0xFF;
+ fs->currentsector.sector[489] = 0xFF;
+ fs->currentsector.sector[490] = 0xFF;
+ fs->currentsector.sector[491] = 0xFF;
+
+ // FSI_Nxt_Free
+ fs->currentsector.sector[492] = 0xFF;
+ fs->currentsector.sector[493] = 0xFF;
+ fs->currentsector.sector[494] = 0xFF;
+ fs->currentsector.sector[495] = 0xFF;
+
+ // Signature
+ fs->currentsector.sector[510] = 0x55;
+ fs->currentsector.sector[511] = 0xAA;
+
+ if (fs->disk_io.write_media(sector_lba, fs->currentsector.sector, 1))
+ return 1;
+ else
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_erase_fat: Erase FAT table using fs details in fs struct
+//-----------------------------------------------------------------------------
+static int fatfs_erase_fat(struct fatfs *fs, int is_fat32)
+{
+ uint32 i;
+
+ // Zero sector initially
+ memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
+
+ // Initialise default allocate / reserved clusters
+ if (!is_fat32)
+ {
+ SET_16BIT_WORD(fs->currentsector.sector, 0, 0xFFF8);
+ SET_16BIT_WORD(fs->currentsector.sector, 2, 0xFFFF);
+ }
+ else
+ {
+ SET_32BIT_WORD(fs->currentsector.sector, 0, 0x0FFFFFF8);
+ SET_32BIT_WORD(fs->currentsector.sector, 4, 0xFFFFFFFF);
+ SET_32BIT_WORD(fs->currentsector.sector, 8, 0x0FFFFFFF);
+ }
+
+ if (!fs->disk_io.write_media(fs->fat_begin_lba + 0, fs->currentsector.sector, 1))
+ return 0;
+
+ // Zero remaining FAT sectors
+ memset(fs->currentsector.sector, 0, FAT_SECTOR_SIZE);
+ for (i=1;i<fs->fat_sectors*fs->num_of_fats;i++)
+ if (!fs->disk_io.write_media(fs->fat_begin_lba + i, fs->currentsector.sector, 1))
+ return 0;
+
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format_fat16: Format a FAT16 partition
+//-----------------------------------------------------------------------------
+int fatfs_format_fat16(struct fatfs *fs, uint32 volume_sectors, const char *name)
+{
+ fs->currentsector.address = FAT32_INVALID_CLUSTER;
+ fs->currentsector.dirty = 0;
+
+ fs->next_free_cluster = 0; // Invalid
+
+ fatfs_fat_init(fs);
+
+ // Make sure we have read + write functions
+ if (!fs->disk_io.read_media || !fs->disk_io.write_media)
+ return FAT_INIT_MEDIA_ACCESS_ERROR;
+
+ // Volume is FAT16
+ fs->fat_type = FAT_TYPE_16;
+
+ // Not valid for FAT16
+ fs->fs_info_sector = 0;
+ fs->rootdir_first_cluster = 0;
+
+ // Sector 0: Boot sector
+ // NOTE: We don't need an MBR, it is a waste of a good sector!
+ fs->lba_begin = 0;
+ if (!fatfs_create_boot_sector(fs, fs->lba_begin, volume_sectors, name, 0))
+ return 0;
+
+ // For FAT16 (which this may be), rootdir_first_cluster is actuall rootdir_first_sector
+ fs->rootdir_first_sector = fs->reserved_sectors + (fs->num_of_fats * fs->fat_sectors);
+ fs->rootdir_sectors = ((fs->root_entry_count * 32) + (FAT_SECTOR_SIZE - 1)) / FAT_SECTOR_SIZE;
+
+ // First FAT LBA address
+ fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
+
+ // The address of the first data cluster on this volume
+ fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
+
+ // Initialise FAT sectors
+ if (!fatfs_erase_fat(fs, 0))
+ return 0;
+
+ // Erase Root directory
+ if (!fatfs_erase_sectors(fs, fs->lba_begin + fs->rootdir_first_sector, fs->rootdir_sectors))
+ return 0;
+
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format_fat32: Format a FAT32 partition
+//-----------------------------------------------------------------------------
+int fatfs_format_fat32(struct fatfs *fs, uint32 volume_sectors, const char *name)
+{
+ fs->currentsector.address = FAT32_INVALID_CLUSTER;
+ fs->currentsector.dirty = 0;
+
+ fs->next_free_cluster = 0; // Invalid
+
+ fatfs_fat_init(fs);
+
+ // Make sure we have read + write functions
+ if (!fs->disk_io.read_media || !fs->disk_io.write_media)
+ return FAT_INIT_MEDIA_ACCESS_ERROR;
+
+ // Volume is FAT32
+ fs->fat_type = FAT_TYPE_32;
+
+ // Basic defaults for normal FAT32 partitions
+ fs->fs_info_sector = 1;
+ fs->rootdir_first_cluster = 2;
+
+ // Sector 0: Boot sector
+ // NOTE: We don't need an MBR, it is a waste of a good sector!
+ fs->lba_begin = 0;
+ if (!fatfs_create_boot_sector(fs, fs->lba_begin, volume_sectors, name, 1))
+ return 0;
+
+ // First FAT LBA address
+ fs->fat_begin_lba = fs->lba_begin + fs->reserved_sectors;
+
+ // The address of the first data cluster on this volume
+ fs->cluster_begin_lba = fs->fat_begin_lba + (fs->num_of_fats * fs->fat_sectors);
+
+ // Initialise FSInfo sector
+ if (!fatfs_create_fsinfo_sector(fs, fs->fs_info_sector))
+ return 0;
+
+ // Initialise FAT sectors
+ if (!fatfs_erase_fat(fs, 1))
+ return 0;
+
+ // Erase Root directory
+ if (!fatfs_erase_sectors(fs, fatfs_lba_of_cluster(fs, fs->rootdir_first_cluster), fs->sectors_per_cluster))
+ return 0;
+
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_format: Format a partition with either FAT16 or FAT32 based on size
+//-----------------------------------------------------------------------------
+int fatfs_format(struct fatfs *fs, uint32 volume_sectors, const char *name)
+{
+ // 2GB - 32K limit for safe behaviour for FAT16
+ if (volume_sectors <= 4194304)
+ return fatfs_format_fat16(fs, volume_sectors, name);
+ else
+ return fatfs_format_fat32(fs, volume_sectors, name);
+}
+#endif /*FATFS_INC_FORMAT_SUPPORT*/
--- /dev/null
+#ifndef __FAT_FORMAT_H__
+#define __FAT_FORMAT_H__
+
+#include "fat_defs.h"
+#include "fat_opts.h"
+#include "fat_access.h"
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+int fatfs_format(struct fatfs *fs, uint32 volume_sectors, const char *name);
+int fatfs_format_fat16(struct fatfs *fs, uint32 volume_sectors, const char *name);
+int fatfs_format_fat32(struct fatfs *fs, uint32 volume_sectors, const char *name);
+
+#endif
--- /dev/null
+#ifndef __FAT_LIST_H__
+#define __FAT_LIST_H__
+
+#ifndef FAT_ASSERT
+ #define FAT_ASSERT(x)
+#endif
+
+#ifndef FAT_INLINE
+ #define FAT_INLINE
+#endif
+
+//-----------------------------------------------------------------
+// Types
+//-----------------------------------------------------------------
+struct fat_list;
+
+struct fat_node
+{
+ struct fat_node *previous;
+ struct fat_node *next;
+};
+
+struct fat_list
+{
+ struct fat_node *head;
+ struct fat_node *tail;
+};
+
+//-----------------------------------------------------------------
+// Macros
+//-----------------------------------------------------------------
+#define fat_list_entry(p, t, m) p ? ((t *)((char *)(p)-(char*)(&((t *)0)->m))) : 0
+#define fat_list_next(l, p) (p)->next
+#define fat_list_prev(l, p) (p)->previous
+#define fat_list_first(l) (l)->head
+#define fat_list_last(l) (l)->tail
+#define fat_list_for_each(l, p) for ((p) = (l)->head; (p); (p) = (p)->next)
+
+//-----------------------------------------------------------------
+// Inline Functions
+//-----------------------------------------------------------------
+
+//-----------------------------------------------------------------
+// fat_list_init:
+//-----------------------------------------------------------------
+static FAT_INLINE void fat_list_init(struct fat_list *list)
+{
+ FAT_ASSERT(list);
+
+ list->head = list->tail = 0;
+}
+//-----------------------------------------------------------------
+// fat_list_remove:
+//-----------------------------------------------------------------
+static FAT_INLINE void fat_list_remove(struct fat_list *list, struct fat_node *node)
+{
+ FAT_ASSERT(list);
+ FAT_ASSERT(node);
+
+ if(!node->previous)
+ list->head = node->next;
+ else
+ node->previous->next = node->next;
+
+ if(!node->next)
+ list->tail = node->previous;
+ else
+ node->next->previous = node->previous;
+}
+//-----------------------------------------------------------------
+// fat_list_insert_after:
+//-----------------------------------------------------------------
+static FAT_INLINE void fat_list_insert_after(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
+{
+ FAT_ASSERT(list);
+ FAT_ASSERT(node);
+ FAT_ASSERT(new_node);
+
+ new_node->previous = node;
+ new_node->next = node->next;
+ if (!node->next)
+ list->tail = new_node;
+ else
+ node->next->previous = new_node;
+ node->next = new_node;
+}
+//-----------------------------------------------------------------
+// fat_list_insert_before:
+//-----------------------------------------------------------------
+static FAT_INLINE void fat_list_insert_before(struct fat_list *list, struct fat_node *node, struct fat_node *new_node)
+{
+ FAT_ASSERT(list);
+ FAT_ASSERT(node);
+ FAT_ASSERT(new_node);
+
+ new_node->previous = node->previous;
+ new_node->next = node;
+ if (!node->previous)
+ list->head = new_node;
+ else
+ node->previous->next = new_node;
+ node->previous = new_node;
+}
+//-----------------------------------------------------------------
+// fat_list_insert_first:
+//-----------------------------------------------------------------
+static FAT_INLINE void fat_list_insert_first(struct fat_list *list, struct fat_node *node)
+{
+ FAT_ASSERT(list);
+ FAT_ASSERT(node);
+
+ if (!list->head)
+ {
+ list->head = node;
+ list->tail = node;
+ node->previous = 0;
+ node->next = 0;
+ }
+ else
+ fat_list_insert_before(list, list->head, node);
+}
+//-----------------------------------------------------------------
+// fat_list_insert_last:
+//-----------------------------------------------------------------
+static FAT_INLINE void fat_list_insert_last(struct fat_list *list, struct fat_node *node)
+{
+ FAT_ASSERT(list);
+ FAT_ASSERT(node);
+
+ if (!list->tail)
+ fat_list_insert_first(list, node);
+ else
+ fat_list_insert_after(list, list->tail, node);
+}
+//-----------------------------------------------------------------
+// fat_list_is_empty:
+//-----------------------------------------------------------------
+static FAT_INLINE int fat_list_is_empty(struct fat_list *list)
+{
+ FAT_ASSERT(list);
+
+ return !list->head;
+}
+//-----------------------------------------------------------------
+// fat_list_pop_head:
+//-----------------------------------------------------------------
+static FAT_INLINE struct fat_node * fat_list_pop_head(struct fat_list *list)
+{
+ struct fat_node * node;
+
+ FAT_ASSERT(list);
+
+ node = fat_list_first(list);
+ if (node)
+ fat_list_remove(list, node);
+
+ return node;
+}
+
+#endif
+
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+// FAT16/32 File IO Library\r
+// V2.6\r
+// Ultra-Embedded.com\r
+// Copyright 2003 - 2012\r
+//\r
+// Email: admin@ultra-embedded.com\r
+//\r
+// License: GPL\r
+// If you would like a version with a more permissive license for use in\r
+// closed source commercial applications please contact me for details.\r
+//-----------------------------------------------------------------------------\r
+//\r
+// This file is part of FAT File IO Library.\r
+//\r
+// FAT File IO Library is free software; you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation; either version 2 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// FAT File IO Library is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with FAT File IO Library; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+#include <stdlib.h>
+#include <string.h>
+#include "fat_misc.h"
+
+//-----------------------------------------------------------------------------
+// fatfs_lfn_cache_init: Clear long file name cache
+//-----------------------------------------------------------------------------
+void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable)
+{
+ int i = 0;
+
+ lfn->no_of_strings = 0;
+
+#if FATFS_INC_LFN_SUPPORT
+
+ // Zero out buffer also
+ if (wipeTable)
+ for (i=0;i<MAX_LONGFILENAME_ENTRIES;i++)
+ memset(lfn->String[i], 0x00, MAX_LFN_ENTRY_LENGTH);
+#endif
+}
+//-----------------------------------------------------------------------------
+// fatfs_lfn_cache_entry - Function extracts long file name text from sector
+// at a specific offset
+//-----------------------------------------------------------------------------
+#if FATFS_INC_LFN_SUPPORT
+void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer)
+{
+ uint8 LFNIndex, i;
+ LFNIndex = entryBuffer[0] & 0x1F;
+
+ // Limit file name to cache size!
+ if (LFNIndex > MAX_LONGFILENAME_ENTRIES)
+ return ;
+
+ // This is an error condition
+ if (LFNIndex == 0)
+ return ;
+
+ if (lfn->no_of_strings == 0)
+ lfn->no_of_strings = LFNIndex;
+
+ lfn->String[LFNIndex-1][0] = entryBuffer[1];
+ lfn->String[LFNIndex-1][1] = entryBuffer[3];
+ lfn->String[LFNIndex-1][2] = entryBuffer[5];
+ lfn->String[LFNIndex-1][3] = entryBuffer[7];
+ lfn->String[LFNIndex-1][4] = entryBuffer[9];
+ lfn->String[LFNIndex-1][5] = entryBuffer[0x0E];
+ lfn->String[LFNIndex-1][6] = entryBuffer[0x10];
+ lfn->String[LFNIndex-1][7] = entryBuffer[0x12];
+ lfn->String[LFNIndex-1][8] = entryBuffer[0x14];
+ lfn->String[LFNIndex-1][9] = entryBuffer[0x16];
+ lfn->String[LFNIndex-1][10] = entryBuffer[0x18];
+ lfn->String[LFNIndex-1][11] = entryBuffer[0x1C];
+ lfn->String[LFNIndex-1][12] = entryBuffer[0x1E];
+
+ for (i=0; i<MAX_LFN_ENTRY_LENGTH; i++)
+ if (lfn->String[LFNIndex-1][i]==0xFF)
+ lfn->String[LFNIndex-1][i] = 0x20; // Replace with spaces
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_lfn_cache_get: Get a reference to the long filename
+//-----------------------------------------------------------------------------
+#if FATFS_INC_LFN_SUPPORT
+char* fatfs_lfn_cache_get(struct lfn_cache *lfn)
+{
+ // Null terminate long filename
+ if (lfn->no_of_strings == MAX_LONGFILENAME_ENTRIES)
+ lfn->Null = '\0';
+ else if (lfn->no_of_strings)
+ lfn->String[lfn->no_of_strings][0] = '\0';
+ else
+ lfn->String[0][0] = '\0';
+
+ return (char*)&lfn->String[0][0];
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_entry_lfn_text: If LFN text entry found
+//-----------------------------------------------------------------------------
+#if FATFS_INC_LFN_SUPPORT
+int fatfs_entry_lfn_text(struct fat_dir_entry *entry)
+{
+ if ((entry->Attr & FILE_ATTR_LFN_TEXT) == FILE_ATTR_LFN_TEXT)
+ return 1;
+ else
+ return 0;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_entry_lfn_invalid: If SFN found not relating to LFN
+//-----------------------------------------------------------------------------
+#if FATFS_INC_LFN_SUPPORT
+int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry)
+{
+ if ( (entry->Name[0]==FILE_HEADER_BLANK) ||
+ (entry->Name[0]==FILE_HEADER_DELETED)||
+ (entry->Attr==FILE_ATTR_VOLUME_ID) ||
+ (entry->Attr & FILE_ATTR_SYSHID) )
+ return 1;
+ else
+ return 0;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_entry_lfn_exists: If LFN exists and correlation SFN found
+//-----------------------------------------------------------------------------
+#if FATFS_INC_LFN_SUPPORT
+int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry)
+{
+ if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) &&
+ (entry->Name[0]!=FILE_HEADER_BLANK) &&
+ (entry->Name[0]!=FILE_HEADER_DELETED) &&
+ (entry->Attr!=FILE_ATTR_VOLUME_ID) &&
+ (!(entry->Attr&FILE_ATTR_SYSHID)) &&
+ (lfn->no_of_strings) )
+ return 1;
+ else
+ return 0;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_entry_sfn_only: If SFN only exists
+//-----------------------------------------------------------------------------
+int fatfs_entry_sfn_only(struct fat_dir_entry *entry)
+{
+ if ( (entry->Attr!=FILE_ATTR_LFN_TEXT) &&
+ (entry->Name[0]!=FILE_HEADER_BLANK) &&
+ (entry->Name[0]!=FILE_HEADER_DELETED) &&
+ (entry->Attr!=FILE_ATTR_VOLUME_ID) &&
+ (!(entry->Attr&FILE_ATTR_SYSHID)) )
+ return 1;
+ else
+ return 0;
+}
+// TODO: FILE_ATTR_SYSHID ?!?!??!
+//-----------------------------------------------------------------------------
+// fatfs_entry_is_dir: Returns 1 if a directory
+//-----------------------------------------------------------------------------
+int fatfs_entry_is_dir(struct fat_dir_entry *entry)
+{
+ if (entry->Attr & FILE_TYPE_DIR)
+ return 1;
+ else
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_entry_is_file: Returns 1 is a file entry
+//-----------------------------------------------------------------------------
+int fatfs_entry_is_file(struct fat_dir_entry *entry)
+{
+ if (entry->Attr & FILE_TYPE_FILE)
+ return 1;
+ else
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_lfn_entries_required: Calculate number of 13 characters entries
+//-----------------------------------------------------------------------------
+#if FATFS_INC_LFN_SUPPORT
+int fatfs_lfn_entries_required(char *filename)
+{
+ int length = (int)strlen(filename);
+
+ if (length)
+ return (length + MAX_LFN_ENTRY_LENGTH - 1) / MAX_LFN_ENTRY_LENGTH;
+ else
+ return 0;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_filename_to_lfn:
+//-----------------------------------------------------------------------------
+#if FATFS_INC_LFN_SUPPORT
+void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk)
+{
+ int i;
+ int nameIndexes[MAX_LFN_ENTRY_LENGTH] = {1,3,5,7,9,0x0E,0x10,0x12,0x14,0x16,0x18,0x1C,0x1E};
+
+ // 13 characters entries
+ int length = (int)strlen(filename);
+ int entriesRequired = fatfs_lfn_entries_required(filename);
+
+ // Filename offset
+ int start = entry * MAX_LFN_ENTRY_LENGTH;
+
+ // Initialise to zeros
+ memset(buffer, 0x00, FAT_DIR_ENTRY_SIZE);
+
+ // LFN entry number
+ buffer[0] = (uint8)(((entriesRequired-1)==entry)?(0x40|(entry+1)):(entry+1));
+
+ // LFN flag
+ buffer[11] = 0x0F;
+
+ // Checksum of short filename
+ buffer[13] = sfnChk;
+
+ // Copy to buffer
+ for (i=0;i<MAX_LFN_ENTRY_LENGTH;i++)
+ {
+ if ( (start+i) < length )
+ buffer[nameIndexes[i]] = filename[start+i];
+ else if ( (start+i) == length )
+ buffer[nameIndexes[i]] = 0x00;
+ else
+ {
+ buffer[nameIndexes[i]] = 0xFF;
+ buffer[nameIndexes[i]+1] = 0xFF;
+ }
+ }
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_sfn_create_entry: Create the short filename directory entry
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir)
+{
+ int i;
+
+ // Copy short filename
+ for (i=0;i<FAT_SFN_SIZE_FULL;i++)
+ entry->Name[i] = shortfilename[i];
+
+ // Unless we have a RTC we might as well set these to 1980
+ entry->CrtTimeTenth = 0x00;
+ entry->CrtTime[1] = entry->CrtTime[0] = 0x00;
+ entry->CrtDate[1] = 0x00;
+ entry->CrtDate[0] = 0x20;
+ entry->LstAccDate[1] = 0x00;
+ entry->LstAccDate[0] = 0x20;
+ entry->WrtTime[1] = entry->WrtTime[0] = 0x00;
+ entry->WrtDate[1] = 0x00;
+ entry->WrtDate[0] = 0x20;
+
+ if (!dir)
+ entry->Attr = FILE_TYPE_FILE;
+ else
+ entry->Attr = FILE_TYPE_DIR;
+
+ entry->NTRes = 0x00;
+
+ entry->FstClusHI = FAT_HTONS((uint16)((startCluster>>16) & 0xFFFF));
+ entry->FstClusLO = FAT_HTONS((uint16)((startCluster>>0) & 0xFFFF));
+ entry->FileSize = FAT_HTONL(size);
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_lfn_create_sfn: Create a padded SFN
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fatfs_lfn_create_sfn(char *sfn_output, char *filename)
+{
+ int i;
+ int dotPos = -1;
+ char ext[3];
+ int pos;
+ int len = (int)strlen(filename);
+
+ // Invalid to start with .
+ if (filename[0]=='.')
+ return 0;
+
+ memset(sfn_output, ' ', FAT_SFN_SIZE_FULL);
+ memset(ext, ' ', 3);
+
+ // Find dot seperator
+ for (i = 0; i< len; i++)
+ {
+ if (filename[i]=='.')
+ dotPos = i;
+ }
+
+ // Extract extensions
+ if (dotPos!=-1)
+ {
+ // Copy first three chars of extension
+ for (i = (dotPos+1); i < (dotPos+1+3); i++)
+ if (i<len)
+ ext[i-(dotPos+1)] = filename[i];
+
+ // Shorten the length to the dot position
+ len = dotPos;
+ }
+
+ // Add filename part
+ pos = 0;
+ for (i=0;i<len;i++)
+ {
+ if ( (filename[i]!=' ') && (filename[i]!='.') )
+ {
+ if (filename[i] >= 'a' && filename[i] <= 'z')
+ sfn_output[pos++] = filename[i] - 'a' + 'A';
+ else
+ sfn_output[pos++] = filename[i];
+ }
+
+ // Fill upto 8 characters
+ if (pos==FAT_SFN_SIZE_PARTIAL)
+ break;
+ }
+
+ // Add extension part
+ for (i=FAT_SFN_SIZE_PARTIAL;i<FAT_SFN_SIZE_FULL;i++)
+ {
+ if (ext[i-FAT_SFN_SIZE_PARTIAL] >= 'a' && ext[i-FAT_SFN_SIZE_PARTIAL] <= 'z')
+ sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL] - 'a' + 'A';
+ else
+ sfn_output[i] = ext[i-FAT_SFN_SIZE_PARTIAL];
+ }
+
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_itoa:
+//-----------------------------------------------------------------------------
+static void fatfs_itoa(uint32 num, char *s)
+{
+ char* cp;
+ char outbuf[12];
+ const char digits[] = "0123456789ABCDEF";
+
+ // Build string backwards
+ cp = outbuf;
+ do
+ {
+ *cp++ = digits[(int)(num % 10)];
+ }
+ while ((num /= 10) > 0);
+
+ *cp-- = 0;
+
+ // Copy in forwards
+ while (cp >= outbuf)
+ *s++ = *cp--;
+
+ *s = 0;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_lfn_generate_tail:
+// sfn_input = Input short filename, spaced format & in upper case
+// sfn_output = Output short filename with tail
+//-----------------------------------------------------------------------------
+#if FATFS_INC_LFN_SUPPORT
+#if FATFS_INC_WRITE_SUPPORT
+int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum)
+{
+ int tail_chars;
+ char tail_str[12];
+
+ if (tailNum > 99999)
+ return 0;
+
+ // Convert to number
+ memset(tail_str, 0x00, sizeof(tail_str));
+ tail_str[0] = '~';
+ fatfs_itoa(tailNum, tail_str+1);
+
+ // Copy in base filename
+ memcpy(sfn_output, sfn_input, FAT_SFN_SIZE_FULL);
+
+ // Overwrite with tail
+ tail_chars = (int)strlen(tail_str);
+ memcpy(sfn_output+(FAT_SFN_SIZE_PARTIAL-tail_chars), tail_str, tail_chars);
+
+ return 1;
+}
+#endif
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_convert_from_fat_time: Convert FAT time to h/m/s
+//-----------------------------------------------------------------------------
+#if FATFS_INC_TIME_DATE_SUPPORT
+void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds)
+{
+ *hours = (fat_time >> FAT_TIME_HOURS_SHIFT) & FAT_TIME_HOURS_MASK;
+ *minutes = (fat_time >> FAT_TIME_MINUTES_SHIFT) & FAT_TIME_MINUTES_MASK;
+ *seconds = (fat_time >> FAT_TIME_SECONDS_SHIFT) & FAT_TIME_SECONDS_MASK;
+ *seconds = *seconds * FAT_TIME_SECONDS_SCALE;
+}
+//-----------------------------------------------------------------------------
+// fatfs_convert_from_fat_date: Convert FAT date to d/m/y
+//-----------------------------------------------------------------------------
+void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year)
+{
+ *day = (fat_date >> FAT_DATE_DAY_SHIFT) & FAT_DATE_DAY_MASK;
+ *month = (fat_date >> FAT_DATE_MONTH_SHIFT) & FAT_DATE_MONTH_MASK;
+ *year = (fat_date >> FAT_DATE_YEAR_SHIFT) & FAT_DATE_YEAR_MASK;
+ *year = *year + FAT_DATE_YEAR_OFFSET;
+}
+//-----------------------------------------------------------------------------
+// fatfs_convert_to_fat_time: Convert h/m/s to FAT time
+//-----------------------------------------------------------------------------
+uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds)
+{
+ uint16 fat_time = 0;
+
+ // Most FAT times are to a resolution of 2 seconds
+ seconds /= FAT_TIME_SECONDS_SCALE;
+
+ fat_time = (hours & FAT_TIME_HOURS_MASK) << FAT_TIME_HOURS_SHIFT;
+ fat_time|= (minutes & FAT_TIME_MINUTES_MASK) << FAT_TIME_MINUTES_SHIFT;
+ fat_time|= (seconds & FAT_TIME_SECONDS_MASK) << FAT_TIME_SECONDS_SHIFT;
+
+ return fat_time;
+}
+//-----------------------------------------------------------------------------
+// fatfs_convert_to_fat_date: Convert d/m/y to FAT date
+//-----------------------------------------------------------------------------
+uint16 fatfs_convert_to_fat_date(int day, int month, int year)
+{
+ uint16 fat_date = 0;
+
+ // FAT dates are relative to 1980
+ if (year >= FAT_DATE_YEAR_OFFSET)
+ year -= FAT_DATE_YEAR_OFFSET;
+
+ fat_date = (day & FAT_DATE_DAY_MASK) << FAT_DATE_DAY_SHIFT;
+ fat_date|= (month & FAT_DATE_MONTH_MASK) << FAT_DATE_MONTH_SHIFT;
+ fat_date|= (year & FAT_DATE_YEAR_MASK) << FAT_DATE_YEAR_SHIFT;
+
+ return fat_date;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_print_sector:
+//-----------------------------------------------------------------------------
+#ifdef FATFS_DEBUG
+void fatfs_print_sector(uint32 sector, uint8 *data)
+{
+ int i;
+ int j;
+
+ FAT_PRINTF(("Sector %d:\n", sector));
+
+ for (i=0;i<FAT_SECTOR_SIZE;i++)
+ {
+ if (!((i) % 16))
+ {
+ FAT_PRINTF((" %04d: ", i));
+ }
+
+ FAT_PRINTF(("%02x", data[i]));
+ if (!((i+1) % 4))
+ {
+ FAT_PRINTF((" "));
+ }
+
+ if (!((i+1) % 16))
+ {
+ FAT_PRINTF((" "));
+ for (j=0;j<16;j++)
+ {
+ char ch = data[i-15+j];
+
+ // Is printable?
+ if (ch > 31 && ch < 127)
+ {
+ FAT_PRINTF(("%c", ch));
+ }
+ else
+ {
+ FAT_PRINTF(("."));
+ }
+ }
+
+ FAT_PRINTF(("\n"));
+ }
+ }
+}
+#endif
--- /dev/null
+#ifndef __FAT_MISC_H__
+#define __FAT_MISC_H__
+
+#include "fat_defs.h"
+#include "fat_opts.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------------------
+#define MAX_LONGFILENAME_ENTRIES 20
+#define MAX_LFN_ENTRY_LENGTH 13
+
+//-----------------------------------------------------------------------------
+// Macros
+//-----------------------------------------------------------------------------
+#define GET_32BIT_WORD(buffer, location) ( ((uint32)buffer[location+3]<<24) + ((uint32)buffer[location+2]<<16) + ((uint32)buffer[location+1]<<8) + (uint32)buffer[location+0] )
+#define GET_16BIT_WORD(buffer, location) ( ((uint16)buffer[location+1]<<8) + (uint16)buffer[location+0] )
+
+#define SET_32BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
+ buffer[location+1] = (uint8)((value>>8)&0xFF); \
+ buffer[location+2] = (uint8)((value>>16)&0xFF); \
+ buffer[location+3] = (uint8)((value>>24)&0xFF); }
+
+#define SET_16BIT_WORD(buffer, location, value) { buffer[location+0] = (uint8)((value)&0xFF); \
+ buffer[location+1] = (uint8)((value>>8)&0xFF); }
+
+//-----------------------------------------------------------------------------
+// Structures
+//-----------------------------------------------------------------------------
+struct lfn_cache
+{
+#if FATFS_INC_LFN_SUPPORT
+ // Long File Name Structure (max 260 LFN length)
+ uint8 String[MAX_LONGFILENAME_ENTRIES][MAX_LFN_ENTRY_LENGTH];
+ uint8 Null;
+#endif
+ uint8 no_of_strings;
+};
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+void fatfs_lfn_cache_init(struct lfn_cache *lfn, int wipeTable);
+void fatfs_lfn_cache_entry(struct lfn_cache *lfn, uint8 *entryBuffer);
+char* fatfs_lfn_cache_get(struct lfn_cache *lfn);
+int fatfs_entry_lfn_text(struct fat_dir_entry *entry);
+int fatfs_entry_lfn_invalid(struct fat_dir_entry *entry);
+int fatfs_entry_lfn_exists(struct lfn_cache *lfn, struct fat_dir_entry *entry);
+int fatfs_entry_sfn_only(struct fat_dir_entry *entry);
+int fatfs_entry_is_dir(struct fat_dir_entry *entry);
+int fatfs_entry_is_file(struct fat_dir_entry *entry);
+int fatfs_lfn_entries_required(char *filename);
+void fatfs_filename_to_lfn(char *filename, uint8 *buffer, int entry, uint8 sfnChk);
+void fatfs_sfn_create_entry(char *shortfilename, uint32 size, uint32 startCluster, struct fat_dir_entry *entry, int dir);
+int fatfs_lfn_create_sfn(char *sfn_output, char *filename);
+int fatfs_lfn_generate_tail(char *sfn_output, char *sfn_input, uint32 tailNum);
+void fatfs_convert_from_fat_time(uint16 fat_time, int *hours, int *minutes, int *seconds);
+void fatfs_convert_from_fat_date(uint16 fat_date, int *day, int *month, int *year);
+uint16 fatfs_convert_to_fat_time(int hours, int minutes, int seconds);
+uint16 fatfs_convert_to_fat_date(int day, int month, int year);
+void fatfs_print_sector(uint32 sector, uint8 *data);
+
+#endif
--- /dev/null
+#ifndef __FAT_OPTS_H__
+#define __FAT_OPTS_H__
+
+#ifdef FATFS_USE_CUSTOM_OPTS_FILE
+ #include "fat_custom.h"
+#endif
+
+//-------------------------------------------------------------
+// Configuration
+//-------------------------------------------------------------
+
+// Is the processor little endian (1) or big endian (0)
+#ifndef FATFS_IS_LITTLE_ENDIAN
+ #define FATFS_IS_LITTLE_ENDIAN 1
+#endif
+
+// Max filename Length
+#ifndef FATFS_MAX_LONG_FILENAME
+ #define FATFS_MAX_LONG_FILENAME 260
+#endif
+
+// Max open files (reduce to lower memory requirements)
+#ifndef FATFS_MAX_OPEN_FILES
+ #define FATFS_MAX_OPEN_FILES 2
+#endif
+
+// Number of sectors per FAT_BUFFER (min 1)
+#ifndef FAT_BUFFER_SECTORS
+ #define FAT_BUFFER_SECTORS 1
+#endif
+
+// Max FAT sectors to buffer (min 1)
+// (mem used is FAT_BUFFERS * FAT_BUFFER_SECTORS * FAT_SECTOR_SIZE)
+#ifndef FAT_BUFFERS
+ #define FAT_BUFFERS 1
+#endif
+
+// Size of cluster chain cache (can be undefined)
+// Mem used = FAT_CLUSTER_CACHE_ENTRIES * 4 * 2
+// Improves access speed considerably
+//#define FAT_CLUSTER_CACHE_ENTRIES 128
+
+// Include support for writing files (1 / 0)?
+#ifndef FATFS_INC_WRITE_SUPPORT
+ #define FATFS_INC_WRITE_SUPPORT 1
+#endif
+
+// Support long filenames (1 / 0)?
+// (if not (0) only 8.3 format is supported)
+#ifndef FATFS_INC_LFN_SUPPORT
+ #define FATFS_INC_LFN_SUPPORT 1
+#endif
+
+// Support directory listing (1 / 0)?
+#ifndef FATFS_DIR_LIST_SUPPORT
+ #define FATFS_DIR_LIST_SUPPORT 1
+#endif
+
+// Support time/date (1 / 0)?
+#ifndef FATFS_INC_TIME_DATE_SUPPORT
+ #define FATFS_INC_TIME_DATE_SUPPORT 0
+#endif
+
+// Include support for formatting disks (1 / 0)?
+#ifndef FATFS_INC_FORMAT_SUPPORT
+ #define FATFS_INC_FORMAT_SUPPORT 0
+#endif
+
+// Sector size used
+#define FAT_SECTOR_SIZE 512
+
+// Printf output (directory listing / debug)
+#ifndef FAT_PRINTF
+ void ventoy_syslog_printf(const char *Fmt, ...);
+ #define FAT_PRINTF(a) ventoy_syslog_printf a
+#endif
+
+// Time/Date support requires time.h
+#if FATFS_INC_TIME_DATE_SUPPORT
+ #include <time.h>
+#endif
+
+#endif
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+// FAT16/32 File IO Library\r
+// V2.6\r
+// Ultra-Embedded.com\r
+// Copyright 2003 - 2012\r
+//\r
+// Email: admin@ultra-embedded.com\r
+//\r
+// License: GPL\r
+// If you would like a version with a more permissive license for use in\r
+// closed source commercial applications please contact me for details.\r
+//-----------------------------------------------------------------------------\r
+//\r
+// This file is part of FAT File IO Library.\r
+//\r
+// FAT File IO Library is free software; you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation; either version 2 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// FAT File IO Library is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with FAT File IO Library; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+#include <string.h>
+#include <assert.h>
+#include "fat_string.h"
+
+//-----------------------------------------------------------------------------
+// fatfs_total_path_levels: Take a filename and path and count the sub levels
+// of folders. E.g. C:\folder\file.zip = 1 level
+// Acceptable input formats are:
+// c:\folder\file.zip
+// /dev/etc/samba.conf
+// Returns: -1 = Error, 0 or more = Ok
+//-----------------------------------------------------------------------------
+int fatfs_total_path_levels(char *path)
+{
+ int levels = 0;
+ char expectedchar;
+
+ if (!path)
+ return -1;
+
+ // Acceptable formats:
+ // c:\folder\file.zip
+ // /dev/etc/samba.conf
+ if (*path == '/')
+ {
+ expectedchar = '/';
+ path++;
+ }
+ else if (path[1] == ':' || path[2] == '\\')
+ {
+ expectedchar = '\\';
+ path += 3;
+ }
+ else
+ return -1;
+
+ // Count levels in path string
+ while (*path)
+ {
+ // Fast forward through actual subdir text to next slash
+ for (; *path; )
+ {
+ // If slash detected escape from for loop
+ if (*path == expectedchar) { path++; break; }
+ path++;
+ }
+
+ // Increase number of subdirs founds
+ levels++;
+ }
+
+ // Subtract the file itself
+ return levels-1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_get_substring: Get a substring from 'path' which contains the folder
+// (or file) at the specified level.
+// E.g. C:\folder\file.zip : Level 0 = C:\folder, Level 1 = file.zip
+// Returns: -1 = Error, 0 = Ok
+//-----------------------------------------------------------------------------
+int fatfs_get_substring(char *path, int levelreq, char *output, int max_len)
+{
+ int i;
+ int pathlen=0;
+ int levels=0;
+ int copypnt=0;
+ char expectedchar;
+
+ if (!path || max_len <= 0)
+ return -1;
+
+ // Acceptable formats:
+ // c:\folder\file.zip
+ // /dev/etc/samba.conf
+ if (*path == '/')
+ {
+ expectedchar = '/';
+ path++;
+ }
+ else if (path[1] == ':' || path[2] == '\\')
+ {
+ expectedchar = '\\';
+ path += 3;
+ }
+ else
+ return -1;
+
+ // Get string length of path
+ pathlen = (int)strlen (path);
+
+ // Loop through the number of times as characters in 'path'
+ for (i = 0; i<pathlen; i++)
+ {
+ // If a '\' is found then increase level
+ if (*path == expectedchar) levels++;
+
+ // If correct level and the character is not a '\' or '/' then copy text to 'output'
+ if ( (levels == levelreq) && (*path != expectedchar) && (copypnt < (max_len-1)))
+ output[copypnt++] = *path;
+
+ // Increment through path string
+ path++;
+ }
+
+ // Null Terminate
+ output[copypnt] = '\0';
+
+ // If a string was copied return 0 else return 1
+ if (output[0] != '\0')
+ return 0; // OK
+ else
+ return -1; // Error
+}
+//-----------------------------------------------------------------------------
+// fatfs_split_path: Full path contains the passed in string.
+// Returned is the path string and file Name string
+// E.g. C:\folder\file.zip -> path = C:\folder filename = file.zip
+// E.g. C:\file.zip -> path = [blank] filename = file.zip
+//-----------------------------------------------------------------------------
+int fatfs_split_path(char *full_path, char *path, int max_path, char *filename, int max_filename)
+{
+ int strindex;
+
+ // Count the levels to the filepath
+ int levels = fatfs_total_path_levels(full_path);
+ if (levels == -1)
+ return -1;
+
+ // Get filename part of string
+ if (fatfs_get_substring(full_path, levels, filename, max_filename) != 0)
+ return -1;
+
+ // If root file
+ if (levels == 0)
+ path[0] = '\0';
+ else
+ {
+ strindex = (int)strlen(full_path) - (int)strlen(filename);
+ if (strindex > max_path)
+ strindex = max_path;
+
+ memcpy(path, full_path, strindex);
+ path[strindex-1] = '\0';
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// FileString_StrCmpNoCase: Compare two strings case with case sensitivity
+//-----------------------------------------------------------------------------
+static int FileString_StrCmpNoCase(char *s1, char *s2, int n)
+{
+ int diff;
+ char a,b;
+
+ while (n--)
+ {
+ a = *s1;
+ b = *s2;
+
+ // Make lower case if uppercase
+ if ((a>='A') && (a<='Z'))
+ a+= 32;
+ if ((b>='A') && (b<='Z'))
+ b+= 32;
+
+ diff = a - b;
+
+ // If different
+ if (diff)
+ return diff;
+
+ // If run out of strings
+ if ( (*s1 == 0) || (*s2 == 0) )
+ break;
+
+ s1++;
+ s2++;
+ }
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// FileString_GetExtension: Get index to extension within filename
+// Returns -1 if not found or index otherwise
+//-----------------------------------------------------------------------------
+static int FileString_GetExtension(char *str)
+{
+ int dotPos = -1;
+ char *strSrc = str;
+
+ // Find last '.' in string (if at all)
+ while (*strSrc)
+ {
+ if (*strSrc=='.')
+ dotPos = (int)(strSrc-str);
+
+ strSrc++;
+ }
+
+ return dotPos;
+}
+//-----------------------------------------------------------------------------
+// FileString_TrimLength: Get length of string excluding trailing spaces
+// Returns -1 if not found or index otherwise
+//-----------------------------------------------------------------------------
+static int FileString_TrimLength(char *str, int strLen)
+{
+ int length = strLen;
+ char *strSrc = str+strLen-1;
+
+ // Find last non white space
+ while (strLen != 0)
+ {
+ if (*strSrc == ' ')
+ length = (int)(strSrc - str);
+ else
+ break;
+
+ strSrc--;
+ strLen--;
+ }
+
+ return length;
+}
+//-----------------------------------------------------------------------------
+// fatfs_compare_names: Compare two filenames (without copying or changing origonals)
+// Returns 1 if match, 0 if not
+//-----------------------------------------------------------------------------
+int fatfs_compare_names(char* strA, char* strB)
+{
+ char *ext1 = NULL;
+ char *ext2 = NULL;
+ int ext1Pos, ext2Pos;
+ int file1Len, file2Len;
+
+ // Get both files extension
+ ext1Pos = FileString_GetExtension(strA);
+ ext2Pos = FileString_GetExtension(strB);
+
+ // NOTE: Extension position can be different for matching
+ // filename if trailing space are present before it!
+ // Check that if one has an extension, so does the other
+ if ((ext1Pos==-1) && (ext2Pos!=-1))
+ return 0;
+ if ((ext2Pos==-1) && (ext1Pos!=-1))
+ return 0;
+
+ // If they both have extensions, compare them
+ if (ext1Pos!=-1)
+ {
+ // Set pointer to start of extension
+ ext1 = strA+ext1Pos+1;
+ ext2 = strB+ext2Pos+1;
+
+ // Verify that the file extension lengths match!
+ if (strlen(ext1) != strlen(ext2))
+ return 0;
+
+ // If they dont match
+ if (FileString_StrCmpNoCase(ext1, ext2, (int)strlen(ext1))!=0)
+ return 0;
+
+ // Filelength is upto extensions
+ file1Len = ext1Pos;
+ file2Len = ext2Pos;
+ }
+ // No extensions
+ else
+ {
+ // Filelength is actual filelength
+ file1Len = (int)strlen(strA);
+ file2Len = (int)strlen(strB);
+ }
+
+ // Find length without trailing spaces (before ext)
+ file1Len = FileString_TrimLength(strA, file1Len);
+ file2Len = FileString_TrimLength(strB, file2Len);
+
+ // Check the file lengths match
+ if (file1Len!=file2Len)
+ return 0;
+
+ // Compare main part of filenames
+ if (FileString_StrCmpNoCase(strA, strB, file1Len)!=0)
+ return 0;
+ else
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_string_ends_with_slash: Does the string end with a slash (\ or /)
+//-----------------------------------------------------------------------------
+int fatfs_string_ends_with_slash(char *path)
+{
+ if (path)
+ {
+ while (*path)
+ {
+ // Last character?
+ if (!(*(path+1)))
+ {
+ if (*path == '\\' || *path == '/')
+ return 1;
+ }
+
+ path++;
+ }
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_get_sfn_display_name: Get display name for SFN entry
+//-----------------------------------------------------------------------------
+int fatfs_get_sfn_display_name(char* out, char* in)
+{
+ int len = 0;
+ while (*in && len <= 11)
+ {
+ char a = *in++;
+
+ if (a == ' ')
+ continue;
+ // Make lower case if uppercase
+ else if ((a>='A') && (a<='Z'))
+ a+= 32;
+
+ *out++ = a;
+ len++;
+ }
+
+ *out = '\0';
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_get_extension: Get extension of filename passed in 'filename'.
+// Returned extension is always lower case.
+// Returns: 1 if ok, 0 if not.
+//-----------------------------------------------------------------------------
+int fatfs_get_extension(char* filename, char* out, int maxlen)
+{
+ int len = 0;
+
+ // Get files extension offset
+ int ext_pos = FileString_GetExtension(filename);
+
+ if (ext_pos > 0 && out && maxlen)
+ {
+ filename += ext_pos + 1;
+
+ while (*filename && len < (maxlen-1))
+ {
+ char a = *filename++;
+
+ // Make lowercase if uppercase
+ if ((a>='A') && (a<='Z'))
+ a+= 32;
+
+ *out++ = a;
+ len++;
+ }
+
+ *out = '\0';
+ return 1;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_create_path_string: Append path & filename to create file path string.
+// Returns: 1 if ok, 0 if not.
+//-----------------------------------------------------------------------------
+int fatfs_create_path_string(char* path, char *filename, char* out, int maxlen)
+{
+ int len = 0;
+ char last = 0;
+ char seperator = '/';
+
+ if (path && filename && out && maxlen > 0)
+ {
+ while (*path && len < (maxlen-2))
+ {
+ last = *path++;
+ if (last == '\\')
+ seperator = '\\';
+ *out++ = last;
+ len++;
+ }
+
+ // Add a seperator if trailing one not found
+ if (last != '\\' && last != '/')
+ *out++ = seperator;
+
+ while (*filename && len < (maxlen-1))
+ {
+ *out++ = *filename++;
+ len++;
+ }
+
+ *out = '\0';
+
+ return 1;
+ }
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// Test Bench
+//-----------------------------------------------------------------------------
+#ifdef FAT_STRING_TESTBENCH
+void main(void)
+{
+ char output[255];
+ char output2[255];
+
+ assert(fatfs_total_path_levels("C:\\folder\\file.zip") == 1);
+ assert(fatfs_total_path_levels("C:\\file.zip") == 0);
+ assert(fatfs_total_path_levels("C:\\folder\\folder2\\file.zip") == 2);
+ assert(fatfs_total_path_levels("C:\\") == -1);
+ assert(fatfs_total_path_levels("") == -1);
+ assert(fatfs_total_path_levels("/dev/etc/file.zip") == 2);
+ assert(fatfs_total_path_levels("/dev/file.zip") == 1);
+
+ assert(fatfs_get_substring("C:\\folder\\file.zip", 0, output, sizeof(output)) == 0);
+ assert(strcmp(output, "folder") == 0);
+
+ assert(fatfs_get_substring("C:\\folder\\file.zip", 1, output, sizeof(output)) == 0);
+ assert(strcmp(output, "file.zip") == 0);
+
+ assert(fatfs_get_substring("/dev/etc/file.zip", 0, output, sizeof(output)) == 0);
+ assert(strcmp(output, "dev") == 0);
+
+ assert(fatfs_get_substring("/dev/etc/file.zip", 1, output, sizeof(output)) == 0);
+ assert(strcmp(output, "etc") == 0);
+
+ assert(fatfs_get_substring("/dev/etc/file.zip", 2, output, sizeof(output)) == 0);
+ assert(strcmp(output, "file.zip") == 0);
+
+ assert(fatfs_split_path("C:\\folder\\file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
+ assert(strcmp(output, "C:\\folder") == 0);
+ assert(strcmp(output2, "file.zip") == 0);
+
+ assert(fatfs_split_path("C:\\file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
+ assert(output[0] == 0);
+ assert(strcmp(output2, "file.zip") == 0);
+
+ assert(fatfs_split_path("/dev/etc/file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
+ assert(strcmp(output, "/dev/etc") == 0);
+ assert(strcmp(output2, "file.zip") == 0);
+
+ assert(FileString_GetExtension("C:\\file.zip") == strlen("C:\\file"));
+ assert(FileString_GetExtension("C:\\file.zip.ext") == strlen("C:\\file.zip"));
+ assert(FileString_GetExtension("C:\\file.zip.") == strlen("C:\\file.zip"));
+
+ assert(FileString_TrimLength("C:\\file.zip", strlen("C:\\file.zip")) == strlen("C:\\file.zip"));
+ assert(FileString_TrimLength("C:\\file.zip ", strlen("C:\\file.zip ")) == strlen("C:\\file.zip"));
+ assert(FileString_TrimLength(" ", strlen(" ")) == 0);
+
+ assert(fatfs_compare_names("C:\\file.ext", "C:\\file.ext") == 1);
+ assert(fatfs_compare_names("C:\\file2.ext", "C:\\file.ext") == 0);
+ assert(fatfs_compare_names("C:\\file .ext", "C:\\file.ext") == 1);
+ assert(fatfs_compare_names("C:\\file .ext", "C:\\file2.ext") == 0);
+
+ assert(fatfs_string_ends_with_slash("C:\\folder") == 0);
+ assert(fatfs_string_ends_with_slash("C:\\folder\\") == 1);
+ assert(fatfs_string_ends_with_slash("/path") == 0);
+ assert(fatfs_string_ends_with_slash("/path/a") == 0);
+ assert(fatfs_string_ends_with_slash("/path/") == 1);
+
+ assert(fatfs_get_extension("/mypath/file.wav", output, 4) == 1);
+ assert(strcmp(output, "wav") == 0);
+ assert(fatfs_get_extension("/mypath/file.WAV", output, 4) == 1);
+ assert(strcmp(output, "wav") == 0);
+ assert(fatfs_get_extension("/mypath/file.zip", output, 4) == 1);
+ assert(strcmp(output, "ext") != 0);
+
+ assert(fatfs_create_path_string("/mydir1", "myfile.txt", output, sizeof(output)) == 1);
+ assert(strcmp(output, "/mydir1/myfile.txt") == 0);
+ assert(fatfs_create_path_string("/mydir2/", "myfile2.txt", output, sizeof(output)) == 1);
+ assert(strcmp(output, "/mydir2/myfile2.txt") == 0);
+ assert(fatfs_create_path_string("C:\\mydir3", "myfile3.txt", output, sizeof(output)) == 1);
+ assert(strcmp(output, "C:\\mydir3\\myfile3.txt") == 0);
+}
+#endif
--- /dev/null
+#ifndef __FILESTRING_H__
+#define __FILESTRING_H__
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+int fatfs_total_path_levels(char *path);
+int fatfs_get_substring(char *Path, int levelreq, char *output, int max_len);
+int fatfs_split_path(char *FullPath, char *Path, int max_path, char *FileName, int max_filename);
+int fatfs_compare_names(char* strA, char* strB);
+int fatfs_string_ends_with_slash(char *path);
+int fatfs_get_sfn_display_name(char* out, char* in);
+int fatfs_get_extension(char* filename, char* out, int maxlen);
+int fatfs_create_path_string(char* path, char *filename, char* out, int maxlen);
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+#endif
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+// FAT16/32 File IO Library\r
+// V2.6\r
+// Ultra-Embedded.com\r
+// Copyright 2003 - 2012\r
+//\r
+// Email: admin@ultra-embedded.com\r
+//\r
+// License: GPL\r
+// If you would like a version with a more permissive license for use in\r
+// closed source commercial applications please contact me for details.\r
+//-----------------------------------------------------------------------------\r
+//\r
+// This file is part of FAT File IO Library.\r
+//\r
+// FAT File IO Library is free software; you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation; either version 2 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// FAT File IO Library is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with FAT File IO Library; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+#include <string.h>
+#include "fat_defs.h"
+#include "fat_access.h"
+#include "fat_table.h"
+
+#ifndef FAT_BUFFERS
+ #define FAT_BUFFERS 1
+#endif
+
+#ifndef FAT_BUFFER_SECTORS
+ #define FAT_BUFFER_SECTORS 1
+#endif
+
+#if FAT_BUFFERS < 1 || FAT_BUFFER_SECTORS < 1
+ #error "FAT_BUFFERS & FAT_BUFFER_SECTORS must be at least 1"
+#endif
+
+//-----------------------------------------------------------------------------
+// FAT Sector Buffer
+//-----------------------------------------------------------------------------
+#define FAT32_GET_32BIT_WORD(pbuf, location) ( GET_32BIT_WORD(pbuf->ptr, location) )
+#define FAT32_SET_32BIT_WORD(pbuf, location, value) { SET_32BIT_WORD(pbuf->ptr, location, value); pbuf->dirty = 1; }
+#define FAT16_GET_16BIT_WORD(pbuf, location) ( GET_16BIT_WORD(pbuf->ptr, location) )
+#define FAT16_SET_16BIT_WORD(pbuf, location, value) { SET_16BIT_WORD(pbuf->ptr, location, value); pbuf->dirty = 1; }
+
+//-----------------------------------------------------------------------------
+// fatfs_fat_init:
+//-----------------------------------------------------------------------------
+void fatfs_fat_init(struct fatfs *fs)
+{
+ int i;
+
+ // FAT buffer chain head
+ fs->fat_buffer_head = NULL;
+
+ for (i=0;i<FAT_BUFFERS;i++)
+ {
+ // Initialise buffers to invalid
+ fs->fat_buffers[i].address = FAT32_INVALID_CLUSTER;
+ fs->fat_buffers[i].dirty = 0;
+ memset(fs->fat_buffers[i].sector, 0x00, sizeof(fs->fat_buffers[i].sector));
+ fs->fat_buffers[i].ptr = NULL;
+
+ // Add to head of queue
+ fs->fat_buffers[i].next = fs->fat_buffer_head;
+ fs->fat_buffer_head = &fs->fat_buffers[i];
+ }
+}
+//-----------------------------------------------------------------------------
+// fatfs_fat_writeback: Writeback 'dirty' FAT sectors to disk
+//-----------------------------------------------------------------------------
+static int fatfs_fat_writeback(struct fatfs *fs, struct fat_buffer *pcur)
+{
+ if (pcur)
+ {
+ // Writeback sector if changed
+ if (pcur->dirty)
+ {
+ if (fs->disk_io.write_media)
+ {
+ uint32 sectors = FAT_BUFFER_SECTORS;
+ uint32 offset = pcur->address - fs->fat_begin_lba;
+
+ // Limit to sectors used for the FAT
+ if ((offset + FAT_BUFFER_SECTORS) <= fs->fat_sectors)
+ sectors = FAT_BUFFER_SECTORS;
+ else
+ sectors = fs->fat_sectors - offset;
+
+ if (!fs->disk_io.write_media(pcur->address, pcur->sector, sectors))
+ return 0;
+ }
+
+ pcur->dirty = 0;
+ }
+
+ return 1;
+ }
+ else
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_fat_read_sector: Read a FAT sector
+//-----------------------------------------------------------------------------
+static struct fat_buffer *fatfs_fat_read_sector(struct fatfs *fs, uint32 sector)
+{
+ struct fat_buffer *last = NULL;
+ struct fat_buffer *pcur = fs->fat_buffer_head;
+
+ // Itterate through sector buffer list
+ while (pcur)
+ {
+ // Sector within this buffer?
+ if ((sector >= pcur->address) && (sector < (pcur->address + FAT_BUFFER_SECTORS)))
+ break;
+
+ // End of list?
+ if (pcur->next == NULL)
+ {
+ // Remove buffer from list
+ if (last)
+ last->next = NULL;
+ // We the first and last buffer in the chain?
+ else
+ fs->fat_buffer_head = NULL;
+ }
+
+ last = pcur;
+ pcur = pcur->next;
+ }
+
+ // We found the sector already in FAT buffer chain
+ if (pcur)
+ {
+ pcur->ptr = (uint8 *)(pcur->sector + ((sector - pcur->address) * FAT_SECTOR_SIZE));
+ return pcur;
+ }
+
+ // Else, we removed the last item from the list
+ pcur = last;
+
+ // Add to start of sector buffer list (now newest sector)
+ pcur->next = fs->fat_buffer_head;
+ fs->fat_buffer_head = pcur;
+
+ // Writeback sector if changed
+ if (pcur->dirty)
+ if (!fatfs_fat_writeback(fs, pcur))
+ return 0;
+
+ // Address is now new sector
+ pcur->address = sector;
+
+ // Read next sector
+ if (!fs->disk_io.read_media(pcur->address, pcur->sector, FAT_BUFFER_SECTORS))
+ {
+ // Read failed, invalidate buffer address
+ pcur->address = FAT32_INVALID_CLUSTER;
+ return NULL;
+ }
+
+ pcur->ptr = pcur->sector;
+ return pcur;
+}
+//-----------------------------------------------------------------------------
+// fatfs_fat_purge: Purge 'dirty' FAT sectors to disk
+//-----------------------------------------------------------------------------
+int fatfs_fat_purge(struct fatfs *fs)
+{
+ struct fat_buffer *pcur = fs->fat_buffer_head;
+
+ // Itterate through sector buffer list
+ while (pcur)
+ {
+ // Writeback sector if changed
+ if (pcur->dirty)
+ if (!fatfs_fat_writeback(fs, pcur))
+ return 0;
+
+ pcur = pcur->next;
+ }
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// General FAT Table Operations
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// fatfs_find_next_cluster: Return cluster number of next cluster in chain by
+// reading FAT table and traversing it. Return 0xffffffff for end of chain.
+//-----------------------------------------------------------------------------
+uint32 fatfs_find_next_cluster(struct fatfs *fs, uint32 current_cluster)
+{
+ uint32 fat_sector_offset, position;
+ uint32 nextcluster;
+ struct fat_buffer *pbuf;
+
+ // Why is '..' labelled with cluster 0 when it should be 2 ??
+ if (current_cluster == 0)
+ current_cluster = 2;
+
+ // Find which sector of FAT table to read
+ if (fs->fat_type == FAT_TYPE_16)
+ fat_sector_offset = current_cluster / 256;
+ else
+ fat_sector_offset = current_cluster / 128;
+
+ // Read FAT sector into buffer
+ pbuf = fatfs_fat_read_sector(fs, fs->fat_begin_lba+fat_sector_offset);
+ if (!pbuf)
+ return (FAT32_LAST_CLUSTER);
+
+ if (fs->fat_type == FAT_TYPE_16)
+ {
+ // Find 32 bit entry of current sector relating to cluster number
+ position = (current_cluster - (fat_sector_offset * 256)) * 2;
+
+ // Read Next Clusters value from Sector Buffer
+ nextcluster = FAT16_GET_16BIT_WORD(pbuf, (uint16)position);
+
+ // If end of chain found
+ if (nextcluster >= 0xFFF8 && nextcluster <= 0xFFFF)
+ return (FAT32_LAST_CLUSTER);
+ }
+ else
+ {
+ // Find 32 bit entry of current sector relating to cluster number
+ position = (current_cluster - (fat_sector_offset * 128)) * 4;
+
+ // Read Next Clusters value from Sector Buffer
+ nextcluster = FAT32_GET_32BIT_WORD(pbuf, (uint16)position);
+
+ // Mask out MS 4 bits (its 28bit addressing)
+ nextcluster = nextcluster & 0x0FFFFFFF;
+
+ // If end of chain found
+ if (nextcluster >= 0x0FFFFFF8 && nextcluster <= 0x0FFFFFFF)
+ return (FAT32_LAST_CLUSTER);
+ }
+
+ // Else return next cluster
+ return (nextcluster);
+}
+//-----------------------------------------------------------------------------
+// fatfs_set_fs_info_next_free_cluster: Write the next free cluster to the FSINFO table
+//-----------------------------------------------------------------------------
+void fatfs_set_fs_info_next_free_cluster(struct fatfs *fs, uint32 newValue)
+{
+ if (fs->fat_type == FAT_TYPE_16)
+ ;
+ else
+ {
+ // Load sector to change it
+ struct fat_buffer *pbuf = fatfs_fat_read_sector(fs, fs->lba_begin+fs->fs_info_sector);
+ if (!pbuf)
+ return ;
+
+ // Change
+ FAT32_SET_32BIT_WORD(pbuf, 492, newValue);
+ fs->next_free_cluster = newValue;
+
+ // Write back FSINFO sector to disk
+ if (fs->disk_io.write_media)
+ fs->disk_io.write_media(pbuf->address, pbuf->sector, 1);
+
+ // Invalidate cache entry
+ pbuf->address = FAT32_INVALID_CLUSTER;
+ pbuf->dirty = 0;
+ }
+}
+//-----------------------------------------------------------------------------
+// fatfs_find_blank_cluster: Find a free cluster entry by reading the FAT
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fatfs_find_blank_cluster(struct fatfs *fs, uint32 start_cluster, uint32 *free_cluster)
+{
+ uint32 fat_sector_offset, position;
+ uint32 nextcluster;
+ uint32 current_cluster = start_cluster;
+ struct fat_buffer *pbuf;
+
+ do
+ {
+ // Find which sector of FAT table to read
+ if (fs->fat_type == FAT_TYPE_16)
+ fat_sector_offset = current_cluster / 256;
+ else
+ fat_sector_offset = current_cluster / 128;
+
+ if ( fat_sector_offset < fs->fat_sectors)
+ {
+ // Read FAT sector into buffer
+ pbuf = fatfs_fat_read_sector(fs, fs->fat_begin_lba+fat_sector_offset);
+ if (!pbuf)
+ return 0;
+
+ if (fs->fat_type == FAT_TYPE_16)
+ {
+ // Find 32 bit entry of current sector relating to cluster number
+ position = (current_cluster - (fat_sector_offset * 256)) * 2;
+
+ // Read Next Clusters value from Sector Buffer
+ nextcluster = FAT16_GET_16BIT_WORD(pbuf, (uint16)position);
+ }
+ else
+ {
+ // Find 32 bit entry of current sector relating to cluster number
+ position = (current_cluster - (fat_sector_offset * 128)) * 4;
+
+ // Read Next Clusters value from Sector Buffer
+ nextcluster = FAT32_GET_32BIT_WORD(pbuf, (uint16)position);
+
+ // Mask out MS 4 bits (its 28bit addressing)
+ nextcluster = nextcluster & 0x0FFFFFFF;
+ }
+
+ if (nextcluster !=0 )
+ current_cluster++;
+ }
+ else
+ // Otherwise, run out of FAT sectors to check...
+ return 0;
+ }
+ while (nextcluster != 0x0);
+
+ // Found blank entry
+ *free_cluster = current_cluster;
+ return 1;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_fat_set_cluster: Set a cluster link in the chain. NOTE: Immediate
+// write (slow).
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fatfs_fat_set_cluster(struct fatfs *fs, uint32 cluster, uint32 next_cluster)
+{
+ struct fat_buffer *pbuf;
+ uint32 fat_sector_offset, position;
+
+ // Find which sector of FAT table to read
+ if (fs->fat_type == FAT_TYPE_16)
+ fat_sector_offset = cluster / 256;
+ else
+ fat_sector_offset = cluster / 128;
+
+ // Read FAT sector into buffer
+ pbuf = fatfs_fat_read_sector(fs, fs->fat_begin_lba+fat_sector_offset);
+ if (!pbuf)
+ return 0;
+
+ if (fs->fat_type == FAT_TYPE_16)
+ {
+ // Find 16 bit entry of current sector relating to cluster number
+ position = (cluster - (fat_sector_offset * 256)) * 2;
+
+ // Write Next Clusters value to Sector Buffer
+ FAT16_SET_16BIT_WORD(pbuf, (uint16)position, ((uint16)next_cluster));
+ }
+ else
+ {
+ // Find 32 bit entry of current sector relating to cluster number
+ position = (cluster - (fat_sector_offset * 128)) * 4;
+
+ // Write Next Clusters value to Sector Buffer
+ FAT32_SET_32BIT_WORD(pbuf, (uint16)position, next_cluster);
+ }
+
+ return 1;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_free_cluster_chain: Follow a chain marking each element as free
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fatfs_free_cluster_chain(struct fatfs *fs, uint32 start_cluster)
+{
+ uint32 last_cluster;
+ uint32 next_cluster = start_cluster;
+
+ // Loop until end of chain
+ while ( (next_cluster != FAT32_LAST_CLUSTER) && (next_cluster != 0x00000000) )
+ {
+ last_cluster = next_cluster;
+
+ // Find next link
+ next_cluster = fatfs_find_next_cluster(fs, next_cluster);
+
+ // Clear last link
+ fatfs_fat_set_cluster(fs, last_cluster, 0x00000000);
+ }
+
+ return 1;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_fat_add_cluster_to_chain: Follow a chain marking and then add a new entry
+// to the current tail.
+//-----------------------------------------------------------------------------
+#if FATFS_INC_WRITE_SUPPORT
+int fatfs_fat_add_cluster_to_chain(struct fatfs *fs, uint32 start_cluster, uint32 newEntry)
+{
+ uint32 last_cluster = FAT32_LAST_CLUSTER;
+ uint32 next_cluster = start_cluster;
+
+ if (start_cluster == FAT32_LAST_CLUSTER)
+ return 0;
+
+ // Loop until end of chain
+ while ( next_cluster != FAT32_LAST_CLUSTER )
+ {
+ last_cluster = next_cluster;
+
+ // Find next link
+ next_cluster = fatfs_find_next_cluster(fs, next_cluster);
+ if (!next_cluster)
+ return 0;
+ }
+
+ // Add link in for new cluster
+ fatfs_fat_set_cluster(fs, last_cluster, newEntry);
+
+ // Mark new cluster as end of chain
+ fatfs_fat_set_cluster(fs, newEntry, FAT32_LAST_CLUSTER);
+
+ return 1;
+}
+#endif
+//-----------------------------------------------------------------------------
+// fatfs_count_free_clusters:
+//-----------------------------------------------------------------------------
+uint32 fatfs_count_free_clusters(struct fatfs *fs)
+{
+ uint32 i,j;
+ uint32 count = 0;
+ struct fat_buffer *pbuf;
+
+ for (i = 0; i < fs->fat_sectors; i++)
+ {
+ // Read FAT sector into buffer
+ pbuf = fatfs_fat_read_sector(fs, fs->fat_begin_lba + i);
+ if (!pbuf)
+ break;
+
+ for (j = 0; j < FAT_SECTOR_SIZE; )
+ {
+ if (fs->fat_type == FAT_TYPE_16)
+ {
+ if (FAT16_GET_16BIT_WORD(pbuf, (uint16)j) == 0)
+ count++;
+
+ j += 2;
+ }
+ else
+ {
+ if (FAT32_GET_32BIT_WORD(pbuf, (uint16)j) == 0)
+ count++;
+
+ j += 4;
+ }
+ }
+ }
+
+ return count;
+}
--- /dev/null
+#ifndef __FAT_TABLE_H__
+#define __FAT_TABLE_H__
+
+#include "fat_opts.h"
+#include "fat_misc.h"
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+void fatfs_fat_init(struct fatfs *fs);
+int fatfs_fat_purge(struct fatfs *fs);
+uint32 fatfs_find_next_cluster(struct fatfs *fs, uint32 current_cluster);
+void fatfs_set_fs_info_next_free_cluster(struct fatfs *fs, uint32 newValue);
+int fatfs_find_blank_cluster(struct fatfs *fs, uint32 start_cluster, uint32 *free_cluster);
+int fatfs_fat_set_cluster(struct fatfs *fs, uint32 cluster, uint32 next_cluster);
+int fatfs_fat_add_cluster_to_chain(struct fatfs *fs, uint32 start_cluster, uint32 newEntry);
+int fatfs_free_cluster_chain(struct fatfs *fs, uint32 start_cluster);
+uint32 fatfs_count_free_clusters(struct fatfs *fs);
+
+#endif
--- /dev/null
+#ifndef __FAT_TYPES_H__
+#define __FAT_TYPES_H__
+
+// Detect 64-bit compilation on GCC
+#if defined(__GNUC__) && defined(__SIZEOF_LONG__)
+ #if __SIZEOF_LONG__ == 8
+ #define FATFS_DEF_UINT32_AS_INT
+ #endif
+#endif
+
+//-------------------------------------------------------------
+// System specific types
+//-------------------------------------------------------------
+#ifndef FATFS_NO_DEF_TYPES
+ typedef unsigned char uint8;
+ typedef unsigned short uint16;
+
+ // If compiling on a 64-bit machine, use int as 32-bits
+ #ifdef FATFS_DEF_UINT32_AS_INT
+ typedef unsigned int uint32;
+ // Else for 32-bit machines & embedded systems, use long...
+ #else
+ typedef unsigned long uint32;
+ #endif
+#endif
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+//-------------------------------------------------------------
+// Endian Macros
+//-------------------------------------------------------------
+// FAT is little endian so big endian systems need to swap words
+
+// Little Endian - No swap required
+#if FATFS_IS_LITTLE_ENDIAN == 1
+
+ #define FAT_HTONS(n) (n)
+ #define FAT_HTONL(n) (n)
+
+// Big Endian - Swap required
+#else
+
+ #define FAT_HTONS(n) ((((uint16)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
+ #define FAT_HTONL(n) (((((uint32)(n) & 0xFF)) << 24) | \
+ ((((uint32)(n) & 0xFF00)) << 8) | \
+ ((((uint32)(n) & 0xFF0000)) >> 8) | \
+ ((((uint32)(n) & 0xFF000000)) >> 24))
+
+#endif
+
+//-------------------------------------------------------------
+// Structure Packing Compile Options
+//-------------------------------------------------------------
+#ifdef __GNUC__
+ #define STRUCT_PACK
+ #define STRUCT_PACK_BEGIN
+ #define STRUCT_PACK_END
+ #define STRUCT_PACKED __attribute__ ((packed))
+#else
+ // Other compilers may require other methods of packing structures
+ #define STRUCT_PACK
+ #define STRUCT_PACK_BEGIN
+ #define STRUCT_PACK_END
+ #define STRUCT_PACKED
+#endif
+
+#endif
--- /dev/null
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+// FAT16/32 File IO Library\r
+// V2.6\r
+// Ultra-Embedded.com\r
+// Copyright 2003 - 2012\r
+//\r
+// Email: admin@ultra-embedded.com\r
+//\r
+// License: GPL\r
+// If you would like a version with a more permissive license for use in\r
+// closed source commercial applications please contact me for details.\r
+//-----------------------------------------------------------------------------\r
+//\r
+// This file is part of FAT File IO Library.\r
+//\r
+// FAT File IO Library is free software; you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation; either version 2 of the License, or\r
+// (at your option) any later version.\r
+//\r
+// FAT File IO Library is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+//\r
+// You should have received a copy of the GNU General Public License\r
+// along with FAT File IO Library; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+//-----------------------------------------------------------------------------\r
+//-----------------------------------------------------------------------------\r
+#include <string.h>
+#include "fat_defs.h"
+#include "fat_access.h"
+#include "fat_table.h"
+#include "fat_write.h"
+#include "fat_string.h"
+#include "fat_misc.h"
+
+#if FATFS_INC_WRITE_SUPPORT
+//-----------------------------------------------------------------------------
+// fatfs_add_free_space: Allocate another cluster of free space to the end
+// of a files cluster chain.
+//-----------------------------------------------------------------------------
+int fatfs_add_free_space(struct fatfs *fs, uint32 *startCluster, uint32 clusters)
+{
+ uint32 i;
+ uint32 nextcluster;
+ uint32 start = *startCluster;
+
+ // Set the next free cluster hint to unknown
+ if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
+ fatfs_set_fs_info_next_free_cluster(fs, FAT32_LAST_CLUSTER);
+
+ for (i=0;i<clusters;i++)
+ {
+ // Start looking for free clusters from the beginning
+ if (fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &nextcluster))
+ {
+ // Point last to this
+ fatfs_fat_set_cluster(fs, start, nextcluster);
+
+ // Point this to end of file
+ fatfs_fat_set_cluster(fs, nextcluster, FAT32_LAST_CLUSTER);
+
+ // Adjust argument reference
+ start = nextcluster;
+ if (i == 0)
+ *startCluster = nextcluster;
+ }
+ else
+ return 0;
+ }
+
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_allocate_free_space: Add an ammount of free space to a file either from
+// 'startCluster' if newFile = false, or allocating a new start to the chain if
+// newFile = true.
+//-----------------------------------------------------------------------------
+int fatfs_allocate_free_space(struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size)
+{
+ uint32 clusterSize;
+ uint32 clusterCount;
+ uint32 nextcluster;
+
+ if (size==0)
+ return 0;
+
+ // Set the next free cluster hint to unknown
+ if (fs->next_free_cluster != FAT32_LAST_CLUSTER)
+ fatfs_set_fs_info_next_free_cluster(fs, FAT32_LAST_CLUSTER);
+
+ // Work out size and clusters
+ clusterSize = fs->sectors_per_cluster * FAT_SECTOR_SIZE;
+ clusterCount = (size / clusterSize);
+
+ // If any left over
+ if (size-(clusterSize*clusterCount))
+ clusterCount++;
+
+ // Allocated first link in the chain if a new file
+ if (newFile)
+ {
+ if (!fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &nextcluster))
+ return 0;
+
+ // If this is all that is needed then all done
+ if (clusterCount==1)
+ {
+ fatfs_fat_set_cluster(fs, nextcluster, FAT32_LAST_CLUSTER);
+ *startCluster = nextcluster;
+ return 1;
+ }
+ }
+ // Allocate from end of current chain (startCluster is end of chain)
+ else
+ nextcluster = *startCluster;
+
+ if (!fatfs_add_free_space(fs, &nextcluster, clusterCount))
+ return 0;
+
+ return 1;
+}
+//-----------------------------------------------------------------------------
+// fatfs_find_free_dir_offset: Find a free space in the directory for a new entry
+// which takes up 'entryCount' blocks (or allocate some more)
+//-----------------------------------------------------------------------------
+static int fatfs_find_free_dir_offset(struct fatfs *fs, uint32 dirCluster, int entryCount, uint32 *pSector, uint8 *pOffset)
+{
+ struct fat_dir_entry *directoryEntry;
+ uint8 item=0;
+ uint16 recordoffset = 0;
+ uint8 i=0;
+ int x=0;
+ int possible_spaces = 0;
+ int start_recorded = 0;
+
+ // No entries required?
+ if (entryCount == 0)
+ return 0;
+
+ // Main cluster following loop
+ while (1)
+ {
+ // Read sector
+ if (fatfs_sector_reader(fs, dirCluster, x++, 0))
+ {
+ // Analyse Sector
+ for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
+ {
+ // Create the multiplier for sector access
+ recordoffset = FAT_DIR_ENTRY_SIZE * item;
+
+ // Overlay directory entry over buffer
+ directoryEntry = (struct fat_dir_entry*)(fs->currentsector.sector+recordoffset);
+
+ // LFN Entry
+ if (fatfs_entry_lfn_text(directoryEntry))
+ {
+ // First entry?
+ if (possible_spaces == 0)
+ {
+ // Store start
+ *pSector = x-1;
+ *pOffset = item;
+ start_recorded = 1;
+ }
+
+ // Increment the count in-case the file turns
+ // out to be deleted...
+ possible_spaces++;
+ }
+ // SFN Entry
+ else
+ {
+ // Has file been deleted?
+ if (fs->currentsector.sector[recordoffset] == FILE_HEADER_DELETED)
+ {
+ // First entry?
+ if (possible_spaces == 0)
+ {
+ // Store start
+ *pSector = x-1;
+ *pOffset = item;
+ start_recorded = 1;
+ }
+
+ possible_spaces++;
+
+ // We have found enough space?
+ if (possible_spaces >= entryCount)
+ return 1;
+
+ // Else continue counting until we find a valid entry!
+ }
+ // Is the file entry empty?
+ else if (fs->currentsector.sector[recordoffset] == FILE_HEADER_BLANK)
+ {
+ // First entry?
+ if (possible_spaces == 0)
+ {
+ // Store start
+ *pSector = x-1;
+ *pOffset = item;
+ start_recorded = 1;
+ }
+
+ // Increment the blank entries count
+ possible_spaces++;
+
+ // We have found enough space?
+ if (possible_spaces >= entryCount)
+ return 1;
+ }
+ // File entry is valid
+ else
+ {
+ // Reset all flags
+ possible_spaces = 0;
+ start_recorded = 0;
+ }
+ }
+ } // End of for
+ } // End of if
+ // Run out of free space in the directory, allocate some more
+ else
+ {
+ uint32 newCluster;
+
+ // Get a new cluster for directory
+ if (!fatfs_find_blank_cluster(fs, fs->rootdir_first_cluster, &newCluster))
+ return 0;
+
+ // Add cluster to end of directory tree
+ if (!fatfs_fat_add_cluster_to_chain(fs, dirCluster, newCluster))
+ return 0;
+
+ // Erase new directory cluster
+ memset(fs->currentsector.sector, 0x00, FAT_SECTOR_SIZE);
+ for (i=0;i<fs->sectors_per_cluster;i++)
+ {
+ if (!fatfs_write_sector(fs, newCluster, i, 0))
+ return 0;
+ }
+
+ // If non of the name fitted on previous sectors
+ if (!start_recorded)
+ {
+ // Store start
+ *pSector = (x-1);
+ *pOffset = 0;
+ start_recorded = 1;
+ }
+
+ return 1;
+ }
+ } // End of while loop
+
+ return 0;
+}
+//-----------------------------------------------------------------------------
+// fatfs_add_file_entry: Add a directory entry to a location found by FindFreeOffset
+//-----------------------------------------------------------------------------
+int fatfs_add_file_entry(struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir)
+{
+ uint8 item=0;
+ uint16 recordoffset = 0;
+ uint8 i=0;
+ uint32 x=0;
+ int entryCount;
+ struct fat_dir_entry shortEntry;
+ int dirtySector = 0;
+
+ uint32 dirSector = 0;
+ uint8 dirOffset = 0;
+ int foundEnd = 0;
+
+ uint8 checksum;
+ uint8 *pSname;
+
+ // No write access?
+ if (!fs->disk_io.write_media)
+ return 0;
+
+#if FATFS_INC_LFN_SUPPORT
+ // How many LFN entries are required?
+ // NOTE: We always request one LFN even if it would fit in a SFN!
+ entryCount = fatfs_lfn_entries_required(filename);
+ if (!entryCount)
+ return 0;
+#else
+ entryCount = 0;
+#endif
+
+ // Find space in the directory for this filename (or allocate some more)
+ // NOTE: We need to find space for at least the LFN + SFN (or just the SFN if LFNs not supported).
+ if (!fatfs_find_free_dir_offset(fs, dirCluster, entryCount + 1, &dirSector, &dirOffset))
+ return 0;
+
+ // Generate checksum of short filename
+ pSname = (uint8*)shortfilename;
+ checksum = 0;
+ for (i=11; i!=0; i--) checksum = ((checksum & 1) ? 0x80 : 0) + (checksum >> 1) + *pSname++;
+
+ // Start from current sector where space was found!
+ x = dirSector;
+
+ // Main cluster following loop
+ while (1)
+ {
+ // Read sector
+ if (fatfs_sector_reader(fs, dirCluster, x++, 0))
+ {
+ // Analyse Sector
+ for (item = 0; item < FAT_DIR_ENTRIES_PER_SECTOR; item++)
+ {
+ // Create the multiplier for sector access
+ recordoffset = FAT_DIR_ENTRY_SIZE * item;
+
+ // If the start position for the entry has been found
+ if (foundEnd==0)
+ if ( (dirSector==(x-1)) && (dirOffset==item) )
+ foundEnd = 1;
+
+ // Start adding filename
+ if (foundEnd)
+ {
+ if (entryCount==0)
+ {
+ // Short filename
+ fatfs_sfn_create_entry(shortfilename, size, startCluster, &shortEntry, dir);
+
+#if FATFS_INC_TIME_DATE_SUPPORT
+ // Update create, access & modify time & date
+ fatfs_update_timestamps(&shortEntry, 1, 1, 1);
+#endif
+
+ memcpy(&fs->currentsector.sector[recordoffset], &shortEntry, sizeof(shortEntry));
+
+ // Writeback
+ return fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1);
+ }
+#if FATFS_INC_LFN_SUPPORT
+ else
+ {
+ entryCount--;
+
+ // Copy entry to directory buffer
+ fatfs_filename_to_lfn(filename, &fs->currentsector.sector[recordoffset], entryCount, checksum);
+ dirtySector = 1;
+ }
+#endif
+ }
+ } // End of if
+
+ // Write back to disk before loading another sector
+ if (dirtySector)
+ {
+ if (!fs->disk_io.write_media(fs->currentsector.address, fs->currentsector.sector, 1))
+ return 0;
+
+ dirtySector = 0;
+ }
+ }
+ else
+ return 0;
+ } // End of while loop
+
+ return 0;
+}
+#endif
--- /dev/null
+#ifndef __FAT_WRITE_H__
+#define __FAT_WRITE_H__
+
+#include "fat_defs.h"
+#include "fat_opts.h"
+
+//-----------------------------------------------------------------------------
+// Prototypes
+//-----------------------------------------------------------------------------
+int fatfs_add_file_entry(struct fatfs *fs, uint32 dirCluster, char *filename, char *shortfilename, uint32 startCluster, uint32 size, int dir);
+int fatfs_add_free_space(struct fatfs *fs, uint32 *startCluster, uint32 clusters);
+int fatfs_allocate_free_space(struct fatfs *fs, int newFile, uint32 *startCluster, uint32 size);
+
+#endif
--- /dev/null
+/* Copyright (c) 2013-2016 the Civetweb developers
+ * Copyright (c) 2004-2013 Sergey Lyubka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+#if defined(_WIN32)
+#if !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS /* Disable deprecation warning in VS2005 */
+#endif
+#ifndef _WIN32_WINNT /* defined for tdm-gcc so we can use getnameinfo */
+#define _WIN32_WINNT 0x0501
+#endif
+#else
+#if defined(__GNUC__) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE /* for setgroups() */
+#endif
+#if defined(__linux__) && !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 600 /* For flockfile() on Linux */
+#endif
+#ifndef _LARGEFILE_SOURCE
+#define _LARGEFILE_SOURCE /* For fseeko(), ftello() */
+#endif
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64 /* Use 64-bit file offsets by default */
+#endif
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS /* <inttypes.h> wants this for C++ */
+#endif
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS /* C++ wants that for INT64_MAX */
+#endif
+#ifdef __sun
+#define __EXTENSIONS__ /* to expose flockfile and friends in stdio.h */
+#define __inline inline /* not recognized on older compiler versions */
+#endif
+#endif
+
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+#define USE_TIMERS
+#endif
+
+#if defined(_MSC_VER)
+/* 'type cast' : conversion from 'int' to 'HANDLE' of greater size */
+#pragma warning(disable : 4306)
+/* conditional expression is constant: introduced by FD_SET(..) */
+#pragma warning(disable : 4127)
+/* non-constant aggregate initializer: issued due to missing C99 support */
+#pragma warning(disable : 4204)
+/* padding added after data member */
+#pragma warning(disable : 4820)
+/* not defined as a preprocessor macro, replacing with '0' for '#if/#elif' */
+#pragma warning(disable : 4668)
+/* no function prototype given: converting '()' to '(void)' */
+#pragma warning(disable : 4255)
+/* function has been selected for automatic inline expansion */
+#pragma warning(disable : 4711)
+#endif
+
+
+/* This code uses static_assert to check some conditions.
+ * Unfortunately some compilers still do not support it, so we have a
+ * replacement function here. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1600)
+#define mg_static_assert static_assert
+#elif defined(__cplusplus) && (__cplusplus >= 201103L)
+#define mg_static_assert static_assert
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+#define mg_static_assert _Static_assert
+#else
+char static_assert_replacement[1];
+#define mg_static_assert(cond, txt) \
+ extern char static_assert_replacement[(cond) ? 1 : -1]
+#endif
+
+mg_static_assert(sizeof(int) == 4 || sizeof(int) == 8,
+ "int data type size check");
+mg_static_assert(sizeof(void *) == 4 || sizeof(void *) == 8,
+ "pointer data type size check");
+mg_static_assert(sizeof(void *) >= sizeof(int), "data type size check");
+/* mg_static_assert(sizeof(size_t) == 4 || sizeof(size_t) == 8, "size_t data
+ * type size check"); */
+
+/* DTL -- including winsock2.h works better if lean and mean */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#if defined(__SYMBIAN32__)
+#define NO_SSL /* SSL is not supported */
+#define NO_CGI /* CGI is not supported */
+#define PATH_MAX FILENAME_MAX
+#endif /* __SYMBIAN32__ */
+
+
+/* Include the header file here, so the CivetWeb interface is defined for the
+ * entire implementation, including the following forward definitions. */
+#include "civetweb.h"
+
+
+#ifndef IGNORE_UNUSED_RESULT
+#define IGNORE_UNUSED_RESULT(a) ((void)((a) && 1))
+#endif
+
+#ifndef _WIN32_WCE /* Some ANSI #includes are not available on Windows CE */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#endif /* !_WIN32_WCE */
+
+#ifdef __MACH__
+
+#define CLOCK_MONOTONIC (1)
+#define CLOCK_REALTIME (2)
+
+#include <sys/time.h>
+#include <mach/clock.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <assert.h>
+
+
+/* clock_gettime is not implemented on OSX */
+int clock_gettime(int clk_id, struct timespec *t);
+
+int
+clock_gettime(int clk_id, struct timespec *t)
+{
+ memset(t, 0, sizeof(*t));
+ if (clk_id == CLOCK_REALTIME) {
+ struct timeval now;
+ int rv = gettimeofday(&now, NULL);
+ if (rv) {
+ return rv;
+ }
+ t->tv_sec = now.tv_sec;
+ t->tv_nsec = now.tv_usec * 1000;
+ return 0;
+
+ } else if (clk_id == CLOCK_MONOTONIC) {
+ static uint64_t clock_start_time = 0;
+ static mach_timebase_info_data_t timebase_ifo = {0, 0};
+
+ uint64_t now = mach_absolute_time();
+
+ if (clock_start_time == 0) {
+ kern_return_t mach_status = mach_timebase_info(&timebase_ifo);
+#if defined(DEBUG)
+ assert(mach_status == KERN_SUCCESS);
+#else
+ /* appease "unused variable" warning for release builds */
+ (void)mach_status;
+#endif
+ clock_start_time = now;
+ }
+
+ now = (uint64_t)((double)(now - clock_start_time)
+ * (double)timebase_ifo.numer
+ / (double)timebase_ifo.denom);
+
+ t->tv_sec = now / 1000000000;
+ t->tv_nsec = now % 1000000000;
+ return 0;
+ }
+ return -1; /* EINVAL - Clock ID is unknown */
+}
+#endif
+
+
+#include <time.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+
+
+#ifndef MAX_WORKER_THREADS
+#define MAX_WORKER_THREADS (1024 * 64)
+#endif
+#ifndef SOCKET_TIMEOUT_QUANTUM
+#define SOCKET_TIMEOUT_QUANTUM (10000)
+#endif
+
+mg_static_assert(MAX_WORKER_THREADS >= 1,
+ "worker threads must be a positive number");
+
+#if defined(_WIN32) \
+ && !defined(__SYMBIAN32__) /* WINDOWS / UNIX include block */
+#include <windows.h>
+#include <winsock2.h> /* DTL add for SO_EXCLUSIVE */
+#include <ws2tcpip.h>
+
+typedef const char *SOCK_OPT_TYPE;
+
+#if !defined(PATH_MAX)
+#define PATH_MAX (MAX_PATH)
+#endif
+
+#if !defined(PATH_MAX)
+#define PATH_MAX (4096)
+#endif
+
+mg_static_assert(PATH_MAX >= 1, "path length must be a positive number");
+
+#ifndef _IN_PORT_T
+#ifndef in_port_t
+#define in_port_t u_short
+#endif
+#endif
+
+#ifndef _WIN32_WCE
+#include <process.h>
+#include <direct.h>
+#include <io.h>
+#else /* _WIN32_WCE */
+#define NO_CGI /* WinCE has no pipes */
+
+typedef long off_t;
+
+#define errno ((int)(GetLastError()))
+#define strerror(x) (_ultoa(x, (char *)_alloca(sizeof(x) * 3), 10))
+#endif /* _WIN32_WCE */
+
+#define MAKEUQUAD(lo, hi) \
+ ((uint64_t)(((uint32_t)(lo)) | ((uint64_t)((uint32_t)(hi))) << 32))
+#define RATE_DIFF (10000000) /* 100 nsecs */
+#define EPOCH_DIFF (MAKEUQUAD(0xd53e8000, 0x019db1de))
+#define SYS2UNIX_TIME(lo, hi) \
+ ((time_t)((MAKEUQUAD((lo), (hi)) - EPOCH_DIFF) / RATE_DIFF))
+
+/* Visual Studio 6 does not know __func__ or __FUNCTION__
+ * The rest of MS compilers use __FUNCTION__, not C99 __func__
+ * Also use _strtoui64 on modern M$ compilers */
+#if defined(_MSC_VER)
+#if (_MSC_VER < 1300)
+#define STRX(x) #x
+#define STR(x) STRX(x)
+#define __func__ __FILE__ ":" STR(__LINE__)
+#define strtoull(x, y, z) ((unsigned __int64)_atoi64(x))
+#define strtoll(x, y, z) (_atoi64(x))
+#else
+#define __func__ __FUNCTION__
+#define strtoull(x, y, z) (_strtoui64(x, y, z))
+#define strtoll(x, y, z) (_strtoi64(x, y, z))
+#endif
+#endif /* _MSC_VER */
+
+#define ERRNO ((int)(GetLastError()))
+#define NO_SOCKLEN_T
+
+#if defined(_WIN64) || defined(__MINGW64__)
+#define SSL_LIB "ssleay64.dll"
+#define CRYPTO_LIB "libeay64.dll"
+#else
+#define SSL_LIB "ssleay32.dll"
+#define CRYPTO_LIB "libeay32.dll"
+#endif
+
+#define O_NONBLOCK (0)
+#ifndef W_OK
+#define W_OK (2) /* http://msdn.microsoft.com/en-us/library/1w06ktdy.aspx */
+#endif
+#if !defined(EWOULDBLOCK)
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif /* !EWOULDBLOCK */
+#define _POSIX_
+#define INT64_FMT "I64d"
+#define UINT64_FMT "I64u"
+
+#define WINCDECL __cdecl
+#define SHUT_RD (0)
+#define SHUT_WR (1)
+#define SHUT_BOTH (2)
+#define vsnprintf_impl _vsnprintf
+#define access _access
+#define mg_sleep(x) (Sleep(x))
+
+#define pipe(x) _pipe(x, MG_BUF_LEN, _O_BINARY)
+#ifndef popen
+#define popen(x, y) (_popen(x, y))
+#endif
+#ifndef pclose
+#define pclose(x) (_pclose(x))
+#endif
+#define close(x) (_close(x))
+#define dlsym(x, y) (GetProcAddress((HINSTANCE)(x), (y)))
+#define RTLD_LAZY (0)
+#define fseeko(x, y, z) (_lseeki64(_fileno(x), (y), (z)) == -1 ? -1 : 0)
+#define fdopen(x, y) (_fdopen((x), (y)))
+#define write(x, y, z) (_write((x), (y), (unsigned)z))
+#define read(x, y, z) (_read((x), (y), (unsigned)z))
+#define flockfile(x) (EnterCriticalSection(&global_log_file_lock))
+#define funlockfile(x) (LeaveCriticalSection(&global_log_file_lock))
+#define sleep(x) (Sleep((x)*1000))
+#define rmdir(x) (_rmdir(x))
+#define timegm(x) (_mkgmtime(x))
+
+#if !defined(fileno)
+#define fileno(x) (_fileno(x))
+#endif /* !fileno MINGW #defines fileno */
+
+typedef HANDLE pthread_mutex_t;
+typedef DWORD pthread_key_t;
+typedef HANDLE pthread_t;
+typedef struct {
+ CRITICAL_SECTION threadIdSec;
+ int waitingthreadcount; /* The number of threads queued. */
+ pthread_t *waitingthreadhdls; /* The thread handles. */
+} pthread_cond_t;
+
+#ifndef __clockid_t_defined
+typedef DWORD clockid_t;
+#endif
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC (1)
+#endif
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME (2)
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1900)
+#define _TIMESPEC_DEFINED
+#endif
+#ifndef _TIMESPEC_DEFINED
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* nanoseconds */
+};
+#endif
+
+#define pid_t HANDLE /* MINGW typedefs pid_t to int. Using #define here. */
+
+static int pthread_mutex_lock(pthread_mutex_t *);
+static int pthread_mutex_unlock(pthread_mutex_t *);
+static void path_to_unicode(const struct mg_connection *conn,
+ const char *path,
+ wchar_t *wbuf,
+ size_t wbuf_len);
+struct file;
+static const char *
+mg_fgets(char *buf, size_t size, struct file *filep, char **p);
+
+
+#if defined(HAVE_STDINT)
+#include <stdint.h>
+#else
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned __int64 uint64_t;
+typedef __int64 int64_t;
+#define INT64_MAX (9223372036854775807)
+#endif /* HAVE_STDINT */
+
+/* POSIX dirent interface */
+struct dirent {
+ char d_name[PATH_MAX];
+};
+
+typedef struct DIR {
+ HANDLE handle;
+ WIN32_FIND_DATAW info;
+ struct dirent result;
+} DIR;
+
+#if defined(_WIN32) && !defined(POLLIN)
+#ifndef HAVE_POLL
+struct pollfd {
+ SOCKET fd;
+ short events;
+ short revents;
+};
+#define POLLIN (0x0300)
+#endif
+#endif
+
+/* Mark required libraries */
+#if defined(_MSC_VER)
+#pragma comment(lib, "Ws2_32.lib")
+#endif
+
+#else /* defined(_WIN32) && !defined(__SYMBIAN32__) - WINDOWS / UNIX include \
+ block */
+
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <netdb.h>
+#include <netinet/tcp.h>
+typedef const void *SOCK_OPT_TYPE;
+
+#if defined(ANDROID)
+typedef unsigned short int in_port_t;
+#endif
+
+#include <pwd.h>
+#include <unistd.h>
+#include <grp.h>
+#include <dirent.h>
+#define vsnprintf_impl vsnprintf
+
+#if !defined(NO_SSL_DL) && !defined(NO_SSL)
+#include <dlfcn.h>
+#endif
+#include <pthread.h>
+#if defined(__MACH__)
+#define SSL_LIB "libssl.dylib"
+#define CRYPTO_LIB "libcrypto.dylib"
+#else
+#if !defined(SSL_LIB)
+#define SSL_LIB "libssl.so"
+#endif
+#if !defined(CRYPTO_LIB)
+#define CRYPTO_LIB "libcrypto.so"
+#endif
+#endif
+#ifndef O_BINARY
+#define O_BINARY (0)
+#endif /* O_BINARY */
+#define closesocket(a) (close(a))
+#define mg_mkdir(conn, path, mode) (mkdir(path, mode))
+#define mg_remove(conn, x) (remove(x))
+#define mg_sleep(x) (usleep((x)*1000))
+#define mg_opendir(conn, x) (opendir(x))
+#define mg_closedir(x) (closedir(x))
+#define mg_readdir(x) (readdir(x))
+#define ERRNO (errno)
+#define INVALID_SOCKET (-1)
+#define INT64_FMT PRId64
+#define UINT64_FMT PRIu64
+typedef int SOCKET;
+#define WINCDECL
+
+#if defined(__hpux)
+/* HPUX 11 does not have monotonic, fall back to realtime */
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC CLOCK_REALTIME
+#endif
+
+/* HPUX defines socklen_t incorrectly as size_t which is 64bit on
+ * Itanium. Without defining _XOPEN_SOURCE or _XOPEN_SOURCE_EXTENDED
+ * the prototypes use int* rather than socklen_t* which matches the
+ * actual library expectation. When called with the wrong size arg
+ * accept() returns a zero client inet addr and check_acl() always
+ * fails. Since socklen_t is widely used below, just force replace
+ * their typedef with int. - DTL
+ */
+#define socklen_t int
+#endif /* hpux */
+
+#endif /* defined(_WIN32) && !defined(__SYMBIAN32__) - WINDOWS / UNIX include \
+ block */
+
+/* va_copy should always be a macro, C99 and C++11 - DTL */
+#ifndef va_copy
+#define va_copy(x, y) ((x) = (y))
+#endif
+
+#ifdef _WIN32
+/* Create substitutes for POSIX functions in Win32. */
+
+#if defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+
+static CRITICAL_SECTION global_log_file_lock;
+static DWORD
+pthread_self(void)
+{
+ return GetCurrentThreadId();
+}
+
+
+static int
+pthread_key_create(
+ pthread_key_t *key,
+ void (*_ignored)(void *) /* destructor not supported for Windows */
+ )
+{
+ (void)_ignored;
+
+ if ((key != 0)) {
+ *key = TlsAlloc();
+ return (*key != TLS_OUT_OF_INDEXES) ? 0 : -1;
+ }
+ return -2;
+}
+
+
+static int
+pthread_key_delete(pthread_key_t key)
+{
+ return TlsFree(key) ? 0 : 1;
+}
+
+
+static int
+pthread_setspecific(pthread_key_t key, void *value)
+{
+ return TlsSetValue(key, value) ? 0 : 1;
+}
+
+
+static void *
+pthread_getspecific(pthread_key_t key)
+{
+ return TlsGetValue(key);
+}
+
+#if defined(__MINGW32__)
+/* Enable unused function warning again */
+#pragma GCC diagnostic pop
+#endif
+
+static struct pthread_mutex_undefined_struct *pthread_mutex_attr = NULL;
+#else
+static pthread_mutexattr_t pthread_mutex_attr;
+#endif /* _WIN32 */
+
+
+#define PASSWORDS_FILE_NAME ".htpasswd"
+#define CGI_ENVIRONMENT_SIZE (4096)
+#define MAX_CGI_ENVIR_VARS (256)
+#define MG_BUF_LEN (8192)
+
+#ifndef MAX_REQUEST_SIZE
+#define MAX_REQUEST_SIZE (16384)
+#endif
+
+mg_static_assert(MAX_REQUEST_SIZE >= 256,
+ "request size length must be a positive number");
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+
+#if !defined(DEBUG_TRACE)
+#if defined(DEBUG)
+
+
+static void DEBUG_TRACE_FUNC(const char *func,
+ unsigned line,
+ PRINTF_FORMAT_STRING(const char *fmt),
+ ...) PRINTF_ARGS(3, 4);
+
+static void
+DEBUG_TRACE_FUNC(const char *func, unsigned line, const char *fmt, ...)
+{
+ va_list args;
+ flockfile(stdout);
+ printf("*** %lu.%p.%s.%u: ",
+ (unsigned long)time(NULL),
+ (void *)pthread_self(),
+ func,
+ line);
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ putchar('\n');
+ fflush(stdout);
+ funlockfile(stdout);
+}
+
+#define DEBUG_TRACE(fmt, ...) \
+ DEBUG_TRACE_FUNC(__func__, __LINE__, fmt, __VA_ARGS__)
+
+#else
+#define DEBUG_TRACE(fmt, ...) \
+ do { \
+ } while (0)
+#endif /* DEBUG */
+#endif /* DEBUG_TRACE */
+
+#if defined(MEMORY_DEBUGGING)
+unsigned long mg_memory_debug_blockCount = 0;
+unsigned long mg_memory_debug_totalMemUsed = 0;
+
+
+static void *
+mg_malloc_ex(size_t size, const char *file, unsigned line)
+{
+ void *data = malloc(size + sizeof(size_t));
+ void *memory = 0;
+ char mallocStr[256];
+
+ if (data) {
+ *(size_t *)data = size;
+ mg_memory_debug_totalMemUsed += size;
+ mg_memory_debug_blockCount++;
+ memory = (void *)(((char *)data) + sizeof(size_t));
+ }
+
+ sprintf(mallocStr,
+ "MEM: %p %5lu alloc %7lu %4lu --- %s:%u\n",
+ memory,
+ (unsigned long)size,
+ mg_memory_debug_totalMemUsed,
+ mg_memory_debug_blockCount,
+ file,
+ line);
+#if defined(_WIN32)
+ OutputDebugStringA(mallocStr);
+#else
+ DEBUG_TRACE("%s", mallocStr);
+#endif
+
+ return memory;
+}
+
+
+static void *
+mg_calloc_ex(size_t count, size_t size, const char *file, unsigned line)
+{
+ void *data = mg_malloc_ex(size * count, file, line);
+ if (data) {
+ memset(data, 0, size);
+ }
+ return data;
+}
+
+
+static void
+mg_free_ex(void *memory, const char *file, unsigned line)
+{
+ char mallocStr[256];
+ void *data = (void *)(((char *)memory) - sizeof(size_t));
+ size_t size;
+
+ if (memory) {
+ size = *(size_t *)data;
+ mg_memory_debug_totalMemUsed -= size;
+ mg_memory_debug_blockCount--;
+ sprintf(mallocStr,
+ "MEM: %p %5lu free %7lu %4lu --- %s:%u\n",
+ memory,
+ (unsigned long)size,
+ mg_memory_debug_totalMemUsed,
+ mg_memory_debug_blockCount,
+ file,
+ line);
+#if defined(_WIN32)
+ OutputDebugStringA(mallocStr);
+#else
+ DEBUG_TRACE("%s", mallocStr);
+#endif
+
+ free(data);
+ }
+}
+
+
+static void *
+mg_realloc_ex(void *memory, size_t newsize, const char *file, unsigned line)
+{
+ char mallocStr[256];
+ void *data;
+ void *_realloc;
+ size_t oldsize;
+
+ if (newsize) {
+ if (memory) {
+ data = (void *)(((char *)memory) - sizeof(size_t));
+ oldsize = *(size_t *)data;
+ _realloc = realloc(data, newsize + sizeof(size_t));
+ if (_realloc) {
+ data = _realloc;
+ mg_memory_debug_totalMemUsed -= oldsize;
+ sprintf(mallocStr,
+ "MEM: %p %5lu r-free %7lu %4lu --- %s:%u\n",
+ memory,
+ (unsigned long)oldsize,
+ mg_memory_debug_totalMemUsed,
+ mg_memory_debug_blockCount,
+ file,
+ line);
+#if defined(_WIN32)
+ OutputDebugStringA(mallocStr);
+#else
+ DEBUG_TRACE("%s", mallocStr);
+#endif
+ mg_memory_debug_totalMemUsed += newsize;
+ sprintf(mallocStr,
+ "MEM: %p %5lu r-alloc %7lu %4lu --- %s:%u\n",
+ memory,
+ (unsigned long)newsize,
+ mg_memory_debug_totalMemUsed,
+ mg_memory_debug_blockCount,
+ file,
+ line);
+#if defined(_WIN32)
+ OutputDebugStringA(mallocStr);
+#else
+ DEBUG_TRACE("%s", mallocStr);
+#endif
+ *(size_t *)data = newsize;
+ data = (void *)(((char *)data) + sizeof(size_t));
+ } else {
+#if defined(_WIN32)
+ OutputDebugStringA("MEM: realloc failed\n");
+#else
+ DEBUG_TRACE("%s", "MEM: realloc failed\n");
+#endif
+ return _realloc;
+ }
+ } else {
+ data = mg_malloc_ex(newsize, file, line);
+ }
+ } else {
+ data = 0;
+ mg_free_ex(memory, file, line);
+ }
+
+ return data;
+}
+
+#define mg_malloc(a) mg_malloc_ex(a, __FILE__, __LINE__)
+#define mg_calloc(a, b) mg_calloc_ex(a, b, __FILE__, __LINE__)
+#define mg_realloc(a, b) mg_realloc_ex(a, b, __FILE__, __LINE__)
+#define mg_free(a) mg_free_ex(a, __FILE__, __LINE__)
+
+#else
+
+static __inline void *
+mg_malloc(size_t a)
+{
+ return malloc(a);
+}
+
+static __inline void *
+mg_calloc(size_t a, size_t b)
+{
+ return calloc(a, b);
+}
+
+static __inline void *
+mg_realloc(void *a, size_t b)
+{
+ return realloc(a, b);
+}
+
+static __inline void
+mg_free(void *a)
+{
+ free(a);
+}
+
+#endif
+
+
+static void mg_vsnprintf(const struct mg_connection *conn,
+ int *truncated,
+ char *buf,
+ size_t buflen,
+ const char *fmt,
+ va_list ap);
+
+static void mg_snprintf(const struct mg_connection *conn,
+ int *truncated,
+ char *buf,
+ size_t buflen,
+ PRINTF_FORMAT_STRING(const char *fmt),
+ ...) PRINTF_ARGS(5, 6);
+
+/* This following lines are just meant as a reminder to use the mg-functions
+ * for memory management */
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef calloc
+#undef calloc
+#endif
+#ifdef realloc
+#undef realloc
+#endif
+#ifdef free
+#undef free
+#endif
+#ifdef snprintf
+#undef snprintf
+#endif
+#ifdef vsnprintf
+#undef vsnprintf
+#endif
+#define malloc DO_NOT_USE_THIS_FUNCTION__USE_mg_malloc
+#define calloc DO_NOT_USE_THIS_FUNCTION__USE_mg_calloc
+#define realloc DO_NOT_USE_THIS_FUNCTION__USE_mg_realloc
+#define free DO_NOT_USE_THIS_FUNCTION__USE_mg_free
+#define snprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_snprintf
+#ifdef _WIN32 /* vsnprintf must not be used in any system, * \
+ * but this define only works well for Windows. */
+#define vsnprintf DO_NOT_USE_THIS_FUNCTION__USE_mg_vsnprintf
+#endif
+
+#define MD5_STATIC static
+#include "md5.inl"
+
+/* Darwin prior to 7.0 and Win32 do not have socklen_t */
+#ifdef NO_SOCKLEN_T
+typedef int socklen_t;
+#endif /* NO_SOCKLEN_T */
+#define _DARWIN_UNLIMITED_SELECT
+
+#define IP_ADDR_STR_LEN (50) /* IPv6 hex string is 46 chars */
+
+#if !defined(MSG_NOSIGNAL)
+#define MSG_NOSIGNAL (0)
+#endif
+
+#if !defined(SOMAXCONN)
+#define SOMAXCONN (100)
+#endif
+
+/* Size of the accepted socket queue */
+#if !defined(MGSQLEN)
+#define MGSQLEN (20)
+#endif
+
+#if defined(NO_SSL_DL)
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#else
+/* SSL loaded dynamically from DLL.
+ * I put the prototypes here to be independent from OpenSSL source
+ * installation. */
+
+typedef struct ssl_st SSL;
+typedef struct ssl_method_st SSL_METHOD;
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct x509_store_ctx_st X509_STORE_CTX;
+
+#define SSL_CTRL_OPTIONS (32)
+#define SSL_CTRL_CLEAR_OPTIONS (77)
+#define SSL_CTRL_SET_ECDH_AUTO (94)
+
+#define SSL_VERIFY_NONE (0)
+#define SSL_VERIFY_PEER (1)
+#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT (2)
+#define SSL_VERIFY_CLIENT_ONCE (4)
+#define SSL_OP_ALL ((long)(0x80000BFFUL))
+#define SSL_OP_NO_SSLv2 (0x01000000L)
+#define SSL_OP_NO_SSLv3 (0x02000000L)
+#define SSL_OP_NO_TLSv1 (0x04000000L)
+#define SSL_OP_NO_TLSv1_2 (0x08000000L)
+#define SSL_OP_NO_TLSv1_1 (0x10000000L)
+#define SSL_OP_SINGLE_DH_USE (0x00100000L)
+
+struct ssl_func {
+ const char *name; /* SSL function name */
+ void (*ptr)(void); /* Function pointer */
+};
+
+#define SSL_free (*(void (*)(SSL *))ssl_sw[0].ptr)
+#define SSL_accept (*(int (*)(SSL *))ssl_sw[1].ptr)
+#define SSL_connect (*(int (*)(SSL *))ssl_sw[2].ptr)
+#define SSL_read (*(int (*)(SSL *, void *, int))ssl_sw[3].ptr)
+#define SSL_write (*(int (*)(SSL *, const void *, int))ssl_sw[4].ptr)
+#define SSL_get_error (*(int (*)(SSL *, int))ssl_sw[5].ptr)
+#define SSL_set_fd (*(int (*)(SSL *, SOCKET))ssl_sw[6].ptr)
+#define SSL_new (*(SSL * (*)(SSL_CTX *))ssl_sw[7].ptr)
+#define SSL_CTX_new (*(SSL_CTX * (*)(SSL_METHOD *))ssl_sw[8].ptr)
+#define SSLv23_server_method (*(SSL_METHOD * (*)(void))ssl_sw[9].ptr)
+#define SSL_library_init (*(int (*)(void))ssl_sw[10].ptr)
+#define SSL_CTX_use_PrivateKey_file \
+ (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[11].ptr)
+#define SSL_CTX_use_certificate_file \
+ (*(int (*)(SSL_CTX *, const char *, int))ssl_sw[12].ptr)
+#define SSL_CTX_set_default_passwd_cb \
+ (*(void (*)(SSL_CTX *, mg_callback_t))ssl_sw[13].ptr)
+#define SSL_CTX_free (*(void (*)(SSL_CTX *))ssl_sw[14].ptr)
+#define SSL_load_error_strings (*(void (*)(void))ssl_sw[15].ptr)
+#define SSL_CTX_use_certificate_chain_file \
+ (*(int (*)(SSL_CTX *, const char *))ssl_sw[16].ptr)
+#define SSLv23_client_method (*(SSL_METHOD * (*)(void))ssl_sw[17].ptr)
+#define SSL_pending (*(int (*)(SSL *))ssl_sw[18].ptr)
+#define SSL_CTX_set_verify \
+ (*(void (*)(SSL_CTX *, \
+ int, \
+ int (*verify_callback)(int, X509_STORE_CTX *)))ssl_sw[19].ptr)
+#define SSL_shutdown (*(int (*)(SSL *))ssl_sw[20].ptr)
+#define SSL_CTX_load_verify_locations \
+ (*(int (*)(SSL_CTX *, const char *, const char *))ssl_sw[21].ptr)
+#define SSL_CTX_set_default_verify_paths (*(int (*)(SSL_CTX *))ssl_sw[22].ptr)
+#define SSL_CTX_set_verify_depth (*(void (*)(SSL_CTX *, int))ssl_sw[23].ptr)
+#define SSL_get_peer_certificate (*(X509 * (*)(SSL *))ssl_sw[24].ptr)
+#define SSL_get_version (*(const char *(*)(SSL *))ssl_sw[25].ptr)
+#define SSL_get_current_cipher (*(SSL_CIPHER * (*)(SSL *))ssl_sw[26].ptr)
+#define SSL_CIPHER_get_name \
+ (*(const char *(*)(const SSL_CIPHER *))ssl_sw[27].ptr)
+#define SSL_CTX_check_private_key (*(int (*)(SSL_CTX *))ssl_sw[28].ptr)
+#define SSL_CTX_set_session_id_context \
+ (*(int (*)(SSL_CTX *, const unsigned char *, unsigned int))ssl_sw[29].ptr)
+#define SSL_CTX_ctrl (*(long (*)(SSL_CTX *, int, long, void *))ssl_sw[30].ptr)
+#define SSL_CTX_set_cipher_list \
+ (*(int (*)(SSL_CTX *, const char *))ssl_sw[31].ptr)
+#define SSL_CTX_set_options(ctx, op) \
+ SSL_CTX_ctrl((ctx), SSL_CTRL_OPTIONS, (op), NULL)
+#define SSL_CTX_clear_options(ctx, op) \
+ SSL_CTX_ctrl((ctx), SSL_CTRL_CLEAR_OPTIONS, (op), NULL)
+#define SSL_CTX_set_ecdh_auto(ctx, onoff) \
+ SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff, NULL)
+
+#define CRYPTO_num_locks (*(int (*)(void))crypto_sw[0].ptr)
+#define CRYPTO_set_locking_callback \
+ (*(void (*)(void (*)(int, int, const char *, int)))crypto_sw[1].ptr)
+#define CRYPTO_set_id_callback \
+ (*(void (*)(unsigned long (*)(void)))crypto_sw[2].ptr)
+#define ERR_get_error (*(unsigned long (*)(void))crypto_sw[3].ptr)
+#define ERR_error_string (*(char *(*)(unsigned long, char *))crypto_sw[4].ptr)
+#define ERR_remove_state (*(void (*)(unsigned long))crypto_sw[5].ptr)
+#define ERR_free_strings (*(void (*)(void))crypto_sw[6].ptr)
+#define ENGINE_cleanup (*(void (*)(void))crypto_sw[7].ptr)
+#define CONF_modules_unload (*(void (*)(int))crypto_sw[8].ptr)
+#define CRYPTO_cleanup_all_ex_data (*(void (*)(void))crypto_sw[9].ptr)
+#define EVP_cleanup (*(void (*)(void))crypto_sw[10].ptr)
+
+
+/* set_ssl_option() function updates this array.
+ * It loads SSL library dynamically and changes NULLs to the actual addresses
+ * of respective functions. The macros above (like SSL_connect()) are really
+ * just calling these functions indirectly via the pointer. */
+static struct ssl_func ssl_sw[] = {{"SSL_free", NULL},
+ {"SSL_accept", NULL},
+ {"SSL_connect", NULL},
+ {"SSL_read", NULL},
+ {"SSL_write", NULL},
+ {"SSL_get_error", NULL},
+ {"SSL_set_fd", NULL},
+ {"SSL_new", NULL},
+ {"SSL_CTX_new", NULL},
+ {"SSLv23_server_method", NULL},
+ {"SSL_library_init", NULL},
+ {"SSL_CTX_use_PrivateKey_file", NULL},
+ {"SSL_CTX_use_certificate_file", NULL},
+ {"SSL_CTX_set_default_passwd_cb", NULL},
+ {"SSL_CTX_free", NULL},
+ {"SSL_load_error_strings", NULL},
+ {"SSL_CTX_use_certificate_chain_file", NULL},
+ {"SSLv23_client_method", NULL},
+ {"SSL_pending", NULL},
+ {"SSL_CTX_set_verify", NULL},
+ {"SSL_shutdown", NULL},
+ {"SSL_CTX_load_verify_locations", NULL},
+ {"SSL_CTX_set_default_verify_paths", NULL},
+ {"SSL_CTX_set_verify_depth", NULL},
+ {"SSL_get_peer_certificate", NULL},
+ {"SSL_get_version", NULL},
+ {"SSL_get_current_cipher", NULL},
+ {"SSL_CIPHER_get_name", NULL},
+ {"SSL_CTX_check_private_key", NULL},
+ {"SSL_CTX_set_session_id_context", NULL},
+ {"SSL_CTX_ctrl", NULL},
+ {"SSL_CTX_set_cipher_list", NULL},
+ {NULL, NULL}};
+
+
+/* Similar array as ssl_sw. These functions could be located in different
+ * lib. */
+#if !defined(NO_SSL)
+static struct ssl_func crypto_sw[] = {{"CRYPTO_num_locks", NULL},
+ {"CRYPTO_set_locking_callback", NULL},
+ {"CRYPTO_set_id_callback", NULL},
+ {"ERR_get_error", NULL},
+ {"ERR_error_string", NULL},
+ {"ERR_remove_state", NULL},
+ {"ERR_free_strings", NULL},
+ {"ENGINE_cleanup", NULL},
+ {"CONF_modules_unload", NULL},
+ {"CRYPTO_cleanup_all_ex_data", NULL},
+ {"EVP_cleanup", NULL},
+ {NULL, NULL}};
+#endif /* NO_SSL */
+#endif /* NO_SSL_DL */
+
+
+#if !defined(NO_CACHING)
+static const char *month_names[] = {"Jan",
+ "Feb",
+ "Mar",
+ "Apr",
+ "May",
+ "Jun",
+ "Jul",
+ "Aug",
+ "Sep",
+ "Oct",
+ "Nov",
+ "Dec"};
+#endif /* !NO_CACHING */
+
+/* Unified socket address. For IPv6 support, add IPv6 address structure in the
+ * union u. */
+union usa {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#if defined(USE_IPV6)
+ struct sockaddr_in6 sin6;
+#endif
+};
+
+/* Describes a string (chunk of memory). */
+struct vec {
+ const char *ptr;
+ size_t len;
+};
+
+struct file {
+ uint64_t size;
+ time_t last_modified;
+ FILE *fp;
+ const char *membuf; /* Non-NULL if file data is in memory */
+ int is_directory;
+ int gzipped; /* set to 1 if the content is gzipped
+ * in which case we need a content-encoding: gzip header */
+};
+
+#define STRUCT_FILE_INITIALIZER \
+ { \
+ (uint64_t)0, (time_t)0, (FILE *)NULL, (const char *)NULL, 0, 0 \
+ }
+
+/* Describes listening socket, or socket which was accept()-ed by the master
+ * thread and queued for future handling by the worker thread. */
+struct socket {
+ SOCKET sock; /* Listening socket */
+ union usa lsa; /* Local socket address */
+ union usa rsa; /* Remote socket address */
+ unsigned char is_ssl; /* Is port SSL-ed */
+ unsigned char ssl_redir; /* Is port supposed to redirect everything to SSL
+ * port */
+};
+
+/* NOTE(lsm): this enum shoulds be in sync with the config_options below. */
+enum {
+ CGI_EXTENSIONS,
+ CGI_ENVIRONMENT,
+ PUT_DELETE_PASSWORDS_FILE,
+ CGI_INTERPRETER,
+ PROTECT_URI,
+ AUTHENTICATION_DOMAIN,
+ SSI_EXTENSIONS,
+ THROTTLE,
+ ACCESS_LOG_FILE,
+ ENABLE_DIRECTORY_LISTING,
+ ERROR_LOG_FILE,
+ GLOBAL_PASSWORDS_FILE,
+ INDEX_FILES,
+ ENABLE_KEEP_ALIVE,
+ ACCESS_CONTROL_LIST,
+ EXTRA_MIME_TYPES,
+ LISTENING_PORTS,
+ DOCUMENT_ROOT,
+ SSL_CERTIFICATE,
+ NUM_THREADS,
+ RUN_AS_USER,
+ REWRITE,
+ HIDE_FILES,
+ REQUEST_TIMEOUT,
+ SSL_DO_VERIFY_PEER,
+ SSL_CA_PATH,
+ SSL_CA_FILE,
+ SSL_VERIFY_DEPTH,
+ SSL_DEFAULT_VERIFY_PATHS,
+ SSL_CIPHER_LIST,
+ SSL_PROTOCOL_VERSION,
+ SSL_SHORT_TRUST,
+#if defined(USE_WEBSOCKET)
+ WEBSOCKET_TIMEOUT,
+#endif
+ DECODE_URL,
+
+#if defined(USE_LUA)
+ LUA_PRELOAD_FILE,
+ LUA_SCRIPT_EXTENSIONS,
+ LUA_SERVER_PAGE_EXTENSIONS,
+#endif
+#if defined(USE_DUKTAPE)
+ DUKTAPE_SCRIPT_EXTENSIONS,
+#endif
+
+#if defined(USE_WEBSOCKET)
+ WEBSOCKET_ROOT,
+#endif
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+ LUA_WEBSOCKET_EXTENSIONS,
+#endif
+ ACCESS_CONTROL_ALLOW_ORIGIN,
+ ERROR_PAGES,
+ CONFIG_TCP_NODELAY, /* Prepended CONFIG_ to avoid conflict with the
+ * socket option typedef TCP_NODELAY. */
+#if !defined(NO_CACHING)
+ STATIC_FILE_MAX_AGE,
+#endif
+
+ NUM_OPTIONS
+};
+
+
+/* Config option name, config types, default value */
+static struct mg_option config_options[] = {
+ {"cgi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.cgi$|**.pl$|**.php$"},
+ {"cgi_environment", CONFIG_TYPE_STRING, NULL},
+ {"put_delete_auth_file", CONFIG_TYPE_FILE, NULL},
+ {"cgi_interpreter", CONFIG_TYPE_FILE, NULL},
+ {"protect_uri", CONFIG_TYPE_STRING, NULL},
+ {"authentication_domain", CONFIG_TYPE_STRING, "mydomain.com"},
+ {"ssi_pattern", CONFIG_TYPE_EXT_PATTERN, "**.shtml$|**.shtm$"},
+ {"throttle", CONFIG_TYPE_STRING, NULL},
+ {"access_log_file", CONFIG_TYPE_FILE, NULL},
+ {"enable_directory_listing", CONFIG_TYPE_BOOLEAN, "yes"},
+ {"error_log_file", CONFIG_TYPE_FILE, NULL},
+ {"global_auth_file", CONFIG_TYPE_FILE, NULL},
+ {"index_files",
+ CONFIG_TYPE_STRING,
+#ifdef USE_LUA
+ "index.xhtml,index.html,index.htm,index.lp,index.lsp,index.lua,index.cgi,"
+ "index.shtml,index.php"},
+#else
+ "index.xhtml,index.html,index.htm,index.cgi,index.shtml,index.php"},
+#endif
+ {"enable_keep_alive", CONFIG_TYPE_BOOLEAN, "no"},
+ {"access_control_list", CONFIG_TYPE_STRING, NULL},
+ {"extra_mime_types", CONFIG_TYPE_STRING, NULL},
+ {"listening_ports", CONFIG_TYPE_STRING, "8080"},
+ {"document_root", CONFIG_TYPE_DIRECTORY, NULL},
+ {"ssl_certificate", CONFIG_TYPE_FILE, NULL},
+ {"num_threads", CONFIG_TYPE_NUMBER, "50"},
+ {"run_as_user", CONFIG_TYPE_STRING, NULL},
+ {"url_rewrite_patterns", CONFIG_TYPE_STRING, NULL},
+ {"hide_files_patterns", CONFIG_TYPE_EXT_PATTERN, NULL},
+ {"request_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
+ {"ssl_verify_peer", CONFIG_TYPE_BOOLEAN, "no"},
+ {"ssl_ca_path", CONFIG_TYPE_DIRECTORY, NULL},
+ {"ssl_ca_file", CONFIG_TYPE_FILE, NULL},
+ {"ssl_verify_depth", CONFIG_TYPE_NUMBER, "9"},
+ {"ssl_default_verify_paths", CONFIG_TYPE_BOOLEAN, "yes"},
+ {"ssl_cipher_list", CONFIG_TYPE_STRING, NULL},
+ {"ssl_protocol_version", CONFIG_TYPE_NUMBER, "0"},
+ {"ssl_short_trust", CONFIG_TYPE_BOOLEAN, "no"},
+#if defined(USE_WEBSOCKET)
+ {"websocket_timeout_ms", CONFIG_TYPE_NUMBER, "30000"},
+#endif
+ {"decode_url", CONFIG_TYPE_BOOLEAN, "yes"},
+
+#if defined(USE_LUA)
+ {"lua_preload_file", CONFIG_TYPE_FILE, NULL},
+ {"lua_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
+ {"lua_server_page_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lp$|**.lsp$"},
+#endif
+#if defined(USE_DUKTAPE)
+ /* The support for duktape is still in alpha version state.
+ * The name of this config option might change. */
+ {"duktape_script_pattern", CONFIG_TYPE_EXT_PATTERN, "**.ssjs$"},
+#endif
+
+#if defined(USE_WEBSOCKET)
+ {"websocket_root", CONFIG_TYPE_DIRECTORY, NULL},
+#endif
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+ {"lua_websocket_pattern", CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
+#endif
+ {"access_control_allow_origin", CONFIG_TYPE_STRING, "*"},
+ {"error_pages", CONFIG_TYPE_DIRECTORY, NULL},
+ {"tcp_nodelay", CONFIG_TYPE_NUMBER, "0"},
+#if !defined(NO_CACHING)
+ {"static_file_max_age", CONFIG_TYPE_NUMBER, "3600"},
+#endif
+
+ {NULL, CONFIG_TYPE_UNKNOWN, NULL}};
+
+/* Check if the config_options and the corresponding enum have compatible
+ * sizes. */
+mg_static_assert((sizeof(config_options) / sizeof(config_options[0]))
+ == (NUM_OPTIONS + 1),
+ "config_options and enum not sync");
+
+enum { REQUEST_HANDLER, WEBSOCKET_HANDLER, AUTH_HANDLER };
+
+struct mg_handler_info {
+ /* Name/Pattern of the URI. */
+ char *uri;
+ size_t uri_len;
+
+ /* handler type */
+ int handler_type;
+
+ /* Handler for http/https or authorization requests. */
+ mg_request_handler handler;
+
+ /* Handler for ws/wss (websocket) requests. */
+ mg_websocket_connect_handler connect_handler;
+ mg_websocket_ready_handler ready_handler;
+ mg_websocket_data_handler data_handler;
+ mg_websocket_close_handler close_handler;
+
+ /* Handler for authorization requests */
+ mg_authorization_handler auth_handler;
+
+ /* User supplied argument for the handler function. */
+ void *cbdata;
+
+ /* next handler in a linked list */
+ struct mg_handler_info *next;
+};
+
+struct mg_context {
+ volatile int stop_flag; /* Should we stop event loop */
+ SSL_CTX *ssl_ctx; /* SSL context */
+ char *config[NUM_OPTIONS]; /* Civetweb configuration parameters */
+ struct mg_callbacks callbacks; /* User-defined callback function */
+ void *user_data; /* User-defined data */
+ int context_type; /* 1 = server context, 2 = client context */
+
+ struct socket *listening_sockets;
+ in_port_t *listening_ports;
+ unsigned int num_listening_sockets;
+
+ volatile int
+ running_worker_threads; /* Number of currently running worker threads */
+ pthread_mutex_t thread_mutex; /* Protects (max|num)_threads */
+ pthread_cond_t thread_cond; /* Condvar for tracking workers terminations */
+
+ struct socket queue[MGSQLEN]; /* Accepted sockets */
+ volatile int sq_head; /* Head of the socket queue */
+ volatile int sq_tail; /* Tail of the socket queue */
+ pthread_cond_t sq_full; /* Signaled when socket is produced */
+ pthread_cond_t sq_empty; /* Signaled when socket is consumed */
+ pthread_t masterthreadid; /* The master thread ID */
+ unsigned int
+ cfg_worker_threads; /* The number of configured worker threads. */
+ pthread_t *workerthreadids; /* The worker thread IDs */
+
+ time_t start_time; /* Server start time, used for authentication */
+ uint64_t auth_nonce_mask; /* Mask for all nonce values */
+ pthread_mutex_t nonce_mutex; /* Protects nonce_count */
+ unsigned long nonce_count; /* Used nonces, used for authentication */
+
+ char *systemName; /* What operating system is running */
+
+ /* linked list of uri handlers */
+ struct mg_handler_info *handlers;
+
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+ /* linked list of shared lua websockets */
+ struct mg_shared_lua_websocket_list *shared_lua_websockets;
+#endif
+
+#ifdef USE_TIMERS
+ struct ttimers *timers;
+#endif
+};
+
+
+struct mg_connection {
+ struct mg_request_info request_info;
+ struct mg_context *ctx;
+ SSL *ssl; /* SSL descriptor */
+ SSL_CTX *client_ssl_ctx; /* SSL context for client connections */
+ struct socket client; /* Connected client */
+ time_t conn_birth_time; /* Time (wall clock) when connection was
+ * established */
+ struct timespec req_time; /* Time (since system start) when the request
+ * was received */
+ int64_t num_bytes_sent; /* Total bytes sent to client */
+ int64_t content_len; /* Content-Length header value */
+ int64_t consumed_content; /* How many bytes of content have been read */
+ int is_chunked; /* Transfer-Encoding is chunked: 0=no, 1=yes:
+ * data available, 2: all data read */
+ size_t chunk_remainder; /* Unread data from the last chunk */
+ char *buf; /* Buffer for received data */
+ char *path_info; /* PATH_INFO part of the URL */
+
+ int must_close; /* 1 if connection must be closed */
+ int in_error_handler; /* 1 if in handler for user defined error
+ * pages */
+ int internal_error; /* 1 if an error occured while processing the
+ * request */
+
+ int buf_size; /* Buffer size */
+ int request_len; /* Size of the request + headers in a buffer */
+ int data_len; /* Total size of data in a buffer */
+ int status_code; /* HTTP reply status code, e.g. 200 */
+ int throttle; /* Throttling, bytes/sec. <= 0 means no
+ * throttle */
+ time_t last_throttle_time; /* Last time throttled data was sent */
+ int64_t last_throttle_bytes; /* Bytes sent this second */
+ pthread_mutex_t mutex; /* Used by mg_(un)lock_connection to ensure
+ * atomic transmissions for websockets */
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+ void *lua_websocket_state; /* Lua_State for a websocket connection */
+#endif
+};
+
+
+static pthread_key_t sTlsKey; /* Thread local storage index */
+static int sTlsInit = 0;
+static int thread_idx_max = 0;
+
+
+struct mg_workerTLS {
+ int is_master;
+ unsigned long thread_idx;
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ HANDLE pthread_cond_helper_mutex;
+#endif
+};
+
+/* Directory entry */
+struct de {
+ struct mg_connection *conn;
+ char *file_name;
+ struct file file;
+};
+
+
+#if defined(USE_WEBSOCKET)
+static int is_websocket_protocol(const struct mg_connection *conn);
+#else
+#define is_websocket_protocol(conn) (0)
+#endif
+
+
+static int
+mg_atomic_inc(volatile int *addr)
+{
+ int ret;
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ /* Depending on the SDK, this function uses either
+ * (volatile unsigned int *) or (volatile LONG *),
+ * so whatever you use, the other SDK is likely to raise a warning. */
+ ret = InterlockedIncrement((volatile long *)addr);
+#elif defined(__GNUC__) \
+ && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
+ ret = __sync_add_and_fetch(addr, 1);
+#else
+ ret = (++(*addr));
+#endif
+ return ret;
+}
+
+
+static int
+mg_atomic_dec(volatile int *addr)
+{
+ int ret;
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ /* Depending on the SDK, this function uses either
+ * (volatile unsigned int *) or (volatile LONG *),
+ * so whatever you use, the other SDK is likely to raise a warning. */
+ ret = InterlockedDecrement((volatile long *)addr);
+#elif defined(__GNUC__) \
+ && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 0)))
+ ret = __sync_sub_and_fetch(addr, 1);
+#else
+ ret = (--(*addr));
+#endif
+ return ret;
+}
+
+#if !defined(NO_THREAD_NAME)
+#if defined(_WIN32) && defined(_MSC_VER)
+/* Set the thread name for debugging purposes in Visual Studio
+ * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+ */
+#pragma pack(push, 8)
+typedef struct tagTHREADNAME_INFO {
+ DWORD dwType; /* Must be 0x1000. */
+ LPCSTR szName; /* Pointer to name (in user addr space). */
+ DWORD dwThreadID; /* Thread ID (-1=caller thread). */
+ DWORD dwFlags; /* Reserved for future use, must be zero. */
+} THREADNAME_INFO;
+#pragma pack(pop)
+#elif defined(__linux__)
+#include <sys/prctl.h>
+#include <sys/sendfile.h>
+#endif
+
+
+static void
+mg_set_thread_name(const char *name)
+{
+ char threadName[16 + 1]; /* 16 = Max. thread length in Linux/OSX/.. */
+
+ mg_snprintf(
+ NULL, NULL, threadName, sizeof(threadName), "civetweb-%s", name);
+
+#if defined(_WIN32)
+#if defined(_MSC_VER)
+ /* Windows and Visual Studio Compiler */
+ __try
+ {
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = threadName;
+ info.dwThreadID = ~0U;
+ info.dwFlags = 0;
+
+ RaiseException(0x406D1388,
+ 0,
+ sizeof(info) / sizeof(ULONG_PTR),
+ (ULONG_PTR *)&info);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ }
+#elif defined(__MINGW32__)
+/* No option known to set thread name for MinGW */
+#endif
+#elif defined(__GLIBC__) \
+ && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 12)))
+ /* pthread_setname_np first appeared in glibc in version 2.12*/
+ (void)pthread_setname_np(pthread_self(), threadName);
+#elif defined(__linux__)
+ /* on linux we can use the old prctl function */
+ (void)prctl(PR_SET_NAME, threadName, 0, 0, 0);
+#endif
+}
+#else /* !defined(NO_THREAD_NAME) */
+void
+mg_set_thread_name(const char *threadName)
+{
+}
+#endif
+
+
+#if defined(MG_LEGACY_INTERFACE)
+const char **
+mg_get_valid_option_names(void)
+{
+ /* This function is deprecated. Use mg_get_valid_options instead. */
+ static const char *
+ data[2 * sizeof(config_options) / sizeof(config_options[0])] = {0};
+ int i;
+
+ for (i = 0; config_options[i].name != NULL; i++) {
+ data[i * 2] = config_options[i].name;
+ data[i * 2 + 1] = config_options[i].default_value;
+ }
+
+ return data;
+}
+#endif
+
+
+const struct mg_option *
+mg_get_valid_options(void)
+{
+ return config_options;
+}
+
+
+static int
+is_file_in_memory(const struct mg_connection *conn,
+ const char *path,
+ struct file *filep)
+{
+ size_t size = 0;
+ if (!conn || !filep) {
+ return 0;
+ }
+
+ if (conn->ctx->callbacks.open_file) {
+ filep->membuf = conn->ctx->callbacks.open_file(conn, path, &size);
+ if (filep->membuf != NULL) {
+ /* NOTE: override filep->size only on success. Otherwise, it might
+ * break constructs like if (!mg_stat() || !mg_fopen()) ... */
+ filep->size = size;
+ }
+ }
+
+ return filep->membuf != NULL;
+}
+
+
+static int
+is_file_opened(const struct file *filep)
+{
+ if (!filep) {
+ return 0;
+ }
+
+ return filep->membuf != NULL || filep->fp != NULL;
+}
+
+
+/* mg_fopen will open a file either in memory or on the disk.
+ * The input parameter path is a string in UTF-8 encoding.
+ * The input parameter mode is the same as for fopen.
+ * Either fp or membuf will be set in the output struct filep.
+ * The function returns 1 on success, 0 on error. */
+static int
+mg_fopen(const struct mg_connection *conn,
+ const char *path,
+ const char *mode,
+ struct file *filep)
+{
+ struct stat st;
+
+ if (!filep) {
+ return 0;
+ }
+
+ /* TODO (high): mg_fopen should only open a file, while mg_stat should
+ * only get the file status. They should not work on different members of
+ * the same structure (bad cohesion). */
+ memset(filep, 0, sizeof(*filep));
+
+ if (stat(path, &st) == 0) {
+ filep->size = (uint64_t)(st.st_size);
+ }
+
+ if (!is_file_in_memory(conn, path, filep)) {
+#ifdef _WIN32
+ wchar_t wbuf[PATH_MAX], wmode[20];
+ path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
+ MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, ARRAY_SIZE(wmode));
+ filep->fp = _wfopen(wbuf, wmode);
+#else
+ /* Linux et al already use unicode. No need to convert. */
+ filep->fp = fopen(path, mode);
+#endif
+ }
+
+ return is_file_opened(filep);
+}
+
+
+static void
+mg_fclose(struct file *filep)
+{
+ if (filep != NULL && filep->fp != NULL) {
+ fclose(filep->fp);
+ }
+}
+
+
+static void
+mg_strlcpy(register char *dst, register const char *src, size_t n)
+{
+ for (; *src != '\0' && n > 1; n--) {
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+}
+
+
+static int
+lowercase(const char *s)
+{
+ return tolower(*(const unsigned char *)s);
+}
+
+
+int
+mg_strncasecmp(const char *s1, const char *s2, size_t len)
+{
+ int diff = 0;
+
+ if (len > 0) {
+ do {
+ diff = lowercase(s1++) - lowercase(s2++);
+ } while (diff == 0 && s1[-1] != '\0' && --len > 0);
+ }
+
+ return diff;
+}
+
+
+int
+mg_strcasecmp(const char *s1, const char *s2)
+{
+ int diff;
+
+ do {
+ diff = lowercase(s1++) - lowercase(s2++);
+ } while (diff == 0 && s1[-1] != '\0');
+
+ return diff;
+}
+
+
+static char *
+mg_strndup(const char *ptr, size_t len)
+{
+ char *p;
+
+ if ((p = (char *)mg_malloc(len + 1)) != NULL) {
+ mg_strlcpy(p, ptr, len + 1);
+ }
+
+ return p;
+}
+
+
+static char *
+mg_strdup(const char *str)
+{
+ return mg_strndup(str, strlen(str));
+}
+
+
+static const char *
+mg_strcasestr(const char *big_str, const char *small_str)
+{
+ size_t i, big_len = strlen(big_str), small_len = strlen(small_str);
+
+ if (big_len >= small_len) {
+ for (i = 0; i <= (big_len - small_len); i++) {
+ if (mg_strncasecmp(big_str + i, small_str, small_len) == 0) {
+ return big_str + i;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/* Return null terminated string of given maximum length.
+ * Report errors if length is exceeded. */
+static void
+mg_vsnprintf(const struct mg_connection *conn,
+ int *truncated,
+ char *buf,
+ size_t buflen,
+ const char *fmt,
+ va_list ap)
+{
+ int n, ok;
+
+ if (buflen == 0) {
+ return;
+ }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wformat-nonliteral"
+/* Using fmt as a non-literal is intended here, since it is mostly called
+ * indirectly by mg_snprintf */
+#endif
+
+ n = (int)vsnprintf_impl(buf, buflen, fmt, ap);
+ ok = (n >= 0) && ((size_t)n < buflen);
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+ if (ok) {
+ if (truncated) {
+ *truncated = 0;
+ }
+ } else {
+ if (truncated) {
+ *truncated = 1;
+ }
+ mg_cry(conn,
+ "truncating vsnprintf buffer: [%.*s]",
+ (int)((buflen > 200) ? 200 : (buflen - 1)),
+ buf);
+ n = (int)buflen - 1;
+ }
+ buf[n] = '\0';
+}
+
+
+static void
+mg_snprintf(const struct mg_connection *conn,
+ int *truncated,
+ char *buf,
+ size_t buflen,
+ const char *fmt,
+ ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ mg_vsnprintf(conn, truncated, buf, buflen, fmt, ap);
+ va_end(ap);
+}
+
+
+static int
+get_option_index(const char *name)
+{
+ int i;
+
+ for (i = 0; config_options[i].name != NULL; i++) {
+ if (strcmp(config_options[i].name, name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+const char *
+mg_get_option(const struct mg_context *ctx, const char *name)
+{
+ int i;
+ if ((i = get_option_index(name)) == -1) {
+ return NULL;
+ } else if (!ctx || ctx->config[i] == NULL) {
+ return "";
+ } else {
+ return ctx->config[i];
+ }
+}
+
+
+struct mg_context *
+mg_get_context(const struct mg_connection *conn)
+{
+ return (conn == NULL) ? (struct mg_context *)NULL : (conn->ctx);
+}
+
+
+void *
+mg_get_user_data(const struct mg_context *ctx)
+{
+ return (ctx == NULL) ? NULL : ctx->user_data;
+}
+
+
+void
+mg_set_user_connection_data(struct mg_connection *conn, void *data)
+{
+ if (conn != NULL) {
+ conn->request_info.conn_data = data;
+ }
+}
+
+
+void *
+mg_get_user_connection_data(const struct mg_connection *conn)
+{
+ if (conn != NULL) {
+ return conn->request_info.conn_data;
+ }
+ return NULL;
+}
+
+
+size_t
+mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl)
+{
+ size_t i;
+ if (!ctx) {
+ return 0;
+ }
+ for (i = 0; i < size && i < ctx->num_listening_sockets; i++) {
+ ssl[i] = ctx->listening_sockets[i].is_ssl;
+ ports[i] = ctx->listening_ports[i];
+ }
+ return i;
+}
+
+
+int
+mg_get_server_ports(const struct mg_context *ctx,
+ int size,
+ struct mg_server_ports *ports)
+{
+ int i, cnt = 0;
+
+ if (size <= 0) {
+ return -1;
+ }
+ memset(ports, 0, sizeof(*ports) * (size_t)size);
+ if (!ctx) {
+ return -1;
+ }
+ if (!ctx->listening_sockets || !ctx->listening_ports) {
+ return -1;
+ }
+
+ for (i = 0; (i < size) && (i < (int)ctx->num_listening_sockets); i++) {
+
+ ports[cnt].port = ctx->listening_ports[i];
+ ports[cnt].is_ssl = ctx->listening_sockets[i].is_ssl;
+ ports[cnt].is_redirect = ctx->listening_sockets[i].ssl_redir;
+
+ if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET) {
+ /* IPv4 */
+ ports[cnt].protocol = 1;
+ cnt++;
+ } else if (ctx->listening_sockets[i].lsa.sa.sa_family == AF_INET6) {
+ /* IPv6 */
+ ports[cnt].protocol = 3;
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
+
+static void
+sockaddr_to_string(char *buf, size_t len, const union usa *usa)
+{
+ buf[0] = '\0';
+
+ if (!usa) {
+ return;
+ }
+
+ if (usa->sa.sa_family == AF_INET) {
+ getnameinfo(&usa->sa,
+ sizeof(usa->sin),
+ buf,
+ (unsigned)len,
+ NULL,
+ 0,
+ NI_NUMERICHOST);
+ }
+#if defined(USE_IPV6)
+ else if (usa->sa.sa_family == AF_INET6) {
+ getnameinfo(&usa->sa,
+ sizeof(usa->sin6),
+ buf,
+ (unsigned)len,
+ NULL,
+ 0,
+ NI_NUMERICHOST);
+ }
+#endif
+}
+
+
+/* Convert time_t to a string. According to RFC2616, Sec 14.18, this must be
+ * included in all responses other than 100, 101, 5xx. */
+static void
+gmt_time_string(char *buf, size_t buf_len, time_t *t)
+{
+ struct tm *tm;
+
+ tm = ((t != NULL) ? gmtime(t) : NULL);
+ if (tm != NULL) {
+ strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
+ } else {
+ mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
+ buf[buf_len - 1] = '\0';
+ }
+}
+
+
+/* difftime for struct timespec. Return value is in seconds. */
+static double
+mg_difftimespec(const struct timespec *ts_now, const struct timespec *ts_before)
+{
+ return (double)(ts_now->tv_nsec - ts_before->tv_nsec) * 1.0E-9
+ + (double)(ts_now->tv_sec - ts_before->tv_sec);
+}
+
+
+/* Print error message to the opened error log stream. */
+void
+mg_cry(const struct mg_connection *conn, const char *fmt, ...)
+{
+ char buf[MG_BUF_LEN], src_addr[IP_ADDR_STR_LEN];
+ va_list ap;
+ struct file fi;
+ time_t timestamp;
+
+ va_start(ap, fmt);
+ IGNORE_UNUSED_RESULT(vsnprintf_impl(buf, sizeof(buf), fmt, ap));
+ va_end(ap);
+ buf[sizeof(buf) - 1] = 0;
+
+ if (!conn) {
+ puts(buf);
+ return;
+ }
+
+ /* Do not lock when getting the callback value, here and below.
+ * I suppose this is fine, since function cannot disappear in the
+ * same way string option can. */
+ if ((conn->ctx->callbacks.log_message == NULL)
+ || (conn->ctx->callbacks.log_message(conn, buf) == 0)) {
+
+ if (conn->ctx->config[ERROR_LOG_FILE] != NULL) {
+ if (mg_fopen(conn, conn->ctx->config[ERROR_LOG_FILE], "a+", &fi)
+ == 0) {
+ fi.fp = NULL;
+ }
+ } else {
+ fi.fp = NULL;
+ }
+
+ if (fi.fp != NULL) {
+ flockfile(fi.fp);
+ timestamp = time(NULL);
+
+ sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+ fprintf(fi.fp,
+ "[%010lu] [error] [client %s] ",
+ (unsigned long)timestamp,
+ src_addr);
+
+ if (conn->request_info.request_method != NULL) {
+ fprintf(fi.fp,
+ "%s %s: ",
+ conn->request_info.request_method,
+ conn->request_info.request_uri);
+ }
+
+ fprintf(fi.fp, "%s", buf);
+ fputc('\n', fi.fp);
+ fflush(fi.fp);
+ funlockfile(fi.fp);
+ mg_fclose(&fi);
+ }
+ }
+}
+
+
+/* Return fake connection structure. Used for logging, if connection
+ * is not applicable at the moment of logging. */
+static struct mg_connection *
+fc(struct mg_context *ctx)
+{
+ static struct mg_connection fake_connection;
+ fake_connection.ctx = ctx;
+ return &fake_connection;
+}
+
+
+const char *
+mg_version(void)
+{
+ return CIVETWEB_VERSION;
+}
+
+
+const struct mg_request_info *
+mg_get_request_info(const struct mg_connection *conn)
+{
+ if (!conn) {
+ return NULL;
+ }
+ return &conn->request_info;
+}
+
+
+/* Skip the characters until one of the delimiters characters found.
+ * 0-terminate resulting word. Skip the delimiter and following whitespaces.
+ * Advance pointer to buffer to the next word. Return found 0-terminated word.
+ * Delimiters can be quoted with quotechar. */
+static char *
+skip_quoted(char **buf,
+ const char *delimiters,
+ const char *whitespace,
+ char quotechar)
+{
+ char *p, *begin_word, *end_word, *end_whitespace;
+
+ begin_word = *buf;
+ end_word = begin_word + strcspn(begin_word, delimiters);
+
+ /* Check for quotechar */
+ if (end_word > begin_word) {
+ p = end_word - 1;
+ while (*p == quotechar) {
+ /* While the delimiter is quoted, look for the next delimiter. */
+ /* This happens, e.g., in calls from parse_auth_header,
+ * if the user name contains a " character. */
+
+ /* If there is anything beyond end_word, copy it. */
+ if (*end_word != '\0') {
+ size_t end_off = strcspn(end_word + 1, delimiters);
+ memmove(p, end_word, end_off + 1);
+ p += end_off; /* p must correspond to end_word - 1 */
+ end_word += end_off + 1;
+ } else {
+ *p = '\0';
+ break;
+ }
+ }
+ for (p++; p < end_word; p++) {
+ *p = '\0';
+ }
+ }
+
+ if (*end_word == '\0') {
+ *buf = end_word;
+ } else {
+ end_whitespace = end_word + 1 + strspn(end_word + 1, whitespace);
+
+ for (p = end_word; p < end_whitespace; p++) {
+ *p = '\0';
+ }
+
+ *buf = end_whitespace;
+ }
+
+ return begin_word;
+}
+
+
+/* Simplified version of skip_quoted without quote char
+ * and whitespace == delimiters */
+static char *
+skip(char **buf, const char *delimiters)
+{
+ return skip_quoted(buf, delimiters, delimiters, 0);
+}
+
+
+/* Return HTTP header value, or NULL if not found. */
+static const char *
+get_header(const struct mg_request_info *ri, const char *name)
+{
+ int i;
+ if (ri) {
+ for (i = 0; i < ri->num_headers; i++) {
+ if (!mg_strcasecmp(name, ri->http_headers[i].name)) {
+ return ri->http_headers[i].value;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+const char *
+mg_get_header(const struct mg_connection *conn, const char *name)
+{
+ if (!conn) {
+ return NULL;
+ }
+
+ return get_header(&conn->request_info, name);
+}
+
+
+/* A helper function for traversing a comma separated list of values.
+ * It returns a list pointer shifted to the next value, or NULL if the end
+ * of the list found.
+ * Value is stored in val vector. If value has form "x=y", then eq_val
+ * vector is initialized to point to the "y" part, and val vector length
+ * is adjusted to point only to "x". */
+static const char *
+next_option(const char *list, struct vec *val, struct vec *eq_val)
+{
+ int end;
+
+reparse:
+ if (val == NULL || list == NULL || *list == '\0') {
+ /* End of the list */
+ list = NULL;
+ } else {
+ /* Skip over leading LWS */
+ while (*list == ' ' || *list == '\t')
+ list++;
+
+ val->ptr = list;
+ if ((list = strchr(val->ptr, ',')) != NULL) {
+ /* Comma found. Store length and shift the list ptr */
+ val->len = ((size_t)(list - val->ptr));
+ list++;
+ } else {
+ /* This value is the last one */
+ list = val->ptr + strlen(val->ptr);
+ val->len = ((size_t)(list - val->ptr));
+ }
+
+ /* Adjust length for trailing LWS */
+ end = (int)val->len - 1;
+ while (end >= 0 && (val->ptr[end] == ' ' || val->ptr[end] == '\t'))
+ end--;
+ val->len = (size_t)(end + 1);
+
+ if (val->len == 0) {
+ /* Ignore any empty entries. */
+ goto reparse;
+ }
+
+ if (eq_val != NULL) {
+ /* Value has form "x=y", adjust pointers and lengths
+ * so that val points to "x", and eq_val points to "y". */
+ eq_val->len = 0;
+ eq_val->ptr = (const char *)memchr(val->ptr, '=', val->len);
+ if (eq_val->ptr != NULL) {
+ eq_val->ptr++; /* Skip over '=' character */
+ eq_val->len = ((size_t)(val->ptr - eq_val->ptr)) + val->len;
+ val->len = ((size_t)(eq_val->ptr - val->ptr)) - 1;
+ }
+ }
+ }
+
+ return list;
+}
+
+/* A helper function for checking if a comma separated list of values contains
+ * the given option (case insensitvely).
+ * 'header' can be NULL, in which case false is returned. */
+static int
+header_has_option(const char *header, const char *option)
+{
+ struct vec opt_vec;
+ struct vec eq_vec;
+
+ assert(option != NULL);
+ assert(option[0] != '\0');
+
+ while ((header = next_option(header, &opt_vec, &eq_vec)) != NULL) {
+ if (mg_strncasecmp(option, opt_vec.ptr, opt_vec.len) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Perform case-insensitive match of string against pattern */
+static int
+match_prefix(const char *pattern, size_t pattern_len, const char *str)
+{
+ const char *or_str;
+ size_t i;
+ int j, len, res;
+
+ if ((or_str = (const char *)memchr(pattern, '|', pattern_len)) != NULL) {
+ res = match_prefix(pattern, (size_t)(or_str - pattern), str);
+ return res > 0 ? res : match_prefix(or_str + 1,
+ (size_t)((pattern + pattern_len)
+ - (or_str + 1)),
+ str);
+ }
+
+ for (i = 0, j = 0; i < pattern_len; i++, j++) {
+ if (pattern[i] == '?' && str[j] != '\0') {
+ continue;
+ } else if (pattern[i] == '$') {
+ return str[j] == '\0' ? j : -1;
+ } else if (pattern[i] == '*') {
+ i++;
+ if (pattern[i] == '*') {
+ i++;
+ len = (int)strlen(str + j);
+ } else {
+ len = (int)strcspn(str + j, "/");
+ }
+ if (i == pattern_len) {
+ return j + len;
+ }
+ do {
+ res = match_prefix(pattern + i, pattern_len - i, str + j + len);
+ } while (res == -1 && len-- > 0);
+ return res == -1 ? -1 : j + res + len;
+ } else if (lowercase(&pattern[i]) != lowercase(&str[j])) {
+ return -1;
+ }
+ }
+ return j;
+}
+
+
+/* HTTP 1.1 assumes keep alive if "Connection:" header is not set
+ * This function must tolerate situations when connection info is not
+ * set up, for example if request parsing failed. */
+static int
+should_keep_alive(const struct mg_connection *conn)
+{
+ if (conn != NULL) {
+ const char *http_version = conn->request_info.http_version;
+ const char *header = mg_get_header(conn, "Connection");
+ if (conn->must_close || conn->internal_error || conn->status_code == 401
+ || mg_strcasecmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes") != 0
+ || (header != NULL && !header_has_option(header, "keep-alive"))
+ || (header == NULL && http_version
+ && 0 != strcmp(http_version, "1.1"))) {
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+static int
+should_decode_url(const struct mg_connection *conn)
+{
+ if (!conn || !conn->ctx) {
+ return 0;
+ }
+
+ return (mg_strcasecmp(conn->ctx->config[DECODE_URL], "yes") == 0);
+}
+
+
+static const char *
+suggest_connection_header(const struct mg_connection *conn)
+{
+ return should_keep_alive(conn) ? "keep-alive" : "close";
+}
+
+
+static int
+send_no_cache_header(struct mg_connection *conn)
+{
+ /* Send all current and obsolete cache opt-out directives. */
+ return mg_printf(conn,
+ "Cache-Control: no-cache, no-store, "
+ "must-revalidate, private, max-age=0\r\n"
+ "Pragma: no-cache\r\n"
+ "Expires: 0\r\n");
+}
+
+
+static int
+send_static_cache_header(struct mg_connection *conn)
+{
+#if !defined(NO_CACHING)
+ /* Read the server config to check how long a file may be cached.
+ * The configuration is in seconds. */
+ int max_age = atoi(conn->ctx->config[STATIC_FILE_MAX_AGE]);
+ if (max_age <= 0) {
+ /* 0 means "do not cache". All values <0 are reserved
+ * and may be used differently in the future. */
+ /* If a file should not be cached, do not only send
+ * max-age=0, but also pragmas and Expires headers. */
+ return send_no_cache_header(conn);
+ }
+
+ /* Use "Cache-Control: max-age" instead of "Expires" header.
+ * Reason: see https://www.mnot.net/blog/2007/05/15/expires_max-age */
+ /* See also https://www.mnot.net/cache_docs/ */
+ /* According to RFC 2616, Section 14.21, caching times should not exceed
+ * one year. A year with 365 days corresponds to 31536000 seconds, a leap
+ * year to 31622400 seconds. For the moment, we just send whatever has
+ * been configured, still the behavior for >1 year should be considered
+ * as undefined. */
+ return mg_printf(conn, "Cache-Control: max-age=%u\r\n", (unsigned)max_age);
+#else /* NO_CACHING */
+ return send_no_cache_header(conn);
+#endif /* !NO_CACHING */
+}
+
+
+static void handle_file_based_request(struct mg_connection *conn,
+ const char *path,
+ struct file *filep);
+
+static int
+mg_stat(struct mg_connection *conn, const char *path, struct file *filep);
+
+
+const char *
+mg_get_response_code_text(struct mg_connection *conn, int response_code)
+{
+ /* See IANA HTTP status code assignment:
+ * http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
+ */
+
+ switch (response_code) {
+ /* RFC2616 Section 10.1 - Informational 1xx */
+ case 100:
+ return "Continue"; /* RFC2616 Section 10.1.1 */
+ case 101:
+ return "Switching Protocols"; /* RFC2616 Section 10.1.2 */
+ case 102:
+ return "Processing"; /* RFC2518 Section 10.1 */
+
+ /* RFC2616 Section 10.2 - Successful 2xx */
+ case 200:
+ return "OK"; /* RFC2616 Section 10.2.1 */
+ case 201:
+ return "Created"; /* RFC2616 Section 10.2.2 */
+ case 202:
+ return "Accepted"; /* RFC2616 Section 10.2.3 */
+ case 203:
+ return "Non-Authoritative Information"; /* RFC2616 Section 10.2.4 */
+ case 204:
+ return "No Content"; /* RFC2616 Section 10.2.5 */
+ case 205:
+ return "Reset Content"; /* RFC2616 Section 10.2.6 */
+ case 206:
+ return "Partial Content"; /* RFC2616 Section 10.2.7 */
+ case 207:
+ return "Multi-Status"; /* RFC2518 Section 10.2, RFC4918 Section 11.1 */
+ case 208:
+ return "Already Reported"; /* RFC5842 Section 7.1 */
+
+ case 226:
+ return "IM used"; /* RFC3229 Section 10.4.1 */
+
+ /* RFC2616 Section 10.3 - Redirection 3xx */
+ case 300:
+ return "Multiple Choices"; /* RFC2616 Section 10.3.1 */
+ case 301:
+ return "Moved Permanently"; /* RFC2616 Section 10.3.2 */
+ case 302:
+ return "Found"; /* RFC2616 Section 10.3.3 */
+ case 303:
+ return "See Other"; /* RFC2616 Section 10.3.4 */
+ case 304:
+ return "Not Modified"; /* RFC2616 Section 10.3.5 */
+ case 305:
+ return "Use Proxy"; /* RFC2616 Section 10.3.6 */
+ case 307:
+ return "Temporary Redirect"; /* RFC2616 Section 10.3.8 */
+ case 308:
+ return "Permanent Redirect"; /* RFC7238 Section 3 */
+
+ /* RFC2616 Section 10.4 - Client Error 4xx */
+ case 400:
+ return "Bad Request"; /* RFC2616 Section 10.4.1 */
+ case 401:
+ return "Unauthorized"; /* RFC2616 Section 10.4.2 */
+ case 402:
+ return "Payment Required"; /* RFC2616 Section 10.4.3 */
+ case 403:
+ return "Forbidden"; /* RFC2616 Section 10.4.4 */
+ case 404:
+ return "Not Found"; /* RFC2616 Section 10.4.5 */
+ case 405:
+ return "Method Not Allowed"; /* RFC2616 Section 10.4.6 */
+ case 406:
+ return "Not Acceptable"; /* RFC2616 Section 10.4.7 */
+ case 407:
+ return "Proxy Authentication Required"; /* RFC2616 Section 10.4.8 */
+ case 408:
+ return "Request Time-out"; /* RFC2616 Section 10.4.9 */
+ case 409:
+ return "Conflict"; /* RFC2616 Section 10.4.10 */
+ case 410:
+ return "Gone"; /* RFC2616 Section 10.4.11 */
+ case 411:
+ return "Length Required"; /* RFC2616 Section 10.4.12 */
+ case 412:
+ return "Precondition Failed"; /* RFC2616 Section 10.4.13 */
+ case 413:
+ return "Request Entity Too Large"; /* RFC2616 Section 10.4.14 */
+ case 414:
+ return "Request-URI Too Large"; /* RFC2616 Section 10.4.15 */
+ case 415:
+ return "Unsupported Media Type"; /* RFC2616 Section 10.4.16 */
+ case 416:
+ return "Requested range not satisfiable"; /* RFC2616 Section 10.4.17 */
+ case 417:
+ return "Expectation Failed"; /* RFC2616 Section 10.4.18 */
+
+ case 421:
+ return "Misdirected Request"; /* RFC7540 Section 9.1.2 */
+ case 422:
+ return "Unproccessable entity"; /* RFC2518 Section 10.3, RFC4918
+ * Section 11.2 */
+ case 423:
+ return "Locked"; /* RFC2518 Section 10.4, RFC4918 Section 11.3 */
+ case 424:
+ return "Failed Dependency"; /* RFC2518 Section 10.5, RFC4918
+ * Section 11.4 */
+
+ case 426:
+ return "Upgrade Required"; /* RFC 2817 Section 4 */
+
+ case 428:
+ return "Precondition Required"; /* RFC 6585, Section 3 */
+ case 429:
+ return "Too Many Requests"; /* RFC 6585, Section 4 */
+
+ case 431:
+ return "Request Header Fields Too Large"; /* RFC 6585, Section 5 */
+
+ case 451:
+ return "Unavailable For Legal Reasons"; /* draft-tbray-http-legally-restricted-status-05,
+ * Section 3 */
+
+ /* RFC2616 Section 10.5 - Server Error 5xx */
+ case 500:
+ return "Internal Server Error"; /* RFC2616 Section 10.5.1 */
+ case 501:
+ return "Not Implemented"; /* RFC2616 Section 10.5.2 */
+ case 502:
+ return "Bad Gateway"; /* RFC2616 Section 10.5.3 */
+ case 503:
+ return "Service Unavailable"; /* RFC2616 Section 10.5.4 */
+ case 504:
+ return "Gateway Time-out"; /* RFC2616 Section 10.5.5 */
+ case 505:
+ return "HTTP Version not supported"; /* RFC2616 Section 10.5.6 */
+ case 506:
+ return "Variant Also Negotiates"; /* RFC 2295, Section 8.1 */
+ case 507:
+ return "Insufficient Storage"; /* RFC2518 Section 10.6, RFC4918
+ * Section 11.5 */
+ case 508:
+ return "Loop Detected"; /* RFC5842 Section 7.1 */
+
+ case 510:
+ return "Not Extended"; /* RFC 2774, Section 7 */
+ case 511:
+ return "Network Authentication Required"; /* RFC 6585, Section 6 */
+
+ /* Other status codes, not shown in the IANA HTTP status code assignment.
+ * E.g., "de facto" standards due to common use, ... */
+ case 418:
+ return "I am a teapot"; /* RFC2324 Section 2.3.2 */
+ case 419:
+ return "Authentication Timeout"; /* common use */
+ case 420:
+ return "Enhance Your Calm"; /* common use */
+ case 440:
+ return "Login Timeout"; /* common use */
+ case 509:
+ return "Bandwidth Limit Exceeded"; /* common use */
+
+ default:
+ /* This error code is unknown. This should not happen. */
+ if (conn) {
+ mg_cry(conn, "Unknown HTTP response code: %u", response_code);
+ }
+
+ /* Return at least a category according to RFC 2616 Section 10. */
+ if (response_code >= 100 && response_code < 200) {
+ /* Unknown informational status code */
+ return "Information";
+ }
+ if (response_code >= 200 && response_code < 300) {
+ /* Unknown success code */
+ return "Success";
+ }
+ if (response_code >= 300 && response_code < 400) {
+ /* Unknown redirection code */
+ return "Redirection";
+ }
+ if (response_code >= 400 && response_code < 500) {
+ /* Unknown request error code */
+ return "Client Error";
+ }
+ if (response_code >= 500 && response_code < 600) {
+ /* Unknown server error code */
+ return "Server Error";
+ }
+
+ /* Response code not even within reasonable range */
+ return "";
+ }
+}
+
+
+static void send_http_error(struct mg_connection *,
+ int,
+ PRINTF_FORMAT_STRING(const char *fmt),
+ ...) PRINTF_ARGS(3, 4);
+
+static void
+send_http_error(struct mg_connection *conn, int status, const char *fmt, ...)
+{
+ char buf[MG_BUF_LEN];
+ va_list ap;
+ int len, i, page_handler_found, scope, truncated;
+ char date[64];
+ time_t curtime = time(NULL);
+ const char *error_handler = NULL;
+ struct file error_page_file = STRUCT_FILE_INITIALIZER;
+ const char *error_page_file_ext, *tstr;
+
+ const char *status_text = mg_get_response_code_text(conn, status);
+
+ if (conn == NULL) {
+ return;
+ }
+
+ conn->status_code = status;
+ if (conn->in_error_handler || conn->ctx->callbacks.http_error == NULL
+ || conn->ctx->callbacks.http_error(conn, status)) {
+ if (!conn->in_error_handler) {
+ /* Send user defined error pages, if defined */
+ error_handler = conn->ctx->config[ERROR_PAGES];
+ error_page_file_ext = conn->ctx->config[INDEX_FILES];
+ page_handler_found = 0;
+ if (error_handler != NULL) {
+ for (scope = 1; (scope <= 3) && !page_handler_found; scope++) {
+ switch (scope) {
+ case 1: /* Handler for specific error, e.g. 404 error */
+ mg_snprintf(conn,
+ &truncated,
+ buf,
+ sizeof(buf) - 32,
+ "%serror%03u.",
+ error_handler,
+ status);
+ break;
+ case 2: /* Handler for error group, e.g., 5xx error handler
+ * for all server errors (500-599) */
+ mg_snprintf(conn,
+ &truncated,
+ buf,
+ sizeof(buf) - 32,
+ "%serror%01uxx.",
+ error_handler,
+ status / 100);
+ break;
+ default: /* Handler for all errors */
+ mg_snprintf(conn,
+ &truncated,
+ buf,
+ sizeof(buf) - 32,
+ "%serror.",
+ error_handler);
+ break;
+ }
+
+ /* String truncation in buf may only occur if error_handler
+ * is too long. This string is from the config, not from a
+ * client. */
+ (void)truncated;
+
+ len = (int)strlen(buf);
+
+ tstr = strchr(error_page_file_ext, '.');
+
+ while (tstr) {
+ for (i = 1; i < 32 && tstr[i] != 0 && tstr[i] != ',';
+ i++)
+ buf[len + i - 1] = tstr[i];
+ buf[len + i - 1] = 0;
+ if (mg_stat(conn, buf, &error_page_file)) {
+ page_handler_found = 1;
+ break;
+ }
+ tstr = strchr(tstr + i, '.');
+ }
+ }
+ }
+
+ if (page_handler_found) {
+ conn->in_error_handler = 1;
+ handle_file_based_request(conn, buf, &error_page_file);
+ conn->in_error_handler = 0;
+ return;
+ }
+ }
+
+ /* No custom error page. Send default error page. */
+ gmt_time_string(date, sizeof(date), &curtime);
+
+ conn->must_close = 1;
+ mg_printf(conn, "HTTP/1.1 %d %s\r\n", status, status_text);
+ send_no_cache_header(conn);
+ mg_printf(conn,
+ "Date: %s\r\n"
+ "Connection: close\r\n\r\n",
+ date);
+
+ /* Errors 1xx, 204 and 304 MUST NOT send a body */
+ if (status > 199 && status != 204 && status != 304) {
+
+ mg_printf(conn, "Error %d: %s\n", status, status_text);
+
+ if (fmt != NULL) {
+ va_start(ap, fmt);
+ mg_vsnprintf(conn, NULL, buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ mg_write(conn, buf, strlen(buf));
+ DEBUG_TRACE("Error %i - [%s]", status, buf);
+ }
+
+ } else {
+ /* No body allowed. Close the connection. */
+ DEBUG_TRACE("Error %i", status);
+ }
+ }
+}
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+/* Create substitutes for POSIX functions in Win32. */
+
+#if defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+
+static int
+pthread_mutex_init(pthread_mutex_t *mutex, void *unused)
+{
+ (void)unused;
+ *mutex = CreateMutex(NULL, FALSE, NULL);
+ return *mutex == NULL ? -1 : 0;
+}
+
+
+static int
+pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+ return CloseHandle(*mutex) == 0 ? -1 : 0;
+}
+
+
+static int
+pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ return WaitForSingleObject(*mutex, INFINITE) == WAIT_OBJECT_0 ? 0 : -1;
+}
+
+
+#ifdef ENABLE_UNUSED_PTHREAD_FUNCTIONS
+static int
+pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ switch (WaitForSingleObject(*mutex, 0)) {
+ case WAIT_OBJECT_0:
+ return 0;
+ case WAIT_TIMEOUT:
+ return -2; /* EBUSY */
+ }
+ return -1;
+}
+#endif
+
+
+static int
+pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+ return ReleaseMutex(*mutex) == 0 ? -1 : 0;
+}
+
+
+#ifndef WIN_PTHREADS_TIME_H
+static int
+clock_gettime(clockid_t clk_id, struct timespec *tp)
+{
+ FILETIME ft;
+ ULARGE_INTEGER li;
+ BOOL ok = FALSE;
+ double d;
+ static double perfcnt_per_sec = 0.0;
+
+ if (tp) {
+ memset(tp, 0, sizeof(*tp));
+ if (clk_id == CLOCK_REALTIME) {
+ GetSystemTimeAsFileTime(&ft);
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ li.QuadPart -= 116444736000000000; /* 1.1.1970 in filedate */
+ tp->tv_sec = (time_t)(li.QuadPart / 10000000);
+ tp->tv_nsec = (long)(li.QuadPart % 10000000) * 100;
+ ok = TRUE;
+ } else if (clk_id == CLOCK_MONOTONIC) {
+ if (perfcnt_per_sec == 0.0) {
+ QueryPerformanceFrequency((LARGE_INTEGER *)&li);
+ perfcnt_per_sec = 1.0 / li.QuadPart;
+ }
+ if (perfcnt_per_sec != 0.0) {
+ QueryPerformanceCounter((LARGE_INTEGER *)&li);
+ d = li.QuadPart * perfcnt_per_sec;
+ tp->tv_sec = (time_t)d;
+ d -= tp->tv_sec;
+ tp->tv_nsec = (long)(d * 1.0E9);
+ ok = TRUE;
+ }
+ }
+ }
+
+ return ok ? 0 : -1;
+}
+#endif
+
+
+static int
+pthread_cond_init(pthread_cond_t *cv, const void *unused)
+{
+ (void)unused;
+ InitializeCriticalSection(&cv->threadIdSec);
+ cv->waitingthreadcount = 0;
+ cv->waitingthreadhdls =
+ (pthread_t *)mg_calloc(MAX_WORKER_THREADS, sizeof(pthread_t));
+ return (cv->waitingthreadhdls != NULL) ? 0 : -1;
+}
+
+
+static int
+pthread_cond_timedwait(pthread_cond_t *cv,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ struct mg_workerTLS *tls =
+ (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
+ int ok;
+ struct timespec tsnow;
+ int64_t nsnow, nswaitabs, nswaitrel;
+ DWORD mswaitrel;
+
+ EnterCriticalSection(&cv->threadIdSec);
+ assert(cv->waitingthreadcount < MAX_WORKER_THREADS);
+ cv->waitingthreadhdls[cv->waitingthreadcount] =
+ tls->pthread_cond_helper_mutex;
+ cv->waitingthreadcount++;
+ LeaveCriticalSection(&cv->threadIdSec);
+
+ if (abstime) {
+ clock_gettime(CLOCK_REALTIME, &tsnow);
+ nsnow = (((int64_t)tsnow.tv_sec) * 1000000000) + tsnow.tv_nsec;
+ nswaitabs =
+ (((int64_t)abstime->tv_sec) * 1000000000) + abstime->tv_nsec;
+ nswaitrel = nswaitabs - nsnow;
+ if (nswaitrel < 0) {
+ nswaitrel = 0;
+ }
+ mswaitrel = (DWORD)(nswaitrel / 1000000);
+ } else {
+ mswaitrel = INFINITE;
+ }
+
+ pthread_mutex_unlock(mutex);
+ ok = (WAIT_OBJECT_0
+ == WaitForSingleObject(tls->pthread_cond_helper_mutex, mswaitrel));
+ pthread_mutex_lock(mutex);
+
+ return ok ? 0 : -1;
+}
+
+
+static int
+pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex)
+{
+ return pthread_cond_timedwait(cv, mutex, NULL);
+}
+
+
+static int
+pthread_cond_signal(pthread_cond_t *cv)
+{
+ int i;
+ HANDLE wkup = NULL;
+ BOOL ok = FALSE;
+
+ EnterCriticalSection(&cv->threadIdSec);
+ if (cv->waitingthreadcount) {
+ wkup = cv->waitingthreadhdls[0];
+ ok = SetEvent(wkup);
+
+ for (i = 1; i < cv->waitingthreadcount; i++) {
+ cv->waitingthreadhdls[i - 1] = cv->waitingthreadhdls[i];
+ }
+ cv->waitingthreadcount--;
+
+ assert(ok);
+ }
+ LeaveCriticalSection(&cv->threadIdSec);
+
+ return ok ? 0 : 1;
+}
+
+
+static int
+pthread_cond_broadcast(pthread_cond_t *cv)
+{
+ EnterCriticalSection(&cv->threadIdSec);
+ while (cv->waitingthreadcount) {
+ pthread_cond_signal(cv);
+ }
+ LeaveCriticalSection(&cv->threadIdSec);
+
+ return 0;
+}
+
+
+static int
+pthread_cond_destroy(pthread_cond_t *cv)
+{
+ EnterCriticalSection(&cv->threadIdSec);
+ assert(cv->waitingthreadcount == 0);
+ mg_free(cv->waitingthreadhdls);
+ cv->waitingthreadhdls = 0;
+ LeaveCriticalSection(&cv->threadIdSec);
+ DeleteCriticalSection(&cv->threadIdSec);
+
+ return 0;
+}
+
+
+#if defined(__MINGW32__)
+/* Enable unused function warning again */
+#pragma GCC diagnostic pop
+#endif
+
+
+/* For Windows, change all slashes to backslashes in path names. */
+static void
+change_slashes_to_backslashes(char *path)
+{
+ int i;
+
+ for (i = 0; path[i] != '\0'; i++) {
+ if (path[i] == '/') {
+ path[i] = '\\';
+ }
+
+ /* remove double backslash (check i > 0 to preserve UNC paths,
+ * like \\server\file.txt) */
+ if ((path[i] == '\\') && (i > 0)) {
+ while (path[i + 1] == '\\' || path[i + 1] == '/') {
+ (void)memmove(path + i + 1, path + i + 2, strlen(path + i + 1));
+ }
+ }
+ }
+}
+
+
+static int
+mg_wcscasecmp(const wchar_t *s1, const wchar_t *s2)
+{
+ int diff;
+
+ do {
+ diff = tolower(*s1) - tolower(*s2);
+ s1++;
+ s2++;
+ } while (diff == 0 && s1[-1] != '\0');
+
+ return diff;
+}
+
+
+/* Encode 'path' which is assumed UTF-8 string, into UNICODE string.
+ * wbuf and wbuf_len is a target buffer and its length. */
+static void
+path_to_unicode(const struct mg_connection *conn,
+ const char *path,
+ wchar_t *wbuf,
+ size_t wbuf_len)
+{
+ char buf[PATH_MAX], buf2[PATH_MAX];
+ wchar_t wbuf2[MAX_PATH + 1];
+ DWORD long_len, err;
+ int (*fcompare)(const wchar_t *, const wchar_t *) = mg_wcscasecmp;
+
+ mg_strlcpy(buf, path, sizeof(buf));
+ change_slashes_to_backslashes(buf);
+
+ /* Convert to Unicode and back. If doubly-converted string does not
+ * match the original, something is fishy, reject. */
+ memset(wbuf, 0, wbuf_len * sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, (int)wbuf_len);
+ WideCharToMultiByte(
+ CP_UTF8, 0, wbuf, (int)wbuf_len, buf2, sizeof(buf2), NULL, NULL);
+ if (strcmp(buf, buf2) != 0) {
+ wbuf[0] = L'\0';
+ }
+
+ /* TODO: Add a configuration to switch between case sensitive and
+ * case insensitive URIs for Windows server. */
+ /*
+ if (conn) {
+ if (conn->ctx->config[WINDOWS_CASE_SENSITIVE]) {
+ fcompare = wcscmp;
+ }
+ }
+ */
+ (void)conn; /* conn is currently unused */
+
+ /* Only accept a full file path, not a Windows short (8.3) path. */
+ memset(wbuf2, 0, ARRAY_SIZE(wbuf2) * sizeof(wchar_t));
+ long_len = GetLongPathNameW(wbuf, wbuf2, ARRAY_SIZE(wbuf2) - 1);
+ if (long_len == 0) {
+ err = GetLastError();
+ if (err == ERROR_FILE_NOT_FOUND) {
+ /* File does not exist. This is not always a problem here. */
+ return;
+ }
+ }
+ if ((long_len >= ARRAY_SIZE(wbuf2)) || (fcompare(wbuf, wbuf2) != 0)) {
+ /* Short name is used. */
+ wbuf[0] = L'\0';
+ }
+}
+
+
+#if defined(_WIN32_WCE)
+/* Create substitutes for POSIX functions in Win32. */
+
+#if defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+
+static time_t
+time(time_t *ptime)
+{
+ time_t t;
+ SYSTEMTIME st;
+ FILETIME ft;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+ t = SYS2UNIX_TIME(ft.dwLowDateTime, ft.dwHighDateTime);
+
+ if (ptime != NULL) {
+ *ptime = t;
+ }
+
+ return t;
+}
+
+
+static struct tm *
+localtime(const time_t *ptime, struct tm *ptm)
+{
+ int64_t t = ((int64_t)*ptime) * RATE_DIFF + EPOCH_DIFF;
+ FILETIME ft, lft;
+ SYSTEMTIME st;
+ TIME_ZONE_INFORMATION tzinfo;
+
+ if (ptm == NULL) {
+ return NULL;
+ }
+
+ *(int64_t *)&ft = t;
+ FileTimeToLocalFileTime(&ft, &lft);
+ FileTimeToSystemTime(&lft, &st);
+ ptm->tm_year = st.wYear - 1900;
+ ptm->tm_mon = st.wMonth - 1;
+ ptm->tm_wday = st.wDayOfWeek;
+ ptm->tm_mday = st.wDay;
+ ptm->tm_hour = st.wHour;
+ ptm->tm_min = st.wMinute;
+ ptm->tm_sec = st.wSecond;
+ ptm->tm_yday = 0; /* hope nobody uses this */
+ ptm->tm_isdst =
+ GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_DAYLIGHT ? 1 : 0;
+
+ return ptm;
+}
+
+
+static struct tm *
+gmtime(const time_t *ptime, struct tm *ptm)
+{
+ /* FIXME(lsm): fix this. */
+ return localtime(ptime, ptm);
+}
+
+
+static size_t
+strftime(char *dst, size_t dst_size, const char *fmt, const struct tm *tm)
+{
+ (void)mg_snprintf(NULL, dst, dst_size, "implement strftime() for WinCE");
+ return 0;
+}
+
+
+#if defined(__MINGW32__)
+/* Enable unused function warning again */
+#pragma GCC diagnostic pop
+#endif
+
+#endif
+
+
+/* Windows happily opens files with some garbage at the end of file name.
+ * For example, fopen("a.cgi ", "r") on Windows successfully opens
+ * "a.cgi", despite one would expect an error back.
+ * This function returns non-0 if path ends with some garbage. */
+static int
+path_cannot_disclose_cgi(const char *path)
+{
+ static const char *allowed_last_characters = "_-";
+ int last = path[strlen(path) - 1];
+ return isalnum(last) || strchr(allowed_last_characters, last) != NULL;
+}
+
+
+static int
+mg_stat(struct mg_connection *conn, const char *path, struct file *filep)
+{
+ wchar_t wbuf[PATH_MAX];
+ WIN32_FILE_ATTRIBUTE_DATA info;
+ time_t creation_time;
+
+ if (!filep) {
+ return 0;
+ }
+ memset(filep, 0, sizeof(*filep));
+
+ if (conn && is_file_in_memory(conn, path, filep)) {
+ /* filep->is_directory = 0; filep->gzipped = 0; .. already done by
+ * memset */
+ filep->last_modified = time(NULL);
+ /* last_modified = now ... assumes the file may change during runtime,
+ * so every mg_fopen call may return different data */
+ /* last_modified = conn->ctx.start_time;
+ * May be used it the data does not change during runtime. This allows
+ * browser caching. Since we do not know, we have to assume the file
+ * in memory may change. */
+ return 1;
+ }
+
+ if (path && path[4] == 0 && memcmp(path, "www/", 4) == 0)
+ {
+ filep->size = 512;
+ filep->is_directory = 1;
+ return 1;
+ }
+
+ path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
+ if (GetFileAttributesExW(wbuf, GetFileExInfoStandard, &info) != 0) {
+ filep->size = MAKEUQUAD(info.nFileSizeLow, info.nFileSizeHigh);
+ filep->last_modified =
+ SYS2UNIX_TIME(info.ftLastWriteTime.dwLowDateTime,
+ info.ftLastWriteTime.dwHighDateTime);
+
+ /* On Windows, the file creation time can be higher than the
+ * modification time, e.g. when a file is copied.
+ * Since the Last-Modified timestamp is used for caching
+ * it should be based on the most recent timestamp. */
+ creation_time = SYS2UNIX_TIME(info.ftCreationTime.dwLowDateTime,
+ info.ftCreationTime.dwHighDateTime);
+ if (creation_time > filep->last_modified) {
+ filep->last_modified = creation_time;
+ }
+
+ filep->is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ /* If file name is fishy, reset the file structure and return
+ * error.
+ * Note it is important to reset, not just return the error, cause
+ * functions like is_file_opened() check the struct. */
+ if (!filep->is_directory && !path_cannot_disclose_cgi(path)) {
+ memset(filep, 0, sizeof(*filep));
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int
+mg_remove(const struct mg_connection *conn, const char *path)
+{
+ wchar_t wbuf[PATH_MAX];
+ path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
+ return DeleteFileW(wbuf) ? 0 : -1;
+}
+
+
+static int
+mg_mkdir(const struct mg_connection *conn, const char *path, int mode)
+{
+ wchar_t wbuf[PATH_MAX];
+ (void)mode;
+ path_to_unicode(conn, path, wbuf, ARRAY_SIZE(wbuf));
+ return CreateDirectoryW(wbuf, NULL) ? 0 : -1;
+}
+
+
+/* Create substitutes for POSIX functions in Win32. */
+
+#if defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+
+/* Implementation of POSIX opendir/closedir/readdir for Windows. */
+static DIR *
+mg_opendir(const struct mg_connection *conn, const char *name)
+{
+ DIR *dir = NULL;
+ wchar_t wpath[PATH_MAX];
+ DWORD attrs;
+
+ if (name == NULL) {
+ SetLastError(ERROR_BAD_ARGUMENTS);
+ } else if ((dir = (DIR *)mg_malloc(sizeof(*dir))) == NULL) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ } else {
+ path_to_unicode(conn, name, wpath, ARRAY_SIZE(wpath));
+ attrs = GetFileAttributesW(wpath);
+ if (attrs != 0xFFFFFFFF && ((attrs & FILE_ATTRIBUTE_DIRECTORY)
+ == FILE_ATTRIBUTE_DIRECTORY)) {
+ (void)wcscat(wpath, L"\\*");
+ dir->handle = FindFirstFileW(wpath, &dir->info);
+ dir->result.d_name[0] = '\0';
+ } else {
+ mg_free(dir);
+ dir = NULL;
+ }
+ }
+
+ return dir;
+}
+
+
+static int
+mg_closedir(DIR *dir)
+{
+ int result = 0;
+
+ if (dir != NULL) {
+ if (dir->handle != INVALID_HANDLE_VALUE)
+ result = FindClose(dir->handle) ? 0 : -1;
+
+ mg_free(dir);
+ } else {
+ result = -1;
+ SetLastError(ERROR_BAD_ARGUMENTS);
+ }
+
+ return result;
+}
+
+
+static struct dirent *
+mg_readdir(DIR *dir)
+{
+ struct dirent *result = 0;
+
+ if (dir) {
+ if (dir->handle != INVALID_HANDLE_VALUE) {
+ result = &dir->result;
+ (void)WideCharToMultiByte(CP_UTF8,
+ 0,
+ dir->info.cFileName,
+ -1,
+ result->d_name,
+ sizeof(result->d_name),
+ NULL,
+ NULL);
+
+ if (!FindNextFileW(dir->handle, &dir->info)) {
+ (void)FindClose(dir->handle);
+ dir->handle = INVALID_HANDLE_VALUE;
+ }
+
+ } else {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+ } else {
+ SetLastError(ERROR_BAD_ARGUMENTS);
+ }
+
+ return result;
+}
+
+
+#ifndef HAVE_POLL
+static int
+poll(struct pollfd *pfd, unsigned int n, int milliseconds)
+{
+ struct timeval tv;
+ fd_set set;
+ unsigned int i;
+ int result;
+ SOCKET maxfd = 0;
+
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = milliseconds / 1000;
+ tv.tv_usec = (milliseconds % 1000) * 1000;
+ FD_ZERO(&set);
+
+ for (i = 0; i < n; i++) {
+ FD_SET((SOCKET)pfd[i].fd, &set);
+ pfd[i].revents = 0;
+
+ if (pfd[i].fd > maxfd) {
+ maxfd = pfd[i].fd;
+ }
+ }
+
+ if ((result = select((int)maxfd + 1, &set, NULL, NULL, &tv)) > 0) {
+ for (i = 0; i < n; i++) {
+ if (FD_ISSET(pfd[i].fd, &set)) {
+ pfd[i].revents = POLLIN;
+ }
+ }
+ }
+
+ return result;
+}
+#endif /* HAVE_POLL */
+
+#if defined(__MINGW32__)
+/* Enable unused function warning again */
+#pragma GCC diagnostic pop
+#endif
+
+
+static void
+set_close_on_exec(SOCKET sock, struct mg_connection *conn /* may be null */)
+{
+ (void)conn; /* Unused. */
+ (void)SetHandleInformation((HANDLE)(intptr_t)sock, HANDLE_FLAG_INHERIT, 0);
+}
+
+
+int
+mg_start_thread(mg_thread_func_t f, void *p)
+{
+#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
+ /* Compile-time option to control stack size, e.g. -DUSE_STACK_SIZE=16384
+ */
+ return ((_beginthread((void(__cdecl *)(void *))f, USE_STACK_SIZE, p)
+ == ((uintptr_t)(-1L)))
+ ? -1
+ : 0);
+#else
+ return (
+ (_beginthread((void(__cdecl *)(void *))f, 0, p) == ((uintptr_t)(-1L)))
+ ? -1
+ : 0);
+#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
+}
+
+
+/* Start a thread storing the thread context. */
+static int
+mg_start_thread_with_id(unsigned(__stdcall *f)(void *),
+ void *p,
+ pthread_t *threadidptr)
+{
+ uintptr_t uip;
+ HANDLE threadhandle;
+ int result = -1;
+
+ uip = _beginthreadex(NULL, 0, (unsigned(__stdcall *)(void *))f, p, 0, NULL);
+ threadhandle = (HANDLE)uip;
+ if ((uip != (uintptr_t)(-1L)) && (threadidptr != NULL)) {
+ *threadidptr = threadhandle;
+ result = 0;
+ }
+
+ return result;
+}
+
+
+/* Wait for a thread to finish. */
+static int
+mg_join_thread(pthread_t threadid)
+{
+ int result;
+ DWORD dwevent;
+
+ result = -1;
+ dwevent = WaitForSingleObject(threadid, INFINITE);
+ if (dwevent == WAIT_FAILED) {
+ DEBUG_TRACE("WaitForSingleObject() failed, error %d", ERRNO);
+ } else {
+ if (dwevent == WAIT_OBJECT_0) {
+ CloseHandle(threadid);
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+#if !defined(NO_SSL_DL)
+/* Create substitutes for POSIX functions in Win32. */
+
+#if defined(__MINGW32__)
+/* Show no warning in case system functions are not used. */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+
+static HANDLE
+dlopen(const char *dll_name, int flags)
+{
+ wchar_t wbuf[PATH_MAX];
+ (void)flags;
+ path_to_unicode(NULL, dll_name, wbuf, ARRAY_SIZE(wbuf));
+ return LoadLibraryW(wbuf);
+}
+
+
+static int
+dlclose(void *handle)
+{
+ int result;
+
+ if (FreeLibrary((HMODULE)handle) != 0) {
+ result = 0;
+ } else {
+ result = -1;
+ }
+
+ return result;
+}
+
+
+#if defined(__MINGW32__)
+/* Enable unused function warning again */
+#pragma GCC diagnostic pop
+#endif
+
+#endif
+
+
+#if !defined(NO_CGI)
+#define SIGKILL (0)
+
+static int
+kill(pid_t pid, int sig_num)
+{
+ (void)TerminateProcess((HANDLE)pid, (UINT)sig_num);
+ (void)CloseHandle((HANDLE)pid);
+ return 0;
+}
+
+
+static void
+trim_trailing_whitespaces(char *s)
+{
+ char *e = s + strlen(s) - 1;
+ while (e > s && isspace(*(unsigned char *)e)) {
+ *e-- = '\0';
+ }
+}
+
+
+static pid_t
+spawn_process(struct mg_connection *conn,
+ const char *prog,
+ char *envblk,
+ char *envp[],
+ int fdin[2],
+ int fdout[2],
+ int fderr[2],
+ const char *dir)
+{
+ HANDLE me;
+ char *p, *interp, full_interp[PATH_MAX], full_dir[PATH_MAX],
+ cmdline[PATH_MAX], buf[PATH_MAX];
+ int truncated;
+ struct file file = STRUCT_FILE_INITIALIZER;
+ STARTUPINFOA si;
+ PROCESS_INFORMATION pi = {0};
+
+ (void)envp;
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_HIDE;
+
+ me = GetCurrentProcess();
+ DuplicateHandle(me,
+ (HANDLE)_get_osfhandle(fdin[0]),
+ me,
+ &si.hStdInput,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS);
+ DuplicateHandle(me,
+ (HANDLE)_get_osfhandle(fdout[1]),
+ me,
+ &si.hStdOutput,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS);
+ DuplicateHandle(me,
+ (HANDLE)_get_osfhandle(fderr[1]),
+ me,
+ &si.hStdError,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS);
+
+ /* Mark handles that should not be inherited. See
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499%28v=vs.85%29.aspx
+ */
+ SetHandleInformation((HANDLE)_get_osfhandle(fdin[1]),
+ HANDLE_FLAG_INHERIT,
+ 0);
+ SetHandleInformation((HANDLE)_get_osfhandle(fdout[0]),
+ HANDLE_FLAG_INHERIT,
+ 0);
+ SetHandleInformation((HANDLE)_get_osfhandle(fderr[0]),
+ HANDLE_FLAG_INHERIT,
+ 0);
+
+ /* If CGI file is a script, try to read the interpreter line */
+ interp = conn->ctx->config[CGI_INTERPRETER];
+ if (interp == NULL) {
+ buf[0] = buf[1] = '\0';
+
+ /* Read the first line of the script into the buffer */
+ mg_snprintf(
+ conn, &truncated, cmdline, sizeof(cmdline), "%s/%s", dir, prog);
+
+ if (truncated) {
+ pi.hProcess = (pid_t)-1;
+ goto spawn_cleanup;
+ }
+
+ if (mg_fopen(conn, cmdline, "r", &file)) {
+ p = (char *)file.membuf;
+ mg_fgets(buf, sizeof(buf), &file, &p);
+ mg_fclose(&file);
+ buf[sizeof(buf) - 1] = '\0';
+ }
+
+ if (buf[0] == '#' && buf[1] == '!') {
+ trim_trailing_whitespaces(buf + 2);
+ } else {
+ buf[2] = '\0';
+ }
+ interp = buf + 2;
+ }
+
+ if (interp[0] != '\0') {
+ GetFullPathNameA(interp, sizeof(full_interp), full_interp, NULL);
+ interp = full_interp;
+ }
+ GetFullPathNameA(dir, sizeof(full_dir), full_dir, NULL);
+
+ if (interp[0] != '\0') {
+ mg_snprintf(conn,
+ &truncated,
+ cmdline,
+ sizeof(cmdline),
+ "\"%s\" \"%s\\%s\"",
+ interp,
+ full_dir,
+ prog);
+ } else {
+ mg_snprintf(conn,
+ &truncated,
+ cmdline,
+ sizeof(cmdline),
+ "\"%s\\%s\"",
+ full_dir,
+ prog);
+ }
+
+ if (truncated) {
+ pi.hProcess = (pid_t)-1;
+ goto spawn_cleanup;
+ }
+
+ DEBUG_TRACE("Running [%s]", cmdline);
+ if (CreateProcessA(NULL,
+ cmdline,
+ NULL,
+ NULL,
+ TRUE,
+ CREATE_NEW_PROCESS_GROUP,
+ envblk,
+ NULL,
+ &si,
+ &pi) == 0) {
+ mg_cry(
+ conn, "%s: CreateProcess(%s): %ld", __func__, cmdline, (long)ERRNO);
+ pi.hProcess = (pid_t)-1;
+ /* goto spawn_cleanup; */
+ }
+
+spawn_cleanup:
+ (void)CloseHandle(si.hStdOutput);
+ (void)CloseHandle(si.hStdError);
+ (void)CloseHandle(si.hStdInput);
+ if (pi.hThread != NULL) {
+ (void)CloseHandle(pi.hThread);
+ }
+
+ return (pid_t)pi.hProcess;
+}
+#endif /* !NO_CGI */
+
+
+static int
+set_non_blocking_mode(SOCKET sock)
+{
+ unsigned long on = 1;
+ return ioctlsocket(sock, (long)FIONBIO, &on);
+}
+
+#else
+
+static int
+mg_stat(struct mg_connection *conn, const char *path, struct file *filep)
+{
+ struct stat st;
+ if (!filep) {
+ return 0;
+ }
+ memset(filep, 0, sizeof(*filep));
+
+ if (conn && is_file_in_memory(conn, path, filep)) {
+ return 1;
+ }
+
+ if (path && path[4] == 0 && memcmp(path, "www/", 4) == 0)
+ {
+ filep->size = 512;
+ filep->is_directory = 1;
+ return 1;
+ }
+
+ if (0 == stat(path, &st)) {
+ filep->size = (uint64_t)(st.st_size);
+ filep->last_modified = st.st_mtime;
+ filep->is_directory = S_ISDIR(st.st_mode);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void
+set_close_on_exec(SOCKET fd, struct mg_connection *conn /* may be null */)
+{
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
+ if (conn) {
+ mg_cry(conn,
+ "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
+ __func__,
+ strerror(ERRNO));
+ }
+ }
+}
+
+
+int
+mg_start_thread(mg_thread_func_t func, void *param)
+{
+ pthread_t thread_id;
+ pthread_attr_t attr;
+ int result;
+
+ (void)pthread_attr_init(&attr);
+ (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
+ /* Compile-time option to control stack size,
+ * e.g. -DUSE_STACK_SIZE=16384 */
+ (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
+#endif /* defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1) */
+
+ result = pthread_create(&thread_id, &attr, func, param);
+ pthread_attr_destroy(&attr);
+
+ return result;
+}
+
+
+/* Start a thread storing the thread context. */
+static int
+mg_start_thread_with_id(mg_thread_func_t func,
+ void *param,
+ pthread_t *threadidptr)
+{
+ pthread_t thread_id;
+ pthread_attr_t attr;
+ int result;
+
+ (void)pthread_attr_init(&attr);
+
+#if defined(USE_STACK_SIZE) && (USE_STACK_SIZE > 1)
+ /* Compile-time option to control stack size,
+ * e.g. -DUSE_STACK_SIZE=16384 */
+ (void)pthread_attr_setstacksize(&attr, USE_STACK_SIZE);
+#endif /* defined(USE_STACK_SIZE) && USE_STACK_SIZE > 1 */
+
+ result = pthread_create(&thread_id, &attr, func, param);
+ pthread_attr_destroy(&attr);
+ if ((result == 0) && (threadidptr != NULL)) {
+ *threadidptr = thread_id;
+ }
+ return result;
+}
+
+
+/* Wait for a thread to finish. */
+static int
+mg_join_thread(pthread_t threadid)
+{
+ int result;
+
+ result = pthread_join(threadid, NULL);
+ return result;
+}
+
+
+#ifndef NO_CGI
+static pid_t
+spawn_process(struct mg_connection *conn,
+ const char *prog,
+ char *envblk,
+ char *envp[],
+ int fdin[2],
+ int fdout[2],
+ int fderr[2],
+ const char *dir)
+{
+ pid_t pid;
+ const char *interp;
+
+ (void)envblk;
+
+ if (conn == NULL) {
+ return 0;
+ }
+
+ if ((pid = fork()) == -1) {
+ /* Parent */
+ send_http_error(conn,
+ 500,
+ "Error: Creating CGI process\nfork(): %s",
+ strerror(ERRNO));
+ } else if (pid == 0) {
+ /* Child */
+ if (chdir(dir) != 0) {
+ mg_cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO));
+ } else if (dup2(fdin[0], 0) == -1) {
+ mg_cry(conn,
+ "%s: dup2(%d, 0): %s",
+ __func__,
+ fdin[0],
+ strerror(ERRNO));
+ } else if (dup2(fdout[1], 1) == -1) {
+ mg_cry(conn,
+ "%s: dup2(%d, 1): %s",
+ __func__,
+ fdout[1],
+ strerror(ERRNO));
+ } else if (dup2(fderr[1], 2) == -1) {
+ mg_cry(conn,
+ "%s: dup2(%d, 2): %s",
+ __func__,
+ fderr[1],
+ strerror(ERRNO));
+ } else {
+ /* Keep stderr and stdout in two different pipes.
+ * Stdout will be sent back to the client,
+ * stderr should go into a server error log. */
+ (void)close(fdin[0]);
+ (void)close(fdout[1]);
+ (void)close(fderr[1]);
+
+ /* Close write end fdin and read end fdout and fderr */
+ (void)close(fdin[1]);
+ (void)close(fdout[0]);
+ (void)close(fderr[0]);
+
+ /* After exec, all signal handlers are restored to their default
+ * values, with one exception of SIGCHLD. According to
+ * POSIX.1-2001 and Linux's implementation, SIGCHLD's handler will
+ * leave unchanged after exec if it was set to be ignored. Restore
+ * it to default action. */
+ signal(SIGCHLD, SIG_DFL);
+
+ interp = conn->ctx->config[CGI_INTERPRETER];
+ if (interp == NULL) {
+ (void)execle(prog, prog, NULL, envp);
+ mg_cry(conn,
+ "%s: execle(%s): %s",
+ __func__,
+ prog,
+ strerror(ERRNO));
+ } else {
+ (void)execle(interp, interp, prog, NULL, envp);
+ mg_cry(conn,
+ "%s: execle(%s %s): %s",
+ __func__,
+ interp,
+ prog,
+ strerror(ERRNO));
+ }
+ }
+ exit(EXIT_FAILURE);
+ }
+
+ return pid;
+}
+#endif /* !NO_CGI */
+
+
+static int
+set_non_blocking_mode(SOCKET sock)
+{
+ int flags;
+
+ flags = fcntl(sock, F_GETFL, 0);
+ (void)fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+
+ return 0;
+}
+#endif /* _WIN32 */
+/* End of initial operating system specific define block. */
+
+
+/* Get a random number (independent of C rand function) */
+static uint64_t
+get_random(void)
+{
+ static uint64_t lfsr = 0; /* Linear feedback shift register */
+ static uint64_t lcg = 0; /* Linear congruential generator */
+ struct timespec now;
+
+ memset(&now, 0, sizeof(now));
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ if (lfsr == 0) {
+ /* lfsr will be only 0 if has not been initialized,
+ * so this code is called only once. */
+ lfsr = (((uint64_t)now.tv_sec) << 21) ^ ((uint64_t)now.tv_nsec)
+ ^ ((uint64_t)(ptrdiff_t)&now) ^ (((uint64_t)time(NULL)) << 33);
+ lcg = (((uint64_t)now.tv_sec) << 25) + (uint64_t)now.tv_nsec
+ + (uint64_t)(ptrdiff_t)&now;
+ } else {
+ /* Get the next step of both random number generators. */
+ lfsr = (lfsr >> 1)
+ | ((((lfsr >> 0) ^ (lfsr >> 1) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1)
+ << 63);
+ lcg = lcg * 6364136223846793005 + 1442695040888963407;
+ }
+
+ /* Combining two pseudo-random number generators and a high resolution part
+ * of the current server time will make it hard (impossible?) to guess the
+ * next number. */
+ return (lfsr ^ lcg ^ (uint64_t)now.tv_nsec);
+}
+
+
+/* Write data to the IO channel - opened file descriptor, socket or SSL
+ * descriptor. Return number of bytes written. */
+static int
+push(struct mg_context *ctx,
+ FILE *fp,
+ SOCKET sock,
+ SSL *ssl,
+ const char *buf,
+ int len,
+ double timeout)
+{
+ struct timespec start, now;
+ int n, err;
+
+#ifdef _WIN32
+ typedef int len_t;
+#else
+ typedef size_t len_t;
+#endif
+
+ if (timeout > 0) {
+ memset(&start, 0, sizeof(start));
+ memset(&now, 0, sizeof(now));
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ }
+
+ if (ctx == NULL) {
+ return -1;
+ }
+
+#ifdef NO_SSL
+ if (ssl) {
+ return -1;
+ }
+#endif
+
+ do {
+
+#ifndef NO_SSL
+ if (ssl != NULL) {
+ n = SSL_write(ssl, buf, len);
+ if (n <= 0) {
+ err = SSL_get_error(ssl, n);
+ if ((err == 5 /* SSL_ERROR_SYSCALL */) && (n == -1)) {
+ err = ERRNO;
+ } else {
+ DEBUG_TRACE("SSL_write() failed, error %d", err);
+ return -1;
+ }
+ } else {
+ err = 0;
+ }
+ } else
+#endif
+ if (fp != NULL) {
+ n = (int)fwrite(buf, 1, (size_t)len, fp);
+ if (ferror(fp)) {
+ n = -1;
+ err = ERRNO;
+ } else {
+ err = 0;
+ }
+ } else {
+ n = (int)send(sock, buf, (len_t)len, MSG_NOSIGNAL);
+ err = (n < 0) ? ERRNO : 0;
+ }
+
+ if (ctx->stop_flag) {
+ return -1;
+ }
+
+ if ((n > 0) || (n == 0 && len == 0)) {
+ /* some data has been read, or no data was requested */
+ return n;
+ }
+ if (n == 0) {
+ /* shutdown of the socket at client side */
+ return -1;
+ }
+ if (n < 0) {
+ /* socket error - check errno */
+ DEBUG_TRACE("send() failed, error %d", err);
+
+ /* TODO: error handling depending on the error code.
+ * These codes are different between Windows and Linux.
+ */
+ return -1;
+ }
+
+ /* This code is not reached in the moment.
+ * ==> Fix the TODOs above first. */
+
+ if (timeout > 0) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ }
+
+ } while ((timeout <= 0) || (mg_difftimespec(&now, &start) <= timeout));
+
+ (void)err; /* Avoid unused warning if NO_SSL is set and DEBUG_TRACE is not
+ used */
+
+ return -1;
+}
+
+
+static int64_t
+push_all(struct mg_context *ctx,
+ FILE *fp,
+ SOCKET sock,
+ SSL *ssl,
+ const char *buf,
+ int64_t len)
+{
+ double timeout = -1.0;
+ int64_t n, nwritten = 0;
+
+ if (ctx == NULL) {
+ return -1;
+ }
+
+ if (ctx->config[REQUEST_TIMEOUT]) {
+ timeout = atoi(ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+ }
+
+ while (len > 0 && ctx->stop_flag == 0) {
+ n = push(ctx, fp, sock, ssl, buf + nwritten, (int)len, timeout);
+ if (n < 0) {
+ if (nwritten == 0) {
+ nwritten = n; /* Propagate the error */
+ }
+ break;
+ } else if (n == 0) {
+ break; /* No more data to write */
+ } else {
+ nwritten += n;
+ len -= n;
+ }
+ }
+
+ return nwritten;
+}
+
+
+/* Read from IO channel - opened file descriptor, socket, or SSL descriptor.
+ * Return negative value on error, or number of bytes read on success. */
+static int
+pull(FILE *fp, struct mg_connection *conn, char *buf, int len, double timeout)
+{
+ int nread, err;
+ struct timespec start, now;
+
+#ifdef _WIN32
+ typedef int len_t;
+#else
+ typedef size_t len_t;
+#endif
+
+ if (timeout > 0) {
+ memset(&start, 0, sizeof(start));
+ memset(&now, 0, sizeof(now));
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ }
+
+ do {
+ if (fp != NULL) {
+ /* Use read() instead of fread(), because if we're reading from the
+ * CGI pipe, fread() may block until IO buffer is filled up. We
+ * cannot afford to block and must pass all read bytes immediately
+ * to the client. */
+ nread = (int)read(fileno(fp), buf, (size_t)len);
+ err = (nread < 0) ? ERRNO : 0;
+
+#ifndef NO_SSL
+ } else if (conn->ssl != NULL) {
+ nread = SSL_read(conn->ssl, buf, len);
+ if (nread <= 0) {
+ err = SSL_get_error(conn->ssl, nread);
+ if ((err == 5 /* SSL_ERROR_SYSCALL */) && (nread == -1)) {
+ err = ERRNO;
+ } else {
+ DEBUG_TRACE("SSL_read() failed, error %d", err);
+ return -1;
+ }
+ } else {
+ err = 0;
+ }
+#endif
+
+ } else {
+ nread = (int)recv(conn->client.sock, buf, (len_t)len, 0);
+ err = (nread < 0) ? ERRNO : 0;
+ }
+
+ if (conn->ctx->stop_flag) {
+ return -1;
+ }
+
+ if ((nread > 0) || (nread == 0 && len == 0)) {
+ /* some data has been read, or no data was requested */
+ return nread;
+ }
+ if (nread == 0) {
+ /* shutdown of the socket at client side */
+ return -1;
+ }
+ if (nread < 0) {
+/* socket error - check errno */
+#ifdef _WIN32
+ if (err == WSAEWOULDBLOCK) {
+ /* standard case if called from close_socket_gracefully */
+ return -1;
+ } else if (err == WSAETIMEDOUT) {
+ /* timeout is handled by the while loop */
+ } else {
+ DEBUG_TRACE("recv() failed, error %d", err);
+ return -1;
+ }
+#else
+ /* TODO: POSIX returns either EAGAIN or EWOULDBLOCK in both cases,
+ * if the timeout is reached and if the socket was set to non-
+ * blocking in close_socket_gracefully, so we can not distinguish
+ * here. We have to wait for the timeout in both cases for now.
+ */
+ if (err == EAGAIN || err == EWOULDBLOCK || err == EINTR) {
+ /* EAGAIN/EWOULDBLOCK:
+ * standard case if called from close_socket_gracefully
+ * => should return -1 */
+ /* or timeout occured
+ * => the code must stay in the while loop */
+
+ /* EINTR can be generated on a socket with a timeout set even
+ * when SA_RESTART is effective for all relevant signals
+ * (see signal(7)).
+ * => stay in the while loop */
+ } else {
+ DEBUG_TRACE("recv() failed, error %d", err);
+ return -1;
+ }
+#endif
+ }
+ if (timeout > 0) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ }
+ } while ((timeout <= 0) || (mg_difftimespec(&now, &start) <= timeout));
+
+ /* Timeout occured, but no data available. */
+ return -1;
+}
+
+
+static int
+pull_all(FILE *fp, struct mg_connection *conn, char *buf, int len)
+{
+ int n, nread = 0;
+ double timeout = -1.0;
+
+ if (conn->ctx->config[REQUEST_TIMEOUT]) {
+ timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+ }
+
+ while (len > 0 && conn->ctx->stop_flag == 0) {
+ n = pull(fp, conn, buf + nread, len, timeout);
+ if (n < 0) {
+ if (nread == 0) {
+ nread = n; /* Propagate the error */
+ }
+ break;
+ } else if (n == 0) {
+ break; /* No more data to read */
+ } else {
+ conn->consumed_content += n;
+ nread += n;
+ len -= n;
+ }
+ }
+
+ return nread;
+}
+
+
+static void
+discard_unread_request_data(struct mg_connection *conn)
+{
+ char buf[MG_BUF_LEN];
+ size_t to_read;
+ int nread;
+
+ if (conn == NULL) {
+ return;
+ }
+
+ to_read = sizeof(buf);
+
+ if (conn->is_chunked) {
+ /* Chunked encoding: 1=chunk not read completely, 2=chunk read
+ * completely */
+ while (conn->is_chunked == 1) {
+ nread = mg_read(conn, buf, to_read);
+ if (nread <= 0) {
+ break;
+ }
+ }
+
+ } else {
+ /* Not chunked: content length is known */
+ while (conn->consumed_content < conn->content_len) {
+ if (to_read
+ > (size_t)(conn->content_len - conn->consumed_content)) {
+ to_read = (size_t)(conn->content_len - conn->consumed_content);
+ }
+
+ nread = mg_read(conn, buf, to_read);
+ if (nread <= 0) {
+ break;
+ }
+ }
+ }
+}
+
+
+static int
+mg_read_inner(struct mg_connection *conn, void *buf, size_t len)
+{
+ int64_t n, buffered_len, nread;
+ int64_t len64 =
+ (int64_t)(len > INT_MAX ? INT_MAX : len); /* since the return value is
+ * int, we may not read more
+ * bytes */
+ const char *body;
+
+ if (conn == NULL) {
+ return 0;
+ }
+
+ /* If Content-Length is not set for a PUT or POST request, read until
+ * socket is closed */
+ if (conn->consumed_content == 0 && conn->content_len == -1) {
+ conn->content_len = INT64_MAX;
+ conn->must_close = 1;
+ }
+
+ nread = 0;
+ if (conn->consumed_content < conn->content_len) {
+ /* Adjust number of bytes to read. */
+ int64_t left_to_read = conn->content_len - conn->consumed_content;
+ if (left_to_read < len64) {
+ /* Do not read more than the total content length of the request.
+ */
+ len64 = left_to_read;
+ }
+
+ /* Return buffered data */
+ buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
+ - conn->consumed_content;
+ if (buffered_len > 0) {
+ if (len64 < buffered_len) {
+ buffered_len = len64;
+ }
+ body = conn->buf + conn->request_len + conn->consumed_content;
+ memcpy(buf, body, (size_t)buffered_len);
+ len64 -= buffered_len;
+ conn->consumed_content += buffered_len;
+ nread += buffered_len;
+ buf = (char *)buf + buffered_len;
+ }
+
+ /* We have returned all buffered data. Read new data from the remote
+ * socket.
+ */
+ if ((n = pull_all(NULL, conn, (char *)buf, (int)len64)) >= 0) {
+ nread += n;
+ } else {
+ nread = (nread > 0 ? nread : n);
+ }
+ }
+ return (int)nread;
+}
+
+
+static char
+mg_getc(struct mg_connection *conn)
+{
+ char c;
+ if (conn == NULL) {
+ return 0;
+ }
+ conn->content_len++;
+ if (mg_read_inner(conn, &c, 1) <= 0) {
+ return (char)0;
+ }
+ return c;
+}
+
+
+int
+mg_read(struct mg_connection *conn, void *buf, size_t len)
+{
+ if (len > INT_MAX) {
+ len = INT_MAX;
+ }
+
+ if (conn == NULL) {
+ return 0;
+ }
+
+ if (conn->is_chunked) {
+ size_t all_read = 0;
+
+ while (len > 0) {
+
+ if (conn->is_chunked == 2) {
+ /* No more data left to read */
+ return 0;
+ }
+
+ if (conn->chunk_remainder) {
+ /* copy from the remainder of the last received chunk */
+ long read_ret;
+ size_t read_now =
+ ((conn->chunk_remainder > len) ? (len)
+ : (conn->chunk_remainder));
+
+ conn->content_len += (int)read_now;
+ read_ret =
+ mg_read_inner(conn, (char *)buf + all_read, read_now);
+ all_read += (size_t)read_ret;
+
+ conn->chunk_remainder -= read_now;
+ len -= read_now;
+
+ if (conn->chunk_remainder == 0) {
+ /* the rest of the data in the current chunk has been read
+ */
+ if ((mg_getc(conn) != '\r') || (mg_getc(conn) != '\n')) {
+ /* Protocol violation */
+ return -1;
+ }
+ }
+
+ } else {
+ /* fetch a new chunk */
+ int i = 0;
+ char lenbuf[64];
+ char *end = 0;
+ unsigned long chunkSize = 0;
+
+ for (i = 0; i < ((int)sizeof(lenbuf) - 1); i++) {
+ lenbuf[i] = mg_getc(conn);
+ if (i > 0 && lenbuf[i] == '\r' && lenbuf[i - 1] != '\r') {
+ continue;
+ }
+ if (i > 1 && lenbuf[i] == '\n' && lenbuf[i - 1] == '\r') {
+ lenbuf[i + 1] = 0;
+ chunkSize = strtoul(lenbuf, &end, 16);
+ if (chunkSize == 0) {
+ /* regular end of content */
+ conn->is_chunked = 2;
+ }
+ break;
+ }
+ if (!isalnum(lenbuf[i])) {
+ /* illegal character for chunk length */
+ return -1;
+ }
+ }
+ if ((end == NULL) || (*end != '\r')) {
+ /* chunksize not set correctly */
+ return -1;
+ }
+ if (chunkSize == 0) {
+ break;
+ }
+
+ conn->chunk_remainder = chunkSize;
+ }
+ }
+
+ return (int)all_read;
+ }
+ return mg_read_inner(conn, buf, len);
+}
+
+
+int
+mg_write(struct mg_connection *conn, const void *buf, size_t len)
+{
+ time_t now;
+ int64_t n, total, allowed;
+
+ if (conn == NULL) {
+ return 0;
+ }
+
+ if (conn->throttle > 0) {
+ if ((now = time(NULL)) != conn->last_throttle_time) {
+ conn->last_throttle_time = now;
+ conn->last_throttle_bytes = 0;
+ }
+ allowed = conn->throttle - conn->last_throttle_bytes;
+ if (allowed > (int64_t)len) {
+ allowed = (int64_t)len;
+ }
+ if ((total = push_all(conn->ctx,
+ NULL,
+ conn->client.sock,
+ conn->ssl,
+ (const char *)buf,
+ (int64_t)allowed)) == allowed) {
+ buf = (const char *)buf + total;
+ conn->last_throttle_bytes += total;
+ while (total < (int64_t)len && conn->ctx->stop_flag == 0) {
+ allowed = conn->throttle > (int64_t)len - total
+ ? (int64_t)len - total
+ : conn->throttle;
+ if ((n = push_all(conn->ctx,
+ NULL,
+ conn->client.sock,
+ conn->ssl,
+ (const char *)buf,
+ (int64_t)allowed)) != allowed) {
+ break;
+ }
+ sleep(1);
+ conn->last_throttle_bytes = allowed;
+ conn->last_throttle_time = time(NULL);
+ buf = (const char *)buf + n;
+ total += n;
+ }
+ }
+ } else {
+ total = push_all(conn->ctx,
+ NULL,
+ conn->client.sock,
+ conn->ssl,
+ (const char *)buf,
+ (int64_t)len);
+ }
+ return (int)total;
+}
+
+
+/* Alternative alloc_vprintf() for non-compliant C runtimes */
+static int
+alloc_vprintf2(char **buf, const char *fmt, va_list ap)
+{
+ va_list ap_copy;
+ size_t size = MG_BUF_LEN / 4;
+ int len = -1;
+
+ *buf = NULL;
+ while (len < 0) {
+ if (*buf) {
+ mg_free(*buf);
+ }
+
+ size *= 4;
+ *buf = (char *)mg_malloc(size);
+ if (!*buf) {
+ break;
+ }
+
+ va_copy(ap_copy, ap);
+ len = vsnprintf_impl(*buf, size - 1, fmt, ap_copy);
+ va_end(ap_copy);
+ (*buf)[size - 1] = 0;
+ }
+
+ return len;
+}
+
+
+/* Print message to buffer. If buffer is large enough to hold the message,
+ * return buffer. If buffer is to small, allocate large enough buffer on heap,
+ * and return allocated buffer. */
+static int
+alloc_vprintf(char **out_buf,
+ char *prealloc_buf,
+ size_t prealloc_size,
+ const char *fmt,
+ va_list ap)
+{
+ va_list ap_copy;
+ int len;
+
+ /* Windows is not standard-compliant, and vsnprintf() returns -1 if
+ * buffer is too small. Also, older versions of msvcrt.dll do not have
+ * _vscprintf(). However, if size is 0, vsnprintf() behaves correctly.
+ * Therefore, we make two passes: on first pass, get required message
+ * length.
+ * On second pass, actually print the message. */
+ va_copy(ap_copy, ap);
+ len = vsnprintf_impl(NULL, 0, fmt, ap_copy);
+ va_end(ap_copy);
+
+ if (len < 0) {
+ /* C runtime is not standard compliant, vsnprintf() returned -1.
+ * Switch to alternative code path that uses incremental allocations.
+ */
+ va_copy(ap_copy, ap);
+ len = alloc_vprintf2(out_buf, fmt, ap);
+ va_end(ap_copy);
+
+ } else if ((size_t)(len) >= prealloc_size) {
+ /* The pre-allocated buffer not large enough. */
+ /* Allocate a new buffer. */
+ *out_buf = (char *)mg_malloc((size_t)(len) + 1);
+ if (!*out_buf) {
+ /* Allocation failed. Return -1 as "out of memory" error. */
+ return -1;
+ }
+ /* Buffer allocation successful. Store the string there. */
+ va_copy(ap_copy, ap);
+ IGNORE_UNUSED_RESULT(
+ vsnprintf_impl(*out_buf, (size_t)(len) + 1, fmt, ap_copy));
+ va_end(ap_copy);
+
+ } else {
+ /* The pre-allocated buffer is large enough.
+ * Use it to store the string and return the address. */
+ va_copy(ap_copy, ap);
+ IGNORE_UNUSED_RESULT(
+ vsnprintf_impl(prealloc_buf, prealloc_size, fmt, ap_copy));
+ va_end(ap_copy);
+ *out_buf = prealloc_buf;
+ }
+
+ return len;
+}
+
+
+static int
+mg_vprintf(struct mg_connection *conn, const char *fmt, va_list ap)
+{
+ char mem[MG_BUF_LEN];
+ char *buf = NULL;
+ int len;
+
+ if ((len = alloc_vprintf(&buf, mem, sizeof(mem), fmt, ap)) > 0) {
+ len = mg_write(conn, buf, (size_t)len);
+ }
+ if (buf != mem && buf != NULL) {
+ mg_free(buf);
+ }
+
+ return len;
+}
+
+
+int
+mg_printf(struct mg_connection *conn, const char *fmt, ...)
+{
+ va_list ap;
+ int result;
+
+ va_start(ap, fmt);
+ result = mg_vprintf(conn, fmt, ap);
+ va_end(ap);
+
+ return result;
+}
+
+
+int
+mg_url_decode(const char *src,
+ int src_len,
+ char *dst,
+ int dst_len,
+ int is_form_url_encoded)
+{
+ int i, j, a, b;
+#define HEXTOI(x) (isdigit(x) ? x - '0' : x - 'W')
+
+ for (i = j = 0; i < src_len && j < dst_len - 1; i++, j++) {
+ if (i < src_len - 2 && src[i] == '%'
+ && isxdigit(*(const unsigned char *)(src + i + 1))
+ && isxdigit(*(const unsigned char *)(src + i + 2))) {
+ a = tolower(*(const unsigned char *)(src + i + 1));
+ b = tolower(*(const unsigned char *)(src + i + 2));
+ dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b));
+ i += 2;
+ } else if (is_form_url_encoded && src[i] == '+') {
+ dst[j] = ' ';
+ } else {
+ dst[j] = src[i];
+ }
+ }
+
+ dst[j] = '\0'; /* Null-terminate the destination */
+
+ return i >= src_len ? j : -1;
+}
+
+
+int
+mg_get_var(const char *data,
+ size_t data_len,
+ const char *name,
+ char *dst,
+ size_t dst_len)
+{
+ return mg_get_var2(data, data_len, name, dst, dst_len, 0);
+}
+
+
+int
+mg_get_var2(const char *data,
+ size_t data_len,
+ const char *name,
+ char *dst,
+ size_t dst_len,
+ size_t occurrence)
+{
+ const char *p, *e, *s;
+ size_t name_len;
+ int len;
+
+ if (dst == NULL || dst_len == 0) {
+ len = -2;
+ } else if (data == NULL || name == NULL || data_len == 0) {
+ len = -1;
+ dst[0] = '\0';
+ } else {
+ name_len = strlen(name);
+ e = data + data_len;
+ len = -1;
+ dst[0] = '\0';
+
+ /* data is "var1=val1&var2=val2...". Find variable first */
+ for (p = data; p + name_len < e; p++) {
+ if ((p == data || p[-1] == '&') && p[name_len] == '='
+ && !mg_strncasecmp(name, p, name_len) && 0 == occurrence--) {
+ /* Point p to variable value */
+ p += name_len + 1;
+
+ /* Point s to the end of the value */
+ s = (const char *)memchr(p, '&', (size_t)(e - p));
+ if (s == NULL) {
+ s = e;
+ }
+ /* assert(s >= p); */
+ if (s < p) {
+ return -3;
+ }
+
+ /* Decode variable into destination buffer */
+ len = mg_url_decode(p, (int)(s - p), dst, (int)dst_len, 1);
+
+ /* Redirect error code from -1 to -2 (destination buffer too
+ * small). */
+ if (len == -1) {
+ len = -2;
+ }
+ break;
+ }
+ }
+ }
+
+ return len;
+}
+
+
+int
+mg_get_cookie(const char *cookie_header,
+ const char *var_name,
+ char *dst,
+ size_t dst_size)
+{
+ const char *s, *p, *end;
+ int name_len, len = -1;
+
+ if (dst == NULL || dst_size == 0) {
+ len = -2;
+ } else if (var_name == NULL || (s = cookie_header) == NULL) {
+ len = -1;
+ dst[0] = '\0';
+ } else {
+ name_len = (int)strlen(var_name);
+ end = s + strlen(s);
+ dst[0] = '\0';
+
+ for (; (s = mg_strcasestr(s, var_name)) != NULL; s += name_len) {
+ if (s[name_len] == '=') {
+ s += name_len + 1;
+ if ((p = strchr(s, ' ')) == NULL) {
+ p = end;
+ }
+ if (p[-1] == ';') {
+ p--;
+ }
+ if (*s == '"' && p[-1] == '"' && p > s + 1) {
+ s++;
+ p--;
+ }
+ if ((size_t)(p - s) < dst_size) {
+ len = (int)(p - s);
+ mg_strlcpy(dst, s, (size_t)len + 1);
+ } else {
+ len = -3;
+ }
+ break;
+ }
+ }
+ }
+ return len;
+}
+
+
+#if defined(USE_WEBSOCKET) || defined(USE_LUA)
+static void
+base64_encode(const unsigned char *src, int src_len, char *dst)
+{
+ static const char *b64 =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ int i, j, a, b, c;
+
+ for (i = j = 0; i < src_len; i += 3) {
+ a = src[i];
+ b = i + 1 >= src_len ? 0 : src[i + 1];
+ c = i + 2 >= src_len ? 0 : src[i + 2];
+
+ dst[j++] = b64[a >> 2];
+ dst[j++] = b64[((a & 3) << 4) | (b >> 4)];
+ if (i + 1 < src_len) {
+ dst[j++] = b64[(b & 15) << 2 | (c >> 6)];
+ }
+ if (i + 2 < src_len) {
+ dst[j++] = b64[c & 63];
+ }
+ }
+ while (j % 4 != 0) {
+ dst[j++] = '=';
+ }
+ dst[j++] = '\0';
+}
+#endif
+
+
+#if defined(USE_LUA)
+static unsigned char
+b64reverse(char letter)
+{
+ if (letter >= 'A' && letter <= 'Z') {
+ return letter - 'A';
+ }
+ if (letter >= 'a' && letter <= 'z') {
+ return letter - 'a' + 26;
+ }
+ if (letter >= '0' && letter <= '9') {
+ return letter - '0' + 52;
+ }
+ if (letter == '+') {
+ return 62;
+ }
+ if (letter == '/') {
+ return 63;
+ }
+ if (letter == '=') {
+ return 255; /* normal end */
+ }
+ return 254; /* error */
+}
+
+
+static int
+base64_decode(const unsigned char *src, int src_len, char *dst, size_t *dst_len)
+{
+ int i;
+ unsigned char a, b, c, d;
+
+ *dst_len = 0;
+
+ for (i = 0; i < src_len; i += 4) {
+ a = b64reverse(src[i]);
+ if (a >= 254) {
+ return i;
+ }
+
+ b = b64reverse(i + 1 >= src_len ? 0 : src[i + 1]);
+ if (b >= 254) {
+ return i + 1;
+ }
+
+ c = b64reverse(i + 2 >= src_len ? 0 : src[i + 2]);
+ if (c == 254) {
+ return i + 2;
+ }
+
+ d = b64reverse(i + 3 >= src_len ? 0 : src[i + 3]);
+ if (d == 254) {
+ return i + 3;
+ }
+
+ dst[(*dst_len)++] = (a << 2) + (b >> 4);
+ if (c != 255) {
+ dst[(*dst_len)++] = (b << 4) + (c >> 2);
+ if (d != 255) {
+ dst[(*dst_len)++] = (c << 6) + d;
+ }
+ }
+ }
+ return -1;
+}
+#endif
+
+
+static int
+is_put_or_delete_method(const struct mg_connection *conn)
+{
+ if (conn) {
+ const char *s = conn->request_info.request_method;
+ return s != NULL && (!strcmp(s, "PUT") || !strcmp(s, "DELETE")
+ || !strcmp(s, "MKCOL") || !strcmp(s, "PATCH"));
+ }
+ return 0;
+}
+
+
+static void
+interpret_uri(struct mg_connection *conn, /* in: request (must be valid) */
+ char *filename, /* out: filename */
+ size_t filename_buf_len, /* in: size of filename buffer */
+ struct file *filep, /* out: file structure */
+ int *is_found, /* out: file is found (directly) */
+ int *is_script_resource, /* out: handled by a script? */
+ int *is_websocket_request, /* out: websocket connetion? */
+ int *is_put_or_delete_request /* out: put/delete a file? */
+ )
+{
+/* TODO (high): Restructure this function */
+
+#if !defined(NO_FILES)
+ const char *uri = conn->request_info.local_uri;
+ const char *root = conn->ctx->config[DOCUMENT_ROOT];
+ const char *rewrite;
+ struct vec a, b;
+ int match_len;
+ char gz_path[PATH_MAX];
+ char const *accept_encoding;
+ int truncated;
+#if !defined(NO_CGI) || defined(USE_LUA)
+ char *p;
+#endif
+#else
+ (void)filename_buf_len; /* unused if NO_FILES is defined */
+#endif
+
+ memset(filep, 0, sizeof(*filep));
+ *filename = 0;
+ *is_found = 0;
+ *is_script_resource = 0;
+ *is_put_or_delete_request = is_put_or_delete_method(conn);
+
+#if defined(USE_WEBSOCKET)
+ *is_websocket_request = is_websocket_protocol(conn);
+#if !defined(NO_FILES)
+ if (*is_websocket_request && conn->ctx->config[WEBSOCKET_ROOT]) {
+ root = conn->ctx->config[WEBSOCKET_ROOT];
+ }
+#endif /* !NO_FILES */
+#else /* USE_WEBSOCKET */
+ *is_websocket_request = 0;
+#endif /* USE_WEBSOCKET */
+
+#if !defined(NO_FILES)
+ /* Note that root == NULL is a regular use case here. This occurs,
+ * if all requests are handled by callbacks, so the WEBSOCKET_ROOT
+ * config is not required. */
+ if (root == NULL) {
+ /* all file related outputs have already been set to 0, just return
+ */
+ return;
+ }
+
+ /* Using buf_len - 1 because memmove() for PATH_INFO may shift part
+ * of the path one byte on the right.
+ * If document_root is NULL, leave the file empty. */
+ mg_snprintf(
+ conn, &truncated, filename, filename_buf_len - 1, "%s%s", root, uri);
+
+ if (truncated) {
+ goto interpret_cleanup;
+ }
+
+ rewrite = conn->ctx->config[REWRITE];
+ while ((rewrite = next_option(rewrite, &a, &b)) != NULL) {
+ if ((match_len = match_prefix(a.ptr, a.len, uri)) > 0) {
+ mg_snprintf(conn,
+ &truncated,
+ filename,
+ filename_buf_len - 1,
+ "%.*s%s",
+ (int)b.len,
+ b.ptr,
+ uri + match_len);
+ break;
+ }
+ }
+
+ if (truncated) {
+ goto interpret_cleanup;
+ }
+
+ /* Local file path and name, corresponding to requested URI
+ * is now stored in "filename" variable. */
+ if (mg_stat(conn, filename, filep)) {
+#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
+ /* File exists. Check if it is a script type. */
+ if (0
+#if !defined(NO_CGI)
+ || match_prefix(conn->ctx->config[CGI_EXTENSIONS],
+ strlen(conn->ctx->config[CGI_EXTENSIONS]),
+ filename) > 0
+#endif
+#if defined(USE_LUA)
+ || match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
+ strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
+ filename) > 0
+#endif
+#if defined(USE_DUKTAPE)
+ || match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
+ strlen(
+ conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
+ filename) > 0
+#endif
+ ) {
+ /* The request addresses a CGI script or a Lua script. The URI
+ * corresponds to the script itself (like /path/script.cgi),
+ * and there is no additional resource path
+ * (like /path/script.cgi/something).
+ * Requests that modify (replace or delete) a resource, like
+ * PUT and DELETE requests, should replace/delete the script
+ * file.
+ * Requests that read or write from/to a resource, like GET and
+ * POST requests, should call the script and return the
+ * generated response. */
+ *is_script_resource = !*is_put_or_delete_request;
+ }
+#endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
+ *is_found = 1;
+ return;
+ }
+
+ /* If we can't find the actual file, look for the file
+ * with the same name but a .gz extension. If we find it,
+ * use that and set the gzipped flag in the file struct
+ * to indicate that the response need to have the content-
+ * encoding: gzip header.
+ * We can only do this if the browser declares support. */
+ if ((accept_encoding = mg_get_header(conn, "Accept-Encoding")) != NULL) {
+ if (strstr(accept_encoding, "gzip") != NULL) {
+ mg_snprintf(
+ conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", filename);
+
+ if (truncated) {
+ goto interpret_cleanup;
+ }
+
+ if (mg_stat(conn, gz_path, filep)) {
+ if (filep) {
+ filep->gzipped = 1;
+ *is_found = 1;
+ }
+ /* Currently gz files can not be scripts. */
+ return;
+ }
+ }
+ }
+
+#if !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE)
+ /* Support PATH_INFO for CGI scripts. */
+ for (p = filename + strlen(filename); p > filename + 1; p--) {
+ if (*p == '/') {
+ *p = '\0';
+ if ((0
+#if !defined(NO_CGI)
+ || match_prefix(conn->ctx->config[CGI_EXTENSIONS],
+ strlen(conn->ctx->config[CGI_EXTENSIONS]),
+ filename) > 0
+#endif
+#if defined(USE_LUA)
+ || match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
+ strlen(
+ conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
+ filename) > 0
+#endif
+#if defined(USE_DUKTAPE)
+ || match_prefix(
+ conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
+ strlen(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
+ filename) > 0
+#endif
+ ) && mg_stat(conn, filename, filep)) {
+ /* Shift PATH_INFO block one character right, e.g.
+ * "/x.cgi/foo/bar\x00" => "/x.cgi\x00/foo/bar\x00"
+ * conn->path_info is pointing to the local variable "path"
+ * declared in handle_request(), so PATH_INFO is not valid
+ * after handle_request returns. */
+ conn->path_info = p + 1;
+ memmove(p + 2, p + 1, strlen(p + 1) + 1); /* +1 is for
+ * trailing \0 */
+ p[1] = '/';
+ *is_script_resource = 1;
+ break;
+ } else {
+ *p = '/';
+ }
+ }
+ }
+#endif /* !defined(NO_CGI) || defined(USE_LUA) || defined(USE_DUKTAPE) */
+#endif /* !defined(NO_FILES) */
+ return;
+
+#if !defined(NO_FILES)
+/* Reset all outputs */
+interpret_cleanup:
+ memset(filep, 0, sizeof(*filep));
+ *filename = 0;
+ *is_found = 0;
+ *is_script_resource = 0;
+ *is_websocket_request = 0;
+ *is_put_or_delete_request = 0;
+#endif /* !defined(NO_FILES) */
+}
+
+
+/* Check whether full request is buffered. Return:
+ * -1 if request is malformed
+ * 0 if request is not yet fully buffered
+ * >0 actual request length, including last \r\n\r\n */
+static int
+get_request_len(const char *buf, int buflen)
+{
+ const char *s, *e;
+ int len = 0;
+
+ for (s = buf, e = s + buflen - 1; len <= 0 && s < e; s++)
+ /* Control characters are not allowed but >=128 is. */
+ if (!isprint(*(const unsigned char *)s) && *s != '\r' && *s != '\n'
+ && *(const unsigned char *)s < 128) {
+ len = -1;
+ break; /* [i_a] abort scan as soon as one malformed character is
+ * found; */
+ /* don't let subsequent \r\n\r\n win us over anyhow */
+ } else if (s[0] == '\n' && s[1] == '\n') {
+ len = (int)(s - buf) + 2;
+ } else if (s[0] == '\n' && &s[1] < e && s[1] == '\r' && s[2] == '\n') {
+ len = (int)(s - buf) + 3;
+ }
+
+ return len;
+}
+
+
+#if !defined(NO_CACHING)
+/* Convert month to the month number. Return -1 on error, or month number */
+static int
+get_month_index(const char *s)
+{
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(month_names); i++) {
+ if (!strcmp(s, month_names[i])) {
+ return (int)i;
+ }
+ }
+
+ return -1;
+}
+
+
+/* Parse UTC date-time string, and return the corresponding time_t value. */
+static time_t
+parse_date_string(const char *datetime)
+{
+ char month_str[32] = {0};
+ int second, minute, hour, day, month, year;
+ time_t result = (time_t)0;
+ struct tm tm;
+
+ if ((sscanf(datetime,
+ "%d/%3s/%d %d:%d:%d",
+ &day,
+ month_str,
+ &year,
+ &hour,
+ &minute,
+ &second) == 6) || (sscanf(datetime,
+ "%d %3s %d %d:%d:%d",
+ &day,
+ month_str,
+ &year,
+ &hour,
+ &minute,
+ &second) == 6)
+ || (sscanf(datetime,
+ "%*3s, %d %3s %d %d:%d:%d",
+ &day,
+ month_str,
+ &year,
+ &hour,
+ &minute,
+ &second) == 6) || (sscanf(datetime,
+ "%d-%3s-%d %d:%d:%d",
+ &day,
+ month_str,
+ &year,
+ &hour,
+ &minute,
+ &second) == 6)) {
+ month = get_month_index(month_str);
+ if ((month >= 0) && (year >= 1970)) {
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = minute;
+ tm.tm_sec = second;
+ result = timegm(&tm);
+ }
+ }
+
+ return result;
+}
+#endif /* !NO_CACHING */
+
+
+/* Protect against directory disclosure attack by removing '..',
+ * excessive '/' and '\' characters */
+static void
+remove_double_dots_and_double_slashes(char *s)
+{
+ char *p = s;
+
+ while (*s != '\0') {
+ *p++ = *s++;
+ if (s[-1] == '/' || s[-1] == '\\') {
+ /* Skip all following slashes, backslashes and double-dots */
+ while (s[0] != '\0') {
+ if (s[0] == '/' || s[0] == '\\') {
+ s++;
+ } else if (s[0] == '.' && s[1] == '.') {
+ s += 2;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ *p = '\0';
+}
+
+
+static const struct {
+ const char *extension;
+ size_t ext_len;
+ const char *mime_type;
+} builtin_mime_types[] = {
+ /* IANA registered MIME types (http://www.iana.org/assignments/media-types)
+ * application types */
+ {".doc", 4, "application/msword"},
+ {".eps", 4, "application/postscript"},
+ {".exe", 4, "application/octet-stream"},
+ {".js", 3, "application/javascript"},
+ {".json", 5, "application/json"},
+ {".pdf", 4, "application/pdf"},
+ {".ps", 3, "application/postscript"},
+ {".rtf", 4, "application/rtf"},
+ {".xhtml", 6, "application/xhtml+xml"},
+ {".xsl", 4, "application/xml"},
+ {".xslt", 5, "application/xml"},
+
+ /* fonts */
+ {".ttf", 4, "application/font-sfnt"},
+ {".cff", 4, "application/font-sfnt"},
+ {".otf", 4, "application/font-sfnt"},
+ {".aat", 4, "application/font-sfnt"},
+ {".sil", 4, "application/font-sfnt"},
+ {".pfr", 4, "application/font-tdpfr"},
+ {".woff", 5, "application/font-woff"},
+
+ /* audio */
+ {".mp3", 4, "audio/mpeg"},
+ {".oga", 4, "audio/ogg"},
+ {".ogg", 4, "audio/ogg"},
+
+ /* image */
+ {".gif", 4, "image/gif"},
+ {".ief", 4, "image/ief"},
+ {".jpeg", 5, "image/jpeg"},
+ {".jpg", 4, "image/jpeg"},
+ {".jpm", 4, "image/jpm"},
+ {".jpx", 4, "image/jpx"},
+ {".png", 4, "image/png"},
+ {".svg", 4, "image/svg+xml"},
+ {".tif", 4, "image/tiff"},
+ {".tiff", 5, "image/tiff"},
+
+ /* model */
+ {".wrl", 4, "model/vrml"},
+
+ /* text */
+ {".css", 4, "text/css"},
+ {".csv", 4, "text/csv"},
+ {".htm", 4, "text/html"},
+ {".html", 5, "text/html"},
+ {".sgm", 4, "text/sgml"},
+ {".shtm", 5, "text/html"},
+ {".shtml", 6, "text/html"},
+ {".txt", 4, "text/plain"},
+ {".xml", 4, "text/xml"},
+
+ /* video */
+ {".mov", 4, "video/quicktime"},
+ {".mp4", 4, "video/mp4"},
+ {".mpeg", 5, "video/mpeg"},
+ {".mpg", 4, "video/mpeg"},
+ {".ogv", 4, "video/ogg"},
+ {".qt", 3, "video/quicktime"},
+
+ /* not registered types
+ * (http://reference.sitepoint.com/html/mime-types-full,
+ * http://www.hansenb.pdx.edu/DMKB/dict/tutorials/mime_typ.php, ..) */
+ {".arj", 4, "application/x-arj-compressed"},
+ {".gz", 3, "application/x-gunzip"},
+ {".rar", 4, "application/x-arj-compressed"},
+ {".swf", 4, "application/x-shockwave-flash"},
+ {".tar", 4, "application/x-tar"},
+ {".tgz", 4, "application/x-tar-gz"},
+ {".torrent", 8, "application/x-bittorrent"},
+ {".ppt", 4, "application/x-mspowerpoint"},
+ {".xls", 4, "application/x-msexcel"},
+ {".zip", 4, "application/x-zip-compressed"},
+ {".aac",
+ 4,
+ "audio/aac"}, /* http://en.wikipedia.org/wiki/Advanced_Audio_Coding */
+ {".aif", 4, "audio/x-aif"},
+ {".m3u", 4, "audio/x-mpegurl"},
+ {".mid", 4, "audio/x-midi"},
+ {".ra", 3, "audio/x-pn-realaudio"},
+ {".ram", 4, "audio/x-pn-realaudio"},
+ {".wav", 4, "audio/x-wav"},
+ {".bmp", 4, "image/bmp"},
+ {".ico", 4, "image/x-icon"},
+ {".pct", 4, "image/x-pct"},
+ {".pict", 5, "image/pict"},
+ {".rgb", 4, "image/x-rgb"},
+ {".webm", 5, "video/webm"}, /* http://en.wikipedia.org/wiki/WebM */
+ {".asf", 4, "video/x-ms-asf"},
+ {".avi", 4, "video/x-msvideo"},
+ {".m4v", 4, "video/x-m4v"},
+ {NULL, 0, NULL}};
+
+
+const char *
+mg_get_builtin_mime_type(const char *path)
+{
+ const char *ext;
+ size_t i, path_len;
+
+ path_len = strlen(path);
+
+ for (i = 0; builtin_mime_types[i].extension != NULL; i++) {
+ ext = path + (path_len - builtin_mime_types[i].ext_len);
+ if (path_len > builtin_mime_types[i].ext_len
+ && mg_strcasecmp(ext, builtin_mime_types[i].extension) == 0) {
+ return builtin_mime_types[i].mime_type;
+ }
+ }
+
+ return "text/plain";
+}
+
+
+/* Look at the "path" extension and figure what mime type it has.
+ * Store mime type in the vector. */
+static void
+get_mime_type(struct mg_context *ctx, const char *path, struct vec *vec)
+{
+ struct vec ext_vec, mime_vec;
+ const char *list, *ext;
+ size_t path_len;
+
+ path_len = strlen(path);
+
+ if (ctx == NULL || vec == NULL) {
+ return;
+ }
+
+ /* Scan user-defined mime types first, in case user wants to
+ * override default mime types. */
+ list = ctx->config[EXTRA_MIME_TYPES];
+ while ((list = next_option(list, &ext_vec, &mime_vec)) != NULL) {
+ /* ext now points to the path suffix */
+ ext = path + path_len - ext_vec.len;
+ if (mg_strncasecmp(ext, ext_vec.ptr, ext_vec.len) == 0) {
+ *vec = mime_vec;
+ return;
+ }
+ }
+
+ vec->ptr = mg_get_builtin_mime_type(path);
+ vec->len = strlen(vec->ptr);
+}
+
+
+/* Stringify binary data. Output buffer must be twice as big as input,
+ * because each byte takes 2 bytes in string representation */
+static void
+bin2str(char *to, const unsigned char *p, size_t len)
+{
+ static const char *hex = "0123456789abcdef";
+
+ for (; len--; p++) {
+ *to++ = hex[p[0] >> 4];
+ *to++ = hex[p[0] & 0x0f];
+ }
+ *to = '\0';
+}
+
+
+/* Return stringified MD5 hash for list of strings. Buffer must be 33 bytes. */
+char *
+mg_md5(char buf[33], ...)
+{
+ md5_byte_t hash[16];
+ const char *p;
+ va_list ap;
+ md5_state_t ctx;
+
+ md5_init(&ctx);
+
+ va_start(ap, buf);
+ while ((p = va_arg(ap, const char *)) != NULL) {
+ md5_append(&ctx, (const md5_byte_t *)p, strlen(p));
+ }
+ va_end(ap);
+
+ md5_finish(&ctx, hash);
+ bin2str(buf, hash, sizeof(hash));
+ return buf;
+}
+
+
+/* Check the user's password, return 1 if OK */
+static int
+check_password(const char *method,
+ const char *ha1,
+ const char *uri,
+ const char *nonce,
+ const char *nc,
+ const char *cnonce,
+ const char *qop,
+ const char *response)
+{
+ char ha2[32 + 1], expected_response[32 + 1];
+
+ /* Some of the parameters may be NULL */
+ if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL
+ || qop == NULL
+ || response == NULL) {
+ return 0;
+ }
+
+ /* NOTE(lsm): due to a bug in MSIE, we do not compare the URI */
+ if (strlen(response) != 32) {
+ return 0;
+ }
+
+ mg_md5(ha2, method, ":", uri, NULL);
+ mg_md5(expected_response,
+ ha1,
+ ":",
+ nonce,
+ ":",
+ nc,
+ ":",
+ cnonce,
+ ":",
+ qop,
+ ":",
+ ha2,
+ NULL);
+
+ return mg_strcasecmp(response, expected_response) == 0;
+}
+
+
+/* Use the global passwords file, if specified by auth_gpass option,
+ * or search for .htpasswd in the requested directory. */
+static void
+open_auth_file(struct mg_connection *conn, const char *path, struct file *filep)
+{
+ if (conn != NULL && conn->ctx != NULL) {
+ char name[PATH_MAX];
+ const char *p, *e, *gpass = conn->ctx->config[GLOBAL_PASSWORDS_FILE];
+ struct file file = STRUCT_FILE_INITIALIZER;
+ int truncated;
+
+ if (gpass != NULL) {
+ /* Use global passwords file */
+ if (!mg_fopen(conn, gpass, "r", filep)) {
+#ifdef DEBUG
+ mg_cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
+#endif
+ }
+ /* Important: using local struct file to test path for is_directory
+ * flag. If filep is used, mg_stat() makes it appear as if auth file
+ * was opened. */
+ } else if (mg_stat(conn, path, &file) && file.is_directory) {
+ mg_snprintf(conn,
+ &truncated,
+ name,
+ sizeof(name),
+ "%s/%s",
+ path,
+ PASSWORDS_FILE_NAME);
+
+ if (truncated || !mg_fopen(conn, name, "r", filep)) {
+#ifdef DEBUG
+ mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO));
+#endif
+ }
+ } else {
+ /* Try to find .htpasswd in requested directory. */
+ for (p = path, e = p + strlen(p) - 1; e > p; e--) {
+ if (e[0] == '/') {
+ break;
+ }
+ }
+ mg_snprintf(conn,
+ &truncated,
+ name,
+ sizeof(name),
+ "%.*s/%s",
+ (int)(e - p),
+ p,
+ PASSWORDS_FILE_NAME);
+
+ if (truncated || !mg_fopen(conn, name, "r", filep)) {
+#ifdef DEBUG
+ mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO));
+#endif
+ }
+ }
+ }
+}
+
+
+/* Parsed Authorization header */
+struct ah {
+ char *user, *uri, *cnonce, *response, *qop, *nc, *nonce;
+};
+
+
+/* Return 1 on success. Always initializes the ah structure. */
+static int
+parse_auth_header(struct mg_connection *conn,
+ char *buf,
+ size_t buf_size,
+ struct ah *ah)
+{
+ char *name, *value, *s;
+ const char *auth_header;
+ uint64_t nonce;
+
+ if (!ah || !conn) {
+ return 0;
+ }
+
+ (void)memset(ah, 0, sizeof(*ah));
+ if ((auth_header = mg_get_header(conn, "Authorization")) == NULL
+ || mg_strncasecmp(auth_header, "Digest ", 7) != 0) {
+ return 0;
+ }
+
+ /* Make modifiable copy of the auth header */
+ (void)mg_strlcpy(buf, auth_header + 7, buf_size);
+ s = buf;
+
+ /* Parse authorization header */
+ for (;;) {
+ /* Gobble initial spaces */
+ while (isspace(*(unsigned char *)s)) {
+ s++;
+ }
+ name = skip_quoted(&s, "=", " ", 0);
+ /* Value is either quote-delimited, or ends at first comma or space. */
+ if (s[0] == '\"') {
+ s++;
+ value = skip_quoted(&s, "\"", " ", '\\');
+ if (s[0] == ',') {
+ s++;
+ }
+ } else {
+ value = skip_quoted(&s, ", ", " ", 0); /* IE uses commas, FF uses
+ * spaces */
+ }
+ if (*name == '\0') {
+ break;
+ }
+
+ if (!strcmp(name, "username")) {
+ ah->user = value;
+ } else if (!strcmp(name, "cnonce")) {
+ ah->cnonce = value;
+ } else if (!strcmp(name, "response")) {
+ ah->response = value;
+ } else if (!strcmp(name, "uri")) {
+ ah->uri = value;
+ } else if (!strcmp(name, "qop")) {
+ ah->qop = value;
+ } else if (!strcmp(name, "nc")) {
+ ah->nc = value;
+ } else if (!strcmp(name, "nonce")) {
+ ah->nonce = value;
+ }
+ }
+
+#ifndef NO_NONCE_CHECK
+ /* Read the nonce from the response. */
+ if (ah->nonce == NULL) {
+ return 0;
+ }
+ s = NULL;
+ nonce = strtoull(ah->nonce, &s, 10);
+ if ((s == NULL) || (*s != 0)) {
+ return 0;
+ }
+
+ /* Convert the nonce from the client to a number. */
+ nonce ^= conn->ctx->auth_nonce_mask;
+
+ /* The converted number corresponds to the time the nounce has been
+ * created. This should not be earlier than the server start. */
+ /* Server side nonce check is valuable in all situations but one:
+ * if the server restarts frequently, but the client should not see
+ * that, so the server should accept nonces from previous starts. */
+ /* However, the reasonable default is to not accept a nonce from a
+ * previous start, so if anyone changed the access rights between
+ * two restarts, a new login is required. */
+ if (nonce < (uint64_t)conn->ctx->start_time) {
+ /* nonce is from a previous start of the server and no longer valid
+ * (replay attack?) */
+ return 0;
+ }
+ /* Check if the nonce is too high, so it has not (yet) been used by the
+ * server. */
+ if (nonce >= ((uint64_t)conn->ctx->start_time + conn->ctx->nonce_count)) {
+ return 0;
+ }
+#endif
+
+ /* CGI needs it as REMOTE_USER */
+ if (ah->user != NULL) {
+ conn->request_info.remote_user = mg_strdup(ah->user);
+ } else {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+static const char *
+mg_fgets(char *buf, size_t size, struct file *filep, char **p)
+{
+ const char *eof;
+ size_t len;
+ const char *memend;
+
+ if (!filep) {
+ return NULL;
+ }
+
+ if (filep->membuf != NULL && *p != NULL) {
+ memend = (const char *)&filep->membuf[filep->size];
+ /* Search for \n from p till the end of stream */
+ eof = (char *)memchr(*p, '\n', (size_t)(memend - *p));
+ if (eof != NULL) {
+ eof += 1; /* Include \n */
+ } else {
+ eof = memend; /* Copy remaining data */
+ }
+ len = (size_t)(eof - *p) > size - 1 ? size - 1 : (size_t)(eof - *p);
+ memcpy(buf, *p, len);
+ buf[len] = '\0';
+ *p += len;
+ return len ? eof : NULL;
+ } else if (filep->fp != NULL) {
+ return fgets(buf, (int)size, filep->fp);
+ } else {
+ return NULL;
+ }
+}
+
+struct read_auth_file_struct {
+ struct mg_connection *conn;
+ struct ah ah;
+ char *domain;
+ char buf[256 + 256 + 40];
+ char *f_user;
+ char *f_domain;
+ char *f_ha1;
+};
+
+
+static int
+read_auth_file(struct file *filep, struct read_auth_file_struct *workdata)
+{
+ char *p;
+ int is_authorized = 0;
+ struct file fp;
+ size_t l;
+
+ if (!filep || !workdata) {
+ return 0;
+ }
+
+ /* Loop over passwords file */
+ p = (char *)filep->membuf;
+ while (mg_fgets(workdata->buf, sizeof(workdata->buf), filep, &p) != NULL) {
+ l = strlen(workdata->buf);
+ while (l > 0) {
+ if (isspace(workdata->buf[l - 1])
+ || iscntrl(workdata->buf[l - 1])) {
+ l--;
+ workdata->buf[l] = 0;
+ } else
+ break;
+ }
+ if (l < 1) {
+ continue;
+ }
+
+ workdata->f_user = workdata->buf;
+
+ if (workdata->f_user[0] == ':') {
+ /* user names may not contain a ':' and may not be empty,
+ * so lines starting with ':' may be used for a special purpose */
+ if (workdata->f_user[1] == '#') {
+ /* :# is a comment */
+ continue;
+ } else if (!strncmp(workdata->f_user + 1, "include=", 8)) {
+ if (mg_fopen(workdata->conn, workdata->f_user + 9, "r", &fp)) {
+ is_authorized = read_auth_file(&fp, workdata);
+ mg_fclose(&fp);
+ } else {
+ mg_cry(workdata->conn,
+ "%s: cannot open authorization file: %s",
+ __func__,
+ workdata->buf);
+ }
+ continue;
+ }
+ /* everything is invalid for the moment (might change in the
+ * future) */
+ mg_cry(workdata->conn,
+ "%s: syntax error in authorization file: %s",
+ __func__,
+ workdata->buf);
+ continue;
+ }
+
+ workdata->f_domain = strchr(workdata->f_user, ':');
+ if (workdata->f_domain == NULL) {
+ mg_cry(workdata->conn,
+ "%s: syntax error in authorization file: %s",
+ __func__,
+ workdata->buf);
+ continue;
+ }
+ *(workdata->f_domain) = 0;
+ (workdata->f_domain)++;
+
+ workdata->f_ha1 = strchr(workdata->f_domain, ':');
+ if (workdata->f_ha1 == NULL) {
+ mg_cry(workdata->conn,
+ "%s: syntax error in authorization file: %s",
+ __func__,
+ workdata->buf);
+ continue;
+ }
+ *(workdata->f_ha1) = 0;
+ (workdata->f_ha1)++;
+
+ if (!strcmp(workdata->ah.user, workdata->f_user)
+ && !strcmp(workdata->domain, workdata->f_domain)) {
+ return check_password(workdata->conn->request_info.request_method,
+ workdata->f_ha1,
+ workdata->ah.uri,
+ workdata->ah.nonce,
+ workdata->ah.nc,
+ workdata->ah.cnonce,
+ workdata->ah.qop,
+ workdata->ah.response);
+ }
+ }
+
+ return is_authorized;
+}
+
+
+/* Authorize against the opened passwords file. Return 1 if authorized. */
+static int
+authorize(struct mg_connection *conn, struct file *filep)
+{
+ struct read_auth_file_struct workdata;
+ char buf[MG_BUF_LEN];
+
+ if (!conn || !conn->ctx) {
+ return 0;
+ }
+
+ memset(&workdata, 0, sizeof(workdata));
+ workdata.conn = conn;
+
+ if (!parse_auth_header(conn, buf, sizeof(buf), &workdata.ah)) {
+ return 0;
+ }
+ workdata.domain = conn->ctx->config[AUTHENTICATION_DOMAIN];
+
+ return read_auth_file(filep, &workdata);
+}
+
+
+/* Return 1 if request is authorised, 0 otherwise. */
+static int
+check_authorization(struct mg_connection *conn, const char *path)
+{
+ char fname[PATH_MAX];
+ struct vec uri_vec, filename_vec;
+ const char *list;
+ struct file file = STRUCT_FILE_INITIALIZER;
+ int authorized = 1, truncated;
+
+ if (!conn || !conn->ctx) {
+ return 0;
+ }
+
+ list = conn->ctx->config[PROTECT_URI];
+ while ((list = next_option(list, &uri_vec, &filename_vec)) != NULL) {
+ if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
+ mg_snprintf(conn,
+ &truncated,
+ fname,
+ sizeof(fname),
+ "%.*s",
+ (int)filename_vec.len,
+ filename_vec.ptr);
+
+ if (truncated || !mg_fopen(conn, fname, "r", &file)) {
+ mg_cry(conn,
+ "%s: cannot open %s: %s",
+ __func__,
+ fname,
+ strerror(errno));
+ }
+ break;
+ }
+ }
+
+ if (!is_file_opened(&file)) {
+ open_auth_file(conn, path, &file);
+ }
+
+ if (is_file_opened(&file)) {
+ authorized = authorize(conn, &file);
+ mg_fclose(&file);
+ }
+
+ return authorized;
+}
+
+
+static void
+send_authorization_request(struct mg_connection *conn)
+{
+ char date[64];
+ time_t curtime = time(NULL);
+
+ if (conn && conn->ctx) {
+ uint64_t nonce = (uint64_t)(conn->ctx->start_time);
+
+ (void)pthread_mutex_lock(&conn->ctx->nonce_mutex);
+ nonce += conn->ctx->nonce_count;
+ ++conn->ctx->nonce_count;
+ (void)pthread_mutex_unlock(&conn->ctx->nonce_mutex);
+
+ nonce ^= conn->ctx->auth_nonce_mask;
+ conn->status_code = 401;
+ conn->must_close = 1;
+
+ gmt_time_string(date, sizeof(date), &curtime);
+
+ mg_printf(conn, "HTTP/1.1 401 Unauthorized\r\n");
+ send_no_cache_header(conn);
+ mg_printf(conn,
+ "Date: %s\r\n"
+ "Connection: %s\r\n"
+ "Content-Length: 0\r\n"
+ "WWW-Authenticate: Digest qop=\"auth\", realm=\"%s\", "
+ "nonce=\"%" UINT64_FMT "\"\r\n\r\n",
+ date,
+ suggest_connection_header(conn),
+ conn->ctx->config[AUTHENTICATION_DOMAIN],
+ nonce);
+ }
+}
+
+
+#if !defined(NO_FILES)
+static int
+is_authorized_for_put(struct mg_connection *conn)
+{
+ if (conn) {
+ struct file file = STRUCT_FILE_INITIALIZER;
+ const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
+ int ret = 0;
+
+ if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) {
+ ret = authorize(conn, &file);
+ mg_fclose(&file);
+ }
+
+ return ret;
+ }
+ return 0;
+}
+#endif
+
+
+int
+mg_modify_passwords_file(const char *fname,
+ const char *domain,
+ const char *user,
+ const char *pass)
+{
+ int found, i;
+ char line[512], u[512] = "", d[512] = "", ha1[33], tmp[PATH_MAX + 8];
+ FILE *fp, *fp2;
+
+ found = 0;
+ fp = fp2 = NULL;
+
+ /* Regard empty password as no password - remove user record. */
+ if (pass != NULL && pass[0] == '\0') {
+ pass = NULL;
+ }
+
+ /* Other arguments must not be empty */
+ if (fname == NULL || domain == NULL || user == NULL) {
+ return 0;
+ }
+
+ /* Using the given file format, user name and domain must not contain ':'
+ */
+ if (strchr(user, ':') != NULL) {
+ return 0;
+ }
+ if (strchr(domain, ':') != NULL) {
+ return 0;
+ }
+
+ /* Do not allow control characters like newline in user name and domain.
+ * Do not allow excessively long names either. */
+ for (i = 0; i < 255 && user[i] != 0; i++) {
+ if (iscntrl(user[i])) {
+ return 0;
+ }
+ }
+ if (user[i]) {
+ return 0;
+ }
+ for (i = 0; i < 255 && domain[i] != 0; i++) {
+ if (iscntrl(domain[i])) {
+ return 0;
+ }
+ }
+ if (domain[i]) {
+ return 0;
+ }
+
+ /* The maximum length of the path to the password file is limited */
+ if ((strlen(fname) + 4) >= PATH_MAX) {
+ return 0;
+ }
+
+ /* Create a temporary file name. Length has been checked before. */
+ strcpy(tmp, fname);
+ strcat(tmp, ".tmp");
+
+ /* Create the file if does not exist */
+ /* Use of fopen here is OK, since fname is only ASCII */
+ if ((fp = fopen(fname, "a+")) != NULL) {
+ (void)fclose(fp);
+ }
+
+ /* Open the given file and temporary file */
+ if ((fp = fopen(fname, "r")) == NULL) {
+ return 0;
+ } else if ((fp2 = fopen(tmp, "w+")) == NULL) {
+ fclose(fp);
+ return 0;
+ }
+
+ /* Copy the stuff to temporary file */
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ if (sscanf(line, "%255[^:]:%255[^:]:%*s", u, d) != 2) {
+ continue;
+ }
+ u[255] = 0;
+ d[255] = 0;
+
+ if (!strcmp(u, user) && !strcmp(d, domain)) {
+ found++;
+ if (pass != NULL) {
+ mg_md5(ha1, user, ":", domain, ":", pass, NULL);
+ fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
+ }
+ } else {
+ fprintf(fp2, "%s", line);
+ }
+ }
+
+ /* If new user, just add it */
+ if (!found && pass != NULL) {
+ mg_md5(ha1, user, ":", domain, ":", pass, NULL);
+ fprintf(fp2, "%s:%s:%s\n", user, domain, ha1);
+ }
+
+ /* Close files */
+ fclose(fp);
+ fclose(fp2);
+
+ /* Put the temp file in place of real file */
+ IGNORE_UNUSED_RESULT(remove(fname));
+ IGNORE_UNUSED_RESULT(rename(tmp, fname));
+
+ return 1;
+}
+
+
+static int
+is_valid_port(unsigned long port)
+{
+ return port < 0xffff;
+}
+
+
+static int
+mg_inet_pton(int af, const char *src, void *dst, size_t dstlen)
+{
+ struct addrinfo hints, *res, *ressave;
+ int func_ret = 0;
+ int gai_ret;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = af;
+
+ gai_ret = getaddrinfo(src, NULL, &hints, &res);
+ if (gai_ret != 0) {
+ /* gai_strerror could be used to convert gai_ret to a string */
+ /* POSIX return values: see
+ * http://pubs.opengroup.org/onlinepubs/9699919799/functions/freeaddrinfo.html
+ */
+ /* Windows return values: see
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms738520%28v=vs.85%29.aspx
+ */
+ return 0;
+ }
+
+ ressave = res;
+
+ while (res) {
+ if (dstlen >= res->ai_addrlen) {
+ memcpy(dst, res->ai_addr, res->ai_addrlen);
+ func_ret = 1;
+ }
+ res = res->ai_next;
+ }
+
+ freeaddrinfo(ressave);
+ return func_ret;
+}
+
+
+static int
+connect_socket(struct mg_context *ctx /* may be NULL */,
+ const char *host,
+ int port,
+ int use_ssl,
+ char *ebuf,
+ size_t ebuf_len,
+ SOCKET *sock /* output: socket, must not be NULL */,
+ union usa *sa /* output: socket address, must not be NULL */
+ )
+{
+ int ip_ver = 0;
+ *sock = INVALID_SOCKET;
+ memset(sa, 0, sizeof(*sa));
+
+ if (ebuf_len > 0) {
+ *ebuf = 0;
+ }
+
+ if (host == NULL) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "NULL host");
+ return 0;
+ }
+
+ if (port < 0 || !is_valid_port((unsigned)port)) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "invalid port");
+ return 0;
+ }
+
+ if (use_ssl && (SSLv23_client_method == NULL)) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "SSL is not initialized");
+ return 0;
+ }
+
+ if (mg_inet_pton(AF_INET, host, &sa->sin, sizeof(sa->sin))) {
+ sa->sin.sin_port = htons((uint16_t)port);
+ ip_ver = 4;
+#ifdef USE_IPV6
+ } else if (mg_inet_pton(AF_INET6, host, &sa->sin6, sizeof(sa->sin6))) {
+ sa->sin6.sin6_port = htons((uint16_t)port);
+ ip_ver = 6;
+ } else if (host[0] == '[') {
+ /* While getaddrinfo on Windows will work with [::1],
+ * getaddrinfo on Linux only works with ::1 (without []). */
+ size_t l = strlen(host + 1);
+ char *h = l > 1 ? mg_strdup(host + 1) : NULL;
+ if (h) {
+ h[l - 1] = 0;
+ if (mg_inet_pton(AF_INET6, h, &sa->sin6, sizeof(sa->sin6))) {
+ sa->sin6.sin6_port = htons((uint16_t)port);
+ ip_ver = 6;
+ }
+ mg_free(h);
+ }
+#endif
+ }
+
+ if (ip_ver == 0) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "host not found");
+ return 0;
+ }
+
+ if (ip_ver == 4) {
+ *sock = socket(PF_INET, SOCK_STREAM, 0);
+ }
+#ifdef USE_IPV6
+ else if (ip_ver == 6) {
+ *sock = socket(PF_INET6, SOCK_STREAM, 0);
+ }
+#endif
+
+ if (*sock == INVALID_SOCKET) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "socket(): %s",
+ strerror(ERRNO));
+ return 0;
+ }
+
+ set_close_on_exec(*sock, fc(ctx));
+
+ if ((ip_ver == 4)
+ && (connect(*sock, (struct sockaddr *)&sa->sin, sizeof(sa->sin))
+ == 0)) {
+ /* connected with IPv4 */
+ return 1;
+ }
+
+#ifdef USE_IPV6
+ if ((ip_ver == 6)
+ && (connect(*sock, (struct sockaddr *)&sa->sin6, sizeof(sa->sin6))
+ == 0)) {
+ /* connected with IPv6 */
+ return 1;
+ }
+#endif
+
+ /* Not connected */
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "connect(%s:%d): %s",
+ host,
+ port,
+ strerror(ERRNO));
+ closesocket(*sock);
+ *sock = INVALID_SOCKET;
+ return 0;
+}
+
+
+int
+mg_url_encode(const char *src, char *dst, size_t dst_len)
+{
+ static const char *dont_escape = "._-$,;~()";
+ static const char *hex = "0123456789abcdef";
+ char *pos = dst;
+ const char *end = dst + dst_len - 1;
+
+ for (; *src != '\0' && pos < end; src++, pos++) {
+ if (isalnum(*(const unsigned char *)src)
+ || strchr(dont_escape, *(const unsigned char *)src) != NULL) {
+ *pos = *src;
+ } else if (pos + 2 < end) {
+ pos[0] = '%';
+ pos[1] = hex[(*(const unsigned char *)src) >> 4];
+ pos[2] = hex[(*(const unsigned char *)src) & 0xf];
+ pos += 2;
+ } else {
+ break;
+ }
+ }
+
+ *pos = '\0';
+ return (*src == '\0') ? (int)(pos - dst) : -1;
+}
+
+
+static void
+print_dir_entry(struct de *de)
+{
+ char size[64], mod[64], href[PATH_MAX];
+ struct tm *tm;
+
+ if (de->file.is_directory) {
+ mg_snprintf(de->conn,
+ NULL, /* Buffer is big enough */
+ size,
+ sizeof(size),
+ "%s",
+ "[DIRECTORY]");
+ } else {
+ /* We use (signed) cast below because MSVC 6 compiler cannot
+ * convert unsigned __int64 to double. Sigh. */
+ if (de->file.size < 1024) {
+ mg_snprintf(de->conn,
+ NULL, /* Buffer is big enough */
+ size,
+ sizeof(size),
+ "%d",
+ (int)de->file.size);
+ } else if (de->file.size < 0x100000) {
+ mg_snprintf(de->conn,
+ NULL, /* Buffer is big enough */
+ size,
+ sizeof(size),
+ "%.1fk",
+ (double)de->file.size / 1024.0);
+ } else if (de->file.size < 0x40000000) {
+ mg_snprintf(de->conn,
+ NULL, /* Buffer is big enough */
+ size,
+ sizeof(size),
+ "%.1fM",
+ (double)de->file.size / 1048576);
+ } else {
+ mg_snprintf(de->conn,
+ NULL, /* Buffer is big enough */
+ size,
+ sizeof(size),
+ "%.1fG",
+ (double)de->file.size / 1073741824);
+ }
+ }
+
+ /* Note: mg_snprintf will not cause a buffer overflow above.
+ * So, string truncation checks are not required here. */
+
+ tm = localtime(&de->file.last_modified);
+ if (tm != NULL) {
+ strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm);
+ } else {
+ mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
+ mod[sizeof(mod) - 1] = '\0';
+ }
+ mg_url_encode(de->file_name, href, sizeof(href));
+ de->conn->num_bytes_sent +=
+ mg_printf(de->conn,
+ "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
+ "<td> %s</td><td> %s</td></tr>\n",
+ de->conn->request_info.local_uri,
+ href,
+ de->file.is_directory ? "/" : "",
+ de->file_name,
+ de->file.is_directory ? "/" : "",
+ mod,
+ size);
+}
+
+
+/* This function is called from send_directory() and used for
+ * sorting directory entries by size, or name, or modification time.
+ * On windows, __cdecl specification is needed in case if project is built
+ * with __stdcall convention. qsort always requires __cdels callback. */
+static int WINCDECL
+compare_dir_entries(const void *p1, const void *p2)
+{
+ if (p1 && p2) {
+ const struct de *a = (const struct de *)p1, *b = (const struct de *)p2;
+ const char *query_string = a->conn->request_info.query_string;
+ int cmp_result = 0;
+
+ if (query_string == NULL) {
+ query_string = "na";
+ }
+
+ if (a->file.is_directory && !b->file.is_directory) {
+ return -1; /* Always put directories on top */
+ } else if (!a->file.is_directory && b->file.is_directory) {
+ return 1; /* Always put directories on top */
+ } else if (*query_string == 'n') {
+ cmp_result = strcmp(a->file_name, b->file_name);
+ } else if (*query_string == 's') {
+ cmp_result = a->file.size == b->file.size
+ ? 0
+ : a->file.size > b->file.size ? 1 : -1;
+ } else if (*query_string == 'd') {
+ cmp_result =
+ (a->file.last_modified == b->file.last_modified)
+ ? 0
+ : ((a->file.last_modified > b->file.last_modified) ? 1
+ : -1);
+ }
+
+ return query_string[1] == 'd' ? -cmp_result : cmp_result;
+ }
+ return 0;
+}
+
+
+static int
+must_hide_file(struct mg_connection *conn, const char *path)
+{
+ if (conn && conn->ctx) {
+ const char *pw_pattern = "**" PASSWORDS_FILE_NAME "$";
+ const char *pattern = conn->ctx->config[HIDE_FILES];
+ return match_prefix(pw_pattern, strlen(pw_pattern), path) > 0
+ || (pattern != NULL
+ && match_prefix(pattern, strlen(pattern), path) > 0);
+ }
+ return 0;
+}
+
+
+static int
+scan_directory(struct mg_connection *conn,
+ const char *dir,
+ void *data,
+ void (*cb)(struct de *, void *))
+{
+ char path[PATH_MAX];
+ struct dirent *dp;
+ DIR *dirp;
+ struct de de;
+ int truncated;
+
+ if ((dirp = mg_opendir(conn, dir)) == NULL) {
+ return 0;
+ } else {
+ de.conn = conn;
+
+ while ((dp = mg_readdir(dirp)) != NULL) {
+ /* Do not show current dir and hidden files */
+ if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")
+ || must_hide_file(conn, dp->d_name)) {
+ continue;
+ }
+
+ mg_snprintf(
+ conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
+
+ /* If we don't memset stat structure to zero, mtime will have
+ * garbage and strftime() will segfault later on in
+ * print_dir_entry(). memset is required only if mg_stat()
+ * fails. For more details, see
+ * http://code.google.com/p/mongoose/issues/detail?id=79 */
+ memset(&de.file, 0, sizeof(de.file));
+
+ if (truncated) {
+ /* If the path is not complete, skip processing. */
+ continue;
+ }
+
+ if (!mg_stat(conn, path, &de.file)) {
+ mg_cry(conn,
+ "%s: mg_stat(%s) failed: %s",
+ __func__,
+ path,
+ strerror(ERRNO));
+ }
+ de.file_name = dp->d_name;
+ cb(&de, data);
+ }
+ (void)mg_closedir(dirp);
+ }
+ return 1;
+}
+
+
+#if !defined(NO_FILES)
+static int
+remove_directory(struct mg_connection *conn, const char *dir)
+{
+ char path[PATH_MAX];
+ struct dirent *dp;
+ DIR *dirp;
+ struct de de;
+ int truncated;
+ int ok = 1;
+
+ if ((dirp = mg_opendir(conn, dir)) == NULL) {
+ return 0;
+ } else {
+ de.conn = conn;
+
+ while ((dp = mg_readdir(dirp)) != NULL) {
+ /* Do not show current dir (but show hidden files as they will
+ * also be removed) */
+ if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
+ continue;
+ }
+
+ mg_snprintf(
+ conn, &truncated, path, sizeof(path), "%s/%s", dir, dp->d_name);
+
+ /* If we don't memset stat structure to zero, mtime will have
+ * garbage and strftime() will segfault later on in
+ * print_dir_entry(). memset is required only if mg_stat()
+ * fails. For more details, see
+ * http://code.google.com/p/mongoose/issues/detail?id=79 */
+ memset(&de.file, 0, sizeof(de.file));
+
+ if (truncated) {
+ /* Do not delete anything shorter */
+ ok = 0;
+ continue;
+ }
+
+ if (!mg_stat(conn, path, &de.file)) {
+ mg_cry(conn,
+ "%s: mg_stat(%s) failed: %s",
+ __func__,
+ path,
+ strerror(ERRNO));
+ ok = 0;
+ }
+ if (de.file.membuf == NULL) {
+ /* file is not in memory */
+ if (de.file.is_directory) {
+ if (remove_directory(conn, path) == 0) {
+ ok = 0;
+ }
+ } else {
+ if (mg_remove(conn, path) == 0) {
+ ok = 0;
+ }
+ }
+ } else {
+ /* file is in memory. It can not be deleted. */
+ ok = 0;
+ }
+ }
+ (void)mg_closedir(dirp);
+
+ IGNORE_UNUSED_RESULT(rmdir(dir));
+ }
+
+ return ok;
+}
+#endif
+
+
+struct dir_scan_data {
+ struct de *entries;
+ unsigned int num_entries;
+ unsigned int arr_size;
+};
+
+
+/* Behaves like realloc(), but frees original pointer on failure */
+static void *
+realloc2(void *ptr, size_t size)
+{
+ void *new_ptr = mg_realloc(ptr, size);
+ if (new_ptr == NULL) {
+ mg_free(ptr);
+ }
+ return new_ptr;
+}
+
+
+static void
+dir_scan_callback(struct de *de, void *data)
+{
+ struct dir_scan_data *dsd = (struct dir_scan_data *)data;
+
+ if (dsd->entries == NULL || dsd->num_entries >= dsd->arr_size) {
+ dsd->arr_size *= 2;
+ dsd->entries =
+ (struct de *)realloc2(dsd->entries,
+ dsd->arr_size * sizeof(dsd->entries[0]));
+ }
+ if (dsd->entries == NULL) {
+ /* TODO(lsm, low): propagate an error to the caller */
+ dsd->num_entries = 0;
+ } else {
+ dsd->entries[dsd->num_entries].file_name = mg_strdup(de->file_name);
+ dsd->entries[dsd->num_entries].file = de->file;
+ dsd->entries[dsd->num_entries].conn = de->conn;
+ dsd->num_entries++;
+ }
+}
+
+
+static void
+handle_directory_request(struct mg_connection *conn, const char *dir)
+{
+ unsigned int i;
+ int sort_direction;
+ struct dir_scan_data data = {NULL, 0, 128};
+ char date[64];
+ time_t curtime = time(NULL);
+
+ if (!scan_directory(conn, dir, &data, dir_scan_callback)) {
+ send_http_error(conn,
+ 500,
+ "Error: Cannot open directory\nopendir(%s): %s",
+ dir,
+ strerror(ERRNO));
+ return;
+ }
+
+ gmt_time_string(date, sizeof(date), &curtime);
+
+ if (!conn) {
+ return;
+ }
+
+ sort_direction = conn->request_info.query_string != NULL
+ && conn->request_info.query_string[1] == 'd'
+ ? 'a'
+ : 'd';
+
+ conn->must_close = 1;
+ mg_printf(conn, "HTTP/1.1 200 OK\r\n");
+ send_static_cache_header(conn);
+ mg_printf(conn,
+ "Date: %s\r\n"
+ "Connection: close\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n\r\n",
+ date);
+
+ conn->num_bytes_sent +=
+ mg_printf(conn,
+ "<html><head><title>Index of %s</title>"
+ "<style>th {text-align: left;}</style></head>"
+ "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
+ "<tr><th><a href=\"?n%c\">Name</a></th>"
+ "<th><a href=\"?d%c\">Modified</a></th>"
+ "<th><a href=\"?s%c\">Size</a></th></tr>"
+ "<tr><td colspan=\"3\"><hr></td></tr>",
+ conn->request_info.local_uri,
+ conn->request_info.local_uri,
+ sort_direction,
+ sort_direction,
+ sort_direction);
+
+ /* Print first entry - link to a parent directory */
+ conn->num_bytes_sent +=
+ mg_printf(conn,
+ "<tr><td><a href=\"%s%s\">%s</a></td>"
+ "<td> %s</td><td> %s</td></tr>\n",
+ conn->request_info.local_uri,
+ "..",
+ "Parent directory",
+ "-",
+ "-");
+
+ /* Sort and print directory entries */
+ if (data.entries != NULL) {
+ qsort(data.entries,
+ (size_t)data.num_entries,
+ sizeof(data.entries[0]),
+ compare_dir_entries);
+ for (i = 0; i < data.num_entries; i++) {
+ print_dir_entry(&data.entries[i]);
+ mg_free(data.entries[i].file_name);
+ }
+ mg_free(data.entries);
+ }
+
+ conn->num_bytes_sent += mg_printf(conn, "%s", "</table></body></html>");
+ conn->status_code = 200;
+}
+
+
+/* Send len bytes from the opened file to the client. */
+static void
+send_file_data(struct mg_connection *conn,
+ struct file *filep,
+ int64_t offset,
+ int64_t len)
+{
+ char buf[MG_BUF_LEN];
+ int to_read, num_read, num_written;
+ int64_t size;
+
+ if (!filep || !conn) {
+ return;
+ }
+
+ /* Sanity check the offset */
+ size = filep->size > INT64_MAX ? INT64_MAX : (int64_t)(filep->size);
+ offset = offset < 0 ? 0 : offset > size ? size : offset;
+
+ if (len > 0 && filep->membuf != NULL && size > 0) {
+ /* file stored in memory */
+ if (len > size - offset) {
+ len = size - offset;
+ }
+ mg_write(conn, filep->membuf + offset, (size_t)len);
+ } else if (len > 0 && filep->fp != NULL) {
+/* file stored on disk */
+#if defined(__linux__)
+ /* sendfile is only available for Linux */
+ if (conn->throttle == 0 && conn->ssl == 0) {
+ off_t sf_offs = (off_t)offset;
+ ssize_t sf_sent;
+ int sf_file = fileno(filep->fp);
+ int loop_cnt = 0;
+
+ do {
+ /* 2147479552 (0x7FFFF000) is a limit found by experiment on
+ * 64 bit Linux (2^31 minus one memory page of 4k?). */
+ size_t sf_tosend =
+ (size_t)((len < 0x7FFFF000) ? len : 0x7FFFF000);
+ sf_sent =
+ sendfile(conn->client.sock, sf_file, &sf_offs, sf_tosend);
+ if (sf_sent > 0) {
+ conn->num_bytes_sent += sf_sent;
+ len -= sf_sent;
+ offset += sf_sent;
+ } else if (loop_cnt == 0) {
+ /* This file can not be sent using sendfile.
+ * This might be the case for pseudo-files in the
+ * /sys/ and /proc/ file system.
+ * Use the regular user mode copy code instead. */
+ break;
+ } else if (sf_sent == 0) {
+ /* No error, but 0 bytes sent. May be EOF? */
+ return;
+ }
+ loop_cnt++;
+
+ } while ((len > 0) && (sf_sent >= 0));
+
+ if (sf_sent > 0) {
+ return; /* OK */
+ }
+
+ /* sf_sent<0 means error, thus fall back to the classic way */
+ /* This is always the case, if sf_file is not a "normal" file,
+ * e.g., for sending data from the output of a CGI process. */
+ offset = (int64_t)sf_offs;
+ }
+#endif
+ if ((offset > 0) && (fseeko(filep->fp, offset, SEEK_SET) != 0)) {
+ mg_cry(conn, "%s: fseeko() failed: %s", __func__, strerror(ERRNO));
+ send_http_error(
+ conn,
+ 500,
+ "%s",
+ "Error: Unable to access file at requested position.");
+ } else {
+ while (len > 0) {
+ /* Calculate how much to read from the file in the buffer */
+ to_read = sizeof(buf);
+ if ((int64_t)to_read > len) {
+ to_read = (int)len;
+ }
+
+ /* Read from file, exit the loop on error */
+ if ((num_read = (int)fread(buf, 1, (size_t)to_read, filep->fp))
+ <= 0) {
+ break;
+ }
+
+ /* Send read bytes to the client, exit the loop on error */
+ if ((num_written = mg_write(conn, buf, (size_t)num_read))
+ != num_read) {
+ break;
+ }
+
+ /* Both read and were successful, adjust counters */
+ conn->num_bytes_sent += num_written;
+ len -= num_written;
+ }
+ }
+ }
+}
+
+
+static int
+parse_range_header(const char *header, int64_t *a, int64_t *b)
+{
+ return sscanf(header, "bytes=%" INT64_FMT "-%" INT64_FMT, a, b);
+}
+
+
+static void
+construct_etag(char *buf, size_t buf_len, const struct file *filep)
+{
+ if (filep != NULL && buf != NULL) {
+ mg_snprintf(NULL,
+ NULL, /* All calls to construct_etag use 64 byte buffer */
+ buf,
+ buf_len,
+ "\"%lx.%" INT64_FMT "\"",
+ (unsigned long)filep->last_modified,
+ filep->size);
+ }
+}
+
+
+static void
+fclose_on_exec(struct file *filep, struct mg_connection *conn)
+{
+ if (filep != NULL && filep->fp != NULL) {
+#ifdef _WIN32
+ (void)conn; /* Unused. */
+#else
+ if (fcntl(fileno(filep->fp), F_SETFD, FD_CLOEXEC) != 0) {
+ mg_cry(conn,
+ "%s: fcntl(F_SETFD FD_CLOEXEC) failed: %s",
+ __func__,
+ strerror(ERRNO));
+ }
+#endif
+ }
+}
+
+
+static void
+handle_static_file_request(struct mg_connection *conn,
+ const char *path,
+ struct file *filep,
+ const char *mime_type)
+{
+ char date[64], lm[64], etag[64];
+ char range[128]; /* large enough, so there will be no overflow */
+ const char *msg = "OK", *hdr;
+ time_t curtime = time(NULL);
+ int64_t cl, r1, r2;
+ struct vec mime_vec;
+ int n, truncated;
+ char gz_path[PATH_MAX];
+ const char *encoding = "";
+ const char *cors1, *cors2, *cors3;
+
+ if (conn == NULL || conn->ctx == NULL || filep == NULL) {
+ return;
+ }
+
+ if (mime_type == NULL) {
+ get_mime_type(conn->ctx, path, &mime_vec);
+ } else {
+ mime_vec.ptr = mime_type;
+ mime_vec.len = strlen(mime_type);
+ }
+ if (filep->size > INT64_MAX) {
+ send_http_error(conn,
+ 500,
+ "Error: File size is too large to send\n%" INT64_FMT,
+ filep->size);
+ }
+ cl = (int64_t)filep->size;
+ conn->status_code = 200;
+ range[0] = '\0';
+
+ /* if this file is in fact a pre-gzipped file, rewrite its filename
+ * it's important to rewrite the filename after resolving
+ * the mime type from it, to preserve the actual file's type */
+ if (filep->gzipped) {
+ mg_snprintf(conn, &truncated, gz_path, sizeof(gz_path), "%s.gz", path);
+
+ if (truncated) {
+ send_http_error(conn,
+ 500,
+ "Error: Path of zipped file too long (%s)",
+ path);
+ return;
+ }
+
+ path = gz_path;
+ encoding = "Content-Encoding: gzip\r\n";
+ }
+
+ if (!mg_fopen(conn, path, "rb", filep)) {
+ send_http_error(conn,
+ 500,
+ "Error: Cannot open file\nfopen(%s): %s",
+ path,
+ strerror(ERRNO));
+ return;
+ }
+
+ fclose_on_exec(filep, conn);
+
+ /* If Range: header specified, act accordingly */
+ r1 = r2 = 0;
+ hdr = mg_get_header(conn, "Range");
+ if (hdr != NULL && (n = parse_range_header(hdr, &r1, &r2)) > 0 && r1 >= 0
+ && r2 >= 0) {
+ /* actually, range requests don't play well with a pre-gzipped
+ * file (since the range is specified in the uncompressed space) */
+ if (filep->gzipped) {
+ send_http_error(
+ conn,
+ 501,
+ "%s",
+ "Error: Range requests in gzipped files are not supported");
+ mg_fclose(filep);
+ return;
+ }
+ conn->status_code = 206;
+ cl = n == 2 ? (r2 > cl ? cl : r2) - r1 + 1 : cl - r1;
+ mg_snprintf(conn,
+ NULL, /* range buffer is big enough */
+ range,
+ sizeof(range),
+ "Content-Range: bytes "
+ "%" INT64_FMT "-%" INT64_FMT "/%" INT64_FMT "\r\n",
+ r1,
+ r1 + cl - 1,
+ filep->size);
+ msg = "Partial Content";
+ }
+
+ hdr = mg_get_header(conn, "Origin");
+ if (hdr) {
+ /* Cross-origin resource sharing (CORS), see
+ * http://www.html5rocks.com/en/tutorials/cors/,
+ * http://www.html5rocks.com/static/images/cors_server_flowchart.png -
+ * preflight is not supported for files. */
+ cors1 = "Access-Control-Allow-Origin: ";
+ cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
+ cors3 = "\r\n";
+ } else {
+ cors1 = cors2 = cors3 = "";
+ }
+
+ /* Prepare Etag, Date, Last-Modified headers. Must be in UTC, according to
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3 */
+ gmt_time_string(date, sizeof(date), &curtime);
+ gmt_time_string(lm, sizeof(lm), &filep->last_modified);
+ construct_etag(etag, sizeof(etag), filep);
+
+ (void)mg_printf(conn,
+ "HTTP/1.1 %d %s\r\n"
+ "%s%s%s"
+ "Date: %s\r\n",
+ conn->status_code,
+ msg,
+ cors1,
+ cors2,
+ cors3,
+ date);
+ send_static_cache_header(conn);
+ (void)mg_printf(conn,
+ "Last-Modified: %s\r\n"
+ "Etag: %s\r\n"
+ "Content-Type: %.*s\r\n"
+ "Content-Length: %" INT64_FMT "\r\n"
+ "Connection: %s\r\n"
+ "Accept-Ranges: bytes\r\n"
+ "%s%s\r\n",
+ lm,
+ etag,
+ (int)mime_vec.len,
+ mime_vec.ptr,
+ cl,
+ suggest_connection_header(conn),
+ range,
+ encoding);
+
+ if (strcmp(conn->request_info.request_method, "HEAD") != 0) {
+ send_file_data(conn, filep, r1, cl);
+ }
+ mg_fclose(filep);
+}
+
+
+void
+mg_send_file(struct mg_connection *conn, const char *path)
+{
+ mg_send_mime_file(conn, path, NULL);
+}
+
+
+void
+mg_send_mime_file(struct mg_connection *conn,
+ const char *path,
+ const char *mime_type)
+{
+ struct file file = STRUCT_FILE_INITIALIZER;
+ if (mg_stat(conn, path, &file)) {
+ if (file.is_directory) {
+ if (!conn) {
+ return;
+ }
+ if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING],
+ "yes")) {
+ handle_directory_request(conn, path);
+ } else {
+ send_http_error(conn,
+ 403,
+ "%s",
+ "Error: Directory listing denied");
+ }
+ } else {
+ handle_static_file_request(conn, path, &file, mime_type);
+ }
+ } else {
+ send_http_error(conn, 404, "%s", "Error: File not found");
+ }
+}
+
+
+/* For a given PUT path, create all intermediate subdirectories.
+ * Return 0 if the path itself is a directory.
+ * Return 1 if the path leads to a file.
+ * Return -1 for if the path is too long.
+ * Return -2 if path can not be created.
+*/
+static int
+put_dir(struct mg_connection *conn, const char *path)
+{
+ char buf[PATH_MAX];
+ const char *s, *p;
+ struct file file = STRUCT_FILE_INITIALIZER;
+ size_t len;
+ int res = 1;
+
+ for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
+ len = (size_t)(p - path);
+ if (len >= sizeof(buf)) {
+ /* path too long */
+ res = -1;
+ break;
+ }
+ memcpy(buf, path, len);
+ buf[len] = '\0';
+
+ /* Try to create intermediate directory */
+ DEBUG_TRACE("mkdir(%s)", buf);
+ if (!mg_stat(conn, buf, &file) && mg_mkdir(conn, buf, 0755) != 0) {
+ /* path does not exixt and can not be created */
+ res = -2;
+ break;
+ }
+
+ /* Is path itself a directory? */
+ if (p[1] == '\0') {
+ res = 0;
+ }
+ }
+
+ return res;
+}
+
+
+static void
+remove_bad_file(const struct mg_connection *conn, const char *path)
+{
+ int r = mg_remove(conn, path);
+ if (r != 0) {
+ mg_cry(conn, "%s: Cannot remove invalid file %s", __func__, path);
+ }
+}
+
+
+long long
+mg_store_body(struct mg_connection *conn, const char *path)
+{
+ char buf[MG_BUF_LEN];
+ long long len = 0;
+ int ret, n;
+ struct file fi;
+
+ if (conn->consumed_content != 0) {
+ mg_cry(conn, "%s: Contents already consumed", __func__);
+ return -11;
+ }
+
+ ret = put_dir(conn, path);
+ if (ret < 0) {
+ /* -1 for path too long,
+ * -2 for path can not be created. */
+ return ret;
+ }
+ if (ret != 1) {
+ /* Return 0 means, path itself is a directory. */
+ return 0;
+ }
+
+ if (mg_fopen(conn, path, "w", &fi) == 0) {
+ return -12;
+ }
+
+ ret = mg_read(conn, buf, sizeof(buf));
+ while (ret > 0) {
+ n = (int)fwrite(buf, 1, (size_t)ret, fi.fp);
+ if (n != ret) {
+ mg_fclose(&fi);
+ remove_bad_file(conn, path);
+ return -13;
+ }
+ ret = mg_read(conn, buf, sizeof(buf));
+ }
+
+ /* TODO: mg_fclose should return an error,
+ * and every caller should check and handle it. */
+ if (fclose(fi.fp) != 0) {
+ remove_bad_file(conn, path);
+ return -14;
+ }
+
+ return len;
+}
+
+
+/* Parse HTTP headers from the given buffer, advance buffer to the point
+ * where parsing stopped. */
+static void
+parse_http_headers(char **buf, struct mg_request_info *ri)
+{
+ int i;
+
+ if (!ri) {
+ return;
+ }
+
+ ri->num_headers = 0;
+
+ for (i = 0; i < (int)ARRAY_SIZE(ri->http_headers); i++) {
+ char *dp = *buf;
+ while ((*dp != ':') && (*dp != '\r') && (*dp != 0)) {
+ dp++;
+ }
+ if (!*dp) {
+ /* neither : nor \r\n. This is not a valid field. */
+ break;
+ }
+ if (*dp == '\r') {
+ if (dp[1] == '\n') {
+ /* \r\n */
+ ri->http_headers[i].name = *buf;
+ ri->http_headers[i].value = 0;
+ *buf = dp;
+ } else {
+ /* stray \r. This is not valid. */
+ break;
+ }
+ } else {
+ /* (*dp == ':') */
+ *dp = 0;
+ ri->http_headers[i].name = *buf;
+ do {
+ dp++;
+ } while (*dp == ' ');
+
+ ri->http_headers[i].value = dp;
+ *buf = strstr(dp, "\r\n");
+ }
+
+ ri->num_headers = i + 1;
+ if (*buf) {
+ (*buf)[0] = 0;
+ (*buf)[1] = 0;
+ *buf += 2;
+ } else {
+ *buf = dp;
+ break;
+ }
+
+ if (*buf[0] == '\r') {
+ /* This is the end of the header */
+ break;
+ }
+ }
+}
+
+
+static int
+is_valid_http_method(const char *method)
+{
+ return !strcmp(method, "GET") /* HTTP (RFC 2616) */
+ || !strcmp(method, "POST") /* HTTP (RFC 2616) */
+ || !strcmp(method, "HEAD") /* HTTP (RFC 2616) */
+ || !strcmp(method, "PUT") /* HTTP (RFC 2616) */
+ || !strcmp(method, "DELETE") /* HTTP (RFC 2616) */
+ || !strcmp(method, "OPTIONS") /* HTTP (RFC 2616) */
+ /* TRACE method (RFC 2616) is not supported for security reasons */
+ || !strcmp(method, "CONNECT") /* HTTP (RFC 2616) */
+
+ || !strcmp(method, "PROPFIND") /* WEBDAV (RFC 2518) */
+ || !strcmp(method, "MKCOL") /* WEBDAV (RFC 2518) */
+
+ /* Unsupported WEBDAV Methods: */
+ /* PROPPATCH, COPY, MOVE, LOCK, UNLOCK (RFC 2518) */
+ /* + 11 methods from RFC 3253 */
+ /* ORDERPATCH (RFC 3648) */
+ /* ACL (RFC 3744) */
+ /* SEARCH (RFC 5323) */
+ /* + MicroSoft extensions
+ * https://msdn.microsoft.com/en-us/library/aa142917.aspx */
+
+ /* PATCH method only allowed for CGI/Lua/LSP and callbacks. */
+ || !strcmp(method, "PATCH"); /* PATCH method (RFC 5789) */
+}
+
+
+/* Parse HTTP request, fill in mg_request_info structure.
+ * This function modifies the buffer by NUL-terminating
+ * HTTP request components, header names and header values. */
+static int
+parse_http_message(char *buf, int len, struct mg_request_info *ri)
+{
+ int is_request, request_length;
+
+ if (!ri) {
+ return 0;
+ }
+
+ request_length = get_request_len(buf, len);
+
+ if (request_length > 0) {
+ /* Reset attributes. DO NOT TOUCH is_ssl, remote_ip, remote_addr,
+ * remote_port */
+ ri->remote_user = ri->request_method = ri->request_uri =
+ ri->http_version = NULL;
+ ri->num_headers = 0;
+
+ buf[request_length - 1] = '\0';
+
+ /* RFC says that all initial whitespaces should be ingored */
+ while (*buf != '\0' && isspace(*(unsigned char *)buf)) {
+ buf++;
+ }
+ ri->request_method = skip(&buf, " ");
+ ri->request_uri = skip(&buf, " ");
+ ri->http_version = skip(&buf, "\r\n");
+
+ /* HTTP message could be either HTTP request or HTTP response, e.g.
+ * "GET / HTTP/1.0 ...." or "HTTP/1.0 200 OK ..." */
+ is_request = is_valid_http_method(ri->request_method);
+ if ((is_request && memcmp(ri->http_version, "HTTP/", 5) != 0)
+ || (!is_request && memcmp(ri->request_method, "HTTP/", 5) != 0)) {
+ request_length = -1;
+ } else {
+ if (is_request) {
+ ri->http_version += 5;
+ }
+ parse_http_headers(&buf, ri);
+ }
+ }
+ return request_length;
+}
+
+
+/* Keep reading the input (either opened file descriptor fd, or socket sock,
+ * or SSL descriptor ssl) into buffer buf, until \r\n\r\n appears in the
+ * buffer (which marks the end of HTTP request). Buffer buf may already
+ * have some data. The length of the data is stored in nread.
+ * Upon every read operation, increase nread by the number of bytes read. */
+static int
+read_request(FILE *fp,
+ struct mg_connection *conn,
+ char *buf,
+ int bufsiz,
+ int *nread)
+{
+ int request_len, n = 0;
+ struct timespec last_action_time;
+ double request_timeout;
+
+ if (!conn) {
+ return 0;
+ }
+
+ memset(&last_action_time, 0, sizeof(last_action_time));
+
+ if (conn->ctx->config[REQUEST_TIMEOUT]) {
+ /* value of request_timeout is in seconds, config in milliseconds */
+ request_timeout = atof(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+ } else {
+ request_timeout = -1.0;
+ }
+
+ request_len = get_request_len(buf, *nread);
+
+ /* first time reading from this connection */
+ clock_gettime(CLOCK_MONOTONIC, &last_action_time);
+
+ while (
+ (conn->ctx->stop_flag == 0) && (*nread < bufsiz) && (request_len == 0)
+ && ((mg_difftimespec(&last_action_time, &(conn->req_time))
+ <= request_timeout) || (request_timeout < 0))
+ && ((n = pull(fp, conn, buf + *nread, bufsiz - *nread, request_timeout))
+ > 0)) {
+ *nread += n;
+ /* assert(*nread <= bufsiz); */
+ if (*nread > bufsiz) {
+ return -2;
+ }
+ request_len = get_request_len(buf, *nread);
+ if (request_timeout > 0.0) {
+ clock_gettime(CLOCK_MONOTONIC, &last_action_time);
+ }
+ }
+
+ return (request_len <= 0 && n <= 0) ? -1 : request_len;
+}
+
+#if !defined(NO_FILES)
+/* For given directory path, substitute it to valid index file.
+ * Return 1 if index file has been found, 0 if not found.
+ * If the file is found, it's stats is returned in stp. */
+static int
+substitute_index_file(struct mg_connection *conn,
+ char *path,
+ size_t path_len,
+ struct file *filep)
+{
+ if (conn && conn->ctx) {
+ const char *list = conn->ctx->config[INDEX_FILES];
+ struct file file = STRUCT_FILE_INITIALIZER;
+ struct vec filename_vec;
+ size_t n = strlen(path);
+ int found = 0;
+
+ /* The 'path' given to us points to the directory. Remove all trailing
+ * directory separator characters from the end of the path, and
+ * then append single directory separator character. */
+ while (n > 0 && path[n - 1] == '/') {
+ n--;
+ }
+ path[n] = '/';
+
+ /* Traverse index files list. For each entry, append it to the given
+ * path and see if the file exists. If it exists, break the loop */
+ while ((list = next_option(list, &filename_vec, NULL)) != NULL) {
+ /* Ignore too long entries that may overflow path buffer */
+ if (filename_vec.len > path_len - (n + 2)) {
+ continue;
+ }
+
+ /* Prepare full path to the index file */
+ mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
+
+ /* Does it exist? */
+ if (mg_stat(conn, path, &file)) {
+ /* Yes it does, break the loop */
+ *filep = file;
+ found = 1;
+ break;
+ }
+ }
+
+ /* If no index file exists, restore directory path */
+ if (!found) {
+ path[n] = '\0';
+ }
+
+ return found;
+ }
+ return 0;
+}
+#endif
+
+
+#if !defined(NO_CACHING)
+/* Return True if we should reply 304 Not Modified. */
+static int
+is_not_modified(const struct mg_connection *conn, const struct file *filep)
+{
+ char etag[64];
+ const char *ims = mg_get_header(conn, "If-Modified-Since");
+ const char *inm = mg_get_header(conn, "If-None-Match");
+ construct_etag(etag, sizeof(etag), filep);
+ if (!filep) {
+ return 0;
+ }
+ return (inm != NULL && !mg_strcasecmp(etag, inm))
+ || (ims != NULL && (filep->last_modified <= parse_date_string(ims)));
+}
+#endif /* !NO_CACHING */
+
+
+#if !defined(NO_CGI) || !defined(NO_FILES)
+static int
+forward_body_data(struct mg_connection *conn, FILE *fp, SOCKET sock, SSL *ssl)
+{
+ const char *expect, *body;
+ char buf[MG_BUF_LEN];
+ int to_read, nread, success = 0;
+ int64_t buffered_len;
+ double timeout = -1.0;
+
+ if (!conn) {
+ return 0;
+ }
+ if (conn->ctx->config[REQUEST_TIMEOUT]) {
+ timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+ }
+
+ expect = mg_get_header(conn, "Expect");
+ /* assert(fp != NULL); */
+ if (!fp) {
+ send_http_error(conn, 500, "%s", "Error: NULL File");
+ return 0;
+ }
+
+ if (conn->content_len == -1 && !conn->is_chunked) {
+ /* Content length is not specified by the client. */
+ send_http_error(conn,
+ 411,
+ "%s",
+ "Error: Client did not specify content length");
+ } else if ((expect != NULL)
+ && (mg_strcasecmp(expect, "100-continue") != 0)) {
+ /* Client sent an "Expect: xyz" header and xyz is not 100-continue. */
+ send_http_error(conn,
+ 417,
+ "Error: Can not fulfill expectation %s",
+ expect);
+ } else {
+ if (expect != NULL) {
+ (void)mg_printf(conn, "%s", "HTTP/1.1 100 Continue\r\n\r\n");
+ conn->status_code = 100;
+ } else {
+ conn->status_code = 200;
+ }
+
+ buffered_len = (int64_t)(conn->data_len) - (int64_t)conn->request_len
+ - conn->consumed_content;
+
+ /* assert(buffered_len >= 0); */
+ /* assert(conn->consumed_content == 0); */
+
+ if ((buffered_len < 0) || (conn->consumed_content != 0)) {
+ send_http_error(conn, 500, "%s", "Error: Size mismatch");
+ return 0;
+ }
+
+ if (buffered_len > 0) {
+ if ((int64_t)buffered_len > conn->content_len) {
+ buffered_len = (int)conn->content_len;
+ }
+ body = conn->buf + conn->request_len + conn->consumed_content;
+ push_all(conn->ctx, fp, sock, ssl, body, (int64_t)buffered_len);
+ conn->consumed_content += buffered_len;
+ }
+
+ nread = 0;
+ while (conn->consumed_content < conn->content_len) {
+ to_read = sizeof(buf);
+ if ((int64_t)to_read > conn->content_len - conn->consumed_content) {
+ to_read = (int)(conn->content_len - conn->consumed_content);
+ }
+ nread = pull(NULL, conn, buf, to_read, timeout);
+ if (nread <= 0
+ || push_all(conn->ctx, fp, sock, ssl, buf, nread) != nread) {
+ break;
+ }
+ conn->consumed_content += nread;
+ }
+
+ if (conn->consumed_content == conn->content_len) {
+ success = (nread >= 0);
+ }
+
+ /* Each error code path in this function must send an error */
+ if (!success) {
+ /* NOTE: Maybe some data has already been sent. */
+ /* TODO (low): If some data has been sent, a correct error
+ * reply can no longer be sent, so just close the connection */
+ send_http_error(conn, 500, "%s", "");
+ }
+ }
+
+ return success;
+}
+#endif
+
+#if !defined(NO_CGI)
+/* This structure helps to create an environment for the spawned CGI program.
+ * Environment is an array of "VARIABLE=VALUE\0" ASCIIZ strings,
+ * last element must be NULL.
+ * However, on Windows there is a requirement that all these VARIABLE=VALUE\0
+ * strings must reside in a contiguous buffer. The end of the buffer is
+ * marked by two '\0' characters.
+ * We satisfy both worlds: we create an envp array (which is vars), all
+ * entries are actually pointers inside buf. */
+struct cgi_environment {
+ struct mg_connection *conn;
+ /* Data block */
+ char *buf; /* Environment buffer */
+ size_t buflen; /* Space available in buf */
+ size_t bufused; /* Space taken in buf */
+ /* Index block */
+ char **var; /* char **envp */
+ size_t varlen; /* Number of variables available in var */
+ size_t varused; /* Number of variables stored in var */
+};
+
+
+static void addenv(struct cgi_environment *env,
+ PRINTF_FORMAT_STRING(const char *fmt),
+ ...) PRINTF_ARGS(2, 3);
+
+/* Append VARIABLE=VALUE\0 string to the buffer, and add a respective
+ * pointer into the vars array. Assumes env != NULL and fmt != NULL. */
+static void
+addenv(struct cgi_environment *env, const char *fmt, ...)
+{
+ size_t n, space;
+ int truncated;
+ char *added;
+ va_list ap;
+
+ /* Calculate how much space is left in the buffer */
+ space = (env->buflen - env->bufused);
+
+ /* Calculate an estimate for the required space */
+ n = strlen(fmt) + 2 + 128;
+
+ do {
+ if (space <= n) {
+ /* Allocate new buffer */
+ n = env->buflen + CGI_ENVIRONMENT_SIZE;
+ added = (char *)mg_realloc(env->buf, n);
+ if (!added) {
+ /* Out of memory */
+ mg_cry(env->conn,
+ "%s: Cannot allocate memory for CGI variable [%s]",
+ __func__,
+ fmt);
+ return;
+ }
+ env->buf = added;
+ env->buflen = n;
+ space = (env->buflen - env->bufused);
+ }
+
+ /* Make a pointer to the free space int the buffer */
+ added = env->buf + env->bufused;
+
+ /* Copy VARIABLE=VALUE\0 string into the free space */
+ va_start(ap, fmt);
+ mg_vsnprintf(env->conn, &truncated, added, (size_t)space, fmt, ap);
+ va_end(ap);
+
+ /* Do not add truncated strings to the environment */
+ if (truncated) {
+ /* Reallocate the buffer */
+ space = 0;
+ n = 1;
+ }
+ } while (truncated);
+
+ /* Calculate number of bytes added to the environment */
+ n = strlen(added) + 1;
+ env->bufused += n;
+
+ /* Now update the variable index */
+ space = (env->varlen - env->varused);
+ if (space < 2) {
+ mg_cry(env->conn,
+ "%s: Cannot register CGI variable [%s]",
+ __func__,
+ fmt);
+ return;
+ }
+
+ /* Append a pointer to the added string into the envp array */
+ env->var[env->varused] = added;
+ env->varused++;
+}
+
+
+static void
+prepare_cgi_environment(struct mg_connection *conn,
+ const char *prog,
+ struct cgi_environment *env)
+{
+ const char *s;
+ struct vec var_vec;
+ char *p, src_addr[IP_ADDR_STR_LEN], http_var_name[128];
+ int i, truncated;
+
+ if (conn == NULL || prog == NULL || env == NULL) {
+ return;
+ }
+
+ env->conn = conn;
+ env->buflen = CGI_ENVIRONMENT_SIZE;
+ env->bufused = 0;
+ env->buf = (char *)mg_malloc(env->buflen);
+ env->varlen = MAX_CGI_ENVIR_VARS;
+ env->varused = 0;
+ env->var = (char **)mg_malloc(env->buflen * sizeof(char *));
+
+ addenv(env, "SERVER_NAME=%s", conn->ctx->config[AUTHENTICATION_DOMAIN]);
+ addenv(env, "SERVER_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
+ addenv(env, "DOCUMENT_ROOT=%s", conn->ctx->config[DOCUMENT_ROOT]);
+ addenv(env, "SERVER_SOFTWARE=%s/%s", "Civetweb", mg_version());
+
+ /* Prepare the environment block */
+ addenv(env, "%s", "GATEWAY_INTERFACE=CGI/1.1");
+ addenv(env, "%s", "SERVER_PROTOCOL=HTTP/1.1");
+ addenv(env, "%s", "REDIRECT_STATUS=200"); /* For PHP */
+
+#if defined(USE_IPV6)
+ if (conn->client.lsa.sa.sa_family == AF_INET6) {
+ addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin6.sin6_port));
+ } else
+#endif
+ {
+ addenv(env, "SERVER_PORT=%d", ntohs(conn->client.lsa.sin.sin_port));
+ }
+
+ sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+ addenv(env, "REMOTE_ADDR=%s", src_addr);
+
+ addenv(env, "REQUEST_METHOD=%s", conn->request_info.request_method);
+ addenv(env, "REMOTE_PORT=%d", conn->request_info.remote_port);
+
+ addenv(env, "REQUEST_URI=%s", conn->request_info.request_uri);
+ addenv(env, "LOCAL_URI=%s", conn->request_info.local_uri);
+
+ /* SCRIPT_NAME */
+ addenv(env,
+ "SCRIPT_NAME=%.*s",
+ (int)strlen(conn->request_info.local_uri)
+ - ((conn->path_info == NULL) ? 0 : (int)strlen(conn->path_info)),
+ conn->request_info.local_uri);
+
+ addenv(env, "SCRIPT_FILENAME=%s", prog);
+ if (conn->path_info == NULL) {
+ addenv(env, "PATH_TRANSLATED=%s", conn->ctx->config[DOCUMENT_ROOT]);
+ } else {
+ addenv(env,
+ "PATH_TRANSLATED=%s%s",
+ conn->ctx->config[DOCUMENT_ROOT],
+ conn->path_info);
+ }
+
+ addenv(env, "HTTPS=%s", conn->ssl == NULL ? "off" : "on");
+
+ if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
+ addenv(env, "CONTENT_TYPE=%s", s);
+ }
+ if (conn->request_info.query_string != NULL) {
+ addenv(env, "QUERY_STRING=%s", conn->request_info.query_string);
+ }
+ if ((s = mg_get_header(conn, "Content-Length")) != NULL) {
+ addenv(env, "CONTENT_LENGTH=%s", s);
+ }
+ if ((s = getenv("PATH")) != NULL) {
+ addenv(env, "PATH=%s", s);
+ }
+ if (conn->path_info != NULL) {
+ addenv(env, "PATH_INFO=%s", conn->path_info);
+ }
+
+ if (conn->status_code > 0) {
+ /* CGI error handler should show the status code */
+ addenv(env, "STATUS=%d", conn->status_code);
+ }
+
+#if defined(_WIN32)
+ if ((s = getenv("COMSPEC")) != NULL) {
+ addenv(env, "COMSPEC=%s", s);
+ }
+ if ((s = getenv("SYSTEMROOT")) != NULL) {
+ addenv(env, "SYSTEMROOT=%s", s);
+ }
+ if ((s = getenv("SystemDrive")) != NULL) {
+ addenv(env, "SystemDrive=%s", s);
+ }
+ if ((s = getenv("ProgramFiles")) != NULL) {
+ addenv(env, "ProgramFiles=%s", s);
+ }
+ if ((s = getenv("ProgramFiles(x86)")) != NULL) {
+ addenv(env, "ProgramFiles(x86)=%s", s);
+ }
+#else
+ if ((s = getenv("LD_LIBRARY_PATH")) != NULL) {
+ addenv(env, "LD_LIBRARY_PATH=%s", s);
+ }
+#endif /* _WIN32 */
+
+ if ((s = getenv("PERLLIB")) != NULL) {
+ addenv(env, "PERLLIB=%s", s);
+ }
+
+ if (conn->request_info.remote_user != NULL) {
+ addenv(env, "REMOTE_USER=%s", conn->request_info.remote_user);
+ addenv(env, "%s", "AUTH_TYPE=Digest");
+ }
+
+ /* Add all headers as HTTP_* variables */
+ for (i = 0; i < conn->request_info.num_headers; i++) {
+
+ (void)mg_snprintf(conn,
+ &truncated,
+ http_var_name,
+ sizeof(http_var_name),
+ "HTTP_%s",
+ conn->request_info.http_headers[i].name);
+
+ if (truncated) {
+ mg_cry(conn,
+ "%s: HTTP header variable too long [%s]",
+ __func__,
+ conn->request_info.http_headers[i].name);
+ continue;
+ }
+
+ /* Convert variable name into uppercase, and change - to _ */
+ for (p = http_var_name; *p != '\0'; p++) {
+ if (*p == '-') {
+ *p = '_';
+ }
+ *p = (char)toupper(*(unsigned char *)p);
+ }
+
+ addenv(env,
+ "%s=%s",
+ http_var_name,
+ conn->request_info.http_headers[i].value);
+ }
+
+ /* Add user-specified variables */
+ s = conn->ctx->config[CGI_ENVIRONMENT];
+ while ((s = next_option(s, &var_vec, NULL)) != NULL) {
+ addenv(env, "%.*s", (int)var_vec.len, var_vec.ptr);
+ }
+
+ env->var[env->varused] = NULL;
+ env->buf[env->bufused] = '\0';
+}
+
+
+static void
+handle_cgi_request(struct mg_connection *conn, const char *prog)
+{
+ char *buf;
+ size_t buflen;
+ int headers_len, data_len, i, truncated;
+ int fdin[2] = {-1, -1}, fdout[2] = {-1, -1}, fderr[2] = {-1, -1};
+ const char *status, *status_text, *connection_state;
+ char *pbuf, dir[PATH_MAX], *p;
+ struct mg_request_info ri;
+ struct cgi_environment blk;
+ FILE *in = NULL, *out = NULL, *err = NULL;
+ struct file fout = STRUCT_FILE_INITIALIZER;
+ pid_t pid = (pid_t)-1;
+
+ if (conn == NULL) {
+ return;
+ }
+
+ buf = NULL;
+ buflen = 16384;
+ prepare_cgi_environment(conn, prog, &blk);
+
+ /* CGI must be executed in its own directory. 'dir' must point to the
+ * directory containing executable program, 'p' must point to the
+ * executable program name relative to 'dir'. */
+ (void)mg_snprintf(conn, &truncated, dir, sizeof(dir), "%s", prog);
+
+ if (truncated) {
+ mg_cry(conn, "Error: CGI program \"%s\": Path too long", prog);
+ send_http_error(conn, 500, "Error: %s", "CGI path too long");
+ goto done;
+ }
+
+ if ((p = strrchr(dir, '/')) != NULL) {
+ *p++ = '\0';
+ } else {
+ dir[0] = '.', dir[1] = '\0';
+ p = (char *)prog;
+ }
+
+ if (pipe(fdin) != 0 || pipe(fdout) != 0 || pipe(fderr) != 0) {
+ status = strerror(ERRNO);
+ mg_cry(conn,
+ "Error: CGI program \"%s\": Can not create CGI pipes: %s",
+ prog,
+ status);
+ send_http_error(conn, 500, "Error: Cannot create CGI pipe: %s", status);
+ goto done;
+ }
+
+ pid = spawn_process(conn, p, blk.buf, blk.var, fdin, fdout, fderr, dir);
+
+ if (pid == (pid_t)-1) {
+ status = strerror(ERRNO);
+ mg_cry(conn,
+ "Error: CGI program \"%s\": Can not spawn CGI process: %s",
+ prog,
+ status);
+ send_http_error(conn,
+ 500,
+ "Error: Cannot spawn CGI process [%s]: %s",
+ prog,
+ status);
+ goto done;
+ }
+
+ /* Make sure child closes all pipe descriptors. It must dup them to 0,1 */
+ set_close_on_exec((SOCKET)fdin[0], conn); /* stdin read */
+ set_close_on_exec((SOCKET)fdout[1], conn); /* stdout write */
+ set_close_on_exec((SOCKET)fderr[1], conn); /* stderr write */
+ set_close_on_exec((SOCKET)fdin[1], conn); /* stdin write */
+ set_close_on_exec((SOCKET)fdout[0], conn); /* stdout read */
+ set_close_on_exec((SOCKET)fderr[0], conn); /* stderr read */
+
+ /* Parent closes only one side of the pipes.
+ * If we don't mark them as closed, close() attempt before
+ * return from this function throws an exception on Windows.
+ * Windows does not like when closed descriptor is closed again. */
+ (void)close(fdin[0]);
+ (void)close(fdout[1]);
+ (void)close(fderr[1]);
+ fdin[0] = fdout[1] = fderr[1] = -1;
+
+ if ((in = fdopen(fdin[1], "wb")) == NULL) {
+ status = strerror(ERRNO);
+ mg_cry(conn,
+ "Error: CGI program \"%s\": Can not open stdin: %s",
+ prog,
+ status);
+ send_http_error(conn,
+ 500,
+ "Error: CGI can not open fdin\nfopen: %s",
+ status);
+ goto done;
+ }
+
+ if ((out = fdopen(fdout[0], "rb")) == NULL) {
+ status = strerror(ERRNO);
+ mg_cry(conn,
+ "Error: CGI program \"%s\": Can not open stdout: %s",
+ prog,
+ status);
+ send_http_error(conn,
+ 500,
+ "Error: CGI can not open fdout\nfopen: %s",
+ status);
+ goto done;
+ }
+
+ if ((err = fdopen(fderr[0], "rb")) == NULL) {
+ status = strerror(ERRNO);
+ mg_cry(conn,
+ "Error: CGI program \"%s\": Can not open stderr: %s",
+ prog,
+ status);
+ send_http_error(conn,
+ 500,
+ "Error: CGI can not open fdout\nfopen: %s",
+ status);
+ goto done;
+ }
+
+ setbuf(in, NULL);
+ setbuf(out, NULL);
+ setbuf(err, NULL);
+ fout.fp = out;
+
+ if ((conn->request_info.content_length > 0) || conn->is_chunked) {
+ /* This is a POST/PUT request, or another request with body data. */
+ if (!forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
+ /* Error sending the body data */
+ mg_cry(conn,
+ "Error: CGI program \"%s\": Forward body data failed",
+ prog);
+ goto done;
+ }
+ }
+
+ /* Close so child gets an EOF. */
+ fclose(in);
+ in = NULL;
+ fdin[1] = -1;
+
+ /* Now read CGI reply into a buffer. We need to set correct
+ * status code, thus we need to see all HTTP headers first.
+ * Do not send anything back to client, until we buffer in all
+ * HTTP headers. */
+ data_len = 0;
+ buf = (char *)mg_malloc(buflen);
+ if (buf == NULL) {
+ send_http_error(conn,
+ 500,
+ "Error: Not enough memory for CGI buffer (%u bytes)",
+ (unsigned int)buflen);
+ mg_cry(conn,
+ "Error: CGI program \"%s\": Not enough memory for buffer (%u "
+ "bytes)",
+ prog,
+ (unsigned int)buflen);
+ goto done;
+ }
+ headers_len = read_request(out, conn, buf, (int)buflen, &data_len);
+ if (headers_len <= 0) {
+
+ /* Could not parse the CGI response. Check if some error message on
+ * stderr. */
+ i = pull_all(err, conn, buf, (int)buflen);
+ if (i > 0) {
+ mg_cry(conn,
+ "Error: CGI program \"%s\" sent error "
+ "message: [%.*s]",
+ prog,
+ i,
+ buf);
+ send_http_error(conn,
+ 500,
+ "Error: CGI program \"%s\" sent error "
+ "message: [%.*s]",
+ prog,
+ i,
+ buf);
+ } else {
+ mg_cry(conn,
+ "Error: CGI program sent malformed or too big "
+ "(>%u bytes) HTTP headers: [%.*s]",
+ (unsigned)buflen,
+ data_len,
+ buf);
+
+ send_http_error(conn,
+ 500,
+ "Error: CGI program sent malformed or too big "
+ "(>%u bytes) HTTP headers: [%.*s]",
+ (unsigned)buflen,
+ data_len,
+ buf);
+ }
+
+ goto done;
+ }
+ pbuf = buf;
+ buf[headers_len - 1] = '\0';
+ parse_http_headers(&pbuf, &ri);
+
+ /* Make up and send the status line */
+ status_text = "OK";
+ if ((status = get_header(&ri, "Status")) != NULL) {
+ conn->status_code = atoi(status);
+ status_text = status;
+ while (isdigit(*(const unsigned char *)status_text)
+ || *status_text == ' ') {
+ status_text++;
+ }
+ } else if (get_header(&ri, "Location") != NULL) {
+ conn->status_code = 302;
+ } else {
+ conn->status_code = 200;
+ }
+ connection_state = get_header(&ri, "Connection");
+ if (!header_has_option(connection_state, "keep-alive")) {
+ conn->must_close = 1;
+ }
+ (void)mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, status_text);
+
+ /* Send headers */
+ for (i = 0; i < ri.num_headers; i++) {
+ mg_printf(conn,
+ "%s: %s\r\n",
+ ri.http_headers[i].name,
+ ri.http_headers[i].value);
+ }
+ mg_write(conn, "\r\n", 2);
+
+ /* Send chunk of data that may have been read after the headers */
+ conn->num_bytes_sent +=
+ mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len));
+
+ /* Read the rest of CGI output and send to the client */
+ send_file_data(conn, &fout, 0, INT64_MAX);
+
+done:
+ mg_free(blk.var);
+ mg_free(blk.buf);
+
+ if (pid != (pid_t)-1) {
+ kill(pid, SIGKILL);
+#if !defined(_WIN32)
+ {
+ int st;
+ while (waitpid(pid, &st, 0) != -1)
+ ; /* clean zombies */
+ }
+#endif
+ }
+ if (fdin[0] != -1) {
+ close(fdin[0]);
+ }
+ if (fdout[1] != -1) {
+ close(fdout[1]);
+ }
+
+ if (in != NULL) {
+ fclose(in);
+ } else if (fdin[1] != -1) {
+ close(fdin[1]);
+ }
+
+ if (out != NULL) {
+ fclose(out);
+ } else if (fdout[0] != -1) {
+ close(fdout[0]);
+ }
+
+ if (err != NULL) {
+ fclose(err);
+ } else if (fderr[0] != -1) {
+ close(fderr[0]);
+ }
+
+ if (buf != NULL) {
+ mg_free(buf);
+ }
+}
+#endif /* !NO_CGI */
+
+
+#if !defined(NO_FILES)
+static void
+mkcol(struct mg_connection *conn, const char *path)
+{
+ int rc, body_len;
+ struct de de;
+ char date[64];
+ time_t curtime = time(NULL);
+
+ if (conn == NULL) {
+ return;
+ }
+
+ /* TODO (mid): Check the send_http_error situations in this function */
+
+ memset(&de.file, 0, sizeof(de.file));
+ if (!mg_stat(conn, path, &de.file)) {
+ mg_cry(conn,
+ "%s: mg_stat(%s) failed: %s",
+ __func__,
+ path,
+ strerror(ERRNO));
+ }
+
+ if (de.file.last_modified) {
+ /* TODO (high): This check does not seem to make any sense ! */
+ send_http_error(
+ conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO));
+ return;
+ }
+
+ body_len = conn->data_len - conn->request_len;
+ if (body_len > 0) {
+ send_http_error(
+ conn, 415, "Error: mkcol(%s): %s", path, strerror(ERRNO));
+ return;
+ }
+
+ rc = mg_mkdir(conn, path, 0755);
+
+ if (rc == 0) {
+ conn->status_code = 201;
+ gmt_time_string(date, sizeof(date), &curtime);
+ mg_printf(conn,
+ "HTTP/1.1 %d Created\r\n"
+ "Date: %s\r\n",
+ conn->status_code,
+ date);
+ send_static_cache_header(conn);
+ mg_printf(conn,
+ "Content-Length: 0\r\n"
+ "Connection: %s\r\n\r\n",
+ suggest_connection_header(conn));
+ } else if (rc == -1) {
+ if (errno == EEXIST) {
+ send_http_error(
+ conn, 405, "Error: mkcol(%s): %s", path, strerror(ERRNO));
+ } else if (errno == EACCES) {
+ send_http_error(
+ conn, 403, "Error: mkcol(%s): %s", path, strerror(ERRNO));
+ } else if (errno == ENOENT) {
+ send_http_error(
+ conn, 409, "Error: mkcol(%s): %s", path, strerror(ERRNO));
+ } else {
+ send_http_error(conn, 500, "fopen(%s): %s", path, strerror(ERRNO));
+ }
+ }
+}
+
+
+static void
+put_file(struct mg_connection *conn, const char *path)
+{
+ struct file file = STRUCT_FILE_INITIALIZER;
+ const char *range;
+ int64_t r1, r2;
+ int rc;
+ char date[64];
+ time_t curtime = time(NULL);
+
+ if (conn == NULL) {
+ return;
+ }
+
+ if (mg_stat(conn, path, &file)) {
+ /* File already exists */
+ conn->status_code = 200;
+
+ if (file.is_directory) {
+ /* This is an already existing directory,
+ * so there is nothing to do for the server. */
+ rc = 0;
+
+ } else {
+ /* File exists and is not a directory. */
+ /* Can it be replaced? */
+
+ if (file.membuf != NULL) {
+ /* This is an "in-memory" file, that can not be replaced */
+ send_http_error(
+ conn,
+ 405,
+ "Error: Put not possible\nReplacing %s is not supported",
+ path);
+ return;
+ }
+
+ /* Check if the server may write this file */
+ if (access(path, W_OK) == 0) {
+ /* Access granted */
+ conn->status_code = 200;
+ rc = 1;
+ } else {
+ send_http_error(
+ conn,
+ 403,
+ "Error: Put not possible\nReplacing %s is not allowed",
+ path);
+ return;
+ }
+ }
+ } else {
+ /* File should be created */
+ conn->status_code = 201;
+ rc = put_dir(conn, path);
+ }
+
+ if (rc == 0) {
+ /* put_dir returns 0 if path is a directory */
+ gmt_time_string(date, sizeof(date), &curtime);
+ mg_printf(conn,
+ "HTTP/1.1 %d %s\r\n",
+ conn->status_code,
+ mg_get_response_code_text(NULL, conn->status_code));
+ send_no_cache_header(conn);
+ mg_printf(conn,
+ "Date: %s\r\n"
+ "Content-Length: 0\r\n"
+ "Connection: %s\r\n\r\n",
+ date,
+ suggest_connection_header(conn));
+
+ /* Request to create a directory has been fulfilled successfully.
+ * No need to put a file. */
+ return;
+ }
+
+ if (rc == -1) {
+ /* put_dir returns -1 if the path is too long */
+ send_http_error(conn,
+ 414,
+ "Error: Path too long\nput_dir(%s): %s",
+ path,
+ strerror(ERRNO));
+ return;
+ }
+
+ if (rc == -2) {
+ /* put_dir returns -2 if the directory can not be created */
+ send_http_error(conn,
+ 500,
+ "Error: Can not create directory\nput_dir(%s): %s",
+ path,
+ strerror(ERRNO));
+ return;
+ }
+
+ /* A file should be created or overwritten. */
+ if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
+ mg_fclose(&file);
+ send_http_error(conn,
+ 500,
+ "Error: Can not create file\nfopen(%s): %s",
+ path,
+ strerror(ERRNO));
+ return;
+ }
+
+ fclose_on_exec(&file, conn);
+ range = mg_get_header(conn, "Content-Range");
+ r1 = r2 = 0;
+ if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
+ conn->status_code = 206; /* Partial content */
+ fseeko(file.fp, r1, SEEK_SET);
+ }
+
+ if (!forward_body_data(conn, file.fp, INVALID_SOCKET, NULL)) {
+ /* forward_body_data failed.
+ * The error code has already been sent to the client,
+ * and conn->status_code is already set. */
+ mg_fclose(&file);
+ return;
+ }
+
+ gmt_time_string(date, sizeof(date), &curtime);
+ mg_printf(conn,
+ "HTTP/1.1 %d %s\r\n",
+ conn->status_code,
+ mg_get_response_code_text(NULL, conn->status_code));
+ send_no_cache_header(conn);
+ mg_printf(conn,
+ "Date: %s\r\n"
+ "Content-Length: 0\r\n"
+ "Connection: %s\r\n\r\n",
+ date,
+ suggest_connection_header(conn));
+
+ mg_fclose(&file);
+}
+
+
+static void
+delete_file(struct mg_connection *conn, const char *path)
+{
+ struct de de;
+ memset(&de.file, 0, sizeof(de.file));
+ if (!mg_stat(conn, path, &de.file)) {
+ /* mg_stat returns 0 if the file does not exist */
+ send_http_error(conn,
+ 404,
+ "Error: Cannot delete file\nFile %s not found",
+ path);
+ return;
+ }
+
+ if (de.file.membuf != NULL) {
+ /* the file is cached in memory */
+ send_http_error(
+ conn,
+ 405,
+ "Error: Delete not possible\nDeleting %s is not supported",
+ path);
+ return;
+ }
+
+ if (de.file.is_directory) {
+ if (remove_directory(conn, path)) {
+ /* Delete is successful: Return 204 without content. */
+ send_http_error(conn, 204, "%s", "");
+ } else {
+ /* Delete is not successful: Return 500 (Server error). */
+ send_http_error(conn, 500, "Error: Could not delete %s", path);
+ }
+ return;
+ }
+
+ /* This is an existing file (not a directory).
+ * Check if write permission is granted. */
+ if (access(path, W_OK) != 0) {
+ /* File is read only */
+ send_http_error(
+ conn,
+ 403,
+ "Error: Delete not possible\nDeleting %s is not allowed",
+ path);
+ return;
+ }
+
+ /* Try to delete it. */
+ if (mg_remove(conn, path) == 0) {
+ /* Delete was successful: Return 204 without content. */
+ send_http_error(conn, 204, "%s", "");
+ } else {
+ /* Delete not successful (file locked). */
+ send_http_error(conn,
+ 423,
+ "Error: Cannot delete file\nremove(%s): %s",
+ path,
+ strerror(ERRNO));
+ }
+}
+#endif /* !NO_FILES */
+
+
+static void
+send_ssi_file(struct mg_connection *, const char *, struct file *, int);
+
+
+static void
+do_ssi_include(struct mg_connection *conn,
+ const char *ssi,
+ char *tag,
+ int include_level)
+{
+ char file_name[MG_BUF_LEN], path[512], *p;
+ struct file file = STRUCT_FILE_INITIALIZER;
+ size_t len;
+ int truncated = 0;
+
+ if (conn == NULL) {
+ return;
+ }
+
+ /* sscanf() is safe here, since send_ssi_file() also uses buffer
+ * of size MG_BUF_LEN to get the tag. So strlen(tag) is
+ * always < MG_BUF_LEN. */
+ if (sscanf(tag, " virtual=\"%511[^\"]\"", file_name) == 1) {
+ /* File name is relative to the webserver root */
+ file_name[511] = 0;
+ (void)mg_snprintf(conn,
+ &truncated,
+ path,
+ sizeof(path),
+ "%s/%s",
+ conn->ctx->config[DOCUMENT_ROOT],
+ file_name);
+
+ } else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) {
+ /* File name is relative to the webserver working directory
+ * or it is absolute system path */
+ file_name[511] = 0;
+ (void)
+ mg_snprintf(conn, &truncated, path, sizeof(path), "%s", file_name);
+
+ } else if (sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1
+ || sscanf(tag, " \"%511[^\"]\"", file_name) == 1) {
+ /* File name is relative to the currect document */
+ file_name[511] = 0;
+ (void)mg_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi);
+
+ if (!truncated) {
+ if ((p = strrchr(path, '/')) != NULL) {
+ p[1] = '\0';
+ }
+ len = strlen(path);
+ (void)mg_snprintf(conn,
+ &truncated,
+ path + len,
+ sizeof(path) - len,
+ "%s",
+ file_name);
+ }
+
+ } else {
+ mg_cry(conn, "Bad SSI #include: [%s]", tag);
+ return;
+ }
+
+ if (truncated) {
+ mg_cry(conn, "SSI #include path length overflow: [%s]", tag);
+ return;
+ }
+
+ if (!mg_fopen(conn, path, "rb", &file)) {
+ mg_cry(conn,
+ "Cannot open SSI #include: [%s]: fopen(%s): %s",
+ tag,
+ path,
+ strerror(ERRNO));
+ } else {
+ fclose_on_exec(&file, conn);
+ if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
+ strlen(conn->ctx->config[SSI_EXTENSIONS]),
+ path) > 0) {
+ send_ssi_file(conn, path, &file, include_level + 1);
+ } else {
+ send_file_data(conn, &file, 0, INT64_MAX);
+ }
+ mg_fclose(&file);
+ }
+}
+
+
+#if !defined(NO_POPEN)
+static void
+do_ssi_exec(struct mg_connection *conn, char *tag)
+{
+ char cmd[1024] = "";
+ struct file file = STRUCT_FILE_INITIALIZER;
+
+ if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) {
+ mg_cry(conn, "Bad SSI #exec: [%s]", tag);
+ } else {
+ cmd[1023] = 0;
+ if ((file.fp = popen(cmd, "r")) == NULL) {
+ mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
+ } else {
+ send_file_data(conn, &file, 0, INT64_MAX);
+ pclose(file.fp);
+ }
+ }
+}
+#endif /* !NO_POPEN */
+
+
+static int
+mg_fgetc(struct file *filep, int offset)
+{
+ if (filep == NULL) {
+ return EOF;
+ }
+ if (filep->membuf != NULL && offset >= 0
+ && ((unsigned int)(offset)) < filep->size) {
+ return ((const unsigned char *)filep->membuf)[offset];
+ } else if (filep->fp != NULL) {
+ return fgetc(filep->fp);
+ } else {
+ return EOF;
+ }
+}
+
+
+static void
+send_ssi_file(struct mg_connection *conn,
+ const char *path,
+ struct file *filep,
+ int include_level)
+{
+ char buf[MG_BUF_LEN];
+ int ch, offset, len, in_ssi_tag;
+
+ if (include_level > 10) {
+ mg_cry(conn, "SSI #include level is too deep (%s)", path);
+ return;
+ }
+
+ in_ssi_tag = len = offset = 0;
+ while ((ch = mg_fgetc(filep, offset)) != EOF) {
+ if (in_ssi_tag && ch == '>') {
+ in_ssi_tag = 0;
+ buf[len++] = (char)ch;
+ buf[len] = '\0';
+ /* assert(len <= (int) sizeof(buf)); */
+ if (len > (int)sizeof(buf)) {
+ break;
+ }
+ if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
+ /* Not an SSI tag, pass it */
+ (void)mg_write(conn, buf, (size_t)len);
+ } else {
+ if (!memcmp(buf + 5, "include", 7)) {
+ do_ssi_include(conn, path, buf + 12, include_level);
+#if !defined(NO_POPEN)
+ } else if (!memcmp(buf + 5, "exec", 4)) {
+ do_ssi_exec(conn, buf + 9);
+#endif /* !NO_POPEN */
+ } else {
+ mg_cry(conn,
+ "%s: unknown SSI "
+ "command: \"%s\"",
+ path,
+ buf);
+ }
+ }
+ len = 0;
+ } else if (in_ssi_tag) {
+ if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
+ /* Not an SSI tag */
+ in_ssi_tag = 0;
+ } else if (len == (int)sizeof(buf) - 2) {
+ mg_cry(conn, "%s: SSI tag is too large", path);
+ len = 0;
+ }
+ buf[len++] = (char)(ch & 0xff);
+ } else if (ch == '<') {
+ in_ssi_tag = 1;
+ if (len > 0) {
+ mg_write(conn, buf, (size_t)len);
+ }
+ len = 0;
+ buf[len++] = (char)(ch & 0xff);
+ } else {
+ buf[len++] = (char)(ch & 0xff);
+ if (len == (int)sizeof(buf)) {
+ mg_write(conn, buf, (size_t)len);
+ len = 0;
+ }
+ }
+ }
+
+ /* Send the rest of buffered data */
+ if (len > 0) {
+ mg_write(conn, buf, (size_t)len);
+ }
+}
+
+
+static void
+handle_ssi_file_request(struct mg_connection *conn,
+ const char *path,
+ struct file *filep)
+{
+ char date[64];
+ time_t curtime = time(NULL);
+ const char *cors1, *cors2, *cors3;
+
+ if (conn == NULL || path == NULL || filep == NULL) {
+ return;
+ }
+
+ if (mg_get_header(conn, "Origin")) {
+ /* Cross-origin resource sharing (CORS). */
+ cors1 = "Access-Control-Allow-Origin: ";
+ cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
+ cors3 = "\r\n";
+ } else {
+ cors1 = cors2 = cors3 = "";
+ }
+
+ if (!mg_fopen(conn, path, "rb", filep)) {
+ /* File exists (precondition for calling this function),
+ * but can not be opened by the server. */
+ send_http_error(conn,
+ 500,
+ "Error: Cannot read file\nfopen(%s): %s",
+ path,
+ strerror(ERRNO));
+ } else {
+ conn->must_close = 1;
+ gmt_time_string(date, sizeof(date), &curtime);
+ fclose_on_exec(filep, conn);
+ mg_printf(conn, "HTTP/1.1 200 OK\r\n");
+ send_no_cache_header(conn);
+ mg_printf(conn,
+ "%s%s%s"
+ "Date: %s\r\n"
+ "Content-Type: text/html\r\n"
+ "Connection: %s\r\n\r\n",
+ cors1,
+ cors2,
+ cors3,
+ date,
+ suggest_connection_header(conn));
+ send_ssi_file(conn, path, filep, 0);
+ mg_fclose(filep);
+ }
+}
+
+
+#if !defined(NO_FILES)
+static void
+send_options(struct mg_connection *conn)
+{
+ char date[64];
+ time_t curtime = time(NULL);
+
+ if (!conn) {
+ return;
+ }
+
+ conn->status_code = 200;
+ conn->must_close = 1;
+ gmt_time_string(date, sizeof(date), &curtime);
+
+ mg_printf(conn,
+ "HTTP/1.1 200 OK\r\n"
+ "Date: %s\r\n"
+ /* TODO: "Cache-Control" (?) */
+ "Connection: %s\r\n"
+ "Allow: GET, POST, HEAD, CONNECT, PUT, DELETE, OPTIONS, "
+ "PROPFIND, MKCOL\r\n"
+ "DAV: 1\r\n\r\n",
+ date,
+ suggest_connection_header(conn));
+}
+
+
+/* Writes PROPFIND properties for a collection element */
+static void
+print_props(struct mg_connection *conn, const char *uri, struct file *filep)
+{
+ char mtime[64];
+
+ if (conn == NULL || uri == NULL || filep == NULL) {
+ return;
+ }
+
+ gmt_time_string(mtime, sizeof(mtime), &filep->last_modified);
+ conn->num_bytes_sent +=
+ mg_printf(conn,
+ "<d:response>"
+ "<d:href>%s</d:href>"
+ "<d:propstat>"
+ "<d:prop>"
+ "<d:resourcetype>%s</d:resourcetype>"
+ "<d:getcontentlength>%" INT64_FMT "</d:getcontentlength>"
+ "<d:getlastmodified>%s</d:getlastmodified>"
+ "</d:prop>"
+ "<d:status>HTTP/1.1 200 OK</d:status>"
+ "</d:propstat>"
+ "</d:response>\n",
+ uri,
+ filep->is_directory ? "<d:collection/>" : "",
+ filep->size,
+ mtime);
+}
+
+
+static void
+print_dav_dir_entry(struct de *de, void *data)
+{
+ char href[PATH_MAX];
+ char href_encoded[PATH_MAX];
+ int truncated;
+
+ struct mg_connection *conn = (struct mg_connection *)data;
+ if (!de || !conn) {
+ return;
+ }
+ mg_snprintf(conn,
+ &truncated,
+ href,
+ sizeof(href),
+ "%s%s",
+ conn->request_info.local_uri,
+ de->file_name);
+
+ if (!truncated) {
+ mg_url_encode(href, href_encoded, PATH_MAX - 1);
+ print_props(conn, href_encoded, &de->file);
+ }
+}
+
+
+static void
+handle_propfind(struct mg_connection *conn,
+ const char *path,
+ struct file *filep)
+{
+ const char *depth = mg_get_header(conn, "Depth");
+ char date[64];
+ time_t curtime = time(NULL);
+
+ gmt_time_string(date, sizeof(date), &curtime);
+
+ if (!conn || !path || !filep || !conn->ctx) {
+ return;
+ }
+
+ conn->must_close = 1;
+ conn->status_code = 207;
+ mg_printf(conn,
+ "HTTP/1.1 207 Multi-Status\r\n"
+ "Date: %s\r\n",
+ date);
+ send_static_cache_header(conn);
+ mg_printf(conn,
+ "Connection: %s\r\n"
+ "Content-Type: text/xml; charset=utf-8\r\n\r\n",
+ suggest_connection_header(conn));
+
+ conn->num_bytes_sent +=
+ mg_printf(conn,
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<d:multistatus xmlns:d='DAV:'>\n");
+
+ /* Print properties for the requested resource itself */
+ print_props(conn, conn->request_info.local_uri, filep);
+
+ /* If it is a directory, print directory entries too if Depth is not 0 */
+ if (filep && filep->is_directory
+ && !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes")
+ && (depth == NULL || strcmp(depth, "0") != 0)) {
+ scan_directory(conn, path, conn, &print_dav_dir_entry);
+ }
+
+ conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>");
+}
+#endif
+
+void
+mg_lock_connection(struct mg_connection *conn)
+{
+ if (conn) {
+ (void)pthread_mutex_lock(&conn->mutex);
+ }
+}
+
+void
+mg_unlock_connection(struct mg_connection *conn)
+{
+ if (conn) {
+ (void)pthread_mutex_unlock(&conn->mutex);
+ }
+}
+
+void
+mg_lock_context(struct mg_context *ctx)
+{
+ if (ctx) {
+ (void)pthread_mutex_lock(&ctx->nonce_mutex);
+ }
+}
+
+void
+mg_unlock_context(struct mg_context *ctx)
+{
+ if (ctx) {
+ (void)pthread_mutex_unlock(&ctx->nonce_mutex);
+ }
+}
+
+#if defined(USE_TIMERS)
+#include "timer.inl"
+#endif /* USE_TIMERS */
+
+#ifdef USE_LUA
+#include "mod_lua.inl"
+#endif /* USE_LUA */
+
+#ifdef USE_DUKTAPE
+#include "mod_duktape.inl"
+#endif /* USE_DUKTAPE */
+
+#if defined(USE_WEBSOCKET)
+
+/* START OF SHA-1 code
+ * Copyright(c) By Steve Reid <steve@edmweb.com> */
+#define SHA1HANDSOFF
+
+/* According to current tests (May 2015), the <solarisfixes.h> is not required.
+ *
+ * #if defined(__sun)
+ * #include "solarisfixes.h"
+ * #endif
+ */
+
+
+static int
+is_big_endian(void)
+{
+ static const int n = 1;
+ return ((char *)&n)[0] == 0;
+}
+
+
+union char64long16 {
+ unsigned char c[64];
+ uint32_t l[16];
+};
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+
+static uint32_t
+blk0(union char64long16 *block, int i)
+{
+ /* Forrest: SHA expect BIG_ENDIAN, swap if LITTLE_ENDIAN */
+ if (!is_big_endian()) {
+ block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00)
+ | (rol(block->l[i], 8) & 0x00FF00FF);
+ }
+ return block->l[i];
+}
+
+#define blk(i) \
+ (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \
+ ^ block->l[(i + 2) & 15] ^ block->l[i & 15], \
+ 1))
+#define R0(v, w, x, y, z, i) \
+ z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + rol(v, 5); \
+ w = rol(w, 30);
+#define R1(v, w, x, y, z, i) \
+ z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
+ w = rol(w, 30);
+#define R2(v, w, x, y, z, i) \
+ z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \
+ w = rol(w, 30);
+#define R3(v, w, x, y, z, i) \
+ z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
+ w = rol(w, 30);
+#define R4(v, w, x, y, z, i) \
+ z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
+ w = rol(w, 30);
+
+
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+
+static void
+SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
+{
+ uint32_t a, b, c, d, e;
+ union char64long16 block[1];
+
+ memcpy(block, buffer, 64);
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ R0(a, b, c, d, e, 0);
+ R0(e, a, b, c, d, 1);
+ R0(d, e, a, b, c, 2);
+ R0(c, d, e, a, b, 3);
+ R0(b, c, d, e, a, 4);
+ R0(a, b, c, d, e, 5);
+ R0(e, a, b, c, d, 6);
+ R0(d, e, a, b, c, 7);
+ R0(c, d, e, a, b, 8);
+ R0(b, c, d, e, a, 9);
+ R0(a, b, c, d, e, 10);
+ R0(e, a, b, c, d, 11);
+ R0(d, e, a, b, c, 12);
+ R0(c, d, e, a, b, 13);
+ R0(b, c, d, e, a, 14);
+ R0(a, b, c, d, e, 15);
+ R1(e, a, b, c, d, 16);
+ R1(d, e, a, b, c, 17);
+ R1(c, d, e, a, b, 18);
+ R1(b, c, d, e, a, 19);
+ R2(a, b, c, d, e, 20);
+ R2(e, a, b, c, d, 21);
+ R2(d, e, a, b, c, 22);
+ R2(c, d, e, a, b, 23);
+ R2(b, c, d, e, a, 24);
+ R2(a, b, c, d, e, 25);
+ R2(e, a, b, c, d, 26);
+ R2(d, e, a, b, c, 27);
+ R2(c, d, e, a, b, 28);
+ R2(b, c, d, e, a, 29);
+ R2(a, b, c, d, e, 30);
+ R2(e, a, b, c, d, 31);
+ R2(d, e, a, b, c, 32);
+ R2(c, d, e, a, b, 33);
+ R2(b, c, d, e, a, 34);
+ R2(a, b, c, d, e, 35);
+ R2(e, a, b, c, d, 36);
+ R2(d, e, a, b, c, 37);
+ R2(c, d, e, a, b, 38);
+ R2(b, c, d, e, a, 39);
+ R3(a, b, c, d, e, 40);
+ R3(e, a, b, c, d, 41);
+ R3(d, e, a, b, c, 42);
+ R3(c, d, e, a, b, 43);
+ R3(b, c, d, e, a, 44);
+ R3(a, b, c, d, e, 45);
+ R3(e, a, b, c, d, 46);
+ R3(d, e, a, b, c, 47);
+ R3(c, d, e, a, b, 48);
+ R3(b, c, d, e, a, 49);
+ R3(a, b, c, d, e, 50);
+ R3(e, a, b, c, d, 51);
+ R3(d, e, a, b, c, 52);
+ R3(c, d, e, a, b, 53);
+ R3(b, c, d, e, a, 54);
+ R3(a, b, c, d, e, 55);
+ R3(e, a, b, c, d, 56);
+ R3(d, e, a, b, c, 57);
+ R3(c, d, e, a, b, 58);
+ R3(b, c, d, e, a, 59);
+ R4(a, b, c, d, e, 60);
+ R4(e, a, b, c, d, 61);
+ R4(d, e, a, b, c, 62);
+ R4(c, d, e, a, b, 63);
+ R4(b, c, d, e, a, 64);
+ R4(a, b, c, d, e, 65);
+ R4(e, a, b, c, d, 66);
+ R4(d, e, a, b, c, 67);
+ R4(c, d, e, a, b, 68);
+ R4(b, c, d, e, a, 69);
+ R4(a, b, c, d, e, 70);
+ R4(e, a, b, c, d, 71);
+ R4(d, e, a, b, c, 72);
+ R4(c, d, e, a, b, 73);
+ R4(b, c, d, e, a, 74);
+ R4(a, b, c, d, e, 75);
+ R4(e, a, b, c, d, 76);
+ R4(d, e, a, b, c, 77);
+ R4(c, d, e, a, b, 78);
+ R4(b, c, d, e, a, 79);
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ a = b = c = d = e = 0;
+ memset(block, '\0', sizeof(block));
+}
+
+
+static void
+SHA1Init(SHA1_CTX *context)
+{
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+
+static void
+SHA1Update(SHA1_CTX *context, const unsigned char *data, uint32_t len)
+{
+ uint32_t i, j;
+
+ j = context->count[0];
+ if ((context->count[0] += len << 3) < j) {
+ context->count[1]++;
+ }
+ context->count[1] += (len >> 29);
+ j = (j >> 3) & 63;
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64 - j));
+ SHA1Transform(context->state, context->buffer);
+ for (; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ } else
+ i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+static void
+SHA1Final(unsigned char digest[20], SHA1_CTX *context)
+{
+ unsigned i;
+ unsigned char finalcount[8], c;
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3 - (i & 3)) * 8)) & 255);
+ }
+ c = 0200;
+ SHA1Update(context, &c, 1);
+ while ((context->count[0] & 504) != 448) {
+ c = 0000;
+ SHA1Update(context, &c, 1);
+ }
+ SHA1Update(context, finalcount, 8);
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)((context->state[i >> 2]
+ >> ((3 - (i & 3)) * 8)) & 255);
+ }
+ memset(context, '\0', sizeof(*context));
+ memset(&finalcount, '\0', sizeof(finalcount));
+}
+/* END OF SHA1 CODE */
+
+
+static int
+send_websocket_handshake(struct mg_connection *conn, const char *websock_key)
+{
+ static const char *magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+ const char *protocol = NULL;
+ char buf[100], sha[20], b64_sha[sizeof(sha) * 2];
+ SHA1_CTX sha_ctx;
+ int truncated;
+
+ /* Calculate Sec-WebSocket-Accept reply from Sec-WebSocket-Key. */
+ mg_snprintf(conn, &truncated, buf, sizeof(buf), "%s%s", websock_key, magic);
+ if (truncated) {
+ conn->must_close = 1;
+ return 0;
+ }
+
+ SHA1Init(&sha_ctx);
+ SHA1Update(&sha_ctx, (unsigned char *)buf, (uint32_t)strlen(buf));
+ SHA1Final((unsigned char *)sha, &sha_ctx);
+ base64_encode((unsigned char *)sha, sizeof(sha), b64_sha);
+ mg_printf(conn,
+ "HTTP/1.1 101 Switching Protocols\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Accept: %s\r\n",
+ b64_sha);
+ protocol = mg_get_header(conn, "Sec-WebSocket-Protocol");
+ if (protocol) {
+ /* The protocol is a comma seperated list of names. */
+ /* The server must only return one value from this list. */
+ /* First check if it is a list or just a single value. */
+ const char *sep = strchr(protocol, ',');
+ if (sep == NULL) {
+ /* Just a single protocol -> accept it. */
+ mg_printf(conn, "Sec-WebSocket-Protocol: %s\r\n\r\n", protocol);
+ } else {
+ /* Multiple protocols -> accept the first one. */
+ /* This is just a quick fix if the client offers multiple
+ * protocols. In order to get the behavior intended by
+ * RFC 6455 (https://tools.ietf.org/rfc/rfc6455.txt), it is
+ * required to have a list of websocket subprotocols accepted
+ * by the server. Then the server must either select a subprotocol
+ * supported by client and server, or the server has to abort the
+ * handshake by not returning a Sec-Websocket-Protocol header if
+ * no subprotocol is acceptable.
+ */
+ mg_printf(conn,
+ "Sec-WebSocket-Protocol: %.*s\r\n\r\n",
+ (int)(sep - protocol),
+ protocol);
+ }
+ /* TODO: Real subprotocol negotiation instead of just taking the first
+ * websocket subprotocol suggested by the client. */
+ } else {
+ mg_printf(conn, "%s", "\r\n");
+ }
+
+ return 1;
+}
+
+
+static void
+read_websocket(struct mg_connection *conn,
+ mg_websocket_data_handler ws_data_handler,
+ void *callback_data)
+{
+ /* Pointer to the beginning of the portion of the incoming websocket
+ * message queue.
+ * The original websocket upgrade request is never removed, so the queue
+ * begins after it. */
+ unsigned char *buf = (unsigned char *)conn->buf + conn->request_len;
+ int n, error, exit_by_callback;
+
+ /* body_len is the length of the entire queue in bytes
+ * len is the length of the current message
+ * data_len is the length of the current message's data payload
+ * header_len is the length of the current message's header */
+ size_t i, len, mask_len = 0, data_len = 0, header_len, body_len;
+
+ /* "The masking key is a 32-bit value chosen at random by the client."
+ * http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-17#section-5
+ */
+ unsigned char mask[4];
+
+ /* data points to the place where the message is stored when passed to
+ * the
+ * websocket_data callback. This is either mem on the stack, or a
+ * dynamically allocated buffer if it is too large. */
+ char mem[4096];
+ char *data = mem;
+ unsigned char mop; /* mask flag and opcode */
+ double timeout = -1.0;
+
+ if (conn->ctx->config[WEBSOCKET_TIMEOUT]) {
+ timeout = atoi(conn->ctx->config[WEBSOCKET_TIMEOUT]) / 1000.0;
+ }
+ if ((timeout <= 0.0) && (conn->ctx->config[REQUEST_TIMEOUT])) {
+ timeout = atoi(conn->ctx->config[REQUEST_TIMEOUT]) / 1000.0;
+ }
+
+ mg_set_thread_name("wsock");
+
+ /* Loop continuously, reading messages from the socket, invoking the
+ * callback, and waiting repeatedly until an error occurs. */
+ while (!conn->ctx->stop_flag) {
+ header_len = 0;
+ assert(conn->data_len >= conn->request_len);
+ if ((body_len = (size_t)(conn->data_len - conn->request_len)) >= 2) {
+ len = buf[1] & 127;
+ mask_len = buf[1] & 128 ? 4 : 0;
+ if (len < 126 && body_len >= mask_len) {
+ data_len = len;
+ header_len = 2 + mask_len;
+ } else if (len == 126 && body_len >= 4 + mask_len) {
+ header_len = 4 + mask_len;
+ data_len = ((((size_t)buf[2]) << 8) + buf[3]);
+ } else if (body_len >= 10 + mask_len) {
+ header_len = 10 + mask_len;
+ data_len = (((uint64_t)ntohl(*(uint32_t *)(void *)&buf[2]))
+ << 32) + ntohl(*(uint32_t *)(void *)&buf[6]);
+ }
+ }
+
+ if (header_len > 0 && body_len >= header_len) {
+ /* Allocate space to hold websocket payload */
+ data = mem;
+ if (data_len > sizeof(mem)) {
+ data = (char *)mg_malloc(data_len);
+ if (data == NULL) {
+ /* Allocation failed, exit the loop and then close the
+ * connection */
+ mg_cry(conn, "websocket out of memory; closing connection");
+ break;
+ }
+ }
+
+ /* Copy the mask before we shift the queue and destroy it */
+ if (mask_len > 0) {
+ memcpy(mask, buf + header_len - mask_len, sizeof(mask));
+ } else {
+ memset(mask, 0, sizeof(mask));
+ }
+
+ /* Read frame payload from the first message in the queue into
+ * data and advance the queue by moving the memory in place. */
+ assert(body_len >= header_len);
+ if (data_len + header_len > body_len) {
+ mop = buf[0]; /* current mask and opcode */
+ /* Overflow case */
+ len = body_len - header_len;
+ memcpy(data, buf + header_len, len);
+ error = 0;
+ while (len < data_len) {
+ n = pull(
+ NULL, conn, data + len, (int)(data_len - len), timeout);
+ if (n <= 0) {
+ error = 1;
+ break;
+ }
+ len += (size_t)n;
+ }
+ if (error) {
+ mg_cry(conn, "Websocket pull failed; closing connection");
+ break;
+ }
+ conn->data_len = conn->request_len;
+ } else {
+ mop = buf[0]; /* current mask and opcode, overwritten by
+ * memmove() */
+ /* Length of the message being read at the front of the
+ * queue */
+ len = data_len + header_len;
+
+ /* Copy the data payload into the data pointer for the
+ * callback */
+ memcpy(data, buf + header_len, data_len);
+
+ /* Move the queue forward len bytes */
+ memmove(buf, buf + len, body_len - len);
+
+ /* Mark the queue as advanced */
+ conn->data_len -= (int)len;
+ }
+
+ /* Apply mask if necessary */
+ if (mask_len > 0) {
+ for (i = 0; i < data_len; ++i) {
+ data[i] ^= mask[i & 3];
+ }
+ }
+
+ /* Exit the loop if callback signals to exit (server side),
+ * or "connection close" opcode received (client side). */
+ exit_by_callback = 0;
+ if ((ws_data_handler != NULL)
+ && !ws_data_handler(conn, mop, data, data_len, callback_data)) {
+ exit_by_callback = 1;
+ }
+
+ if (data != mem) {
+ mg_free(data);
+ }
+
+ if (exit_by_callback
+ || ((mop & 0xf) == WEBSOCKET_OPCODE_CONNECTION_CLOSE)) {
+ /* Opcode == 8, connection close */
+ break;
+ }
+
+ /* Not breaking the loop, process next websocket frame. */
+ } else {
+ /* Read from the socket into the next available location in the
+ * message queue. */
+ if ((n = pull(NULL,
+ conn,
+ conn->buf + conn->data_len,
+ conn->buf_size - conn->data_len,
+ timeout)) <= 0) {
+ /* Error, no bytes read */
+ break;
+ }
+ conn->data_len += n;
+ }
+ }
+
+ mg_set_thread_name("worker");
+}
+
+
+static int
+mg_websocket_write_exec(struct mg_connection *conn,
+ int opcode,
+ const char *data,
+ size_t dataLen,
+ uint32_t masking_key)
+{
+ unsigned char header[14];
+ size_t headerLen = 1;
+
+ int retval = -1;
+
+ header[0] = 0x80 + (opcode & 0xF);
+
+ /* Frame format: http://tools.ietf.org/html/rfc6455#section-5.2 */
+ if (dataLen < 126) {
+ /* inline 7-bit length field */
+ header[1] = (unsigned char)dataLen;
+ headerLen = 2;
+ } else if (dataLen <= 0xFFFF) {
+ /* 16-bit length field */
+ header[1] = 126;
+ *(uint16_t *)(void *)(header + 2) = htons((uint16_t)dataLen);
+ headerLen = 4;
+ } else {
+ /* 64-bit length field */
+ header[1] = 127;
+ *(uint32_t *)(void *)(header + 2) = htonl((uint64_t)dataLen >> 32);
+ *(uint32_t *)(void *)(header + 6) = htonl(dataLen & 0xFFFFFFFF);
+ headerLen = 10;
+ }
+
+ if (masking_key) {
+ /* add mask */
+ header[1] |= 0x80;
+ *(uint32_t *)(void *)(header + headerLen) = masking_key;
+ headerLen += 4;
+ }
+
+
+ /* Note that POSIX/Winsock's send() is threadsafe
+ * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
+ * but mongoose's mg_printf/mg_write is not (because of the loop in
+ * push(), although that is only a problem if the packet is large or
+ * outgoing buffer is full). */
+ (void)mg_lock_connection(conn);
+ retval = mg_write(conn, header, headerLen);
+ if (dataLen > 0) {
+ retval = mg_write(conn, data, dataLen);
+ }
+ mg_unlock_connection(conn);
+
+ return retval;
+}
+
+int
+mg_websocket_write(struct mg_connection *conn,
+ int opcode,
+ const char *data,
+ size_t dataLen)
+{
+ return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
+}
+
+
+static void
+mask_data(const char *in, size_t in_len, uint32_t masking_key, char *out)
+{
+ size_t i = 0;
+
+ i = 0;
+ if ((in_len > 3) && ((ptrdiff_t)in % 4) == 0) {
+ /* Convert in 32 bit words, if data is 4 byte aligned */
+ while (i < (in_len - 3)) {
+ *(uint32_t *)(void *)(out + i) =
+ *(uint32_t *)(void *)(in + i) ^ masking_key;
+ i += 4;
+ }
+ }
+ if (i != in_len) {
+ /* convert 1-3 remaining bytes if ((dataLen % 4) != 0)*/
+ while (i < in_len) {
+ *(uint8_t *)(void *)(out + i) =
+ *(uint8_t *)(void *)(in + i)
+ ^ *(((uint8_t *)&masking_key) + (i % 4));
+ i++;
+ }
+ }
+}
+
+
+int
+mg_websocket_client_write(struct mg_connection *conn,
+ int opcode,
+ const char *data,
+ size_t dataLen)
+{
+ int retval = -1;
+ char *masked_data = (char *)mg_malloc(((dataLen + 7) / 4) * 4);
+ uint32_t masking_key = (uint32_t)get_random();
+
+ if (masked_data == NULL) {
+ /* Return -1 in an error case */
+ mg_cry(conn,
+ "Cannot allocate buffer for masked websocket response: "
+ "Out of memory");
+ return -1;
+ }
+
+ mask_data(data, dataLen, masking_key, masked_data);
+
+ retval = mg_websocket_write_exec(
+ conn, opcode, masked_data, dataLen, masking_key);
+ mg_free(masked_data);
+
+ return retval;
+}
+
+
+static void
+handle_websocket_request(struct mg_connection *conn,
+ const char *path,
+ int is_callback_resource,
+ mg_websocket_connect_handler ws_connect_handler,
+ mg_websocket_ready_handler ws_ready_handler,
+ mg_websocket_data_handler ws_data_handler,
+ mg_websocket_close_handler ws_close_handler,
+ void *cbData)
+{
+ const char *websock_key = mg_get_header(conn, "Sec-WebSocket-Key");
+ const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
+ int lua_websock = 0;
+
+#if !defined(USE_LUA)
+ (void)path;
+#endif
+
+ /* Step 1: Check websocket protocol version. */
+ /* Step 1.1: Check Sec-WebSocket-Key. */
+ if (!websock_key) {
+ /* The RFC standard version (https://tools.ietf.org/html/rfc6455)
+ * requires a Sec-WebSocket-Key header.
+ */
+ /* It could be the hixie draft version
+ * (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76).
+ */
+ const char *key1 = mg_get_header(conn, "Sec-WebSocket-Key1");
+ const char *key2 = mg_get_header(conn, "Sec-WebSocket-Key2");
+ char key3[8];
+
+ if ((key1 != NULL) && (key2 != NULL)) {
+ /* This version uses 8 byte body data in a GET request */
+ conn->content_len = 8;
+ if (8 == mg_read(conn, key3, 8)) {
+ /* This is the hixie version */
+ send_http_error(conn,
+ 426,
+ "%s",
+ "Protocol upgrade to RFC 6455 required");
+ return;
+ }
+ }
+ /* This is an unknown version */
+ send_http_error(conn, 400, "%s", "Malformed websocket request");
+ return;
+ }
+
+ /* Step 1.2: Check websocket protocol version. */
+ /* The RFC version (https://tools.ietf.org/html/rfc6455) is 13. */
+ if (version == NULL || strcmp(version, "13") != 0) {
+ /* Reject wrong versions */
+ send_http_error(conn, 426, "%s", "Protocol upgrade required");
+ return;
+ }
+
+ /* Step 1.3: Could check for "Host", but we do not really nead this
+ * value for anything, so just ignore it. */
+
+ /* Step 2: If a callback is responsible, call it. */
+ if (is_callback_resource) {
+ if (ws_connect_handler != NULL
+ && ws_connect_handler(conn, cbData) != 0) {
+ /* C callback has returned non-zero, do not proceed with
+ * handshake.
+ */
+ /* Note that C callbacks are no longer called when Lua is
+ * responsible, so C can no longer filter callbacks for Lua. */
+ return;
+ }
+ }
+#if defined(USE_LUA)
+ /* Step 3: No callback. Check if Lua is responsible. */
+ else {
+ /* Step 3.1: Check if Lua is responsible. */
+ if (conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]) {
+ lua_websock =
+ match_prefix(conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS],
+ strlen(
+ conn->ctx->config[LUA_WEBSOCKET_EXTENSIONS]),
+ path);
+ }
+
+ if (lua_websock) {
+ /* Step 3.2: Lua is responsible: call it. */
+ conn->lua_websocket_state = lua_websocket_new(path, conn);
+ if (!conn->lua_websocket_state) {
+ /* Lua rejected the new client */
+ return;
+ }
+ }
+ }
+#endif
+
+ /* Step 4: Check if there is a responsible websocket handler. */
+ if (!is_callback_resource && !lua_websock) {
+ /* There is no callback, an Lua is not responsible either. */
+ /* Reply with a 404 Not Found or with nothing at all?
+ * TODO (mid): check the websocket standards, how to reply to
+ * requests to invalid websocket addresses. */
+ send_http_error(conn, 404, "%s", "Not found");
+ return;
+ }
+
+ /* Step 5: The websocket connection has been accepted */
+ if (!send_websocket_handshake(conn, websock_key)) {
+ send_http_error(conn, 500, "%s", "Websocket handshake failed");
+ return;
+ }
+
+ /* Step 6: Call the ready handler */
+ if (is_callback_resource) {
+ if (ws_ready_handler != NULL) {
+ ws_ready_handler(conn, cbData);
+ }
+#if defined(USE_LUA)
+ } else if (lua_websock) {
+ if (!lua_websocket_ready(conn, conn->lua_websocket_state)) {
+ /* the ready handler returned false */
+ return;
+ }
+#endif
+ }
+
+ /* Step 7: Enter the read loop */
+ if (is_callback_resource) {
+ read_websocket(conn, ws_data_handler, cbData);
+#if defined(USE_LUA)
+ } else if (lua_websock) {
+ read_websocket(conn, lua_websocket_data, conn->lua_websocket_state);
+#endif
+ }
+
+ /* Step 8: Call the close handler */
+ if (ws_close_handler) {
+ ws_close_handler(conn, cbData);
+ }
+}
+
+
+static int
+is_websocket_protocol(const struct mg_connection *conn)
+{
+ const char *upgrade, *connection;
+
+ /* A websocket protocoll has the following HTTP headers:
+ *
+ * Connection: Upgrade
+ * Upgrade: Websocket
+ */
+
+ upgrade = mg_get_header(conn, "Upgrade");
+ if (upgrade == NULL) {
+ return 0; /* fail early, don't waste time checking other header
+ * fields
+ */
+ }
+ if (!mg_strcasestr(upgrade, "websocket")) {
+ return 0;
+ }
+
+ connection = mg_get_header(conn, "Connection");
+ if (connection == NULL) {
+ return 0;
+ }
+ if (!mg_strcasestr(connection, "upgrade")) {
+ return 0;
+ }
+
+ /* The headers "Host", "Sec-WebSocket-Key", "Sec-WebSocket-Protocol" and
+ * "Sec-WebSocket-Version" are also required.
+ * Don't check them here, since even an unsupported websocket protocol
+ * request still IS a websocket request (in contrast to a standard HTTP
+ * request). It will fail later in handle_websocket_request.
+ */
+
+ return 1;
+}
+#endif /* !USE_WEBSOCKET */
+
+
+static int
+isbyte(int n)
+{
+ return n >= 0 && n <= 255;
+}
+
+
+static int
+parse_net(const char *spec, uint32_t *net, uint32_t *mask)
+{
+ int n, a, b, c, d, slash = 32, len = 0;
+
+ if ((sscanf(spec, "%d.%d.%d.%d/%d%n", &a, &b, &c, &d, &slash, &n) == 5
+ || sscanf(spec, "%d.%d.%d.%d%n", &a, &b, &c, &d, &n) == 4) && isbyte(a)
+ && isbyte(b) && isbyte(c) && isbyte(d) && slash >= 0
+ && slash < 33) {
+ len = n;
+ *net = ((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8)
+ | (uint32_t)d;
+ *mask = slash ? 0xffffffffU << (32 - slash) : 0;
+ }
+
+ return len;
+}
+
+
+static int
+set_throttle(const char *spec, uint32_t remote_ip, const char *uri)
+{
+ int throttle = 0;
+ struct vec vec, val;
+ uint32_t net, mask;
+ char mult;
+ double v;
+
+ while ((spec = next_option(spec, &vec, &val)) != NULL) {
+ mult = ',';
+ if (sscanf(val.ptr, "%lf%c", &v, &mult) < 1 || v < 0
+ || (lowercase(&mult) != 'k' && lowercase(&mult) != 'm'
+ && mult != ',')) {
+ continue;
+ }
+ v *= lowercase(&mult) == 'k' ? 1024 : lowercase(&mult) == 'm' ? 1048576
+ : 1;
+ if (vec.len == 1 && vec.ptr[0] == '*') {
+ throttle = (int)v;
+ } else if (parse_net(vec.ptr, &net, &mask) > 0) {
+ if ((remote_ip & mask) == net) {
+ throttle = (int)v;
+ }
+ } else if (match_prefix(vec.ptr, vec.len, uri) > 0) {
+ throttle = (int)v;
+ }
+ }
+
+ return throttle;
+}
+
+
+static uint32_t
+get_remote_ip(const struct mg_connection *conn)
+{
+ if (!conn) {
+ return 0;
+ }
+ return ntohl(*(const uint32_t *)&conn->client.rsa.sin.sin_addr);
+}
+
+
+/* The mg_upload function is superseeded by mg_handle_form_request. */
+#include "handle_form.inl"
+
+
+#if defined(MG_LEGACY_INTERFACE)
+/* Implement the deprecated mg_upload function by calling the new
+ * mg_handle_form_request function. While mg_upload could only handle
+ * HTML forms sent as POST request in multipart/form-data format
+ * containing only file input elements, mg_handle_form_request can
+ * handle all form input elements and all standard request methods. */
+struct mg_upload_user_data {
+ struct mg_connection *conn;
+ const char *destination_dir;
+ int num_uploaded_files;
+};
+
+
+/* Helper function for deprecated mg_upload. */
+static int
+mg_upload_field_found(const char *key,
+ const char *filename,
+ char *path,
+ size_t pathlen,
+ void *user_data)
+{
+ int truncated = 0;
+ struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
+ (void)key;
+
+ if (!filename) {
+ mg_cry(fud->conn, "%s: No filename set", __func__);
+ return FORM_FIELD_STORAGE_ABORT;
+ }
+ mg_snprintf(fud->conn,
+ &truncated,
+ path,
+ pathlen - 1,
+ "%s/%s",
+ fud->destination_dir,
+ filename);
+ if (!truncated) {
+ mg_cry(fud->conn, "%s: File path too long", __func__);
+ return FORM_FIELD_STORAGE_ABORT;
+ }
+ return FORM_FIELD_STORAGE_STORE;
+}
+
+
+/* Helper function for deprecated mg_upload. */
+static int
+mg_upload_field_get(const char *key,
+ const char *value,
+ size_t value_size,
+ void *user_data)
+{
+ /* Function should never be called */
+ (void)key;
+ (void)value;
+ (void)value_size;
+ (void)user_data;
+
+ return 0;
+}
+
+
+/* Helper function for deprecated mg_upload. */
+static int
+mg_upload_field_stored(const char *path, long long file_size, void *user_data)
+{
+ struct mg_upload_user_data *fud = (struct mg_upload_user_data *)user_data;
+ (void)file_size;
+
+ fud->num_uploaded_files++;
+ fud->conn->ctx->callbacks.upload(fud->conn, path);
+
+ return 0;
+}
+
+
+/* Deprecated function mg_upload - use mg_handle_form_request instead. */
+int
+mg_upload(struct mg_connection *conn, const char *destination_dir)
+{
+ struct mg_upload_user_data fud = {conn, destination_dir, 0};
+ struct mg_form_data_handler fdh = {mg_upload_field_found,
+ mg_upload_field_get,
+ mg_upload_field_stored,
+ 0};
+ int ret;
+
+ fdh.user_data = (void *)&fud;
+ ret = mg_handle_form_request(conn, &fdh);
+
+ if (ret < 0) {
+ mg_cry(conn, "%s: Error while parsing the request", __func__);
+ }
+
+ return fud.num_uploaded_files;
+}
+#endif
+
+
+static int
+get_first_ssl_listener_index(const struct mg_context *ctx)
+{
+ unsigned int i;
+ int idx = -1;
+ if (ctx) {
+ for (i = 0; idx == -1 && i < ctx->num_listening_sockets; i++) {
+ idx = ctx->listening_sockets[i].is_ssl ? ((int)(i)) : -1;
+ }
+ }
+ return idx;
+}
+
+
+static void
+redirect_to_https_port(struct mg_connection *conn, int ssl_index)
+{
+ char host[1025];
+ const char *host_header;
+ size_t hostlen;
+
+ host_header = mg_get_header(conn, "Host");
+ hostlen = sizeof(host);
+ if (host_header != NULL) {
+ char *pos;
+
+ mg_strlcpy(host, host_header, hostlen);
+ host[hostlen - 1] = '\0';
+ pos = strchr(host, ':');
+ if (pos != NULL) {
+ *pos = '\0';
+ }
+ } else {
+ /* Cannot get host from the Host: header.
+ * Fallback to our IP address. */
+ if (conn) {
+ sockaddr_to_string(host, hostlen, &conn->client.lsa);
+ }
+ }
+
+ /* Send host, port, uri and (if it exists) ?query_string */
+ if (conn) {
+ mg_printf(conn,
+ "HTTP/1.1 302 Found\r\nLocation: https://%s:%d%s%s%s\r\n\r\n",
+ host,
+ (int)ntohs(
+ conn->ctx->listening_sockets[ssl_index].lsa.sin.sin_port),
+ conn->request_info.local_uri,
+ (conn->request_info.query_string == NULL) ? "" : "?",
+ (conn->request_info.query_string == NULL)
+ ? ""
+ : conn->request_info.query_string);
+ }
+}
+
+
+static void
+mg_set_handler_type(struct mg_context *ctx,
+ const char *uri,
+ int handler_type,
+ int is_delete_request,
+ mg_request_handler handler,
+ mg_websocket_connect_handler connect_handler,
+ mg_websocket_ready_handler ready_handler,
+ mg_websocket_data_handler data_handler,
+ mg_websocket_close_handler close_handler,
+ mg_authorization_handler auth_handler,
+ void *cbdata)
+{
+ struct mg_handler_info *tmp_rh, **lastref;
+ size_t urilen = strlen(uri);
+
+ if (handler_type == WEBSOCKET_HANDLER) {
+ /* assert(handler == NULL); */
+ /* assert(is_delete_request || connect_handler!=NULL ||
+ * ready_handler!=NULL || data_handler!=NULL ||
+ * close_handler!=NULL);
+ */
+ /* assert(auth_handler == NULL); */
+ if (handler != NULL) {
+ return;
+ }
+ if (!is_delete_request && connect_handler == NULL
+ && ready_handler == NULL
+ && data_handler == NULL
+ && close_handler == NULL) {
+ return;
+ }
+ if (auth_handler != NULL) {
+ return;
+ }
+ } else if (handler_type == REQUEST_HANDLER) {
+ /* assert(connect_handler==NULL && ready_handler==NULL &&
+ * data_handler==NULL && close_handler==NULL); */
+ /* assert(is_delete_request || (handler!=NULL));
+ */
+ /* assert(auth_handler == NULL); */
+ if (connect_handler != NULL || ready_handler != NULL
+ || data_handler != NULL
+ || close_handler != NULL) {
+ return;
+ }
+ if (!is_delete_request && (handler == NULL)) {
+ return;
+ }
+ if (auth_handler != NULL) {
+ return;
+ }
+ } else { /* AUTH_HANDLER */
+ /* assert(handler == NULL); */
+ /* assert(connect_handler==NULL && ready_handler==NULL &&
+ * data_handler==NULL && close_handler==NULL); */
+ /* assert(auth_handler != NULL); */
+ if (handler != NULL) {
+ return;
+ }
+ if (connect_handler != NULL || ready_handler != NULL
+ || data_handler != NULL
+ || close_handler != NULL) {
+ return;
+ }
+ if (!is_delete_request && (auth_handler == NULL)) {
+ return;
+ }
+ }
+
+ if (!ctx) {
+ return;
+ }
+
+ mg_lock_context(ctx);
+
+ /* first try to find an existing handler */
+ lastref = &(ctx->handlers);
+ for (tmp_rh = ctx->handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
+ if (tmp_rh->handler_type == handler_type) {
+ if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri, uri)) {
+ if (!is_delete_request) {
+ /* update existing handler */
+ if (handler_type == REQUEST_HANDLER) {
+ tmp_rh->handler = handler;
+ } else if (handler_type == WEBSOCKET_HANDLER) {
+ tmp_rh->connect_handler = connect_handler;
+ tmp_rh->ready_handler = ready_handler;
+ tmp_rh->data_handler = data_handler;
+ tmp_rh->close_handler = close_handler;
+ } else { /* AUTH_HANDLER */
+ tmp_rh->auth_handler = auth_handler;
+ }
+ tmp_rh->cbdata = cbdata;
+ } else {
+ /* remove existing handler */
+ *lastref = tmp_rh->next;
+ mg_free(tmp_rh->uri);
+ mg_free(tmp_rh);
+ }
+ mg_unlock_context(ctx);
+ return;
+ }
+ }
+ lastref = &(tmp_rh->next);
+ }
+
+ if (is_delete_request) {
+ /* no handler to set, this was a remove request to a non-existing
+ * handler */
+ mg_unlock_context(ctx);
+ return;
+ }
+
+ tmp_rh =
+ (struct mg_handler_info *)mg_calloc(sizeof(struct mg_handler_info), 1);
+ if (tmp_rh == NULL) {
+ mg_unlock_context(ctx);
+ mg_cry(fc(ctx), "%s", "Cannot create new request handler struct, OOM");
+ return;
+ }
+ tmp_rh->uri = mg_strdup(uri);
+ if (!tmp_rh->uri) {
+ mg_unlock_context(ctx);
+ mg_free(tmp_rh);
+ mg_cry(fc(ctx), "%s", "Cannot create new request handler struct, OOM");
+ return;
+ }
+ tmp_rh->uri_len = urilen;
+ if (handler_type == REQUEST_HANDLER) {
+ tmp_rh->handler = handler;
+ } else if (handler_type == WEBSOCKET_HANDLER) {
+ tmp_rh->connect_handler = connect_handler;
+ tmp_rh->ready_handler = ready_handler;
+ tmp_rh->data_handler = data_handler;
+ tmp_rh->close_handler = close_handler;
+ } else { /* AUTH_HANDLER */
+ tmp_rh->auth_handler = auth_handler;
+ }
+ tmp_rh->cbdata = cbdata;
+ tmp_rh->handler_type = handler_type;
+ tmp_rh->next = NULL;
+
+ *lastref = tmp_rh;
+ mg_unlock_context(ctx);
+}
+
+
+void
+mg_set_request_handler(struct mg_context *ctx,
+ const char *uri,
+ mg_request_handler handler,
+ void *cbdata)
+{
+ mg_set_handler_type(ctx,
+ uri,
+ REQUEST_HANDLER,
+ handler == NULL,
+ handler,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ cbdata);
+}
+
+
+void
+mg_set_websocket_handler(struct mg_context *ctx,
+ const char *uri,
+ mg_websocket_connect_handler connect_handler,
+ mg_websocket_ready_handler ready_handler,
+ mg_websocket_data_handler data_handler,
+ mg_websocket_close_handler close_handler,
+ void *cbdata)
+{
+ int is_delete_request = (connect_handler == NULL) && (ready_handler == NULL)
+ && (data_handler == NULL)
+ && (close_handler == NULL);
+ mg_set_handler_type(ctx,
+ uri,
+ WEBSOCKET_HANDLER,
+ is_delete_request,
+ NULL,
+ connect_handler,
+ ready_handler,
+ data_handler,
+ close_handler,
+ NULL,
+ cbdata);
+}
+
+
+void
+mg_set_auth_handler(struct mg_context *ctx,
+ const char *uri,
+ mg_request_handler handler,
+ void *cbdata)
+{
+ mg_set_handler_type(ctx,
+ uri,
+ AUTH_HANDLER,
+ handler == NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ handler,
+ cbdata);
+}
+
+
+static int
+get_request_handler(struct mg_connection *conn,
+ int handler_type,
+ mg_request_handler *handler,
+ mg_websocket_connect_handler *connect_handler,
+ mg_websocket_ready_handler *ready_handler,
+ mg_websocket_data_handler *data_handler,
+ mg_websocket_close_handler *close_handler,
+ mg_authorization_handler *auth_handler,
+ void **cbdata)
+{
+ const struct mg_request_info *request_info = mg_get_request_info(conn);
+ if (request_info) {
+ const char *uri = request_info->local_uri;
+ size_t urilen = strlen(uri);
+ struct mg_handler_info *tmp_rh;
+
+ if (!conn || !conn->ctx) {
+ return 0;
+ }
+
+ mg_lock_context(conn->ctx);
+
+ /* first try for an exact match */
+ for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
+ tmp_rh = tmp_rh->next) {
+ if (tmp_rh->handler_type == handler_type) {
+ if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri, uri)) {
+ if (handler_type == WEBSOCKET_HANDLER) {
+ *connect_handler = tmp_rh->connect_handler;
+ *ready_handler = tmp_rh->ready_handler;
+ *data_handler = tmp_rh->data_handler;
+ *close_handler = tmp_rh->close_handler;
+ } else if (handler_type == REQUEST_HANDLER) {
+ *handler = tmp_rh->handler;
+ } else { /* AUTH_HANDLER */
+ *auth_handler = tmp_rh->auth_handler;
+ }
+ *cbdata = tmp_rh->cbdata;
+ mg_unlock_context(conn->ctx);
+ return 1;
+ }
+ }
+ }
+
+ /* next try for a partial match, we will accept uri/something */
+ for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
+ tmp_rh = tmp_rh->next) {
+ if (tmp_rh->handler_type == handler_type) {
+ if (tmp_rh->uri_len < urilen && uri[tmp_rh->uri_len] == '/'
+ && memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {
+ if (handler_type == WEBSOCKET_HANDLER) {
+ *connect_handler = tmp_rh->connect_handler;
+ *ready_handler = tmp_rh->ready_handler;
+ *data_handler = tmp_rh->data_handler;
+ *close_handler = tmp_rh->close_handler;
+ } else if (handler_type == REQUEST_HANDLER) {
+ *handler = tmp_rh->handler;
+ } else { /* AUTH_HANDLER */
+ *auth_handler = tmp_rh->auth_handler;
+ }
+ *cbdata = tmp_rh->cbdata;
+ mg_unlock_context(conn->ctx);
+ return 1;
+ }
+ }
+ }
+
+ /* finally try for pattern match */
+ for (tmp_rh = conn->ctx->handlers; tmp_rh != NULL;
+ tmp_rh = tmp_rh->next) {
+ if (tmp_rh->handler_type == handler_type) {
+ if (match_prefix(tmp_rh->uri, tmp_rh->uri_len, uri) > 0) {
+ if (handler_type == WEBSOCKET_HANDLER) {
+ *connect_handler = tmp_rh->connect_handler;
+ *ready_handler = tmp_rh->ready_handler;
+ *data_handler = tmp_rh->data_handler;
+ *close_handler = tmp_rh->close_handler;
+ } else if (handler_type == REQUEST_HANDLER) {
+ *handler = tmp_rh->handler;
+ } else { /* AUTH_HANDLER */
+ *auth_handler = tmp_rh->auth_handler;
+ }
+ *cbdata = tmp_rh->cbdata;
+ mg_unlock_context(conn->ctx);
+ return 1;
+ }
+ }
+ }
+
+ mg_unlock_context(conn->ctx);
+ }
+ return 0; /* none found */
+}
+
+
+#if defined(USE_WEBSOCKET) && defined(MG_LEGACY_INTERFACE)
+static int
+deprecated_websocket_connect_wrapper(const struct mg_connection *conn,
+ void *cbdata)
+{
+ struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
+ if (pcallbacks->websocket_connect) {
+ return pcallbacks->websocket_connect(conn);
+ }
+ /* No handler set - assume "OK" */
+ return 0;
+}
+
+
+static void
+deprecated_websocket_ready_wrapper(struct mg_connection *conn, void *cbdata)
+{
+ struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
+ if (pcallbacks->websocket_ready) {
+ pcallbacks->websocket_ready(conn);
+ }
+}
+
+
+static int
+deprecated_websocket_data_wrapper(struct mg_connection *conn,
+ int bits,
+ char *data,
+ size_t len,
+ void *cbdata)
+{
+ struct mg_callbacks *pcallbacks = (struct mg_callbacks *)cbdata;
+ if (pcallbacks->websocket_data) {
+ return pcallbacks->websocket_data(conn, bits, data, len);
+ }
+ /* No handler set - assume "OK" */
+ return 1;
+}
+#endif
+
+
+/* This is the heart of the Civetweb's logic.
+ * This function is called when the request is read, parsed and validated,
+ * and Civetweb must decide what action to take: serve a file, or
+ * a directory, or call embedded function, etcetera. */
+static void
+handle_request(struct mg_connection *conn)
+{
+ if (conn) {
+ struct mg_request_info *ri = &conn->request_info;
+ char path[PATH_MAX];
+ int uri_len, ssl_index;
+ int is_found = 0, is_script_resource = 0, is_websocket_request = 0,
+ is_put_or_delete_request = 0, is_callback_resource = 0;
+ int i;
+ struct file file = STRUCT_FILE_INITIALIZER;
+ mg_request_handler callback_handler = NULL;
+ mg_websocket_connect_handler ws_connect_handler = NULL;
+ mg_websocket_ready_handler ws_ready_handler = NULL;
+ mg_websocket_data_handler ws_data_handler = NULL;
+ mg_websocket_close_handler ws_close_handler = NULL;
+ void *callback_data = NULL;
+ mg_authorization_handler auth_handler = NULL;
+ void *auth_callback_data = NULL;
+#if !defined(NO_FILES)
+ time_t curtime = time(NULL);
+ char date[64];
+#endif
+
+ path[0] = 0;
+
+ if (!ri) {
+ return;
+ }
+
+ /* 1. get the request url */
+ /* 1.1. split into url and query string */
+ if ((conn->request_info.query_string = strchr(ri->request_uri, '?'))
+ != NULL) {
+ *((char *)conn->request_info.query_string++) = '\0';
+ }
+ uri_len = (int)strlen(ri->local_uri);
+
+ /* 1.2. decode url (if config says so) */
+ if (should_decode_url(conn)) {
+ mg_url_decode(
+ ri->local_uri, uri_len, (char *)ri->local_uri, uri_len + 1, 0);
+ }
+
+ /* 1.3. clean URIs, so a path like allowed_dir/../forbidden_file is
+ * not possible */
+ remove_double_dots_and_double_slashes((char *)ri->local_uri);
+
+ /* step 1. completed, the url is known now */
+ DEBUG_TRACE("URL: %s", ri->local_uri);
+
+ /* 2. do a https redirect, if required */
+ if (!conn->client.is_ssl && conn->client.ssl_redir) {
+ ssl_index = get_first_ssl_listener_index(conn->ctx);
+ if (ssl_index >= 0) {
+ redirect_to_https_port(conn, ssl_index);
+ } else {
+ /* A http to https forward port has been specified,
+ * but no https port to forward to. */
+ send_http_error(conn,
+ 503,
+ "%s",
+ "Error: SSL forward not configured properly");
+ mg_cry(conn, "Can not redirect to SSL, no SSL port available");
+ }
+ return;
+ }
+
+ /* 3. if this ip has limited speed, set it for this connection */
+ conn->throttle = set_throttle(conn->ctx->config[THROTTLE],
+ get_remote_ip(conn),
+ ri->local_uri);
+
+ /* 4. call a "handle everything" callback, if registered */
+ if (conn->ctx->callbacks.begin_request != NULL) {
+ /* Note that since V1.7 the "begin_request" function is called
+ * before an authorization check. If an authorization check is
+ * required, use a request_handler instead. */
+ i = conn->ctx->callbacks.begin_request(conn);
+ if (i > 0) {
+ /* callback already processed the request. Store the
+ return value as a status code for the access log. */
+ conn->status_code = i;
+ return;
+ } else if (i == 0) {
+ /* civetweb should process the request */
+ } else {
+ /* unspecified - may change with the next version */
+ return;
+ }
+ }
+
+ /* request not yet handled by a handler or redirect, so the request
+ * is processed here */
+
+ /* 5. interpret the url to find out how the request must be handled
+ */
+ /* 5.1. first test, if the request targets the regular http(s)://
+ * protocol namespace or the websocket ws(s):// protocol namespace.
+ */
+ is_websocket_request = is_websocket_protocol(conn);
+
+ /* 5.2. check if the request will be handled by a callback */
+ if (get_request_handler(conn,
+ is_websocket_request ? WEBSOCKET_HANDLER
+ : REQUEST_HANDLER,
+ &callback_handler,
+ &ws_connect_handler,
+ &ws_ready_handler,
+ &ws_data_handler,
+ &ws_close_handler,
+ NULL,
+ &callback_data)) {
+ /* 5.2.1. A callback will handle this request. All requests
+ * handled
+ * by a callback have to be considered as requests to a script
+ * resource. */
+ is_callback_resource = 1;
+ is_script_resource = 1;
+ is_put_or_delete_request = is_put_or_delete_method(conn);
+ } else {
+ no_callback_resource:
+ /* 5.2.2. No callback is responsible for this request. The URI
+ * addresses a file based resource (static content or Lua/cgi
+ * scripts in the file system). */
+ is_callback_resource = 0;
+ interpret_uri(conn,
+ path,
+ sizeof(path),
+ &file,
+ &is_found,
+ &is_script_resource,
+ &is_websocket_request,
+ &is_put_or_delete_request);
+ }
+
+ /* 6. authorization check */
+ /* 6.1. a custom authorization handler is installed */
+ if (get_request_handler(conn,
+ AUTH_HANDLER,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &auth_handler,
+ &auth_callback_data)) {
+ if (!auth_handler(conn, auth_callback_data)) {
+ return;
+ }
+ } else if (is_put_or_delete_request && !is_script_resource
+ && !is_callback_resource) {
+/* 6.2. this request is a PUT/DELETE to a real file */
+/* 6.2.1. thus, the server must have real files */
+#if defined(NO_FILES)
+ if (1) {
+#else
+ if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
+#endif
+ /* This server does not have any real files, thus the
+ * PUT/DELETE methods are not valid. */
+ send_http_error(conn,
+ 405,
+ "%s method not allowed",
+ conn->request_info.request_method);
+ return;
+ }
+
+#if !defined(NO_FILES)
+ /* 6.2.2. Check if put authorization for static files is
+ * available.
+ */
+ if (!is_authorized_for_put(conn)) {
+ send_authorization_request(conn);
+ return;
+ }
+#endif
+
+ } else {
+ /* 6.3. This is either a OPTIONS, GET, HEAD or POST request,
+ * or it is a PUT or DELETE request to a resource that does not
+ * correspond to a file. Check authorization. */
+ if (!check_authorization(conn, path)) {
+ send_authorization_request(conn);
+ return;
+ }
+ }
+
+ /* request is authorized or does not need authorization */
+
+ /* 7. check if there are request handlers for this uri */
+ if (is_callback_resource) {
+ if (!is_websocket_request) {
+ i = callback_handler(conn, callback_data);
+ if (i > 0) {
+ /* Do nothing, callback has served the request. Store
+ * the
+ * return value as status code for the log and discard
+ * all
+ * data from the client not used by the callback. */
+ conn->status_code = i;
+ discard_unread_request_data(conn);
+ } else {
+ /* TODO (high): what if the handler did NOT handle the
+ * request */
+ /* The last version did handle this as a file request,
+ * but
+ * since a file request is not always a script resource,
+ * the authorization check might be different */
+ interpret_uri(conn,
+ path,
+ sizeof(path),
+ &file,
+ &is_found,
+ &is_script_resource,
+ &is_websocket_request,
+ &is_put_or_delete_request);
+ callback_handler = NULL;
+
+ /* TODO (very low): goto is deprecated but for the
+ * moment,
+ * a goto is simpler than some curious loop. */
+ /* The situation "callback does not handle the request"
+ * needs to be reconsidered anyway. */
+ goto no_callback_resource;
+ }
+ } else {
+#if defined(USE_WEBSOCKET)
+ handle_websocket_request(conn,
+ path,
+ is_callback_resource,
+ ws_connect_handler,
+ ws_ready_handler,
+ ws_data_handler,
+ ws_close_handler,
+ callback_data);
+#endif
+ }
+ return;
+ }
+
+/* 8. handle websocket requests */
+#if defined(USE_WEBSOCKET)
+ if (is_websocket_request) {
+ if (is_script_resource) {
+ /* Websocket Lua script */
+ handle_websocket_request(conn,
+ path,
+ 0 /* Lua Script */,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &conn->ctx->callbacks);
+ } else {
+#if defined(MG_LEGACY_INTERFACE)
+ handle_websocket_request(
+ conn,
+ path,
+ !is_script_resource /* could be deprecated global callback */,
+ deprecated_websocket_connect_wrapper,
+ deprecated_websocket_ready_wrapper,
+ deprecated_websocket_data_wrapper,
+ NULL,
+ &conn->ctx->callbacks);
+#else
+ send_http_error(conn, 404, "%s", "Not found");
+#endif
+ }
+ return;
+ } else
+#endif
+
+#if defined(NO_FILES)
+ /* 9a. In case the server uses only callbacks, this uri is
+ * unknown.
+ * Then, all request handling ends here. */
+ send_http_error(conn, 404, "%s", "Not Found");
+
+#else
+ /* 9b. This request is either for a static file or resource handled
+ * by a script file. Thus, a DOCUMENT_ROOT must exist. */
+ if (conn->ctx->config[DOCUMENT_ROOT] == NULL) {
+ send_http_error(conn, 404, "%s", "Not Found");
+ return;
+ }
+
+ /* 10. File is handled by a script. */
+ if (is_script_resource) {
+ handle_file_based_request(conn, path, &file);
+ return;
+ }
+
+ /* 11. Handle put/delete/mkcol requests */
+ if (is_put_or_delete_request) {
+ /* 11.1. PUT method */
+ if (!strcmp(ri->request_method, "PUT")) {
+ put_file(conn, path);
+ return;
+ }
+ /* 11.2. DELETE method */
+ if (!strcmp(ri->request_method, "DELETE")) {
+ delete_file(conn, path);
+ return;
+ }
+ /* 11.3. MKCOL method */
+ if (!strcmp(ri->request_method, "MKCOL")) {
+ mkcol(conn, path);
+ return;
+ }
+ /* 11.4. PATCH method
+ * This method is not supported for static resources,
+ * only for scripts (Lua, CGI) and callbacks. */
+ send_http_error(conn,
+ 405,
+ "%s method not allowed",
+ conn->request_info.request_method);
+ return;
+ }
+
+ /* 11. File does not exist, or it was configured that it should be
+ * hidden */
+ if (!is_found || (must_hide_file(conn, path))) {
+ send_http_error(conn, 404, "%s", "Not found");
+ return;
+ }
+
+ /* 12. Directory uris should end with a slash */
+ if (file.is_directory && ri->local_uri[uri_len - 1] != '/') {
+ gmt_time_string(date, sizeof(date), &curtime);
+ mg_printf(conn,
+ "HTTP/1.1 301 Moved Permanently\r\n"
+ "Location: %s/\r\n"
+ "Date: %s\r\n"
+ /* "Cache-Control: private\r\n" (= default) */
+ "Content-Length: 0\r\n"
+ "Connection: %s\r\n\r\n",
+ ri->request_uri,
+ date,
+ suggest_connection_header(conn));
+ return;
+ }
+
+ /* 13. Handle other methods than GET/HEAD */
+ /* 13.1. Handle PROPFIND */
+ if (!strcmp(ri->request_method, "PROPFIND")) {
+ handle_propfind(conn, path, &file);
+ return;
+ }
+ /* 13.2. Handle OPTIONS for files */
+ if (!strcmp(ri->request_method, "OPTIONS")) {
+ /* This standard handler is only used for real files.
+ * Scripts should support the OPTIONS method themselves, to allow a
+ * maximum flexibility.
+ * Lua and CGI scripts may fully support CORS this way (including
+ * preflights). */
+ send_options(conn);
+ return;
+ }
+ /* 13.3. everything but GET and HEAD (e.g. POST) */
+ if (0 != strcmp(ri->request_method, "GET")
+ && 0 != strcmp(ri->request_method, "HEAD")) {
+ send_http_error(conn,
+ 405,
+ "%s method not allowed",
+ conn->request_info.request_method);
+ return;
+ }
+
+ /* 14. directories */
+ if (file.is_directory) {
+ if (substitute_index_file(conn, path, sizeof(path), &file)) {
+ /* 14.1. use a substitute file */
+ /* TODO (high): substitute index may be a script resource.
+ * define what should be possible in this case. */
+ } else {
+ /* 14.2. no substitute file */
+ if (!mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING],
+ "yes")) {
+ handle_directory_request(conn, path);
+ } else {
+ send_http_error(conn,
+ 403,
+ "%s",
+ "Error: Directory listing denied");
+ }
+ return;
+ }
+ }
+
+ handle_file_based_request(conn, path, &file);
+#endif /* !defined(NO_FILES) */
+
+#if 0
+ /* Perform redirect and auth checks before calling begin_request()
+ * handler.
+ * Otherwise, begin_request() would need to perform auth checks and
+ * redirects. */
+#endif
+ }
+ return;
+}
+
+
+static void
+handle_file_based_request(struct mg_connection *conn,
+ const char *path,
+ struct file *file)
+{
+ if (!conn || !conn->ctx) {
+ return;
+ }
+
+ if (0) {
+#ifdef USE_LUA
+ } else if (match_prefix(conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS],
+ strlen(
+ conn->ctx->config[LUA_SERVER_PAGE_EXTENSIONS]),
+ path) > 0) {
+ /* Lua server page: an SSI like page containing mostly plain html
+ * code
+ * plus some tags with server generated contents. */
+ handle_lsp_request(conn, path, file, NULL);
+ } else if (match_prefix(conn->ctx->config[LUA_SCRIPT_EXTENSIONS],
+ strlen(conn->ctx->config[LUA_SCRIPT_EXTENSIONS]),
+ path) > 0) {
+ /* Lua in-server module script: a CGI like script used to generate
+ * the
+ * entire reply. */
+ mg_exec_lua_script(conn, path, NULL);
+#endif
+#if defined(USE_DUKTAPE)
+ } else if (match_prefix(conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS],
+ strlen(
+ conn->ctx->config[DUKTAPE_SCRIPT_EXTENSIONS]),
+ path) > 0) {
+ /* Call duktape to generate the page */
+ mg_exec_duktape_script(conn, path);
+#endif
+#if !defined(NO_CGI)
+ } else if (match_prefix(conn->ctx->config[CGI_EXTENSIONS],
+ strlen(conn->ctx->config[CGI_EXTENSIONS]),
+ path) > 0) {
+ /* CGI scripts may support all HTTP methods */
+ handle_cgi_request(conn, path);
+#endif /* !NO_CGI */
+ } else if (match_prefix(conn->ctx->config[SSI_EXTENSIONS],
+ strlen(conn->ctx->config[SSI_EXTENSIONS]),
+ path) > 0) {
+ handle_ssi_file_request(conn, path, file);
+#if !defined(NO_CACHING)
+ } else if ((!conn->in_error_handler) && is_not_modified(conn, file)) {
+ /* Send 304 "Not Modified" - this must not send any body data */
+ send_http_error(conn, 304, "%s", "");
+#endif /* !NO_CACHING */
+ } else {
+ handle_static_file_request(conn, path, file, NULL);
+ }
+}
+
+
+static void
+close_all_listening_sockets(struct mg_context *ctx)
+{
+ unsigned int i;
+ if (!ctx) {
+ return;
+ }
+
+ for (i = 0; i < ctx->num_listening_sockets; i++) {
+ closesocket(ctx->listening_sockets[i].sock);
+ ctx->listening_sockets[i].sock = INVALID_SOCKET;
+ }
+ mg_free(ctx->listening_sockets);
+ ctx->listening_sockets = NULL;
+ mg_free(ctx->listening_ports);
+ ctx->listening_ports = NULL;
+}
+
+
+/* Valid listening port specification is: [ip_address:]port[s]
+ * Examples for IPv4: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
+ * Examples for IPv6: [::]:80, [::1]:80,
+ * [FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:443s
+ * see https://tools.ietf.org/html/rfc3513#section-2.2 */
+static int
+parse_port_string(const struct vec *vec, struct socket *so)
+{
+ unsigned int a, b, c, d, port;
+ int ch, len;
+#if defined(USE_IPV6)
+ char buf[100] = {0};
+#endif
+
+ /* MacOS needs that. If we do not zero it, subsequent bind() will fail.
+ * Also, all-zeroes in the socket address means binding to all addresses
+ * for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT). */
+ memset(so, 0, sizeof(*so));
+ so->lsa.sin.sin_family = AF_INET;
+
+ if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len)
+ == 5) {
+ /* Bind to a specific IPv4 address, e.g. 192.168.1.5:8080 */
+ so->lsa.sin.sin_addr.s_addr =
+ htonl((a << 24) | (b << 16) | (c << 8) | d);
+ so->lsa.sin.sin_port = htons((uint16_t)port);
+#if defined(USE_IPV6)
+ } else if (sscanf(vec->ptr, "[%49[^]]]:%u%n", buf, &port, &len) == 2
+ && mg_inet_pton(
+ AF_INET6, buf, &so->lsa.sin6, sizeof(so->lsa.sin6))) {
+ /* IPv6 address, examples: see above */
+ /* so->lsa.sin6.sin6_family = AF_INET6; already set by mg_inet_pton
+ */
+ so->lsa.sin6.sin6_port = htons((uint16_t)port);
+#endif
+ } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
+ /* If only port is specified, bind to IPv4, INADDR_ANY */
+ so->lsa.sin.sin_port = htons((uint16_t)port);
+ } else {
+ /* Parsing failure. Make port invalid. */
+ port = 0;
+ len = 0;
+ }
+
+ /* sscanf and the option splitting code ensure the following condition
+ */
+ if ((len < 0) && ((unsigned)len > (unsigned)vec->len)) {
+ return 0;
+ }
+ ch = vec->ptr[len]; /* Next character after the port number */
+ so->is_ssl = (ch == 's');
+ so->ssl_redir = (ch == 'r');
+
+ /* Make sure the port is valid and vector ends with 's', 'r' or ',' */
+ return is_valid_port(port)
+ && (ch == '\0' || ch == 's' || ch == 'r' || ch == ',');
+}
+
+
+static int
+set_ports_option(struct mg_context *ctx)
+{
+ const char *list;
+ int on = 1;
+#if defined(USE_IPV6)
+ int off = 0;
+#endif
+ struct vec vec;
+ struct socket so, *ptr;
+
+ in_port_t *portPtr;
+ union usa usa;
+ socklen_t len;
+
+ int portsTotal = 0;
+ int portsOk = 0;
+
+ if (!ctx) {
+ return 0;
+ }
+
+ memset(&so, 0, sizeof(so));
+ memset(&usa, 0, sizeof(usa));
+ len = sizeof(usa);
+ list = ctx->config[LISTENING_PORTS];
+ while ((list = next_option(list, &vec, NULL)) != NULL) {
+
+ portsTotal++;
+
+ if (!parse_port_string(&vec, &so)) {
+ mg_cry(fc(ctx),
+ "%.*s: invalid port spec (entry %i). Expecting list of: %s",
+ (int)vec.len,
+ vec.ptr,
+ portsTotal,
+ "[IP_ADDRESS:]PORT[s|r]");
+ continue;
+ }
+
+ if (so.is_ssl && ctx->ssl_ctx == NULL) {
+
+ mg_cry(fc(ctx),
+ "Cannot add SSL socket (entry %i). Is -ssl_certificate "
+ "option set?",
+ portsTotal);
+ continue;
+ }
+
+ if ((so.sock = socket(so.lsa.sa.sa_family, SOCK_STREAM, 6))
+ == INVALID_SOCKET) {
+
+ mg_cry(fc(ctx), "cannot create socket (entry %i)", portsTotal);
+ continue;
+ }
+
+#ifdef _WIN32
+ /* Windows SO_REUSEADDR lets many procs binds to a
+ * socket, SO_EXCLUSIVEADDRUSE makes the bind fail
+ * if someone already has the socket -- DTL */
+ /* NOTE: If SO_EXCLUSIVEADDRUSE is used,
+ * Windows might need a few seconds before
+ * the same port can be used again in the
+ * same process, so a short Sleep may be
+ * required between mg_stop and mg_start.
+ */
+ if (setsockopt(so.sock,
+ SOL_SOCKET,
+ SO_EXCLUSIVEADDRUSE,
+ (SOCK_OPT_TYPE)&on,
+ sizeof(on)) != 0) {
+
+ mg_cry(fc(ctx),
+ "cannot set socket option SO_EXCLUSIVEADDRUSE (entry %i)",
+ portsTotal);
+ }
+#else
+ if (setsockopt(so.sock,
+ SOL_SOCKET,
+ SO_REUSEADDR,
+ (SOCK_OPT_TYPE)&on,
+ sizeof(on)) != 0) {
+
+ mg_cry(fc(ctx),
+ "cannot set socket option SO_REUSEADDR (entry %i)",
+ portsTotal);
+ }
+#endif
+
+#if defined(USE_IPV6)
+ if (so.lsa.sa.sa_family == AF_INET6
+ && setsockopt(so.sock,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (void *)&off,
+ sizeof(off)) != 0) {
+
+ mg_cry(fc(ctx),
+ "cannot set socket option IPV6_V6ONLY (entry %i)",
+ portsTotal);
+ }
+#endif
+
+ if (so.lsa.sa.sa_family == AF_INET) {
+
+ len = sizeof(so.lsa.sin);
+ if (bind(so.sock, &so.lsa.sa, len) != 0) {
+ mg_cry(fc(ctx),
+ "cannot bind to %.*s: %d (%s)",
+ (int)vec.len,
+ vec.ptr,
+ (int)ERRNO,
+ strerror(errno));
+ closesocket(so.sock);
+ so.sock = INVALID_SOCKET;
+ continue;
+ }
+ }
+#if defined(USE_IPV6)
+ else if (so.lsa.sa.sa_family == AF_INET6) {
+
+ len = sizeof(so.lsa.sin6);
+ if (bind(so.sock, &so.lsa.sa, len) != 0) {
+ mg_cry(fc(ctx),
+ "cannot bind to IPv6 %.*s: %d (%s)",
+ (int)vec.len,
+ vec.ptr,
+ (int)ERRNO,
+ strerror(errno));
+ closesocket(so.sock);
+ so.sock = INVALID_SOCKET;
+ continue;
+ }
+ }
+#endif
+ else {
+ mg_cry(fc(ctx),
+ "cannot bind: address family not supported (entry %i)",
+ portsTotal);
+ continue;
+ }
+
+ if (listen(so.sock, SOMAXCONN) != 0) {
+
+ mg_cry(fc(ctx),
+ "cannot listen to %.*s: %d (%s)",
+ (int)vec.len,
+ vec.ptr,
+ (int)ERRNO,
+ strerror(errno));
+ closesocket(so.sock);
+ so.sock = INVALID_SOCKET;
+ continue;
+ }
+
+ if (getsockname(so.sock, &(usa.sa), &len) != 0) {
+
+ int err = (int)ERRNO;
+ mg_cry(fc(ctx),
+ "call to getsockname failed %.*s: %d (%s)",
+ (int)vec.len,
+ vec.ptr,
+ err,
+ strerror(errno));
+ closesocket(so.sock);
+ so.sock = INVALID_SOCKET;
+ continue;
+ }
+
+ if ((ptr = (struct socket *)
+ mg_realloc(ctx->listening_sockets,
+ (ctx->num_listening_sockets + 1)
+ * sizeof(ctx->listening_sockets[0]))) == NULL) {
+
+ mg_cry(fc(ctx), "%s", "Out of memory");
+ closesocket(so.sock);
+ so.sock = INVALID_SOCKET;
+ continue;
+ }
+
+ if ((portPtr =
+ (in_port_t *)mg_realloc(ctx->listening_ports,
+ (ctx->num_listening_sockets + 1)
+ * sizeof(ctx->listening_ports[0])))
+ == NULL) {
+
+ mg_cry(fc(ctx), "%s", "Out of memory");
+ closesocket(so.sock);
+ so.sock = INVALID_SOCKET;
+ mg_free(ptr);
+ continue;
+ }
+
+ set_close_on_exec(so.sock, fc(ctx));
+ ctx->listening_sockets = ptr;
+ ctx->listening_sockets[ctx->num_listening_sockets] = so;
+ ctx->listening_ports = portPtr;
+ ctx->listening_ports[ctx->num_listening_sockets] =
+ ntohs(usa.sin.sin_port);
+ ctx->num_listening_sockets++;
+ portsOk++;
+ }
+
+ if (portsOk != portsTotal) {
+ close_all_listening_sockets(ctx);
+ portsOk = 0;
+ }
+
+ return portsOk;
+}
+
+
+static const char *
+header_val(const struct mg_connection *conn, const char *header)
+{
+ const char *header_value;
+
+ if ((header_value = mg_get_header(conn, header)) == NULL) {
+ return "-";
+ } else {
+ return header_value;
+ }
+}
+
+
+static void
+log_access(const struct mg_connection *conn)
+{
+ const struct mg_request_info *ri;
+ struct file fi;
+ char date[64], src_addr[IP_ADDR_STR_LEN];
+ struct tm *tm;
+
+ const char *referer;
+ const char *user_agent;
+
+ char buf[4096];
+
+ if (!conn || !conn->ctx) {
+ return;
+ }
+
+ if (conn->ctx->config[ACCESS_LOG_FILE] != NULL) {
+ if (mg_fopen(conn, conn->ctx->config[ACCESS_LOG_FILE], "a+", &fi)
+ == 0) {
+ fi.fp = NULL;
+ }
+ } else {
+ fi.fp = NULL;
+ }
+
+ if (fi.fp == NULL && conn->ctx->callbacks.log_message == NULL) {
+ return;
+ }
+
+ tm = localtime(&conn->conn_birth_time);
+ if (tm != NULL) {
+ strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
+ } else {
+ mg_strlcpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
+ date[sizeof(date) - 1] = '\0';
+ }
+
+ ri = &conn->request_info;
+
+ sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
+ referer = header_val(conn, "Referer");
+ user_agent = header_val(conn, "User-Agent");
+
+ mg_snprintf(conn,
+ NULL, /* Ignore truncation in access log */
+ buf,
+ sizeof(buf),
+ "%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
+ src_addr,
+ ri->remote_user == NULL ? "-" : ri->remote_user,
+ date,
+ ri->request_method ? ri->request_method : "-",
+ ri->request_uri ? ri->request_uri : "-",
+ ri->query_string ? "?" : "",
+ ri->query_string ? ri->query_string : "",
+ ri->http_version,
+ conn->status_code,
+ conn->num_bytes_sent,
+ referer,
+ user_agent);
+
+ if (conn->ctx->callbacks.log_access) {
+ conn->ctx->callbacks.log_access(conn, buf);
+ }
+
+ if (fi.fp) {
+ flockfile(fi.fp);
+ fprintf(fi.fp, "%s\n", buf);
+ fflush(fi.fp);
+ funlockfile(fi.fp);
+ mg_fclose(&fi);
+ }
+}
+
+
+/* Verify given socket address against the ACL.
+ * Return -1 if ACL is malformed, 0 if address is disallowed, 1 if allowed.
+ */
+static int
+check_acl(struct mg_context *ctx, uint32_t remote_ip)
+{
+ int allowed, flag;
+ uint32_t net, mask;
+ struct vec vec;
+
+ if (ctx) {
+ const char *list = ctx->config[ACCESS_CONTROL_LIST];
+
+ /* If any ACL is set, deny by default */
+ allowed = list == NULL ? '+' : '-';
+
+ while ((list = next_option(list, &vec, NULL)) != NULL) {
+ flag = vec.ptr[0];
+ if ((flag != '+' && flag != '-')
+ || parse_net(&vec.ptr[1], &net, &mask) == 0) {
+ mg_cry(fc(ctx),
+ "%s: subnet must be [+|-]x.x.x.x[/x]",
+ __func__);
+ return -1;
+ }
+
+ if (net == (remote_ip & mask)) {
+ allowed = flag;
+ }
+ }
+
+ return allowed == '+';
+ }
+ return -1;
+}
+
+
+#if !defined(_WIN32)
+static int
+set_uid_option(struct mg_context *ctx)
+{
+ struct passwd *pw;
+ if (ctx) {
+ const char *uid = ctx->config[RUN_AS_USER];
+ int success = 0;
+
+ if (uid == NULL) {
+ success = 1;
+ } else {
+ if ((pw = getpwnam(uid)) == NULL) {
+ mg_cry(fc(ctx), "%s: unknown user [%s]", __func__, uid);
+ } else if (setgid(pw->pw_gid) == -1) {
+ mg_cry(fc(ctx),
+ "%s: setgid(%s): %s",
+ __func__,
+ uid,
+ strerror(errno));
+ } else if (setgroups(0, NULL)) {
+ mg_cry(fc(ctx),
+ "%s: setgroups(): %s",
+ __func__,
+ strerror(errno));
+ } else if (setuid(pw->pw_uid) == -1) {
+ mg_cry(fc(ctx),
+ "%s: setuid(%s): %s",
+ __func__,
+ uid,
+ strerror(errno));
+ } else {
+ success = 1;
+ }
+ }
+
+ return success;
+ }
+ return 0;
+}
+#endif /* !_WIN32 */
+
+
+static void
+tls_dtor(void *key)
+{
+ struct mg_workerTLS *tls = (struct mg_workerTLS *)key;
+ /* key == pthread_getspecific(sTlsKey); */
+
+ if (tls) {
+ if (tls->is_master == 2) {
+ tls->is_master = -3; /* Mark memory as dead */
+ mg_free(tls);
+ }
+ }
+ pthread_setspecific(sTlsKey, NULL);
+}
+
+
+#if !defined(NO_SSL)
+
+/* Must be set if sizeof(pthread_t) > sizeof(unsigned long) */
+static unsigned long
+ssl_id_callback(void)
+{
+#ifdef _WIN32
+ return GetCurrentThreadId();
+#else
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+/* For every compiler, either "sizeof(pthread_t) > sizeof(unsigned long)"
+ * or not, so one of the two conditions will be unreachable by construction.
+ * Unfortunately the C standard does not define a way to check this at
+ * compile time, since the #if preprocessor conditions can not use the sizeof
+ * operator as an argument. */
+#endif
+
+ if (sizeof(pthread_t) > sizeof(unsigned long)) {
+ /* This is the problematic case for CRYPTO_set_id_callback:
+ * The OS pthread_t can not be cast to unsigned long. */
+ struct mg_workerTLS *tls =
+ (struct mg_workerTLS *)pthread_getspecific(sTlsKey);
+ if (tls == NULL) {
+ /* SSL called from an unknown thread: Create some thread index.
+ */
+ tls = (struct mg_workerTLS *)mg_malloc(sizeof(struct mg_workerTLS));
+ tls->is_master = -2; /* -2 means "3rd party thread" */
+ tls->thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
+ pthread_setspecific(sTlsKey, tls);
+ }
+ return tls->thread_idx;
+ } else {
+ /* pthread_t may be any data type, so a simple cast to unsigned long
+ * can rise a warning/error, depending on the platform.
+ * Here memcpy is used as an anything-to-anything cast. */
+ unsigned long ret = 0;
+ pthread_t t = pthread_self();
+ memcpy(&ret, &t, sizeof(pthread_t));
+ return ret;
+ }
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+}
+
+
+static int ssl_use_pem_file(struct mg_context *ctx, const char *pem);
+static const char *ssl_error(void);
+
+
+static int
+refresh_trust(struct mg_connection *conn)
+{
+ static int reload_lock = 0;
+ static long int data_check = 0;
+
+ struct stat cert_buf;
+ long int t;
+ char *pem;
+ int should_verify_peer;
+
+ if ((pem = conn->ctx->config[SSL_CERTIFICATE]) == NULL
+ && conn->ctx->callbacks.init_ssl == NULL) {
+ return 0;
+ }
+
+ t = data_check;
+ if (stat(pem, &cert_buf) != -1) {
+ t = (long int)cert_buf.st_mtime;
+ }
+
+ if (data_check != t) {
+ data_check = t;
+
+ should_verify_peer =
+ (conn->ctx->config[SSL_DO_VERIFY_PEER] != NULL)
+ && (mg_strcasecmp(conn->ctx->config[SSL_DO_VERIFY_PEER], "yes")
+ == 0);
+
+ if (should_verify_peer) {
+ char *ca_path = conn->ctx->config[SSL_CA_PATH];
+ char *ca_file = conn->ctx->config[SSL_CA_FILE];
+ if (SSL_CTX_load_verify_locations(conn->ctx->ssl_ctx,
+ ca_file,
+ ca_path) != 1) {
+ mg_cry(fc(conn->ctx),
+ "SSL_CTX_load_verify_locations error: %s "
+ "ssl_verify_peer requires setting "
+ "either ssl_ca_path or ssl_ca_file. Is any of them "
+ "present in "
+ "the .conf file?",
+ ssl_error());
+ return 0;
+ }
+ }
+
+ if (!reload_lock) {
+ reload_lock = 1;
+ if (ssl_use_pem_file(conn->ctx, pem) == 0) {
+ return 0;
+ }
+ reload_lock = 0;
+ }
+ }
+ /* lock while cert is reloading */
+ while (reload_lock) {
+ sleep(1);
+ }
+
+ return 1;
+}
+
+
+static pthread_mutex_t *ssl_mutexes;
+
+
+static int
+sslize(struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *))
+{
+ int ret, err;
+ int short_trust;
+
+ if (!conn) {
+ return 0;
+ }
+
+ short_trust =
+ (conn->ctx->config[SSL_SHORT_TRUST] != NULL)
+ && (mg_strcasecmp(conn->ctx->config[SSL_SHORT_TRUST], "yes") == 0);
+
+ if (short_trust) {
+ int trust_ret = refresh_trust(conn);
+ if (!trust_ret) {
+ return trust_ret;
+ }
+ }
+
+ conn->ssl = SSL_new(s);
+ if (conn->ssl == NULL) {
+ return 0;
+ }
+
+ ret = SSL_set_fd(conn->ssl, conn->client.sock);
+ if (ret != 1) {
+ err = SSL_get_error(conn->ssl, ret);
+ (void)err; /* TODO: set some error message */
+ SSL_free(conn->ssl);
+ conn->ssl = NULL;
+ /* maybe not? CRYPTO_cleanup_all_ex_data(); */
+ /* see
+ * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
+ ERR_remove_state(0);
+ return 0;
+ }
+
+ ret = func(conn->ssl);
+ if (ret != 1) {
+ err = SSL_get_error(conn->ssl, ret);
+ (void)err; /* TODO: set some error message */
+ SSL_free(conn->ssl);
+ conn->ssl = NULL;
+ /* maybe not? CRYPTO_cleanup_all_ex_data(); */
+ /* see
+ * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
+ ERR_remove_state(0);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Return OpenSSL error message (from CRYPTO lib) */
+static const char *
+ssl_error(void)
+{
+ unsigned long err;
+ err = ERR_get_error();
+ return err == 0 ? "" : ERR_error_string(err, NULL);
+}
+
+
+static void
+ssl_locking_callback(int mode, int mutex_num, const char *file, int line)
+{
+ (void)line;
+ (void)file;
+
+ if (mode & 1) {
+ /* 1 is CRYPTO_LOCK */
+ (void)pthread_mutex_lock(&ssl_mutexes[mutex_num]);
+ } else {
+ (void)pthread_mutex_unlock(&ssl_mutexes[mutex_num]);
+ }
+}
+
+
+#if !defined(NO_SSL_DL)
+static void *
+load_dll(struct mg_context *ctx, const char *dll_name, struct ssl_func *sw)
+{
+ union {
+ void *p;
+ void (*fp)(void);
+ } u;
+ void *dll_handle;
+ struct ssl_func *fp;
+
+ if ((dll_handle = dlopen(dll_name, RTLD_LAZY)) == NULL) {
+ mg_cry(fc(ctx), "%s: cannot load %s", __func__, dll_name);
+ return NULL;
+ }
+
+ for (fp = sw; fp->name != NULL; fp++) {
+#ifdef _WIN32
+ /* GetProcAddress() returns pointer to function */
+ u.fp = (void (*)(void))dlsym(dll_handle, fp->name);
+#else
+ /* dlsym() on UNIX returns void *. ISO C forbids casts of data
+ * pointers to function pointers. We need to use a union to make a
+ * cast. */
+ u.p = dlsym(dll_handle, fp->name);
+#endif /* _WIN32 */
+ if (u.fp == NULL) {
+ mg_cry(fc(ctx),
+ "%s: %s: cannot find %s",
+ __func__,
+ dll_name,
+ fp->name);
+ dlclose(dll_handle);
+ return NULL;
+ } else {
+ fp->ptr = u.fp;
+ }
+ }
+
+ return dll_handle;
+}
+
+
+static void *ssllib_dll_handle; /* Store the ssl library handle. */
+static void *cryptolib_dll_handle; /* Store the crypto library handle. */
+
+#endif /* NO_SSL_DL */
+
+
+#if defined(SSL_ALREADY_INITIALIZED)
+static int cryptolib_users = 1; /* Reference counter for crypto library. */
+#else
+static int cryptolib_users = 0; /* Reference counter for crypto library. */
+#endif
+
+
+static int
+initialize_ssl(struct mg_context *ctx)
+{
+ int i;
+ size_t size;
+
+#if !defined(NO_SSL_DL)
+ if (!cryptolib_dll_handle) {
+ cryptolib_dll_handle = load_dll(ctx, CRYPTO_LIB, crypto_sw);
+ if (!cryptolib_dll_handle) {
+ return 0;
+ }
+ }
+#endif /* NO_SSL_DL */
+
+ if (mg_atomic_inc(&cryptolib_users) > 1) {
+ return 1;
+ }
+
+ /* Initialize locking callbacks, needed for thread safety.
+ * http://www.openssl.org/support/faq.html#PROG1
+ */
+ i = CRYPTO_num_locks();
+ if (i < 0) {
+ i = 0;
+ }
+ size = sizeof(pthread_mutex_t) * ((size_t)(i));
+ if ((ssl_mutexes = (pthread_mutex_t *)mg_malloc(size)) == NULL) {
+ mg_cry(fc(ctx),
+ "%s: cannot allocate mutexes: %s",
+ __func__,
+ ssl_error());
+ return 0;
+ }
+
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_init(&ssl_mutexes[i], &pthread_mutex_attr);
+ }
+
+ CRYPTO_set_locking_callback(&ssl_locking_callback);
+ CRYPTO_set_id_callback(&ssl_id_callback);
+
+ return 1;
+}
+
+
+static int
+ssl_use_pem_file(struct mg_context *ctx, const char *pem)
+{
+ if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0) {
+ mg_cry(fc(ctx),
+ "%s: cannot open certificate file %s: %s",
+ __func__,
+ pem,
+ ssl_error());
+ return 0;
+ }
+
+ /* could use SSL_CTX_set_default_passwd_cb_userdata */
+ if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0) {
+ mg_cry(fc(ctx),
+ "%s: cannot open private key file %s: %s",
+ __func__,
+ pem,
+ ssl_error());
+ return 0;
+ }
+
+ if (SSL_CTX_check_private_key(ctx->ssl_ctx) == 0) {
+ mg_cry(fc(ctx),
+ "%s: certificate and private key do not match: %s",
+ __func__,
+ pem);
+ return 0;
+ }
+
+ if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem) == 0) {
+ mg_cry(fc(ctx),
+ "%s: cannot use certificate chain file %s: %s",
+ __func__,
+ pem,
+ ssl_error());
+ return 0;
+ }
+ return 1;
+}
+
+
+static long
+ssl_get_protocol(int version_id)
+{
+ long ret = SSL_OP_ALL;
+ if (version_id > 0)
+ ret |= SSL_OP_NO_SSLv2;
+ if (version_id > 1)
+ ret |= SSL_OP_NO_SSLv3;
+ if (version_id > 2)
+ ret |= SSL_OP_NO_TLSv1;
+ if (version_id > 3)
+ ret |= SSL_OP_NO_TLSv1_1;
+ return ret;
+}
+
+
+/* Dynamically load SSL library. Set up ctx->ssl_ctx pointer. */
+static int
+set_ssl_option(struct mg_context *ctx)
+{
+ const char *pem;
+ int callback_ret;
+ int should_verify_peer;
+ const char *ca_path;
+ const char *ca_file;
+ int use_default_verify_paths;
+ int verify_depth;
+ time_t now_rt = time(NULL);
+ struct timespec now_mt;
+ md5_byte_t ssl_context_id[16];
+ md5_state_t md5state;
+ int protocol_ver;
+
+ /* If PEM file is not specified and the init_ssl callback
+ * is not specified, skip SSL initialization. */
+ if (!ctx) {
+ return 0;
+ }
+ if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL
+ && ctx->callbacks.init_ssl == NULL) {
+ return 1;
+ }
+
+ if (!initialize_ssl(ctx)) {
+ return 0;
+ }
+
+#if !defined(NO_SSL_DL)
+ if (!ssllib_dll_handle) {
+ ssllib_dll_handle = load_dll(ctx, SSL_LIB, ssl_sw);
+ if (!ssllib_dll_handle) {
+ return 0;
+ }
+ }
+#endif /* NO_SSL_DL */
+
+ /* Initialize SSL library */
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
+ mg_cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error());
+ return 0;
+ }
+
+ SSL_CTX_clear_options(ctx->ssl_ctx,
+ SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1
+ | SSL_OP_NO_TLSv1_1);
+ protocol_ver = atoi(ctx->config[SSL_PROTOCOL_VERSION]);
+ SSL_CTX_set_options(ctx->ssl_ctx, ssl_get_protocol(protocol_ver));
+ SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_SINGLE_DH_USE);
+ SSL_CTX_set_ecdh_auto(ctx->ssl_ctx, 1);
+
+ /* If a callback has been specified, call it. */
+ callback_ret =
+ (ctx->callbacks.init_ssl == NULL)
+ ? 0
+ : (ctx->callbacks.init_ssl(ctx->ssl_ctx, ctx->user_data));
+
+ /* If callback returns 0, civetweb sets up the SSL certificate.
+ * If it returns 1, civetweb assumes the calback already did this.
+ * If it returns -1, initializing ssl fails. */
+ if (callback_ret < 0) {
+ mg_cry(fc(ctx), "SSL callback returned error: %i", callback_ret);
+ return 0;
+ }
+ if (callback_ret > 0) {
+ if (pem != NULL) {
+ (void)SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem);
+ }
+ return 1;
+ }
+
+ /* Use some UID as session context ID. */
+ md5_init(&md5state);
+ md5_append(&md5state, (const md5_byte_t *)&now_rt, sizeof(now_rt));
+ clock_gettime(CLOCK_MONOTONIC, &now_mt);
+ md5_append(&md5state, (const md5_byte_t *)&now_mt, sizeof(now_mt));
+ md5_append(&md5state,
+ (const md5_byte_t *)ctx->config[LISTENING_PORTS],
+ strlen(ctx->config[LISTENING_PORTS]));
+ md5_append(&md5state, (const md5_byte_t *)ctx, sizeof(*ctx));
+ md5_finish(&md5state, ssl_context_id);
+
+ SSL_CTX_set_session_id_context(ctx->ssl_ctx,
+ (const unsigned char *)&ssl_context_id,
+ sizeof(ssl_context_id));
+
+ if (pem != NULL) {
+ if (!ssl_use_pem_file(ctx, pem)) {
+ return 0;
+ }
+ }
+
+ should_verify_peer =
+ (ctx->config[SSL_DO_VERIFY_PEER] != NULL)
+ && (mg_strcasecmp(ctx->config[SSL_DO_VERIFY_PEER], "yes") == 0);
+
+ use_default_verify_paths =
+ (ctx->config[SSL_DEFAULT_VERIFY_PATHS] != NULL)
+ && (mg_strcasecmp(ctx->config[SSL_DEFAULT_VERIFY_PATHS], "yes") == 0);
+
+ if (should_verify_peer) {
+ ca_path = ctx->config[SSL_CA_PATH];
+ ca_file = ctx->config[SSL_CA_FILE];
+ if (SSL_CTX_load_verify_locations(ctx->ssl_ctx, ca_file, ca_path)
+ != 1) {
+ mg_cry(fc(ctx),
+ "SSL_CTX_load_verify_locations error: %s "
+ "ssl_verify_peer requires setting "
+ "either ssl_ca_path or ssl_ca_file. Is any of them "
+ "present in "
+ "the .conf file?",
+ ssl_error());
+ return 0;
+ }
+
+ SSL_CTX_set_verify(ctx->ssl_ctx,
+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+ NULL);
+
+ if (use_default_verify_paths
+ && SSL_CTX_set_default_verify_paths(ctx->ssl_ctx) != 1) {
+ mg_cry(fc(ctx),
+ "SSL_CTX_set_default_verify_paths error: %s",
+ ssl_error());
+ return 0;
+ }
+
+ if (ctx->config[SSL_VERIFY_DEPTH]) {
+ verify_depth = atoi(ctx->config[SSL_VERIFY_DEPTH]);
+ SSL_CTX_set_verify_depth(ctx->ssl_ctx, verify_depth);
+ }
+ }
+
+ if (ctx->config[SSL_CIPHER_LIST] != NULL) {
+ if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, ctx->config[SSL_CIPHER_LIST])
+ != 1) {
+ mg_cry(fc(ctx), "SSL_CTX_set_cipher_list error: %s", ssl_error());
+ }
+ }
+
+ return 1;
+}
+
+
+static void
+uninitialize_ssl(struct mg_context *ctx)
+{
+ int i;
+ (void)ctx;
+
+ if (mg_atomic_dec(&cryptolib_users) == 0) {
+
+ /* Shutdown according to
+ * https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
+ * http://stackoverflow.com/questions/29845527/how-to-properly-uninitialize-openssl
+ */
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_id_callback(NULL);
+ ENGINE_cleanup();
+ CONF_modules_unload(1);
+ ERR_free_strings();
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+ ERR_remove_state(0);
+
+ for (i = 0; i < CRYPTO_num_locks(); i++) {
+ pthread_mutex_destroy(&ssl_mutexes[i]);
+ }
+ mg_free(ssl_mutexes);
+ ssl_mutexes = NULL;
+ }
+}
+#endif /* !NO_SSL */
+
+
+static int
+set_gpass_option(struct mg_context *ctx)
+{
+ if (ctx) {
+ struct file file = STRUCT_FILE_INITIALIZER;
+ const char *path = ctx->config[GLOBAL_PASSWORDS_FILE];
+ if (path != NULL && !mg_stat(fc(ctx), path, &file)) {
+ mg_cry(fc(ctx), "Cannot open %s: %s", path, strerror(ERRNO));
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+static int
+set_acl_option(struct mg_context *ctx)
+{
+ return check_acl(ctx, (uint32_t)0x7f000001UL) != -1;
+}
+
+
+static void
+reset_per_request_attributes(struct mg_connection *conn)
+{
+ if (!conn) {
+ return;
+ }
+ conn->path_info = NULL;
+ conn->num_bytes_sent = conn->consumed_content = 0;
+ conn->status_code = -1;
+ conn->is_chunked = 0;
+ conn->must_close = conn->request_len = conn->throttle = 0;
+ conn->request_info.content_length = -1;
+ conn->request_info.remote_user = NULL;
+ conn->request_info.request_method = NULL;
+ conn->request_info.request_uri = NULL;
+ conn->request_info.local_uri = NULL;
+ conn->request_info.uri = NULL; /* TODO: cleanup uri,
+ * local_uri and request_uri */
+ conn->request_info.http_version = NULL;
+ conn->request_info.num_headers = 0;
+ conn->data_len = 0;
+ conn->chunk_remainder = 0;
+ conn->internal_error = 0;
+}
+
+
+static int
+set_sock_timeout(SOCKET sock, int milliseconds)
+{
+ int r0 = 0, r1, r2;
+
+#ifdef _WIN32
+ /* Windows specific */
+
+ DWORD tv = (DWORD)milliseconds;
+
+#else
+ /* Linux, ... (not Windows) */
+
+ struct timeval tv;
+
+/* TCP_USER_TIMEOUT/RFC5482 (http://tools.ietf.org/html/rfc5482):
+ * max. time waiting for the acknowledged of TCP data before the connection
+ * will be forcefully closed and ETIMEDOUT is returned to the application.
+ * If this option is not set, the default timeout of 20-30 minutes is used.
+*/
+/* #define TCP_USER_TIMEOUT (18) */
+
+#if defined(TCP_USER_TIMEOUT)
+ unsigned int uto = (unsigned int)milliseconds;
+ r0 = setsockopt(sock, 6, TCP_USER_TIMEOUT, (const void *)&uto, sizeof(uto));
+#endif
+
+ memset(&tv, 0, sizeof(tv));
+ tv.tv_sec = milliseconds / 1000;
+ tv.tv_usec = (milliseconds * 1000) % 1000000;
+
+#endif /* _WIN32 */
+
+ r1 = setsockopt(
+ sock, SOL_SOCKET, SO_RCVTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
+ r2 = setsockopt(
+ sock, SOL_SOCKET, SO_SNDTIMEO, (SOCK_OPT_TYPE)&tv, sizeof(tv));
+
+ return r0 || r1 || r2;
+}
+
+
+static int
+set_tcp_nodelay(SOCKET sock, int nodelay_on)
+{
+ if (setsockopt(sock,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (SOCK_OPT_TYPE)&nodelay_on,
+ sizeof(nodelay_on)) != 0) {
+ /* Error */
+ return 1;
+ }
+ /* OK */
+ return 0;
+}
+
+
+static void
+close_socket_gracefully(struct mg_connection *conn)
+{
+#if defined(_WIN32)
+ char buf[MG_BUF_LEN];
+ int n;
+#endif
+ struct linger linger;
+
+ if (!conn) {
+ return;
+ }
+
+ /* Set linger option to avoid socket hanging out after close. This
+ * prevent
+ * ephemeral port exhaust problem under high QPS. */
+ linger.l_onoff = 1;
+ linger.l_linger = 1;
+
+ if (setsockopt(conn->client.sock,
+ SOL_SOCKET,
+ SO_LINGER,
+ (char *)&linger,
+ sizeof(linger)) != 0) {
+ mg_cry(conn,
+ "%s: setsockopt(SOL_SOCKET SO_LINGER) failed: %s",
+ __func__,
+ strerror(ERRNO));
+ }
+
+ /* Send FIN to the client */
+ shutdown(conn->client.sock, SHUT_WR);
+ set_non_blocking_mode(conn->client.sock);
+
+#if defined(_WIN32)
+ /* Read and discard pending incoming data. If we do not do that and
+ * close
+ * the socket, the data in the send buffer may be discarded. This
+ * behaviour is seen on Windows, when client keeps sending data
+ * when server decides to close the connection; then when client
+ * does recv() it gets no data back. */
+ do {
+ n = pull(
+ NULL, conn, buf, sizeof(buf), 1E-10 /* TODO: allow 0 as timeout */);
+ } while (n > 0);
+#endif
+
+ /* Now we know that our FIN is ACK-ed, safe to close */
+ closesocket(conn->client.sock);
+ conn->client.sock = INVALID_SOCKET;
+}
+
+
+static void
+close_connection(struct mg_connection *conn)
+{
+ if (!conn || !conn->ctx) {
+ return;
+ }
+
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+ if (conn->lua_websocket_state) {
+ lua_websocket_close(conn, conn->lua_websocket_state);
+ conn->lua_websocket_state = NULL;
+ }
+#endif
+
+ /* call the connection_close callback if assigned */
+ if ((conn->ctx->callbacks.connection_close != NULL)
+ && (conn->ctx->context_type == 1)) {
+ conn->ctx->callbacks.connection_close(conn);
+ }
+
+ mg_lock_connection(conn);
+
+ conn->must_close = 1;
+
+#ifndef NO_SSL
+ if (conn->ssl != NULL) {
+ /* Run SSL_shutdown twice to ensure completly close SSL connection
+ */
+ SSL_shutdown(conn->ssl);
+ SSL_free(conn->ssl);
+ /* maybe not? CRYPTO_cleanup_all_ex_data(); */
+ /* see
+ * https://wiki.openssl.org/index.php/Talk:Library_Initialization */
+ ERR_remove_state(0);
+ conn->ssl = NULL;
+ }
+#endif
+ if (conn->client.sock != INVALID_SOCKET) {
+ close_socket_gracefully(conn);
+ conn->client.sock = INVALID_SOCKET;
+ }
+
+ mg_unlock_connection(conn);
+}
+
+void
+mg_close_connection(struct mg_connection *conn)
+{
+ struct mg_context *client_ctx = NULL;
+ unsigned int i;
+
+ if (conn == NULL) {
+ return;
+ }
+
+ if (conn->ctx->context_type == 2) {
+ client_ctx = conn->ctx;
+ /* client context: loops must end */
+ conn->ctx->stop_flag = 1;
+ }
+
+#ifndef NO_SSL
+ if (conn->client_ssl_ctx != NULL) {
+ SSL_CTX_free((SSL_CTX *)conn->client_ssl_ctx);
+ }
+#endif
+ close_connection(conn);
+ if (client_ctx != NULL) {
+ /* join worker thread and free context */
+ for (i = 0; i < client_ctx->cfg_worker_threads; i++) {
+ if (client_ctx->workerthreadids[i] != 0) {
+ mg_join_thread(client_ctx->workerthreadids[i]);
+ }
+ }
+ mg_free(client_ctx->workerthreadids);
+ mg_free(client_ctx);
+ (void)pthread_mutex_destroy(&conn->mutex);
+ mg_free(conn);
+ }
+}
+
+
+static struct mg_connection *
+mg_connect_client_impl(const struct mg_client_options *client_options,
+ int use_ssl,
+ char *ebuf,
+ size_t ebuf_len)
+{
+ static struct mg_context fake_ctx;
+ struct mg_connection *conn = NULL;
+ SOCKET sock;
+ union usa sa;
+
+ if (!connect_socket(&fake_ctx,
+ client_options->host,
+ client_options->port,
+ use_ssl,
+ ebuf,
+ ebuf_len,
+ &sock,
+ &sa)) {
+ ;
+ } else if ((conn = (struct mg_connection *)
+ mg_calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE)) == NULL) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "calloc(): %s",
+ strerror(ERRNO));
+ closesocket(sock);
+#ifndef NO_SSL
+ } else if (use_ssl
+ && (conn->client_ssl_ctx = SSL_CTX_new(SSLv23_client_method()))
+ == NULL) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "SSL_CTX_new error");
+ closesocket(sock);
+ mg_free(conn);
+ conn = NULL;
+#endif /* NO_SSL */
+
+ } else {
+
+#ifdef USE_IPV6
+ socklen_t len = (sa.sa.sa_family == AF_INET)
+ ? sizeof(conn->client.rsa.sin)
+ : sizeof(conn->client.rsa.sin6);
+ struct sockaddr *psa =
+ (sa.sa.sa_family == AF_INET)
+ ? (struct sockaddr *)&(conn->client.rsa.sin)
+ : (struct sockaddr *)&(conn->client.rsa.sin6);
+#else
+ socklen_t len = sizeof(conn->client.rsa.sin);
+ struct sockaddr *psa = (struct sockaddr *)&(conn->client.rsa.sin);
+#endif
+
+ conn->buf_size = MAX_REQUEST_SIZE;
+ conn->buf = (char *)(conn + 1);
+ conn->ctx = &fake_ctx;
+ conn->client.sock = sock;
+ conn->client.lsa = sa;
+
+ if (getsockname(sock, psa, &len) != 0) {
+ mg_cry(conn,
+ "%s: getsockname() failed: %s",
+ __func__,
+ strerror(ERRNO));
+ }
+
+ conn->client.is_ssl = use_ssl ? 1 : 0;
+ (void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
+
+#ifndef NO_SSL
+ if (use_ssl) {
+ fake_ctx.ssl_ctx = conn->client_ssl_ctx;
+
+ /* TODO: Check ssl_verify_peer and ssl_ca_path here.
+ * SSL_CTX_set_verify call is needed to switch off server
+ * certificate checking, which is off by default in OpenSSL and
+ * on in yaSSL. */
+ /* TODO: SSL_CTX_set_verify(conn->client_ssl_ctx,
+ * SSL_VERIFY_PEER, verify_ssl_server); */
+
+ if (client_options->client_cert) {
+ if (!ssl_use_pem_file(&fake_ctx, client_options->client_cert)) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "Can not use SSL client certificate");
+ SSL_CTX_free(conn->client_ssl_ctx);
+ closesocket(sock);
+ mg_free(conn);
+ conn = NULL;
+ }
+ }
+
+ if (client_options->server_cert) {
+ SSL_CTX_load_verify_locations(conn->client_ssl_ctx,
+ client_options->server_cert,
+ NULL);
+ SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_PEER, NULL);
+ } else {
+ SSL_CTX_set_verify(conn->client_ssl_ctx, SSL_VERIFY_NONE, NULL);
+ }
+
+ if (!sslize(conn, conn->client_ssl_ctx, SSL_connect)) {
+ mg_snprintf(NULL,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "SSL connection error");
+ SSL_CTX_free(conn->client_ssl_ctx);
+ closesocket(sock);
+ mg_free(conn);
+ conn = NULL;
+ }
+ }
+#endif
+ }
+
+ return conn;
+}
+
+
+CIVETWEB_API struct mg_connection *
+mg_connect_client_secure(const struct mg_client_options *client_options,
+ char *error_buffer,
+ size_t error_buffer_size)
+{
+ return mg_connect_client_impl(client_options,
+ 1,
+ error_buffer,
+ error_buffer_size);
+}
+
+
+struct mg_connection *
+mg_connect_client(const char *host,
+ int port,
+ int use_ssl,
+ char *error_buffer,
+ size_t error_buffer_size)
+{
+ struct mg_client_options opts;
+ memset(&opts, 0, sizeof(opts));
+ opts.host = host;
+ opts.port = port;
+ return mg_connect_client_impl(&opts,
+ use_ssl,
+ error_buffer,
+ error_buffer_size);
+}
+
+
+static const struct {
+ const char *proto;
+ size_t proto_len;
+ unsigned default_port;
+} abs_uri_protocols[] = {{"http://", 7, 80},
+ {"https://", 8, 443},
+ {"ws://", 5, 80},
+ {"wss://", 6, 443},
+ {NULL, 0, 0}};
+
+
+/* Check if the uri is valid.
+ * return 0 for invalid uri,
+ * return 1 for *,
+ * return 2 for relative uri,
+ * return 3 for absolute uri without port,
+ * return 4 for absolute uri with port */
+static int
+get_uri_type(const char *uri)
+{
+ int i;
+ char *hostend, *portbegin, *portend;
+ unsigned long port;
+
+ /* According to the HTTP standard
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
+ * URI can be an asterisk (*) or should start with slash (relative uri),
+ * or it should start with the protocol (absolute uri). */
+ if (uri[0] == '*' && uri[1] == '\0') {
+ /* asterisk */
+ return 1;
+ }
+ if (uri[0] == '/') {
+ /* relative uri */
+ return 2;
+ }
+
+ /* It could be an absolute uri: */
+ /* This function only checks if the uri is valid, not if it is
+ * addressing the current server. So civetweb can also be used
+ * as a proxy server. */
+ for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
+ if (mg_strncasecmp(uri,
+ abs_uri_protocols[i].proto,
+ abs_uri_protocols[i].proto_len) == 0) {
+
+ hostend = strchr(uri + abs_uri_protocols[i].proto_len, '/');
+ if (!hostend) {
+ return 0;
+ }
+ portbegin = strchr(uri + abs_uri_protocols[i].proto_len, ':');
+ if (!portbegin) {
+ return 3;
+ }
+
+ port = strtoul(portbegin + 1, &portend, 10);
+ if ((portend != hostend) || !port || !is_valid_port(port)) {
+ return 0;
+ }
+
+ return 4;
+ }
+ }
+
+ return 0;
+}
+
+
+/* Return NULL or the relative uri at the current server */
+static const char *
+get_rel_url_at_current_server(const char *uri, const struct mg_connection *conn)
+{
+ const char *server_domain;
+ size_t server_domain_len;
+ size_t request_domain_len = 0;
+ unsigned long port = 0;
+ int i;
+ const char *hostbegin = NULL;
+ const char *hostend = NULL;
+ const char *portbegin;
+ char *portend;
+
+ /* DNS is case insensitive, so use case insensitive string compare here
+ */
+ server_domain = conn->ctx->config[AUTHENTICATION_DOMAIN];
+ if (!server_domain) {
+ return 0;
+ }
+ server_domain_len = strlen(server_domain);
+ if (!server_domain_len) {
+ return 0;
+ }
+
+ for (i = 0; abs_uri_protocols[i].proto != NULL; i++) {
+ if (mg_strncasecmp(uri,
+ abs_uri_protocols[i].proto,
+ abs_uri_protocols[i].proto_len) == 0) {
+
+ hostbegin = uri + abs_uri_protocols[i].proto_len;
+ hostend = strchr(hostbegin, '/');
+ if (!hostend) {
+ return 0;
+ }
+ portbegin = strchr(hostbegin, ':');
+ if ((!portbegin) || (portbegin > hostend)) {
+ port = abs_uri_protocols[i].default_port;
+ request_domain_len = (size_t)(hostend - hostbegin);
+ } else {
+ port = strtoul(portbegin + 1, &portend, 10);
+ if ((portend != hostend) || !port || !is_valid_port(port)) {
+ return 0;
+ }
+ request_domain_len = (size_t)(portbegin - hostbegin);
+ }
+ /* protocol found, port set */
+ break;
+ }
+ }
+
+ if (!port) {
+ /* port remains 0 if the protocol is not found */
+ return 0;
+ }
+
+#if defined(USE_IPV6)
+ if (conn->client.lsa.sa.sa_family == AF_INET6) {
+ if (ntohs(conn->client.lsa.sin6.sin6_port) != port) {
+ /* Request is directed to a different port */
+ return 0;
+ }
+ } else
+#endif
+ {
+ if (ntohs(conn->client.lsa.sin.sin_port) != port) {
+ /* Request is directed to a different port */
+ return 0;
+ }
+ }
+
+ if ((request_domain_len != server_domain_len)
+ || (0 != memcmp(server_domain, hostbegin, server_domain_len))) {
+ /* Request is directed to another server */
+ return 0;
+ }
+
+ return hostend;
+}
+
+
+static int
+getreq(struct mg_connection *conn, char *ebuf, size_t ebuf_len, int *err)
+{
+ const char *cl;
+
+ if (ebuf_len > 0) {
+ ebuf[0] = '\0';
+ }
+ *err = 0;
+
+ reset_per_request_attributes(conn);
+
+ if (!conn) {
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "Internal error");
+ *err = 500;
+ return 0;
+ }
+ /* Set the time the request was received. This value should be used for
+ * timeouts. */
+ clock_gettime(CLOCK_MONOTONIC, &(conn->req_time));
+
+ conn->request_len =
+ read_request(NULL, conn, conn->buf, conn->buf_size, &conn->data_len);
+ /* assert(conn->request_len < 0 || conn->data_len >= conn->request_len);
+ */
+ if (conn->request_len >= 0 && conn->data_len < conn->request_len) {
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "Invalid request size");
+ *err = 500;
+ return 0;
+ }
+
+ if (conn->request_len == 0 && conn->data_len == conn->buf_size) {
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "Request Too Large");
+ *err = 413;
+ return 0;
+ } else if (conn->request_len <= 0) {
+ if (conn->data_len > 0) {
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "Client sent malformed request");
+ *err = 400;
+ } else {
+ /* Server did not send anything -> just close the connection */
+ conn->must_close = 1;
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "Client did not send a request");
+ *err = 0;
+ }
+ return 0;
+ } else if (parse_http_message(conn->buf,
+ conn->buf_size,
+ &conn->request_info) <= 0) {
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "Bad Request");
+ *err = 400;
+ return 0;
+ } else {
+ /* Message is a valid request or response */
+ if ((cl = get_header(&conn->request_info, "Content-Length")) != NULL) {
+ /* Request/response has content length set */
+ char *endptr = NULL;
+ conn->content_len = strtoll(cl, &endptr, 10);
+ if (endptr == cl) {
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "Bad Request");
+ *err = 411;
+ return 0;
+ }
+ /* Publish the content length back to the request info. */
+ conn->request_info.content_length = conn->content_len;
+ } else if ((cl = get_header(&conn->request_info, "Transfer-Encoding"))
+ != NULL
+ && !mg_strcasecmp(cl, "chunked")) {
+ conn->is_chunked = 1;
+ } else if (!mg_strcasecmp(conn->request_info.request_method, "POST")
+ || !mg_strcasecmp(conn->request_info.request_method,
+ "PUT")) {
+ /* POST or PUT request without content length set */
+ conn->content_len = -1;
+ } else if (!mg_strncasecmp(conn->request_info.request_method,
+ "HTTP/",
+ 5)) {
+ /* Response without content length set */
+ conn->content_len = -1;
+ } else {
+ /* Other request */
+ conn->content_len = 0;
+ }
+ }
+ return 1;
+}
+
+
+int
+mg_get_response(struct mg_connection *conn,
+ char *ebuf,
+ size_t ebuf_len,
+ int timeout)
+{
+ if (conn) {
+ /* Implementation of API function for HTTP clients */
+ int err, ret;
+ struct mg_context *octx = conn->ctx;
+ struct mg_context rctx = *(conn->ctx);
+ char txt[32]; /* will not overflow */
+
+ if (timeout >= 0) {
+ mg_snprintf(conn, NULL, txt, sizeof(txt), "%i", timeout);
+ rctx.config[REQUEST_TIMEOUT] = txt;
+ set_sock_timeout(conn->client.sock, timeout);
+ } else {
+ rctx.config[REQUEST_TIMEOUT] = NULL;
+ }
+
+ conn->ctx = &rctx;
+ ret = getreq(conn, ebuf, ebuf_len, &err);
+ conn->ctx = octx;
+
+ /* TODO: 1) uri is deprecated;
+ * 2) here, ri.uri is the http response code */
+ conn->request_info.uri = conn->request_info.request_uri;
+
+ /* TODO (mid): Define proper return values - maybe return length?
+ * For the first test use <0 for error and >0 for OK */
+ return (ret == 0) ? -1 : +1;
+ }
+ return -1;
+}
+
+
+struct mg_connection *
+mg_download(const char *host,
+ int port,
+ int use_ssl,
+ char *ebuf,
+ size_t ebuf_len,
+ const char *fmt,
+ ...)
+{
+ struct mg_connection *conn;
+ va_list ap;
+ int i;
+ int reqerr;
+
+ va_start(ap, fmt);
+ ebuf[0] = '\0';
+
+ /* open a connection */
+ conn = mg_connect_client(host, port, use_ssl, ebuf, ebuf_len);
+
+ if (conn != NULL) {
+ i = mg_vprintf(conn, fmt, ap);
+ if (i <= 0) {
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ ebuf_len,
+ "%s",
+ "Error sending request");
+ } else {
+ getreq(conn, ebuf, ebuf_len, &reqerr);
+
+ /* TODO: 1) uri is deprecated;
+ * 2) here, ri.uri is the http response code */
+ conn->request_info.uri = conn->request_info.request_uri;
+ }
+ }
+
+ /* if an error occured, close the connection */
+ if (ebuf[0] != '\0' && conn != NULL) {
+ mg_close_connection(conn);
+ conn = NULL;
+ }
+
+ va_end(ap);
+ return conn;
+}
+
+
+struct websocket_client_thread_data {
+ struct mg_connection *conn;
+ mg_websocket_data_handler data_handler;
+ mg_websocket_close_handler close_handler;
+ void *callback_data;
+};
+
+
+#if defined(USE_WEBSOCKET)
+#ifdef _WIN32
+static unsigned __stdcall websocket_client_thread(void *data)
+#else
+static void *
+websocket_client_thread(void *data)
+#endif
+{
+ struct websocket_client_thread_data *cdata =
+ (struct websocket_client_thread_data *)data;
+
+ mg_set_thread_name("ws-client");
+
+ if (cdata->conn->ctx) {
+ if (cdata->conn->ctx->callbacks.init_thread) {
+ /* 3 indicates a websocket client thread */
+ /* TODO: check if conn->ctx can be set */
+ cdata->conn->ctx->callbacks.init_thread(cdata->conn->ctx, 3);
+ }
+ }
+
+ read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
+
+ DEBUG_TRACE("%s", "Websocket client thread exited\n");
+
+ if (cdata->close_handler != NULL) {
+ cdata->close_handler(cdata->conn, cdata->callback_data);
+ }
+
+ mg_free((void *)cdata);
+
+#ifdef _WIN32
+ return 0;
+#else
+ return NULL;
+#endif
+}
+#endif
+
+
+struct mg_connection *
+mg_connect_websocket_client(const char *host,
+ int port,
+ int use_ssl,
+ char *error_buffer,
+ size_t error_buffer_size,
+ const char *path,
+ const char *origin,
+ mg_websocket_data_handler data_func,
+ mg_websocket_close_handler close_func,
+ void *user_data)
+{
+ struct mg_connection *conn = NULL;
+
+#if defined(USE_WEBSOCKET)
+ struct mg_context *newctx = NULL;
+ struct websocket_client_thread_data *thread_data;
+ static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
+ static const char *handshake_req;
+
+ if (origin != NULL) {
+ handshake_req = "GET %s HTTP/1.1\r\n"
+ "Host: %s\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Key: %s\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Origin: %s\r\n"
+ "\r\n";
+ } else {
+ handshake_req = "GET %s HTTP/1.1\r\n"
+ "Host: %s\r\n"
+ "Upgrade: websocket\r\n"
+ "Connection: Upgrade\r\n"
+ "Sec-WebSocket-Key: %s\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "\r\n";
+ }
+
+ /* Establish the client connection and request upgrade */
+ conn = mg_download(host,
+ port,
+ use_ssl,
+ error_buffer,
+ error_buffer_size,
+ handshake_req,
+ path,
+ host,
+ magic,
+ origin);
+
+ /* Connection object will be null if something goes wrong */
+ if (conn == NULL || (strcmp(conn->request_info.request_uri, "101") != 0)) {
+ if (!*error_buffer) {
+ /* if there is a connection, but it did not return 101,
+ * error_buffer is not yet set */
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ error_buffer,
+ error_buffer_size,
+ "Unexpected server reply");
+ }
+ DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer);
+ if (conn != NULL) {
+ mg_free(conn);
+ conn = NULL;
+ }
+ return conn;
+ }
+
+ /* For client connections, mg_context is fake. Since we need to set a
+ * callback function, we need to create a copy and modify it. */
+ newctx = (struct mg_context *)mg_malloc(sizeof(struct mg_context));
+ memcpy(newctx, conn->ctx, sizeof(struct mg_context));
+ newctx->user_data = user_data;
+ newctx->context_type = 2; /* client context type */
+ newctx->cfg_worker_threads = 1; /* one worker thread will be created */
+ newctx->workerthreadids =
+ (pthread_t *)mg_calloc(newctx->cfg_worker_threads, sizeof(pthread_t));
+ conn->ctx = newctx;
+ thread_data = (struct websocket_client_thread_data *)
+ mg_calloc(sizeof(struct websocket_client_thread_data), 1);
+ thread_data->conn = conn;
+ thread_data->data_handler = data_func;
+ thread_data->close_handler = close_func;
+ thread_data->callback_data = NULL;
+
+ /* Start a thread to read the websocket client connection
+ * This thread will automatically stop when mg_disconnect is
+ * called on the client connection */
+ if (mg_start_thread_with_id(websocket_client_thread,
+ (void *)thread_data,
+ newctx->workerthreadids) != 0) {
+ mg_free((void *)thread_data);
+ mg_free((void *)newctx->workerthreadids);
+ mg_free((void *)newctx);
+ mg_free((void *)conn);
+ conn = NULL;
+ DEBUG_TRACE("%s",
+ "Websocket client connect thread could not be started\r\n");
+ }
+#else
+ /* Appease "unused parameter" warnings */
+ (void)host;
+ (void)port;
+ (void)use_ssl;
+ (void)error_buffer;
+ (void)error_buffer_size;
+ (void)path;
+ (void)origin;
+ (void)user_data;
+ (void)data_func;
+ (void)close_func;
+#endif
+
+ return conn;
+}
+
+
+static void
+process_new_connection(struct mg_connection *conn)
+{
+ if (conn && conn->ctx) {
+ struct mg_request_info *ri = &conn->request_info;
+ int keep_alive_enabled, keep_alive, discard_len;
+ char ebuf[100];
+ const char *hostend;
+ int reqerr, uri_type;
+
+ keep_alive_enabled =
+ !strcmp(conn->ctx->config[ENABLE_KEEP_ALIVE], "yes");
+
+ /* Important: on new connection, reset the receiving buffer. Credit
+ * goes to crule42. */
+ conn->data_len = 0;
+ do {
+ if (!getreq(conn, ebuf, sizeof(ebuf), &reqerr)) {
+ /* The request sent by the client could not be understood by
+ * the server, or it was incomplete or a timeout. Send an
+ * error message and close the connection. */
+ if (reqerr > 0) {
+ /*assert(ebuf[0] != '\0');*/
+ send_http_error(conn, reqerr, "%s", ebuf);
+ }
+ } else if (strcmp(ri->http_version, "1.0")
+ && strcmp(ri->http_version, "1.1")) {
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ sizeof(ebuf),
+ "Bad HTTP version: [%s]",
+ ri->http_version);
+ send_http_error(conn, 505, "%s", ebuf);
+ }
+
+ if (ebuf[0] == '\0') {
+ uri_type = get_uri_type(conn->request_info.request_uri);
+ switch (uri_type) {
+ case 1:
+ /* Asterisk */
+ conn->request_info.local_uri = NULL;
+ break;
+ case 2:
+ /* relative uri */
+ conn->request_info.local_uri =
+ conn->request_info.request_uri;
+ break;
+ case 3:
+ case 4:
+ /* absolute uri (with/without port) */
+ hostend = get_rel_url_at_current_server(
+ conn->request_info.request_uri, conn);
+ if (hostend) {
+ conn->request_info.local_uri = hostend;
+ } else {
+ conn->request_info.local_uri = NULL;
+ }
+ break;
+ default:
+ mg_snprintf(conn,
+ NULL, /* No truncation check for ebuf */
+ ebuf,
+ sizeof(ebuf),
+ "Invalid URI: [%s]",
+ ri->request_uri);
+ send_http_error(conn, 400, "%s", ebuf);
+ break;
+ }
+
+ /* TODO: cleanup uri, local_uri and request_uri */
+ conn->request_info.uri = conn->request_info.local_uri;
+ }
+
+ if (ebuf[0] == '\0') {
+ if (conn->request_info.local_uri) {
+ /* handle request to local server */
+ handle_request(conn);
+ if (conn->ctx->callbacks.end_request != NULL) {
+ conn->ctx->callbacks.end_request(conn,
+ conn->status_code);
+ }
+ log_access(conn);
+ } else {
+ /* TODO: handle non-local request (PROXY) */
+ conn->must_close = 1;
+ }
+ } else {
+ conn->must_close = 1;
+ }
+
+ if (ri->remote_user != NULL) {
+ mg_free((void *)ri->remote_user);
+ /* Important! When having connections with and without auth
+ * would cause double free and then crash */
+ ri->remote_user = NULL;
+ }
+
+ /* NOTE(lsm): order is important here. should_keep_alive() call
+ * is
+ * using parsed request, which will be invalid after memmove's
+ * below.
+ * Therefore, memorize should_keep_alive() result now for later
+ * use
+ * in loop exit condition. */
+ keep_alive = conn->ctx->stop_flag == 0 && keep_alive_enabled
+ && conn->content_len >= 0 && should_keep_alive(conn);
+
+ /* Discard all buffered data for this request */
+ discard_len = conn->content_len >= 0 && conn->request_len > 0
+ && conn->request_len + conn->content_len
+ < (int64_t)conn->data_len
+ ? (int)(conn->request_len + conn->content_len)
+ : conn->data_len;
+ /*assert(discard_len >= 0);*/
+ if (discard_len < 0)
+ break;
+ conn->data_len -= discard_len;
+ if (conn->data_len > 0) {
+ memmove(conn->buf,
+ conn->buf + discard_len,
+ (size_t)conn->data_len);
+ }
+
+ /* assert(conn->data_len >= 0); */
+ /* assert(conn->data_len <= conn->buf_size); */
+
+ if ((conn->data_len < 0) || (conn->data_len > conn->buf_size)) {
+ break;
+ }
+
+ } while (keep_alive);
+ }
+}
+
+
+/* Worker threads take accepted socket from the queue */
+static int
+consume_socket(struct mg_context *ctx, struct socket *sp)
+{
+#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
+ if (!ctx) {
+ return 0;
+ }
+
+ (void)pthread_mutex_lock(&ctx->thread_mutex);
+ DEBUG_TRACE("%s", "going idle");
+
+ /* If the queue is empty, wait. We're idle at this point. */
+ while (ctx->sq_head == ctx->sq_tail && ctx->stop_flag == 0) {
+ pthread_cond_wait(&ctx->sq_full, &ctx->thread_mutex);
+ }
+
+ /* If we're stopping, sq_head may be equal to sq_tail. */
+ if (ctx->sq_head > ctx->sq_tail) {
+ /* Copy socket from the queue and increment tail */
+ *sp = ctx->queue[ctx->sq_tail % QUEUE_SIZE(ctx)];
+ ctx->sq_tail++;
+
+ DEBUG_TRACE("grabbed socket %d, going busy", sp ? sp->sock : -1);
+
+ /* Wrap pointers if needed */
+ while (ctx->sq_tail > QUEUE_SIZE(ctx)) {
+ ctx->sq_tail -= QUEUE_SIZE(ctx);
+ ctx->sq_head -= QUEUE_SIZE(ctx);
+ }
+ }
+
+ (void)pthread_cond_signal(&ctx->sq_empty);
+ (void)pthread_mutex_unlock(&ctx->thread_mutex);
+
+ return !ctx->stop_flag;
+#undef QUEUE_SIZE
+}
+
+
+static void *
+worker_thread_run(void *thread_func_param)
+{
+ struct mg_context *ctx = (struct mg_context *)thread_func_param;
+ struct mg_connection *conn;
+ struct mg_workerTLS tls;
+#if defined(MG_LEGACY_INTERFACE)
+ uint32_t addr;
+#endif
+
+ mg_set_thread_name("worker");
+
+ tls.is_master = 0;
+ tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
+#endif
+
+ if (ctx->callbacks.init_thread) {
+ /* call init_thread for a worker thread (type 1) */
+ ctx->callbacks.init_thread(ctx, 1);
+ }
+
+ conn =
+ (struct mg_connection *)mg_calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);
+ if (conn == NULL) {
+ mg_cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");
+ } else {
+ pthread_setspecific(sTlsKey, &tls);
+ conn->buf_size = MAX_REQUEST_SIZE;
+ conn->buf = (char *)(conn + 1);
+ conn->ctx = ctx;
+ conn->request_info.user_data = ctx->user_data;
+ /* Allocate a mutex for this connection to allow communication both
+ * within the request handler and from elsewhere in the application
+ */
+ (void)pthread_mutex_init(&conn->mutex, &pthread_mutex_attr);
+
+ /* Call consume_socket() even when ctx->stop_flag > 0, to let it
+ * signal sq_empty condvar to wake up the master waiting in
+ * produce_socket() */
+ while (consume_socket(ctx, &conn->client)) {
+ conn->conn_birth_time = time(NULL);
+
+/* Fill in IP, port info early so even if SSL setup below fails,
+ * error handler would have the corresponding info.
+ * Thanks to Johannes Winkelmann for the patch.
+ */
+#if defined(USE_IPV6)
+ if (conn->client.rsa.sa.sa_family == AF_INET6) {
+ conn->request_info.remote_port =
+ ntohs(conn->client.rsa.sin6.sin6_port);
+ } else
+#endif
+ {
+ conn->request_info.remote_port =
+ ntohs(conn->client.rsa.sin.sin_port);
+ }
+
+ sockaddr_to_string(conn->request_info.remote_addr,
+ sizeof(conn->request_info.remote_addr),
+ &conn->client.rsa);
+
+#if defined(MG_LEGACY_INTERFACE)
+ /* This legacy interface only works for the IPv4 case */
+ addr = ntohl(conn->client.rsa.sin.sin_addr.s_addr);
+ memcpy(&conn->request_info.remote_ip, &addr, 4);
+#endif
+
+ conn->request_info.is_ssl = conn->client.is_ssl;
+
+ if (!conn->client.is_ssl
+#ifndef NO_SSL
+ || sslize(conn, conn->ctx->ssl_ctx, SSL_accept)
+#endif
+ ) {
+
+
+ process_new_connection(conn);
+ }
+
+ close_connection(conn);
+ }
+ }
+
+ /* Signal master that we're done with connection and exiting */
+ (void)pthread_mutex_lock(&ctx->thread_mutex);
+ ctx->running_worker_threads--;
+ (void)pthread_cond_signal(&ctx->thread_cond);
+ /* assert(ctx->running_worker_threads >= 0); */
+ (void)pthread_mutex_unlock(&ctx->thread_mutex);
+
+ pthread_setspecific(sTlsKey, NULL);
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ CloseHandle(tls.pthread_cond_helper_mutex);
+#endif
+ pthread_mutex_destroy(&conn->mutex);
+ mg_free(conn);
+
+ DEBUG_TRACE("%s", "exiting");
+ return NULL;
+}
+
+
+/* Threads have different return types on Windows and Unix. */
+#ifdef _WIN32
+static unsigned __stdcall worker_thread(void *thread_func_param)
+{
+ worker_thread_run(thread_func_param);
+ return 0;
+}
+#else
+static void *
+worker_thread(void *thread_func_param)
+{
+ worker_thread_run(thread_func_param);
+ return NULL;
+}
+#endif /* _WIN32 */
+
+
+/* Master thread adds accepted socket to a queue */
+static void
+produce_socket(struct mg_context *ctx, const struct socket *sp)
+{
+#define QUEUE_SIZE(ctx) ((int)(ARRAY_SIZE(ctx->queue)))
+ if (!ctx) {
+ return;
+ }
+ (void)pthread_mutex_lock(&ctx->thread_mutex);
+
+ /* If the queue is full, wait */
+ while (ctx->stop_flag == 0
+ && ctx->sq_head - ctx->sq_tail >= QUEUE_SIZE(ctx)) {
+ (void)pthread_cond_wait(&ctx->sq_empty, &ctx->thread_mutex);
+ }
+
+ if (ctx->sq_head - ctx->sq_tail < QUEUE_SIZE(ctx)) {
+ /* Copy socket to the queue and increment head */
+ ctx->queue[ctx->sq_head % QUEUE_SIZE(ctx)] = *sp;
+ ctx->sq_head++;
+ DEBUG_TRACE("queued socket %d", sp ? sp->sock : -1);
+ }
+
+ (void)pthread_cond_signal(&ctx->sq_full);
+ (void)pthread_mutex_unlock(&ctx->thread_mutex);
+#undef QUEUE_SIZE
+}
+
+
+static void
+accept_new_connection(const struct socket *listener, struct mg_context *ctx)
+{
+ struct socket so;
+ char src_addr[IP_ADDR_STR_LEN];
+ socklen_t len = sizeof(so.rsa);
+ int on = 1;
+ int timeout;
+
+ if (!listener) {
+ return;
+ }
+
+ if ((so.sock = accept(listener->sock, &so.rsa.sa, &len))
+ == INVALID_SOCKET) {
+ } else if (!check_acl(ctx, ntohl(*(uint32_t *)&so.rsa.sin.sin_addr))) {
+ sockaddr_to_string(src_addr, sizeof(src_addr), &so.rsa);
+ mg_cry(fc(ctx), "%s: %s is not allowed to connect", __func__, src_addr);
+ closesocket(so.sock);
+ so.sock = INVALID_SOCKET;
+ } else {
+ /* Put so socket structure into the queue */
+ DEBUG_TRACE("Accepted socket %d", (int)so.sock);
+ set_close_on_exec(so.sock, fc(ctx));
+ so.is_ssl = listener->is_ssl;
+ so.ssl_redir = listener->ssl_redir;
+ if (getsockname(so.sock, &so.lsa.sa, &len) != 0) {
+ mg_cry(fc(ctx),
+ "%s: getsockname() failed: %s",
+ __func__,
+ strerror(ERRNO));
+ }
+
+ /* Set TCP keep-alive. This is needed because if HTTP-level
+ * keep-alive
+ * is enabled, and client resets the connection, server won't get
+ * TCP FIN or RST and will keep the connection open forever. With
+ * TCP keep-alive, next keep-alive handshake will figure out that
+ * the client is down and will close the server end.
+ * Thanks to Igor Klopov who suggested the patch. */
+ if (setsockopt(so.sock,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ (SOCK_OPT_TYPE)&on,
+ sizeof(on)) != 0) {
+ mg_cry(fc(ctx),
+ "%s: setsockopt(SOL_SOCKET SO_KEEPALIVE) failed: %s",
+ __func__,
+ strerror(ERRNO));
+ }
+
+
+ /* Disable TCP Nagle's algorithm. Normally TCP packets are
+ * coalesced
+ * to effectively fill up the underlying IP packet payload and
+ * reduce
+ * the overhead of sending lots of small buffers. However this hurts
+ * the server's throughput (ie. operations per second) when HTTP 1.1
+ * persistent connections are used and the responses are relatively
+ * small (eg. less than 1400 bytes).
+ */
+ if ((ctx != NULL) && (ctx->config[CONFIG_TCP_NODELAY] != NULL)
+ && (!strcmp(ctx->config[CONFIG_TCP_NODELAY], "1"))) {
+ if (set_tcp_nodelay(so.sock, 1) != 0) {
+ mg_cry(fc(ctx),
+ "%s: setsockopt(IPPROTO_TCP TCP_NODELAY) failed: %s",
+ __func__,
+ strerror(ERRNO));
+ }
+ }
+
+ if (ctx && ctx->config[REQUEST_TIMEOUT]) {
+ timeout = atoi(ctx->config[REQUEST_TIMEOUT]);
+ } else {
+ timeout = -1;
+ }
+
+ /* Set socket timeout to the given value, but not more than a
+ * a certain limit (SOCKET_TIMEOUT_QUANTUM, default 10 seconds),
+ * so the server can exit after that time if requested. */
+ if ((timeout > 0) && (timeout < SOCKET_TIMEOUT_QUANTUM)) {
+ set_sock_timeout(so.sock, timeout);
+ } else {
+ set_sock_timeout(so.sock, SOCKET_TIMEOUT_QUANTUM);
+ }
+
+ produce_socket(ctx, &so);
+ }
+}
+
+
+static void
+master_thread_run(void *thread_func_param)
+{
+ struct mg_context *ctx = (struct mg_context *)thread_func_param;
+ struct mg_workerTLS tls;
+ struct pollfd *pfd;
+ unsigned int i;
+ unsigned int workerthreadcount;
+
+ if (!ctx) {
+ return;
+ }
+
+ mg_set_thread_name("master");
+
+/* Increase priority of the master thread */
+#if defined(_WIN32)
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
+#elif defined(USE_MASTER_THREAD_PRIORITY)
+ int min_prio = sched_get_priority_min(SCHED_RR);
+ int max_prio = sched_get_priority_max(SCHED_RR);
+ if ((min_prio >= 0) && (max_prio >= 0)
+ && ((USE_MASTER_THREAD_PRIORITY) <= max_prio)
+ && ((USE_MASTER_THREAD_PRIORITY) >= min_prio)) {
+ struct sched_param sched_param = {0};
+ sched_param.sched_priority = (USE_MASTER_THREAD_PRIORITY);
+ pthread_setschedparam(pthread_self(), SCHED_RR, &sched_param);
+ }
+#endif
+
+/* Initialize thread local storage */
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);
+#endif
+ tls.is_master = 1;
+ pthread_setspecific(sTlsKey, &tls);
+
+ if (ctx->callbacks.init_thread) {
+ /* Callback for the master thread (type 0) */
+ ctx->callbacks.init_thread(ctx, 0);
+ }
+
+ /* Server starts *now* */
+ ctx->start_time = time(NULL);
+
+ /* Allocate memory for the listening sockets, and start the server */
+ pfd =
+ (struct pollfd *)mg_calloc(ctx->num_listening_sockets, sizeof(pfd[0]));
+ while (pfd != NULL && ctx->stop_flag == 0) {
+ for (i = 0; i < ctx->num_listening_sockets; i++) {
+ pfd[i].fd = ctx->listening_sockets[i].sock;
+ pfd[i].events = POLLIN;
+ }
+
+ if (poll(pfd, ctx->num_listening_sockets, 200) > 0) {
+ for (i = 0; i < ctx->num_listening_sockets; i++) {
+ /* NOTE(lsm): on QNX, poll() returns POLLRDNORM after the
+ * successful poll, and POLLIN is defined as
+ * (POLLRDNORM | POLLRDBAND)
+ * Therefore, we're checking pfd[i].revents & POLLIN, not
+ * pfd[i].revents == POLLIN. */
+ if (ctx->stop_flag == 0 && (pfd[i].revents & POLLIN)) {
+ accept_new_connection(&ctx->listening_sockets[i], ctx);
+ }
+ }
+ }
+ }
+ mg_free(pfd);
+ DEBUG_TRACE("%s", "stopping workers");
+
+ /* Stop signal received: somebody called mg_stop. Quit. */
+ close_all_listening_sockets(ctx);
+
+ /* Wakeup workers that are waiting for connections to handle. */
+ pthread_cond_broadcast(&ctx->sq_full);
+
+ /* Wait until all threads finish */
+ (void)pthread_mutex_lock(&ctx->thread_mutex);
+ while (ctx->running_worker_threads > 0) {
+ (void)pthread_cond_wait(&ctx->thread_cond, &ctx->thread_mutex);
+ }
+ (void)pthread_mutex_unlock(&ctx->thread_mutex);
+
+ /* Join all worker threads to avoid leaking threads. */
+ workerthreadcount = ctx->cfg_worker_threads;
+ for (i = 0; i < workerthreadcount; i++) {
+ if (ctx->workerthreadids[i] != 0) {
+ mg_join_thread(ctx->workerthreadids[i]);
+ }
+ }
+
+#if !defined(NO_SSL)
+ if (ctx->ssl_ctx != NULL) {
+ uninitialize_ssl(ctx);
+ }
+#endif
+ DEBUG_TRACE("%s", "exiting");
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ CloseHandle(tls.pthread_cond_helper_mutex);
+#endif
+ pthread_setspecific(sTlsKey, NULL);
+
+ /* Signal mg_stop() that we're done.
+ * WARNING: This must be the very last thing this
+ * thread does, as ctx becomes invalid after this line. */
+ ctx->stop_flag = 2;
+}
+
+
+/* Threads have different return types on Windows and Unix. */
+#ifdef _WIN32
+static unsigned __stdcall master_thread(void *thread_func_param)
+{
+ master_thread_run(thread_func_param);
+ return 0;
+}
+#else
+static void *
+master_thread(void *thread_func_param)
+{
+ master_thread_run(thread_func_param);
+ return NULL;
+}
+#endif /* _WIN32 */
+
+
+static void
+free_context(struct mg_context *ctx)
+{
+ int i;
+ struct mg_handler_info *tmp_rh;
+
+ if (ctx == NULL) {
+ return;
+ }
+
+ if (ctx->callbacks.exit_context) {
+ ctx->callbacks.exit_context(ctx);
+ }
+
+ /* All threads exited, no sync is needed. Destroy thread mutex and
+ * condvars
+ */
+ (void)pthread_mutex_destroy(&ctx->thread_mutex);
+ (void)pthread_cond_destroy(&ctx->thread_cond);
+ (void)pthread_cond_destroy(&ctx->sq_empty);
+ (void)pthread_cond_destroy(&ctx->sq_full);
+
+ /* Destroy other context global data structures mutex */
+ (void)pthread_mutex_destroy(&ctx->nonce_mutex);
+
+#if defined(USE_TIMERS)
+ timers_exit(ctx);
+#endif
+
+ /* Deallocate config parameters */
+ for (i = 0; i < NUM_OPTIONS; i++) {
+ if (ctx->config[i] != NULL) {
+#if defined(_MSC_VER)
+#pragma warning(suppress : 6001)
+#endif
+ mg_free(ctx->config[i]);
+ }
+ }
+
+ /* Deallocate request handlers */
+ while (ctx->handlers) {
+ tmp_rh = ctx->handlers;
+ ctx->handlers = tmp_rh->next;
+ mg_free(tmp_rh->uri);
+ mg_free(tmp_rh);
+ }
+
+#ifndef NO_SSL
+ /* Deallocate SSL context */
+ if (ctx->ssl_ctx != NULL) {
+ SSL_CTX_free(ctx->ssl_ctx);
+ }
+#endif /* !NO_SSL */
+
+ /* Deallocate worker thread ID array */
+ if (ctx->workerthreadids != NULL) {
+ mg_free(ctx->workerthreadids);
+ }
+
+ /* Deallocate the tls variable */
+ if (mg_atomic_dec(&sTlsInit) == 0) {
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ DeleteCriticalSection(&global_log_file_lock);
+#endif /* _WIN32 && !__SYMBIAN32__ */
+#if !defined(_WIN32)
+ pthread_mutexattr_destroy(&pthread_mutex_attr);
+#endif
+
+ pthread_key_delete(sTlsKey);
+ }
+
+ /* deallocate system name string */
+ mg_free(ctx->systemName);
+
+ /* Deallocate context itself */
+ mg_free(ctx);
+}
+
+
+void
+mg_stop(struct mg_context *ctx)
+{
+ pthread_t mt;
+ if (!ctx) {
+ return;
+ }
+
+ /* We don't use a lock here. Calling mg_stop with the same ctx from
+ * two threads is not allowed. */
+ mt = ctx->masterthreadid;
+ if (mt == 0) {
+ return;
+ }
+
+ ctx->masterthreadid = 0;
+ ctx->stop_flag = 1;
+
+ /* Wait until mg_fini() stops */
+ while (ctx->stop_flag != 2) {
+ (void)mg_sleep(10);
+ }
+
+ mg_join_thread(mt);
+ free_context(ctx);
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ (void)WSACleanup();
+#endif /* _WIN32 && !__SYMBIAN32__ */
+}
+
+
+static void
+get_system_name(char **sysName)
+{
+#if defined(_WIN32)
+#if !defined(__SYMBIAN32__)
+ char name[128];
+ DWORD dwVersion = 0;
+ DWORD dwMajorVersion = 0;
+ DWORD dwMinorVersion = 0;
+ DWORD dwBuild = 0;
+
+#ifdef _MSC_VER
+#pragma warning(push)
+// GetVersion was declared deprecated
+#pragma warning(disable : 4996)
+#endif
+ dwVersion = GetVersion();
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+ dwMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
+ dwMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
+ dwBuild = ((dwVersion < 0x80000000) ? (DWORD)(HIWORD(dwVersion)) : 0);
+ (void)dwBuild;
+
+ sprintf(name,
+ "Windows %u.%u",
+ (unsigned)dwMajorVersion,
+ (unsigned)dwMinorVersion);
+ *sysName = mg_strdup(name);
+#else
+ *sysName = mg_strdup("Symbian");
+#endif
+#else
+ struct utsname name;
+ memset(&name, 0, sizeof(name));
+ uname(&name);
+ *sysName = mg_strdup(name.sysname);
+#endif
+}
+
+
+struct mg_context *
+mg_start(const struct mg_callbacks *callbacks,
+ void *user_data,
+ const char **options)
+{
+ struct mg_context *ctx;
+ const char *name, *value, *default_value;
+ int idx, ok, workerthreadcount;
+ unsigned int i;
+ void (*exit_callback)(const struct mg_context *ctx) = 0;
+
+ struct mg_workerTLS tls;
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ WSADATA data;
+ WSAStartup(MAKEWORD(2, 2), &data);
+#endif /* _WIN32 && !__SYMBIAN32__ */
+
+ /* Allocate context and initialize reasonable general case defaults. */
+ if ((ctx = (struct mg_context *)mg_calloc(1, sizeof(*ctx))) == NULL) {
+ return NULL;
+ }
+
+ /* Random number generator will initialize at the first call */
+ ctx->auth_nonce_mask =
+ (uint64_t)get_random() ^ (uint64_t)(ptrdiff_t)(options);
+
+ if (mg_atomic_inc(&sTlsInit) == 1) {
+
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ InitializeCriticalSection(&global_log_file_lock);
+#endif /* _WIN32 && !__SYMBIAN32__ */
+#if !defined(_WIN32)
+ pthread_mutexattr_init(&pthread_mutex_attr);
+ pthread_mutexattr_settype(&pthread_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
+#endif
+
+ if (0 != pthread_key_create(&sTlsKey, tls_dtor)) {
+ /* Fatal error - abort start. However, this situation should
+ * never
+ * occur in practice. */
+ mg_atomic_dec(&sTlsInit);
+ mg_cry(fc(ctx), "Cannot initialize thread local storage");
+ mg_free(ctx);
+ return NULL;
+ }
+ } else {
+ /* TODO (low): istead of sleeping, check if sTlsKey is already
+ * initialized. */
+ mg_sleep(1);
+ }
+
+ tls.is_master = -1;
+ tls.thread_idx = (unsigned)mg_atomic_inc(&thread_idx_max);
+#if defined(_WIN32) && !defined(__SYMBIAN32__)
+ tls.pthread_cond_helper_mutex = NULL;
+#endif
+ pthread_setspecific(sTlsKey, &tls);
+
+#if defined(USE_LUA)
+ lua_init_optional_libraries();
+#endif
+
+ ok = 0 == pthread_mutex_init(&ctx->thread_mutex, &pthread_mutex_attr);
+ ok &= 0 == pthread_cond_init(&ctx->thread_cond, NULL);
+ ok &= 0 == pthread_cond_init(&ctx->sq_empty, NULL);
+ ok &= 0 == pthread_cond_init(&ctx->sq_full, NULL);
+ ok &= 0 == pthread_mutex_init(&ctx->nonce_mutex, &pthread_mutex_attr);
+ if (!ok) {
+ /* Fatal error - abort start. However, this situation should never
+ * occur in practice. */
+ mg_cry(fc(ctx), "Cannot initialize thread synchronization objects");
+ mg_free(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ }
+
+ if (callbacks) {
+ ctx->callbacks = *callbacks;
+ exit_callback = callbacks->exit_context;
+ ctx->callbacks.exit_context = 0;
+ }
+ ctx->user_data = user_data;
+ ctx->handlers = NULL;
+
+#if defined(USE_LUA) && defined(USE_WEBSOCKET)
+ ctx->shared_lua_websockets = 0;
+#endif
+
+ while (options && (name = *options++) != NULL) {
+ if ((idx = get_option_index(name)) == -1) {
+ mg_cry(fc(ctx), "Invalid option: %s", name);
+ free_context(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ } else if ((value = *options++) == NULL) {
+ mg_cry(fc(ctx), "%s: option value cannot be NULL", name);
+ free_context(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ }
+ if (ctx->config[idx] != NULL) {
+ mg_cry(fc(ctx), "warning: %s: duplicate option", name);
+ mg_free(ctx->config[idx]);
+ }
+ ctx->config[idx] = mg_strdup(value);
+ DEBUG_TRACE("[%s] -> [%s]", name, value);
+ }
+
+ /* Set default value if needed */
+ for (i = 0; config_options[i].name != NULL; i++) {
+ default_value = config_options[i].default_value;
+ if (ctx->config[i] == NULL && default_value != NULL) {
+ ctx->config[i] = mg_strdup(default_value);
+ }
+ }
+
+#if defined(NO_FILES)
+ if (ctx->config[DOCUMENT_ROOT] != NULL) {
+ mg_cry(fc(ctx), "%s", "Document root must not be set");
+ free_context(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ }
+#endif
+
+ get_system_name(&ctx->systemName);
+
+ /* NOTE(lsm): order is important here. SSL certificates must
+ * be initialized before listening ports. UID must be set last. */
+ if (!set_gpass_option(ctx) ||
+#if !defined(NO_SSL)
+ !set_ssl_option(ctx) ||
+#endif
+ !set_ports_option(ctx) ||
+#if !defined(_WIN32)
+ !set_uid_option(ctx) ||
+#endif
+ !set_acl_option(ctx)) {
+ free_context(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ }
+
+#if !defined(_WIN32) && !defined(__SYMBIAN32__)
+ /* Ignore SIGPIPE signal, so if browser cancels the request, it
+ * won't kill the whole process. */
+ (void)signal(SIGPIPE, SIG_IGN);
+#endif /* !_WIN32 && !__SYMBIAN32__ */
+
+ workerthreadcount = atoi(ctx->config[NUM_THREADS]);
+
+ if (workerthreadcount > MAX_WORKER_THREADS) {
+ mg_cry(fc(ctx), "Too many worker threads");
+ free_context(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ }
+
+ if (workerthreadcount > 0) {
+ ctx->cfg_worker_threads = ((unsigned int)(workerthreadcount));
+ ctx->workerthreadids =
+ (pthread_t *)mg_calloc(ctx->cfg_worker_threads, sizeof(pthread_t));
+ if (ctx->workerthreadids == NULL) {
+ mg_cry(fc(ctx), "Not enough memory for worker thread ID array");
+ free_context(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ }
+ }
+
+#if defined(USE_TIMERS)
+ if (timers_init(ctx) != 0) {
+ mg_cry(fc(ctx), "Error creating timers");
+ free_context(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ }
+#endif
+
+ /* Context has been created - init user libraries */
+ if (ctx->callbacks.init_context) {
+ ctx->callbacks.init_context(ctx);
+ }
+ ctx->callbacks.exit_context = exit_callback;
+ ctx->context_type = 1; /* server context */
+
+ /* Start master (listening) thread */
+ mg_start_thread_with_id(master_thread, ctx, &ctx->masterthreadid);
+
+ /* Start worker threads */
+ for (i = 0; i < ctx->cfg_worker_threads; i++) {
+ (void)pthread_mutex_lock(&ctx->thread_mutex);
+ ctx->running_worker_threads++;
+ (void)pthread_mutex_unlock(&ctx->thread_mutex);
+ if (mg_start_thread_with_id(worker_thread,
+ ctx,
+ &ctx->workerthreadids[i]) != 0) {
+ (void)pthread_mutex_lock(&ctx->thread_mutex);
+ ctx->running_worker_threads--;
+ (void)pthread_mutex_unlock(&ctx->thread_mutex);
+ if (i > 0) {
+ mg_cry(fc(ctx),
+ "Cannot start worker thread %i: error %ld",
+ i + 1,
+ (long)ERRNO);
+ } else {
+ mg_cry(fc(ctx),
+ "Cannot create threads: error %ld",
+ (long)ERRNO);
+ free_context(ctx);
+ pthread_setspecific(sTlsKey, NULL);
+ return NULL;
+ }
+ break;
+ }
+ }
+
+ pthread_setspecific(sTlsKey, NULL);
+ return ctx;
+}
+
+
+/* Feature check API function */
+unsigned
+mg_check_feature(unsigned feature)
+{
+ static const unsigned feature_set = 0
+/* Set bits for available features according to API documentation.
+ * This bit mask is created at compile time, according to the active
+ * preprocessor defines. It is a single const value at runtime. */
+#if !defined(NO_FILES)
+ | 0x0001u
+#endif
+#if !defined(NO_SSL)
+ | 0x0002u
+#endif
+#if !defined(NO_CGI)
+ | 0x0004u
+#endif
+#if defined(USE_IPV6)
+ | 0x0008u
+#endif
+#if defined(USE_WEBSOCKET)
+ | 0x0010u
+#endif
+#if defined(USE_LUA)
+ | 0x0020u
+#endif
+#if defined(USE_DUKTAPE)
+ | 0x0040u
+#endif
+#if !defined(NO_CACHING)
+ | 0x0080u
+#endif
+
+/* Set some extra bits not defined in the API documentation.
+ * These bits may change without further notice. */
+#if defined(MG_LEGACY_INTERFACE)
+ | 0x8000u
+#endif
+#if defined(MEMORY_DEBUGGING)
+ | 0x0100u
+#endif
+#if defined(USE_TIMERS)
+ | 0x0200u
+#endif
+#if !defined(NO_NONCE_CHECK)
+ | 0x0400u
+#endif
+#if !defined(NO_POPEN)
+ | 0x0800u
+#endif
+ ;
+ return (feature & feature_set);
+}
--- /dev/null
+/* Copyright (c) 2013-2016 the Civetweb developers
+ * Copyright (c) 2004-2013 Sergey Lyubka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef CIVETWEB_HEADER_INCLUDED
+#define CIVETWEB_HEADER_INCLUDED
+
+#define CIVETWEB_VERSION "1.8"
+
+#ifndef CIVETWEB_API
+#if defined(_WIN32)
+#if defined(CIVETWEB_DLL_EXPORTS)
+#define CIVETWEB_API __declspec(dllexport)
+#elif defined(CIVETWEB_DLL_IMPORTS)
+#define CIVETWEB_API __declspec(dllimport)
+#else
+#define CIVETWEB_API
+#endif
+#elif __GNUC__ >= 4
+#define CIVETWEB_API __attribute__((visibility("default")))
+#else
+#define CIVETWEB_API
+#endif
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+struct mg_context; /* Handle for the HTTP service itself */
+struct mg_connection; /* Handle for the individual connection */
+
+
+/* This structure contains information about the HTTP request. */
+struct mg_request_info {
+ const char *request_method; /* "GET", "POST", etc */
+ const char *request_uri; /* URL-decoded URI (absolute or relative,
+ * as in the request) */
+ const char *local_uri; /* URL-decoded URI (relative). Can be NULL
+ * if the request_uri does not address a
+ * resource at the server host. */
+ const char *uri; /* Deprecated: use local_uri instead */
+ const char *http_version; /* E.g. "1.0", "1.1" */
+ const char *query_string; /* URL part after '?', not including '?', or
+ NULL */
+ const char *remote_user; /* Authenticated user, or NULL if no auth
+ used */
+ char remote_addr[48]; /* Client's IP address as a string. */
+
+#if defined(MG_LEGACY_INTERFACE)
+ long remote_ip; /* Client's IP address. Deprecated: use remote_addr instead
+ */
+#endif
+
+ long long content_length; /* Length (in bytes) of the request body,
+ can be -1 if no length was given. */
+ int remote_port; /* Client's port */
+ int is_ssl; /* 1 if SSL-ed, 0 if not */
+ void *user_data; /* User data pointer passed to mg_start() */
+ void *conn_data; /* Connection-specific user data */
+
+ int num_headers; /* Number of HTTP headers */
+ struct mg_header {
+ const char *name; /* HTTP header name */
+ const char *value; /* HTTP header value */
+ } http_headers[64]; /* Maximum 64 headers */
+};
+
+
+/* This structure needs to be passed to mg_start(), to let civetweb know
+ which callbacks to invoke. For a detailed description, see
+ https://github.com/civetweb/civetweb/blob/master/docs/UserManual.md */
+struct mg_callbacks {
+ /* Called when civetweb has received new HTTP request.
+ If the callback returns one, it must process the request
+ by sending valid HTTP headers and a body. Civetweb will not do
+ any further processing. Otherwise it must return zero.
+ Note that since V1.7 the "begin_request" function is called
+ before an authorization check. If an authorization check is
+ required, use a request_handler instead.
+ Return value:
+ 0: civetweb will process the request itself. In this case,
+ the callback must not send any data to the client.
+ 1-999: callback already processed the request. Civetweb will
+ not send any data after the callback returned. The
+ return code is stored as a HTTP status code for the
+ access log. */
+ int (*begin_request)(struct mg_connection *);
+
+ /* Called when civetweb has finished processing request. */
+ void (*end_request)(const struct mg_connection *, int reply_status_code);
+
+ /* Called when civetweb is about to log a message. If callback returns
+ non-zero, civetweb does not log anything. */
+ int (*log_message)(const struct mg_connection *, const char *message);
+
+ /* Called when civetweb is about to log access. If callback returns
+ non-zero, civetweb does not log anything. */
+ int (*log_access)(const struct mg_connection *, const char *message);
+
+ /* Called when civetweb initializes SSL library.
+ Parameters:
+ user_data: parameter user_data passed when starting the server.
+ Return value:
+ 0: civetweb will set up the SSL certificate.
+ 1: civetweb assumes the callback already set up the certificate.
+ -1: initializing ssl fails. */
+ int (*init_ssl)(void *ssl_context, void *user_data);
+
+#if defined(MG_LEGACY_INTERFACE)
+ /* Called when websocket request is received, before websocket handshake.
+ Return value:
+ 0: civetweb proceeds with websocket handshake.
+ 1: connection is closed immediately.
+ This callback is deprecated: Use mg_set_websocket_handler instead. */
+ int (*websocket_connect)(const struct mg_connection *);
+
+ /* Called when websocket handshake is successfully completed, and
+ connection is ready for data exchange.
+ This callback is deprecated: Use mg_set_websocket_handler instead. */
+ void (*websocket_ready)(struct mg_connection *);
+
+ /* Called when data frame has been received from the client.
+ Parameters:
+ bits: first byte of the websocket frame, see websocket RFC at
+ http://tools.ietf.org/html/rfc6455, section 5.2
+ data, data_len: payload, with mask (if any) already applied.
+ Return value:
+ 1: keep this websocket connection open.
+ 0: close this websocket connection.
+ This callback is deprecated: Use mg_set_websocket_handler instead. */
+ int (*websocket_data)(struct mg_connection *,
+ int bits,
+ char *data,
+ size_t data_len);
+#endif /* MG_LEGACY_INTERFACE */
+
+ /* Called when civetweb is closing a connection. The per-context mutex is
+ locked when this is invoked. This is primarily useful for noting when
+ a websocket is closing and removing it from any application-maintained
+ list of clients.
+ Using this callback for websocket connections is deprecated: Use
+ mg_set_websocket_handler instead. */
+ void (*connection_close)(const struct mg_connection *);
+
+ /* Called when civetweb tries to open a file. Used to intercept file open
+ calls, and serve file data from memory instead.
+ Parameters:
+ path: Full path to the file to open.
+ data_len: Placeholder for the file size, if file is served from
+ memory.
+ Return value:
+ NULL: do not serve file from memory, proceed with normal file open.
+ non-NULL: pointer to the file contents in memory. data_len must be
+ initilized with the size of the memory block. */
+ const char *(*open_file)(const struct mg_connection *,
+ const char *path,
+ size_t *data_len);
+
+ /* Called when civetweb is about to serve Lua server page, if
+ Lua support is enabled.
+ Parameters:
+ lua_context: "lua_State *" pointer. */
+ void (*init_lua)(const struct mg_connection *, void *lua_context);
+
+#if defined(MG_LEGACY_INTERFACE)
+ /* Called when civetweb has uploaded a file to a temporary directory as a
+ result of mg_upload() call.
+ Note that mg_upload is deprecated. Use mg_handle_form_request instead.
+ Parameters:
+ file_name: full path name to the uploaded file. */
+ void (*upload)(struct mg_connection *, const char *file_name);
+#endif
+
+ /* Called when civetweb is about to send HTTP error to the client.
+ Implementing this callback allows to create custom error pages.
+ Parameters:
+ status: HTTP error status code.
+ Return value:
+ 1: run civetweb error handler.
+ 0: callback already handled the error. */
+ int (*http_error)(struct mg_connection *, int status);
+
+ /* Called after civetweb context has been created, before requests
+ are processed.
+ Parameters:
+ ctx: context handle */
+ void (*init_context)(const struct mg_context *ctx);
+
+ /* Called when a new worker thread is initialized.
+ Parameters:
+ ctx: context handle
+ thread_type:
+ 0 indicates the master thread
+ 1 indicates a worker thread handling client connections
+ 2 indicates an internal helper thread (timer thread)
+ */
+ void (*init_thread)(const struct mg_context *ctx, int thread_type);
+
+ /* Called when civetweb context is deleted.
+ Parameters:
+ ctx: context handle */
+ void (*exit_context)(const struct mg_context *ctx);
+};
+
+
+/* Start web server.
+
+ Parameters:
+ callbacks: mg_callbacks structure with user-defined callbacks.
+ options: NULL terminated list of option_name, option_value pairs that
+ specify Civetweb configuration parameters.
+
+ Side-effects: on UNIX, ignores SIGCHLD and SIGPIPE signals. If custom
+ processing is required for these, signal handlers must be set up
+ after calling mg_start().
+
+
+ Example:
+ const char *options[] = {
+ "document_root", "/var/www",
+ "listening_ports", "80,443s",
+ NULL
+ };
+ struct mg_context *ctx = mg_start(&my_func, NULL, options);
+
+ Refer to https://github.com/civetweb/civetweb/blob/master/docs/UserManual.md
+ for the list of valid option and their possible values.
+
+ Return:
+ web server context, or NULL on error. */
+CIVETWEB_API struct mg_context *mg_start(const struct mg_callbacks *callbacks,
+ void *user_data,
+ const char **configuration_options);
+
+
+/* Stop the web server.
+
+ Must be called last, when an application wants to stop the web server and
+ release all associated resources. This function blocks until all Civetweb
+ threads are stopped. Context pointer becomes invalid. */
+CIVETWEB_API void mg_stop(struct mg_context *);
+
+
+/* mg_request_handler
+
+ Called when a new request comes in. This callback is URI based
+ and configured with mg_set_request_handler().
+
+ Parameters:
+ conn: current connection information.
+ cbdata: the callback data configured with mg_set_request_handler().
+ Returns:
+ 0: the handler could not handle the request, so fall through.
+ 1 - 999: the handler processed the request. The return code is
+ stored as a HTTP status code for the access log. */
+typedef int (*mg_request_handler)(struct mg_connection *conn, void *cbdata);
+
+
+/* mg_set_request_handler
+
+ Sets or removes a URI mapping for a request handler.
+ This function uses mg_lock_context internally.
+
+ URI's are ordered and prefixed URI's are supported. For example,
+ consider two URIs: /a/b and /a
+ /a matches /a
+ /a/b matches /a/b
+ /a/c matches /a
+
+ Parameters:
+ ctx: server context
+ uri: the URI (exact or pattern) for the handler
+ handler: the callback handler to use when the URI is requested.
+ If NULL, an already registered handler for this URI will be
+ removed.
+ The URI used to remove a handler must match exactly the one used
+ to
+ register it (not only a pattern match).
+ cbdata: the callback data to give to the handler when it is called. */
+CIVETWEB_API void mg_set_request_handler(struct mg_context *ctx,
+ const char *uri,
+ mg_request_handler handler,
+ void *cbdata);
+
+
+/* Callback types for websocket handlers in C/C++.
+
+ mg_websocket_connect_handler
+ Is called when the client intends to establish a websocket connection,
+ before websocket handshake.
+ Return value:
+ 0: civetweb proceeds with websocket handshake.
+ 1: connection is closed immediately.
+
+ mg_websocket_ready_handler
+ Is called when websocket handshake is successfully completed, and
+ connection is ready for data exchange.
+
+ mg_websocket_data_handler
+ Is called when a data frame has been received from the client.
+ Parameters:
+ bits: first byte of the websocket frame, see websocket RFC at
+ http://tools.ietf.org/html/rfc6455, section 5.2
+ data, data_len: payload, with mask (if any) already applied.
+ Return value:
+ 1: keep this websocket connection open.
+ 0: close this websocket connection.
+
+ mg_connection_close_handler
+ Is called, when the connection is closed.*/
+typedef int (*mg_websocket_connect_handler)(const struct mg_connection *,
+ void *);
+typedef void (*mg_websocket_ready_handler)(struct mg_connection *, void *);
+typedef int (*mg_websocket_data_handler)(struct mg_connection *,
+ int,
+ char *,
+ size_t,
+ void *);
+typedef void (*mg_websocket_close_handler)(const struct mg_connection *,
+ void *);
+
+
+/* mg_set_websocket_handler
+
+ Set or remove handler functions for websocket connections.
+ This function works similar to mg_set_request_handler - see there. */
+CIVETWEB_API void
+mg_set_websocket_handler(struct mg_context *ctx,
+ const char *uri,
+ mg_websocket_connect_handler connect_handler,
+ mg_websocket_ready_handler ready_handler,
+ mg_websocket_data_handler data_handler,
+ mg_websocket_close_handler close_handler,
+ void *cbdata);
+
+
+/* mg_authorization_handler
+
+ Some description here
+
+ Parameters:
+ conn: current connection information.
+ cbdata: the callback data configured with mg_set_request_handler().
+ Returns:
+ 0: access denied
+ 1: access granted
+ */
+typedef int (*mg_authorization_handler)(struct mg_connection *conn,
+ void *cbdata);
+
+
+/* mg_set_auth_handler
+
+ Sets or removes a URI mapping for an authorization handler.
+ This function works similar to mg_set_request_handler - see there. */
+CIVETWEB_API void mg_set_auth_handler(struct mg_context *ctx,
+ const char *uri,
+ mg_authorization_handler handler,
+ void *cbdata);
+
+
+/* Get the value of particular configuration parameter.
+ The value returned is read-only. Civetweb does not allow changing
+ configuration at run time.
+ If given parameter name is not valid, NULL is returned. For valid
+ names, return value is guaranteed to be non-NULL. If parameter is not
+ set, zero-length string is returned. */
+CIVETWEB_API const char *mg_get_option(const struct mg_context *ctx,
+ const char *name);
+
+
+/* Get context from connection. */
+CIVETWEB_API struct mg_context *
+mg_get_context(const struct mg_connection *conn);
+
+
+/* Get user data passed to mg_start from context. */
+CIVETWEB_API void *mg_get_user_data(const struct mg_context *ctx);
+
+
+/* Set user data for the current connection. */
+CIVETWEB_API void mg_set_user_connection_data(struct mg_connection *conn,
+ void *data);
+
+
+/* Get user data set for the current connection. */
+CIVETWEB_API void *
+mg_get_user_connection_data(const struct mg_connection *conn);
+
+
+#if defined(MG_LEGACY_INTERFACE)
+/* Return array of strings that represent valid configuration options.
+ For each option, option name and default value is returned, i.e. the
+ number of entries in the array equals to number_of_options x 2.
+ Array is NULL terminated. */
+/* Deprecated: Use mg_get_valid_options instead. */
+CIVETWEB_API const char **mg_get_valid_option_names(void);
+#endif
+
+
+struct mg_option {
+ const char *name;
+ int type;
+ const char *default_value;
+};
+
+
+enum {
+ CONFIG_TYPE_UNKNOWN = 0x0,
+ CONFIG_TYPE_NUMBER = 0x1,
+ CONFIG_TYPE_STRING = 0x2,
+ CONFIG_TYPE_FILE = 0x3,
+ CONFIG_TYPE_DIRECTORY = 0x4,
+ CONFIG_TYPE_BOOLEAN = 0x5,
+ CONFIG_TYPE_EXT_PATTERN = 0x6
+};
+
+
+/* Return array of struct mg_option, representing all valid configuration
+ options of civetweb.c.
+ The array is terminated by a NULL name option. */
+CIVETWEB_API const struct mg_option *mg_get_valid_options(void);
+
+
+struct mg_server_ports {
+ int protocol; /* 1 = IPv4, 2 = IPv6, 3 = both */
+ int port; /* port number */
+ int is_ssl; /* https port: 0 = no, 1 = yes */
+ int is_redirect; /* redirect all requests: 0 = no, 1 = yes */
+ int _reserved1;
+ int _reserved2;
+ int _reserved3;
+ int _reserved4;
+};
+
+
+/* Get the list of ports that civetweb is listening on.
+ The parameter size is the size of the ports array in elements.
+ The caller is responsibility to allocate the required memory.
+ This function returns the number of struct mg_server_ports elements
+ filled in, or <0 in case of an error. */
+CIVETWEB_API int mg_get_server_ports(const struct mg_context *ctx,
+ int size,
+ struct mg_server_ports *ports);
+
+
+/* Deprecated: Use mg_get_server_ports instead. */
+CIVETWEB_API size_t
+mg_get_ports(const struct mg_context *ctx, size_t size, int *ports, int *ssl);
+
+
+/* Add, edit or delete the entry in the passwords file.
+
+ This function allows an application to manipulate .htpasswd files on the
+ fly by adding, deleting and changing user records. This is one of the
+ several ways of implementing authentication on the server side. For another,
+ cookie-based way please refer to the examples/chat in the source tree.
+
+ If password is not NULL, entry is added (or modified if already exists).
+ If password is NULL, entry is deleted.
+
+ Return:
+ 1 on success, 0 on error. */
+CIVETWEB_API int mg_modify_passwords_file(const char *passwords_file_name,
+ const char *domain,
+ const char *user,
+ const char *password);
+
+
+/* Return information associated with the request. */
+CIVETWEB_API const struct mg_request_info *
+mg_get_request_info(const struct mg_connection *);
+
+
+/* Send data to the client.
+ Return:
+ 0 when the connection has been closed
+ -1 on error
+ >0 number of bytes written on success */
+CIVETWEB_API int mg_write(struct mg_connection *, const void *buf, size_t len);
+
+
+/* Send data to a websocket client wrapped in a websocket frame. Uses
+ mg_lock_connection to ensure that the transmission is not interrupted,
+ i.e., when the application is proactively communicating and responding to
+ a request simultaneously.
+
+ Send data to a websocket client wrapped in a websocket frame.
+ This function is available when civetweb is compiled with -DUSE_WEBSOCKET
+
+ Return:
+ 0 when the connection has been closed
+ -1 on error
+ >0 number of bytes written on success */
+CIVETWEB_API int mg_websocket_write(struct mg_connection *conn,
+ int opcode,
+ const char *data,
+ size_t data_len);
+
+
+/* Send data to a websocket server wrapped in a masked websocket frame. Uses
+ mg_lock_connection to ensure that the transmission is not interrupted,
+ i.e., when the application is proactively communicating and responding to
+ a request simultaneously.
+
+ Send data to a websocket server wrapped in a masked websocket frame.
+ This function is available when civetweb is compiled with -DUSE_WEBSOCKET
+
+ Return:
+ 0 when the connection has been closed
+ -1 on error
+ >0 number of bytes written on success */
+CIVETWEB_API int mg_websocket_client_write(struct mg_connection *conn,
+ int opcode,
+ const char *data,
+ size_t data_len);
+
+
+/* Blocks until unique access is obtained to this connection. Intended for use
+ with websockets only.
+ Invoke this before mg_write or mg_printf when communicating with a
+ websocket if your code has server-initiated communication as well as
+ communication in direct response to a message. */
+CIVETWEB_API void mg_lock_connection(struct mg_connection *conn);
+CIVETWEB_API void mg_unlock_connection(struct mg_connection *conn);
+
+
+#if defined(MG_LEGACY_INTERFACE)
+#define mg_lock mg_lock_connection
+#define mg_unlock mg_unlock_connection
+#endif
+
+
+/* Lock server context. This lock may be used to protect resources
+ that are shared between different connection/worker threads. */
+CIVETWEB_API void mg_lock_context(struct mg_context *ctx);
+CIVETWEB_API void mg_unlock_context(struct mg_context *ctx);
+
+
+/* Opcodes, from http://tools.ietf.org/html/rfc6455 */
+enum {
+ WEBSOCKET_OPCODE_CONTINUATION = 0x0,
+ WEBSOCKET_OPCODE_TEXT = 0x1,
+ WEBSOCKET_OPCODE_BINARY = 0x2,
+ WEBSOCKET_OPCODE_CONNECTION_CLOSE = 0x8,
+ WEBSOCKET_OPCODE_PING = 0x9,
+ WEBSOCKET_OPCODE_PONG = 0xa
+};
+
+
+/* Macros for enabling compiler-specific checks for printf-like arguments. */
+#undef PRINTF_FORMAT_STRING
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#include <sal.h>
+#if defined(_MSC_VER) && _MSC_VER > 1400
+#define PRINTF_FORMAT_STRING(s) _Printf_format_string_ s
+#else
+#define PRINTF_FORMAT_STRING(s) __format_string s
+#endif
+#else
+#define PRINTF_FORMAT_STRING(s) s
+#endif
+
+#ifdef __GNUC__
+#define PRINTF_ARGS(x, y) __attribute__((format(printf, x, y)))
+#else
+#define PRINTF_ARGS(x, y)
+#endif
+
+
+/* Send data to the client using printf() semantics.
+ Works exactly like mg_write(), but allows to do message formatting. */
+CIVETWEB_API int mg_printf(struct mg_connection *,
+ PRINTF_FORMAT_STRING(const char *fmt),
+ ...) PRINTF_ARGS(2, 3);
+
+
+/* Send contents of the entire file together with HTTP headers. */
+CIVETWEB_API void mg_send_file(struct mg_connection *conn, const char *path);
+
+/* Send contents of the entire file together with HTTP headers.
+ Parameters:
+ conn: Current connection information.
+ path: Full path to the file to send.
+ mime_type: Content-Type for file. NULL will cause the type to be
+ looked up by the file extension.
+*/
+CIVETWEB_API void mg_send_mime_file(struct mg_connection *conn,
+ const char *path,
+ const char *mime_type);
+
+/* Store body data into a file. */
+CIVETWEB_API long long mg_store_body(struct mg_connection *conn,
+ const char *path);
+/* Read entire request body and stor it in a file "path".
+ Return:
+ < 0 Error
+ >= 0 Number of bytes stored in file "path".
+*/
+
+
+/* Read data from the remote end, return number of bytes read.
+ Return:
+ 0 connection has been closed by peer. No more data could be read.
+ < 0 read error. No more data could be read from the connection.
+ > 0 number of bytes read into the buffer. */
+CIVETWEB_API int mg_read(struct mg_connection *, void *buf, size_t len);
+
+
+/* Get the value of particular HTTP header.
+
+ This is a helper function. It traverses request_info->http_headers array,
+ and if the header is present in the array, returns its value. If it is
+ not present, NULL is returned. */
+CIVETWEB_API const char *mg_get_header(const struct mg_connection *,
+ const char *name);
+
+
+/* Get a value of particular form variable.
+
+ Parameters:
+ data: pointer to form-uri-encoded buffer. This could be either POST data,
+ or request_info.query_string.
+ data_len: length of the encoded data.
+ var_name: variable name to decode from the buffer
+ dst: destination buffer for the decoded variable
+ dst_len: length of the destination buffer
+
+ Return:
+ On success, length of the decoded variable.
+ On error:
+ -1 (variable not found).
+ -2 (destination buffer is NULL, zero length or too small to hold the
+ decoded variable).
+
+ Destination buffer is guaranteed to be '\0' - terminated if it is not
+ NULL or zero length. */
+CIVETWEB_API int mg_get_var(const char *data,
+ size_t data_len,
+ const char *var_name,
+ char *dst,
+ size_t dst_len);
+
+
+/* Get a value of particular form variable.
+
+ Parameters:
+ data: pointer to form-uri-encoded buffer. This could be either POST data,
+ or request_info.query_string.
+ data_len: length of the encoded data.
+ var_name: variable name to decode from the buffer
+ dst: destination buffer for the decoded variable
+ dst_len: length of the destination buffer
+ occurrence: which occurrence of the variable, 0 is the first, 1 the
+ second...
+ this makes it possible to parse a query like
+ b=x&a=y&a=z which will have occurrence values b:0, a:0 and a:1
+
+ Return:
+ On success, length of the decoded variable.
+ On error:
+ -1 (variable not found).
+ -2 (destination buffer is NULL, zero length or too small to hold the
+ decoded variable).
+
+ Destination buffer is guaranteed to be '\0' - terminated if it is not
+ NULL or zero length. */
+CIVETWEB_API int mg_get_var2(const char *data,
+ size_t data_len,
+ const char *var_name,
+ char *dst,
+ size_t dst_len,
+ size_t occurrence);
+
+
+/* Fetch value of certain cookie variable into the destination buffer.
+
+ Destination buffer is guaranteed to be '\0' - terminated. In case of
+ failure, dst[0] == '\0'. Note that RFC allows many occurrences of the same
+ parameter. This function returns only first occurrence.
+
+ Return:
+ On success, value length.
+ On error:
+ -1 (either "Cookie:" header is not present at all or the requested
+ parameter is not found).
+ -2 (destination buffer is NULL, zero length or too small to hold the
+ value). */
+CIVETWEB_API int mg_get_cookie(const char *cookie,
+ const char *var_name,
+ char *buf,
+ size_t buf_len);
+
+
+/* Download data from the remote web server.
+ host: host name to connect to, e.g. "foo.com", or "10.12.40.1".
+ port: port number, e.g. 80.
+ use_ssl: wether to use SSL connection.
+ error_buffer, error_buffer_size: error message placeholder.
+ request_fmt,...: HTTP request.
+ Return:
+ On success, valid pointer to the new connection, suitable for mg_read().
+ On error, NULL. error_buffer contains error message.
+ Example:
+ char ebuf[100];
+ struct mg_connection *conn;
+ conn = mg_download("google.com", 80, 0, ebuf, sizeof(ebuf),
+ "%s", "GET / HTTP/1.0\r\nHost: google.com\r\n\r\n");
+ */
+CIVETWEB_API struct mg_connection *
+mg_download(const char *host,
+ int port,
+ int use_ssl,
+ char *error_buffer,
+ size_t error_buffer_size,
+ PRINTF_FORMAT_STRING(const char *request_fmt),
+ ...) PRINTF_ARGS(6, 7);
+
+
+/* Close the connection opened by mg_download(). */
+CIVETWEB_API void mg_close_connection(struct mg_connection *conn);
+
+
+#if defined(MG_LEGACY_INTERFACE)
+/* File upload functionality. Each uploaded file gets saved into a temporary
+ file and MG_UPLOAD event is sent.
+ Return number of uploaded files.
+ Deprecated: Use mg_handle_form_request instead. */
+CIVETWEB_API int mg_upload(struct mg_connection *conn,
+ const char *destination_dir);
+#endif
+
+
+/* This structure contains callback functions for handling form fields.
+ It is used as an argument to mg_handle_form_request. */
+struct mg_form_data_handler {
+ /* This callback function is called, if a new field has been found.
+ * The return value of this callback is used to define how the field
+ * should be processed.
+ *
+ * Parameters:
+ * key: Name of the field ("name" property of the HTML input field).
+ * filename: Name of a file to upload, at the client computer.
+ * Only set for input fields of type "file", otherwise NULL.
+ * path: Output parameter: File name (incl. path) to store the file
+ * at the server computer. Only used if FORM_FIELD_STORAGE_STORE
+ * is returned by this callback. Existing files will be
+ * overwritten.
+ * pathlen: Length of the buffer for path.
+ * user_data: Value of the member user_data of mg_form_data_handler
+ *
+ * Return value:
+ * The callback must return the intended storage for this field
+ * (See FORM_FIELD_STORAGE_*).
+ */
+ int (*field_found)(const char *key,
+ const char *filename,
+ char *path,
+ size_t pathlen,
+ void *user_data);
+
+ /* If the "field_found" callback returned FORM_FIELD_STORAGE_GET,
+ * this callback will receive the field data.
+ *
+ * Parameters:
+ * key: Name of the field ("name" property of the HTML input field).
+ * value: Value of the input field.
+ * user_data: Value of the member user_data of mg_form_data_handler
+ *
+ * Return value:
+ * TODO: Needs to be defined.
+ */
+ int (*field_get)(const char *key,
+ const char *value,
+ size_t valuelen,
+ void *user_data);
+
+ /* If the "field_found" callback returned FORM_FIELD_STORAGE_STORE,
+ * the data will be stored into a file. If the file has been written
+ * successfully, this callback will be called. This callback will
+ * not be called for only partially uploaded files. The
+ * mg_handle_form_request function will either store the file completely
+ * and call this callback, or it will remove any partial content and
+ * not call this callback function.
+ *
+ * Parameters:
+ * path: Path of the file stored at the server.
+ * file_size: Size of the stored file in bytes.
+ * user_data: Value of the member user_data of mg_form_data_handler
+ *
+ * Return value:
+ * TODO: Needs to be defined.
+ */
+ int (*field_store)(const char *path, long long file_size, void *user_data);
+
+ /* User supplied argument, passed to all callback functions. */
+ void *user_data;
+};
+
+
+/* Return values definition for the "field_found" callback in
+ * mg_form_data_handler. */
+enum {
+ /* Skip this field (neither get nor store it). Continue with the
+ * next field. */
+ FORM_FIELD_STORAGE_SKIP = 0x0,
+ /* Get the field value. */
+ FORM_FIELD_STORAGE_GET = 0x1,
+ /* Store the field value into a file. */
+ FORM_FIELD_STORAGE_STORE = 0x2,
+ /* Stop parsing this request. Skip the remaining fields. */
+ FORM_FIELD_STORAGE_ABORT = 0x10
+};
+
+
+/* Process form data.
+ * Returns the number of fields handled, or < 0 in case of an error.
+ * Note: It is possible that several fields are already handled successfully
+ * (e.g., stored into files), before the request handling is stopped with an
+ * error. In this case a number < 0 is returned as well.
+ * In any case, it is the duty of the caller to remove files once they are
+ * no longer required. */
+CIVETWEB_API int mg_handle_form_request(struct mg_connection *conn,
+ struct mg_form_data_handler *fdh);
+
+
+/* Convenience function -- create detached thread.
+ Return: 0 on success, non-0 on error. */
+typedef void *(*mg_thread_func_t)(void *);
+CIVETWEB_API int mg_start_thread(mg_thread_func_t f, void *p);
+
+
+/* Return builtin mime type for the given file name.
+ For unrecognized extensions, "text/plain" is returned. */
+CIVETWEB_API const char *mg_get_builtin_mime_type(const char *file_name);
+
+
+/* Get text representation of HTTP status code. */
+CIVETWEB_API const char *mg_get_response_code_text(struct mg_connection *conn,
+ int response_code);
+
+
+/* Return CivetWeb version. */
+CIVETWEB_API const char *mg_version(void);
+
+
+/* URL-decode input buffer into destination buffer.
+ 0-terminate the destination buffer.
+ form-url-encoded data differs from URI encoding in a way that it
+ uses '+' as character for space, see RFC 1866 section 8.2.1
+ http://ftp.ics.uci.edu/pub/ietf/html/rfc1866.txt
+ Return: length of the decoded data, or -1 if dst buffer is too small. */
+CIVETWEB_API int mg_url_decode(const char *src,
+ int src_len,
+ char *dst,
+ int dst_len,
+ int is_form_url_encoded);
+
+
+/* URL-encode input buffer into destination buffer.
+ returns the length of the resulting buffer or -1
+ is the buffer is too small. */
+CIVETWEB_API int mg_url_encode(const char *src, char *dst, size_t dst_len);
+
+
+/* MD5 hash given strings.
+ Buffer 'buf' must be 33 bytes long. Varargs is a NULL terminated list of
+ ASCIIz strings. When function returns, buf will contain human-readable
+ MD5 hash. Example:
+ char buf[33];
+ mg_md5(buf, "aa", "bb", NULL); */
+CIVETWEB_API char *mg_md5(char buf[33], ...);
+
+
+/* Print error message to the opened error log stream.
+ This utilizes the provided logging configuration.
+ conn: connection
+ fmt: format string without the line return
+ ...: variable argument list
+ Example:
+ mg_cry(conn,"i like %s", "logging"); */
+CIVETWEB_API void mg_cry(const struct mg_connection *conn,
+ PRINTF_FORMAT_STRING(const char *fmt),
+ ...) PRINTF_ARGS(2, 3);
+
+
+/* utility methods to compare two buffers, case incensitive. */
+CIVETWEB_API int mg_strcasecmp(const char *s1, const char *s2);
+CIVETWEB_API int mg_strncasecmp(const char *s1, const char *s2, size_t len);
+
+
+/* Connect to a websocket as a client
+ Parameters:
+ host: host to connect to, i.e. "echo.websocket.org" or "192.168.1.1" or
+ "localhost"
+ port: server port
+ use_ssl: make a secure connection to server
+ error_buffer, error_buffer_size: buffer for an error message
+ path: server path you are trying to connect to, i.e. if connection to
+ localhost/app, path should be "/app"
+ origin: value of the Origin HTTP header
+ data_func: callback that should be used when data is received from the
+ server
+ user_data: user supplied argument
+
+ Return:
+ On success, valid mg_connection object.
+ On error, NULL. Se error_buffer for details.
+*/
+CIVETWEB_API struct mg_connection *
+mg_connect_websocket_client(const char *host,
+ int port,
+ int use_ssl,
+ char *error_buffer,
+ size_t error_buffer_size,
+ const char *path,
+ const char *origin,
+ mg_websocket_data_handler data_func,
+ mg_websocket_close_handler close_func,
+ void *user_data);
+
+
+/* Connect to a TCP server as a client (can be used to connect to a HTTP server)
+ Parameters:
+ host: host to connect to, i.e. "www.wikipedia.org" or "192.168.1.1" or
+ "localhost"
+ port: server port
+ use_ssl: make a secure connection to server
+ error_buffer, error_buffer_size: buffer for an error message
+
+ Return:
+ On success, valid mg_connection object.
+ On error, NULL. Se error_buffer for details.
+*/
+CIVETWEB_API struct mg_connection *mg_connect_client(const char *host,
+ int port,
+ int use_ssl,
+ char *error_buffer,
+ size_t error_buffer_size);
+
+
+struct mg_client_options {
+ const char *host;
+ int port;
+ const char *client_cert;
+ const char *server_cert;
+ /* TODO: add more data */
+};
+
+
+CIVETWEB_API struct mg_connection *
+mg_connect_client_secure(const struct mg_client_options *client_options,
+ char *error_buffer,
+ size_t error_buffer_size);
+
+
+enum { TIMEOUT_INFINITE = -1 };
+
+
+/* Wait for a response from the server
+ Parameters:
+ conn: connection
+ ebuf, ebuf_len: error message placeholder.
+ timeout: time to wait for a response in milliseconds (if < 0 then wait
+ forever)
+
+ Return:
+ On success, >= 0
+ On error/timeout, < 0
+*/
+CIVETWEB_API int mg_get_response(struct mg_connection *conn,
+ char *ebuf,
+ size_t ebuf_len,
+ int timeout);
+
+
+/* Check which features where set when civetweb has been compiled.
+ Parameters:
+ feature: specifies which feature should be checked
+ 1 serve files (NO_FILES not set)
+ 2 support HTTPS (NO_SSL not set)
+ 4 support CGI (NO_CGI not set)
+ 8 support IPv6 (USE_IPV6 set)
+ 16 support WebSocket (USE_WEBSOCKET set)
+ 32 support Lua scripts and Lua server pages (USE_LUA is set)
+ 64 support server side JavaScript (USE_DUKTAPE is set)
+ 128 support caching (NO_CACHING not set)
+ The result is undefined for all other feature values.
+
+ Return:
+ If feature is available > 0
+ If feature is not available = 0
+*/
+CIVETWEB_API unsigned mg_check_feature(unsigned feature);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* CIVETWEB_HEADER_INCLUDED */
--- /dev/null
+/* Copyright (c) 2016 the Civetweb developers
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+
+static int
+url_encoded_field_found(const struct mg_connection *conn,
+ const char *key,
+ size_t key_len,
+ const char *filename,
+ size_t filename_len,
+ char *path,
+ size_t path_len,
+ struct mg_form_data_handler *fdh)
+{
+ char key_dec[1024];
+ char filename_dec[1024];
+ int key_dec_len;
+ int filename_dec_len;
+ int ret;
+
+ key_dec_len =
+ mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
+
+ if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
+ return FORM_FIELD_STORAGE_SKIP;
+ }
+
+ if (filename) {
+ filename_dec_len = mg_url_decode(filename,
+ (int)filename_len,
+ filename_dec,
+ (int)sizeof(filename_dec),
+ 1);
+
+ if (((size_t)filename_dec_len >= (size_t)sizeof(filename_dec))
+ || (filename_dec_len < 0)) {
+ /* Log error message and skip this field. */
+ mg_cry(conn, "%s: Cannot decode filename", __func__);
+ return FORM_FIELD_STORAGE_SKIP;
+ }
+ } else {
+ filename_dec[0] = 0;
+ }
+
+ ret =
+ fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data);
+
+ if ((ret & 0xF) == FORM_FIELD_STORAGE_GET) {
+ if (fdh->field_get == NULL) {
+ mg_cry(conn, "%s: Function \"Get\" not available", __func__);
+ return FORM_FIELD_STORAGE_SKIP;
+ }
+ }
+ if ((ret & 0xF) == FORM_FIELD_STORAGE_STORE) {
+ if (fdh->field_store == NULL) {
+ mg_cry(conn, "%s: Function \"Store\" not available", __func__);
+ return FORM_FIELD_STORAGE_SKIP;
+ }
+ }
+
+ return ret;
+}
+
+
+static int
+url_encoded_field_get(const struct mg_connection *conn,
+ const char *key,
+ size_t key_len,
+ const char *value,
+ size_t value_len,
+ struct mg_form_data_handler *fdh)
+{
+ char key_dec[1024];
+
+ char *value_dec = mg_malloc(value_len + 1);
+ int value_dec_len;
+
+ if (!value_dec) {
+ /* Log error message and stop parsing the form data. */
+ mg_cry(conn,
+ "%s: Not enough memory (required: %lu)",
+ __func__,
+ (unsigned long)(value_len + 1));
+ return FORM_FIELD_STORAGE_ABORT;
+ }
+
+ mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
+
+ value_dec_len =
+ mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
+
+ return fdh->field_get(key_dec,
+ value_dec,
+ (size_t)value_dec_len,
+ fdh->user_data);
+}
+
+
+static int
+field_stored(const struct mg_connection *conn,
+ const char *path,
+ long long file_size,
+ struct mg_form_data_handler *fdh)
+{
+ /* Equivalent to "upload" callback of "mg_upload". */
+
+ (void)conn; /* we do not need mg_cry here, so conn is currently unused */
+
+ return fdh->field_store(path, file_size, fdh->user_data);
+}
+
+
+static const char *
+search_boundary(const char *buf,
+ size_t buf_len,
+ const char *boundary,
+ size_t boundary_len)
+{
+ /* We must do a binary search here, not a string search, since the buffer
+ * may contain '\x00' bytes, if binary data is transferred. */
+ int clen = (int)buf_len - (int)boundary_len - 4;
+ int i;
+
+ for (i = 0; i <= clen; i++) {
+ if (!memcmp(buf + i, "\r\n--", 4)) {
+ if (!memcmp(buf + i + 4, boundary, boundary_len)) {
+ return buf + i;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+int
+mg_handle_form_request(struct mg_connection *conn,
+ struct mg_form_data_handler *fdh)
+{
+ const char *content_type;
+ char path[512];
+ char buf[1024];
+ int field_storage;
+ int buf_fill = 0;
+ int r;
+ int field_count = 0;
+ struct file fstore = STRUCT_FILE_INITIALIZER;
+ int64_t file_size = 0; /* init here, to a avoid a false positive
+ "uninitialized variable used" warning */
+
+ int has_body_data =
+ (conn->request_info.content_length > 0) || (conn->is_chunked);
+
+ /* There are three ways to encode data from a HTML form:
+ * 1) method: GET (default)
+ * The form data is in the HTTP query string.
+ * 2) method: POST, enctype: "application/x-www-form-urlencoded"
+ * The form data is in the request body.
+ * The body is url encoded (the default encoding for POST).
+ * 3) method: POST, enctype: "multipart/form-data".
+ * The form data is in the request body of a multipart message.
+ * This is the typical way to handle file upload from a form.
+ */
+
+ if (!has_body_data) {
+ const char *data;
+
+ if (strcmp(conn->request_info.request_method, "GET")) {
+ /* No body data, but not a GET request.
+ * This is not a valid form request. */
+ return -1;
+ }
+
+ /* GET request: form data is in the query string. */
+ /* The entire data has already been loaded, so there is no nead to
+ * call mg_read. We just need to split the query string into key-value
+ * pairs. */
+ data = conn->request_info.query_string;
+ if (!data) {
+ /* No query string. */
+ return -1;
+ }
+
+ /* Split data in a=1&b=xy&c=3&c=4 ... */
+ while (*data) {
+ const char *val = strchr(data, '=');
+ const char *next;
+ ptrdiff_t keylen, vallen;
+
+ if (!val) {
+ break;
+ }
+ keylen = val - data;
+
+ /* In every "field_found" callback we ask what to do with the
+ * data ("field_storage"). This could be:
+ * FORM_FIELD_STORAGE_SKIP (0) ... ignore the value of this field
+ * FORM_FIELD_STORAGE_GET (1) ... read the data and call the get
+ * callback function
+ * FORM_FIELD_STORAGE_STORE (2) ... store the data in a file
+ * FORM_FIELD_STORAGE_READ (3) ... let the user read the data
+ * (for parsing long data on the fly)
+ * (currently not implemented)
+ * FORM_FIELD_STORAGE_ABORT (flag) ... stop parsing
+ */
+ memset(path, 0, sizeof(path));
+ field_count++;
+ field_storage = url_encoded_field_found(conn,
+ data,
+ (size_t)keylen,
+ NULL,
+ 0,
+ path,
+ sizeof(path) - 1,
+ fdh);
+
+ val++;
+ next = strchr(val, '&');
+ if (next) {
+ vallen = next - val;
+ next++;
+ } else {
+ vallen = (ptrdiff_t)strlen(val);
+ next = val + vallen;
+ }
+
+ if (field_storage == FORM_FIELD_STORAGE_GET) {
+ /* Call callback */
+ url_encoded_field_get(
+ conn, data, (size_t)keylen, val, (size_t)vallen, fdh);
+ }
+ if (field_storage == FORM_FIELD_STORAGE_STORE) {
+ /* Store the content to a file */
+ if (mg_fopen(conn, path, "wb", &fstore) == 0) {
+ fstore.fp = NULL;
+ }
+ file_size = 0;
+ if (fstore.fp != NULL) {
+ size_t n =
+ (size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
+ if ((n != (size_t)vallen) || (ferror(fstore.fp))) {
+ mg_cry(conn,
+ "%s: Cannot write file %s",
+ __func__,
+ path);
+ fclose(fstore.fp);
+ fstore.fp = NULL;
+ remove_bad_file(conn, path);
+ }
+ file_size += (int64_t)n;
+
+ if (fstore.fp) {
+ r = fclose(fstore.fp);
+ if (r == 0) {
+ /* stored successfully */
+ field_stored(conn, path, file_size, fdh);
+ } else {
+ mg_cry(conn,
+ "%s: Error saving file %s",
+ __func__,
+ path);
+ remove_bad_file(conn, path);
+ }
+ fstore.fp = NULL;
+ }
+
+ } else {
+ mg_cry(conn, "%s: Cannot create file %s", __func__, path);
+ }
+ }
+
+ /* if (field_storage == FORM_FIELD_STORAGE_READ) { */
+ /* The idea of "field_storage=read" is to let the API user read
+ * data chunk by chunk and to some data processing on the fly.
+ * This should avoid the need to store data in the server:
+ * It should neither be stored in memory, like
+ * "field_storage=get" does, nor in a file like
+ * "field_storage=store".
+ * However, for a "GET" request this does not make any much
+ * sense, since the data is already stored in memory, as it is
+ * part of the query string.
+ */
+ /* } */
+
+ if ((field_storage & FORM_FIELD_STORAGE_ABORT)
+ == FORM_FIELD_STORAGE_ABORT) {
+ /* Stop parsing the request */
+ break;
+ }
+
+ /* Proceed to next entry */
+ data = next;
+ }
+
+ return field_count;
+ }
+
+ content_type = mg_get_header(conn, "Content-Type");
+
+ if (!content_type
+ || !mg_strcasecmp(content_type, "APPLICATION/X-WWW-FORM-URLENCODED")
+ || !mg_strcasecmp(content_type, "APPLICATION/WWW-FORM-URLENCODED")) {
+ /* The form data is in the request body data, encoded in key/value
+ * pairs. */
+ int all_data_read = 0;
+
+ /* Read body data and split it in keys and values.
+ * The encoding is like in the "GET" case above: a=1&b&c=3&c=4.
+ * Here we use "POST", and read the data from the request body.
+ * The data read on the fly, so it is not required to buffer the
+ * entire request in memory before processing it. */
+ for (;;) {
+ const char *val;
+ const char *next;
+ ptrdiff_t keylen, vallen;
+ ptrdiff_t used;
+ int end_of_key_value_pair_found = 0;
+ int get_block;
+
+ if ((size_t)buf_fill < (sizeof(buf) - 1)) {
+
+ size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
+ r = mg_read(conn, buf + (size_t)buf_fill, to_read);
+ if (r < 0) {
+ /* read error */
+ return -1;
+ }
+ if (r != (int)to_read) {
+ /* TODO: Create a function to get "all_data_read" from
+ * the conn object. All data is read if the Content-Length
+ * has been reached, or if chunked encoding is used and
+ * the end marker has been read, or if the connection has
+ * been closed. */
+ all_data_read = 1;
+ }
+ buf_fill += r;
+ buf[buf_fill] = 0;
+ if (buf_fill < 1) {
+ break;
+ }
+ }
+
+ val = strchr(buf, '=');
+
+ if (!val) {
+ break;
+ }
+ keylen = val - buf;
+ val++;
+
+ /* Call callback */
+ memset(path, 0, sizeof(path));
+ field_count++;
+ field_storage = url_encoded_field_found(conn,
+ buf,
+ (size_t)keylen,
+ NULL,
+ 0,
+ path,
+ sizeof(path) - 1,
+ fdh);
+
+ if ((field_storage & FORM_FIELD_STORAGE_ABORT)
+ == FORM_FIELD_STORAGE_ABORT) {
+ /* Stop parsing the request */
+ break;
+ }
+
+ if (field_storage == FORM_FIELD_STORAGE_STORE) {
+ if (mg_fopen(conn, path, "wb", &fstore) == 0) {
+ fstore.fp = NULL;
+ }
+ file_size = 0;
+ if (!fstore.fp) {
+ mg_cry(conn, "%s: Cannot create file %s", __func__, path);
+ }
+ }
+
+ get_block = 0;
+ /* Loop to read values larger than sizeof(buf)-keylen-2 */
+ do {
+ next = strchr(val, '&');
+ if (next) {
+ vallen = next - val;
+ next++;
+ end_of_key_value_pair_found = 1;
+ } else {
+ vallen = (ptrdiff_t)strlen(val);
+ next = val + vallen;
+ }
+
+ if (field_storage == FORM_FIELD_STORAGE_GET) {
+#if 0
+ if (!end_of_key_value_pair_found && !all_data_read) {
+ /* This callback will deliver partial contents */
+ }
+#else
+ (void)all_data_read; /* avoid warning */
+#endif
+
+ /* Call callback */
+ url_encoded_field_get(conn,
+ ((get_block > 0) ? NULL : buf),
+ ((get_block > 0) ? 0
+ : (size_t)keylen),
+ val,
+ (size_t)vallen,
+ fdh);
+ get_block++;
+ }
+ if (fstore.fp) {
+ size_t n =
+ (size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
+ if ((n != (size_t)vallen) || (ferror(fstore.fp))) {
+ mg_cry(conn,
+ "%s: Cannot write file %s",
+ __func__,
+ path);
+ fclose(fstore.fp);
+ fstore.fp = NULL;
+ remove_bad_file(conn, path);
+ }
+ file_size += (int64_t)n;
+ }
+
+ if (!end_of_key_value_pair_found) {
+ used = next - buf;
+ memmove(buf,
+ buf + (size_t)used,
+ sizeof(buf) - (size_t)used);
+ buf_fill -= (int)used;
+ if ((size_t)buf_fill < (sizeof(buf) - 1)) {
+
+ size_t to_read = sizeof(buf) - 1 - (size_t)buf_fill;
+ r = mg_read(conn, buf + (size_t)buf_fill, to_read);
+ if (r < 0) {
+ /* read error */
+ return -1;
+ }
+ if (r != (int)to_read) {
+ /* TODO: Create a function to get "all_data_read"
+ * from the conn object. All data is read if the
+ * Content-Length has been reached, or if chunked
+ * encoding is used and the end marker has been
+ * read, or if the connection has been closed. */
+ all_data_read = 1;
+ }
+ buf_fill += r;
+ buf[buf_fill] = 0;
+ if (buf_fill < 1) {
+ break;
+ }
+ val = buf;
+ }
+ }
+
+ } while (!end_of_key_value_pair_found);
+
+ if (fstore.fp) {
+ r = fclose(fstore.fp);
+ if (r == 0) {
+ /* stored successfully */
+ field_stored(conn, path, file_size, fdh);
+ } else {
+ mg_cry(conn, "%s: Error saving file %s", __func__, path);
+ remove_bad_file(conn, path);
+ }
+ fstore.fp = NULL;
+ }
+
+ /* Proceed to next entry */
+ used = next - buf;
+ memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
+ buf_fill -= (int)used;
+ }
+
+ return field_count;
+ }
+
+ if (!mg_strncasecmp(content_type, "MULTIPART/FORM-DATA;", 20)) {
+ /* The form data is in the request body data, encoded as multipart
+ * content (see https://www.ietf.org/rfc/rfc1867.txt,
+ * https://www.ietf.org/rfc/rfc2388.txt). */
+ const char *boundary;
+ size_t bl;
+ ptrdiff_t used;
+ struct mg_request_info part_header;
+ char *hbuf, *hend, *fbeg, *fend, *nbeg, *nend;
+ const char *content_disp;
+ const char *next;
+
+ memset(&part_header, 0, sizeof(part_header));
+
+ /* Skip all spaces between MULTIPART/FORM-DATA; and BOUNDARY= */
+ bl = 20;
+ while (content_type[bl] == ' ') {
+ bl++;
+ }
+
+ /* There has to be a BOUNDARY definition in the Content-Type header */
+ if (mg_strncasecmp(content_type + bl, "BOUNDARY=", 9)) {
+ /* Malformed request */
+ return -1;
+ }
+
+ boundary = content_type + bl + 9;
+ bl = strlen(boundary);
+
+ if (bl + 800 > sizeof(buf)) {
+ /* Sanity check: The algorithm can not work if bl >= sizeof(buf),
+ * and it will not work effectively, if the buf is only a few byte
+ * larger than bl, or it buf can not hold the multipart header
+ * plus the boundary.
+ * Check some reasonable number here, that should be fulfilled by
+ * any reasonable request from every browser. If it is not
+ * fulfilled, it might be a hand-made request, intended to
+ * interfere with the algorithm. */
+ return -1;
+ }
+
+ for (;;) {
+ size_t towrite, n;
+ int get_block;
+
+ r = mg_read(conn,
+ buf + (size_t)buf_fill,
+ sizeof(buf) - 1 - (size_t)buf_fill);
+ if (r < 0) {
+ /* read error */
+ return -1;
+ }
+ buf_fill += r;
+ buf[buf_fill] = 0;
+ if (buf_fill < 1) {
+ /* No data */
+ return -1;
+ }
+
+ if (buf[0] != '-' || buf[1] != '-') {
+ /* Malformed request */
+ return -1;
+ }
+ if (strncmp(buf + 2, boundary, bl)) {
+ /* Malformed request */
+ return -1;
+ }
+ if (buf[bl + 2] != '\r' || buf[bl + 3] != '\n') {
+ /* Every part must end with \r\n, if there is another part.
+ * The end of the request has an extra -- */
+ if (((size_t)buf_fill != (size_t)(bl + 6))
+ || (strncmp(buf + bl + 2, "--\r\n", 4))) {
+ /* Malformed request */
+ return -1;
+ }
+ /* End of the request */
+ break;
+ }
+
+ /* Next, we need to get the part header: Read until \r\n\r\n */
+ hbuf = buf + bl + 4;
+ hend = strstr(hbuf, "\r\n\r\n");
+ if (!hend) {
+ /* Malformed request */
+ return -1;
+ }
+
+ parse_http_headers(&hbuf, &part_header);
+ if ((hend + 2) != hbuf) {
+ /* Malformed request */
+ return -1;
+ }
+
+ /* Skip \r\n\r\n */
+ hend += 4;
+
+ /* According to the RFC, every part has to have a header field like:
+ * Content-Disposition: form-data; name="..." */
+ content_disp = get_header(&part_header, "Content-Disposition");
+ if (!content_disp) {
+ /* Malformed request */
+ return -1;
+ }
+
+ /* Get the mandatory name="..." part of the Content-Disposition
+ * header. */
+ nbeg = strstr(content_disp, "name=\"");
+ if (!nbeg) {
+ /* Malformed request */
+ return -1;
+ }
+ nbeg += 6;
+ nend = strchr(nbeg, '\"');
+ if (!nend) {
+ /* Malformed request */
+ return -1;
+ }
+
+ /* Get the optional filename="..." part of the Content-Disposition
+ * header. */
+ fbeg = strstr(content_disp, "filename=\"");
+ if (fbeg) {
+ fbeg += 10;
+ fend = strchr(fbeg, '\"');
+ if (!fend) {
+ /* Malformed request (the filename field is optional, but if
+ * it exists, it needs to be terminated correctly). */
+ return -1;
+ }
+
+ /* TODO: check Content-Type */
+ /* Content-Type: application/octet-stream */
+
+ } else {
+ fend = fbeg;
+ }
+
+ memset(path, 0, sizeof(path));
+ field_count++;
+ field_storage = url_encoded_field_found(conn,
+ nbeg,
+ (size_t)(nend - nbeg),
+ fbeg,
+ (size_t)(fend - fbeg),
+ path,
+ sizeof(path) - 1,
+ fdh);
+
+ /* If the boundary is already in the buffer, get the address,
+ * otherwise next will be NULL. */
+ next = search_boundary(hbuf,
+ (size_t)((buf - hbuf) + buf_fill),
+ boundary,
+ bl);
+
+ if (field_storage == FORM_FIELD_STORAGE_STORE) {
+ /* Store the content to a file */
+ if (mg_fopen(conn, path, "wb", &fstore) == 0) {
+ fstore.fp = NULL;
+ }
+ file_size = 0;
+
+ if (!fstore.fp) {
+ mg_cry(conn, "%s: Cannot create file %s", __func__, path);
+ }
+ }
+
+ get_block = 0;
+ while (!next) {
+ /* Set "towrite" to the number of bytes available
+ * in the buffer */
+ towrite = (size_t)(buf - hend + buf_fill);
+ /* Subtract the boundary length, to deal with
+ * cases the boundary is only partially stored
+ * in the buffer. */
+ towrite -= bl + 4;
+
+ if (field_storage == FORM_FIELD_STORAGE_GET) {
+ url_encoded_field_get(conn,
+ ((get_block > 0) ? NULL : nbeg),
+ ((get_block > 0)
+ ? 0
+ : (size_t)(nend - nbeg)),
+ hend,
+ towrite,
+ fdh);
+ get_block++;
+ }
+
+ if (field_storage == FORM_FIELD_STORAGE_STORE) {
+ if (fstore.fp) {
+
+ /* Store the content of the buffer. */
+ n = (size_t)fwrite(hend, 1, towrite, fstore.fp);
+ if ((n != towrite) || (ferror(fstore.fp))) {
+ mg_cry(conn,
+ "%s: Cannot write file %s",
+ __func__,
+ path);
+ fclose(fstore.fp);
+ fstore.fp = NULL;
+ remove_bad_file(conn, path);
+ }
+ file_size += (int64_t)n;
+ }
+ }
+
+ memmove(buf, hend + towrite, bl + 4);
+ buf_fill = (int)(bl + 4);
+ hend = buf;
+
+ /* Read new data */
+ r = mg_read(conn,
+ buf + (size_t)buf_fill,
+ sizeof(buf) - 1 - (size_t)buf_fill);
+ if (r < 0) {
+ /* read error */
+ return -1;
+ }
+ buf_fill += r;
+ buf[buf_fill] = 0;
+ if (buf_fill < 1) {
+ /* No data */
+ return -1;
+ }
+
+ /* Find boundary */
+ next = search_boundary(buf, (size_t)buf_fill, boundary, bl);
+ }
+
+ towrite = (size_t)(next - hend);
+
+ if (field_storage == FORM_FIELD_STORAGE_GET) {
+ /* Call callback */
+ url_encoded_field_get(conn,
+ ((get_block > 0) ? NULL : nbeg),
+ ((get_block > 0) ? 0
+ : (size_t)(nend - nbeg)),
+ hend,
+ towrite,
+ fdh);
+ }
+
+ if (field_storage == FORM_FIELD_STORAGE_STORE) {
+
+ if (fstore.fp) {
+ n = (size_t)fwrite(hend, 1, towrite, fstore.fp);
+ if ((n != towrite) || (ferror(fstore.fp))) {
+ mg_cry(conn,
+ "%s: Cannot write file %s",
+ __func__,
+ path);
+ fclose(fstore.fp);
+ fstore.fp = NULL;
+ remove_bad_file(conn, path);
+ }
+ file_size += (int64_t)n;
+ }
+ }
+
+ if (field_storage == FORM_FIELD_STORAGE_STORE) {
+
+ if (fstore.fp) {
+ r = fclose(fstore.fp);
+ if (r == 0) {
+ /* stored successfully */
+ field_stored(conn, path, file_size, fdh);
+ } else {
+ mg_cry(conn,
+ "%s: Error saving file %s",
+ __func__,
+ path);
+ remove_bad_file(conn, path);
+ }
+ fstore.fp = NULL;
+ }
+ }
+
+ if ((field_storage & FORM_FIELD_STORAGE_ABORT)
+ == FORM_FIELD_STORAGE_ABORT) {
+ /* Stop parsing the request */
+ break;
+ }
+
+ /* Remove from the buffer */
+ used = next - buf + 2;
+ memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
+ buf_fill -= (int)used;
+ }
+
+ /* All parts handled */
+ return field_count;
+ }
+
+ /* Unknown Content-Type */
+ return -1;
+}
--- /dev/null
+/*
+ * This an amalgamation of md5.c and md5.h into a single file
+ * with all static declaration to reduce linker conflicts
+ * in Civetweb.
+ *
+ * The MD5_STATIC declaration was added to facilitate static
+ * inclusion.
+ * No Face Press, LLC
+ */
+
+/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.h is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Removed support for non-ANSI compilers; removed
+ references to Ghostscript; clarified derivation from RFC 1321;
+ now handles byte order either statically or dynamically.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
+ added conditionalization for C++ compilation from Martin
+ Purschke <purschke@bnl.gov>.
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef md5_INCLUDED
+#define md5_INCLUDED
+
+/*
+ * This package supports both compile-time and run-time determination of CPU
+ * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
+ * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
+ * defined as non-zero, the code will be compiled to run only on big-endian
+ * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
+ * run on either big- or little-endian CPUs, but will run slightly less
+ * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
+ */
+
+typedef unsigned char md5_byte_t; /* 8-bit byte */
+typedef unsigned int md5_word_t; /* 32-bit word */
+
+/* Define the state of the MD5 Algorithm. */
+typedef struct md5_state_s {
+ md5_word_t count[2]; /* message length in bits, lsw first */
+ md5_word_t abcd[4]; /* digest buffer */
+ md5_byte_t buf[64]; /* accumulate block */
+} md5_state_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Initialize the algorithm. */
+MD5_STATIC void md5_init(md5_state_t *pms);
+
+/* Append a string to the message. */
+MD5_STATIC void
+md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes);
+
+/* Finish the message and return the digest. */
+MD5_STATIC void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
+
+#ifdef __cplusplus
+} /* end extern "C" */
+#endif
+
+#endif /* md5_INCLUDED */
+
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+#ifndef MD5_STATIC
+#include <string.h>
+#endif
+
+#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
+#ifdef ARCH_IS_BIG_ENDIAN
+#define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
+#else
+#define BYTE_ORDER (0)
+#endif
+
+#define T_MASK ((md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 (0x242070db)
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 (0x4787c62a)
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 (0x698098d8)
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 (0x6b901122)
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 (0x49b40821)
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 (0x265e5a51)
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 (0x02441453)
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 (0x21e1cde6)
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 (0x455a14ed)
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 (0x676f02d9)
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 (0x6d9d6122)
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 (0x4bdecfa9)
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 (0x289b7ec6)
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 (0x04881d05)
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 (0x1fa27cf8)
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 (0x432aff97)
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 (0x655b59c3)
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 (0x6fa87e4f)
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 (0x4e0811a1)
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 (0x2ad7d2bb)
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+static void
+md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)
+{
+ md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2],
+ d = pms->abcd[3];
+ md5_word_t t;
+#if BYTE_ORDER > 0
+ /* Define storage only for big-endian CPUs. */
+ md5_word_t X[16];
+#else
+ /* Define storage for little-endian or both types of CPUs. */
+ md5_word_t xbuf[16];
+ const md5_word_t *X;
+#endif
+
+ {
+#if BYTE_ORDER == 0
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
+#endif
+#if BYTE_ORDER <= 0 /* little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const md5_byte_t *)0) & 3)) {
+ /* data are properly aligned, a direct assignment is possible */
+ /* cast through a (void *) should avoid a compiler warning,
+ see
+ https://github.com/bel2125/civetweb/issues/94#issuecomment-98112861
+ */
+ X = (const md5_word_t *)(const void *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+#endif
+#if BYTE_ORDER == 0
+ else /* dynamic big-endian */
+#endif
+#if BYTE_ORDER >= 0 /* big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const md5_byte_t *xp = data;
+ int i;
+
+#if BYTE_ORDER == 0
+ X = xbuf; /* (dynamic only) */
+#else
+#define xbuf X /* (static only) */
+#endif
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = (md5_word_t)(xp[0]) + (md5_word_t)(xp[1] << 8)
+ + (md5_word_t)(xp[2] << 16)
+ + (md5_word_t)(xp[3] << 24);
+ }
+#endif
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/* Round 1. */
+/* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + F(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 7, T1);
+ SET(d, a, b, c, 1, 12, T2);
+ SET(c, d, a, b, 2, 17, T3);
+ SET(b, c, d, a, 3, 22, T4);
+ SET(a, b, c, d, 4, 7, T5);
+ SET(d, a, b, c, 5, 12, T6);
+ SET(c, d, a, b, 6, 17, T7);
+ SET(b, c, d, a, 7, 22, T8);
+ SET(a, b, c, d, 8, 7, T9);
+ SET(d, a, b, c, 9, 12, T10);
+ SET(c, d, a, b, 10, 17, T11);
+ SET(b, c, d, a, 11, 22, T12);
+ SET(a, b, c, d, 12, 7, T13);
+ SET(d, a, b, c, 13, 12, T14);
+ SET(c, d, a, b, 14, 17, T15);
+ SET(b, c, d, a, 15, 22, T16);
+#undef SET
+
+/* Round 2. */
+/* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + G(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 1, 5, T17);
+ SET(d, a, b, c, 6, 9, T18);
+ SET(c, d, a, b, 11, 14, T19);
+ SET(b, c, d, a, 0, 20, T20);
+ SET(a, b, c, d, 5, 5, T21);
+ SET(d, a, b, c, 10, 9, T22);
+ SET(c, d, a, b, 15, 14, T23);
+ SET(b, c, d, a, 4, 20, T24);
+ SET(a, b, c, d, 9, 5, T25);
+ SET(d, a, b, c, 14, 9, T26);
+ SET(c, d, a, b, 3, 14, T27);
+ SET(b, c, d, a, 8, 20, T28);
+ SET(a, b, c, d, 13, 5, T29);
+ SET(d, a, b, c, 2, 9, T30);
+ SET(c, d, a, b, 7, 14, T31);
+ SET(b, c, d, a, 12, 20, T32);
+#undef SET
+
+/* Round 3. */
+/* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + H(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 5, 4, T33);
+ SET(d, a, b, c, 8, 11, T34);
+ SET(c, d, a, b, 11, 16, T35);
+ SET(b, c, d, a, 14, 23, T36);
+ SET(a, b, c, d, 1, 4, T37);
+ SET(d, a, b, c, 4, 11, T38);
+ SET(c, d, a, b, 7, 16, T39);
+ SET(b, c, d, a, 10, 23, T40);
+ SET(a, b, c, d, 13, 4, T41);
+ SET(d, a, b, c, 0, 11, T42);
+ SET(c, d, a, b, 3, 16, T43);
+ SET(b, c, d, a, 6, 23, T44);
+ SET(a, b, c, d, 9, 4, T45);
+ SET(d, a, b, c, 12, 11, T46);
+ SET(c, d, a, b, 15, 16, T47);
+ SET(b, c, d, a, 2, 23, T48);
+#undef SET
+
+/* Round 4. */
+/* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET(a, b, c, d, k, s, Ti) \
+ t = a + I(b, c, d) + X[k] + Ti; \
+ a = ROTATE_LEFT(t, s) + b
+
+ /* Do the following 16 operations. */
+ SET(a, b, c, d, 0, 6, T49);
+ SET(d, a, b, c, 7, 10, T50);
+ SET(c, d, a, b, 14, 15, T51);
+ SET(b, c, d, a, 5, 21, T52);
+ SET(a, b, c, d, 12, 6, T53);
+ SET(d, a, b, c, 3, 10, T54);
+ SET(c, d, a, b, 10, 15, T55);
+ SET(b, c, d, a, 1, 21, T56);
+ SET(a, b, c, d, 8, 6, T57);
+ SET(d, a, b, c, 15, 10, T58);
+ SET(c, d, a, b, 6, 15, T59);
+ SET(b, c, d, a, 13, 21, T60);
+ SET(a, b, c, d, 4, 6, T61);
+ SET(d, a, b, c, 11, 10, T62);
+ SET(c, d, a, b, 2, 15, T63);
+ SET(b, c, d, a, 9, 21, T64);
+#undef SET
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+MD5_STATIC void
+md5_init(md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+MD5_STATIC void
+md5_append(md5_state_t *pms, const md5_byte_t *data, size_t nbytes)
+{
+ const md5_byte_t *p = data;
+ size_t left = nbytes;
+ size_t offset = (pms->count[0] >> 3) & 63;
+ md5_word_t nbits = (md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += (md5_word_t)(nbytes >> 29);
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ size_t copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+MD5_STATIC void
+md5_finish(md5_state_t *pms, md5_byte_t digest[16])
+{
+ static const md5_byte_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
--- /dev/null
+/* This file is part of the CivetWeb web server.
+ * See https://github.com/civetweb/civetweb/
+ * (C) 2015 by the CivetWeb authors, MIT license.
+ */
+
+#include "duktape.h"
+
+/* TODO: the mg context should be added to duktape as well */
+/* Alternative: redefine a new, clean API from scratch (instead of using mg),
+ * or at least do not add problematic functions. */
+/* For evaluation purposes, currently only "send" is supported.
+ * All other ~50 functions will be added later. */
+
+/* Note: This is only experimental support, so the API may still change. */
+
+static const char *civetweb_conn_id = "\xFF"
+ "civetweb_conn";
+static const char *civetweb_ctx_id = "\xFF"
+ "civetweb_ctx";
+
+
+static void *
+mg_duk_mem_alloc(void *udata, duk_size_t size)
+{
+ return mg_malloc(size);
+}
+
+
+static void *
+mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize)
+{
+ return mg_realloc(ptr, newsize);
+}
+
+
+static void
+mg_duk_mem_free(void *udata, void *ptr)
+{
+ mg_free(ptr);
+}
+
+
+static void
+mg_duk_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)
+{
+ /* Script is called "protected" (duk_peval_file), so script errors should
+ * never yield in a call to this function. Maybe calls prior to executing
+ * the script could raise a fatal error. */
+ struct mg_connection *conn;
+
+ duk_push_global_stash(ctx);
+ duk_get_prop_string(ctx, -1, civetweb_conn_id);
+ conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
+
+ mg_cry(conn, "%s", msg);
+}
+
+
+static duk_ret_t
+duk_itf_write(duk_context *ctx)
+{
+ struct mg_connection *conn;
+ duk_double_t ret;
+ duk_size_t len = 0;
+ const char *val = duk_require_lstring(ctx, -1, &len);
+
+ /*
+ duk_push_global_stash(ctx);
+ duk_get_prop_string(ctx, -1, civetweb_conn_id);
+ conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
+ */
+ duk_push_current_function(ctx);
+ duk_get_prop_string(ctx, -1, civetweb_conn_id);
+ conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
+
+ if (!conn) {
+ duk_error(ctx,
+ DUK_ERR_INTERNAL_ERROR,
+ "function not available without connection object");
+ /* probably never reached, but satisfies static code analysis */
+ return DUK_RET_INTERNAL_ERROR;
+ }
+
+ ret = mg_write(conn, val, len);
+
+ duk_push_number(ctx, ret);
+ return 1;
+}
+
+
+static duk_ret_t
+duk_itf_read(duk_context *ctx)
+{
+ struct mg_connection *conn;
+ char buf[1024];
+ int len;
+
+ duk_push_global_stash(ctx);
+ duk_get_prop_string(ctx, -1, civetweb_conn_id);
+ conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
+
+ if (!conn) {
+ duk_error(ctx,
+ DUK_ERR_INTERNAL_ERROR,
+ "function not available without connection object");
+ /* probably never reached, but satisfies static code analysis */
+ return DUK_RET_INTERNAL_ERROR;
+ }
+
+ len = mg_read(conn, buf, sizeof(buf));
+
+ duk_push_lstring(ctx, buf, len);
+ return 1;
+}
+
+
+static duk_ret_t
+duk_itf_getoption(duk_context *ctx)
+{
+ struct mg_context *cv_ctx;
+ const char *ret;
+ duk_size_t len = 0;
+ const char *val = duk_require_lstring(ctx, -1, &len);
+
+ duk_push_current_function(ctx);
+ duk_get_prop_string(ctx, -1, civetweb_ctx_id);
+ cv_ctx = (struct mg_context *)duk_to_pointer(ctx, -1);
+
+ if (!cv_ctx) {
+ duk_error(ctx,
+ DUK_ERR_INTERNAL_ERROR,
+ "function not available without connection object");
+ /* probably never reached, but satisfies static code analysis */
+ return DUK_RET_INTERNAL_ERROR;
+ }
+
+ ret = mg_get_option(cv_ctx, val);
+ if (ret) {
+ duk_push_string(ctx, ret);
+ } else {
+ duk_push_null(ctx);
+ }
+
+ return 1;
+}
+
+
+static void
+mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
+{
+ int i;
+ duk_context *ctx = NULL;
+
+ conn->must_close = 1;
+
+ /* Create Duktape interpreter state */
+ ctx = duk_create_heap(mg_duk_mem_alloc,
+ mg_duk_mem_realloc,
+ mg_duk_mem_free,
+ NULL,
+ mg_duk_fatal_handler);
+ if (!ctx) {
+ mg_cry(conn, "Failed to create a Duktape heap.");
+ goto exec_duktape_finished;
+ }
+
+ /* Add "conn" object */
+ duk_push_global_object(ctx);
+ duk_push_object(ctx); /* create a new table/object ("conn") */
+
+ duk_push_c_function(ctx, duk_itf_write, 1 /* 1 = nargs */);
+ duk_push_pointer(ctx, (void *)conn);
+ duk_put_prop_string(ctx, -2, civetweb_conn_id);
+ duk_put_prop_string(ctx, -2, "write"); /* add function conn.write */
+
+ duk_push_c_function(ctx, duk_itf_read, 0 /* 0 = nargs */);
+ duk_push_pointer(ctx, (void *)conn);
+ duk_put_prop_string(ctx, -2, civetweb_conn_id);
+ duk_put_prop_string(ctx, -2, "read"); /* add function conn.read */
+
+ duk_push_string(ctx, conn->request_info.request_method);
+ duk_put_prop_string(ctx, -2, "request_method"); /* add string conn.r... */
+
+ duk_push_string(ctx, conn->request_info.request_uri);
+ duk_put_prop_string(ctx, -2, "request_uri");
+
+ duk_push_string(ctx, conn->request_info.local_uri);
+ duk_put_prop_string(ctx, -2, "uri");
+
+ duk_push_string(ctx, conn->request_info.http_version);
+ duk_put_prop_string(ctx, -2, "http_version");
+
+ duk_push_string(ctx, conn->request_info.query_string);
+ duk_put_prop_string(ctx, -2, "query_string");
+
+ duk_push_string(ctx, conn->request_info.remote_addr);
+ duk_put_prop_string(ctx, -2, "remote_addr");
+
+ duk_push_int(ctx, conn->request_info.remote_port);
+ duk_put_prop_string(ctx, -2, "remote_port");
+
+ duk_push_int(ctx, ntohs(conn->client.lsa.sin.sin_port));
+ duk_put_prop_string(ctx, -2, "server_port");
+
+ duk_push_object(ctx); /* subfolder "conn.http_headers" */
+ for (i = 0; i < conn->request_info.num_headers; i++) {
+ duk_push_string(ctx, conn->request_info.http_headers[i].value);
+ duk_put_prop_string(ctx, -2, conn->request_info.http_headers[i].name);
+ }
+ duk_put_prop_string(ctx, -2, "http_headers");
+
+ duk_put_prop_string(ctx, -2, "conn"); /* call the table "conn" */
+
+ /* Add "civetweb" object */
+ duk_push_global_object(ctx);
+ duk_push_object(ctx); /* create a new table/object ("conn") */
+
+ duk_push_string(ctx, CIVETWEB_VERSION);
+ duk_put_prop_string(ctx, -2, "version");
+
+ duk_push_string(ctx, script_name);
+ duk_put_prop_string(ctx, -2, "script_name");
+
+ if (conn->ctx != NULL) {
+ duk_push_c_function(ctx, duk_itf_getoption, 1 /* 1 = nargs */);
+ duk_push_pointer(ctx, (void *)(conn->ctx));
+ duk_put_prop_string(ctx, -2, civetweb_ctx_id);
+ duk_put_prop_string(ctx, -2, "getoption"); /* add function conn.write */
+
+ if (conn->ctx->systemName != NULL) {
+ duk_push_string(ctx, conn->ctx->systemName);
+ duk_put_prop_string(ctx, -2, "system");
+ }
+ }
+
+ duk_put_prop_string(ctx, -2, "civetweb"); /* call the table "civetweb" */
+
+ duk_push_global_stash(ctx);
+ duk_push_pointer(ctx, (void *)conn);
+ duk_put_prop_string(ctx, -2, civetweb_conn_id);
+
+ if (duk_peval_file(ctx, script_name) != 0) {
+ mg_cry(conn, "%s", duk_safe_to_string(ctx, -1));
+ goto exec_duktape_finished;
+ }
+ duk_pop(ctx); /* ignore result */
+
+exec_duktape_finished:
+ duk_destroy_heap(ctx);
+}
--- /dev/null
+#include "civetweb_lua.h"
+#include "civetweb_private_lua.h"
+
+#ifdef _WIN32
+static void *
+mmap(void *addr, int64_t len, int prot, int flags, int fd, int offset)
+{
+ /* TODO (low): This is an incomplete implementation of mmap for windows.
+ * Currently it is sufficient, but there are a lot of unused parameters.
+ * Better use a function "mg_map" which only has the required parameters,
+ * and implement it using mmap in Linux and CreateFileMapping in Windows.
+ * Noone should expect a full mmap for Windows here.
+ */
+ HANDLE fh = (HANDLE)_get_osfhandle(fd);
+ HANDLE mh = CreateFileMapping(fh, 0, PAGE_READONLY, 0, 0, 0);
+ void *p = MapViewOfFile(mh, FILE_MAP_READ, 0, 0, (size_t)len);
+ CloseHandle(mh);
+
+ /* unused parameters */
+ (void)addr;
+ (void)prot;
+ (void)flags;
+ (void)offset;
+
+ return p;
+}
+
+static void
+munmap(void *addr, int64_t length)
+{
+ /* unused parameters */
+ (void)length;
+
+ UnmapViewOfFile(addr);
+}
+
+#define MAP_FAILED (NULL)
+#define MAP_PRIVATE (0)
+#define PROT_READ (0)
+#else
+#include <sys/mman.h>
+#endif
+
+static const char *LUASOCKET = "luasocket";
+static const char lua_regkey_ctx = 1;
+static const char lua_regkey_connlist = 2;
+
+/* Forward declarations */
+static void handle_request(struct mg_connection *);
+static int handle_lsp_request(struct mg_connection *,
+ const char *,
+ struct file *,
+ struct lua_State *);
+
+static void
+reg_string(struct lua_State *L, const char *name, const char *val)
+{
+ if (name != NULL && val != NULL) {
+ lua_pushstring(L, name);
+ lua_pushstring(L, val);
+ lua_rawset(L, -3);
+ }
+}
+
+static void
+reg_int(struct lua_State *L, const char *name, int val)
+{
+ if (name != NULL) {
+ lua_pushstring(L, name);
+ lua_pushinteger(L, val);
+ lua_rawset(L, -3);
+ }
+}
+
+static void
+reg_boolean(struct lua_State *L, const char *name, int val)
+{
+ if (name != NULL) {
+ lua_pushstring(L, name);
+ lua_pushboolean(L, val != 0);
+ lua_rawset(L, -3);
+ }
+}
+
+static void
+reg_conn_function(struct lua_State *L,
+ const char *name,
+ lua_CFunction func,
+ struct mg_connection *conn)
+{
+ if (name != NULL && func != NULL && conn != NULL) {
+ lua_pushstring(L, name);
+ lua_pushlightuserdata(L, conn);
+ lua_pushcclosure(L, func, 1);
+ lua_rawset(L, -3);
+ }
+}
+
+static void
+reg_function(struct lua_State *L, const char *name, lua_CFunction func)
+{
+ if (name != NULL && func != NULL) {
+ lua_pushstring(L, name);
+ lua_pushcclosure(L, func, 0);
+ lua_rawset(L, -3);
+ }
+}
+
+static void
+lua_cry(struct mg_connection *conn,
+ int err,
+ lua_State *L,
+ const char *lua_title,
+ const char *lua_operation)
+{
+ switch (err) {
+ case LUA_OK:
+ case LUA_YIELD:
+ break;
+ case LUA_ERRRUN:
+ mg_cry(conn,
+ "%s: %s failed: runtime error: %s",
+ lua_title,
+ lua_operation,
+ lua_tostring(L, -1));
+ break;
+ case LUA_ERRSYNTAX:
+ mg_cry(conn,
+ "%s: %s failed: syntax error: %s",
+ lua_title,
+ lua_operation,
+ lua_tostring(L, -1));
+ break;
+ case LUA_ERRMEM:
+ mg_cry(conn, "%s: %s failed: out of memory", lua_title, lua_operation);
+ break;
+ case LUA_ERRGCMM:
+ mg_cry(conn,
+ "%s: %s failed: error during garbage collection",
+ lua_title,
+ lua_operation);
+ break;
+ case LUA_ERRERR:
+ mg_cry(conn,
+ "%s: %s failed: error in error handling: %s",
+ lua_title,
+ lua_operation,
+ lua_tostring(L, -1));
+ break;
+ default:
+ mg_cry(conn, "%s: %s failed: error %i", lua_title, lua_operation, err);
+ break;
+ }
+}
+
+static int
+lsp_sock_close(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ if ((num_args == 1) && lua_istable(L, -1)) {
+ lua_getfield(L, -1, "sock");
+ closesocket((SOCKET)lua_tonumber(L, -1));
+ } else {
+ return luaL_error(L, "invalid :close() call");
+ }
+ return 1;
+}
+
+static int
+lsp_sock_recv(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ char buf[2000];
+ int n;
+
+ if ((num_args == 1) && lua_istable(L, -1)) {
+ lua_getfield(L, -1, "sock");
+ n = recv((SOCKET)lua_tonumber(L, -1), buf, sizeof(buf), 0);
+ if (n <= 0) {
+ lua_pushnil(L);
+ } else {
+ lua_pushlstring(L, buf, n);
+ }
+ } else {
+ return luaL_error(L, "invalid :close() call");
+ }
+ return 1;
+}
+
+static int
+lsp_sock_send(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ const char *buf;
+ size_t len, sent = 0;
+ int n = 0, sock;
+
+ if ((num_args == 2) && lua_istable(L, -2) && lua_isstring(L, -1)) {
+ buf = lua_tolstring(L, -1, &len);
+ lua_getfield(L, -2, "sock");
+ sock = (int)lua_tonumber(L, -1);
+ while (sent < len) {
+ if ((n = send(sock, buf + sent, (int)(len - sent), 0)) <= 0) {
+ break;
+ }
+ sent += n;
+ }
+ lua_pushnumber(L, n);
+ } else {
+ return luaL_error(L, "invalid :close() call");
+ }
+ return 1;
+}
+
+static const struct luaL_Reg luasocket_methods[] = {{"close", lsp_sock_close},
+ {"send", lsp_sock_send},
+ {"recv", lsp_sock_recv},
+ {NULL, NULL}};
+
+static int
+lsp_connect(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ char ebuf[100];
+ SOCKET sock;
+ union usa sa;
+ int ok;
+
+ if ((num_args == 3) && lua_isstring(L, -3) && lua_isnumber(L, -2)
+ && lua_isnumber(L, -1)) {
+ ok = connect_socket(NULL,
+ lua_tostring(L, -3),
+ (int)lua_tonumber(L, -2),
+ (int)lua_tonumber(L, -1),
+ ebuf,
+ sizeof(ebuf),
+ &sock,
+ &sa);
+ if (!ok) {
+ return luaL_error(L, ebuf);
+ } else {
+ lua_newtable(L);
+ reg_int(L, "sock", (int)sock);
+ reg_string(L, "host", lua_tostring(L, -4));
+ luaL_getmetatable(L, LUASOCKET);
+ lua_setmetatable(L, -2);
+ /* TODO (high): The metatable misses a _gc method to free the
+ * sock object -> currently lsp_connect is a resource leak. */
+ }
+ } else {
+ return luaL_error(
+ L, "connect(host,port,is_ssl): invalid parameter given.");
+ }
+ return 1;
+}
+
+static int
+lsp_error(lua_State *L)
+{
+ lua_getglobal(L, "mg");
+ lua_getfield(L, -1, "onerror");
+ lua_pushvalue(L, -3);
+ lua_pcall(L, 1, 0, 0);
+ return 0;
+}
+
+/* Silently stop processing chunks. */
+static void
+lsp_abort(lua_State *L)
+{
+ int top = lua_gettop(L);
+ lua_getglobal(L, "mg");
+ lua_pushnil(L);
+ lua_setfield(L, -2, "onerror");
+ lua_settop(L, top);
+ lua_pushstring(L, "aborting");
+ lua_error(L);
+}
+
+struct lsp_var_reader_data {
+ const char *begin;
+ unsigned len;
+ unsigned state;
+};
+
+
+static const char *
+lsp_var_reader(lua_State *L, void *ud, size_t *sz)
+{
+ struct lsp_var_reader_data *reader = (struct lsp_var_reader_data *)ud;
+ const char *ret;
+ (void)(L); /* unused */
+
+ switch (reader->state) {
+ case 0:
+ ret = "mg.write(";
+ *sz = strlen(ret);
+ break;
+ case 1:
+ ret = reader->begin;
+ *sz = reader->len;
+ break;
+ case 2:
+ ret = ")";
+ *sz = strlen(ret);
+ break;
+ default:
+ ret = 0;
+ *sz = 0;
+ }
+
+ reader->state++;
+ return ret;
+}
+
+
+static int
+lsp(struct mg_connection *conn,
+ const char *path,
+ const char *p,
+ int64_t len,
+ lua_State *L)
+{
+ int i, j, pos = 0, lines = 1, lualines = 0, is_var, lua_ok;
+ char chunkname[MG_BUF_LEN];
+ struct lsp_var_reader_data data;
+
+ for (i = 0; i < len; i++) {
+ if (p[i] == '\n')
+ lines++;
+ if ((i + 1) < len && p[i] == '<' && p[i + 1] == '?') {
+
+ /* <?= ?> means a variable is enclosed and its value should be
+ * printed */
+ is_var = ((i + 2) < len && p[i + 2] == '=');
+
+ if (is_var)
+ j = i + 2;
+ else
+ j = i + 1;
+
+ while (j < len) {
+ if (p[j] == '\n')
+ lualines++;
+ if ((j + 1) < len && p[j] == '?' && p[j + 1] == '>') {
+ mg_write(conn, p + pos, i - pos);
+
+ mg_snprintf(conn,
+ NULL, /* name only used for debugging */
+ chunkname,
+ sizeof(chunkname),
+ "@%s+%i",
+ path,
+ lines);
+ lua_pushlightuserdata(L, conn);
+ lua_pushcclosure(L, lsp_error, 1);
+
+ if (is_var) {
+ data.begin = p + (i + 3);
+ data.len = j - (i + 3);
+ data.state = 0;
+ lua_ok = mg_lua_load(
+ L, lsp_var_reader, &data, chunkname, NULL);
+ } else {
+ lua_ok = luaL_loadbuffer(L,
+ p + (i + 2),
+ j - (i + 2),
+ chunkname);
+ }
+
+ if (lua_ok) {
+ /* Syntax error or OOM. Error message is pushed on
+ * stack. */
+ lua_pcall(L, 1, 0, 0);
+ } else {
+ /* Success loading chunk. Call it. */
+ lua_pcall(L, 0, 0, 1);
+ }
+
+ pos = j + 2;
+ i = pos - 1;
+ break;
+ }
+ j++;
+ }
+
+ if (lualines > 0) {
+ lines += lualines;
+ lualines = 0;
+ }
+ }
+ }
+
+ if (i > pos) {
+ mg_write(conn, p + pos, i - pos);
+ }
+
+ return 0;
+}
+
+
+/* mg.write: Send data to the client */
+static int
+lsp_write(lua_State *L)
+{
+ struct mg_connection *conn =
+ (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+ int num_args = lua_gettop(L);
+ const char *str;
+ size_t size;
+ int i;
+
+ for (i = 1; i <= num_args; i++) {
+ if (lua_isstring(L, i)) {
+ str = lua_tolstring(L, i, &size);
+ mg_write(conn, str, size);
+ }
+ }
+
+ return 0;
+}
+
+
+/* mg.read: Read data from the client (e.g., from a POST request) */
+static int
+lsp_read(lua_State *L)
+{
+ struct mg_connection *conn =
+ (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+ char buf[1024];
+ int len = mg_read(conn, buf, sizeof(buf));
+
+ if (len <= 0)
+ return 0;
+ lua_pushlstring(L, buf, len);
+
+ return 1;
+}
+
+
+/* mg.keep_alive: Allow Lua pages to use the http keep-alive mechanism */
+static int
+lsp_keep_alive(lua_State *L)
+{
+ struct mg_connection *conn =
+ (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+ int num_args = lua_gettop(L);
+
+ /* This function may be called with one parameter (boolean) to set the
+ keep_alive state.
+ Or without a parameter to just query the current keep_alive state. */
+ if ((num_args == 1) && lua_isboolean(L, 1)) {
+ conn->must_close = !lua_toboolean(L, 1);
+ } else if (num_args != 0) {
+ /* Syntax error */
+ return luaL_error(L, "invalid keep_alive() call");
+ }
+
+ /* Return the current "keep_alive" state. This may be false, even it
+ * keep_alive(true) has been called. */
+ lua_pushboolean(L, should_keep_alive(conn));
+ return 1;
+}
+
+
+/* mg.include: Include another .lp file */
+static int
+lsp_include(lua_State *L)
+{
+ struct mg_connection *conn =
+ (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+ int num_args = lua_gettop(L);
+ struct file file = STRUCT_FILE_INITIALIZER;
+ const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
+
+ if (filename) {
+ if (handle_lsp_request(conn, filename, &file, L)) {
+ /* handle_lsp_request returned an error code, meaning an error
+ occured in
+ the included page and mg.onerror returned non-zero. Stop processing.
+ */
+ lsp_abort(L);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid include() call");
+ }
+ return 0;
+}
+
+
+/* mg.cry: Log an error. Default value for mg.onerror. */
+static int
+lsp_cry(lua_State *L)
+{
+ struct mg_connection *conn =
+ (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+ int num_args = lua_gettop(L);
+ const char *text = (num_args == 1) ? lua_tostring(L, 1) : NULL;
+
+ if (text) {
+ mg_cry(conn, "%s", lua_tostring(L, -1));
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid cry() call");
+ }
+ return 0;
+}
+
+
+/* mg.redirect: Redirect the request (internally). */
+static int
+lsp_redirect(lua_State *L)
+{
+ struct mg_connection *conn =
+ (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+ int num_args = lua_gettop(L);
+ const char *target = (num_args == 1) ? lua_tostring(L, 1) : NULL;
+
+ if (target) {
+ conn->request_info.local_uri = target;
+ handle_request(conn);
+ lsp_abort(L);
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid redirect() call");
+ }
+ return 0;
+}
+
+
+/* mg.send_file */
+static int
+lsp_send_file(lua_State *L)
+{
+ struct mg_connection *conn =
+ (struct mg_connection *)lua_touserdata(L, lua_upvalueindex(1));
+ int num_args = lua_gettop(L);
+ const char *filename = (num_args == 1) ? lua_tostring(L, 1) : NULL;
+
+ if (filename) {
+ mg_send_file(conn, filename);
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid send_file() call");
+ }
+ return 0;
+}
+
+
+/* mg.get_time */
+static int
+lsp_get_time(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ int monotonic = (num_args > 0) ? lua_toboolean(L, 1) : 0;
+ struct timespec ts;
+ double d;
+
+ clock_gettime(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &ts);
+ d = (double)ts.tv_sec + ((double)ts.tv_nsec * 1.0E-9);
+ lua_pushnumber(L, d);
+ return 1;
+}
+
+
+/* mg.get_var */
+static int
+lsp_get_var(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ const char *data, *var_name;
+ size_t data_len, occurrence;
+ int ret;
+ char dst[512];
+
+ if (num_args >= 2 && num_args <= 3) {
+ data = lua_tolstring(L, 1, &data_len);
+ var_name = lua_tostring(L, 2);
+ occurrence = (num_args > 2) ? (long)lua_tonumber(L, 3) : 0;
+
+ ret =
+ mg_get_var2(data, data_len, var_name, dst, sizeof(dst), occurrence);
+ if (ret >= 0) {
+ /* Variable found: return value to Lua */
+ lua_pushstring(L, dst);
+ } else {
+ /* Variable not found (TODO (mid): may be string too long) */
+ lua_pushnil(L);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid get_var() call");
+ }
+ return 1;
+}
+
+
+/* mg.get_mime_type */
+static int
+lsp_get_mime_type(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ struct vec mime_type = {0, 0};
+ struct mg_context *ctx;
+ const char *text;
+
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
+
+ if (num_args == 1) {
+ text = lua_tostring(L, 1);
+ if (text) {
+ if (ctx) {
+ get_mime_type(ctx, text, &mime_type);
+ lua_pushlstring(L, mime_type.ptr, mime_type.len);
+ } else {
+ text = mg_get_builtin_mime_type(text);
+ lua_pushstring(L, text);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid argument for get_mime_type() call");
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid get_mime_type() call");
+ }
+ return 1;
+}
+
+
+/* mg.get_cookie */
+static int
+lsp_get_cookie(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ const char *cookie;
+ const char *var_name;
+ int ret;
+ char dst[512];
+
+ if (num_args == 2) {
+ cookie = lua_tostring(L, 1);
+ var_name = lua_tostring(L, 2);
+ if (cookie != NULL && var_name != NULL) {
+ ret = mg_get_cookie(cookie, var_name, dst, sizeof(dst));
+ } else {
+ ret = -1;
+ }
+
+ if (ret >= 0) {
+ lua_pushlstring(L, dst, ret);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid get_cookie() call");
+ }
+ return 1;
+}
+
+
+/* mg.md5 */
+static int
+lsp_md5(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ const char *text;
+ md5_byte_t hash[16];
+ md5_state_t ctx;
+ size_t text_len;
+ char buf[40];
+
+ if (num_args == 1) {
+ text = lua_tolstring(L, 1, &text_len);
+ if (text) {
+ md5_init(&ctx);
+ md5_append(&ctx, (const md5_byte_t *)text, text_len);
+ md5_finish(&ctx, hash);
+ bin2str(buf, hash, sizeof(hash));
+ lua_pushstring(L, buf);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid md5() call");
+ }
+ return 1;
+}
+
+
+/* mg.url_encode */
+static int
+lsp_url_encode(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ const char *text;
+ size_t text_len;
+ char dst[512];
+
+ if (num_args == 1) {
+ text = lua_tolstring(L, 1, &text_len);
+ if (text) {
+ mg_url_encode(text, dst, sizeof(dst));
+ lua_pushstring(L, dst);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid url_encode() call");
+ }
+ return 1;
+}
+
+
+/* mg.url_decode */
+static int
+lsp_url_decode(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ const char *text;
+ size_t text_len;
+ int is_form;
+ char dst[512];
+
+ if (num_args == 1 || (num_args == 2 && lua_isboolean(L, 2))) {
+ text = lua_tolstring(L, 1, &text_len);
+ is_form = (num_args == 2) ? lua_isboolean(L, 2) : 0;
+ if (text) {
+ mg_url_decode(text, text_len, dst, (int)sizeof(dst), is_form);
+ lua_pushstring(L, dst);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid url_decode() call");
+ }
+ return 1;
+}
+
+
+/* mg.base64_encode */
+static int
+lsp_base64_encode(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ const char *text;
+ size_t text_len;
+ char *dst;
+
+ if (num_args == 1) {
+ text = lua_tolstring(L, 1, &text_len);
+ if (text) {
+ dst = (char *)mg_malloc(text_len * 8 / 6 + 4);
+ if (dst) {
+ base64_encode((const unsigned char *)text, (int)text_len, dst);
+ lua_pushstring(L, dst);
+ mg_free(dst);
+ } else {
+ return luaL_error(L, "out of memory in base64_encode() call");
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid base64_encode() call");
+ }
+ return 1;
+}
+
+
+/* mg.base64_encode */
+static int
+lsp_base64_decode(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ const char *text;
+ size_t text_len, dst_len;
+ int ret;
+ char *dst;
+
+ if (num_args == 1) {
+ text = lua_tolstring(L, 1, &text_len);
+ if (text) {
+ dst = (char *)mg_malloc(text_len);
+ if (dst) {
+ ret = base64_decode((const unsigned char *)text,
+ (int)text_len,
+ dst,
+ &dst_len);
+ if (ret != -1) {
+ mg_free(dst);
+ return luaL_error(
+ L, "illegal character in lsp_base64_decode() call");
+ } else {
+ lua_pushlstring(L, dst, dst_len);
+ mg_free(dst);
+ }
+ } else {
+ return luaL_error(L,
+ "out of memory in lsp_base64_decode() call");
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ /* Syntax error */
+ return luaL_error(L, "invalid lsp_base64_decode() call");
+ }
+ return 1;
+}
+
+
+/* mg.get_response_code_text */
+static int
+lsp_get_response_code_text(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ int type1;
+ double code;
+ const char *text;
+
+ if (num_args == 1) {
+ type1 = lua_type(L, 1);
+ if (type1 == LUA_TNUMBER) {
+ /* If the first argument is a number,
+ convert it to the corresponding text. */
+ code = lua_tonumber(L, 1);
+ text = mg_get_response_code_text(NULL, (int)code);
+ if (text)
+ lua_pushstring(L, text);
+ return text ? 1 : 0;
+ }
+ }
+
+ /* Syntax error */
+ return luaL_error(L, "invalid get_response_code_text() call");
+}
+
+
+/* mg.random - might be better than math.random on some systems */
+static int
+lsp_random(lua_State *L)
+{
+ int num_args = lua_gettop(L);
+ if (num_args == 0) {
+ /* The civetweb internal random number generator will generate
+ * a 64 bit random number. */
+ uint64_t r = get_random();
+ /* Lua "number" is a IEEE 754 double precission float:
+ * https://en.wikipedia.org/wiki/Double-precision_floating-point_format
+ * Thus, mask with 2^53-1 to get an integer with the maximum
+ * precission available. */
+ r &= ((((uint64_t)1) << 53) - 1);
+ lua_pushnumber(L, (double)r);
+ return 1;
+ }
+
+ /* Syntax error */
+ return luaL_error(L, "invalid random() call");
+}
+
+
+union {
+ void *p;
+ void (*f)(unsigned char uuid[16]);
+} pf_uuid_generate;
+
+
+/* mg.uuid */
+static int
+lsp_uuid(lua_State *L)
+{
+ union {
+ unsigned char uuid_array[16];
+ struct uuid_struct_type {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint8_t data4[8];
+ } uuid_struct;
+ } uuid;
+
+ char uuid_str[40];
+ int num_args = lua_gettop(L);
+
+ memset(&uuid, 0, sizeof(uuid));
+ memset(uuid_str, 0, sizeof(uuid_str));
+
+ if (num_args == 0) {
+
+ pf_uuid_generate.f(uuid.uuid_array);
+
+ sprintf(uuid_str,
+ "{%08lX-%04X-%04X-%02X%02X-"
+ "%02X%02X%02X%02X%02X%02X}",
+ (unsigned long)uuid.uuid_struct.data1,
+ (unsigned)uuid.uuid_struct.data2,
+ (unsigned)uuid.uuid_struct.data3,
+ (unsigned)uuid.uuid_struct.data4[0],
+ (unsigned)uuid.uuid_struct.data4[1],
+ (unsigned)uuid.uuid_struct.data4[2],
+ (unsigned)uuid.uuid_struct.data4[3],
+ (unsigned)uuid.uuid_struct.data4[4],
+ (unsigned)uuid.uuid_struct.data4[5],
+ (unsigned)uuid.uuid_struct.data4[6],
+ (unsigned)uuid.uuid_struct.data4[7]);
+
+ lua_pushstring(L, uuid_str);
+ return 1;
+ }
+
+ /* Syntax error */
+ return luaL_error(L, "invalid random() call");
+}
+
+
+#ifdef USE_WEBSOCKET
+struct lua_websock_data {
+ lua_State *state;
+ char *script;
+ unsigned references;
+ struct mg_connection *conn[MAX_WORKER_THREADS];
+ pthread_mutex_t ws_mutex;
+};
+#endif
+
+
+/* mg.write for websockets */
+static int
+lwebsock_write(lua_State *L)
+{
+#ifdef USE_WEBSOCKET
+ int num_args = lua_gettop(L);
+ struct lua_websock_data *ws;
+ const char *str;
+ size_t size;
+ int opcode = -1;
+ unsigned i;
+ struct mg_connection *client = NULL;
+
+ lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ ws = (struct lua_websock_data *)lua_touserdata(L, -1);
+
+ (void)pthread_mutex_lock(&(ws->ws_mutex));
+
+ if (num_args == 1) {
+ /* just one text: send it to all client */
+ if (lua_isstring(L, 1)) {
+ opcode = WEBSOCKET_OPCODE_TEXT;
+ }
+ } else if (num_args == 2) {
+ if (lua_isnumber(L, 1)) {
+ /* opcode number and message text */
+ opcode = (int)lua_tointeger(L, 1);
+ } else if (lua_isstring(L, 1)) {
+ /* opcode string and message text */
+ str = lua_tostring(L, 1);
+ if (!mg_strncasecmp(str, "text", 4))
+ opcode = WEBSOCKET_OPCODE_TEXT;
+ else if (!mg_strncasecmp(str, "bin", 3))
+ opcode = WEBSOCKET_OPCODE_BINARY;
+ else if (!mg_strncasecmp(str, "close", 5))
+ opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
+ else if (!mg_strncasecmp(str, "ping", 4))
+ opcode = WEBSOCKET_OPCODE_PING;
+ else if (!mg_strncasecmp(str, "pong", 4))
+ opcode = WEBSOCKET_OPCODE_PONG;
+ else if (!mg_strncasecmp(str, "cont", 4))
+ opcode = WEBSOCKET_OPCODE_CONTINUATION;
+ } else if (lua_isuserdata(L, 1)) {
+ /* client id and message text */
+ client = (struct mg_connection *)lua_touserdata(L, 1);
+ opcode = WEBSOCKET_OPCODE_TEXT;
+ }
+ } else if (num_args == 3) {
+ if (lua_isuserdata(L, 1)) {
+ client = (struct mg_connection *)lua_touserdata(L, 1);
+ if (lua_isnumber(L, 2)) {
+ /* client id, opcode number and message text */
+ opcode = (int)lua_tointeger(L, 2);
+ } else if (lua_isstring(L, 2)) {
+ /* client id, opcode string and message text */
+ str = lua_tostring(L, 2);
+ if (!mg_strncasecmp(str, "text", 4))
+ opcode = WEBSOCKET_OPCODE_TEXT;
+ else if (!mg_strncasecmp(str, "bin", 3))
+ opcode = WEBSOCKET_OPCODE_BINARY;
+ else if (!mg_strncasecmp(str, "close", 5))
+ opcode = WEBSOCKET_OPCODE_CONNECTION_CLOSE;
+ else if (!mg_strncasecmp(str, "ping", 4))
+ opcode = WEBSOCKET_OPCODE_PING;
+ else if (!mg_strncasecmp(str, "pong", 4))
+ opcode = WEBSOCKET_OPCODE_PONG;
+ else if (!mg_strncasecmp(str, "cont", 4))
+ opcode = WEBSOCKET_OPCODE_CONTINUATION;
+ }
+ }
+ }
+
+ if (opcode >= 0 && opcode < 16 && lua_isstring(L, num_args)) {
+ str = lua_tolstring(L, num_args, &size);
+ if (client) {
+ for (i = 0; i < ws->references; i++) {
+ if (client == ws->conn[i]) {
+ mg_websocket_write(ws->conn[i], opcode, str, size);
+ }
+ }
+ } else {
+ for (i = 0; i < ws->references; i++) {
+ mg_websocket_write(ws->conn[i], opcode, str, size);
+ }
+ }
+ } else {
+ (void)pthread_mutex_unlock(&(ws->ws_mutex));
+ return luaL_error(L, "invalid websocket write() call");
+ }
+
+ (void)pthread_mutex_unlock(&(ws->ws_mutex));
+
+#else
+ (void)(L); /* unused */
+#endif
+ return 0;
+}
+
+
+struct laction_arg {
+ lua_State *state;
+ const char *script;
+ pthread_mutex_t *pmutex;
+ char txt[1];
+};
+
+
+static int
+lua_action(struct laction_arg *arg)
+{
+ int err, ok;
+ struct mg_context *ctx;
+
+ (void)pthread_mutex_lock(arg->pmutex);
+
+ lua_pushlightuserdata(arg->state, (void *)&lua_regkey_ctx);
+ lua_gettable(arg->state, LUA_REGISTRYINDEX);
+ ctx = (struct mg_context *)lua_touserdata(arg->state, -1);
+
+ err = luaL_loadstring(arg->state, arg->txt);
+ if (err != 0) {
+ lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
+ (void)pthread_mutex_unlock(arg->pmutex);
+ mg_free(arg);
+ return 0;
+ }
+ err = lua_pcall(arg->state, 0, 1, 0);
+ if (err != 0) {
+ lua_cry(fc(ctx), err, arg->state, arg->script, "timer");
+ (void)pthread_mutex_unlock(arg->pmutex);
+ mg_free(arg);
+ return 0;
+ }
+
+ ok = lua_type(arg->state, -1);
+ if (lua_isboolean(arg->state, -1)) {
+ ok = lua_toboolean(arg->state, -1);
+ } else {
+ ok = 0;
+ }
+ lua_pop(arg->state, 1);
+
+ (void)pthread_mutex_unlock(arg->pmutex);
+
+ if (!ok) {
+ mg_free(arg);
+ }
+ return ok;
+}
+
+
+static int
+lua_action_free(struct laction_arg *arg)
+{
+ if (lua_action(arg)) {
+ mg_free(arg);
+ }
+ return 0;
+}
+
+
+static int
+lwebsocket_set_timer(lua_State *L, int is_periodic)
+{
+#if defined(USE_TIMERS) && defined(USE_WEBSOCKET)
+ int num_args = lua_gettop(L);
+ struct lua_websock_data *ws;
+ int type1, type2, ok = 0;
+ double timediff;
+ struct mg_context *ctx;
+ struct laction_arg *arg;
+ const char *txt;
+ size_t txt_len;
+
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ ctx = (struct mg_context *)lua_touserdata(L, -1);
+
+ lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ ws = (struct lua_websock_data *)lua_touserdata(L, -1);
+
+ if (num_args < 2) {
+ return luaL_error(L,
+ "not enough arguments for set_timer/interval() call");
+ }
+
+ type1 = lua_type(L, 1);
+ type2 = lua_type(L, 2);
+
+ if (type1 == LUA_TSTRING && type2 == LUA_TNUMBER && num_args == 2) {
+ timediff = (double)lua_tonumber(L, 2);
+ txt = lua_tostring(L, 1);
+ txt_len = strlen(txt);
+ arg = (struct laction_arg *)mg_malloc(sizeof(struct laction_arg)
+ + txt_len + 10);
+ arg->state = L;
+ arg->script = ws->script;
+ arg->pmutex = &(ws->ws_mutex);
+ memcpy(arg->txt, "return(", 7);
+ memcpy(arg->txt + 7, txt, txt_len);
+ arg->txt[txt_len + 7] = ')';
+ arg->txt[txt_len + 8] = 0;
+ ok =
+ (0
+ == timer_add(ctx,
+ timediff,
+ is_periodic,
+ 1,
+ (taction)(is_periodic ? lua_action : lua_action_free),
+ (void *)arg));
+ } else if (type1 == LUA_TFUNCTION && type2 == LUA_TNUMBER) {
+ /* TODO (mid): not implemented yet */
+ return luaL_error(L, "invalid arguments for set_timer/interval() call");
+ } else {
+ return luaL_error(L, "invalid arguments for set_timer/interval() call");
+ }
+
+ lua_pushboolean(L, ok);
+ return 1;
+
+#else
+ (void)(L); /* unused */
+ (void)(is_periodic); /* unused */
+ return 0;
+#endif
+}
+
+
+/* mg.set_timeout for websockets */
+static int
+lwebsocket_set_timeout(lua_State *L)
+{
+ return lwebsocket_set_timer(L, 0);
+}
+
+
+/* mg.set_interval for websockets */
+static int
+lwebsocket_set_interval(lua_State *L)
+{
+ return lwebsocket_set_timer(L, 1);
+}
+
+enum {
+ LUA_ENV_TYPE_LUA_SERVER_PAGE = 0,
+ LUA_ENV_TYPE_PLAIN_LUA_PAGE = 1,
+ LUA_ENV_TYPE_LUA_WEBSOCKET = 2,
+};
+
+
+static void
+prepare_lua_request_info(struct mg_connection *conn, lua_State *L)
+{
+ const char *s;
+ int i;
+
+ /* Export mg.request_info */
+ lua_pushstring(L, "request_info");
+ lua_newtable(L);
+ reg_string(L, "request_method", conn->request_info.request_method);
+ reg_string(L, "request_uri", conn->request_info.request_uri);
+ reg_string(L, "uri", conn->request_info.local_uri);
+ reg_string(L, "http_version", conn->request_info.http_version);
+ reg_string(L, "query_string", conn->request_info.query_string);
+#if defined(MG_LEGACY_INTERFACE)
+ reg_int(L, "remote_ip", conn->request_info.remote_ip); /* remote_ip is
+ deprecated, use
+ remote_addr
+ instead */
+#endif
+ reg_string(L, "remote_addr", conn->request_info.remote_addr);
+ /* TODO (high): ip version */
+ reg_int(L, "remote_port", conn->request_info.remote_port);
+ reg_int(L, "num_headers", conn->request_info.num_headers);
+ reg_int(L, "server_port", ntohs(conn->client.lsa.sin.sin_port));
+
+ if (conn->request_info.content_length >= 0) {
+ /* reg_int64: content_length */
+ lua_pushstring(L, "content_length");
+ lua_pushnumber(
+ L,
+ (lua_Number)conn->request_info
+ .content_length); /* lua_Number may be used as 52 bit integer */
+ lua_rawset(L, -3);
+ }
+ if ((s = mg_get_header(conn, "Content-Type")) != NULL) {
+ reg_string(L, "content_type", s);
+ }
+
+ if (conn->request_info.remote_user != NULL) {
+ reg_string(L, "remote_user", conn->request_info.remote_user);
+ reg_string(L, "auth_type", "Digest");
+ }
+
+ reg_boolean(L, "https", conn->ssl != NULL);
+
+ if (conn->status_code > 0) {
+ /* Lua error handler should show the status code */
+ reg_int(L, "status", conn->status_code);
+ }
+
+ lua_pushstring(L, "http_headers");
+ lua_newtable(L);
+ for (i = 0; i < conn->request_info.num_headers; i++) {
+ reg_string(L,
+ conn->request_info.http_headers[i].name,
+ conn->request_info.http_headers[i].value);
+ }
+ lua_rawset(L, -3);
+
+ lua_rawset(L, -3);
+}
+
+
+void
+civetweb_open_lua_libs(lua_State *L)
+{
+ {
+ extern void luaL_openlibs(lua_State *);
+ luaL_openlibs(L);
+ }
+
+#ifdef USE_LUA_SQLITE3
+ {
+ extern int luaopen_lsqlite3(lua_State *);
+ luaopen_lsqlite3(L);
+ }
+#endif
+#ifdef USE_LUA_LUAXML
+ {
+ extern int luaopen_LuaXML_lib(lua_State *);
+ luaopen_LuaXML_lib(L);
+ }
+#endif
+#ifdef USE_LUA_FILE_SYSTEM
+ {
+ extern int luaopen_lfs(lua_State *);
+ luaopen_lfs(L);
+ }
+#endif
+#ifdef USE_LUA_BINARY
+ {
+ /* TODO (low): Test if this could be used as a replacement for bit32.
+ * Check again with Lua 5.3 later. */
+ extern int luaopen_binary(lua_State *);
+
+ luaL_requiref(L, "binary", luaopen_binary, 1);
+ lua_pop(L, 1);
+ }
+#endif
+}
+
+
+static void
+prepare_lua_environment(struct mg_context *ctx,
+ struct mg_connection *conn,
+ struct lua_websock_data *ws_conn_list,
+ lua_State *L,
+ const char *script_name,
+ int lua_env_type)
+{
+ civetweb_open_lua_libs(L);
+
+#if LUA_VERSION_NUM == 502
+ /* Keep the "connect" method for compatibility,
+ * but do not backport it to Lua 5.1.
+ * TODO: Redesign the interface.
+ */
+ luaL_newmetatable(L, LUASOCKET);
+ lua_pushliteral(L, "__index");
+ luaL_newlib(L, luasocket_methods);
+ lua_rawset(L, -3);
+ lua_pop(L, 1);
+ lua_register(L, "connect", lsp_connect);
+#endif
+
+ /* Store context in the registry */
+ if (ctx != NULL) {
+ lua_pushlightuserdata(L, (void *)&lua_regkey_ctx);
+ lua_pushlightuserdata(L, (void *)ctx);
+ lua_settable(L, LUA_REGISTRYINDEX);
+ }
+ if (ws_conn_list != NULL) {
+ lua_pushlightuserdata(L, (void *)&lua_regkey_connlist);
+ lua_pushlightuserdata(L, (void *)ws_conn_list);
+ lua_settable(L, LUA_REGISTRYINDEX);
+ }
+
+ /* Register mg module */
+ lua_newtable(L);
+
+ switch (lua_env_type) {
+ case LUA_ENV_TYPE_LUA_SERVER_PAGE:
+ reg_string(L, "lua_type", "page");
+ break;
+ case LUA_ENV_TYPE_PLAIN_LUA_PAGE:
+ reg_string(L, "lua_type", "script");
+ break;
+ case LUA_ENV_TYPE_LUA_WEBSOCKET:
+ reg_string(L, "lua_type", "websocket");
+ break;
+ }
+
+ if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE
+ || lua_env_type == LUA_ENV_TYPE_PLAIN_LUA_PAGE) {
+ reg_conn_function(L, "cry", lsp_cry, conn);
+ reg_conn_function(L, "read", lsp_read, conn);
+ reg_conn_function(L, "write", lsp_write, conn);
+ reg_conn_function(L, "keep_alive", lsp_keep_alive, conn);
+ reg_conn_function(L, "send_file", lsp_send_file, conn);
+ }
+
+ if (lua_env_type == LUA_ENV_TYPE_LUA_SERVER_PAGE) {
+ reg_conn_function(L, "include", lsp_include, conn);
+ reg_conn_function(L, "redirect", lsp_redirect, conn);
+ }
+
+ if (lua_env_type == LUA_ENV_TYPE_LUA_WEBSOCKET) {
+ reg_function(L, "write", lwebsock_write);
+#ifdef USE_TIMERS
+ reg_function(L, "set_timeout", lwebsocket_set_timeout);
+ reg_function(L, "set_interval", lwebsocket_set_interval);
+#endif
+ /* reg_conn_function(L, "send_file", lsp_send_file, conn); */
+ }
+
+ reg_function(L, "time", lsp_get_time);
+ reg_function(L, "get_var", lsp_get_var);
+ reg_function(L, "get_mime_type", lsp_get_mime_type);
+ reg_function(L, "get_cookie", lsp_get_cookie);
+ reg_function(L, "md5", lsp_md5);
+ reg_function(L, "url_encode", lsp_url_encode);
+ reg_function(L, "url_decode", lsp_url_decode);
+ reg_function(L, "base64_encode", lsp_base64_encode);
+ reg_function(L, "base64_decode", lsp_base64_decode);
+ reg_function(L, "get_response_code_text", lsp_get_response_code_text);
+ reg_function(L, "random", lsp_random);
+ if (pf_uuid_generate.f) {
+ reg_function(L, "uuid", lsp_uuid);
+ }
+
+ reg_string(L, "version", CIVETWEB_VERSION);
+
+ reg_string(L, "script_name", script_name);
+
+ if (ctx != NULL) {
+ reg_string(L, "document_root", ctx->config[DOCUMENT_ROOT]);
+ reg_string(L, "auth_domain", ctx->config[AUTHENTICATION_DOMAIN]);
+#if defined(USE_WEBSOCKET)
+ reg_string(L, "websocket_root", ctx->config[WEBSOCKET_ROOT]);
+#endif
+
+ if (ctx->systemName != NULL) {
+ reg_string(L, "system", ctx->systemName);
+ }
+ }
+
+ /* Export connection specific info */
+ if (conn != NULL) {
+ prepare_lua_request_info(conn, L);
+ }
+
+ lua_setglobal(L, "mg");
+
+ /* Register default mg.onerror function */
+ IGNORE_UNUSED_RESULT(
+ luaL_dostring(L,
+ "mg.onerror = function(e) mg.write('\\nLua error:\\n', "
+ "debug.traceback(e, 1)) end"));
+
+ if (ctx != NULL) {
+ /* Preload */
+ if (ctx->config[LUA_PRELOAD_FILE] != NULL) {
+ IGNORE_UNUSED_RESULT(luaL_dofile(L, ctx->config[LUA_PRELOAD_FILE]));
+ }
+
+ if (ctx->callbacks.init_lua != NULL) {
+ ctx->callbacks.init_lua(conn, L);
+ }
+ }
+}
+
+
+static int
+lua_error_handler(lua_State *L)
+{
+ const char *error_msg = lua_isstring(L, -1) ? lua_tostring(L, -1) : "?\n";
+
+ lua_getglobal(L, "mg");
+ if (!lua_isnil(L, -1)) {
+ lua_getfield(L, -1, "write"); /* call mg.write() */
+ lua_pushstring(L, error_msg);
+ lua_pushliteral(L, "\n");
+ lua_call(L, 2, 0);
+ IGNORE_UNUSED_RESULT(
+ luaL_dostring(L, "mg.write(debug.traceback(), '\\n')"));
+ } else {
+ printf("Lua error: [%s]\n", error_msg);
+ IGNORE_UNUSED_RESULT(
+ luaL_dostring(L, "print(debug.traceback(), '\\n')"));
+ }
+ /* TODO(lsm, low): leave the stack balanced */
+
+ return 0;
+}
+
+
+static void *
+lua_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
+{
+
+ (void)ud;
+ (void)osize; /* not used */
+
+ if (nsize == 0) {
+ mg_free(ptr);
+ return NULL;
+ }
+ return mg_realloc(ptr, nsize);
+}
+
+
+static void
+mg_exec_lua_script(struct mg_connection *conn,
+ const char *path,
+ const void **exports)
+{
+ int i;
+ lua_State *L;
+
+ /* Assume the script does not support keep_alive. The script may change this
+ * by calling mg.keep_alive(true). */
+ conn->must_close = 1;
+
+ /* Execute a plain Lua script. */
+ if (path != NULL && (L = lua_newstate(lua_allocator, NULL)) != NULL) {
+ prepare_lua_environment(
+ conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_PLAIN_LUA_PAGE);
+ lua_pushcclosure(L, &lua_error_handler, 0);
+
+ if (exports != NULL) {
+#if LUA_VERSION_NUM > 501
+ lua_pushglobaltable(L);
+ for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
+ lua_CFunction func;
+ lua_pushstring(L, (const char *)(exports[i]));
+ *(const void **)(&func) = exports[i + 1];
+ lua_pushcclosure(L, func, 0);
+ lua_rawset(L, -3);
+ }
+#else
+ for (i = 0; exports[i] != NULL && exports[i + 1] != NULL; i += 2) {
+ lua_CFunction func;
+ const char *name = (const char *)(exports[i]);
+ *(const void **)(&func) = exports[i + 1];
+ lua_register(L, name, func);
+ }
+#endif
+ }
+
+ if (luaL_loadfile(L, path) != 0) {
+ lua_error_handler(L);
+ }
+ lua_pcall(L, 0, 0, -2);
+ lua_close(L);
+ }
+}
+
+
+static int
+handle_lsp_request(struct mg_connection *conn,
+ const char *path,
+ struct file *filep,
+ struct lua_State *ls)
+{
+ void *p = NULL;
+ lua_State *L = NULL;
+ int error = 1;
+ struct file filesize = STRUCT_FILE_INITIALIZER;
+
+ /* Assume the script does not support keep_alive. The script may change this
+ * by calling mg.keep_alive(true). */
+ conn->must_close = 1;
+
+ /* We need both mg_stat to get file size, and mg_fopen to get fd */
+ if (!mg_stat(conn, path, &filesize)) {
+
+ /* File not found */
+ if (ls == NULL) {
+ send_http_error(conn, 500, "Error: File %s not found", path);
+ } else {
+ luaL_error(ls, "File [%s] not found", path);
+ }
+
+ goto cleanup_handle_lsp_request;
+ }
+
+ if (!mg_fopen(conn, path, "r", filep)) {
+
+ /* File not found or not accessible */
+ if (ls == NULL) {
+ send_http_error(conn,
+ 500,
+ "Error: Cannot open script file %s",
+ path);
+ } else {
+ luaL_error(ls, "Cannot [%s] not found", path);
+ }
+
+ goto cleanup_handle_lsp_request;
+ }
+
+ /* TODO: Operations mg_fopen and mg_stat should do what their names
+ * indicate. They should not fill in different members of the same
+ * struct file.
+ * See Github issue #225 */
+ filep->size = filesize.size;
+
+ if (filep->membuf == NULL
+ && (p = mmap(NULL,
+ (size_t)filep->size,
+ PROT_READ,
+ MAP_PRIVATE,
+ fileno(filep->fp),
+ 0)) == MAP_FAILED) {
+
+ /* mmap failed */
+ if (ls == NULL) {
+ send_http_error(
+ conn,
+ 500,
+ "Error: Cannot open script\nFile %s can not be mapped",
+ path);
+ } else {
+ luaL_error(ls,
+ "mmap(%s, %zu, %d): %s",
+ path,
+ (size_t)filep->size,
+ fileno(filep->fp),
+ strerror(errno));
+ }
+
+ goto cleanup_handle_lsp_request;
+ }
+
+ if (ls != NULL) {
+ L = ls;
+ } else {
+ L = lua_newstate(lua_allocator, NULL);
+ if (L == NULL) {
+ send_http_error(
+ conn,
+ 500,
+ "%s",
+ "Error: Cannot execute script\nlua_newstate failed");
+
+ goto cleanup_handle_lsp_request;
+ }
+ prepare_lua_environment(
+ conn->ctx, conn, NULL, L, path, LUA_ENV_TYPE_LUA_SERVER_PAGE);
+ }
+
+ /* Lua state is ready to use */
+ /* We're not sending HTTP headers here, Lua page must do it. */
+ error = lsp(conn,
+ path,
+ (filep->membuf == NULL) ? (const char *)p
+ : (const char *)filep->membuf,
+ filep->size,
+ L);
+
+
+cleanup_handle_lsp_request:
+
+ if (L != NULL && ls == NULL)
+ lua_close(L);
+ if (p != NULL)
+ munmap(p, filep->size);
+ mg_fclose(filep);
+
+ return error;
+}
+
+
+#ifdef USE_WEBSOCKET
+struct mg_shared_lua_websocket_list {
+ struct lua_websock_data ws;
+ struct mg_shared_lua_websocket_list *next;
+};
+
+
+static void *
+lua_websocket_new(const char *script, struct mg_connection *conn)
+{
+ struct mg_shared_lua_websocket_list **shared_websock_list =
+ &(conn->ctx->shared_lua_websockets);
+ struct lua_websock_data *ws;
+ int err, ok = 0;
+
+ assert(conn->lua_websocket_state == NULL);
+
+ /* lock list (mg_context global) */
+ mg_lock_context(conn->ctx);
+ while (*shared_websock_list) {
+ /* check if ws already in list */
+ if (0 == strcmp(script, (*shared_websock_list)->ws.script)) {
+ break;
+ }
+ shared_websock_list = &((*shared_websock_list)->next);
+ }
+
+ if (*shared_websock_list == NULL) {
+ /* add ws to list */
+ *shared_websock_list = (struct mg_shared_lua_websocket_list *)
+ mg_calloc(sizeof(struct mg_shared_lua_websocket_list), 1);
+ if (*shared_websock_list == NULL) {
+ mg_unlock_context(conn->ctx);
+ mg_cry(conn, "Cannot create shared websocket struct, OOM");
+ return NULL;
+ }
+ /* init ws list element */
+ ws = &(*shared_websock_list)->ws;
+ ws->script = mg_strdup(script); /* TODO (low): handle OOM */
+ pthread_mutex_init(&(ws->ws_mutex), &pthread_mutex_attr);
+ (void)pthread_mutex_lock(&(ws->ws_mutex));
+ ws->state = lua_newstate(lua_allocator, NULL);
+ ws->conn[0] = conn;
+ ws->references = 1;
+ prepare_lua_environment(
+ conn->ctx, NULL, ws, ws->state, script, LUA_ENV_TYPE_LUA_WEBSOCKET);
+ err = luaL_loadfile(ws->state, script);
+ if (err != 0) {
+ lua_cry(conn, err, ws->state, script, "load");
+ }
+ err = lua_pcall(ws->state, 0, 0, 0);
+ if (err != 0) {
+ lua_cry(conn, err, ws->state, script, "init");
+ }
+ } else {
+ /* inc ref count */
+ ws = &(*shared_websock_list)->ws;
+ (void)pthread_mutex_lock(&(ws->ws_mutex));
+ (*shared_websock_list)->ws.conn[(ws->references)++] = conn;
+ }
+ mg_unlock_context(conn->ctx);
+
+ /* call add */
+ lua_getglobal(ws->state, "open");
+ lua_newtable(ws->state);
+ prepare_lua_request_info(conn, ws->state);
+ lua_pushstring(ws->state, "client");
+ lua_pushlightuserdata(ws->state, (void *)conn);
+ lua_rawset(ws->state, -3);
+
+ err = lua_pcall(ws->state, 1, 1, 0);
+ if (err != 0) {
+ lua_cry(conn, err, ws->state, script, "open handler");
+ } else {
+ if (lua_isboolean(ws->state, -1)) {
+ ok = lua_toboolean(ws->state, -1);
+ }
+ lua_pop(ws->state, 1);
+ }
+ if (!ok) {
+ /* Remove from ws connection list. */
+ /* TODO (mid): Check if list entry and Lua state needs to be deleted
+ * (see websocket_close). */
+ (*shared_websock_list)->ws.conn[--(ws->references)] = 0;
+ }
+
+ (void)pthread_mutex_unlock(&(ws->ws_mutex));
+
+ return ok ? (void *)ws : NULL;
+}
+
+
+static int
+lua_websocket_data(struct mg_connection *conn,
+ int bits,
+ char *data,
+ size_t data_len,
+ void *ws_arg)
+{
+ struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+ int err, ok = 0;
+
+ assert(ws != NULL);
+ assert(ws->state != NULL);
+
+ (void)pthread_mutex_lock(&(ws->ws_mutex));
+
+ lua_getglobal(ws->state, "data");
+ lua_newtable(ws->state);
+ lua_pushstring(ws->state, "client");
+ lua_pushlightuserdata(ws->state, (void *)conn);
+ lua_rawset(ws->state, -3);
+ lua_pushstring(ws->state, "bits"); /* TODO: dont use "bits" but fields with
+ a meaning according to
+ http://tools.ietf.org/html/rfc6455,
+ section 5.2 */
+ lua_pushnumber(ws->state, bits);
+ lua_rawset(ws->state, -3);
+ lua_pushstring(ws->state, "data");
+ lua_pushlstring(ws->state, data, data_len);
+ lua_rawset(ws->state, -3);
+
+ err = lua_pcall(ws->state, 1, 1, 0);
+ if (err != 0) {
+ lua_cry(conn, err, ws->state, ws->script, "data handler");
+ } else {
+ if (lua_isboolean(ws->state, -1)) {
+ ok = lua_toboolean(ws->state, -1);
+ }
+ lua_pop(ws->state, 1);
+ }
+ (void)pthread_mutex_unlock(&(ws->ws_mutex));
+
+ return ok;
+}
+
+
+static int
+lua_websocket_ready(struct mg_connection *conn, void *ws_arg)
+{
+ struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+ int err, ok = 0;
+
+ assert(ws != NULL);
+ assert(ws->state != NULL);
+
+ (void)pthread_mutex_lock(&(ws->ws_mutex));
+
+ lua_getglobal(ws->state, "ready");
+ lua_newtable(ws->state);
+ lua_pushstring(ws->state, "client");
+ lua_pushlightuserdata(ws->state, (void *)conn);
+ lua_rawset(ws->state, -3);
+ err = lua_pcall(ws->state, 1, 1, 0);
+ if (err != 0) {
+ lua_cry(conn, err, ws->state, ws->script, "ready handler");
+ } else {
+ if (lua_isboolean(ws->state, -1)) {
+ ok = lua_toboolean(ws->state, -1);
+ }
+ lua_pop(ws->state, 1);
+ }
+
+ (void)pthread_mutex_unlock(&(ws->ws_mutex));
+
+ return ok;
+}
+
+
+static void
+lua_websocket_close(struct mg_connection *conn, void *ws_arg)
+{
+ struct lua_websock_data *ws = (struct lua_websock_data *)(ws_arg);
+ struct mg_shared_lua_websocket_list **shared_websock_list =
+ &(conn->ctx->shared_lua_websockets);
+ int err = 0;
+ unsigned i;
+
+ assert(ws != NULL);
+ assert(ws->state != NULL);
+
+ (void)pthread_mutex_lock(&(ws->ws_mutex));
+
+ lua_getglobal(ws->state, "close");
+ lua_newtable(ws->state);
+ lua_pushstring(ws->state, "client");
+ lua_pushlightuserdata(ws->state, (void *)conn);
+ lua_rawset(ws->state, -3);
+
+ err = lua_pcall(ws->state, 1, 0, 0);
+ if (err != 0) {
+ lua_cry(conn, err, ws->state, ws->script, "close handler");
+ }
+ for (i = 0; i < ws->references; i++) {
+ if (ws->conn[i] == conn) {
+ ws->references--;
+ ws->conn[i] = ws->conn[ws->references];
+ }
+ }
+ /* TODO: Delete lua_websock_data and remove it from the websocket list.
+ This must only be done, when all connections are closed, and all
+ asynchronous operations and timers are completed/expired. */
+ (void)shared_websock_list; /* shared_websock_list unused (see open TODO) */
+
+ (void)pthread_mutex_unlock(&(ws->ws_mutex));
+}
+#endif
+
+
+static void
+lua_init_optional_libraries(void)
+{
+#if !defined(_WIN32)
+ void *dll_handle = dlopen("libuuid.so", RTLD_LAZY);
+ pf_uuid_generate.p = dlsym(dll_handle, "uuid_generate");
+#else
+ pf_uuid_generate.p = 0;
+#endif
+}
--- /dev/null
+
+#if !defined(MAX_TIMERS)
+#define MAX_TIMERS MAX_WORKER_THREADS
+#endif
+
+typedef int (*taction)(void *arg);
+
+struct ttimer {
+ double time;
+ double period;
+ taction action;
+ void *arg;
+};
+
+struct ttimers {
+ pthread_t threadid; /* Timer thread ID */
+ pthread_mutex_t mutex; /* Protects timer lists */
+ struct ttimer timers[MAX_TIMERS]; /* List of timers */
+ unsigned timer_count; /* Current size of timer list */
+};
+
+static int
+timer_add(struct mg_context *ctx,
+ double next_time,
+ double period,
+ int is_relative,
+ taction action,
+ void *arg)
+{
+ unsigned u, v;
+ int error = 0;
+ struct timespec now;
+
+ if (ctx->stop_flag) {
+ return 0;
+ }
+
+ if (is_relative) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ next_time += now.tv_sec;
+ next_time += now.tv_nsec * 1.0E-9;
+ }
+
+ pthread_mutex_lock(&ctx->timers->mutex);
+ if (ctx->timers->timer_count == MAX_TIMERS) {
+ error = 1;
+ } else {
+ for (u = 0; u < ctx->timers->timer_count; u++) {
+ if (ctx->timers->timers[u].time < next_time) {
+ for (v = ctx->timers->timer_count; v > u; v--) {
+ ctx->timers->timers[v] = ctx->timers->timers[v - 1];
+ }
+ break;
+ }
+ }
+ ctx->timers->timers[u].time = next_time;
+ ctx->timers->timers[u].period = period;
+ ctx->timers->timers[u].action = action;
+ ctx->timers->timers[u].arg = arg;
+ ctx->timers->timer_count++;
+ }
+ pthread_mutex_unlock(&ctx->timers->mutex);
+ return error;
+}
+
+static void
+timer_thread_run(void *thread_func_param)
+{
+ struct mg_context *ctx = (struct mg_context *)thread_func_param;
+ struct timespec now;
+ double d;
+ unsigned u;
+ int re_schedule;
+ struct ttimer t;
+
+ mg_set_thread_name("timer");
+
+ if (ctx->callbacks.init_thread) {
+ /* Timer thread */
+ ctx->callbacks.init_thread(ctx, 2);
+ }
+
+#if defined(HAVE_CLOCK_NANOSLEEP) /* Linux with librt */
+ /* TODO */
+ while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &request, &request)
+ == EINTR) { /*nop*/
+ ;
+ }
+#else
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
+ while (ctx->stop_flag == 0) {
+ pthread_mutex_lock(&ctx->timers->mutex);
+ if (ctx->timers->timer_count > 0 && d >= ctx->timers->timers[0].time) {
+ t = ctx->timers->timers[0];
+ for (u = 1; u < ctx->timers->timer_count; u++) {
+ ctx->timers->timers[u - 1] = ctx->timers->timers[u];
+ }
+ ctx->timers->timer_count--;
+ pthread_mutex_unlock(&ctx->timers->mutex);
+ re_schedule = t.action(t.arg);
+ if (re_schedule && (t.period > 0)) {
+ timer_add(ctx, t.time + t.period, t.period, 0, t.action, t.arg);
+ }
+ continue;
+ } else {
+ pthread_mutex_unlock(&ctx->timers->mutex);
+ }
+ mg_sleep(1);
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ d = (double)now.tv_sec + (double)now.tv_nsec * 1.0E-9;
+ }
+#endif
+}
+
+#ifdef _WIN32
+static unsigned __stdcall timer_thread(void *thread_func_param)
+{
+ timer_thread_run(thread_func_param);
+ return 0;
+}
+#else
+static void *
+timer_thread(void *thread_func_param)
+{
+ timer_thread_run(thread_func_param);
+ return NULL;
+}
+#endif /* _WIN32 */
+
+static int
+timers_init(struct mg_context *ctx)
+{
+ ctx->timers = (struct ttimers *)mg_calloc(sizeof(struct ttimers), 1);
+ (void)pthread_mutex_init(&ctx->timers->mutex, NULL);
+
+ /* Start timer thread */
+ mg_start_thread_with_id(timer_thread, ctx, &ctx->timers->threadid);
+
+ return 0;
+}
+
+static void
+timers_exit(struct mg_context *ctx)
+{
+ if (ctx->timers) {
+ (void)pthread_mutex_destroy(&ctx->timers->mutex);
+ mg_free(ctx->timers);
+ }
+}
--- /dev/null
+
+Licensing of XZ Embedded
+========================
+
+ All the files in this package have been written by Lasse Collin
+ and/or Igor Pavlov. All these files have been put into the
+ public domain. You can do whatever you want with these files.
+
+ As usual, this software is provided "as is", without any warranty.
+
--- /dev/null
+
+XZ Embedded
+===========
+
+ XZ Embedded is a relatively small, limited implementation of the .xz
+ file format. Currently only decoding is implemented.
+
+ XZ Embedded was written for use in the Linux kernel, but the code can
+ be easily used in other environments too, including regular userspace
+ applications. See userspace/xzminidec.c for an example program.
+
+ This README contains information that is useful only when the copy
+ of XZ Embedded isn't part of the Linux kernel tree. You should also
+ read linux/Documentation/xz.txt even if you aren't using XZ Embedded
+ as part of Linux; information in that file is not repeated in this
+ README.
+
+Compiling the Linux kernel module
+
+ The xz_dec module depends on crc32 module, so make sure that you have
+ it enabled (CONFIG_CRC32).
+
+ Building the xz_dec and xz_dec_test modules without support for BCJ
+ filters:
+
+ cd linux/lib/xz
+ make -C /path/to/kernel/source \
+ KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \
+ CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m
+
+ Building the xz_dec and xz_dec_test modules with support for BCJ
+ filters:
+
+ cd linux/lib/xz
+ make -C /path/to/kernel/source \
+ KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \
+ CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m CONFIG_XZ_DEC_BCJ=y \
+ CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y \
+ CONFIG_XZ_DEC_IA64=y CONFIG_XZ_DEC_ARM=y \
+ CONFIG_XZ_DEC_ARMTHUMB=y CONFIG_XZ_DEC_SPARC=y
+
+ If you want only one or a few of the BCJ filters, omit the appropriate
+ variables. CONFIG_XZ_DEC_BCJ=y is always required to build the support
+ code shared between all BCJ filters.
+
+ Most people don't need the xz_dec_test module. You can skip building
+ it by omitting CONFIG_XZ_DEC_TEST=m from the make command line.
+
+Compiler requirements
+
+ XZ Embedded should compile as either GNU-C89 (used in the Linux
+ kernel) or with any C99 compiler. Getting the code to compile with
+ non-GNU C89 compiler or a C++ compiler should be quite easy as
+ long as there is a data type for unsigned 64-bit integer (or the
+ code is modified not to support large files, which needs some more
+ care than just using 32-bit integer instead of 64-bit).
+
+ If you use GCC, try to use a recent version. For example, on x86-32,
+ xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when
+ compiled with GCC 4.3.3.
+
+Embedding into userspace applications
+
+ To embed the XZ decoder, copy the following files into a single
+ directory in your source code tree:
+
+ linux/include/linux/xz.h
+ linux/lib/xz/xz_crc32.c
+ linux/lib/xz/xz_dec_lzma2.c
+ linux/lib/xz/xz_dec_stream.c
+ linux/lib/xz/xz_lzma2.h
+ linux/lib/xz/xz_private.h
+ linux/lib/xz/xz_stream.h
+ userspace/xz_config.h
+
+ Alternatively, xz.h may be placed into a different directory but then
+ that directory must be in the compiler include path when compiling
+ the .c files.
+
+ Your code should use only the functions declared in xz.h. The rest of
+ the .h files are meant only for internal use in XZ Embedded.
+
+ You may want to modify xz_config.h to be more suitable for your build
+ environment. Probably you should at least skim through it even if the
+ default file works as is.
+
+Integrity check support
+
+ XZ Embedded always supports the integrity check types None and
+ CRC32. Support for CRC64 is optional. SHA-256 is currently not
+ supported in XZ Embedded although the .xz format does support it.
+ The xz tool from XZ Utils uses CRC64 by default, but CRC32 is usually
+ enough in embedded systems to keep the code size smaller.
+
+ If you want support for CRC64, you need to copy linux/lib/xz/xz_crc64.c
+ into your application, and #define XZ_USE_CRC64 in xz_config.h or in
+ compiler flags.
+
+ When using the internal CRC32 or CRC64, their lookup tables need to be
+ initialized with xz_crc32_init() and xz_crc64_init(), respectively.
+ See xz.h for details.
+
+ To use external CRC32 or CRC64 code instead of the code from
+ xz_crc32.c or xz_crc64.c, the following #defines may be used
+ in xz_config.h or in compiler flags:
+
+ #define XZ_INTERNAL_CRC32 0
+ #define XZ_INTERNAL_CRC64 0
+
+ Then it is up to you to provide compatible xz_crc32() or xz_crc64()
+ functions.
+
+ If the .xz file being decompressed uses an integrity check type that
+ isn't supported by XZ Embedded, it is treated as an error and the
+ file cannot be decompressed. For multi-call mode, this can be modified
+ by #defining XZ_DEC_ANY_CHECK. Then xz_dec_run() will return
+ XZ_UNSUPPORTED_CHECK when unsupported check type is detected. After
+ that decompression can be continued normally except that the
+ integrity check won't be verified. In single-call mode there's
+ no way to continue decoding, so XZ_DEC_ANY_CHECK is almost useless
+ in single-call mode.
+
+BCJ filter support
+
+ If you want support for one or more BCJ filters, you need to copy also
+ linux/lib/xz/xz_dec_bcj.c into your application, and use appropriate
+ #defines in xz_config.h or in compiler flags. You don't need these
+ #defines in the code that just uses XZ Embedded via xz.h, but having
+ them always #defined doesn't hurt either.
+
+ #define Instruction set BCJ filter endianness
+ XZ_DEC_X86 x86-32 or x86-64 Little endian only
+ XZ_DEC_POWERPC PowerPC Big endian only
+ XZ_DEC_IA64 Itanium (IA-64) Big or little endian
+ XZ_DEC_ARM ARM Little endian only
+ XZ_DEC_ARMTHUMB ARM-Thumb Little endian only
+ XZ_DEC_SPARC SPARC Big or little endian
+
+ While some architectures are (partially) bi-endian, the endianness
+ setting doesn't change the endianness of the instructions on all
+ architectures. That's why Itanium and SPARC filters work for both big
+ and little endian executables (Itanium has little endian instructions
+ and SPARC has big endian instructions).
+
+ There currently is no filter for little endian PowerPC or big endian
+ ARM or ARM-Thumb. Implementing filters for them can be considered if
+ there is a need for such filters in real-world applications.
+
+Notes about shared libraries
+
+ If you are including XZ Embedded into a shared library, you very
+ probably should rename the xz_* functions to prevent symbol
+ conflicts in case your library is linked against some other library
+ or application that also has XZ Embedded in it (which may even be
+ a different version of XZ Embedded). TODO: Provide an easy way
+ to do this.
+
+ Please don't create a shared library of XZ Embedded itself unless
+ it is fine to rebuild everything depending on that shared library
+ everytime you upgrade to a newer version of XZ Embedded. There are
+ no API or ABI stability guarantees between different versions of
+ XZ Embedded.
+
--- /dev/null
+
+XZ data compression in Linux
+============================
+
+Introduction
+
+ XZ is a general purpose data compression format with high compression
+ ratio and relatively fast decompression. The primary compression
+ algorithm (filter) is LZMA2. Additional filters can be used to improve
+ compression ratio even further. E.g. Branch/Call/Jump (BCJ) filters
+ improve compression ratio of executable data.
+
+ The XZ decompressor in Linux is called XZ Embedded. It supports
+ the LZMA2 filter and optionally also BCJ filters. CRC32 is supported
+ for integrity checking. The home page of XZ Embedded is at
+ <http://tukaani.org/xz/embedded.html>, where you can find the
+ latest version and also information about using the code outside
+ the Linux kernel.
+
+ For userspace, XZ Utils provide a zlib-like compression library
+ and a gzip-like command line tool. XZ Utils can be downloaded from
+ <http://tukaani.org/xz/>.
+
+XZ related components in the kernel
+
+ The xz_dec module provides XZ decompressor with single-call (buffer
+ to buffer) and multi-call (stateful) APIs. The usage of the xz_dec
+ module is documented in include/linux/xz.h.
+
+ The xz_dec_test module is for testing xz_dec. xz_dec_test is not
+ useful unless you are hacking the XZ decompressor. xz_dec_test
+ allocates a char device major dynamically to which one can write
+ .xz files from userspace. The decompressed output is thrown away.
+ Keep an eye on dmesg to see diagnostics printed by xz_dec_test.
+ See the xz_dec_test source code for the details.
+
+ For decompressing the kernel image, initramfs, and initrd, there
+ is a wrapper function in lib/decompress_unxz.c. Its API is the
+ same as in other decompress_*.c files, which is defined in
+ include/linux/decompress/generic.h.
+
+ scripts/xz_wrap.sh is a wrapper for the xz command line tool found
+ from XZ Utils. The wrapper sets compression options to values suitable
+ for compressing the kernel image.
+
+ For kernel makefiles, two commands are provided for use with
+ $(call if_needed). The kernel image should be compressed with
+ $(call if_needed,xzkern) which will use a BCJ filter and a big LZMA2
+ dictionary. It will also append a four-byte trailer containing the
+ uncompressed size of the file, which is needed by the boot code.
+ Other things should be compressed with $(call if_needed,xzmisc)
+ which will use no BCJ filter and 1 MiB LZMA2 dictionary.
+
+Notes on compression options
+
+ Since the XZ Embedded supports only streams with no integrity check or
+ CRC32, make sure that you don't use some other integrity check type
+ when encoding files that are supposed to be decoded by the kernel. With
+ liblzma, you need to use either LZMA_CHECK_NONE or LZMA_CHECK_CRC32
+ when encoding. With the xz command line tool, use --check=none or
+ --check=crc32.
+
+ Using CRC32 is strongly recommended unless there is some other layer
+ which will verify the integrity of the uncompressed data anyway.
+ Double checking the integrity would probably be waste of CPU cycles.
+ Note that the headers will always have a CRC32 which will be validated
+ by the decoder; you can only change the integrity check type (or
+ disable it) for the actual uncompressed data.
+
+ In userspace, LZMA2 is typically used with dictionary sizes of several
+ megabytes. The decoder needs to have the dictionary in RAM, thus big
+ dictionaries cannot be used for files that are intended to be decoded
+ by the kernel. 1 MiB is probably the maximum reasonable dictionary
+ size for in-kernel use (maybe more is OK for initramfs). The presets
+ in XZ Utils may not be optimal when creating files for the kernel,
+ so don't hesitate to use custom settings. Example:
+
+ xz --check=crc32 --lzma2=dict=512KiB inputfile
+
+ An exception to above dictionary size limitation is when the decoder
+ is used in single-call mode. Decompressing the kernel itself is an
+ example of this situation. In single-call mode, the memory usage
+ doesn't depend on the dictionary size, and it is perfectly fine to
+ use a big dictionary: for maximum compression, the dictionary should
+ be at least as big as the uncompressed data itself.
+
+Future plans
+
+ Creating a limited XZ encoder may be considered if people think it is
+ useful. LZMA2 is slower to compress than e.g. Deflate or LZO even at
+ the fastest settings, so it isn't clear if LZMA2 encoder is wanted
+ into the kernel.
+
+ Support for limited random-access reading is planned for the
+ decompression code. I don't know if it could have any use in the
+ kernel, but I know that it would be useful in some embedded projects
+ outside the Linux kernel.
+
+Conformance to the .xz file format specification
+
+ There are a couple of corner cases where things have been simplified
+ at expense of detecting errors as early as possible. These should not
+ matter in practice all, since they don't cause security issues. But
+ it is good to know this if testing the code e.g. with the test files
+ from XZ Utils.
+
+Reporting bugs
+
+ Before reporting a bug, please check that it's not fixed already
+ at upstream. See <http://tukaani.org/xz/embedded.html> to get the
+ latest code.
+
+ Report bugs to <lasse.collin@tukaani.org> or visit #tukaani on
+ Freenode and talk to Larhzu. I don't actively read LKML or other
+ kernel-related mailing lists, so if there's something I should know,
+ you should email to me personally or use IRC.
+
+ Don't bother Igor Pavlov with questions about the XZ implementation
+ in the kernel or about XZ Utils. While these two implementations
+ include essential code that is directly based on Igor Pavlov's code,
+ these implementations aren't maintained nor supported by him.
+
--- /dev/null
+/*
+ * Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef DECOMPRESS_UNXZ_H
+#define DECOMPRESS_UNXZ_H
+
+int unxz(unsigned char *in, int in_size,
+ int (*fill)(void *dest, unsigned int size),
+ int (*flush)(void *src, unsigned int size),
+ unsigned char *out, int *in_used,
+ void (*error)(char *x));
+
+#endif
--- /dev/null
+/*
+ * XZ decompressor
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_H
+#define XZ_H
+
+#ifdef __KERNEL__
+# include <linux/stddef.h>
+# include <linux/types.h>
+#else
+# include <stddef.h>
+# include <stdint.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* In Linux, this is used to make extern functions static when needed. */
+#ifndef XZ_EXTERN
+# define XZ_EXTERN extern
+#endif
+
+/**
+ * enum xz_mode - Operation mode
+ *
+ * @XZ_SINGLE: Single-call mode. This uses less RAM than
+ * than multi-call modes, because the LZMA2
+ * dictionary doesn't need to be allocated as
+ * part of the decoder state. All required data
+ * structures are allocated at initialization,
+ * so xz_dec_run() cannot return XZ_MEM_ERROR.
+ * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2
+ * dictionary buffer. All data structures are
+ * allocated at initialization, so xz_dec_run()
+ * cannot return XZ_MEM_ERROR.
+ * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is
+ * allocated once the required size has been
+ * parsed from the stream headers. If the
+ * allocation fails, xz_dec_run() will return
+ * XZ_MEM_ERROR.
+ *
+ * It is possible to enable support only for a subset of the above
+ * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC,
+ * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled
+ * with support for all operation modes, but the preboot code may
+ * be built with fewer features to minimize code size.
+ */
+enum xz_mode {
+ XZ_SINGLE,
+ XZ_PREALLOC,
+ XZ_DYNALLOC
+};
+
+/**
+ * enum xz_ret - Return codes
+ * @XZ_OK: Everything is OK so far. More input or more
+ * output space is required to continue. This
+ * return code is possible only in multi-call mode
+ * (XZ_PREALLOC or XZ_DYNALLOC).
+ * @XZ_STREAM_END: Operation finished successfully.
+ * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
+ * is still possible in multi-call mode by simply
+ * calling xz_dec_run() again.
+ * Note that this return value is used only if
+ * XZ_DEC_ANY_CHECK was defined at build time,
+ * which is not used in the kernel. Unsupported
+ * check types return XZ_OPTIONS_ERROR if
+ * XZ_DEC_ANY_CHECK was not defined at build time.
+ * @XZ_MEM_ERROR: Allocating memory failed. This return code is
+ * possible only if the decoder was initialized
+ * with XZ_DYNALLOC. The amount of memory that was
+ * tried to be allocated was no more than the
+ * dict_max argument given to xz_dec_init().
+ * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than
+ * allowed by the dict_max argument given to
+ * xz_dec_init(). This return value is possible
+ * only in multi-call mode (XZ_PREALLOC or
+ * XZ_DYNALLOC); the single-call mode (XZ_SINGLE)
+ * ignores the dict_max argument.
+ * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic
+ * bytes).
+ * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
+ * compression options. In the decoder this means
+ * that the header CRC32 matches, but the header
+ * itself specifies something that we don't support.
+ * @XZ_DATA_ERROR: Compressed data is corrupt.
+ * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly
+ * different between multi-call and single-call
+ * mode; more information below.
+ *
+ * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls
+ * to XZ code cannot consume any input and cannot produce any new output.
+ * This happens when there is no new input available, or the output buffer
+ * is full while at least one output byte is still pending. Assuming your
+ * code is not buggy, you can get this error only when decoding a compressed
+ * stream that is truncated or otherwise corrupt.
+ *
+ * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer
+ * is too small or the compressed input is corrupt in a way that makes the
+ * decoder produce more output than the caller expected. When it is
+ * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR
+ * is used instead of XZ_BUF_ERROR.
+ */
+enum xz_ret {
+ XZ_OK,
+ XZ_STREAM_END,
+ XZ_UNSUPPORTED_CHECK,
+ XZ_MEM_ERROR,
+ XZ_MEMLIMIT_ERROR,
+ XZ_FORMAT_ERROR,
+ XZ_OPTIONS_ERROR,
+ XZ_DATA_ERROR,
+ XZ_BUF_ERROR
+};
+
+/**
+ * struct xz_buf - Passing input and output buffers to XZ code
+ * @in: Beginning of the input buffer. This may be NULL if and only
+ * if in_pos is equal to in_size.
+ * @in_pos: Current position in the input buffer. This must not exceed
+ * in_size.
+ * @in_size: Size of the input buffer
+ * @out: Beginning of the output buffer. This may be NULL if and only
+ * if out_pos is equal to out_size.
+ * @out_pos: Current position in the output buffer. This must not exceed
+ * out_size.
+ * @out_size: Size of the output buffer
+ *
+ * Only the contents of the output buffer from out[out_pos] onward, and
+ * the variables in_pos and out_pos are modified by the XZ code.
+ */
+struct xz_buf {
+ const uint8_t *in;
+ size_t in_pos;
+ size_t in_size;
+
+ uint8_t *out;
+ size_t out_pos;
+ size_t out_size;
+};
+
+/**
+ * struct xz_dec - Opaque type to hold the XZ decoder state
+ */
+struct xz_dec;
+
+/**
+ * xz_dec_init() - Allocate and initialize a XZ decoder state
+ * @mode: Operation mode
+ * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for
+ * multi-call decoding. This is ignored in single-call mode
+ * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes
+ * or 2^n + 2^(n-1) bytes (the latter sizes are less common
+ * in practice), so other values for dict_max don't make sense.
+ * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB,
+ * 512 KiB, and 1 MiB are probably the only reasonable values,
+ * except for kernel and initramfs images where a bigger
+ * dictionary can be fine and useful.
+ *
+ * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at
+ * once. The caller must provide enough output space or the decoding will
+ * fail. The output space is used as the dictionary buffer, which is why
+ * there is no need to allocate the dictionary as part of the decoder's
+ * internal state.
+ *
+ * Because the output buffer is used as the workspace, streams encoded using
+ * a big dictionary are not a problem in single-call mode. It is enough that
+ * the output buffer is big enough to hold the actual uncompressed data; it
+ * can be smaller than the dictionary size stored in the stream headers.
+ *
+ * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes
+ * of memory is preallocated for the LZMA2 dictionary. This way there is no
+ * risk that xz_dec_run() could run out of memory, since xz_dec_run() will
+ * never allocate any memory. Instead, if the preallocated dictionary is too
+ * small for decoding the given input stream, xz_dec_run() will return
+ * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be
+ * decoded to avoid allocating excessive amount of memory for the dictionary.
+ *
+ * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC):
+ * dict_max specifies the maximum allowed dictionary size that xz_dec_run()
+ * may allocate once it has parsed the dictionary size from the stream
+ * headers. This way excessive allocations can be avoided while still
+ * limiting the maximum memory usage to a sane value to prevent running the
+ * system out of memory when decompressing streams from untrusted sources.
+ *
+ * On success, xz_dec_init() returns a pointer to struct xz_dec, which is
+ * ready to be used with xz_dec_run(). If memory allocation fails,
+ * xz_dec_init() returns NULL.
+ */
+XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max);
+
+/**
+ * xz_dec_run() - Run the XZ decoder
+ * @s: Decoder state allocated using xz_dec_init()
+ * @b: Input and output buffers
+ *
+ * The possible return values depend on build options and operation mode.
+ * See enum xz_ret for details.
+ *
+ * Note that if an error occurs in single-call mode (return value is not
+ * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the
+ * contents of the output buffer from b->out[b->out_pos] onward are
+ * undefined. This is true even after XZ_BUF_ERROR, because with some filter
+ * chains, there may be a second pass over the output buffer, and this pass
+ * cannot be properly done if the output buffer is truncated. Thus, you
+ * cannot give the single-call decoder a too small buffer and then expect to
+ * get that amount valid data from the beginning of the stream. You must use
+ * the multi-call decoder if you don't want to uncompress the whole stream.
+ */
+XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
+
+/**
+ * xz_dec_reset() - Reset an already allocated decoder state
+ * @s: Decoder state allocated using xz_dec_init()
+ *
+ * This function can be used to reset the multi-call decoder state without
+ * freeing and reallocating memory with xz_dec_end() and xz_dec_init().
+ *
+ * In single-call mode, xz_dec_reset() is always called in the beginning of
+ * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in
+ * multi-call mode.
+ */
+XZ_EXTERN void xz_dec_reset(struct xz_dec *s);
+
+/**
+ * xz_dec_end() - Free the memory allocated for the decoder state
+ * @s: Decoder state allocated using xz_dec_init(). If s is NULL,
+ * this function does nothing.
+ */
+XZ_EXTERN void xz_dec_end(struct xz_dec *s);
+
+/*
+ * Standalone build (userspace build or in-kernel build for boot time use)
+ * needs a CRC32 implementation. For normal in-kernel use, kernel's own
+ * CRC32 module is used instead, and users of this module don't need to
+ * care about the functions below.
+ */
+#ifndef XZ_INTERNAL_CRC32
+# ifdef __KERNEL__
+# define XZ_INTERNAL_CRC32 0
+# else
+# define XZ_INTERNAL_CRC32 1
+# endif
+#endif
+
+/*
+ * If CRC64 support has been enabled with XZ_USE_CRC64, a CRC64
+ * implementation is needed too.
+ */
+#ifndef XZ_USE_CRC64
+# undef XZ_INTERNAL_CRC64
+# define XZ_INTERNAL_CRC64 0
+#endif
+#ifndef XZ_INTERNAL_CRC64
+# ifdef __KERNEL__
+# error Using CRC64 in the kernel has not been implemented.
+# else
+# define XZ_INTERNAL_CRC64 1
+# endif
+#endif
+
+#if XZ_INTERNAL_CRC32
+/*
+ * This must be called before any other xz_* function to initialize
+ * the CRC32 lookup table.
+ */
+XZ_EXTERN void xz_crc32_init(void);
+
+/*
+ * Update CRC32 value using the polynomial from IEEE-802.3. To start a new
+ * calculation, the third argument must be zero. To continue the calculation,
+ * the previously returned value is passed as the third argument.
+ */
+XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc);
+#endif
+
+#if XZ_INTERNAL_CRC64
+/*
+ * This must be called before any other xz_* function (except xz_crc32_init())
+ * to initialize the CRC64 lookup table.
+ */
+XZ_EXTERN void xz_crc64_init(void);
+
+/*
+ * Update CRC64 value using the polynomial from ECMA-182. To start a new
+ * calculation, the third argument must be zero. To continue the calculation,
+ * the previously returned value is passed as the third argument.
+ */
+XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+/*
+ * Important notes about in-place decompression
+ *
+ * At least on x86, the kernel is decompressed in place: the compressed data
+ * is placed to the end of the output buffer, and the decompressor overwrites
+ * most of the compressed data. There must be enough safety margin to
+ * guarantee that the write position is always behind the read position.
+ *
+ * The safety margin for XZ with LZMA2 or BCJ+LZMA2 is calculated below.
+ * Note that the margin with XZ is bigger than with Deflate (gzip)!
+ *
+ * The worst case for in-place decompression is that the beginning of
+ * the file is compressed extremely well, and the rest of the file is
+ * uncompressible. Thus, we must look for worst-case expansion when the
+ * compressor is encoding uncompressible data.
+ *
+ * The structure of the .xz file in case of a compresed kernel is as follows.
+ * Sizes (as bytes) of the fields are in parenthesis.
+ *
+ * Stream Header (12)
+ * Block Header:
+ * Block Header (8-12)
+ * Compressed Data (N)
+ * Block Padding (0-3)
+ * CRC32 (4)
+ * Index (8-20)
+ * Stream Footer (12)
+ *
+ * Normally there is exactly one Block, but let's assume that there are
+ * 2-4 Blocks just in case. Because Stream Header and also Block Header
+ * of the first Block don't make the decompressor produce any uncompressed
+ * data, we can ignore them from our calculations. Block Headers of possible
+ * additional Blocks have to be taken into account still. With these
+ * assumptions, it is safe to assume that the total header overhead is
+ * less than 128 bytes.
+ *
+ * Compressed Data contains LZMA2 or BCJ+LZMA2 encoded data. Since BCJ
+ * doesn't change the size of the data, it is enough to calculate the
+ * safety margin for LZMA2.
+ *
+ * LZMA2 stores the data in chunks. Each chunk has a header whose size is
+ * a maximum of 6 bytes, but to get round 2^n numbers, let's assume that
+ * the maximum chunk header size is 8 bytes. After the chunk header, there
+ * may be up to 64 KiB of actual payload in the chunk. Often the payload is
+ * quite a bit smaller though; to be safe, let's assume that an average
+ * chunk has only 32 KiB of payload.
+ *
+ * The maximum uncompressed size of the payload is 2 MiB. The minimum
+ * uncompressed size of the payload is in practice never less than the
+ * payload size itself. The LZMA2 format would allow uncompressed size
+ * to be less than the payload size, but no sane compressor creates such
+ * files. LZMA2 supports storing uncompressible data in uncompressed form,
+ * so there's never a need to create payloads whose uncompressed size is
+ * smaller than the compressed size.
+ *
+ * The assumption, that the uncompressed size of the payload is never
+ * smaller than the payload itself, is valid only when talking about
+ * the payload as a whole. It is possible that the payload has parts where
+ * the decompressor consumes more input than it produces output. Calculating
+ * the worst case for this would be tricky. Instead of trying to do that,
+ * let's simply make sure that the decompressor never overwrites any bytes
+ * of the payload which it is currently reading.
+ *
+ * Now we have enough information to calculate the safety margin. We need
+ * - 128 bytes for the .xz file format headers;
+ * - 8 bytes per every 32 KiB of uncompressed size (one LZMA2 chunk header
+ * per chunk, each chunk having average payload size of 32 KiB); and
+ * - 64 KiB (biggest possible LZMA2 chunk payload size) to make sure that
+ * the decompressor never overwrites anything from the LZMA2 chunk
+ * payload it is currently reading.
+ *
+ * We get the following formula:
+ *
+ * safety_margin = 128 + uncompressed_size * 8 / 32768 + 65536
+ * = 128 + (uncompressed_size >> 12) + 65536
+ *
+ * For comparison, according to arch/x86/boot/compressed/misc.c, the
+ * equivalent formula for Deflate is this:
+ *
+ * safety_margin = 18 + (uncompressed_size >> 12) + 32768
+ *
+ * Thus, when updating Deflate-only in-place kernel decompressor to
+ * support XZ, the fixed overhead has to be increased from 18+32768 bytes
+ * to 128+65536 bytes.
+ */
+
+/*
+ * STATIC is defined to "static" if we are being built for kernel
+ * decompression (pre-boot code). <linux/decompress/mm.h> will define
+ * STATIC to empty if it wasn't already defined. Since we will need to
+ * know later if we are being used for kernel decompression, we define
+ * XZ_PREBOOT here.
+ */
+#ifdef STATIC
+# define XZ_PREBOOT
+#endif
+#ifdef __KERNEL__
+# include <linux/decompress/mm.h>
+#endif
+#define XZ_EXTERN STATIC
+
+#ifndef XZ_PREBOOT
+# include <linux/slab.h>
+# include <linux/xz.h>
+#else
+/*
+ * Use the internal CRC32 code instead of kernel's CRC32 module, which
+ * is not available in early phase of booting.
+ */
+#define XZ_INTERNAL_CRC32 1
+
+/*
+ * For boot time use, we enable only the BCJ filter of the current
+ * architecture or none if no BCJ filter is available for the architecture.
+ */
+#ifdef CONFIG_X86
+# define XZ_DEC_X86
+#endif
+#ifdef CONFIG_PPC
+# define XZ_DEC_POWERPC
+#endif
+#ifdef CONFIG_ARM
+# define XZ_DEC_ARM
+#endif
+#ifdef CONFIG_IA64
+# define XZ_DEC_IA64
+#endif
+#ifdef CONFIG_SPARC
+# define XZ_DEC_SPARC
+#endif
+
+/*
+ * This will get the basic headers so that memeq() and others
+ * can be defined.
+ */
+#include "xz/xz_private.h"
+
+/*
+ * Replace the normal allocation functions with the versions from
+ * <linux/decompress/mm.h>. vfree() needs to support vfree(NULL)
+ * when XZ_DYNALLOC is used, but the pre-boot free() doesn't support it.
+ * Workaround it here because the other decompressors don't need it.
+ */
+#undef kmalloc
+#undef kfree
+#undef vmalloc
+#undef vfree
+#define kmalloc(size, flags) malloc(size)
+#define kfree(ptr) free(ptr)
+#define vmalloc(size) malloc(size)
+#define vfree(ptr) do { if (ptr != NULL) free(ptr); } while (0)
+
+/*
+ * FIXME: Not all basic memory functions are provided in architecture-specific
+ * files (yet). We define our own versions here for now, but this should be
+ * only a temporary solution.
+ *
+ * memeq and memzero are not used much and any remotely sane implementation
+ * is fast enough. memcpy/memmove speed matters in multi-call mode, but
+ * the kernel image is decompressed in single-call mode, in which only
+ * memcpy speed can matter and only if there is a lot of uncompressible data
+ * (LZMA2 stores uncompressible chunks in uncompressed form). Thus, the
+ * functions below should just be kept small; it's probably not worth
+ * optimizing for speed.
+ */
+
+#ifndef memeq
+static bool memeq(const void *a, const void *b, size_t size)
+{
+ const uint8_t *x = a;
+ const uint8_t *y = b;
+ size_t i;
+
+ for (i = 0; i < size; ++i)
+ if (x[i] != y[i])
+ return false;
+
+ return true;
+}
+#endif
+
+#ifndef memzero
+static void memzero(void *buf, size_t size)
+{
+ uint8_t *b = buf;
+ uint8_t *e = b + size;
+
+ while (b != e)
+ *b++ = '\0';
+}
+#endif
+
+#if 0
+/* Not static to avoid a conflict with the prototype in the Linux headers. */
+void *memmove(void *dest, const void *src, size_t size)
+{
+ uint8_t *d = dest;
+ const uint8_t *s = src;
+ size_t i;
+
+ if (d < s) {
+ for (i = 0; i < size; ++i)
+ d[i] = s[i];
+ } else if (d > s) {
+ i = size;
+ while (i-- > 0)
+ d[i] = s[i];
+ }
+
+ return dest;
+}
+#endif
+
+/*
+ * Since we need memmove anyway, would use it as memcpy too.
+ * Commented out for now to avoid breaking things.
+ */
+/*
+#ifndef memcpy
+# define memcpy memmove
+#endif
+*/
+
+#include "xz/xz_crc32.c"
+#include "xz/xz_dec_stream.c"
+#include "xz/xz_dec_lzma2.c"
+#include "xz/xz_dec_bcj.c"
+
+#endif /* XZ_PREBOOT */
+
+/* Size of the input and output buffers in multi-call mode */
+#define XZ_IOBUF_SIZE 4096
+
+/*
+ * This function implements the API defined in <linux/decompress/generic.h>.
+ *
+ * This wrapper will automatically choose single-call or multi-call mode
+ * of the native XZ decoder API. The single-call mode can be used only when
+ * both input and output buffers are available as a single chunk, i.e. when
+ * fill() and flush() won't be used.
+ */
+int unxz(unsigned char *in, int in_size,
+ int (*fill)(void *dest, unsigned int size),
+ int (*flush)(void *src, unsigned int size),
+ unsigned char *out, int *in_used,
+ void (*error)(char *x))
+{
+ struct xz_buf b;
+ struct xz_dec *s;
+ enum xz_ret ret;
+ bool must_free_in = false;
+
+#if XZ_INTERNAL_CRC32
+ xz_crc32_init();
+#endif
+
+ if (in_used != NULL)
+ *in_used = 0;
+
+ if (fill == NULL && flush == NULL)
+ s = xz_dec_init(XZ_SINGLE, 0);
+ else
+ s = xz_dec_init(XZ_DYNALLOC, (uint32_t)-1);
+
+ if (s == NULL)
+ goto error_alloc_state;
+
+ if (flush == NULL) {
+ b.out = out;
+ b.out_size = (size_t)-1;
+ } else {
+ b.out_size = XZ_IOBUF_SIZE;
+ b.out = malloc(XZ_IOBUF_SIZE);
+ if (b.out == NULL)
+ goto error_alloc_out;
+ }
+
+ if (in == NULL) {
+ must_free_in = true;
+ in = malloc(XZ_IOBUF_SIZE);
+ if (in == NULL)
+ goto error_alloc_in;
+ }
+
+ b.in = in;
+ b.in_pos = 0;
+ b.in_size = in_size;
+ b.out_pos = 0;
+
+ if (fill == NULL && flush == NULL) {
+ ret = xz_dec_run(s, &b);
+ } else {
+ do {
+ if (b.in_pos == b.in_size && fill != NULL) {
+ if (in_used != NULL)
+ *in_used += b.in_pos;
+
+ b.in_pos = 0;
+
+ in_size = fill(in, XZ_IOBUF_SIZE);
+ if (in_size < 0) {
+ /*
+ * This isn't an optimal error code
+ * but it probably isn't worth making
+ * a new one either.
+ */
+ ret = XZ_BUF_ERROR;
+ break;
+ }
+
+ b.in_size = in_size;
+ }
+
+ ret = xz_dec_run(s, &b);
+
+ if (flush != NULL && (b.out_pos == b.out_size
+ || (ret != XZ_OK && b.out_pos > 0))) {
+ /*
+ * Setting ret here may hide an error
+ * returned by xz_dec_run(), but probably
+ * it's not too bad.
+ */
+ if (flush(b.out, b.out_pos) != (int)b.out_pos)
+ ret = XZ_BUF_ERROR;
+
+ b.out_pos = 0;
+ }
+ } while (ret == XZ_OK);
+
+ if (must_free_in)
+ free(in);
+
+ if (flush != NULL)
+ free(b.out);
+ }
+
+ if (in_used != NULL)
+ *in_used += b.in_pos;
+
+ xz_dec_end(s);
+
+ switch (ret) {
+ case XZ_STREAM_END:
+ return 0;
+
+ case XZ_MEM_ERROR:
+ /* This can occur only in multi-call mode. */
+ error("XZ decompressor ran out of memory");
+ break;
+
+ case XZ_FORMAT_ERROR:
+ error("Input is not in the XZ format (wrong magic bytes)");
+ break;
+
+ case XZ_OPTIONS_ERROR:
+ error("Input was encoded with settings that are not "
+ "supported by this XZ decoder");
+ break;
+
+ case XZ_DATA_ERROR:
+ case XZ_BUF_ERROR:
+ error("XZ-compressed data is corrupt");
+ break;
+
+ default:
+ error("Bug in the XZ decompressor");
+ break;
+ }
+
+ return -1;
+
+error_alloc_in:
+ if (flush != NULL)
+ free(b.out);
+
+error_alloc_out:
+ xz_dec_end(s);
+
+error_alloc_state:
+ error("XZ decompressor ran out of memory");
+ return -1;
+}
+
+/*
+ * This macro is used by architecture-specific files to decompress
+ * the kernel image.
+ */
+#define decompress unxz
--- /dev/null
+config XZ_DEC
+ tristate "XZ decompression support"
+ select CRC32
+ help
+ LZMA2 compression algorithm and BCJ filters are supported using
+ the .xz file format as the container. For integrity checking,
+ CRC32 is supported. See Documentation/xz.txt for more information.
+
+if XZ_DEC
+
+config XZ_DEC_X86
+ bool "x86 BCJ filter decoder"
+ default y if X86
+ select XZ_DEC_BCJ
+
+config XZ_DEC_POWERPC
+ bool "PowerPC BCJ filter decoder"
+ default y if PPC
+ select XZ_DEC_BCJ
+
+config XZ_DEC_IA64
+ bool "IA-64 BCJ filter decoder"
+ default y if IA64
+ select XZ_DEC_BCJ
+
+config XZ_DEC_ARM
+ bool "ARM BCJ filter decoder"
+ default y if ARM
+ select XZ_DEC_BCJ
+
+config XZ_DEC_ARMTHUMB
+ bool "ARM-Thumb BCJ filter decoder"
+ default y if (ARM && ARM_THUMB)
+ select XZ_DEC_BCJ
+
+config XZ_DEC_SPARC
+ bool "SPARC BCJ filter decoder"
+ default y if SPARC
+ select XZ_DEC_BCJ
+
+endif
+
+config XZ_DEC_BCJ
+ bool
+ default n
+
+config XZ_DEC_TEST
+ tristate "XZ decompressor tester"
+ default n
+ depends on XZ_DEC
+ help
+ This allows passing .xz files to the in-kernel XZ decoder via
+ a character special file. It calculates CRC32 of the decompressed
+ data and writes diagnostics to the system log.
+
+ Unless you are developing the XZ decoder, you don't need this
+ and should say N.
--- /dev/null
+obj-$(CONFIG_XZ_DEC) += xz_dec.o
+xz_dec-y := xz_dec_syms.o xz_dec_stream.o xz_dec_lzma2.o
+xz_dec-$(CONFIG_XZ_DEC_BCJ) += xz_dec_bcj.o
+
+obj-$(CONFIG_XZ_DEC_TEST) += xz_dec_test.o
--- /dev/null
+/*
+ * CRC32 using the polynomial from IEEE-802.3
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+/*
+ * This is not the fastest implementation, but it is pretty compact.
+ * The fastest versions of xz_crc32() on modern CPUs without hardware
+ * accelerated CRC instruction are 3-5 times as fast as this version,
+ * but they are bigger and use more memory for the lookup table.
+ */
+
+#include "xz_private.h"
+
+/*
+ * STATIC_RW_DATA is used in the pre-boot environment on some architectures.
+ * See <linux/decompress/mm.h> for details.
+ */
+#ifndef STATIC_RW_DATA
+# define STATIC_RW_DATA static
+#endif
+
+STATIC_RW_DATA uint32_t xz_crc32_table[256];
+
+XZ_EXTERN void xz_crc32_init(void)
+{
+ const uint32_t poly = 0xEDB88320;
+
+ uint32_t i;
+ uint32_t j;
+ uint32_t r;
+
+ for (i = 0; i < 256; ++i) {
+ r = i;
+ for (j = 0; j < 8; ++j)
+ r = (r >> 1) ^ (poly & ~((r & 1) - 1));
+
+ xz_crc32_table[i] = r;
+ }
+
+ return;
+}
+
+XZ_EXTERN uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
+{
+ crc = ~crc;
+
+ while (size != 0) {
+ crc = xz_crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+ --size;
+ }
+
+ return ~crc;
+}
--- /dev/null
+/*
+ * CRC64 using the polynomial from ECMA-182
+ *
+ * This file is similar to xz_crc32.c. See the comments there.
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+
+#ifndef STATIC_RW_DATA
+# define STATIC_RW_DATA static
+#endif
+
+STATIC_RW_DATA uint64_t xz_crc64_table[256];
+
+XZ_EXTERN void xz_crc64_init(void)
+{
+ const uint64_t poly = 0xC96C5795D7870F42;
+
+ uint32_t i;
+ uint32_t j;
+ uint64_t r;
+
+ for (i = 0; i < 256; ++i) {
+ r = i;
+ for (j = 0; j < 8; ++j)
+ r = (r >> 1) ^ (poly & ~((r & 1) - 1));
+
+ xz_crc64_table[i] = r;
+ }
+
+ return;
+}
+
+XZ_EXTERN uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc)
+{
+ crc = ~crc;
+
+ while (size != 0) {
+ crc = xz_crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+ --size;
+ }
+
+ return ~crc;
+}
--- /dev/null
+/*
+ * Branch/Call/Jump (BCJ) filter decoders
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+
+/*
+ * The rest of the file is inside this ifdef. It makes things a little more
+ * convenient when building without support for any BCJ filters.
+ */
+#ifdef XZ_DEC_BCJ
+
+struct xz_dec_bcj {
+ /* Type of the BCJ filter being used */
+ enum {
+ BCJ_X86 = 4, /* x86 or x86-64 */
+ BCJ_POWERPC = 5, /* Big endian only */
+ BCJ_IA64 = 6, /* Big or little endian */
+ BCJ_ARM = 7, /* Little endian only */
+ BCJ_ARMTHUMB = 8, /* Little endian only */
+ BCJ_SPARC = 9 /* Big or little endian */
+ } type;
+
+ /*
+ * Return value of the next filter in the chain. We need to preserve
+ * this information across calls, because we must not call the next
+ * filter anymore once it has returned XZ_STREAM_END.
+ */
+ enum xz_ret ret;
+
+ /* True if we are operating in single-call mode. */
+ bool single_call;
+
+ /*
+ * Absolute position relative to the beginning of the uncompressed
+ * data (in a single .xz Block). We care only about the lowest 32
+ * bits so this doesn't need to be uint64_t even with big files.
+ */
+ uint32_t pos;
+
+ /* x86 filter state */
+ uint32_t x86_prev_mask;
+
+ /* Temporary space to hold the variables from struct xz_buf */
+ uint8_t *out;
+ size_t out_pos;
+ size_t out_size;
+
+ struct {
+ /* Amount of already filtered data in the beginning of buf */
+ size_t filtered;
+
+ /* Total amount of data currently stored in buf */
+ size_t size;
+
+ /*
+ * Buffer to hold a mix of filtered and unfiltered data. This
+ * needs to be big enough to hold Alignment + 2 * Look-ahead:
+ *
+ * Type Alignment Look-ahead
+ * x86 1 4
+ * PowerPC 4 0
+ * IA-64 16 0
+ * ARM 4 0
+ * ARM-Thumb 2 2
+ * SPARC 4 0
+ */
+ uint8_t buf[16];
+ } temp;
+};
+
+#ifdef XZ_DEC_X86
+/*
+ * This is used to test the most significant byte of a memory address
+ * in an x86 instruction.
+ */
+static inline int bcj_x86_test_msbyte(uint8_t b)
+{
+ return b == 0x00 || b == 0xFF;
+}
+
+static size_t bcj_x86(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ static const bool mask_to_allowed_status[8]
+ = { true, true, true, false, true, false, false, false };
+
+ static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 };
+
+ size_t i;
+ size_t prev_pos = (size_t)-1;
+ uint32_t prev_mask = s->x86_prev_mask;
+ uint32_t src;
+ uint32_t dest;
+ uint32_t j;
+ uint8_t b;
+
+ if (size <= 4)
+ return 0;
+
+ size -= 4;
+ for (i = 0; i < size; ++i) {
+ if ((buf[i] & 0xFE) != 0xE8)
+ continue;
+
+ prev_pos = i - prev_pos;
+ if (prev_pos > 3) {
+ prev_mask = 0;
+ } else {
+ prev_mask = (prev_mask << (prev_pos - 1)) & 7;
+ if (prev_mask != 0) {
+ b = buf[i + 4 - mask_to_bit_num[prev_mask]];
+ if (!mask_to_allowed_status[prev_mask]
+ || bcj_x86_test_msbyte(b)) {
+ prev_pos = i;
+ prev_mask = (prev_mask << 1) | 1;
+ continue;
+ }
+ }
+ }
+
+ prev_pos = i;
+
+ if (bcj_x86_test_msbyte(buf[i + 4])) {
+ src = get_unaligned_le32(buf + i + 1);
+ while (true) {
+ dest = src - (s->pos + (uint32_t)i + 5);
+ if (prev_mask == 0)
+ break;
+
+ j = mask_to_bit_num[prev_mask] * 8;
+ b = (uint8_t)(dest >> (24 - j));
+ if (!bcj_x86_test_msbyte(b))
+ break;
+
+ src = dest ^ (((uint32_t)1 << (32 - j)) - 1);
+ }
+
+ dest &= 0x01FFFFFF;
+ dest |= (uint32_t)0 - (dest & 0x01000000);
+ put_unaligned_le32(dest, buf + i + 1);
+ i += 4;
+ } else {
+ prev_mask = (prev_mask << 1) | 1;
+ }
+ }
+
+ prev_pos = i - prev_pos;
+ s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1);
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_POWERPC
+static size_t bcj_powerpc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t instr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ instr = get_unaligned_be32(buf + i);
+ if ((instr & 0xFC000003) == 0x48000001) {
+ instr &= 0x03FFFFFC;
+ instr -= s->pos + (uint32_t)i;
+ instr &= 0x03FFFFFC;
+ instr |= 0x48000001;
+ put_unaligned_be32(instr, buf + i);
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_IA64
+static size_t bcj_ia64(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ static const uint8_t branch_table[32] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+ };
+
+ /*
+ * The local variables take a little bit stack space, but it's less
+ * than what LZMA2 decoder takes, so it doesn't make sense to reduce
+ * stack usage here without doing that for the LZMA2 decoder too.
+ */
+
+ /* Loop counters */
+ size_t i;
+ size_t j;
+
+ /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */
+ uint32_t slot;
+
+ /* Bitwise offset of the instruction indicated by slot */
+ uint32_t bit_pos;
+
+ /* bit_pos split into byte and bit parts */
+ uint32_t byte_pos;
+ uint32_t bit_res;
+
+ /* Address part of an instruction */
+ uint32_t addr;
+
+ /* Mask used to detect which instructions to convert */
+ uint32_t mask;
+
+ /* 41-bit instruction stored somewhere in the lowest 48 bits */
+ uint64_t instr;
+
+ /* Instruction normalized with bit_res for easier manipulation */
+ uint64_t norm;
+
+ for (i = 0; i + 16 <= size; i += 16) {
+ mask = branch_table[buf[i] & 0x1F];
+ for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) {
+ if (((mask >> slot) & 1) == 0)
+ continue;
+
+ byte_pos = bit_pos >> 3;
+ bit_res = bit_pos & 7;
+ instr = 0;
+ for (j = 0; j < 6; ++j)
+ instr |= (uint64_t)(buf[i + j + byte_pos])
+ << (8 * j);
+
+ norm = instr >> bit_res;
+
+ if (((norm >> 37) & 0x0F) == 0x05
+ && ((norm >> 9) & 0x07) == 0) {
+ addr = (norm >> 13) & 0x0FFFFF;
+ addr |= ((uint32_t)(norm >> 36) & 1) << 20;
+ addr <<= 4;
+ addr -= s->pos + (uint32_t)i;
+ addr >>= 4;
+
+ norm &= ~((uint64_t)0x8FFFFF << 13);
+ norm |= (uint64_t)(addr & 0x0FFFFF) << 13;
+ norm |= (uint64_t)(addr & 0x100000)
+ << (36 - 20);
+
+ instr &= (1 << bit_res) - 1;
+ instr |= norm << bit_res;
+
+ for (j = 0; j < 6; j++)
+ buf[i + j + byte_pos]
+ = (uint8_t)(instr >> (8 * j));
+ }
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARM
+static size_t bcj_arm(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t addr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ if (buf[i + 3] == 0xEB) {
+ addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8)
+ | ((uint32_t)buf[i + 2] << 16);
+ addr <<= 2;
+ addr -= s->pos + (uint32_t)i + 8;
+ addr >>= 2;
+ buf[i] = (uint8_t)addr;
+ buf[i + 1] = (uint8_t)(addr >> 8);
+ buf[i + 2] = (uint8_t)(addr >> 16);
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_ARMTHUMB
+static size_t bcj_armthumb(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t addr;
+
+ for (i = 0; i + 4 <= size; i += 2) {
+ if ((buf[i + 1] & 0xF8) == 0xF0
+ && (buf[i + 3] & 0xF8) == 0xF8) {
+ addr = (((uint32_t)buf[i + 1] & 0x07) << 19)
+ | ((uint32_t)buf[i] << 11)
+ | (((uint32_t)buf[i + 3] & 0x07) << 8)
+ | (uint32_t)buf[i + 2];
+ addr <<= 1;
+ addr -= s->pos + (uint32_t)i + 4;
+ addr >>= 1;
+ buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07));
+ buf[i] = (uint8_t)(addr >> 11);
+ buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07));
+ buf[i + 2] = (uint8_t)addr;
+ i += 2;
+ }
+ }
+
+ return i;
+}
+#endif
+
+#ifdef XZ_DEC_SPARC
+static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
+{
+ size_t i;
+ uint32_t instr;
+
+ for (i = 0; i + 4 <= size; i += 4) {
+ instr = get_unaligned_be32(buf + i);
+ if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
+ instr <<= 2;
+ instr -= s->pos + (uint32_t)i;
+ instr >>= 2;
+ instr = ((uint32_t)0x40000000 - (instr & 0x400000))
+ | 0x40000000 | (instr & 0x3FFFFF);
+ put_unaligned_be32(instr, buf + i);
+ }
+ }
+
+ return i;
+}
+#endif
+
+/*
+ * Apply the selected BCJ filter. Update *pos and s->pos to match the amount
+ * of data that got filtered.
+ *
+ * NOTE: This is implemented as a switch statement to avoid using function
+ * pointers, which could be problematic in the kernel boot code, which must
+ * avoid pointers to static data (at least on x86).
+ */
+static void bcj_apply(struct xz_dec_bcj *s,
+ uint8_t *buf, size_t *pos, size_t size)
+{
+ size_t filtered;
+
+ buf += *pos;
+ size -= *pos;
+
+ switch (s->type) {
+#ifdef XZ_DEC_X86
+ case BCJ_X86:
+ filtered = bcj_x86(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_POWERPC
+ case BCJ_POWERPC:
+ filtered = bcj_powerpc(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_IA64
+ case BCJ_IA64:
+ filtered = bcj_ia64(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_ARM
+ case BCJ_ARM:
+ filtered = bcj_arm(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+ case BCJ_ARMTHUMB:
+ filtered = bcj_armthumb(s, buf, size);
+ break;
+#endif
+#ifdef XZ_DEC_SPARC
+ case BCJ_SPARC:
+ filtered = bcj_sparc(s, buf, size);
+ break;
+#endif
+ default:
+ /* Never reached but silence compiler warnings. */
+ filtered = 0;
+ break;
+ }
+
+ *pos += filtered;
+ s->pos += filtered;
+}
+
+/*
+ * Flush pending filtered data from temp to the output buffer.
+ * Move the remaining mixture of possibly filtered and unfiltered
+ * data to the beginning of temp.
+ */
+static void bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b)
+{
+ size_t copy_size;
+
+ copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos);
+ memcpy(b->out + b->out_pos, s->temp.buf, copy_size);
+ b->out_pos += copy_size;
+
+ s->temp.filtered -= copy_size;
+ s->temp.size -= copy_size;
+ memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size);
+}
+
+/*
+ * The BCJ filter functions are primitive in sense that they process the
+ * data in chunks of 1-16 bytes. To hide this issue, this function does
+ * some buffering.
+ */
+XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
+ struct xz_dec_lzma2 *lzma2,
+ struct xz_buf *b)
+{
+ size_t out_start;
+
+ /*
+ * Flush pending already filtered data to the output buffer. Return
+ * immediatelly if we couldn't flush everything, or if the next
+ * filter in the chain had already returned XZ_STREAM_END.
+ */
+ if (s->temp.filtered > 0) {
+ bcj_flush(s, b);
+ if (s->temp.filtered > 0)
+ return XZ_OK;
+
+ if (s->ret == XZ_STREAM_END)
+ return XZ_STREAM_END;
+ }
+
+ /*
+ * If we have more output space than what is currently pending in
+ * temp, copy the unfiltered data from temp to the output buffer
+ * and try to fill the output buffer by decoding more data from the
+ * next filter in the chain. Apply the BCJ filter on the new data
+ * in the output buffer. If everything cannot be filtered, copy it
+ * to temp and rewind the output buffer position accordingly.
+ *
+ * This needs to be always run when temp.size == 0 to handle a special
+ * case where the output buffer is full and the next filter has no
+ * more output coming but hasn't returned XZ_STREAM_END yet.
+ */
+ if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) {
+ out_start = b->out_pos;
+ memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size);
+ b->out_pos += s->temp.size;
+
+ s->ret = xz_dec_lzma2_run(lzma2, b);
+ if (s->ret != XZ_STREAM_END
+ && (s->ret != XZ_OK || s->single_call))
+ return s->ret;
+
+ bcj_apply(s, b->out, &out_start, b->out_pos);
+
+ /*
+ * As an exception, if the next filter returned XZ_STREAM_END,
+ * we can do that too, since the last few bytes that remain
+ * unfiltered are meant to remain unfiltered.
+ */
+ if (s->ret == XZ_STREAM_END)
+ return XZ_STREAM_END;
+
+ s->temp.size = b->out_pos - out_start;
+ b->out_pos -= s->temp.size;
+ memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size);
+
+ /*
+ * If there wasn't enough input to the next filter to fill
+ * the output buffer with unfiltered data, there's no point
+ * to try decoding more data to temp.
+ */
+ if (b->out_pos + s->temp.size < b->out_size)
+ return XZ_OK;
+ }
+
+ /*
+ * We have unfiltered data in temp. If the output buffer isn't full
+ * yet, try to fill the temp buffer by decoding more data from the
+ * next filter. Apply the BCJ filter on temp. Then we hopefully can
+ * fill the actual output buffer by copying filtered data from temp.
+ * A mix of filtered and unfiltered data may be left in temp; it will
+ * be taken care on the next call to this function.
+ */
+ if (b->out_pos < b->out_size) {
+ /* Make b->out{,_pos,_size} temporarily point to s->temp. */
+ s->out = b->out;
+ s->out_pos = b->out_pos;
+ s->out_size = b->out_size;
+ b->out = s->temp.buf;
+ b->out_pos = s->temp.size;
+ b->out_size = sizeof(s->temp.buf);
+
+ s->ret = xz_dec_lzma2_run(lzma2, b);
+
+ s->temp.size = b->out_pos;
+ b->out = s->out;
+ b->out_pos = s->out_pos;
+ b->out_size = s->out_size;
+
+ if (s->ret != XZ_OK && s->ret != XZ_STREAM_END)
+ return s->ret;
+
+ bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size);
+
+ /*
+ * If the next filter returned XZ_STREAM_END, we mark that
+ * everything is filtered, since the last unfiltered bytes
+ * of the stream are meant to be left as is.
+ */
+ if (s->ret == XZ_STREAM_END)
+ s->temp.filtered = s->temp.size;
+
+ bcj_flush(s, b);
+ if (s->temp.filtered > 0)
+ return XZ_OK;
+ }
+
+ return s->ret;
+}
+
+XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call)
+{
+ struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s != NULL)
+ s->single_call = single_call;
+
+ return s;
+}
+
+XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id)
+{
+ switch (id) {
+#ifdef XZ_DEC_X86
+ case BCJ_X86:
+#endif
+#ifdef XZ_DEC_POWERPC
+ case BCJ_POWERPC:
+#endif
+#ifdef XZ_DEC_IA64
+ case BCJ_IA64:
+#endif
+#ifdef XZ_DEC_ARM
+ case BCJ_ARM:
+#endif
+#ifdef XZ_DEC_ARMTHUMB
+ case BCJ_ARMTHUMB:
+#endif
+#ifdef XZ_DEC_SPARC
+ case BCJ_SPARC:
+#endif
+ break;
+
+ default:
+ /* Unsupported Filter ID */
+ return XZ_OPTIONS_ERROR;
+ }
+
+ s->type = id;
+ s->ret = XZ_OK;
+ s->pos = 0;
+ s->x86_prev_mask = 0;
+ s->temp.filtered = 0;
+ s->temp.size = 0;
+
+ return XZ_OK;
+}
+
+#endif
--- /dev/null
+/*
+ * LZMA2 decoder
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+#include "xz_lzma2.h"
+
+/*
+ * Range decoder initialization eats the first five bytes of each LZMA chunk.
+ */
+#define RC_INIT_BYTES 5
+
+/*
+ * Minimum number of usable input buffer to safely decode one LZMA symbol.
+ * The worst case is that we decode 22 bits using probabilities and 26
+ * direct bits. This may decode at maximum of 20 bytes of input. However,
+ * lzma_main() does an extra normalization before returning, thus we
+ * need to put 21 here.
+ */
+#define LZMA_IN_REQUIRED 21
+
+/*
+ * Dictionary (history buffer)
+ *
+ * These are always true:
+ * start <= pos <= full <= end
+ * pos <= limit <= end
+ *
+ * In multi-call mode, also these are true:
+ * end == size
+ * size <= size_max
+ * allocated <= size
+ *
+ * Most of these variables are size_t to support single-call mode,
+ * in which the dictionary variables address the actual output
+ * buffer directly.
+ */
+struct dictionary {
+ /* Beginning of the history buffer */
+ uint8_t *buf;
+
+ /* Old position in buf (before decoding more data) */
+ size_t start;
+
+ /* Position in buf */
+ size_t pos;
+
+ /*
+ * How full dictionary is. This is used to detect corrupt input that
+ * would read beyond the beginning of the uncompressed stream.
+ */
+ size_t full;
+
+ /* Write limit; we don't write to buf[limit] or later bytes. */
+ size_t limit;
+
+ /*
+ * End of the dictionary buffer. In multi-call mode, this is
+ * the same as the dictionary size. In single-call mode, this
+ * indicates the size of the output buffer.
+ */
+ size_t end;
+
+ /*
+ * Size of the dictionary as specified in Block Header. This is used
+ * together with "full" to detect corrupt input that would make us
+ * read beyond the beginning of the uncompressed stream.
+ */
+ uint32_t size;
+
+ /*
+ * Maximum allowed dictionary size in multi-call mode.
+ * This is ignored in single-call mode.
+ */
+ uint32_t size_max;
+
+ /*
+ * Amount of memory currently allocated for the dictionary.
+ * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC,
+ * size_max is always the same as the allocated size.)
+ */
+ uint32_t allocated;
+
+ /* Operation mode */
+ enum xz_mode mode;
+};
+
+/* Range decoder */
+struct rc_dec {
+ uint32_t range;
+ uint32_t code;
+
+ /*
+ * Number of initializing bytes remaining to be read
+ * by rc_read_init().
+ */
+ uint32_t init_bytes_left;
+
+ /*
+ * Buffer from which we read our input. It can be either
+ * temp.buf or the caller-provided input buffer.
+ */
+ const uint8_t *in;
+ size_t in_pos;
+ size_t in_limit;
+};
+
+/* Probabilities for a length decoder. */
+struct lzma_len_dec {
+ /* Probability of match length being at least 10 */
+ uint16_t choice;
+
+ /* Probability of match length being at least 18 */
+ uint16_t choice2;
+
+ /* Probabilities for match lengths 2-9 */
+ uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+
+ /* Probabilities for match lengths 10-17 */
+ uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+
+ /* Probabilities for match lengths 18-273 */
+ uint16_t high[LEN_HIGH_SYMBOLS];
+};
+
+struct lzma_dec {
+ /* Distances of latest four matches */
+ uint32_t rep0;
+ uint32_t rep1;
+ uint32_t rep2;
+ uint32_t rep3;
+
+ /* Types of the most recently seen LZMA symbols */
+ enum lzma_state state;
+
+ /*
+ * Length of a match. This is updated so that dict_repeat can
+ * be called again to finish repeating the whole match.
+ */
+ uint32_t len;
+
+ /*
+ * LZMA properties or related bit masks (number of literal
+ * context bits, a mask dervied from the number of literal
+ * position bits, and a mask dervied from the number
+ * position bits)
+ */
+ uint32_t lc;
+ uint32_t literal_pos_mask; /* (1 << lp) - 1 */
+ uint32_t pos_mask; /* (1 << pb) - 1 */
+
+ /* If 1, it's a match. Otherwise it's a single 8-bit literal. */
+ uint16_t is_match[STATES][POS_STATES_MAX];
+
+ /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */
+ uint16_t is_rep[STATES];
+
+ /*
+ * If 0, distance of a repeated match is rep0.
+ * Otherwise check is_rep1.
+ */
+ uint16_t is_rep0[STATES];
+
+ /*
+ * If 0, distance of a repeated match is rep1.
+ * Otherwise check is_rep2.
+ */
+ uint16_t is_rep1[STATES];
+
+ /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */
+ uint16_t is_rep2[STATES];
+
+ /*
+ * If 1, the repeated match has length of one byte. Otherwise
+ * the length is decoded from rep_len_decoder.
+ */
+ uint16_t is_rep0_long[STATES][POS_STATES_MAX];
+
+ /*
+ * Probability tree for the highest two bits of the match
+ * distance. There is a separate probability tree for match
+ * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+ */
+ uint16_t dist_slot[DIST_STATES][DIST_SLOTS];
+
+ /*
+ * Probility trees for additional bits for match distance
+ * when the distance is in the range [4, 127].
+ */
+ uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END];
+
+ /*
+ * Probability tree for the lowest four bits of a match
+ * distance that is equal to or greater than 128.
+ */
+ uint16_t dist_align[ALIGN_SIZE];
+
+ /* Length of a normal match */
+ struct lzma_len_dec match_len_dec;
+
+ /* Length of a repeated match */
+ struct lzma_len_dec rep_len_dec;
+
+ /* Probabilities of literals */
+ uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
+};
+
+struct lzma2_dec {
+ /* Position in xz_dec_lzma2_run(). */
+ enum lzma2_seq {
+ SEQ_CONTROL,
+ SEQ_UNCOMPRESSED_1,
+ SEQ_UNCOMPRESSED_2,
+ SEQ_COMPRESSED_0,
+ SEQ_COMPRESSED_1,
+ SEQ_PROPERTIES,
+ SEQ_LZMA_PREPARE,
+ SEQ_LZMA_RUN,
+ SEQ_COPY
+ } sequence;
+
+ /* Next position after decoding the compressed size of the chunk. */
+ enum lzma2_seq next_sequence;
+
+ /* Uncompressed size of LZMA chunk (2 MiB at maximum) */
+ uint32_t uncompressed;
+
+ /*
+ * Compressed size of LZMA chunk or compressed/uncompressed
+ * size of uncompressed chunk (64 KiB at maximum)
+ */
+ uint32_t compressed;
+
+ /*
+ * True if dictionary reset is needed. This is false before
+ * the first chunk (LZMA or uncompressed).
+ */
+ bool need_dict_reset;
+
+ /*
+ * True if new LZMA properties are needed. This is false
+ * before the first LZMA chunk.
+ */
+ bool need_props;
+};
+
+struct xz_dec_lzma2 {
+ /*
+ * The order below is important on x86 to reduce code size and
+ * it shouldn't hurt on other platforms. Everything up to and
+ * including lzma.pos_mask are in the first 128 bytes on x86-32,
+ * which allows using smaller instructions to access those
+ * variables. On x86-64, fewer variables fit into the first 128
+ * bytes, but this is still the best order without sacrificing
+ * the readability by splitting the structures.
+ */
+ struct rc_dec rc;
+ struct dictionary dict;
+ struct lzma2_dec lzma2;
+ struct lzma_dec lzma;
+
+ /*
+ * Temporary buffer which holds small number of input bytes between
+ * decoder calls. See lzma2_lzma() for details.
+ */
+ struct {
+ uint32_t size;
+ uint8_t buf[3 * LZMA_IN_REQUIRED];
+ } temp;
+};
+
+/**************
+ * Dictionary *
+ **************/
+
+/*
+ * Reset the dictionary state. When in single-call mode, set up the beginning
+ * of the dictionary to point to the actual output buffer.
+ */
+static void dict_reset(struct dictionary *dict, struct xz_buf *b)
+{
+ if (DEC_IS_SINGLE(dict->mode)) {
+ dict->buf = b->out + b->out_pos;
+ dict->end = b->out_size - b->out_pos;
+ }
+
+ dict->start = 0;
+ dict->pos = 0;
+ dict->limit = 0;
+ dict->full = 0;
+}
+
+/* Set dictionary write limit */
+static void dict_limit(struct dictionary *dict, size_t out_max)
+{
+ if (dict->end - dict->pos <= out_max)
+ dict->limit = dict->end;
+ else
+ dict->limit = dict->pos + out_max;
+}
+
+/* Return true if at least one byte can be written into the dictionary. */
+static inline bool dict_has_space(const struct dictionary *dict)
+{
+ return dict->pos < dict->limit;
+}
+
+/*
+ * Get a byte from the dictionary at the given distance. The distance is
+ * assumed to valid, or as a special case, zero when the dictionary is
+ * still empty. This special case is needed for single-call decoding to
+ * avoid writing a '\0' to the end of the destination buffer.
+ */
+static inline uint32_t dict_get(const struct dictionary *dict, uint32_t dist)
+{
+ size_t offset = dict->pos - dist - 1;
+
+ if (dist >= dict->pos)
+ offset += dict->end;
+
+ return dict->full > 0 ? dict->buf[offset] : 0;
+}
+
+/*
+ * Put one byte into the dictionary. It is assumed that there is space for it.
+ */
+static inline void dict_put(struct dictionary *dict, uint8_t byte)
+{
+ dict->buf[dict->pos++] = byte;
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+}
+
+/*
+ * Repeat given number of bytes from the given distance. If the distance is
+ * invalid, false is returned. On success, true is returned and *len is
+ * updated to indicate how many bytes were left to be repeated.
+ */
+static bool dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t dist)
+{
+ size_t back;
+ uint32_t left;
+
+ if (dist >= dict->full || dist >= dict->size)
+ return false;
+
+ left = min_t(size_t, dict->limit - dict->pos, *len);
+ *len -= left;
+
+ back = dict->pos - dist - 1;
+ if (dist >= dict->pos)
+ back += dict->end;
+
+ do {
+ dict->buf[dict->pos++] = dict->buf[back++];
+ if (back == dict->end)
+ back = 0;
+ } while (--left > 0);
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+
+ return true;
+}
+
+/* Copy uncompressed data as is from input to dictionary and output buffers. */
+static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
+ uint32_t *left)
+{
+ size_t copy_size;
+
+ while (*left > 0 && b->in_pos < b->in_size
+ && b->out_pos < b->out_size) {
+ copy_size = min(b->in_size - b->in_pos,
+ b->out_size - b->out_pos);
+ if (copy_size > dict->end - dict->pos)
+ copy_size = dict->end - dict->pos;
+ if (copy_size > *left)
+ copy_size = *left;
+
+ *left -= copy_size;
+
+ memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
+ dict->pos += copy_size;
+
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+
+ if (DEC_IS_MULTI(dict->mode)) {
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
+ memcpy(b->out + b->out_pos, b->in + b->in_pos,
+ copy_size);
+ }
+
+ dict->start = dict->pos;
+
+ b->out_pos += copy_size;
+ b->in_pos += copy_size;
+ }
+}
+
+/*
+ * Flush pending data from dictionary to b->out. It is assumed that there is
+ * enough space in b->out. This is guaranteed because caller uses dict_limit()
+ * before decoding data into the dictionary.
+ */
+static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b)
+{
+ size_t copy_size = dict->pos - dict->start;
+
+ if (DEC_IS_MULTI(dict->mode)) {
+ if (dict->pos == dict->end)
+ dict->pos = 0;
+
+ memcpy(b->out + b->out_pos, dict->buf + dict->start,
+ copy_size);
+ }
+
+ dict->start = dict->pos;
+ b->out_pos += copy_size;
+ return copy_size;
+}
+
+/*****************
+ * Range decoder *
+ *****************/
+
+/* Reset the range decoder. */
+static void rc_reset(struct rc_dec *rc)
+{
+ rc->range = (uint32_t)-1;
+ rc->code = 0;
+ rc->init_bytes_left = RC_INIT_BYTES;
+}
+
+/*
+ * Read the first five initial bytes into rc->code if they haven't been
+ * read already. (Yes, the first byte gets completely ignored.)
+ */
+static bool rc_read_init(struct rc_dec *rc, struct xz_buf *b)
+{
+ while (rc->init_bytes_left > 0) {
+ if (b->in_pos == b->in_size)
+ return false;
+
+ rc->code = (rc->code << 8) + b->in[b->in_pos++];
+ --rc->init_bytes_left;
+ }
+
+ return true;
+}
+
+/* Return true if there may not be enough input for the next decoding loop. */
+static inline bool rc_limit_exceeded(const struct rc_dec *rc)
+{
+ return rc->in_pos > rc->in_limit;
+}
+
+/*
+ * Return true if it is possible (from point of view of range decoder) that
+ * we have reached the end of the LZMA chunk.
+ */
+static inline bool rc_is_finished(const struct rc_dec *rc)
+{
+ return rc->code == 0;
+}
+
+/* Read the next input byte if needed. */
+static __always_inline void rc_normalize(struct rc_dec *rc)
+{
+ if (rc->range < RC_TOP_VALUE) {
+ rc->range <<= RC_SHIFT_BITS;
+ rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++];
+ }
+}
+
+/*
+ * Decode one bit. In some versions, this function has been splitted in three
+ * functions so that the compiler is supposed to be able to more easily avoid
+ * an extra branch. In this particular version of the LZMA decoder, this
+ * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3
+ * on x86). Using a non-splitted version results in nicer looking code too.
+ *
+ * NOTE: This must return an int. Do not make it return a bool or the speed
+ * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care,
+ * and it generates 10-20 % faster code than GCC 3.x from this file anyway.)
+ */
+static __always_inline int rc_bit(struct rc_dec *rc, uint16_t *prob)
+{
+ uint32_t bound;
+ int bit;
+
+ rc_normalize(rc);
+ bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob;
+ if (rc->code < bound) {
+ rc->range = bound;
+ *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS;
+ bit = 0;
+ } else {
+ rc->range -= bound;
+ rc->code -= bound;
+ *prob -= *prob >> RC_MOVE_BITS;
+ bit = 1;
+ }
+
+ return bit;
+}
+
+/* Decode a bittree starting from the most significant bit. */
+static __always_inline uint32_t rc_bittree(struct rc_dec *rc,
+ uint16_t *probs, uint32_t limit)
+{
+ uint32_t symbol = 1;
+
+ do {
+ if (rc_bit(rc, &probs[symbol]))
+ symbol = (symbol << 1) + 1;
+ else
+ symbol <<= 1;
+ } while (symbol < limit);
+
+ return symbol;
+}
+
+/* Decode a bittree starting from the least significant bit. */
+static __always_inline void rc_bittree_reverse(struct rc_dec *rc,
+ uint16_t *probs,
+ uint32_t *dest, uint32_t limit)
+{
+ uint32_t symbol = 1;
+ uint32_t i = 0;
+
+ do {
+ if (rc_bit(rc, &probs[symbol])) {
+ symbol = (symbol << 1) + 1;
+ *dest += 1 << i;
+ } else {
+ symbol <<= 1;
+ }
+ } while (++i < limit);
+}
+
+/* Decode direct bits (fixed fifty-fifty probability) */
+static inline void rc_direct(struct rc_dec *rc, uint32_t *dest, uint32_t limit)
+{
+ uint32_t mask;
+
+ do {
+ rc_normalize(rc);
+ rc->range >>= 1;
+ rc->code -= rc->range;
+ mask = (uint32_t)0 - (rc->code >> 31);
+ rc->code += rc->range & mask;
+ *dest = (*dest << 1) + (mask + 1);
+ } while (--limit > 0);
+}
+
+/********
+ * LZMA *
+ ********/
+
+/* Get pointer to literal coder probability array. */
+static uint16_t *lzma_literal_probs(struct xz_dec_lzma2 *s)
+{
+ uint32_t prev_byte = dict_get(&s->dict, 0);
+ uint32_t low = prev_byte >> (8 - s->lzma.lc);
+ uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc;
+ return s->lzma.literal[low + high];
+}
+
+/* Decode a literal (one 8-bit byte) */
+static void lzma_literal(struct xz_dec_lzma2 *s)
+{
+ uint16_t *probs;
+ uint32_t symbol;
+ uint32_t match_byte;
+ uint32_t match_bit;
+ uint32_t offset;
+ uint32_t i;
+
+ probs = lzma_literal_probs(s);
+
+ if (lzma_state_is_literal(s->lzma.state)) {
+ symbol = rc_bittree(&s->rc, probs, 0x100);
+ } else {
+ symbol = 1;
+ match_byte = dict_get(&s->dict, s->lzma.rep0) << 1;
+ offset = 0x100;
+
+ do {
+ match_bit = match_byte & offset;
+ match_byte <<= 1;
+ i = offset + match_bit + symbol;
+
+ if (rc_bit(&s->rc, &probs[i])) {
+ symbol = (symbol << 1) + 1;
+ offset &= match_bit;
+ } else {
+ symbol <<= 1;
+ offset &= ~match_bit;
+ }
+ } while (symbol < 0x100);
+ }
+
+ dict_put(&s->dict, (uint8_t)symbol);
+ lzma_state_literal(&s->lzma.state);
+}
+
+/* Decode the length of the match into s->lzma.len. */
+static void lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l,
+ uint32_t pos_state)
+{
+ uint16_t *probs;
+ uint32_t limit;
+
+ if (!rc_bit(&s->rc, &l->choice)) {
+ probs = l->low[pos_state];
+ limit = LEN_LOW_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN;
+ } else {
+ if (!rc_bit(&s->rc, &l->choice2)) {
+ probs = l->mid[pos_state];
+ limit = LEN_MID_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS;
+ } else {
+ probs = l->high;
+ limit = LEN_HIGH_SYMBOLS;
+ s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS
+ + LEN_MID_SYMBOLS;
+ }
+ }
+
+ s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit;
+}
+
+/* Decode a match. The distance will be stored in s->lzma.rep0. */
+static void lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+ uint16_t *probs;
+ uint32_t dist_slot;
+ uint32_t limit;
+
+ lzma_state_match(&s->lzma.state);
+
+ s->lzma.rep3 = s->lzma.rep2;
+ s->lzma.rep2 = s->lzma.rep1;
+ s->lzma.rep1 = s->lzma.rep0;
+
+ lzma_len(s, &s->lzma.match_len_dec, pos_state);
+
+ probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)];
+ dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS;
+
+ if (dist_slot < DIST_MODEL_START) {
+ s->lzma.rep0 = dist_slot;
+ } else {
+ limit = (dist_slot >> 1) - 1;
+ s->lzma.rep0 = 2 + (dist_slot & 1);
+
+ if (dist_slot < DIST_MODEL_END) {
+ s->lzma.rep0 <<= limit;
+ probs = s->lzma.dist_special + s->lzma.rep0
+ - dist_slot - 1;
+ rc_bittree_reverse(&s->rc, probs,
+ &s->lzma.rep0, limit);
+ } else {
+ rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS);
+ s->lzma.rep0 <<= ALIGN_BITS;
+ rc_bittree_reverse(&s->rc, s->lzma.dist_align,
+ &s->lzma.rep0, ALIGN_BITS);
+ }
+ }
+}
+
+/*
+ * Decode a repeated match. The distance is one of the four most recently
+ * seen matches. The distance will be stored in s->lzma.rep0.
+ */
+static void lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state)
+{
+ uint32_t tmp;
+
+ if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[
+ s->lzma.state][pos_state])) {
+ lzma_state_short_rep(&s->lzma.state);
+ s->lzma.len = 1;
+ return;
+ }
+ } else {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) {
+ tmp = s->lzma.rep1;
+ } else {
+ if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) {
+ tmp = s->lzma.rep2;
+ } else {
+ tmp = s->lzma.rep3;
+ s->lzma.rep3 = s->lzma.rep2;
+ }
+
+ s->lzma.rep2 = s->lzma.rep1;
+ }
+
+ s->lzma.rep1 = s->lzma.rep0;
+ s->lzma.rep0 = tmp;
+ }
+
+ lzma_state_long_rep(&s->lzma.state);
+ lzma_len(s, &s->lzma.rep_len_dec, pos_state);
+}
+
+/* LZMA decoder core */
+static bool lzma_main(struct xz_dec_lzma2 *s)
+{
+ uint32_t pos_state;
+
+ /*
+ * If the dictionary was reached during the previous call, try to
+ * finish the possibly pending repeat in the dictionary.
+ */
+ if (dict_has_space(&s->dict) && s->lzma.len > 0)
+ dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0);
+
+ /*
+ * Decode more LZMA symbols. One iteration may consume up to
+ * LZMA_IN_REQUIRED - 1 bytes.
+ */
+ while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) {
+ pos_state = s->dict.pos & s->lzma.pos_mask;
+
+ if (!rc_bit(&s->rc, &s->lzma.is_match[
+ s->lzma.state][pos_state])) {
+ lzma_literal(s);
+ } else {
+ if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state]))
+ lzma_rep_match(s, pos_state);
+ else
+ lzma_match(s, pos_state);
+
+ if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0))
+ return false;
+ }
+ }
+
+ /*
+ * Having the range decoder always normalized when we are outside
+ * this function makes it easier to correctly handle end of the chunk.
+ */
+ rc_normalize(&s->rc);
+
+ return true;
+}
+
+/*
+ * Reset the LZMA decoder and range decoder state. Dictionary is nore reset
+ * here, because LZMA state may be reset without resetting the dictionary.
+ */
+static void lzma_reset(struct xz_dec_lzma2 *s)
+{
+ uint16_t *probs;
+ size_t i;
+
+ s->lzma.state = STATE_LIT_LIT;
+ s->lzma.rep0 = 0;
+ s->lzma.rep1 = 0;
+ s->lzma.rep2 = 0;
+ s->lzma.rep3 = 0;
+
+ /*
+ * All probabilities are initialized to the same value. This hack
+ * makes the code smaller by avoiding a separate loop for each
+ * probability array.
+ *
+ * This could be optimized so that only that part of literal
+ * probabilities that are actually required. In the common case
+ * we would write 12 KiB less.
+ */
+ probs = s->lzma.is_match[0];
+ for (i = 0; i < PROBS_TOTAL; ++i)
+ probs[i] = RC_BIT_MODEL_TOTAL / 2;
+
+ rc_reset(&s->rc);
+}
+
+/*
+ * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks
+ * from the decoded lp and pb values. On success, the LZMA decoder state is
+ * reset and true is returned.
+ */
+static bool lzma_props(struct xz_dec_lzma2 *s, uint8_t props)
+{
+ if (props > (4 * 5 + 4) * 9 + 8)
+ return false;
+
+ s->lzma.pos_mask = 0;
+ while (props >= 9 * 5) {
+ props -= 9 * 5;
+ ++s->lzma.pos_mask;
+ }
+
+ s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1;
+
+ s->lzma.literal_pos_mask = 0;
+ while (props >= 9) {
+ props -= 9;
+ ++s->lzma.literal_pos_mask;
+ }
+
+ s->lzma.lc = props;
+
+ if (s->lzma.lc + s->lzma.literal_pos_mask > 4)
+ return false;
+
+ s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1;
+
+ lzma_reset(s);
+
+ return true;
+}
+
+/*********
+ * LZMA2 *
+ *********/
+
+/*
+ * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't
+ * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This
+ * wrapper function takes care of making the LZMA decoder's assumption safe.
+ *
+ * As long as there is plenty of input left to be decoded in the current LZMA
+ * chunk, we decode directly from the caller-supplied input buffer until
+ * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into
+ * s->temp.buf, which (hopefully) gets filled on the next call to this
+ * function. We decode a few bytes from the temporary buffer so that we can
+ * continue decoding from the caller-supplied input buffer again.
+ */
+static bool lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b)
+{
+ size_t in_avail;
+ uint32_t tmp;
+
+ in_avail = b->in_size - b->in_pos;
+ if (s->temp.size > 0 || s->lzma2.compressed == 0) {
+ tmp = 2 * LZMA_IN_REQUIRED - s->temp.size;
+ if (tmp > s->lzma2.compressed - s->temp.size)
+ tmp = s->lzma2.compressed - s->temp.size;
+ if (tmp > in_avail)
+ tmp = in_avail;
+
+ memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp);
+
+ if (s->temp.size + tmp == s->lzma2.compressed) {
+ memzero(s->temp.buf + s->temp.size + tmp,
+ sizeof(s->temp.buf)
+ - s->temp.size - tmp);
+ s->rc.in_limit = s->temp.size + tmp;
+ } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) {
+ s->temp.size += tmp;
+ b->in_pos += tmp;
+ return true;
+ } else {
+ s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED;
+ }
+
+ s->rc.in = s->temp.buf;
+ s->rc.in_pos = 0;
+
+ if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp)
+ return false;
+
+ s->lzma2.compressed -= s->rc.in_pos;
+
+ if (s->rc.in_pos < s->temp.size) {
+ s->temp.size -= s->rc.in_pos;
+ memmove(s->temp.buf, s->temp.buf + s->rc.in_pos,
+ s->temp.size);
+ return true;
+ }
+
+ b->in_pos += s->rc.in_pos - s->temp.size;
+ s->temp.size = 0;
+ }
+
+ in_avail = b->in_size - b->in_pos;
+ if (in_avail >= LZMA_IN_REQUIRED) {
+ s->rc.in = b->in;
+ s->rc.in_pos = b->in_pos;
+
+ if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED)
+ s->rc.in_limit = b->in_pos + s->lzma2.compressed;
+ else
+ s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED;
+
+ if (!lzma_main(s))
+ return false;
+
+ in_avail = s->rc.in_pos - b->in_pos;
+ if (in_avail > s->lzma2.compressed)
+ return false;
+
+ s->lzma2.compressed -= in_avail;
+ b->in_pos = s->rc.in_pos;
+ }
+
+ in_avail = b->in_size - b->in_pos;
+ if (in_avail < LZMA_IN_REQUIRED) {
+ if (in_avail > s->lzma2.compressed)
+ in_avail = s->lzma2.compressed;
+
+ memcpy(s->temp.buf, b->in + b->in_pos, in_avail);
+ s->temp.size = in_avail;
+ b->in_pos += in_avail;
+ }
+
+ return true;
+}
+
+/*
+ * Take care of the LZMA2 control layer, and forward the job of actual LZMA
+ * decoding or copying of uncompressed chunks to other functions.
+ */
+XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
+ struct xz_buf *b)
+{
+ uint32_t tmp;
+
+ while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) {
+ switch (s->lzma2.sequence) {
+ case SEQ_CONTROL:
+ /*
+ * LZMA2 control byte
+ *
+ * Exact values:
+ * 0x00 End marker
+ * 0x01 Dictionary reset followed by
+ * an uncompressed chunk
+ * 0x02 Uncompressed chunk (no dictionary reset)
+ *
+ * Highest three bits (s->control & 0xE0):
+ * 0xE0 Dictionary reset, new properties and state
+ * reset, followed by LZMA compressed chunk
+ * 0xC0 New properties and state reset, followed
+ * by LZMA compressed chunk (no dictionary
+ * reset)
+ * 0xA0 State reset using old properties,
+ * followed by LZMA compressed chunk (no
+ * dictionary reset)
+ * 0x80 LZMA chunk (no dictionary or state reset)
+ *
+ * For LZMA compressed chunks, the lowest five bits
+ * (s->control & 1F) are the highest bits of the
+ * uncompressed size (bits 16-20).
+ *
+ * A new LZMA2 stream must begin with a dictionary
+ * reset. The first LZMA chunk must set new
+ * properties and reset the LZMA state.
+ *
+ * Values that don't match anything described above
+ * are invalid and we return XZ_DATA_ERROR.
+ */
+ tmp = b->in[b->in_pos++];
+
+ if (tmp == 0x00)
+ return XZ_STREAM_END;
+
+ if (tmp >= 0xE0 || tmp == 0x01) {
+ s->lzma2.need_props = true;
+ s->lzma2.need_dict_reset = false;
+ dict_reset(&s->dict, b);
+ } else if (s->lzma2.need_dict_reset) {
+ return XZ_DATA_ERROR;
+ }
+
+ if (tmp >= 0x80) {
+ s->lzma2.uncompressed = (tmp & 0x1F) << 16;
+ s->lzma2.sequence = SEQ_UNCOMPRESSED_1;
+
+ if (tmp >= 0xC0) {
+ /*
+ * When there are new properties,
+ * state reset is done at
+ * SEQ_PROPERTIES.
+ */
+ s->lzma2.need_props = false;
+ s->lzma2.next_sequence
+ = SEQ_PROPERTIES;
+
+ } else if (s->lzma2.need_props) {
+ return XZ_DATA_ERROR;
+
+ } else {
+ s->lzma2.next_sequence
+ = SEQ_LZMA_PREPARE;
+ if (tmp >= 0xA0)
+ lzma_reset(s);
+ }
+ } else {
+ if (tmp > 0x02)
+ return XZ_DATA_ERROR;
+
+ s->lzma2.sequence = SEQ_COMPRESSED_0;
+ s->lzma2.next_sequence = SEQ_COPY;
+ }
+
+ break;
+
+ case SEQ_UNCOMPRESSED_1:
+ s->lzma2.uncompressed
+ += (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.sequence = SEQ_UNCOMPRESSED_2;
+ break;
+
+ case SEQ_UNCOMPRESSED_2:
+ s->lzma2.uncompressed
+ += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.sequence = SEQ_COMPRESSED_0;
+ break;
+
+ case SEQ_COMPRESSED_0:
+ s->lzma2.compressed
+ = (uint32_t)b->in[b->in_pos++] << 8;
+ s->lzma2.sequence = SEQ_COMPRESSED_1;
+ break;
+
+ case SEQ_COMPRESSED_1:
+ s->lzma2.compressed
+ += (uint32_t)b->in[b->in_pos++] + 1;
+ s->lzma2.sequence = s->lzma2.next_sequence;
+ break;
+
+ case SEQ_PROPERTIES:
+ if (!lzma_props(s, b->in[b->in_pos++]))
+ return XZ_DATA_ERROR;
+
+ s->lzma2.sequence = SEQ_LZMA_PREPARE;
+
+ case SEQ_LZMA_PREPARE:
+ if (s->lzma2.compressed < RC_INIT_BYTES)
+ return XZ_DATA_ERROR;
+
+ if (!rc_read_init(&s->rc, b))
+ return XZ_OK;
+
+ s->lzma2.compressed -= RC_INIT_BYTES;
+ s->lzma2.sequence = SEQ_LZMA_RUN;
+
+ case SEQ_LZMA_RUN:
+ /*
+ * Set dictionary limit to indicate how much we want
+ * to be encoded at maximum. Decode new data into the
+ * dictionary. Flush the new data from dictionary to
+ * b->out. Check if we finished decoding this chunk.
+ * In case the dictionary got full but we didn't fill
+ * the output buffer yet, we may run this loop
+ * multiple times without changing s->lzma2.sequence.
+ */
+ dict_limit(&s->dict, min_t(size_t,
+ b->out_size - b->out_pos,
+ s->lzma2.uncompressed));
+ if (!lzma2_lzma(s, b))
+ return XZ_DATA_ERROR;
+
+ s->lzma2.uncompressed -= dict_flush(&s->dict, b);
+
+ if (s->lzma2.uncompressed == 0) {
+ if (s->lzma2.compressed > 0 || s->lzma.len > 0
+ || !rc_is_finished(&s->rc))
+ return XZ_DATA_ERROR;
+
+ rc_reset(&s->rc);
+ s->lzma2.sequence = SEQ_CONTROL;
+
+ } else if (b->out_pos == b->out_size
+ || (b->in_pos == b->in_size
+ && s->temp.size
+ < s->lzma2.compressed)) {
+ return XZ_OK;
+ }
+
+ break;
+
+ case SEQ_COPY:
+ dict_uncompressed(&s->dict, b, &s->lzma2.compressed);
+ if (s->lzma2.compressed > 0)
+ return XZ_OK;
+
+ s->lzma2.sequence = SEQ_CONTROL;
+ break;
+ }
+ }
+
+ return XZ_OK;
+}
+
+XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
+ uint32_t dict_max)
+{
+ struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL)
+ return NULL;
+
+ s->dict.mode = mode;
+ s->dict.size_max = dict_max;
+
+ if (DEC_IS_PREALLOC(mode)) {
+ s->dict.buf = vmalloc(dict_max);
+ if (s->dict.buf == NULL) {
+ kfree(s);
+ return NULL;
+ }
+ } else if (DEC_IS_DYNALLOC(mode)) {
+ s->dict.buf = NULL;
+ s->dict.allocated = 0;
+ }
+
+ return s;
+}
+
+XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props)
+{
+ /* This limits dictionary size to 3 GiB to keep parsing simpler. */
+ if (props > 39)
+ return XZ_OPTIONS_ERROR;
+
+ s->dict.size = 2 + (props & 1);
+ s->dict.size <<= (props >> 1) + 11;
+
+ if (DEC_IS_MULTI(s->dict.mode)) {
+ if (s->dict.size > s->dict.size_max)
+ return XZ_MEMLIMIT_ERROR;
+
+ s->dict.end = s->dict.size;
+
+ if (DEC_IS_DYNALLOC(s->dict.mode)) {
+ if (s->dict.allocated < s->dict.size) {
+ vfree(s->dict.buf);
+ s->dict.buf = vmalloc(s->dict.size);
+ if (s->dict.buf == NULL) {
+ s->dict.allocated = 0;
+ return XZ_MEM_ERROR;
+ }
+ }
+ }
+ }
+
+ s->lzma.len = 0;
+
+ s->lzma2.sequence = SEQ_CONTROL;
+ s->lzma2.need_dict_reset = true;
+
+ s->temp.size = 0;
+
+ return XZ_OK;
+}
+
+XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s)
+{
+ if (DEC_IS_MULTI(s->dict.mode))
+ vfree(s->dict.buf);
+
+ kfree(s);
+}
--- /dev/null
+/*
+ * .xz Stream decoder
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include "xz_private.h"
+#include "xz_stream.h"
+
+#ifdef XZ_USE_CRC64
+# define IS_CRC64(check_type) ((check_type) == XZ_CHECK_CRC64)
+#else
+# define IS_CRC64(check_type) false
+#endif
+
+/* Hash used to validate the Index field */
+struct xz_dec_hash {
+ vli_type unpadded;
+ vli_type uncompressed;
+ uint32_t crc32;
+};
+
+struct xz_dec {
+ /* Position in dec_main() */
+ enum {
+ SEQ_STREAM_HEADER,
+ SEQ_BLOCK_START,
+ SEQ_BLOCK_HEADER,
+ SEQ_BLOCK_UNCOMPRESS,
+ SEQ_BLOCK_PADDING,
+ SEQ_BLOCK_CHECK,
+ SEQ_INDEX,
+ SEQ_INDEX_PADDING,
+ SEQ_INDEX_CRC32,
+ SEQ_STREAM_FOOTER
+ } sequence;
+
+ /* Position in variable-length integers and Check fields */
+ uint32_t pos;
+
+ /* Variable-length integer decoded by dec_vli() */
+ vli_type vli;
+
+ /* Saved in_pos and out_pos */
+ size_t in_start;
+ size_t out_start;
+
+#ifdef XZ_USE_CRC64
+ /* CRC32 or CRC64 value in Block or CRC32 value in Index */
+ uint64_t crc;
+#else
+ /* CRC32 value in Block or Index */
+ uint32_t crc;
+#endif
+
+ /* Type of the integrity check calculated from uncompressed data */
+ enum xz_check check_type;
+
+ /* Operation mode */
+ enum xz_mode mode;
+
+ /*
+ * True if the next call to xz_dec_run() is allowed to return
+ * XZ_BUF_ERROR.
+ */
+ bool allow_buf_error;
+
+ /* Information stored in Block Header */
+ struct {
+ /*
+ * Value stored in the Compressed Size field, or
+ * VLI_UNKNOWN if Compressed Size is not present.
+ */
+ vli_type compressed;
+
+ /*
+ * Value stored in the Uncompressed Size field, or
+ * VLI_UNKNOWN if Uncompressed Size is not present.
+ */
+ vli_type uncompressed;
+
+ /* Size of the Block Header field */
+ uint32_t size;
+ } block_header;
+
+ /* Information collected when decoding Blocks */
+ struct {
+ /* Observed compressed size of the current Block */
+ vli_type compressed;
+
+ /* Observed uncompressed size of the current Block */
+ vli_type uncompressed;
+
+ /* Number of Blocks decoded so far */
+ vli_type count;
+
+ /*
+ * Hash calculated from the Block sizes. This is used to
+ * validate the Index field.
+ */
+ struct xz_dec_hash hash;
+ } block;
+
+ /* Variables needed when verifying the Index field */
+ struct {
+ /* Position in dec_index() */
+ enum {
+ SEQ_INDEX_COUNT,
+ SEQ_INDEX_UNPADDED,
+ SEQ_INDEX_UNCOMPRESSED
+ } sequence;
+
+ /* Size of the Index in bytes */
+ vli_type size;
+
+ /* Number of Records (matches block.count in valid files) */
+ vli_type count;
+
+ /*
+ * Hash calculated from the Records (matches block.hash in
+ * valid files).
+ */
+ struct xz_dec_hash hash;
+ } index;
+
+ /*
+ * Temporary buffer needed to hold Stream Header, Block Header,
+ * and Stream Footer. The Block Header is the biggest (1 KiB)
+ * so we reserve space according to that. buf[] has to be aligned
+ * to a multiple of four bytes; the size_t variables before it
+ * should guarantee this.
+ */
+ struct {
+ size_t pos;
+ size_t size;
+ uint8_t buf[1024];
+ } temp;
+
+ struct xz_dec_lzma2 *lzma2;
+
+#ifdef XZ_DEC_BCJ
+ struct xz_dec_bcj *bcj;
+ bool bcj_active;
+#endif
+};
+
+#ifdef XZ_DEC_ANY_CHECK
+/* Sizes of the Check field with different Check IDs */
+static const uint8_t check_sizes[16] = {
+ 0,
+ 4, 4, 4,
+ 8, 8, 8,
+ 16, 16, 16,
+ 32, 32, 32,
+ 64, 64, 64
+};
+#endif
+
+/*
+ * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller
+ * must have set s->temp.pos to indicate how much data we are supposed
+ * to copy into s->temp.buf. Return true once s->temp.pos has reached
+ * s->temp.size.
+ */
+static bool fill_temp(struct xz_dec *s, struct xz_buf *b)
+{
+ size_t copy_size = min_t(size_t,
+ b->in_size - b->in_pos, s->temp.size - s->temp.pos);
+
+ memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
+ b->in_pos += copy_size;
+ s->temp.pos += copy_size;
+
+ if (s->temp.pos == s->temp.size) {
+ s->temp.pos = 0;
+ return true;
+ }
+
+ return false;
+}
+
+/* Decode a variable-length integer (little-endian base-128 encoding) */
+static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
+ size_t *in_pos, size_t in_size)
+{
+ uint8_t byte;
+
+ if (s->pos == 0)
+ s->vli = 0;
+
+ while (*in_pos < in_size) {
+ byte = in[*in_pos];
+ ++*in_pos;
+
+ s->vli |= (vli_type)(byte & 0x7F) << s->pos;
+
+ if ((byte & 0x80) == 0) {
+ /* Don't allow non-minimal encodings. */
+ if (byte == 0 && s->pos != 0)
+ return XZ_DATA_ERROR;
+
+ s->pos = 0;
+ return XZ_STREAM_END;
+ }
+
+ s->pos += 7;
+ if (s->pos == 7 * VLI_BYTES_MAX)
+ return XZ_DATA_ERROR;
+ }
+
+ return XZ_OK;
+}
+
+/*
+ * Decode the Compressed Data field from a Block. Update and validate
+ * the observed compressed and uncompressed sizes of the Block so that
+ * they don't exceed the values possibly stored in the Block Header
+ * (validation assumes that no integer overflow occurs, since vli_type
+ * is normally uint64_t). Update the CRC32 or CRC64 value if presence of
+ * the CRC32 or CRC64 field was indicated in Stream Header.
+ *
+ * Once the decoding is finished, validate that the observed sizes match
+ * the sizes possibly stored in the Block Header. Update the hash and
+ * Block count, which are later used to validate the Index field.
+ */
+static enum xz_ret dec_block(struct xz_dec *s, struct xz_buf *b)
+{
+ enum xz_ret ret;
+
+ s->in_start = b->in_pos;
+ s->out_start = b->out_pos;
+
+#ifdef XZ_DEC_BCJ
+ if (s->bcj_active)
+ ret = xz_dec_bcj_run(s->bcj, s->lzma2, b);
+ else
+#endif
+ ret = xz_dec_lzma2_run(s->lzma2, b);
+
+ s->block.compressed += b->in_pos - s->in_start;
+ s->block.uncompressed += b->out_pos - s->out_start;
+
+ /*
+ * There is no need to separately check for VLI_UNKNOWN, since
+ * the observed sizes are always smaller than VLI_UNKNOWN.
+ */
+ if (s->block.compressed > s->block_header.compressed
+ || s->block.uncompressed
+ > s->block_header.uncompressed)
+ return XZ_DATA_ERROR;
+
+ if (s->check_type == XZ_CHECK_CRC32)
+ s->crc = xz_crc32(b->out + s->out_start,
+ b->out_pos - s->out_start, s->crc);
+#ifdef XZ_USE_CRC64
+ else if (s->check_type == XZ_CHECK_CRC64)
+ s->crc = xz_crc64(b->out + s->out_start,
+ b->out_pos - s->out_start, s->crc);
+#endif
+
+ if (ret == XZ_STREAM_END) {
+ if (s->block_header.compressed != VLI_UNKNOWN
+ && s->block_header.compressed
+ != s->block.compressed)
+ return XZ_DATA_ERROR;
+
+ if (s->block_header.uncompressed != VLI_UNKNOWN
+ && s->block_header.uncompressed
+ != s->block.uncompressed)
+ return XZ_DATA_ERROR;
+
+ s->block.hash.unpadded += s->block_header.size
+ + s->block.compressed;
+
+#ifdef XZ_DEC_ANY_CHECK
+ s->block.hash.unpadded += check_sizes[s->check_type];
+#else
+ if (s->check_type == XZ_CHECK_CRC32)
+ s->block.hash.unpadded += 4;
+ else if (IS_CRC64(s->check_type))
+ s->block.hash.unpadded += 8;
+#endif
+
+ s->block.hash.uncompressed += s->block.uncompressed;
+ s->block.hash.crc32 = xz_crc32(
+ (const uint8_t *)&s->block.hash,
+ sizeof(s->block.hash), s->block.hash.crc32);
+
+ ++s->block.count;
+ }
+
+ return ret;
+}
+
+/* Update the Index size and the CRC32 value. */
+static void index_update(struct xz_dec *s, const struct xz_buf *b)
+{
+ size_t in_used = b->in_pos - s->in_start;
+ s->index.size += in_used;
+ s->crc = xz_crc32(b->in + s->in_start, in_used, s->crc);
+}
+
+/*
+ * Decode the Number of Records, Unpadded Size, and Uncompressed Size
+ * fields from the Index field. That is, Index Padding and CRC32 are not
+ * decoded by this function.
+ *
+ * This can return XZ_OK (more input needed), XZ_STREAM_END (everything
+ * successfully decoded), or XZ_DATA_ERROR (input is corrupt).
+ */
+static enum xz_ret dec_index(struct xz_dec *s, struct xz_buf *b)
+{
+ enum xz_ret ret;
+
+ do {
+ ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
+ if (ret != XZ_STREAM_END) {
+ index_update(s, b);
+ return ret;
+ }
+
+ switch (s->index.sequence) {
+ case SEQ_INDEX_COUNT:
+ s->index.count = s->vli;
+
+ /*
+ * Validate that the Number of Records field
+ * indicates the same number of Records as
+ * there were Blocks in the Stream.
+ */
+ if (s->index.count != s->block.count)
+ return XZ_DATA_ERROR;
+
+ s->index.sequence = SEQ_INDEX_UNPADDED;
+ break;
+
+ case SEQ_INDEX_UNPADDED:
+ s->index.hash.unpadded += s->vli;
+ s->index.sequence = SEQ_INDEX_UNCOMPRESSED;
+ break;
+
+ case SEQ_INDEX_UNCOMPRESSED:
+ s->index.hash.uncompressed += s->vli;
+ s->index.hash.crc32 = xz_crc32(
+ (const uint8_t *)&s->index.hash,
+ sizeof(s->index.hash),
+ s->index.hash.crc32);
+ --s->index.count;
+ s->index.sequence = SEQ_INDEX_UNPADDED;
+ break;
+ }
+ } while (s->index.count > 0);
+
+ return XZ_STREAM_END;
+}
+
+/*
+ * Validate that the next four or eight input bytes match the value
+ * of s->crc. s->pos must be zero when starting to validate the first byte.
+ * The "bits" argument allows using the same code for both CRC32 and CRC64.
+ */
+static enum xz_ret crc_validate(struct xz_dec *s, struct xz_buf *b,
+ uint32_t bits)
+{
+ do {
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ if (((s->crc >> s->pos) & 0xFF) != b->in[b->in_pos++])
+ return XZ_DATA_ERROR;
+
+ s->pos += 8;
+
+ } while (s->pos < bits);
+
+ s->crc = 0;
+ s->pos = 0;
+
+ return XZ_STREAM_END;
+}
+
+#ifdef XZ_DEC_ANY_CHECK
+/*
+ * Skip over the Check field when the Check ID is not supported.
+ * Returns true once the whole Check field has been skipped over.
+ */
+static bool check_skip(struct xz_dec *s, struct xz_buf *b)
+{
+ while (s->pos < check_sizes[s->check_type]) {
+ if (b->in_pos == b->in_size)
+ return false;
+
+ ++b->in_pos;
+ ++s->pos;
+ }
+
+ s->pos = 0;
+
+ return true;
+}
+#endif
+
+/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */
+static enum xz_ret dec_stream_header(struct xz_dec *s)
+{
+ if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE))
+ return XZ_FORMAT_ERROR;
+
+ if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0)
+ != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2))
+ return XZ_DATA_ERROR;
+
+ if (s->temp.buf[HEADER_MAGIC_SIZE] != 0)
+ return XZ_OPTIONS_ERROR;
+
+ /*
+ * Of integrity checks, we support none (Check ID = 0),
+ * CRC32 (Check ID = 1), and optionally CRC64 (Check ID = 4).
+ * However, if XZ_DEC_ANY_CHECK is defined, we will accept other
+ * check types too, but then the check won't be verified and
+ * a warning (XZ_UNSUPPORTED_CHECK) will be given.
+ */
+ s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1];
+
+#ifdef XZ_DEC_ANY_CHECK
+ if (s->check_type > XZ_CHECK_MAX)
+ return XZ_OPTIONS_ERROR;
+
+ if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
+ return XZ_UNSUPPORTED_CHECK;
+#else
+ if (s->check_type > XZ_CHECK_CRC32 && !IS_CRC64(s->check_type))
+ return XZ_OPTIONS_ERROR;
+#endif
+
+ return XZ_OK;
+}
+
+/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */
+static enum xz_ret dec_stream_footer(struct xz_dec *s)
+{
+ if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE))
+ return XZ_DATA_ERROR;
+
+ if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf))
+ return XZ_DATA_ERROR;
+
+ /*
+ * Validate Backward Size. Note that we never added the size of the
+ * Index CRC32 field to s->index.size, thus we use s->index.size / 4
+ * instead of s->index.size / 4 - 1.
+ */
+ if ((s->index.size >> 2) != get_le32(s->temp.buf + 4))
+ return XZ_DATA_ERROR;
+
+ if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type)
+ return XZ_DATA_ERROR;
+
+ /*
+ * Use XZ_STREAM_END instead of XZ_OK to be more convenient
+ * for the caller.
+ */
+ return XZ_STREAM_END;
+}
+
+/* Decode the Block Header and initialize the filter chain. */
+static enum xz_ret dec_block_header(struct xz_dec *s)
+{
+ enum xz_ret ret;
+
+ /*
+ * Validate the CRC32. We know that the temp buffer is at least
+ * eight bytes so this is safe.
+ */
+ s->temp.size -= 4;
+ if (xz_crc32(s->temp.buf, s->temp.size, 0)
+ != get_le32(s->temp.buf + s->temp.size))
+ return XZ_DATA_ERROR;
+
+ s->temp.pos = 2;
+
+ /*
+ * Catch unsupported Block Flags. We support only one or two filters
+ * in the chain, so we catch that with the same test.
+ */
+#ifdef XZ_DEC_BCJ
+ if (s->temp.buf[1] & 0x3E)
+#else
+ if (s->temp.buf[1] & 0x3F)
+#endif
+ return XZ_OPTIONS_ERROR;
+
+ /* Compressed Size */
+ if (s->temp.buf[1] & 0x40) {
+ if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+ != XZ_STREAM_END)
+ return XZ_DATA_ERROR;
+
+ s->block_header.compressed = s->vli;
+ } else {
+ s->block_header.compressed = VLI_UNKNOWN;
+ }
+
+ /* Uncompressed Size */
+ if (s->temp.buf[1] & 0x80) {
+ if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size)
+ != XZ_STREAM_END)
+ return XZ_DATA_ERROR;
+
+ s->block_header.uncompressed = s->vli;
+ } else {
+ s->block_header.uncompressed = VLI_UNKNOWN;
+ }
+
+#ifdef XZ_DEC_BCJ
+ /* If there are two filters, the first one must be a BCJ filter. */
+ s->bcj_active = s->temp.buf[1] & 0x01;
+ if (s->bcj_active) {
+ if (s->temp.size - s->temp.pos < 2)
+ return XZ_OPTIONS_ERROR;
+
+ ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]);
+ if (ret != XZ_OK)
+ return ret;
+
+ /*
+ * We don't support custom start offset,
+ * so Size of Properties must be zero.
+ */
+ if (s->temp.buf[s->temp.pos++] != 0x00)
+ return XZ_OPTIONS_ERROR;
+ }
+#endif
+
+ /* Valid Filter Flags always take at least two bytes. */
+ if (s->temp.size - s->temp.pos < 2)
+ return XZ_DATA_ERROR;
+
+ /* Filter ID = LZMA2 */
+ if (s->temp.buf[s->temp.pos++] != 0x21)
+ return XZ_OPTIONS_ERROR;
+
+ /* Size of Properties = 1-byte Filter Properties */
+ if (s->temp.buf[s->temp.pos++] != 0x01)
+ return XZ_OPTIONS_ERROR;
+
+ /* Filter Properties contains LZMA2 dictionary size. */
+ if (s->temp.size - s->temp.pos < 1)
+ return XZ_DATA_ERROR;
+
+ ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]);
+ if (ret != XZ_OK)
+ return ret;
+
+ /* The rest must be Header Padding. */
+ while (s->temp.pos < s->temp.size)
+ if (s->temp.buf[s->temp.pos++] != 0x00)
+ return XZ_OPTIONS_ERROR;
+
+ s->temp.pos = 0;
+ s->block.compressed = 0;
+ s->block.uncompressed = 0;
+
+ return XZ_OK;
+}
+
+static enum xz_ret dec_main(struct xz_dec *s, struct xz_buf *b)
+{
+ enum xz_ret ret;
+
+ /*
+ * Store the start position for the case when we are in the middle
+ * of the Index field.
+ */
+ s->in_start = b->in_pos;
+
+ while (true) {
+ switch (s->sequence) {
+ case SEQ_STREAM_HEADER:
+ /*
+ * Stream Header is copied to s->temp, and then
+ * decoded from there. This way if the caller
+ * gives us only little input at a time, we can
+ * still keep the Stream Header decoding code
+ * simple. Similar approach is used in many places
+ * in this file.
+ */
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ /*
+ * If dec_stream_header() returns
+ * XZ_UNSUPPORTED_CHECK, it is still possible
+ * to continue decoding if working in multi-call
+ * mode. Thus, update s->sequence before calling
+ * dec_stream_header().
+ */
+ s->sequence = SEQ_BLOCK_START;
+
+ ret = dec_stream_header(s);
+ if (ret != XZ_OK)
+ return ret;
+
+ case SEQ_BLOCK_START:
+ /* We need one byte of input to continue. */
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ /* See if this is the beginning of the Index field. */
+ if (b->in[b->in_pos] == 0) {
+ s->in_start = b->in_pos++;
+ s->sequence = SEQ_INDEX;
+ break;
+ }
+
+ /*
+ * Calculate the size of the Block Header and
+ * prepare to decode it.
+ */
+ s->block_header.size
+ = ((uint32_t)b->in[b->in_pos] + 1) * 4;
+
+ s->temp.size = s->block_header.size;
+ s->temp.pos = 0;
+ s->sequence = SEQ_BLOCK_HEADER;
+
+ case SEQ_BLOCK_HEADER:
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ ret = dec_block_header(s);
+ if (ret != XZ_OK)
+ return ret;
+
+ s->sequence = SEQ_BLOCK_UNCOMPRESS;
+
+ case SEQ_BLOCK_UNCOMPRESS:
+ ret = dec_block(s, b);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->sequence = SEQ_BLOCK_PADDING;
+
+ case SEQ_BLOCK_PADDING:
+ /*
+ * Size of Compressed Data + Block Padding
+ * must be a multiple of four. We don't need
+ * s->block.compressed for anything else
+ * anymore, so we use it here to test the size
+ * of the Block Padding field.
+ */
+ while (s->block.compressed & 3) {
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ if (b->in[b->in_pos++] != 0)
+ return XZ_DATA_ERROR;
+
+ ++s->block.compressed;
+ }
+
+ s->sequence = SEQ_BLOCK_CHECK;
+
+ case SEQ_BLOCK_CHECK:
+ if (s->check_type == XZ_CHECK_CRC32) {
+ ret = crc_validate(s, b, 32);
+ if (ret != XZ_STREAM_END)
+ return ret;
+ }
+ else if (IS_CRC64(s->check_type)) {
+ ret = crc_validate(s, b, 64);
+ if (ret != XZ_STREAM_END)
+ return ret;
+ }
+#ifdef XZ_DEC_ANY_CHECK
+ else if (!check_skip(s, b)) {
+ return XZ_OK;
+ }
+#endif
+
+ s->sequence = SEQ_BLOCK_START;
+ break;
+
+ case SEQ_INDEX:
+ ret = dec_index(s, b);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->sequence = SEQ_INDEX_PADDING;
+
+ case SEQ_INDEX_PADDING:
+ while ((s->index.size + (b->in_pos - s->in_start))
+ & 3) {
+ if (b->in_pos == b->in_size) {
+ index_update(s, b);
+ return XZ_OK;
+ }
+
+ if (b->in[b->in_pos++] != 0)
+ return XZ_DATA_ERROR;
+ }
+
+ /* Finish the CRC32 value and Index size. */
+ index_update(s, b);
+
+ /* Compare the hashes to validate the Index field. */
+ if (!memeq(&s->block.hash, &s->index.hash,
+ sizeof(s->block.hash)))
+ return XZ_DATA_ERROR;
+
+ s->sequence = SEQ_INDEX_CRC32;
+
+ case SEQ_INDEX_CRC32:
+ ret = crc_validate(s, b, 32);
+ if (ret != XZ_STREAM_END)
+ return ret;
+
+ s->temp.size = STREAM_HEADER_SIZE;
+ s->sequence = SEQ_STREAM_FOOTER;
+
+ case SEQ_STREAM_FOOTER:
+ if (!fill_temp(s, b))
+ return XZ_OK;
+
+ return dec_stream_footer(s);
+ }
+ }
+
+ /* Never reached */
+}
+
+/*
+ * xz_dec_run() is a wrapper for dec_main() to handle some special cases in
+ * multi-call and single-call decoding.
+ *
+ * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we
+ * are not going to make any progress anymore. This is to prevent the caller
+ * from calling us infinitely when the input file is truncated or otherwise
+ * corrupt. Since zlib-style API allows that the caller fills the input buffer
+ * only when the decoder doesn't produce any new output, we have to be careful
+ * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only
+ * after the second consecutive call to xz_dec_run() that makes no progress.
+ *
+ * In single-call mode, if we couldn't decode everything and no error
+ * occurred, either the input is truncated or the output buffer is too small.
+ * Since we know that the last input byte never produces any output, we know
+ * that if all the input was consumed and decoding wasn't finished, the file
+ * must be corrupt. Otherwise the output buffer has to be too small or the
+ * file is corrupt in a way that decoding it produces too big output.
+ *
+ * If single-call decoding fails, we reset b->in_pos and b->out_pos back to
+ * their original values. This is because with some filter chains there won't
+ * be any valid uncompressed data in the output buffer unless the decoding
+ * actually succeeds (that's the price to pay of using the output buffer as
+ * the workspace).
+ */
+XZ_EXTERN enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
+{
+ size_t in_start;
+ size_t out_start;
+ enum xz_ret ret;
+
+ if (DEC_IS_SINGLE(s->mode))
+ xz_dec_reset(s);
+
+ in_start = b->in_pos;
+ out_start = b->out_pos;
+ ret = dec_main(s, b);
+
+ if (DEC_IS_SINGLE(s->mode)) {
+ if (ret == XZ_OK)
+ ret = b->in_pos == b->in_size
+ ? XZ_DATA_ERROR : XZ_BUF_ERROR;
+
+ if (ret != XZ_STREAM_END) {
+ b->in_pos = in_start;
+ b->out_pos = out_start;
+ }
+
+ } else if (ret == XZ_OK && in_start == b->in_pos
+ && out_start == b->out_pos) {
+ if (s->allow_buf_error)
+ ret = XZ_BUF_ERROR;
+
+ s->allow_buf_error = true;
+ } else {
+ s->allow_buf_error = false;
+ }
+
+ return ret;
+}
+
+XZ_EXTERN struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
+{
+ struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL);
+ if (s == NULL)
+ return NULL;
+
+ s->mode = mode;
+
+#ifdef XZ_DEC_BCJ
+ s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode));
+ if (s->bcj == NULL)
+ goto error_bcj;
+#endif
+
+ s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
+ if (s->lzma2 == NULL)
+ goto error_lzma2;
+
+ xz_dec_reset(s);
+ return s;
+
+error_lzma2:
+#ifdef XZ_DEC_BCJ
+ xz_dec_bcj_end(s->bcj);
+error_bcj:
+#endif
+ kfree(s);
+ return NULL;
+}
+
+XZ_EXTERN void xz_dec_reset(struct xz_dec *s)
+{
+ s->sequence = SEQ_STREAM_HEADER;
+ s->allow_buf_error = false;
+ s->pos = 0;
+ s->crc = 0;
+ memzero(&s->block, sizeof(s->block));
+ memzero(&s->index, sizeof(s->index));
+ s->temp.pos = 0;
+ s->temp.size = STREAM_HEADER_SIZE;
+}
+
+XZ_EXTERN void xz_dec_end(struct xz_dec *s)
+{
+ if (s != NULL) {
+ xz_dec_lzma2_end(s->lzma2);
+#ifdef XZ_DEC_BCJ
+ xz_dec_bcj_end(s->bcj);
+#endif
+ kfree(s);
+ }
+}
--- /dev/null
+/*
+ * XZ decoder module information
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include <linux/module.h>
+#include <linux/xz.h>
+
+EXPORT_SYMBOL(xz_dec_init);
+EXPORT_SYMBOL(xz_dec_reset);
+EXPORT_SYMBOL(xz_dec_run);
+EXPORT_SYMBOL(xz_dec_end);
+
+MODULE_DESCRIPTION("XZ decompressor");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org> and Igor Pavlov");
+
+/*
+ * This code is in the public domain, but in Linux it's simplest to just
+ * say it's GPL and consider the authors as the copyright holders.
+ */
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * XZ decoder tester
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/crc32.h>
+#include <linux/xz.h>
+
+/* Maximum supported dictionary size */
+#define DICT_MAX (1 << 20)
+
+/* Device name to pass to register_chrdev(). */
+#define DEVICE_NAME "xz_dec_test"
+
+/* Dynamically allocated device major number */
+static int device_major;
+
+/*
+ * We reuse the same decoder state, and thus can decode only one
+ * file at a time.
+ */
+static bool device_is_open;
+
+/* XZ decoder state */
+static struct xz_dec *state;
+
+/*
+ * Return value of xz_dec_run(). We need to avoid calling xz_dec_run() after
+ * it has returned XZ_STREAM_END, so we make this static.
+ */
+static enum xz_ret ret;
+
+/*
+ * Input and output buffers. The input buffer is used as a temporary safe
+ * place for the data coming from the userspace.
+ */
+static uint8_t buffer_in[1024];
+static uint8_t buffer_out[1024];
+
+/*
+ * Structure to pass the input and output buffers to the XZ decoder.
+ * A few of the fields are never modified so we initialize them here.
+ */
+static struct xz_buf buffers = {
+ .in = buffer_in,
+ .out = buffer_out,
+ .out_size = sizeof(buffer_out)
+};
+
+/*
+ * CRC32 of uncompressed data. This is used to give the user a simple way
+ * to check that the decoder produces correct output.
+ */
+static uint32_t crc;
+
+static int xz_dec_test_open(struct inode *i, struct file *f)
+{
+ if (device_is_open)
+ return -EBUSY;
+
+ device_is_open = true;
+
+ xz_dec_reset(state);
+ ret = XZ_OK;
+ crc = 0xFFFFFFFF;
+
+ buffers.in_pos = 0;
+ buffers.in_size = 0;
+ buffers.out_pos = 0;
+
+ printk(KERN_INFO DEVICE_NAME ": opened\n");
+ return 0;
+}
+
+static int xz_dec_test_release(struct inode *i, struct file *f)
+{
+ device_is_open = false;
+
+ if (ret == XZ_OK)
+ printk(KERN_INFO DEVICE_NAME ": input was truncated\n");
+
+ printk(KERN_INFO DEVICE_NAME ": closed\n");
+ return 0;
+}
+
+/*
+ * Decode the data given to us from the userspace. CRC32 of the uncompressed
+ * data is calculated and is printed at the end of successful decoding. The
+ * uncompressed data isn't stored anywhere for further use.
+ *
+ * The .xz file must have exactly one Stream and no Stream Padding. The data
+ * after the first Stream is considered to be garbage.
+ */
+static ssize_t xz_dec_test_write(struct file *file, const char __user *buf,
+ size_t size, loff_t *pos)
+{
+ size_t remaining;
+
+ if (ret != XZ_OK) {
+ if (size > 0)
+ printk(KERN_INFO DEVICE_NAME ": %zu bytes of "
+ "garbage at the end of the file\n",
+ size);
+
+ return -ENOSPC;
+ }
+
+ printk(KERN_INFO DEVICE_NAME ": decoding %zu bytes of input\n",
+ size);
+
+ remaining = size;
+ while ((remaining > 0 || buffers.out_pos == buffers.out_size)
+ && ret == XZ_OK) {
+ if (buffers.in_pos == buffers.in_size) {
+ buffers.in_pos = 0;
+ buffers.in_size = min(remaining, sizeof(buffer_in));
+ if (copy_from_user(buffer_in, buf, buffers.in_size))
+ return -EFAULT;
+
+ buf += buffers.in_size;
+ remaining -= buffers.in_size;
+ }
+
+ buffers.out_pos = 0;
+ ret = xz_dec_run(state, &buffers);
+ crc = crc32(crc, buffer_out, buffers.out_pos);
+ }
+
+ switch (ret) {
+ case XZ_OK:
+ printk(KERN_INFO DEVICE_NAME ": XZ_OK\n");
+ return size;
+
+ case XZ_STREAM_END:
+ printk(KERN_INFO DEVICE_NAME ": XZ_STREAM_END, "
+ "CRC32 = 0x%08X\n", ~crc);
+ return size - remaining - (buffers.in_size - buffers.in_pos);
+
+ case XZ_MEMLIMIT_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_MEMLIMIT_ERROR\n");
+ break;
+
+ case XZ_FORMAT_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_FORMAT_ERROR\n");
+ break;
+
+ case XZ_OPTIONS_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_OPTIONS_ERROR\n");
+ break;
+
+ case XZ_DATA_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_DATA_ERROR\n");
+ break;
+
+ case XZ_BUF_ERROR:
+ printk(KERN_INFO DEVICE_NAME ": XZ_BUF_ERROR\n");
+ break;
+
+ default:
+ printk(KERN_INFO DEVICE_NAME ": Bug detected!\n");
+ break;
+ }
+
+ return -EIO;
+}
+
+/* Allocate the XZ decoder state and register the character device. */
+static int __init xz_dec_test_init(void)
+{
+ static const struct file_operations fileops = {
+ .owner = THIS_MODULE,
+ .open = &xz_dec_test_open,
+ .release = &xz_dec_test_release,
+ .write = &xz_dec_test_write
+ };
+
+ state = xz_dec_init(XZ_PREALLOC, DICT_MAX);
+ if (state == NULL)
+ return -ENOMEM;
+
+ device_major = register_chrdev(0, DEVICE_NAME, &fileops);
+ if (device_major < 0) {
+ xz_dec_end(state);
+ return device_major;
+ }
+
+ printk(KERN_INFO DEVICE_NAME ": module loaded\n");
+ printk(KERN_INFO DEVICE_NAME ": Create a device node with "
+ "'mknod " DEVICE_NAME " c %d 0' and write .xz files "
+ "to it.\n", device_major);
+ return 0;
+}
+
+static void __exit xz_dec_test_exit(void)
+{
+ unregister_chrdev(device_major, DEVICE_NAME);
+ xz_dec_end(state);
+ printk(KERN_INFO DEVICE_NAME ": module unloaded\n");
+}
+
+module_init(xz_dec_test_init);
+module_exit(xz_dec_test_exit);
+
+MODULE_DESCRIPTION("XZ decompressor tester");
+MODULE_VERSION("1.0");
+MODULE_AUTHOR("Lasse Collin <lasse.collin@tukaani.org>");
+
+/*
+ * This code is in the public domain, but in Linux it's simplest to just
+ * say it's GPL and consider the authors as the copyright holders.
+ */
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * LZMA2 definitions
+ *
+ * Authors: Lasse Collin <lasse.collin@tukaani.org>
+ * Igor Pavlov <http://7-zip.org/>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_LZMA2_H
+#define XZ_LZMA2_H
+
+/* Range coder constants */
+#define RC_SHIFT_BITS 8
+#define RC_TOP_BITS 24
+#define RC_TOP_VALUE (1 << RC_TOP_BITS)
+#define RC_BIT_MODEL_TOTAL_BITS 11
+#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
+#define RC_MOVE_BITS 5
+
+/*
+ * Maximum number of position states. A position state is the lowest pb
+ * number of bits of the current uncompressed offset. In some places there
+ * are different sets of probabilities for different position states.
+ */
+#define POS_STATES_MAX (1 << 4)
+
+/*
+ * This enum is used to track which LZMA symbols have occurred most recently
+ * and in which order. This information is used to predict the next symbol.
+ *
+ * Symbols:
+ * - Literal: One 8-bit byte
+ * - Match: Repeat a chunk of data at some distance
+ * - Long repeat: Multi-byte match at a recently seen distance
+ * - Short repeat: One-byte repeat at a recently seen distance
+ *
+ * The symbol names are in from STATE_oldest_older_previous. REP means
+ * either short or long repeated match, and NONLIT means any non-literal.
+ */
+enum lzma_state {
+ STATE_LIT_LIT,
+ STATE_MATCH_LIT_LIT,
+ STATE_REP_LIT_LIT,
+ STATE_SHORTREP_LIT_LIT,
+ STATE_MATCH_LIT,
+ STATE_REP_LIT,
+ STATE_SHORTREP_LIT,
+ STATE_LIT_MATCH,
+ STATE_LIT_LONGREP,
+ STATE_LIT_SHORTREP,
+ STATE_NONLIT_MATCH,
+ STATE_NONLIT_REP
+};
+
+/* Total number of states */
+#define STATES 12
+
+/* The lowest 7 states indicate that the previous state was a literal. */
+#define LIT_STATES 7
+
+/* Indicate that the latest symbol was a literal. */
+static inline void lzma_state_literal(enum lzma_state *state)
+{
+ if (*state <= STATE_SHORTREP_LIT_LIT)
+ *state = STATE_LIT_LIT;
+ else if (*state <= STATE_LIT_SHORTREP)
+ *state -= 3;
+ else
+ *state -= 6;
+}
+
+/* Indicate that the latest symbol was a match. */
+static inline void lzma_state_match(enum lzma_state *state)
+{
+ *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH;
+}
+
+/* Indicate that the latest state was a long repeated match. */
+static inline void lzma_state_long_rep(enum lzma_state *state)
+{
+ *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP;
+}
+
+/* Indicate that the latest symbol was a short match. */
+static inline void lzma_state_short_rep(enum lzma_state *state)
+{
+ *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP;
+}
+
+/* Test if the previous symbol was a literal. */
+static inline bool lzma_state_is_literal(enum lzma_state state)
+{
+ return state < LIT_STATES;
+}
+
+/* Each literal coder is divided in three sections:
+ * - 0x001-0x0FF: Without match byte
+ * - 0x101-0x1FF: With match byte; match bit is 0
+ * - 0x201-0x2FF: With match byte; match bit is 1
+ *
+ * Match byte is used when the previous LZMA symbol was something else than
+ * a literal (that is, it was some kind of match).
+ */
+#define LITERAL_CODER_SIZE 0x300
+
+/* Maximum number of literal coders */
+#define LITERAL_CODERS_MAX (1 << 4)
+
+/* Minimum length of a match is two bytes. */
+#define MATCH_LEN_MIN 2
+
+/* Match length is encoded with 4, 5, or 10 bits.
+ *
+ * Length Bits
+ * 2-9 4 = Choice=0 + 3 bits
+ * 10-17 5 = Choice=1 + Choice2=0 + 3 bits
+ * 18-273 10 = Choice=1 + Choice2=1 + 8 bits
+ */
+#define LEN_LOW_BITS 3
+#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
+#define LEN_MID_BITS 3
+#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
+#define LEN_HIGH_BITS 8
+#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
+#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
+
+/*
+ * Maximum length of a match is 273 which is a result of the encoding
+ * described above.
+ */
+#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
+
+/*
+ * Different sets of probabilities are used for match distances that have
+ * very short match length: Lengths of 2, 3, and 4 bytes have a separate
+ * set of probabilities for each length. The matches with longer length
+ * use a shared set of probabilities.
+ */
+#define DIST_STATES 4
+
+/*
+ * Get the index of the appropriate probability array for decoding
+ * the distance slot.
+ */
+static inline uint32_t lzma_get_dist_state(uint32_t len)
+{
+ return len < DIST_STATES + MATCH_LEN_MIN
+ ? len - MATCH_LEN_MIN : DIST_STATES - 1;
+}
+
+/*
+ * The highest two bits of a 32-bit match distance are encoded using six bits.
+ * This six-bit value is called a distance slot. This way encoding a 32-bit
+ * value takes 6-36 bits, larger values taking more bits.
+ */
+#define DIST_SLOT_BITS 6
+#define DIST_SLOTS (1 << DIST_SLOT_BITS)
+
+/* Match distances up to 127 are fully encoded using probabilities. Since
+ * the highest two bits (distance slot) are always encoded using six bits,
+ * the distances 0-3 don't need any additional bits to encode, since the
+ * distance slot itself is the same as the actual distance. DIST_MODEL_START
+ * indicates the first distance slot where at least one additional bit is
+ * needed.
+ */
+#define DIST_MODEL_START 4
+
+/*
+ * Match distances greater than 127 are encoded in three pieces:
+ * - distance slot: the highest two bits
+ * - direct bits: 2-26 bits below the highest two bits
+ * - alignment bits: four lowest bits
+ *
+ * Direct bits don't use any probabilities.
+ *
+ * The distance slot value of 14 is for distances 128-191.
+ */
+#define DIST_MODEL_END 14
+
+/* Distance slots that indicate a distance <= 127. */
+#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2)
+#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
+
+/*
+ * For match distances greater than 127, only the highest two bits and the
+ * lowest four bits (alignment) is encoded using probabilities.
+ */
+#define ALIGN_BITS 4
+#define ALIGN_SIZE (1 << ALIGN_BITS)
+#define ALIGN_MASK (ALIGN_SIZE - 1)
+
+/* Total number of all probability variables */
+#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE)
+
+/*
+ * LZMA remembers the four most recent match distances. Reusing these
+ * distances tends to take less space than re-encoding the actual
+ * distance value.
+ */
+#define REPS 4
+
+#endif
--- /dev/null
+/*
+ * Private includes and definitions
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_PRIVATE_H
+#define XZ_PRIVATE_H
+
+#ifdef __KERNEL__
+# include <linux/xz.h>
+# include <linux/kernel.h>
+# include <asm/unaligned.h>
+ /* XZ_PREBOOT may be defined only via decompress_unxz.c. */
+# ifndef XZ_PREBOOT
+# include <linux/slab.h>
+# include <linux/vmalloc.h>
+# include <linux/string.h>
+# ifdef CONFIG_XZ_DEC_X86
+# define XZ_DEC_X86
+# endif
+# ifdef CONFIG_XZ_DEC_POWERPC
+# define XZ_DEC_POWERPC
+# endif
+# ifdef CONFIG_XZ_DEC_IA64
+# define XZ_DEC_IA64
+# endif
+# ifdef CONFIG_XZ_DEC_ARM
+# define XZ_DEC_ARM
+# endif
+# ifdef CONFIG_XZ_DEC_ARMTHUMB
+# define XZ_DEC_ARMTHUMB
+# endif
+# ifdef CONFIG_XZ_DEC_SPARC
+# define XZ_DEC_SPARC
+# endif
+# define memeq(a, b, size) (memcmp(a, b, size) == 0)
+# define memzero(buf, size) memset(buf, 0, size)
+# endif
+# define get_le32(p) le32_to_cpup((const uint32_t *)(p))
+#else
+ /*
+ * For userspace builds, use a separate header to define the required
+ * macros and functions. This makes it easier to adapt the code into
+ * different environments and avoids clutter in the Linux kernel tree.
+ */
+# include "xz_config.h"
+#endif
+
+/* If no specific decoding mode is requested, enable support for all modes. */
+#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \
+ && !defined(XZ_DEC_DYNALLOC)
+# define XZ_DEC_SINGLE
+# define XZ_DEC_PREALLOC
+# define XZ_DEC_DYNALLOC
+#endif
+
+/*
+ * The DEC_IS_foo(mode) macros are used in "if" statements. If only some
+ * of the supported modes are enabled, these macros will evaluate to true or
+ * false at compile time and thus allow the compiler to omit unneeded code.
+ */
+#ifdef XZ_DEC_SINGLE
+# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE)
+#else
+# define DEC_IS_SINGLE(mode) (false)
+#endif
+
+#ifdef XZ_DEC_PREALLOC
+# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC)
+#else
+# define DEC_IS_PREALLOC(mode) (false)
+#endif
+
+#ifdef XZ_DEC_DYNALLOC
+# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC)
+#else
+# define DEC_IS_DYNALLOC(mode) (false)
+#endif
+
+#if !defined(XZ_DEC_SINGLE)
+# define DEC_IS_MULTI(mode) (true)
+#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC)
+# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE)
+#else
+# define DEC_IS_MULTI(mode) (false)
+#endif
+
+/*
+ * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ.
+ * XZ_DEC_BCJ is used to enable generic support for BCJ decoders.
+ */
+#ifndef XZ_DEC_BCJ
+# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \
+ || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \
+ || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \
+ || defined(XZ_DEC_SPARC)
+# define XZ_DEC_BCJ
+# endif
+#endif
+
+/*
+ * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used
+ * before calling xz_dec_lzma2_run().
+ */
+XZ_EXTERN struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode,
+ uint32_t dict_max);
+
+/*
+ * Decode the LZMA2 properties (one byte) and reset the decoder. Return
+ * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not
+ * big enough, and XZ_OPTIONS_ERROR if props indicates something that this
+ * decoder doesn't support.
+ */
+XZ_EXTERN enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s,
+ uint8_t props);
+
+/* Decode raw LZMA2 stream from b->in to b->out. */
+XZ_EXTERN enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s,
+ struct xz_buf *b);
+
+/* Free the memory allocated for the LZMA2 decoder. */
+XZ_EXTERN void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
+
+#ifdef XZ_DEC_BCJ
+/*
+ * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before
+ * calling xz_dec_bcj_run().
+ */
+XZ_EXTERN struct xz_dec_bcj *xz_dec_bcj_create(bool single_call);
+
+/*
+ * Decode the Filter ID of a BCJ filter. This implementation doesn't
+ * support custom start offsets, so no decoding of Filter Properties
+ * is needed. Returns XZ_OK if the given Filter ID is supported.
+ * Otherwise XZ_OPTIONS_ERROR is returned.
+ */
+XZ_EXTERN enum xz_ret xz_dec_bcj_reset(struct xz_dec_bcj *s, uint8_t id);
+
+/*
+ * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is
+ * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run()
+ * must be called directly.
+ */
+XZ_EXTERN enum xz_ret xz_dec_bcj_run(struct xz_dec_bcj *s,
+ struct xz_dec_lzma2 *lzma2,
+ struct xz_buf *b);
+
+/* Free the memory allocated for the BCJ filters. */
+#define xz_dec_bcj_end(s) kfree(s)
+#endif
+
+#endif
--- /dev/null
+/*
+ * Definitions for handling the .xz file format
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_STREAM_H
+#define XZ_STREAM_H
+
+#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32
+# include <linux/crc32.h>
+# undef crc32
+# define xz_crc32(buf, size, crc) \
+ (~crc32_le(~(uint32_t)(crc), buf, size))
+#endif
+
+/*
+ * See the .xz file format specification at
+ * http://tukaani.org/xz/xz-file-format.txt
+ * to understand the container format.
+ */
+
+#define STREAM_HEADER_SIZE 12
+
+#define HEADER_MAGIC "\3757zXZ"
+#define HEADER_MAGIC_SIZE 6
+
+#define FOOTER_MAGIC "YZ"
+#define FOOTER_MAGIC_SIZE 2
+
+/*
+ * Variable-length integer can hold a 63-bit unsigned integer or a special
+ * value indicating that the value is unknown.
+ *
+ * Experimental: vli_type can be defined to uint32_t to save a few bytes
+ * in code size (no effect on speed). Doing so limits the uncompressed and
+ * compressed size of the file to less than 256 MiB and may also weaken
+ * error detection slightly.
+ */
+typedef uint64_t vli_type;
+
+#define VLI_MAX ((vli_type)-1 / 2)
+#define VLI_UNKNOWN ((vli_type)-1)
+
+/* Maximum encoded size of a VLI */
+#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7)
+
+/* Integrity Check types */
+enum xz_check {
+ XZ_CHECK_NONE = 0,
+ XZ_CHECK_CRC32 = 1,
+ XZ_CHECK_CRC64 = 4,
+ XZ_CHECK_SHA256 = 10
+};
+
+/* Maximum possible Check ID */
+#define XZ_CHECK_MAX 15
+
+#endif
--- /dev/null
+#!/bin/sh
+#
+# This is a wrapper for xz to compress the kernel image using appropriate
+# compression options depending on the architecture.
+#
+# Author: Lasse Collin <lasse.collin@tukaani.org>
+#
+# This file has been put into the public domain.
+# You can do whatever you want with this file.
+#
+
+BCJ=
+LZMA2OPTS=
+
+case $SRCARCH in
+ x86) BCJ=--x86 ;;
+ powerpc) BCJ=--powerpc ;;
+ ia64) BCJ=--ia64; LZMA2OPTS=pb=4 ;;
+ arm) BCJ=--arm ;;
+ sparc) BCJ=--sparc ;;
+esac
+
+exec xz --check=crc32 $BCJ --lzma2=$LZMA2OPTS,dict=32MiB
--- /dev/null
+/*
+ * Test application for xz_boot.c
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#define STATIC static
+#define INIT
+
+static void error(/*const*/ char *msg)
+{
+ fprintf(stderr, "%s\n", msg);
+}
+
+/* Disable the CRC64 support even if it was enabled in the Makefile. */
+#undef XZ_USE_CRC64
+
+#include "../linux/lib/decompress_unxz.c"
+
+static uint8_t in[1024 * 1024];
+static uint8_t out[1024 * 1024];
+
+static int fill(void *buf, unsigned int size)
+{
+ return fread(buf, 1, size, stdin);
+}
+
+static int flush(/*const*/ void *buf, unsigned int size)
+{
+ return fwrite(buf, 1, size, stdout);
+}
+
+static void test_buf_to_buf(void)
+{
+ size_t in_size;
+ int ret;
+ in_size = fread(in, 1, sizeof(in), stdin);
+ ret = decompress(in, in_size, NULL, NULL, out, NULL, &error);
+ /* fwrite(out, 1, FIXME, stdout); */
+ fprintf(stderr, "ret = %d\n", ret);
+}
+
+static void test_buf_to_cb(void)
+{
+ size_t in_size;
+ int in_used;
+ int ret;
+ in_size = fread(in, 1, sizeof(in), stdin);
+ ret = decompress(in, in_size, NULL, &flush, NULL, &in_used, &error);
+ fprintf(stderr, "ret = %d; in_used = %d\n", ret, in_used);
+}
+
+static void test_cb_to_cb(void)
+{
+ int ret;
+ ret = decompress(NULL, 0, &fill, &flush, NULL, NULL, &error);
+ fprintf(stderr, "ret = %d\n", ret);
+}
+
+/*
+ * Not used by Linux <= 2.6.37-rc4 and newer probably won't use it either,
+ * but this kind of use case is still required to be supported by the API.
+ */
+static void test_cb_to_buf(void)
+{
+ int in_used;
+ int ret;
+ ret = decompress(in, 0, &fill, NULL, out, &in_used, &error);
+ /* fwrite(out, 1, FIXME, stdout); */
+ fprintf(stderr, "ret = %d; in_used = %d\n", ret, in_used);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2)
+ fprintf(stderr, "Usage: %s [bb|bc|cc|cb]\n", argv[0]);
+ else if (strcmp(argv[1], "bb") == 0)
+ test_buf_to_buf();
+ else if (strcmp(argv[1], "bc") == 0)
+ test_buf_to_cb();
+ else if (strcmp(argv[1], "cc") == 0)
+ test_cb_to_cb();
+ else if (strcmp(argv[1], "cb") == 0)
+ test_cb_to_buf();
+ else
+ fprintf(stderr, "Usage: %s [bb|bc|cc|cb]\n", argv[0]);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Test application to test buffer-to-buffer decoding
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include "xz.h"
+
+#define BUFFER_SIZE (1024 * 1024)
+
+static uint8_t in[BUFFER_SIZE];
+static uint8_t out[BUFFER_SIZE];
+
+int main(void)
+{
+ struct xz_buf b;
+ struct xz_dec *s;
+ enum xz_ret ret;
+
+ xz_crc32_init();
+
+ s = xz_dec_init(XZ_SINGLE, 0);
+ if (s == NULL) {
+ fputs("Initialization failed", stderr);
+ return 1;
+ }
+
+ b.in = in;
+ b.in_pos = 0;
+ b.in_size = fread(in, 1, sizeof(in), stdin);
+ b.out = out;
+ b.out_pos = 0;
+ b.out_size = sizeof(out);
+
+ ret = xz_dec_run(s, &b);
+ xz_dec_end(s);
+
+ fwrite(out, 1, b.out_pos, stdout);
+ fprintf(stderr, "%d\n", ret);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Lazy test for the case when the output size is known
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "xz.h"
+
+static uint8_t in[1];
+static uint8_t out[BUFSIZ];
+
+int main(int argc, char **argv)
+{
+ struct xz_buf b;
+ struct xz_dec *s;
+ enum xz_ret ret;
+ const char *msg;
+ size_t uncomp_size;
+
+ if (argc != 2) {
+ fputs("Give uncompressed size as the argument", stderr);
+ return 1;
+ }
+
+ uncomp_size = atoi(argv[1]);
+
+ xz_crc32_init();
+
+ /*
+ * Support up to 64 MiB dictionary. The actually needed memory
+ * is allocated once the headers have been parsed.
+ */
+ s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
+ if (s == NULL) {
+ msg = "Memory allocation failed\n";
+ goto error;
+ }
+
+ b.in = in;
+ b.in_pos = 0;
+ b.in_size = 0;
+ b.out = out;
+ b.out_pos = 0;
+ b.out_size = uncomp_size < BUFSIZ ? uncomp_size : BUFSIZ;
+
+ while (true) {
+ if (b.in_pos == b.in_size) {
+ b.in_size = fread(in, 1, sizeof(in), stdin);
+ b.in_pos = 0;
+ }
+
+ ret = xz_dec_run(s, &b);
+
+ if (b.out_pos == sizeof(out)) {
+ if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
+ msg = "Write error\n";
+ goto error;
+ }
+
+ uncomp_size -= b.out_pos;
+ b.out_pos = 0;
+ b.out_size = uncomp_size < BUFSIZ
+ ? uncomp_size : BUFSIZ;
+ }
+
+ if (ret == XZ_OK)
+ continue;
+
+#ifdef XZ_DEC_ANY_CHECK
+ if (ret == XZ_UNSUPPORTED_CHECK) {
+ fputs(argv[0], stderr);
+ fputs(": ", stderr);
+ fputs("Unsupported check; not verifying "
+ "file integrity\n", stderr);
+ continue;
+ }
+#endif
+
+ if (uncomp_size != b.out_pos) {
+ msg = "Uncompressed size doesn't match\n";
+ goto error;
+ }
+
+ if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos
+ || fclose(stdout)) {
+ msg = "Write error\n";
+ goto error;
+ }
+
+ switch (ret) {
+ case XZ_STREAM_END:
+ xz_dec_end(s);
+ return 0;
+
+ case XZ_MEM_ERROR:
+ msg = "Memory allocation failed\n";
+ goto error;
+
+ case XZ_MEMLIMIT_ERROR:
+ msg = "Memory usage limit reached\n";
+ goto error;
+
+ case XZ_FORMAT_ERROR:
+ msg = "Not a .xz file\n";
+ goto error;
+
+ case XZ_OPTIONS_ERROR:
+ msg = "Unsupported options in the .xz headers\n";
+ goto error;
+
+ case XZ_DATA_ERROR:
+ case XZ_BUF_ERROR:
+ msg = "File is corrupt\n";
+ goto error;
+
+ default:
+ msg = "Bug!\n";
+ goto error;
+ }
+ }
+
+error:
+ xz_dec_end(s);
+ fputs(argv[0], stderr);
+ fputs(": ", stderr);
+ fputs(msg, stderr);
+ return 1;
+}
--- /dev/null
+/*
+ * Private includes and definitions for userspace use of XZ Embedded
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef XZ_CONFIG_H
+#define XZ_CONFIG_H
+
+/* Uncomment to enable CRC64 support. */
+/* #define XZ_USE_CRC64 */
+
+/* Uncomment as needed to enable BCJ filter decoders. */
+/* #define XZ_DEC_X86 */
+/* #define XZ_DEC_POWERPC */
+/* #define XZ_DEC_IA64 */
+/* #define XZ_DEC_ARM */
+/* #define XZ_DEC_ARMTHUMB */
+/* #define XZ_DEC_SPARC */
+
+/*
+ * MSVC doesn't support modern C but XZ Embedded is mostly C89
+ * so these are enough.
+ */
+#ifdef _MSC_VER
+typedef unsigned char bool;
+# define true 1
+# define false 0
+# define inline __inline
+#else
+# include <stdbool.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "xz.h"
+
+#define kmalloc(size, flags) malloc(size)
+#define kfree(ptr) free(ptr)
+#define vmalloc(size) malloc(size)
+#define vfree(ptr) free(ptr)
+
+#define memeq(a, b, size) (memcmp(a, b, size) == 0)
+#define memzero(buf, size) memset(buf, 0, size)
+
+#ifndef min
+# define min(x, y) ((x) < (y) ? (x) : (y))
+#endif
+#define min_t(type, x, y) min(x, y)
+
+/*
+ * Some functions have been marked with __always_inline to keep the
+ * performance reasonable even when the compiler is optimizing for
+ * small code size. You may be able to save a few bytes by #defining
+ * __always_inline to plain inline, but don't complain if the code
+ * becomes slow.
+ *
+ * NOTE: System headers on GNU/Linux may #define this macro already,
+ * so if you want to change it, you need to #undef it first.
+ */
+#ifndef __always_inline
+# ifdef __GNUC__
+# define __always_inline \
+ inline __attribute__((__always_inline__))
+# else
+# define __always_inline inline
+# endif
+#endif
+
+/* Inline functions to access unaligned unsigned 32-bit integers */
+#ifndef get_unaligned_le32
+static inline uint32_t get_unaligned_le32(const uint8_t *buf)
+{
+ return (uint32_t)buf[0]
+ | ((uint32_t)buf[1] << 8)
+ | ((uint32_t)buf[2] << 16)
+ | ((uint32_t)buf[3] << 24);
+}
+#endif
+
+#ifndef get_unaligned_be32
+static inline uint32_t get_unaligned_be32(const uint8_t *buf)
+{
+ return (uint32_t)(buf[0] << 24)
+ | ((uint32_t)buf[1] << 16)
+ | ((uint32_t)buf[2] << 8)
+ | (uint32_t)buf[3];
+}
+#endif
+
+#ifndef put_unaligned_le32
+static inline void put_unaligned_le32(uint32_t val, uint8_t *buf)
+{
+ buf[0] = (uint8_t)val;
+ buf[1] = (uint8_t)(val >> 8);
+ buf[2] = (uint8_t)(val >> 16);
+ buf[3] = (uint8_t)(val >> 24);
+}
+#endif
+
+#ifndef put_unaligned_be32
+static inline void put_unaligned_be32(uint32_t val, uint8_t *buf)
+{
+ buf[0] = (uint8_t)(val >> 24);
+ buf[1] = (uint8_t)(val >> 16);
+ buf[2] = (uint8_t)(val >> 8);
+ buf[3] = (uint8_t)val;
+}
+#endif
+
+/*
+ * Use get_unaligned_le32() also for aligned access for simplicity. On
+ * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr))
+ * could save a few bytes in code size.
+ */
+#ifndef get_le32
+# define get_le32 get_unaligned_le32
+#endif
+
+#endif
--- /dev/null
+/*
+ * Simple XZ decoder command line tool
+ *
+ * Author: Lasse Collin <lasse.collin@tukaani.org>
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+/*
+ * This is really limited: Not all filters from .xz format are supported,
+ * only CRC32 is supported as the integrity check, and decoding of
+ * concatenated .xz streams is not supported. Thus, you may want to look
+ * at xzdec from XZ Utils if a few KiB bigger tool is not a problem.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include "xz.h"
+
+static uint8_t in[BUFSIZ];
+static uint8_t out[BUFSIZ];
+
+int main(int argc, char **argv)
+{
+ struct xz_buf b;
+ struct xz_dec *s;
+ enum xz_ret ret;
+ const char *msg;
+
+ if (argc >= 2 && strcmp(argv[1], "--help") == 0) {
+ fputs("Uncompress a .xz file from stdin to stdout.\n"
+ "Arguments other than `--help' are ignored.\n",
+ stdout);
+ return 0;
+ }
+
+ xz_crc32_init();
+#ifdef XZ_USE_CRC64
+ xz_crc64_init();
+#endif
+
+ /*
+ * Support up to 64 MiB dictionary. The actually needed memory
+ * is allocated once the headers have been parsed.
+ */
+ s = xz_dec_init(XZ_DYNALLOC, 1 << 26);
+ if (s == NULL) {
+ msg = "Memory allocation failed\n";
+ goto error;
+ }
+
+ b.in = in;
+ b.in_pos = 0;
+ b.in_size = 0;
+ b.out = out;
+ b.out_pos = 0;
+ b.out_size = BUFSIZ;
+
+ while (true) {
+ if (b.in_pos == b.in_size) {
+ b.in_size = fread(in, 1, sizeof(in), stdin);
+ b.in_pos = 0;
+ }
+
+ ret = xz_dec_run(s, &b);
+
+ if (b.out_pos == sizeof(out)) {
+ if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos) {
+ msg = "Write error\n";
+ goto error;
+ }
+
+ b.out_pos = 0;
+ }
+
+ if (ret == XZ_OK)
+ continue;
+
+#ifdef XZ_DEC_ANY_CHECK
+ if (ret == XZ_UNSUPPORTED_CHECK) {
+ fputs(argv[0], stderr);
+ fputs(": ", stderr);
+ fputs("Unsupported check; not verifying "
+ "file integrity\n", stderr);
+ continue;
+ }
+#endif
+
+ if (fwrite(out, 1, b.out_pos, stdout) != b.out_pos
+ || fclose(stdout)) {
+ msg = "Write error\n";
+ goto error;
+ }
+
+ switch (ret) {
+ case XZ_STREAM_END:
+ xz_dec_end(s);
+ return 0;
+
+ case XZ_MEM_ERROR:
+ msg = "Memory allocation failed\n";
+ goto error;
+
+ case XZ_MEMLIMIT_ERROR:
+ msg = "Memory usage limit reached\n";
+ goto error;
+
+ case XZ_FORMAT_ERROR:
+ msg = "Not a .xz file\n";
+ goto error;
+
+ case XZ_OPTIONS_ERROR:
+ msg = "Unsupported options in the .xz headers\n";
+ goto error;
+
+ case XZ_DATA_ERROR:
+ case XZ_BUF_ERROR:
+ msg = "File is corrupt\n";
+ goto error;
+
+ default:
+ msg = "Bug!\n";
+ goto error;
+ }
+ }
+
+error:
+ xz_dec_end(s);
+ fputs(argv[0], stderr);
+ fputs(": ", stderr);
+ fputs(msg, stderr);
+ return 1;
+}
--- /dev/null
+/******************************************************************************
+ * ventoy_http.c ---- ventoy http
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+
+#if defined(_MSC_VER) || defined(WIN32)
+#else
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+#include <linux/limits.h>
+#include <dirent.h>
+#include <pthread.h>
+#endif
+
+#include <ventoy_define.h>
+#include <ventoy_json.h>
+#include <ventoy_util.h>
+#include <ventoy_disk.h>
+#include <ventoy_http.h>
+#include "fat_filelib.h"
+
+static const char *g_json_title_postfix[bios_max + 1] =
+{
+ "", "_legacy", "_uefi", "_ia32", "_aa64", "_mips", ""
+};
+
+static const char *g_ventoy_kbd_layout[] =
+{
+ "QWERTY_USA", "AZERTY", "CZECH_QWERTY", "CZECH_QWERTZ", "DANISH",
+ "DVORAK_USA", "FRENCH", "GERMAN", "ITALIANO", "JAPAN_106", "LATIN_USA",
+ "PORTU_BRAZIL", "QWERTY_UK", "QWERTZ", "QWERTZ_HUN", "QWERTZ_SLOV_CROAT",
+ "SPANISH", "SWEDISH", "TURKISH_Q", "VIETNAMESE",
+ NULL
+};
+
+static const char *g_ventoy_help_lang[] =
+{
+ "de_DE", "en_US", "fr_FR", "hr_HR", "id_ID", "pt_PT", "sr_CY", "sr_SR", "tr_TR", "zh_CN",
+
+ NULL
+};
+
+static char g_pub_path[2 * MAX_PATH];
+static data_control g_data_control[bios_max + 1];
+static data_theme g_data_theme[bios_max + 1];
+static data_alias g_data_menu_alias[bios_max + 1];
+static data_tip g_data_menu_tip[bios_max + 1];
+static data_class g_data_menu_class[bios_max + 1];
+static data_image_list g_data_image_list[bios_max + 1];
+static data_image_list *g_data_image_blacklist = g_data_image_list;
+static data_auto_memdisk g_data_auto_memdisk[bios_max + 1];
+static data_password g_data_password[bios_max + 1];
+static data_conf_replace g_data_conf_replace[bios_max + 1];
+static data_injection g_data_injection[bios_max + 1];
+static data_auto_install g_data_auto_install[bios_max + 1];
+static data_persistence g_data_persistence[bios_max + 1];
+static data_dud g_data_dud[bios_max + 1];
+
+static char *g_pub_json_buffer = NULL;
+static char *g_pub_save_buffer = NULL;
+#define JSON_BUFFER g_pub_json_buffer
+#define JSON_SAVE_BUFFER g_pub_save_buffer
+
+static pthread_mutex_t g_api_mutex;
+static struct mg_context *g_ventoy_http_ctx = NULL;
+
+static int ventoy_is_kbd_valid(const char *key)
+{
+ int i = 0;
+
+ for (i = 0; g_ventoy_kbd_layout[i]; i++)
+ {
+ if (strcmp(g_ventoy_kbd_layout[i], key) == 0)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static const char * ventoy_real_path(const char *org)
+{
+ int count = 0;
+
+ if (g_sysinfo.pathcase)
+ {
+ scnprintf(g_pub_path, MAX_PATH, "%s", org);
+ count = ventoy_path_case(g_pub_path + 1, 1);
+ if (count > 0)
+ {
+ return g_pub_path;
+ }
+ return org;
+ }
+ else
+ {
+ return org;
+ }
+}
+
+
+static int ventoy_json_result(struct mg_connection *conn, const char *err)
+{
+ mg_printf(conn,
+ "HTTP/1.1 200 OK \r\n"
+ "Content-Type: application/json\r\n"
+ "Content-Length: %d\r\n"
+ "\r\n%s",
+ (int)strlen(err), err);
+
+ return 0;
+}
+
+static int ventoy_json_buffer(struct mg_connection *conn, const char *json_buf, int json_len)
+{
+ mg_printf(conn,
+ "HTTP/1.1 200 OK \r\n"
+ "Content-Type: application/json\r\n"
+ "Content-Length: %d\r\n"
+ "\r\n%s",
+ json_len, json_buf);
+
+ return 0;
+}
+
+static void ventoy_free_path_node_list(path_node *list)
+{
+ path_node *next = NULL;
+ path_node *node = list;
+
+ while (node)
+ {
+ next = node->next;
+ free(node);
+ node = next;
+ }
+}
+
+static path_node * ventoy_path_node_add_array(VTOY_JSON *array)
+{
+ path_node *head = NULL;
+ path_node *node = NULL;
+ path_node *cur = NULL;
+ VTOY_JSON *item = NULL;
+
+ for (item = array->pstChild; item; item = item->pstNext)
+ {
+ node = zalloc(sizeof(path_node));
+ if (node)
+ {
+ scnprintf(node->path, sizeof(node->path), "%s", item->unData.pcStrVal);
+ vtoy_list_add(head, cur, node);
+ }
+ }
+
+ return head;
+}
+
+static int ventoy_check_fuzzy_path(char *path, int prefix)
+{
+ int rc;
+ char c;
+ char *cur = NULL;
+ char *pos = NULL;
+
+ if (!path)
+ {
+ return 0;
+ }
+
+ pos = strchr(path, '*');
+ if (pos)
+ {
+ for (cur = pos; *cur; cur++)
+ {
+ if (*cur == '/')
+ {
+ return 0;
+ }
+ }
+
+ while (pos != path)
+ {
+ if (*pos == '/')
+ {
+ break;
+ }
+ pos--;
+ }
+
+ if (*pos == '/')
+ {
+ if (pos != path)
+ {
+ c = *pos;
+ *pos = 0;
+ if (prefix)
+ {
+ rc = ventoy_is_directory_exist("%s%s", g_cur_dir, path);
+ }
+ else
+ {
+ rc = ventoy_is_directory_exist("%s", path);
+ }
+ *pos = c;
+
+ if (rc == 0)
+ {
+ return 0;
+ }
+ }
+
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ if (prefix)
+ {
+ return ventoy_is_file_exist("%s%s", g_cur_dir, path);
+ }
+ else
+ {
+ return ventoy_is_file_exist("%s", path);
+ }
+ }
+}
+
+static int ventoy_path_list_cmp(path_node *list1, path_node *list2)
+{
+ if (NULL == list1 && NULL == list2)
+ {
+ return 0;
+ }
+ else if (list1 && list2)
+ {
+ while (list1 && list2)
+ {
+ if (strcmp(list1->path, list2->path))
+ {
+ return 1;
+ }
+
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+
+static int ventoy_api_device_info(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int pos = 0;
+
+ (void)json;
+
+ VTOY_JSON_FMT_BEGIN(pos, JSON_BUFFER, JSON_BUF_MAX);
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("dev_name", g_sysinfo.cur_model);
+ VTOY_JSON_FMT_STRN("dev_capacity", g_sysinfo.cur_capacity);
+ VTOY_JSON_FMT_STRN("dev_fs", g_sysinfo.cur_fsname);
+ VTOY_JSON_FMT_STRN("ventoy_ver", g_sysinfo.cur_ventoy_ver);
+ VTOY_JSON_FMT_SINT("part_style", g_sysinfo.cur_part_style);
+ VTOY_JSON_FMT_SINT("secure_boot", g_sysinfo.cur_secureboot);
+
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ ventoy_json_buffer(conn, JSON_BUFFER, pos);
+ return 0;
+}
+
+static int ventoy_api_sysinfo(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int pos = 0;
+
+ (void)json;
+
+ VTOY_JSON_FMT_BEGIN(pos, JSON_BUFFER, JSON_BUF_MAX);
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_STRN("language", ventoy_get_os_language());
+ VTOY_JSON_FMT_STRN("curdir", g_cur_dir);
+
+ //read clear
+ VTOY_JSON_FMT_SINT("syntax_error", g_sysinfo.syntax_error);
+ g_sysinfo.syntax_error = 0;
+
+
+ #if defined(_MSC_VER) || defined(WIN32)
+ VTOY_JSON_FMT_STRN("os", "windows");
+ #else
+ VTOY_JSON_FMT_STRN("os", "linux");
+ #endif
+
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ ventoy_json_buffer(conn, JSON_BUFFER, pos);
+ return 0;
+}
+
+static int ventoy_api_handshake(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int pos = 0;
+
+ (void)json;
+
+ VTOY_JSON_FMT_BEGIN(pos, JSON_BUFFER, JSON_BUF_MAX);
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_SINT("status", 0);
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ ventoy_json_buffer(conn, JSON_BUFFER, pos);
+ return 0;
+}
+
+static int ventoy_api_check_exist(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int dir = 0;
+ int pos = 0;
+ int exist = 0;
+ const char *path = NULL;
+
+ path = vtoy_json_get_string_ex(json, "path");
+ vtoy_json_get_int(json, "dir", &dir);
+
+ if (path)
+ {
+ if (dir)
+ {
+ exist = ventoy_is_directory_exist("%s", path);
+ }
+ else
+ {
+ exist = ventoy_is_file_exist("%s", path);
+ }
+ }
+
+ VTOY_JSON_FMT_BEGIN(pos, JSON_BUFFER, JSON_BUF_MAX);
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_SINT("exist", exist);
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ ventoy_json_buffer(conn, JSON_BUFFER, pos);
+ return 0;
+}
+
+static int ventoy_api_check_exist2(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int dir1 = 0;
+ int dir2 = 0;
+ int fuzzy1 = 0;
+ int fuzzy2 = 0;
+ int pos = 0;
+ int exist1 = 0;
+ int exist2 = 0;
+ const char *path1 = NULL;
+ const char *path2 = NULL;
+
+ path1 = vtoy_json_get_string_ex(json, "path1");
+ path2 = vtoy_json_get_string_ex(json, "path2");
+ vtoy_json_get_int(json, "dir1", &dir1);
+ vtoy_json_get_int(json, "dir2", &dir2);
+ vtoy_json_get_int(json, "fuzzy1", &fuzzy1);
+ vtoy_json_get_int(json, "fuzzy2", &fuzzy2);
+
+ if (path1)
+ {
+ if (dir1)
+ {
+ exist1 = ventoy_is_directory_exist("%s", path1);
+ }
+ else
+ {
+ if (fuzzy1)
+ {
+ exist1 = ventoy_check_fuzzy_path((char *)path1, 0);
+ }
+ else
+ {
+ exist1 = ventoy_is_file_exist("%s", path1);
+ }
+ }
+ }
+
+ if (path2)
+ {
+ if (dir2)
+ {
+ exist2 = ventoy_is_directory_exist("%s", path2);
+ }
+ else
+ {
+ if (fuzzy2)
+ {
+ exist2 = ventoy_check_fuzzy_path((char *)path2, 0);
+ }
+ else
+ {
+ exist2 = ventoy_is_file_exist("%s", path2);
+ }
+ }
+ }
+
+ VTOY_JSON_FMT_BEGIN(pos, JSON_BUFFER, JSON_BUF_MAX);
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_SINT("exist1", exist1);
+ VTOY_JSON_FMT_SINT("exist2", exist2);
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ ventoy_json_buffer(conn, JSON_BUFFER, pos);
+ return 0;
+}
+
+static int ventoy_api_check_fuzzy(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int pos = 0;
+ int exist = 0;
+ const char *path = NULL;
+
+ path = vtoy_json_get_string_ex(json, "path");
+ if (path)
+ {
+ exist = ventoy_check_fuzzy_path((char *)path, 0);
+ }
+
+ VTOY_JSON_FMT_BEGIN(pos, JSON_BUFFER, JSON_BUF_MAX);
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_SINT("exist", exist);
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ ventoy_json_buffer(conn, JSON_BUFFER, pos);
+ return 0;
+}
+
+
+#if 0
+#endif
+void ventoy_data_default_control(data_control *data)
+{
+ memset(data, 0, sizeof(data_control));
+
+ data->filter_dot_underscore = 1;
+ data->max_search_level = -1;
+ data->menu_timeout = 0;
+
+ strlcpy(data->default_kbd_layout, "QWERTY_USA");
+ strlcpy(data->help_text_language, "en_US");
+}
+
+int ventoy_data_cmp_control(data_control *data1, data_control *data2)
+{
+ if (data1->default_menu_mode != data2->default_menu_mode ||
+ data1->treeview_style != data2->treeview_style ||
+ data1->filter_dot_underscore != data2->filter_dot_underscore ||
+ data1->sort_casesensitive != data2->sort_casesensitive ||
+ data1->max_search_level != data2->max_search_level ||
+ data1->vhd_no_warning != data2->vhd_no_warning ||
+ data1->filter_iso != data2->filter_iso ||
+ data1->filter_wim != data2->filter_wim ||
+ data1->filter_efi != data2->filter_efi ||
+ data1->filter_img != data2->filter_img ||
+ data1->filter_vhd != data2->filter_vhd ||
+ data1->filter_vtoy != data2->filter_vtoy ||
+ data1->win11_bypass_check != data2->win11_bypass_check ||
+ data1->menu_timeout != data2->menu_timeout)
+ {
+ return 1;
+ }
+
+ if (strcmp(data1->default_search_root, data2->default_search_root) ||
+ strcmp(data1->default_image, data2->default_image) ||
+ strcmp(data1->default_kbd_layout, data2->default_kbd_layout) ||
+ strcmp(data1->help_text_language, data2->help_text_language))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+int ventoy_data_save_control(data_control *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ data_control *def = g_data_control + bios_max;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_DEFAULT_MENU_MODE", default_menu_mode);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_TREE_VIEW_MENU_STYLE", treeview_style);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILT_DOT_UNDERSCORE_FILE", filter_dot_underscore);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_SORT_CASE_SENSITIVE", sort_casesensitive);
+
+ if (data->max_search_level >= 0)
+ {
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_MAX_SEARCH_LEVEL", max_search_level);
+ }
+
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_VHD_NO_WARNING", vhd_no_warning);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILE_FLT_ISO", filter_iso);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILE_FLT_WIM", filter_wim);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILE_FLT_EFI", filter_efi);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILE_FLT_IMG", filter_img);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILE_FLT_VHD", filter_vhd);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_FILE_FLT_VTOY", filter_vtoy);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_WIN11_BYPASS_CHECK", win11_bypass_check);
+ VTOY_JSON_FMT_CTRL_INT(L2, "VTOY_MENU_TIMEOUT", menu_timeout);
+
+ VTOY_JSON_FMT_CTRL_STRN(L2, "VTOY_DEFAULT_KBD_LAYOUT", default_kbd_layout);
+ VTOY_JSON_FMT_CTRL_STRN(L2, "VTOY_HELP_TXT_LANGUAGE", help_text_language);
+
+ if (strcmp(def->default_search_root, data->default_search_root))
+ {
+ VTOY_JSON_FMT_CTRL_STRN_STR(L2, "VTOY_DEFAULT_SEARCH_ROOT", ventoy_real_path(data->default_search_root));
+ }
+
+ if (strcmp(def->default_image, data->default_image))
+ {
+ VTOY_JSON_FMT_CTRL_STRN_STR(L2, "VTOY_DEFAULT_IMAGE", ventoy_real_path(data->default_image));
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+int ventoy_data_json_control(data_control *ctrl, char *buf, int buflen)
+{
+ int i = 0;
+ int pos = 0;
+ int valid = 0;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_SINT("default_menu_mode", ctrl->default_menu_mode);
+ VTOY_JSON_FMT_SINT("treeview_style", ctrl->treeview_style);
+ VTOY_JSON_FMT_SINT("filter_dot_underscore", ctrl->filter_dot_underscore);
+ VTOY_JSON_FMT_SINT("sort_casesensitive", ctrl->sort_casesensitive);
+ VTOY_JSON_FMT_SINT("max_search_level", ctrl->max_search_level);
+ VTOY_JSON_FMT_SINT("vhd_no_warning", ctrl->vhd_no_warning);
+
+ VTOY_JSON_FMT_SINT("filter_iso", ctrl->filter_iso);
+ VTOY_JSON_FMT_SINT("filter_wim", ctrl->filter_wim);
+ VTOY_JSON_FMT_SINT("filter_efi", ctrl->filter_efi);
+ VTOY_JSON_FMT_SINT("filter_img", ctrl->filter_img);
+ VTOY_JSON_FMT_SINT("filter_vhd", ctrl->filter_vhd);
+ VTOY_JSON_FMT_SINT("filter_vtoy", ctrl->filter_vtoy);
+ VTOY_JSON_FMT_SINT("win11_bypass_check", ctrl->win11_bypass_check);
+ VTOY_JSON_FMT_SINT("menu_timeout", ctrl->menu_timeout);
+ VTOY_JSON_FMT_STRN("default_kbd_layout", ctrl->default_kbd_layout);
+ VTOY_JSON_FMT_STRN("help_text_language", ctrl->help_text_language);
+
+ valid = 0;
+ if (ctrl->default_search_root[0] && ventoy_is_directory_exist("%s%s", g_cur_dir, ctrl->default_search_root))
+ {
+ valid = 1;
+ }
+ VTOY_JSON_FMT_STRN("default_search_root", ctrl->default_search_root);
+ VTOY_JSON_FMT_SINT("default_search_root_valid", valid);
+
+
+ valid = 0;
+ if (ctrl->default_image[0] && ventoy_is_file_exist("%s%s", g_cur_dir, ctrl->default_image))
+ {
+ valid = 1;
+ }
+ VTOY_JSON_FMT_STRN("default_image", ctrl->default_image);
+ VTOY_JSON_FMT_SINT("default_image_valid", valid);
+
+ VTOY_JSON_FMT_KEY("help_list");
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (i = 0; g_ventoy_help_lang[i]; i++)
+ {
+ VTOY_JSON_FMT_ITEM(g_ventoy_help_lang[i]);
+ }
+ VTOY_JSON_FMT_ARY_ENDEX();
+
+
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_control(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, control);
+ return 0;
+}
+
+static int ventoy_api_save_control(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ data_control *ctrl = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ ctrl = g_data_control + index;
+
+ VTOY_JSON_INT("default_menu_mode", ctrl->default_menu_mode);
+ VTOY_JSON_INT("treeview_style", ctrl->treeview_style);
+ VTOY_JSON_INT("filter_dot_underscore", ctrl->filter_dot_underscore);
+ VTOY_JSON_INT("sort_casesensitive", ctrl->sort_casesensitive);
+ VTOY_JSON_INT("max_search_level", ctrl->max_search_level);
+ VTOY_JSON_INT("vhd_no_warning", ctrl->vhd_no_warning);
+ VTOY_JSON_INT("filter_iso", ctrl->filter_iso);
+ VTOY_JSON_INT("filter_wim", ctrl->filter_wim);
+ VTOY_JSON_INT("filter_efi", ctrl->filter_efi);
+ VTOY_JSON_INT("filter_img", ctrl->filter_img);
+ VTOY_JSON_INT("filter_vhd", ctrl->filter_vhd);
+ VTOY_JSON_INT("filter_vtoy", ctrl->filter_vtoy);
+ VTOY_JSON_INT("win11_bypass_check", ctrl->win11_bypass_check);
+ VTOY_JSON_INT("menu_timeout", ctrl->menu_timeout);
+
+ VTOY_JSON_STR("default_image", ctrl->default_image);
+ VTOY_JSON_STR("default_search_root", ctrl->default_search_root);
+ VTOY_JSON_STR("help_text_language", ctrl->help_text_language);
+ VTOY_JSON_STR("default_kbd_layout", ctrl->default_kbd_layout);
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+#if 0
+#endif
+
+void ventoy_data_default_theme(data_theme *data)
+{
+ memset(data, 0, sizeof(data_theme));
+ strlcpy(data->gfxmode, "1024x768");
+ scnprintf(data->ventoy_left, sizeof(data->ventoy_left), "5%%");
+ scnprintf(data->ventoy_top, sizeof(data->ventoy_top), "95%%");
+ scnprintf(data->ventoy_color, sizeof(data->ventoy_color), "%s", "#0000ff");
+}
+
+int ventoy_data_cmp_theme(data_theme *data1, data_theme *data2)
+{
+ if (data1->display_mode != data2->display_mode ||
+ strcmp(data1->ventoy_left, data2->ventoy_left) ||
+ strcmp(data1->ventoy_top, data2->ventoy_top) ||
+ strcmp(data1->gfxmode, data2->gfxmode) ||
+ strcmp(data1->ventoy_color, data2->ventoy_color)
+ )
+ {
+ return 1;
+ }
+
+ if (ventoy_path_list_cmp(data1->filelist, data2->filelist))
+ {
+ return 1;
+ }
+
+ if (ventoy_path_list_cmp(data1->fontslist, data2->fontslist))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_theme(data_theme *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ path_node *node = NULL;
+ data_theme *def = g_data_theme + bios_max;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_OBJ_BEGIN_N();
+
+ if (data->filelist)
+ {
+ if (data->filelist->next)
+ {
+ VTOY_JSON_FMT_KEY_L(L2, "file");
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->filelist; node; node = node->next)
+ {
+ VTOY_JSON_FMT_ITEM_PATH_LN(L3, node->path);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L2);
+
+ if (def->default_file != data->default_file)
+ {
+ VTOY_JSON_FMT_SINT_LN(L2, "default_file", data->default_file);
+ }
+ }
+ else
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L2, "file", data->filelist->path);
+ }
+ }
+
+ if (data->display_mode != def->display_mode)
+ {
+ if (display_mode_cli == data->display_mode)
+ {
+ VTOY_JSON_FMT_STRN_LN(L2, "display_mode", "CLI");
+ }
+ else if (display_mode_serial == data->display_mode)
+ {
+ VTOY_JSON_FMT_STRN_LN(L2, "display_mode", "serial");
+ }
+ else if (display_mode_ser_console == data->display_mode)
+ {
+ VTOY_JSON_FMT_STRN_LN(L2, "display_mode", "serial_console");
+ }
+ else
+ {
+ VTOY_JSON_FMT_STRN_LN(L2, "display_mode", "GUI");
+ }
+ }
+
+ VTOY_JSON_FMT_DIFF_STRN(L2, "gfxmode", gfxmode);
+
+ VTOY_JSON_FMT_DIFF_STRN(L2, "ventoy_left", ventoy_left);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "ventoy_top", ventoy_top);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "ventoy_color", ventoy_color);
+
+ if (data->fontslist)
+ {
+ VTOY_JSON_FMT_KEY_L(L2, "fonts");
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->fontslist; node; node = node->next)
+ {
+ VTOY_JSON_FMT_ITEM_PATH_LN(L3, node->path);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_theme(data_theme *data, char *buf, int buflen)
+{
+ int pos = 0;
+ path_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_SINT("default_file", data->default_file);
+ VTOY_JSON_FMT_SINT("display_mode", data->display_mode);
+ VTOY_JSON_FMT_STRN("gfxmode", data->gfxmode);
+
+ VTOY_JSON_FMT_STRN("ventoy_color", data->ventoy_color);
+ VTOY_JSON_FMT_STRN("ventoy_left", data->ventoy_left);
+ VTOY_JSON_FMT_STRN("ventoy_top", data->ventoy_top);
+
+ VTOY_JSON_FMT_KEY("filelist");
+ VTOY_JSON_FMT_ARY_BEGIN();
+ for (node = data->filelist; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_STRN("path", node->path);
+ VTOY_JSON_FMT_SINT("valid", ventoy_is_file_exist("%s%s", g_cur_dir, node->path));
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+ VTOY_JSON_FMT_ARY_ENDEX();
+
+ VTOY_JSON_FMT_KEY("fontslist");
+ VTOY_JSON_FMT_ARY_BEGIN();
+ for (node = data->fontslist; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_STRN("path", node->path);
+ VTOY_JSON_FMT_SINT("valid", ventoy_is_file_exist("%s%s", g_cur_dir, node->path));
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+ VTOY_JSON_FMT_ARY_ENDEX();
+
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_theme(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, theme);
+ return 0;
+}
+
+static int ventoy_api_save_theme(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ data_theme *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_theme + index;
+
+ VTOY_JSON_INT("default_file", data->default_file);
+ VTOY_JSON_INT("display_mode", data->display_mode);
+ VTOY_JSON_STR("gfxmode", data->gfxmode);
+ VTOY_JSON_STR("ventoy_left", data->ventoy_left);
+ VTOY_JSON_STR("ventoy_top", data->ventoy_top);
+ VTOY_JSON_STR("ventoy_color", data->ventoy_color);
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_theme_add_file(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ path_node *node = NULL;
+ path_node *cur = NULL;
+ data_theme *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_theme + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ node = zalloc(sizeof(path_node));
+ if (node)
+ {
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+
+ vtoy_list_add(data->filelist, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_theme_del_file(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ path_node *node = NULL;
+ path_node *last = NULL;
+ data_theme *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_theme + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->filelist, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+static int ventoy_api_theme_add_font(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ path_node *node = NULL;
+ path_node *cur = NULL;
+ data_theme *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_theme + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ node = zalloc(sizeof(path_node));
+ if (node)
+ {
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ vtoy_list_add(data->fontslist, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+static int ventoy_api_theme_del_font(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ path_node *node = NULL;
+ path_node *last = NULL;
+ data_theme *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_theme + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->fontslist, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+#if 0
+#endif
+
+void ventoy_data_default_menu_alias(data_alias *data)
+{
+ memset(data, 0, sizeof(data_alias));
+}
+
+int ventoy_data_cmp_menu_alias(data_alias *data1, data_alias *data2)
+{
+ data_alias_node *list1 = NULL;
+ data_alias_node *list2 = NULL;
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if ((list1->type != list2->type) ||
+ strcmp(list1->path, list2->path) ||
+ strcmp(list1->alias, list2->alias))
+ {
+ return 1;
+ }
+
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_menu_alias(data_alias *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ data_alias_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L2);
+
+ if (node->type == path_type_file)
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "image", node->path);
+ }
+ else
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "dir", node->path);
+ }
+
+ VTOY_JSON_FMT_STRN_EX_LN(L3, "alias", node->alias);
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_menu_alias(data_alias *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ data_alias_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_UINT("type", node->type);
+ VTOY_JSON_FMT_STRN("path", node->path);
+ if (node->type == path_type_file)
+ {
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ }
+ else
+ {
+ valid = ventoy_is_directory_exist("%s%s", g_cur_dir, node->path);
+ }
+
+ VTOY_JSON_FMT_SINT("valid", valid);
+ VTOY_JSON_FMT_STRN("alias", node->alias);
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_alias(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, menu_alias);
+ return 0;
+}
+
+static int ventoy_api_save_alias(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_alias_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ int type = path_type_file;
+ const char *path = NULL;
+ const char *alias = NULL;
+ data_alias_node *node = NULL;
+ data_alias_node *cur = NULL;
+ data_alias *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_menu_alias + index;
+
+ vtoy_json_get_int(json, "type", &type);
+
+ path = VTOY_JSON_STR_EX("path");
+ alias = VTOY_JSON_STR_EX("alias");
+ if (path && alias)
+ {
+ node = zalloc(sizeof(data_alias_node));
+ if (node)
+ {
+ node->type = type;
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ scnprintf(node->alias, sizeof(node->alias), "%s", alias);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_alias_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ data_alias_node *last = NULL;
+ data_alias_node *node = NULL;
+ data_alias *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_menu_alias + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->list, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+#if 0
+#endif
+
+void ventoy_data_default_menu_tip(data_tip *data)
+{
+ memset(data, 0, sizeof(data_tip));
+
+ scnprintf(data->left, sizeof(data->left), "10%%");
+ scnprintf(data->top, sizeof(data->top), "81%%");
+ scnprintf(data->color, sizeof(data->color), "%s", "blue");
+}
+
+int ventoy_data_cmp_menu_tip(data_tip *data1, data_tip *data2)
+{
+ data_tip_node *list1 = NULL;
+ data_tip_node *list2 = NULL;
+
+ if (strcmp(data1->left, data2->left) || strcmp(data1->top, data2->top) || strcmp(data1->color, data2->color))
+ {
+ return 1;
+ }
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if ((list1->type != list2->type) ||
+ strcmp(list1->path, list2->path) ||
+ strcmp(list1->tip, list2->tip))
+ {
+ return 1;
+ }
+
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_menu_tip(data_tip *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ data_tip_node *node = NULL;
+ data_tip *def = g_data_menu_tip + bios_max;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_OBJ_BEGIN_N();
+
+ VTOY_JSON_FMT_DIFF_STRN(L2, "left", left);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "top", top);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "color", color);
+
+ if (data->list)
+ {
+ VTOY_JSON_FMT_KEY_L(L2, "tips");
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L3);
+
+ if (node->type == path_type_file)
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L4, "image", node->path);
+ }
+ else
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L4, "dir", node->path);
+ }
+ VTOY_JSON_FMT_STRN_EX_LN(L4, "tip", node->tip);
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L3);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L1);
+
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_menu_tip(data_tip *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ data_tip_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("left", data->left);
+ VTOY_JSON_FMT_STRN("top", data->top);
+ VTOY_JSON_FMT_STRN("color", data->color);
+
+ VTOY_JSON_FMT_KEY("tips");
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_UINT("type", node->type);
+ VTOY_JSON_FMT_STRN("path", node->path);
+ if (node->type == path_type_file)
+ {
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ }
+ else
+ {
+ valid = ventoy_is_directory_exist("%s%s", g_cur_dir, node->path);
+ }
+
+ VTOY_JSON_FMT_SINT("valid", valid);
+ VTOY_JSON_FMT_STRN("tip", node->tip);
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX();
+
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_tip(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, menu_tip);
+ return 0;
+}
+
+static int ventoy_api_save_tip(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ data_tip *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_menu_tip + index;
+
+ VTOY_JSON_STR("left", data->left);
+ VTOY_JSON_STR("top", data->top);
+ VTOY_JSON_STR("color", data->color);
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_tip_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ int type = path_type_file;
+ const char *path = NULL;
+ const char *tip = NULL;
+ data_tip_node *node = NULL;
+ data_tip_node *cur = NULL;
+ data_tip *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_menu_tip + index;
+
+ vtoy_json_get_int(json, "type", &type);
+
+ path = VTOY_JSON_STR_EX("path");
+ tip = VTOY_JSON_STR_EX("tip");
+ if (path && tip)
+ {
+ node = zalloc(sizeof(data_tip_node));
+ if (node)
+ {
+ node->type = type;
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ scnprintf(node->tip, sizeof(node->tip), "%s", tip);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_tip_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ data_tip_node *last = NULL;
+ data_tip_node *node = NULL;
+ data_tip *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_menu_tip + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->list, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+#if 0
+#endif
+
+void ventoy_data_default_menu_class(data_class *data)
+{
+ memset(data, 0, sizeof(data_class));
+}
+
+int ventoy_data_cmp_menu_class(data_class *data1, data_class *data2)
+{
+ data_class_node *list1 = NULL;
+ data_class_node *list2 = NULL;
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if ((list1->type != list2->type) ||
+ strcmp(list1->path, list2->path) ||
+ strcmp(list1->class, list2->class))
+ {
+ return 1;
+ }
+
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_menu_class(data_class *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ data_class_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L2);
+
+ if (node->type == class_type_key)
+ {
+ VTOY_JSON_FMT_STRN_LN(L3, "key", node->path);
+ }
+ else if (node->type == class_type_dir)
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "dir", node->path);
+ }
+ else
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "parent", node->path);
+ }
+ VTOY_JSON_FMT_STRN_LN(L3, "class", node->class);
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_menu_class(data_class *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ data_class_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_UINT("type", node->type);
+ VTOY_JSON_FMT_STRN("path", node->path);
+
+ if (node->type == class_type_key)
+ {
+ valid = 1;
+ }
+ else
+ {
+ valid = ventoy_is_directory_exist("%s%s", g_cur_dir, node->path);
+ }
+ VTOY_JSON_FMT_SINT("valid", valid);
+
+ VTOY_JSON_FMT_STRN("class", node->class);
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+static int ventoy_api_get_class(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, menu_class);
+ return 0;
+}
+
+static int ventoy_api_save_class(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_class_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ int type = class_type_key;
+ const char *path = NULL;
+ const char *class = NULL;
+ data_class_node *node = NULL;
+ data_class_node *cur = NULL;
+ data_class *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_menu_class + index;
+
+ vtoy_json_get_int(json, "type", &type);
+
+ path = VTOY_JSON_STR_EX("path");
+ class = VTOY_JSON_STR_EX("class");
+ if (path && class)
+ {
+ node = zalloc(sizeof(data_class_node));
+ if (node)
+ {
+ node->type = type;
+
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ scnprintf(node->class, sizeof(node->class), "%s", class);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_class_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ data_class_node *last = NULL;
+ data_class_node *node = NULL;
+ data_class *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_menu_class + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->list, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+#if 0
+#endif
+
+void ventoy_data_default_auto_memdisk(data_auto_memdisk *data)
+{
+ memset(data, 0, sizeof(data_auto_memdisk));
+}
+
+int ventoy_data_cmp_auto_memdisk(data_auto_memdisk *data1, data_auto_memdisk *data2)
+{
+ return ventoy_path_list_cmp(data1->list, data2->list);
+}
+
+int ventoy_data_save_auto_memdisk(data_auto_memdisk *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ path_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_ITEM_PATH_LN(L2, node->path);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+int ventoy_data_json_auto_memdisk(data_auto_memdisk *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ path_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("path", node->path);
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ VTOY_JSON_FMT_SINT("valid", valid);
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_auto_memdisk(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, auto_memdisk);
+ return 0;
+}
+
+static int ventoy_api_save_auto_memdisk(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_auto_memdisk_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ path_node *node = NULL;
+ path_node *cur = NULL;
+ data_auto_memdisk *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_auto_memdisk + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ node = zalloc(sizeof(path_node));
+ if (node)
+ {
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_auto_memdisk_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ path_node *last = NULL;
+ path_node *node = NULL;
+ data_auto_memdisk *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_auto_memdisk + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->list, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+#if 0
+#endif
+
+void ventoy_data_default_image_list(data_image_list *data)
+{
+ memset(data, 0, sizeof(data_image_list));
+}
+
+int ventoy_data_cmp_image_list(data_image_list *data1, data_image_list *data2)
+{
+ if (data1->type != data2->type)
+ {
+ if (data1->list || data2->list)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ return ventoy_path_list_cmp(data1->list, data2->list);
+}
+
+int ventoy_data_save_image_list(data_image_list *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ path_node *node = NULL;
+
+ (void)title;
+
+ if (!(data->list))
+ {
+ return 0;
+ }
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ if (data->type == 0)
+ {
+ VTOY_JSON_FMT_KEY_L(L1, "image_list");
+ }
+ else
+ {
+ VTOY_JSON_FMT_KEY_L(L1, "image_blacklist");
+ }
+
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_ITEM_PATH_LN(L2, node->path);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+int ventoy_data_json_image_list(data_image_list *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ path_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_SINT("type", data->type);
+
+ VTOY_JSON_FMT_KEY("list");
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("path", node->path);
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ VTOY_JSON_FMT_SINT("valid", valid);
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX();
+ VTOY_JSON_FMT_OBJ_END();
+
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_image_list(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, image_list);
+ return 0;
+}
+
+static int ventoy_api_save_image_list(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ data_image_list *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_image_list + index;
+
+ VTOY_JSON_INT("type", data->type);
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_image_list_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ path_node *node = NULL;
+ path_node *cur = NULL;
+ data_image_list *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_image_list + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ node = zalloc(sizeof(path_node));
+ if (node)
+ {
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_image_list_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ path_node *last = NULL;
+ path_node *node = NULL;
+ data_image_list *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_image_list + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->list, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+#if 0
+#endif
+
+void ventoy_data_default_password(data_password *data)
+{
+ memset(data, 0, sizeof(data_password));
+}
+
+int ventoy_data_cmp_password(data_password *data1, data_password *data2)
+{
+ menu_password *list1 = NULL;
+ menu_password *list2 = NULL;
+
+ if (strcmp(data1->bootpwd, data2->bootpwd) ||
+ strcmp(data1->isopwd, data2->isopwd) ||
+ strcmp(data1->wimpwd, data2->wimpwd) ||
+ strcmp(data1->vhdpwd, data2->vhdpwd) ||
+ strcmp(data1->imgpwd, data2->imgpwd) ||
+ strcmp(data1->efipwd, data2->efipwd) ||
+ strcmp(data1->vtoypwd, data2->vtoypwd)
+ )
+ {
+ return 1;
+ }
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if ((list1->type != list2->type) || strcmp(list1->path, list2->path))
+ {
+ return 1;
+ }
+
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_password(data_password *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ menu_password *node = NULL;
+ data_password *def = g_data_password + bios_max;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_OBJ_BEGIN_N();
+
+ VTOY_JSON_FMT_DIFF_STRN(L2, "bootpwd", bootpwd);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "isopwd", isopwd);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "wimpwd", wimpwd);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "vhdpwd", vhdpwd);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "imgpwd", imgpwd);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "efipwd", efipwd);
+ VTOY_JSON_FMT_DIFF_STRN(L2, "vtoypwd", vtoypwd);
+
+ if (data->list)
+ {
+ VTOY_JSON_FMT_KEY_L(L2, "menupwd");
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L3);
+
+ if (node->type == 0)
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L4, "file", node->path);
+ }
+ else
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L4, "parent", node->path);
+ }
+ VTOY_JSON_FMT_STRN_LN(L4, "pwd", node->pwd);
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L3);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L1);
+
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_password(data_password *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ menu_password *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("bootpwd", data->bootpwd);
+ VTOY_JSON_FMT_STRN("isopwd", data->isopwd);
+ VTOY_JSON_FMT_STRN("wimpwd", data->wimpwd);
+ VTOY_JSON_FMT_STRN("vhdpwd", data->vhdpwd);
+ VTOY_JSON_FMT_STRN("imgpwd", data->imgpwd);
+ VTOY_JSON_FMT_STRN("efipwd", data->efipwd);
+ VTOY_JSON_FMT_STRN("vtoypwd", data->vtoypwd);
+
+ VTOY_JSON_FMT_KEY("list");
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_SINT("type", node->type);
+ VTOY_JSON_FMT_STRN("path", node->path);
+ if (node->type == path_type_file)
+ {
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ }
+ else
+ {
+ valid = ventoy_is_directory_exist("%s%s", g_cur_dir, node->path);
+ }
+
+ VTOY_JSON_FMT_SINT("valid", valid);
+ VTOY_JSON_FMT_STRN("pwd", node->pwd);
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX();
+
+ VTOY_JSON_FMT_OBJ_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_password(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, password);
+ return 0;
+}
+
+static int ventoy_api_save_password(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ data_password *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_password + index;
+
+ VTOY_JSON_STR("bootpwd", data->bootpwd);
+ VTOY_JSON_STR("isopwd", data->isopwd);
+ VTOY_JSON_STR("wimpwd", data->wimpwd);
+ VTOY_JSON_STR("vhdpwd", data->vhdpwd);
+ VTOY_JSON_STR("imgpwd", data->imgpwd);
+ VTOY_JSON_STR("efipwd", data->efipwd);
+ VTOY_JSON_STR("vtoypwd", data->vtoypwd);
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_password_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ int type = 0;
+ const char *path = NULL;
+ const char *pwd = NULL;
+ menu_password *node = NULL;
+ menu_password *cur = NULL;
+ data_password *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_password + index;
+
+ vtoy_json_get_int(json, "type", &type);
+
+ path = VTOY_JSON_STR_EX("path");
+ pwd = VTOY_JSON_STR_EX("pwd");
+ if (path && pwd)
+ {
+ node = zalloc(sizeof(menu_password));
+ if (node)
+ {
+ node->type = type;
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ scnprintf(node->pwd, sizeof(node->pwd), "%s", pwd);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_password_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ menu_password *last = NULL;
+ menu_password *node = NULL;
+ data_password *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_password + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->list, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+#if 0
+#endif
+
+void ventoy_data_default_conf_replace(data_conf_replace *data)
+{
+ memset(data, 0, sizeof(data_conf_replace));
+}
+
+int ventoy_data_cmp_conf_replace(data_conf_replace *data1, data_conf_replace *data2)
+{
+ conf_replace_node *list1 = NULL;
+ conf_replace_node *list2 = NULL;
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if (list1->image != list2->image ||
+ strcmp(list1->path, list2->path) ||
+ strcmp(list1->org, list2->org) ||
+ strcmp(list1->new, list2->new)
+ )
+ {
+ return 1;
+ }
+
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_conf_replace(data_conf_replace *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ conf_replace_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L2);
+
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "iso", node->path);
+ VTOY_JSON_FMT_STRN_LN(L3, "org", node->org);
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "new", node->new);
+ if (node->image)
+ {
+ VTOY_JSON_FMT_SINT_LN(L3, "img", node->image);
+ }
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_conf_replace(data_conf_replace *data, char *buf, int buflen)
+{
+ int pos = 0;
+ conf_replace_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("path", node->path);
+ VTOY_JSON_FMT_SINT("valid", ventoy_check_fuzzy_path(node->path, 1));
+ VTOY_JSON_FMT_STRN("org", node->org);
+ VTOY_JSON_FMT_STRN("new", node->new);
+ VTOY_JSON_FMT_SINT("new_valid", ventoy_is_file_exist("%s%s", g_cur_dir, node->new));
+ VTOY_JSON_FMT_SINT("img", node->image);
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_conf_replace(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, conf_replace);
+ return 0;
+}
+
+static int ventoy_api_save_conf_replace(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_conf_replace_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int image = 0;
+ int index = 0;
+ const char *path = NULL;
+ const char *org = NULL;
+ const char *new = NULL;
+ conf_replace_node *node = NULL;
+ conf_replace_node *cur = NULL;
+ data_conf_replace *data = NULL;
+
+ vtoy_json_get_int(json, "img", &image);
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_conf_replace + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ org = VTOY_JSON_STR_EX("org");
+ new = VTOY_JSON_STR_EX("new");
+ if (path && org && new)
+ {
+ node = zalloc(sizeof(conf_replace_node));
+ if (node)
+ {
+ node->image = image;
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ scnprintf(node->org, sizeof(node->org), "%s", org);
+ scnprintf(node->new, sizeof(node->new), "%s", new);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_conf_replace_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ conf_replace_node *last = NULL;
+ conf_replace_node *node = NULL;
+ data_conf_replace *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_conf_replace + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->list, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+#if 0
+#endif
+
+void ventoy_data_default_dud(data_dud *data)
+{
+ memset(data, 0, sizeof(data_dud));
+}
+
+int ventoy_data_cmp_dud(data_dud *data1, data_dud *data2)
+{
+ dud_node *list1 = NULL;
+ dud_node *list2 = NULL;
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if (strcmp(list1->path, list2->path))
+ {
+ return 1;
+ }
+
+ /* no need to compare dud list with default */
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_dud(data_dud *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ dud_node *node = NULL;
+ path_node *pathnode = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L2);
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "image", node->path);
+
+ VTOY_JSON_FMT_KEY_L(L3, "dud");
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+ for (pathnode = node->list; pathnode; pathnode = pathnode->next)
+ {
+ VTOY_JSON_FMT_ITEM_PATH_LN(L4, pathnode->path);
+ }
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L3);
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_dud(data_dud *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ dud_node *node = NULL;
+ path_node *pathnode = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("path", node->path);
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ VTOY_JSON_FMT_SINT("valid", valid);
+
+
+ VTOY_JSON_FMT_KEY("list");
+ VTOY_JSON_FMT_ARY_BEGIN();
+ for (pathnode = node->list; pathnode; pathnode = pathnode->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_STRN("path", pathnode->path);
+
+ valid = ventoy_is_file_exist("%s%s", g_cur_dir, pathnode->path);
+ VTOY_JSON_FMT_SINT("valid", valid);
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+ VTOY_JSON_FMT_ARY_ENDEX();
+
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_dud(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, dud);
+ return 0;
+}
+
+static int ventoy_api_save_dud(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+static int ventoy_api_dud_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ dud_node *node = NULL;
+ dud_node *cur = NULL;
+ data_dud *data = NULL;
+ VTOY_JSON *array = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_dud + index;
+
+ array = vtoy_json_find_item(json, JSON_TYPE_ARRAY, "dud");
+ path = VTOY_JSON_STR_EX("path");
+ if (path && array)
+ {
+ node = zalloc(sizeof(dud_node));
+ if (node)
+ {
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ node->list = ventoy_path_node_add_array(array);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_dud_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ dud_node *last = NULL;
+ dud_node *node = NULL;
+ data_dud *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_dud + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del_ex(last, node, data->list, path, ventoy_free_path_node_list);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+static int ventoy_api_dud_add_inner(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ const char *outpath = NULL;
+ path_node *pcur = NULL;
+ path_node *pnode = NULL;
+ dud_node *node = NULL;
+ data_dud *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_dud + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ outpath = VTOY_JSON_STR_EX("outpath");
+ if (path && outpath)
+ {
+ for (node = data->list; node; node = node->next)
+ {
+ if (strcmp(outpath, node->path) == 0)
+ {
+ pnode = zalloc(sizeof(path_node));
+ if (pnode)
+ {
+ scnprintf(pnode->path, sizeof(pnode->path), "%s", path);
+ vtoy_list_add(node->list, pcur, pnode);
+ }
+
+ break;
+ }
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_dud_del_inner(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ const char *outpath = NULL;
+ path_node *plast = NULL;
+ path_node *pnode = NULL;
+ dud_node *node = NULL;
+ data_dud *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_dud + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ outpath = VTOY_JSON_STR_EX("outpath");
+ if (path && outpath)
+ {
+ for (node = data->list; node; node = node->next)
+ {
+ if (strcmp(outpath, node->path) == 0)
+ {
+ vtoy_list_del(plast, pnode, node->list, path);
+ break;
+ }
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+#if 0
+#endif
+
+void ventoy_data_default_auto_install(data_auto_install *data)
+{
+ memset(data, 0, sizeof(data_auto_install));
+}
+
+int ventoy_data_cmp_auto_install(data_auto_install *data1, data_auto_install *data2)
+{
+ auto_install_node *list1 = NULL;
+ auto_install_node *list2 = NULL;
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if (list1->timeout != list2->timeout ||
+ list1->autosel != list2->autosel ||
+ strcmp(list1->path, list2->path))
+ {
+ return 1;
+ }
+
+ /* no need to compare auto install list with default */
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_auto_install(data_auto_install *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ auto_install_node *node = NULL;
+ path_node *pathnode = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L2);
+ if (node->type == 0)
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "image", node->path);
+ }
+ else
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "parent", node->path);
+ }
+
+
+ VTOY_JSON_FMT_KEY_L(L3, "template");
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+ for (pathnode = node->list; pathnode; pathnode = pathnode->next)
+ {
+ VTOY_JSON_FMT_ITEM_PATH_LN(L4, pathnode->path);
+ }
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L3);
+
+ if (node->timeouten)
+ {
+ VTOY_JSON_FMT_SINT_LN(L3, "timeout", node->timeout);
+ }
+
+ if (node->autoselen)
+ {
+ VTOY_JSON_FMT_SINT_LN(L3, "autosel", node->autosel);
+ }
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_auto_install(data_auto_install *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ auto_install_node *node = NULL;
+ path_node *pathnode = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("path", node->path);
+
+ if (node->type == 0)
+ {
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ }
+ else
+ {
+ valid = ventoy_is_directory_exist("%s%s", g_cur_dir, node->path);
+ }
+ VTOY_JSON_FMT_SINT("valid", valid);
+ VTOY_JSON_FMT_SINT("type", node->type);
+
+ VTOY_JSON_FMT_BOOL("timeouten", node->timeouten);
+ VTOY_JSON_FMT_BOOL("autoselen", node->autoselen);
+
+ VTOY_JSON_FMT_SINT("autosel", node->autosel);
+ VTOY_JSON_FMT_SINT("timeout", node->timeout);
+
+ VTOY_JSON_FMT_KEY("list");
+ VTOY_JSON_FMT_ARY_BEGIN();
+ for (pathnode = node->list; pathnode; pathnode = pathnode->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_STRN("path", pathnode->path);
+
+ valid = ventoy_is_file_exist("%s%s", g_cur_dir, pathnode->path);
+ VTOY_JSON_FMT_SINT("valid", valid);
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+ VTOY_JSON_FMT_ARY_ENDEX();
+
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_auto_install(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, auto_install);
+ return 0;
+}
+
+static int ventoy_api_save_auto_install(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int id = -1;
+ int cnt = 0;
+ int index = 0;
+ uint8_t timeouten = 0;
+ uint8_t autoselen = 0;
+ auto_install_node *node = NULL;
+ data_auto_install *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ vtoy_json_get_int(json, "id", &id);
+
+ vtoy_json_get_bool(json, "timeouten", &timeouten);
+ vtoy_json_get_bool(json, "autoselen", &autoselen);
+
+ data = g_data_auto_install + index;
+
+ if (id >= 0)
+ {
+ for (node = data->list; node; node = node->next)
+ {
+ if (cnt == id)
+ {
+ node->timeouten = (int)timeouten;
+ node->autoselen = (int)autoselen;
+ VTOY_JSON_INT("timeout", node->timeout);
+ VTOY_JSON_INT("autosel", node->autosel);
+ break;
+ }
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+static int ventoy_api_auto_install_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ int type = 0;
+ const char *path = NULL;
+ auto_install_node *node = NULL;
+ auto_install_node *cur = NULL;
+ data_auto_install *data = NULL;
+ VTOY_JSON *array = NULL;
+
+ vtoy_json_get_int(json, "type", &type);
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_auto_install + index;
+
+ array = vtoy_json_find_item(json, JSON_TYPE_ARRAY, "template");
+ path = VTOY_JSON_STR_EX("path");
+ if (path && array)
+ {
+ node = zalloc(sizeof(auto_install_node));
+ if (node)
+ {
+ node->type = type;
+ node->timeouten = 0;
+ node->autoselen = 0;
+ node->autosel = 1;
+ node->timeout = 0;
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ node->list = ventoy_path_node_add_array(array);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_auto_install_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ auto_install_node *last = NULL;
+ auto_install_node *node = NULL;
+ data_auto_install *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_auto_install + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del_ex(last, node, data->list, path, ventoy_free_path_node_list);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_auto_install_add_inner(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ const char *outpath = NULL;
+ path_node *pcur = NULL;
+ path_node *pnode = NULL;
+ auto_install_node *node = NULL;
+ data_auto_install *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_auto_install + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ outpath = VTOY_JSON_STR_EX("outpath");
+ if (path && outpath)
+ {
+ for (node = data->list; node; node = node->next)
+ {
+ if (strcmp(outpath, node->path) == 0)
+ {
+ pnode = zalloc(sizeof(path_node));
+ if (pnode)
+ {
+ scnprintf(pnode->path, sizeof(pnode->path), "%s", path);
+ vtoy_list_add(node->list, pcur, pnode);
+ }
+
+ break;
+ }
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_auto_install_del_inner(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ const char *outpath = NULL;
+ path_node *plast = NULL;
+ path_node *pnode = NULL;
+ auto_install_node *node = NULL;
+ data_auto_install *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_auto_install + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ outpath = VTOY_JSON_STR_EX("outpath");
+ if (path && outpath)
+ {
+ for (node = data->list; node; node = node->next)
+ {
+ if (strcmp(outpath, node->path) == 0)
+ {
+ vtoy_list_del(plast, pnode, node->list, path);
+ break;
+ }
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+#if 0
+#endif
+
+
+void ventoy_data_default_persistence(data_persistence *data)
+{
+ memset(data, 0, sizeof(data_persistence));
+}
+
+int ventoy_data_cmp_persistence(data_persistence *data1, data_persistence *data2)
+{
+ persistence_node *list1 = NULL;
+ persistence_node *list2 = NULL;
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if (list1->timeout != list2->timeout ||
+ list1->autosel != list2->autosel ||
+ strcmp(list1->path, list2->path))
+ {
+ return 1;
+ }
+
+ /* no need to compare auto install list with default */
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_persistence(data_persistence *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ persistence_node *node = NULL;
+ path_node *pathnode = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L2);
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "image", node->path);
+ VTOY_JSON_FMT_KEY_L(L3, "backend");
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+ for (pathnode = node->list; pathnode; pathnode = pathnode->next)
+ {
+ VTOY_JSON_FMT_ITEM_PATH_LN(L4, pathnode->path);
+ }
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L3);
+
+ if (node->timeouten)
+ {
+ VTOY_JSON_FMT_SINT_LN(L3, "timeout", node->timeout);
+ }
+
+ if (node->autoselen)
+ {
+ VTOY_JSON_FMT_SINT_LN(L3, "autosel", node->autosel);
+ }
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_persistence(data_persistence *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ persistence_node *node = NULL;
+ path_node *pathnode = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_STRN("path", node->path);
+
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ VTOY_JSON_FMT_SINT("valid", valid);
+ VTOY_JSON_FMT_SINT("type", node->type);
+
+ VTOY_JSON_FMT_BOOL("timeouten", node->timeouten);
+ VTOY_JSON_FMT_BOOL("autoselen", node->autoselen);
+
+ VTOY_JSON_FMT_SINT("autosel", node->autosel);
+ VTOY_JSON_FMT_SINT("timeout", node->timeout);
+
+ VTOY_JSON_FMT_KEY("list");
+ VTOY_JSON_FMT_ARY_BEGIN();
+ for (pathnode = node->list; pathnode; pathnode = pathnode->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+ VTOY_JSON_FMT_STRN("path", pathnode->path);
+
+ valid = ventoy_is_file_exist("%s%s", g_cur_dir, pathnode->path);
+ VTOY_JSON_FMT_SINT("valid", valid);
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+ VTOY_JSON_FMT_ARY_ENDEX();
+
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+static int ventoy_api_get_persistence(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, persistence);
+ return 0;
+}
+
+static int ventoy_api_save_persistence(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int id = -1;
+ int cnt = 0;
+ int index = 0;
+ uint8_t timeouten = 0;
+ uint8_t autoselen = 0;
+ persistence_node *node = NULL;
+ data_persistence *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ vtoy_json_get_int(json, "id", &id);
+
+ vtoy_json_get_bool(json, "timeouten", &timeouten);
+ vtoy_json_get_bool(json, "autoselen", &autoselen);
+
+ data = g_data_persistence + index;
+
+ if (id >= 0)
+ {
+ for (node = data->list; node; node = node->next)
+ {
+ if (cnt == id)
+ {
+ node->timeouten = (int)timeouten;
+ node->autoselen = (int)autoselen;
+ VTOY_JSON_INT("timeout", node->timeout);
+ VTOY_JSON_INT("autosel", node->autosel);
+ break;
+ }
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+static int ventoy_api_persistence_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ persistence_node *node = NULL;
+ persistence_node *cur = NULL;
+ data_persistence *data = NULL;
+ VTOY_JSON *array = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_persistence + index;
+
+ array = vtoy_json_find_item(json, JSON_TYPE_ARRAY, "backend");
+ path = VTOY_JSON_STR_EX("path");
+ if (path && array)
+ {
+ node = zalloc(sizeof(persistence_node));
+ if (node)
+ {
+ node->timeouten = 0;
+ node->autoselen = 0;
+ node->autosel = 1;
+ node->timeout = 0;
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ node->list = ventoy_path_node_add_array(array);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_persistence_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ persistence_node *last = NULL;
+ persistence_node *node = NULL;
+ data_persistence *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_persistence + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del_ex(last, node, data->list, path, ventoy_free_path_node_list);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_persistence_add_inner(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ const char *outpath = NULL;
+ path_node *pcur = NULL;
+ path_node *pnode = NULL;
+ persistence_node *node = NULL;
+ data_persistence *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_persistence + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ outpath = VTOY_JSON_STR_EX("outpath");
+ if (path && outpath)
+ {
+ for (node = data->list; node; node = node->next)
+ {
+ if (strcmp(outpath, node->path) == 0)
+ {
+ pnode = zalloc(sizeof(path_node));
+ if (pnode)
+ {
+ scnprintf(pnode->path, sizeof(pnode->path), "%s", path);
+ vtoy_list_add(node->list, pcur, pnode);
+ }
+
+ break;
+ }
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_persistence_del_inner(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ const char *outpath = NULL;
+ path_node *plast = NULL;
+ path_node *pnode = NULL;
+ persistence_node *node = NULL;
+ data_persistence *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_persistence + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ outpath = VTOY_JSON_STR_EX("outpath");
+ if (path && outpath)
+ {
+ for (node = data->list; node; node = node->next)
+ {
+ if (strcmp(outpath, node->path) == 0)
+ {
+ vtoy_list_del(plast, pnode, node->list, path);
+ break;
+ }
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+#if 0
+#endif
+
+void ventoy_data_default_injection(data_injection *data)
+{
+ memset(data, 0, sizeof(data_injection));
+}
+
+int ventoy_data_cmp_injection(data_injection *data1, data_injection *data2)
+{
+ injection_node *list1 = NULL;
+ injection_node *list2 = NULL;
+
+ if (NULL == data1->list && NULL == data2->list)
+ {
+ return 0;
+ }
+ else if (data1->list && data2->list)
+ {
+ list1 = data1->list;
+ list2 = data2->list;
+
+ while (list1 && list2)
+ {
+ if ((list1->type != list2->type) ||
+ strcmp(list1->path, list2->path) ||
+ strcmp(list1->archive, list2->archive))
+ {
+ return 1;
+ }
+
+ list1 = list1->next;
+ list2 = list2->next;
+ }
+
+ if (list1 == NULL && list2 == NULL)
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int ventoy_data_save_injection(data_injection *data, const char *title, char *buf, int buflen)
+{
+ int pos = 0;
+ injection_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+
+ VTOY_JSON_FMT_KEY_L(L1, title);
+ VTOY_JSON_FMT_ARY_BEGIN_N();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN_LN(L2);
+
+ if (node->type == 0)
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "image", node->path);
+ }
+ else
+ {
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "parent", node->path);
+ }
+ VTOY_JSON_FMT_STRN_PATH_LN(L3, "archive", node->archive);
+
+ VTOY_JSON_FMT_OBJ_ENDEX_LN(L2);
+ }
+
+ VTOY_JSON_FMT_ARY_ENDEX_LN(L1);
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+int ventoy_data_json_injection(data_injection *data, char *buf, int buflen)
+{
+ int pos = 0;
+ int valid = 0;
+ injection_node *node = NULL;
+
+ VTOY_JSON_FMT_BEGIN(pos, buf, buflen);
+ VTOY_JSON_FMT_ARY_BEGIN();
+
+ for (node = data->list; node; node = node->next)
+ {
+ VTOY_JSON_FMT_OBJ_BEGIN();
+
+ VTOY_JSON_FMT_UINT("type", node->type);
+ VTOY_JSON_FMT_STRN("path", node->path);
+
+ if (node->type == 0)
+ {
+ valid = ventoy_check_fuzzy_path(node->path, 1);
+ }
+ else
+ {
+ valid = ventoy_is_directory_exist("%s%s", g_cur_dir, node->path);
+ }
+ VTOY_JSON_FMT_SINT("valid", valid);
+
+ VTOY_JSON_FMT_STRN("archive", node->archive);
+
+ valid = ventoy_is_file_exist("%s%s", g_cur_dir, node->archive);
+ VTOY_JSON_FMT_SINT("archive_valid", valid);
+
+ VTOY_JSON_FMT_OBJ_ENDEX();
+ }
+
+ VTOY_JSON_FMT_ARY_END();
+ VTOY_JSON_FMT_END(pos);
+
+ return pos;
+}
+
+
+static int ventoy_api_get_injection(struct mg_connection *conn, VTOY_JSON *json)
+{
+ api_get_func(conn, json, injection);
+ return 0;
+}
+
+static int ventoy_api_save_injection(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_injection_add(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ int type = 0;
+ const char *path = NULL;
+ const char *archive = NULL;
+ injection_node *node = NULL;
+ injection_node *cur = NULL;
+ data_injection *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_injection + index;
+
+ vtoy_json_get_int(json, "type", &type);
+
+ path = VTOY_JSON_STR_EX("path");
+ archive = VTOY_JSON_STR_EX("archive");
+ if (path && archive)
+ {
+ node = zalloc(sizeof(injection_node));
+ if (node)
+ {
+ node->type = type;
+
+ scnprintf(node->path, sizeof(node->path), "%s", path);
+ scnprintf(node->archive, sizeof(node->archive), "%s", archive);
+
+ vtoy_list_add(data->list, cur, node);
+ }
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+static int ventoy_api_injection_del(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int ret;
+ int index = 0;
+ const char *path = NULL;
+ injection_node *last = NULL;
+ injection_node *node = NULL;
+ data_injection *data = NULL;
+
+ vtoy_json_get_int(json, "index", &index);
+ data = g_data_injection + index;
+
+ path = VTOY_JSON_STR_EX("path");
+ if (path)
+ {
+ vtoy_list_del(last, node, data->list, path);
+ }
+
+ ret = ventoy_data_save_all();
+
+ ventoy_json_result(conn, ret == 0 ? VTOY_JSON_SUCCESS_RET : VTOY_JSON_FAILED_RET);
+ return 0;
+}
+
+
+#if 0
+#endif
+
+int ventoy_data_save_all(void)
+{
+ ventoy_set_writeback_event();
+ return 0;
+}
+
+int ventoy_data_real_save_all(void)
+{
+ int i = 0;
+ int pos = 0;
+ char title[64];
+
+ pthread_mutex_lock(&g_api_mutex);
+
+ ssprintf(pos, JSON_SAVE_BUFFER, JSON_BUF_MAX, "{\n");
+
+ ventoy_save_plug(control);
+ ventoy_save_plug(theme);
+ ventoy_save_plug(menu_alias);
+ ventoy_save_plug(menu_tip);
+ ventoy_save_plug(menu_class);
+ ventoy_save_plug(auto_install);
+ ventoy_save_plug(persistence);
+ ventoy_save_plug(injection);
+ ventoy_save_plug(conf_replace);
+ ventoy_save_plug(password);
+ ventoy_save_plug(image_list);
+ ventoy_save_plug(auto_memdisk);
+ ventoy_save_plug(dud);
+
+ if (JSON_SAVE_BUFFER[pos - 1] == '\n' && JSON_SAVE_BUFFER[pos - 2] == ',')
+ {
+ JSON_SAVE_BUFFER[pos - 2] = '\n';
+ pos--;
+ }
+ ssprintf(pos, JSON_SAVE_BUFFER, JSON_BUF_MAX, "}\n");
+
+ pthread_mutex_unlock(&g_api_mutex);
+
+ return pos;
+}
+
+int ventoy_http_writeback(void)
+{
+ int ret;
+ int pos;
+ char filename[128];
+
+ ventoy_get_json_path(filename, NULL);
+
+ pos = ventoy_data_real_save_all();
+
+ #ifdef VENTOY_SIM
+ printf("%s", JSON_SAVE_BUFFER);
+ #endif
+
+ ret = ventoy_write_buf_to_file(filename, JSON_SAVE_BUFFER, pos);
+ if (ret)
+ {
+ vlog("Failed to write ventoy.json file.\n");
+ }
+
+ return 0;
+}
+
+
+static JSON_CB g_ventoy_json_cb[] =
+{
+ { "sysinfo", ventoy_api_sysinfo },
+ { "handshake", ventoy_api_handshake },
+ { "check_path", ventoy_api_check_exist },
+ { "check_path2", ventoy_api_check_exist2 },
+ { "check_fuzzy", ventoy_api_check_fuzzy },
+
+ { "device_info", ventoy_api_device_info },
+
+ { "get_control", ventoy_api_get_control },
+ { "save_control", ventoy_api_save_control },
+
+ { "get_theme", ventoy_api_get_theme },
+ { "save_theme", ventoy_api_save_theme },
+ { "theme_add_file", ventoy_api_theme_add_file },
+ { "theme_del_file", ventoy_api_theme_del_file },
+ { "theme_add_font", ventoy_api_theme_add_font },
+ { "theme_del_font", ventoy_api_theme_del_font },
+
+ { "get_alias", ventoy_api_get_alias },
+ { "save_alias", ventoy_api_save_alias },
+ { "alias_add", ventoy_api_alias_add },
+ { "alias_del", ventoy_api_alias_del },
+
+ { "get_tip", ventoy_api_get_tip },
+ { "save_tip", ventoy_api_save_tip },
+ { "tip_add", ventoy_api_tip_add },
+ { "tip_del", ventoy_api_tip_del },
+
+ { "get_class", ventoy_api_get_class },
+ { "save_class", ventoy_api_save_class },
+ { "class_add", ventoy_api_class_add },
+ { "class_del", ventoy_api_class_del },
+
+ { "get_auto_memdisk", ventoy_api_get_auto_memdisk },
+ { "save_auto_memdisk", ventoy_api_save_auto_memdisk },
+ { "auto_memdisk_add", ventoy_api_auto_memdisk_add },
+ { "auto_memdisk_del", ventoy_api_auto_memdisk_del },
+
+ { "get_image_list", ventoy_api_get_image_list },
+ { "save_image_list", ventoy_api_save_image_list },
+ { "image_list_add", ventoy_api_image_list_add },
+ { "image_list_del", ventoy_api_image_list_del },
+
+ { "get_conf_replace", ventoy_api_get_conf_replace },
+ { "save_conf_replace", ventoy_api_save_conf_replace },
+ { "conf_replace_add", ventoy_api_conf_replace_add },
+ { "conf_replace_del", ventoy_api_conf_replace_del },
+
+ { "get_dud", ventoy_api_get_dud },
+ { "save_dud", ventoy_api_save_dud },
+ { "dud_add", ventoy_api_dud_add },
+ { "dud_del", ventoy_api_dud_del },
+ { "dud_add_inner", ventoy_api_dud_add_inner },
+ { "dud_del_inner", ventoy_api_dud_del_inner },
+
+ { "get_auto_install", ventoy_api_get_auto_install },
+ { "save_auto_install", ventoy_api_save_auto_install },
+ { "auto_install_add", ventoy_api_auto_install_add },
+ { "auto_install_del", ventoy_api_auto_install_del },
+ { "auto_install_add_inner", ventoy_api_auto_install_add_inner },
+ { "auto_install_del_inner", ventoy_api_auto_install_del_inner },
+
+ { "get_persistence", ventoy_api_get_persistence },
+ { "save_persistence", ventoy_api_save_persistence },
+ { "persistence_add", ventoy_api_persistence_add },
+ { "persistence_del", ventoy_api_persistence_del },
+ { "persistence_add_inner", ventoy_api_persistence_add_inner },
+ { "persistence_del_inner", ventoy_api_persistence_del_inner },
+
+ { "get_password", ventoy_api_get_password },
+ { "save_password", ventoy_api_save_password },
+ { "password_add", ventoy_api_password_add },
+ { "password_del", ventoy_api_password_del },
+
+ { "get_injection", ventoy_api_get_injection },
+ { "save_injection", ventoy_api_save_injection },
+ { "injection_add", ventoy_api_injection_add },
+ { "injection_del", ventoy_api_injection_del },
+
+
+};
+
+static int ventoy_json_handler(struct mg_connection *conn, VTOY_JSON *json)
+{
+ int i;
+ const char *method = NULL;
+
+ method = vtoy_json_get_string_ex(json, "method");
+ if (!method)
+ {
+ ventoy_json_result(conn, VTOY_JSON_SUCCESS_RET);
+ return 0;
+ }
+
+ if (strcmp(method, "handshake") == 0)
+ {
+ ventoy_api_handshake(conn, json);
+ return 0;
+ }
+
+ for (i = 0; i < (int)(sizeof(g_ventoy_json_cb) / sizeof(g_ventoy_json_cb[0])); i++)
+ {
+ if (strcmp(method, g_ventoy_json_cb[i].method) == 0)
+ {
+ g_ventoy_json_cb[i].callback(conn, json);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int ventoy_request_handler(struct mg_connection *conn)
+{
+ int post_data_len;
+ int post_buf_len;
+ VTOY_JSON *json = NULL;
+ char *post_data_buf = NULL;
+ const struct mg_request_info *ri = NULL;
+ char stack_buf[512];
+
+ ri = mg_get_request_info(conn);
+
+ if (strcmp(ri->uri, "/vtoy/json") == 0)
+ {
+ if (ri->content_length > 500)
+ {
+ post_data_buf = malloc((int)(ri->content_length + 4));
+ post_buf_len = (int)(ri->content_length + 1);
+ }
+ else
+ {
+ post_data_buf = stack_buf;
+ post_buf_len = sizeof(stack_buf);
+ }
+
+ post_data_len = mg_read(conn, post_data_buf, post_buf_len);
+ post_data_buf[post_data_len] = 0;
+
+ json = vtoy_json_create();
+ if (JSON_SUCCESS == vtoy_json_parse(json, post_data_buf))
+ {
+ pthread_mutex_lock(&g_api_mutex);
+ ventoy_json_handler(conn, json->pstChild);
+ pthread_mutex_unlock(&g_api_mutex);
+ }
+ else
+ {
+ ventoy_json_result(conn, VTOY_JSON_INVALID_RET);
+ }
+
+ vtoy_json_destroy(json);
+
+ if (post_data_buf != stack_buf)
+ {
+ free(post_data_buf);
+ }
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+const char *ventoy_web_openfile(const struct mg_connection *conn, const char *path, size_t *data_len)
+{
+ ventoy_file *node = NULL;
+
+ (void)conn;
+
+ if (!path)
+ {
+ return NULL;
+ }
+
+ node = ventoy_tar_find_file(path);
+ if (node)
+ {
+ *data_len = node->size;
+ return node->addr;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+#if 0
+#endif
+
+static int ventoy_parse_control(VTOY_JSON *json, void *p)
+{
+ int i;
+ VTOY_JSON *node = NULL;
+ VTOY_JSON *child = NULL;
+ data_control *data = (data_control *)p;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType == JSON_TYPE_OBJECT)
+ {
+ child = node->pstChild;
+
+ if (strcmp(child->pcName, "VTOY_DEFAULT_MENU_MODE") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->default_menu_mode);
+ }
+ else if (strcmp(child->pcName, "VTOY_WIN11_BYPASS_CHECK") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->win11_bypass_check);
+ }
+ else if (strcmp(child->pcName, "VTOY_TREE_VIEW_MENU_STYLE") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->treeview_style);
+ }
+ else if (strcmp(child->pcName, "VTOY_FILT_DOT_UNDERSCORE_FILE") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->filter_dot_underscore);
+ }
+ else if (strcmp(child->pcName, "VTOY_SORT_CASE_SENSITIVE") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->sort_casesensitive);
+ }
+ else if (strcmp(child->pcName, "VTOY_MAX_SEARCH_LEVEL") == 0)
+ {
+ if (strcmp(child->unData.pcStrVal, "max") == 0)
+ {
+ data->max_search_level = -1;
+ }
+ else
+ {
+ data->max_search_level = (int)strtol(child->unData.pcStrVal, NULL, 10);
+ }
+ }
+ else if (strcmp(child->pcName, "VTOY_DEFAULT_SEARCH_ROOT") == 0)
+ {
+ strlcpy(data->default_search_root, child->unData.pcStrVal);
+ }
+ else if (strcmp(child->pcName, "VTOY_DEFAULT_IMAGE") == 0)
+ {
+ strlcpy(data->default_image, child->unData.pcStrVal);
+ }
+ else if (strcmp(child->pcName, "VTOY_DEFAULT_KBD_LAYOUT") == 0)
+ {
+ for (i = 0; g_ventoy_kbd_layout[i]; i++)
+ {
+ if (strcmp(child->unData.pcStrVal, g_ventoy_kbd_layout[i]) == 0)
+ {
+ strlcpy(data->default_kbd_layout, child->unData.pcStrVal);
+ break;
+ }
+ }
+ }
+ else if (strcmp(child->pcName, "VTOY_HELP_TXT_LANGUAGE") == 0)
+ {
+ for (i = 0; g_ventoy_help_lang[i]; i++)
+ {
+ if (strcmp(child->unData.pcStrVal, g_ventoy_help_lang[i]) == 0)
+ {
+ strlcpy(data->help_text_language, child->unData.pcStrVal);
+ break;
+ }
+ }
+ }
+ else if (strcmp(child->pcName, "VTOY_MENU_TIMEOUT") == 0)
+ {
+ data->menu_timeout = (int)strtol(child->unData.pcStrVal, NULL, 10);
+ }
+ else if (strcmp(child->pcName, "VTOY_VHD_NO_WARNING") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->vhd_no_warning);
+ }
+ else if (strcmp(child->pcName, "VTOY_FILE_FLT_ISO") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->filter_iso);
+ }
+ else if (strcmp(child->pcName, "VTOY_FILE_FLT_IMG") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->filter_img);
+ }
+ else if (strcmp(child->pcName, "VTOY_FILE_FLT_EFI") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->filter_efi);
+ }
+ else if (strcmp(child->pcName, "VTOY_FILE_FLT_WIM") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->filter_wim);
+ }
+ else if (strcmp(child->pcName, "VTOY_FILE_FLT_VHD") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->filter_vhd);
+ }
+ else if (strcmp(child->pcName, "VTOY_FILE_FLT_VTOY") == 0)
+ {
+ CONTROL_PARSE_INT(child, data->filter_vtoy);
+ }
+
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_theme(VTOY_JSON *json, void *p)
+{
+ const char *dismode = NULL;
+ VTOY_JSON *child = NULL;
+ VTOY_JSON *node = NULL;
+ path_node *tail = NULL;
+ path_node *pnode = NULL;
+ data_theme *data = (data_theme *)p;
+
+ if (json->enDataType != JSON_TYPE_OBJECT)
+ {
+ return 0;
+ }
+
+ child = json->pstChild;
+
+ dismode = vtoy_json_get_string_ex(child, "display_mode");
+ vtoy_json_get_string(child, "ventoy_left", sizeof(data->ventoy_left), data->ventoy_left);
+ vtoy_json_get_string(child, "ventoy_top", sizeof(data->ventoy_top), data->ventoy_top);
+ vtoy_json_get_string(child, "ventoy_color", sizeof(data->ventoy_color), data->ventoy_color);
+
+ vtoy_json_get_int(child, "default_file", &(data->default_file));
+ vtoy_json_get_string(child, "gfxmode", sizeof(data->gfxmode), data->gfxmode);
+ vtoy_json_get_string(child, "serial_param", sizeof(data->serial_param), data->serial_param);
+
+ if (dismode)
+ {
+ if (strcmp(dismode, "CLI") == 0)
+ {
+ data->display_mode = display_mode_cli;
+ }
+ else if (strcmp(dismode, "serial") == 0)
+ {
+ data->display_mode = display_mode_serial;
+ }
+ else if (strcmp(dismode, "serial_console") == 0)
+ {
+ data->display_mode = display_mode_ser_console;
+ }
+ else
+ {
+ data->display_mode = display_mode_gui;
+ }
+ }
+
+ node = vtoy_json_find_item(child, JSON_TYPE_STRING, "file");
+ if (node)
+ {
+ data->default_file = 0;
+
+ pnode = zalloc(sizeof(path_node));
+ if (pnode)
+ {
+ strlcpy(pnode->path, node->unData.pcStrVal);
+ data->filelist = pnode;
+ }
+ }
+ else
+ {
+ node = vtoy_json_find_item(child, JSON_TYPE_ARRAY, "file");
+ if (node)
+ {
+ for (node = node->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType == JSON_TYPE_STRING)
+ {
+ pnode = zalloc(sizeof(path_node));
+ if (pnode)
+ {
+ strlcpy(pnode->path, node->unData.pcStrVal);
+ if (data->filelist)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->filelist = tail = pnode;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ node = vtoy_json_find_item(child, JSON_TYPE_ARRAY, "fonts");
+ if (node)
+ {
+ for (node = node->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType == JSON_TYPE_STRING)
+ {
+ pnode = zalloc(sizeof(path_node));
+ if (pnode)
+ {
+ strlcpy(pnode->path, node->unData.pcStrVal);
+ if (data->fontslist)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->fontslist = tail = pnode;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_menu_alias(VTOY_JSON *json, void *p)
+{
+ int type;
+ const char *path = NULL;
+ const char *alias = NULL;
+ data_alias *data = (data_alias *)p;
+ data_alias_node *tail = NULL;
+ data_alias_node *pnode = NULL;
+ VTOY_JSON *node = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ type = path_type_file;
+ path = vtoy_json_get_string_ex(node->pstChild, "image");
+ if (!path)
+ {
+ path = vtoy_json_get_string_ex(node->pstChild, "dir");
+ type = path_type_dir;
+ }
+ alias = vtoy_json_get_string_ex(node->pstChild, "alias");
+
+ if (path && alias)
+ {
+ pnode = zalloc(sizeof(data_alias_node));
+ if (pnode)
+ {
+ pnode->type = type;
+ strlcpy(pnode->path, path);
+ strlcpy(pnode->alias, alias);
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int ventoy_parse_menu_tip(VTOY_JSON *json, void *p)
+{
+ int type;
+ const char *path = NULL;
+ const char *tip = NULL;
+ data_tip *data = (data_tip *)p;
+ data_tip_node *tail = NULL;
+ data_tip_node *pnode = NULL;
+ VTOY_JSON *node = NULL;
+ VTOY_JSON *tips = NULL;
+
+ if (json->enDataType != JSON_TYPE_OBJECT)
+ {
+ return 0;
+ }
+
+ vtoy_json_get_string(json->pstChild, "left", sizeof(data->left), data->left);
+ vtoy_json_get_string(json->pstChild, "top", sizeof(data->top), data->top);
+ vtoy_json_get_string(json->pstChild, "color", sizeof(data->color), data->color);
+
+ tips = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "tips");
+ if (!tips)
+ {
+ return 0;
+ }
+
+ for (node = tips->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ type = path_type_file;
+ path = vtoy_json_get_string_ex(node->pstChild, "image");
+ if (!path)
+ {
+ path = vtoy_json_get_string_ex(node->pstChild, "dir");
+ type = path_type_dir;
+ }
+ tip = vtoy_json_get_string_ex(node->pstChild, "tip");
+
+ if (path && tip)
+ {
+ pnode = zalloc(sizeof(data_tip_node));
+ if (pnode)
+ {
+ pnode->type = type;
+ strlcpy(pnode->path, path);
+ strlcpy(pnode->tip, tip);
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_menu_class(VTOY_JSON *json, void *p)
+{
+ int type;
+ const char *path = NULL;
+ const char *class = NULL;
+ data_class *data = (data_class *)p;
+ data_class_node *tail = NULL;
+ data_class_node *pnode = NULL;
+ VTOY_JSON *node = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ type = class_type_key;
+ path = vtoy_json_get_string_ex(node->pstChild, "key");
+ if (!path)
+ {
+ type = class_type_dir;
+ path = vtoy_json_get_string_ex(node->pstChild, "dir");
+ if (!path)
+ {
+ type = class_type_parent;
+ path = vtoy_json_get_string_ex(node->pstChild, "parent");
+ }
+ }
+ class = vtoy_json_get_string_ex(node->pstChild, "class");
+
+ if (path && class)
+ {
+ pnode = zalloc(sizeof(data_class_node));
+ if (pnode)
+ {
+ pnode->type = type;
+ strlcpy(pnode->path, path);
+ strlcpy(pnode->class, class);
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_auto_install(VTOY_JSON *json, void *p)
+{
+ int type;
+ int count;
+ int timeout;
+ int timeouten;
+ int autosel;
+ int autoselen;
+ const char *path = NULL;
+ const char *file = NULL;
+ data_auto_install *data = (data_auto_install *)p;
+ auto_install_node *tail = NULL;
+ auto_install_node *pnode = NULL;
+ path_node *pathnode = NULL;
+ path_node *pathtail = NULL;
+ VTOY_JSON *node = NULL;
+ VTOY_JSON *filelist = NULL;
+ VTOY_JSON *filenode = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ type = 0;
+ path = vtoy_json_get_string_ex(node->pstChild, "image");
+ if (!path)
+ {
+ path = vtoy_json_get_string_ex(node->pstChild, "parent");
+ type = 1;
+ }
+ if (!path)
+ {
+ continue;
+ }
+
+ file = vtoy_json_get_string_ex(node->pstChild, "template");
+ if (file)
+ {
+ pnode = zalloc(sizeof(auto_install_node));
+ if (pnode)
+ {
+ pnode->type = type;
+ pnode->autosel = 1;
+ strlcpy(pnode->path, path);
+
+ pathnode = zalloc(sizeof(path_node));
+ if (pathnode)
+ {
+ strlcpy(pathnode->path, file);
+ pnode->list = pathnode;
+ }
+ else
+ {
+ free(pnode);
+ }
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+
+ continue;
+ }
+
+
+ timeouten = autoselen = 0;
+ if (JSON_SUCCESS == vtoy_json_get_int(node->pstChild, "timeout", &timeout))
+ {
+ timeouten = 1;
+ }
+ if (JSON_SUCCESS == vtoy_json_get_int(node->pstChild, "autosel", &autosel))
+ {
+ autoselen = 1;
+ }
+
+ filelist = vtoy_json_find_item(node->pstChild, JSON_TYPE_ARRAY, "template");
+ if (!filelist)
+ {
+ continue;
+ }
+
+ pnode = zalloc(sizeof(auto_install_node));
+ if (!pnode)
+ {
+ continue;
+ }
+
+ pnode->type = type;
+ pnode->autoselen = autoselen;
+ pnode->timeouten = timeouten;
+ pnode->timeout = timeout;
+ pnode->autosel = autosel;
+ strlcpy(pnode->path, path);
+
+ count = 0;
+ for (filenode = filelist->pstChild; filenode; filenode = filenode->pstNext)
+ {
+ if (filenode->enDataType != JSON_TYPE_STRING)
+ {
+ continue;
+ }
+
+ pathnode = zalloc(sizeof(path_node));
+ if (pathnode)
+ {
+ count++;
+ strlcpy(pathnode->path, filenode->unData.pcStrVal);
+
+ if (pnode->list)
+ {
+ pathtail->next = pathnode;
+ pathtail = pathnode;
+ }
+ else
+ {
+ pnode->list = pathtail = pathnode;
+ }
+ }
+ }
+
+ if (count == 0)
+ {
+ free(pnode);
+ }
+ else
+ {
+ if (pnode->autoselen && pnode->autosel > count)
+ {
+ pnode->autosel = 1;
+ }
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_persistence(VTOY_JSON *json, void *p)
+{
+ int count;
+ int timeout;
+ int timeouten;
+ int autosel;
+ int autoselen;
+ const char *path = NULL;
+ const char *file = NULL;
+ data_persistence *data = (data_persistence *)p;
+ persistence_node *tail = NULL;
+ persistence_node *pnode = NULL;
+ path_node *pathnode = NULL;
+ path_node *pathtail = NULL;
+ VTOY_JSON *node = NULL;
+ VTOY_JSON *filelist = NULL;
+ VTOY_JSON *filenode = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ path = vtoy_json_get_string_ex(node->pstChild, "image");
+ if (!path)
+ {
+ continue;
+ }
+
+ file = vtoy_json_get_string_ex(node->pstChild, "backend");
+ if (file)
+ {
+ pnode = zalloc(sizeof(persistence_node));
+ if (pnode)
+ {
+ pnode->type = 0;
+ pnode->autosel = 1;
+ strlcpy(pnode->path, path);
+
+ pathnode = zalloc(sizeof(path_node));
+ if (pathnode)
+ {
+ strlcpy(pathnode->path, file);
+ pnode->list = pathnode;
+ }
+ else
+ {
+ free(pnode);
+ }
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+
+ continue;
+ }
+
+
+ timeouten = autoselen = 0;
+ if (JSON_SUCCESS == vtoy_json_get_int(node->pstChild, "timeout", &timeout))
+ {
+ timeouten = 1;
+ }
+ if (JSON_SUCCESS == vtoy_json_get_int(node->pstChild, "autosel", &autosel))
+ {
+ autoselen = 1;
+ }
+
+ filelist = vtoy_json_find_item(node->pstChild, JSON_TYPE_ARRAY, "backend");
+ if (!filelist)
+ {
+ continue;
+ }
+
+ pnode = zalloc(sizeof(persistence_node));
+ if (!pnode)
+ {
+ continue;
+ }
+
+ pnode->type = 0;
+ pnode->autoselen = autoselen;
+ pnode->timeouten = timeouten;
+ pnode->timeout = timeout;
+ pnode->autosel = autosel;
+ strlcpy(pnode->path, path);
+
+ count = 0;
+ for (filenode = filelist->pstChild; filenode; filenode = filenode->pstNext)
+ {
+ if (filenode->enDataType != JSON_TYPE_STRING)
+ {
+ continue;
+ }
+
+ pathnode = zalloc(sizeof(path_node));
+ if (pathnode)
+ {
+ count++;
+ strlcpy(pathnode->path, filenode->unData.pcStrVal);
+
+ if (pnode->list)
+ {
+ pathtail->next = pathnode;
+ pathtail = pathnode;
+ }
+ else
+ {
+ pnode->list = pathtail = pathnode;
+ }
+ }
+ }
+
+ if (count == 0)
+ {
+ free(pnode);
+ }
+ else
+ {
+ if (pnode->autoselen && pnode->autosel > count)
+ {
+ pnode->autosel = 1;
+ }
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_injection(VTOY_JSON *json, void *p)
+{
+ int type;
+ const char *path = NULL;
+ const char *archive = NULL;
+ data_injection *data = (data_injection *)p;
+ injection_node *tail = NULL;
+ injection_node *pnode = NULL;
+ VTOY_JSON *node = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ type = 0;
+ path = vtoy_json_get_string_ex(node->pstChild, "image");
+ if (!path)
+ {
+ path = vtoy_json_get_string_ex(node->pstChild, "parent");
+ type = 1;
+ }
+ archive = vtoy_json_get_string_ex(node->pstChild, "archive");
+
+ if (path && archive)
+ {
+ pnode = zalloc(sizeof(injection_node));
+ if (pnode)
+ {
+ pnode->type = type;
+ strlcpy(pnode->path, path);
+ strlcpy(pnode->archive, archive);
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_conf_replace(VTOY_JSON *json, void *p)
+{
+ int img = 0;
+ const char *path = NULL;
+ const char *org = NULL;
+ const char *new = NULL;
+ data_conf_replace *data = (data_conf_replace *)p;
+ conf_replace_node *tail = NULL;
+ conf_replace_node *pnode = NULL;
+ VTOY_JSON *node = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ path = vtoy_json_get_string_ex(node->pstChild, "iso");
+ org = vtoy_json_get_string_ex(node->pstChild, "org");
+ new = vtoy_json_get_string_ex(node->pstChild, "new");
+
+ img = 0;
+ vtoy_json_get_int(node->pstChild, "img", &img);
+
+ if (path && org && new)
+ {
+ pnode = zalloc(sizeof(conf_replace_node));
+ if (pnode)
+ {
+ strlcpy(pnode->path, path);
+ strlcpy(pnode->org, org);
+ strlcpy(pnode->new, new);
+ if (img == 1)
+ {
+ pnode->image = img;
+ }
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_password(VTOY_JSON *json, void *p)
+{
+ int type;
+ const char *bootpwd = NULL;
+ const char *isopwd= NULL;
+ const char *wimpwd= NULL;
+ const char *imgpwd= NULL;
+ const char *efipwd= NULL;
+ const char *vhdpwd= NULL;
+ const char *vtoypwd= NULL;
+ const char *path = NULL;
+ const char *pwd = NULL;
+ data_password *data = (data_password *)p;
+ menu_password *tail = NULL;
+ menu_password *pnode = NULL;
+ VTOY_JSON *node = NULL;
+ VTOY_JSON *menupwd = NULL;
+
+ if (json->enDataType != JSON_TYPE_OBJECT)
+ {
+ return 0;
+ }
+
+ bootpwd = vtoy_json_get_string_ex(json->pstChild, "bootpwd");
+ isopwd = vtoy_json_get_string_ex(json->pstChild, "isopwd");
+ wimpwd = vtoy_json_get_string_ex(json->pstChild, "wimpwd");
+ imgpwd = vtoy_json_get_string_ex(json->pstChild, "imgpwd");
+ efipwd = vtoy_json_get_string_ex(json->pstChild, "efipwd");
+ vhdpwd = vtoy_json_get_string_ex(json->pstChild, "vhdpwd");
+ vtoypwd = vtoy_json_get_string_ex(json->pstChild, "vtoypwd");
+
+
+ if (bootpwd) strlcpy(data->bootpwd, bootpwd);
+ if (isopwd) strlcpy(data->isopwd, isopwd);
+ if (wimpwd) strlcpy(data->wimpwd, wimpwd);
+ if (imgpwd) strlcpy(data->imgpwd, imgpwd);
+ if (efipwd) strlcpy(data->efipwd, efipwd);
+ if (vhdpwd) strlcpy(data->vhdpwd, vhdpwd);
+ if (vtoypwd) strlcpy(data->vtoypwd, vtoypwd);
+
+
+ menupwd = vtoy_json_find_item(json->pstChild, JSON_TYPE_ARRAY, "menupwd");
+ if (!menupwd)
+ {
+ return 0;
+ }
+
+ for (node = menupwd->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ type = 0;
+ path = vtoy_json_get_string_ex(node->pstChild, "file");
+ if (!path)
+ {
+ path = vtoy_json_get_string_ex(node->pstChild, "parent");
+ type = 1;
+ }
+ pwd = vtoy_json_get_string_ex(node->pstChild, "pwd");
+
+ if (path && pwd)
+ {
+ pnode = zalloc(sizeof(menu_password));
+ if (pnode)
+ {
+ pnode->type = type;
+ strlcpy(pnode->path, path);
+ strlcpy(pnode->pwd, pwd);
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int ventoy_parse_image_list_real(VTOY_JSON *json, int type, void *p)
+{
+ VTOY_JSON *node = NULL;
+ data_image_list *data = (data_image_list *)p;
+ path_node *tail = NULL;
+ path_node *pnode = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ data->type = type;
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType == JSON_TYPE_STRING)
+ {
+ pnode = zalloc(sizeof(path_node));
+ if (pnode)
+ {
+ strlcpy(pnode->path, node->unData.pcStrVal);
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_image_blacklist(VTOY_JSON *json, void *p)
+{
+ return ventoy_parse_image_list_real(json, 1, p);
+}
+static int ventoy_parse_image_list(VTOY_JSON *json, void *p)
+{
+ return ventoy_parse_image_list_real(json, 0, p);
+}
+
+static int ventoy_parse_auto_memdisk(VTOY_JSON *json, void *p)
+{
+ VTOY_JSON *node = NULL;
+ data_auto_memdisk *data = (data_auto_memdisk *)p;
+ path_node *tail = NULL;
+ path_node *pnode = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType == JSON_TYPE_STRING)
+ {
+ pnode = zalloc(sizeof(path_node));
+ if (pnode)
+ {
+ strlcpy(pnode->path, node->unData.pcStrVal);
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+static int ventoy_parse_dud(VTOY_JSON *json, void *p)
+{
+ int count = 0;
+ const char *path = NULL;
+ const char *file = NULL;
+ data_dud *data = (data_dud *)p;
+ dud_node *tail = NULL;
+ dud_node *pnode = NULL;
+ path_node *pathnode = NULL;
+ path_node *pathtail = NULL;
+ VTOY_JSON *node = NULL;
+ VTOY_JSON *filelist = NULL;
+ VTOY_JSON *filenode = NULL;
+
+ if (json->enDataType != JSON_TYPE_ARRAY)
+ {
+ return 0;
+ }
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ if (node->enDataType != JSON_TYPE_OBJECT)
+ {
+ continue;
+ }
+
+ path = vtoy_json_get_string_ex(node->pstChild, "image");
+ if (!path)
+ {
+ continue;
+ }
+
+ file = vtoy_json_get_string_ex(node->pstChild, "dud");
+ if (file)
+ {
+ pnode = zalloc(sizeof(dud_node));
+ if (pnode)
+ {
+ strlcpy(pnode->path, path);
+
+ pathnode = zalloc(sizeof(path_node));
+ if (pathnode)
+ {
+ strlcpy(pathnode->path, file);
+ pnode->list = pathnode;
+ }
+ else
+ {
+ free(pnode);
+ }
+
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+
+ continue;
+ }
+
+ filelist = vtoy_json_find_item(node->pstChild, JSON_TYPE_ARRAY, "dud");
+ if (!filelist)
+ {
+ continue;
+ }
+
+ pnode = zalloc(sizeof(dud_node));
+ if (!pnode)
+ {
+ continue;
+ }
+
+ strlcpy(pnode->path, path);
+
+ for (filenode = filelist->pstChild; filenode; filenode = filenode->pstNext)
+ {
+ if (filenode->enDataType != JSON_TYPE_STRING)
+ {
+ continue;
+ }
+
+ pathnode = zalloc(sizeof(path_node));
+ if (pathnode)
+ {
+ strlcpy(pathnode->path, filenode->unData.pcStrVal);
+ count++;
+
+ if (pnode->list)
+ {
+ pathtail->next = pathnode;
+ pathtail = pathnode;
+ }
+ else
+ {
+ pnode->list = pathtail = pathnode;
+ }
+ }
+ }
+
+ if (count == 0)
+ {
+ free(pnode);
+ }
+ else
+ {
+ if (data->list)
+ {
+ tail->next = pnode;
+ tail = pnode;
+ }
+ else
+ {
+ data->list = tail = pnode;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+#if 0
+#endif
+
+
+static int ventoy_load_old_json(const char *filename)
+{
+ int ret = 0;
+ int offset = 0;
+ int buflen = 0;
+ char *buffer = NULL;
+ unsigned char *start = NULL;
+ VTOY_JSON *json = NULL;
+ VTOY_JSON *node = NULL;
+
+ ret = ventoy_read_file_to_buf(filename, 4, (void **)&buffer, &buflen);
+ if (ret)
+ {
+ vlog("Failed to read old ventoy.json file.\n");
+ return 1;
+ }
+ buffer[buflen] = 0;
+
+ start = (unsigned char *)buffer;
+
+ if (start[0] == 0xef && start[1] == 0xbb && start[2] == 0xbf)
+ {
+ offset = 3;
+ }
+ else if ((start[0] == 0xff && start[1] == 0xfe) || (start[0] == 0xfe && start[1] == 0xff))
+ {
+ vlog("ventoy.json is in UCS-2 encoding, ignore it.\n");
+ free(buffer);
+ return 1;
+ }
+
+ json = vtoy_json_create();
+ if (!json)
+ {
+ free(buffer);
+ return 1;
+ }
+
+ if (vtoy_json_parse_ex(json, buffer + offset, buflen - offset) == JSON_SUCCESS)
+ {
+ vlog("parse ventoy.json success\n");
+
+ for (node = json->pstChild; node; node = node->pstNext)
+ {
+ ventoy_parse_json(control);
+ ventoy_parse_json(theme);
+ ventoy_parse_json(menu_alias);
+ ventoy_parse_json(menu_tip);
+ ventoy_parse_json(menu_class);
+ ventoy_parse_json(auto_install);
+ ventoy_parse_json(persistence);
+ ventoy_parse_json(injection);
+ ventoy_parse_json(conf_replace);
+ ventoy_parse_json(password);
+ ventoy_parse_json(image_list);
+ ventoy_parse_json(image_blacklist);
+ ventoy_parse_json(auto_memdisk);
+ ventoy_parse_json(dud);
+ }
+ }
+ else
+ {
+ vlog("ventoy.json has syntax error.\n");
+ g_sysinfo.syntax_error = 1;
+ ret = 1;
+ }
+
+ vtoy_json_destroy(json);
+
+ free(buffer);
+ return ret;
+}
+
+
+int ventoy_http_start(const char *ip, const char *port)
+{
+ int i;
+ char addr[128];
+ char filename[128];
+ char backupname[128];
+ struct mg_callbacks callbacks;
+ const char *options[] =
+ {
+ "listening_ports", "24681",
+ "document_root", "www",
+ "index_files", "index.html",
+ "num_threads", "16",
+ "error_log_file", LOG_FILE,
+ "request_timeout_ms", "10000",
+ NULL
+ };
+
+ for (i = 0; i <= bios_max; i++)
+ {
+ ventoy_data_default_control(g_data_control + i);
+ ventoy_data_default_theme(g_data_theme + i);
+ ventoy_data_default_menu_alias(g_data_menu_alias + i);
+ ventoy_data_default_menu_class(g_data_menu_class + i);
+ ventoy_data_default_menu_tip(g_data_menu_tip + i);
+ ventoy_data_default_auto_install(g_data_auto_install + i);
+ ventoy_data_default_persistence(g_data_persistence + i);
+ ventoy_data_default_injection(g_data_injection + i);
+ ventoy_data_default_conf_replace(g_data_conf_replace + i);
+ ventoy_data_default_password(g_data_password + i);
+ ventoy_data_default_image_list(g_data_image_list + i);
+ ventoy_data_default_auto_memdisk(g_data_auto_memdisk + i);
+ ventoy_data_default_dud(g_data_dud + i);
+ }
+
+ ventoy_get_json_path(filename, backupname);
+ if (ventoy_is_file_exist("%s", filename))
+ {
+ ventoy_copy_file(filename, backupname);
+ ventoy_load_old_json(filename);
+ }
+
+
+ /* option */
+ scnprintf(addr, sizeof(addr), "%s:%s", ip, port);
+ options[1] = addr;
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.begin_request = ventoy_request_handler;
+#ifndef VENTOY_SIM
+ callbacks.open_file = ventoy_web_openfile;
+#endif
+ g_ventoy_http_ctx = mg_start(&callbacks, NULL, options);
+
+ ventoy_start_writeback_thread(ventoy_http_writeback);
+
+ return g_ventoy_http_ctx ? 0 : 1;
+}
+
+int ventoy_http_stop(void)
+{
+ if (g_ventoy_http_ctx)
+ {
+ mg_stop(g_ventoy_http_ctx);
+ }
+
+ ventoy_stop_writeback_thread();
+ return 0;
+}
+
+int ventoy_http_init(void)
+{
+ if (!g_pub_json_buffer)
+ {
+ g_pub_json_buffer = malloc(JSON_BUF_MAX * 2);
+ g_pub_save_buffer = g_pub_json_buffer + JSON_BUF_MAX;
+ }
+
+ pthread_mutex_init(&g_api_mutex, NULL);
+ return 0;
+}
+
+void ventoy_http_exit(void)
+{
+ check_free(g_pub_json_buffer);
+ g_pub_json_buffer = NULL;
+ g_pub_save_buffer = NULL;
+
+ pthread_mutex_destroy(&g_api_mutex);
+}
+
+
--- /dev/null
+/******************************************************************************
+ * ventoy_http.h
+ *
+ * Copyright (c) 2021, longpanda <admin@ventoy.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __VENTOY_HTTP_H__
+#define __VENTOY_HTTP_H__
+
+#include <civetweb.h>
+
+
+#define L1 " "
+#define L2 " "
+#define L3 " "
+#define L4 " "
+
+typedef enum bios_mode
+{
+ bios_common = 0,
+ bios_legacy,
+ bios_uefi,
+ bios_ia32,
+ bios_aa64,
+ bios_mips,
+
+ bios_max
+}bios_mode;
+
+
+typedef struct data_control
+{
+ int default_menu_mode;
+ int treeview_style;
+ int filter_dot_underscore;
+ int sort_casesensitive;
+ int max_search_level;
+ int vhd_no_warning;
+ int filter_iso;
+ int filter_wim;
+ int filter_efi;
+ int filter_img;
+ int filter_vhd;
+ int filter_vtoy;
+ int win11_bypass_check;
+ int menu_timeout;
+ char default_search_root[MAX_PATH];
+ char default_image[MAX_PATH];
+ char default_kbd_layout[32];
+ char help_text_language[32];
+}data_control;
+
+#define display_mode_gui 0
+#define display_mode_cli 1
+#define display_mode_serial 2
+#define display_mode_ser_console 3
+
+typedef struct path_node
+{
+ char path[MAX_PATH];
+ struct path_node *next;
+}path_node;
+
+typedef struct data_theme
+{
+ int default_file;
+ path_node *filelist;
+ int display_mode;
+ char gfxmode[32];
+
+ char ventoy_left[32];
+ char ventoy_top[32];
+ char ventoy_color[32];
+ char serial_param[256];
+
+ path_node *fontslist;
+}data_theme;
+
+#define path_type_file 0
+#define path_type_dir 1
+
+typedef struct data_alias_node
+{
+ int type;
+ char path[MAX_PATH];
+ char alias[256];
+ struct data_alias_node *next;
+}data_alias_node;
+
+typedef struct data_alias
+{
+ data_alias_node *list;
+}data_alias;
+
+
+typedef struct data_tip_node
+{
+ int type;
+ char path[MAX_PATH];
+ char tip[256];
+ struct data_tip_node *next;
+}data_tip_node;
+
+typedef struct data_tip
+{
+ char left[32];
+ char top[32];
+ char color[32];
+ data_tip_node *list;
+}data_tip;
+
+
+#define class_type_key 0
+#define class_type_dir 1
+#define class_type_parent 2
+typedef struct data_class_node
+{
+ int type;
+ char path[MAX_PATH];
+ char class[256];
+ struct data_class_node *next;
+}data_class_node;
+
+typedef struct data_class
+{
+ data_class_node *list;
+}data_class;
+
+
+typedef struct data_auto_memdisk
+{
+ path_node *list;
+}data_auto_memdisk;
+
+typedef struct data_image_list
+{
+ int type;
+ path_node *list;
+}data_image_list;
+
+typedef struct menu_password
+{
+ int type;
+ char path[MAX_PATH];
+ char pwd[256];
+ struct menu_password *next;
+}menu_password;
+
+typedef struct data_password
+{
+ char bootpwd[256];
+ char isopwd[256];
+ char wimpwd[256];
+ char vhdpwd[256];
+ char imgpwd[256];
+ char efipwd[256];
+ char vtoypwd[256];
+
+ menu_password *list;
+}data_password;
+
+typedef struct conf_replace_node
+{
+ int image;
+ char path[MAX_PATH];
+ char org[256];
+ char new[MAX_PATH];
+ struct conf_replace_node *next;
+}conf_replace_node;
+typedef struct data_conf_replace
+{
+ conf_replace_node *list;
+}data_conf_replace;
+
+typedef struct injection_node
+{
+ int type;
+ char path[MAX_PATH];
+ char archive[MAX_PATH];
+ struct injection_node *next;
+}injection_node;
+typedef struct data_injection
+{
+ injection_node *list;
+}data_injection;
+
+
+
+typedef struct dud_node
+{
+ char path[MAX_PATH];
+ path_node *list;
+
+ struct dud_node *next;
+}dud_node;
+
+typedef struct data_dud
+{
+ dud_node *list;
+}data_dud;
+
+typedef struct auto_install_node
+{
+ int timeouten;
+ int timeout;
+ int autoselen;
+ int autosel;
+ int type;
+ char path[MAX_PATH];
+ path_node *list;
+
+ struct auto_install_node *next;
+}auto_install_node;
+
+typedef struct data_auto_install
+{
+ auto_install_node *list;
+}data_auto_install;
+
+typedef struct persistence_node
+{
+ int timeouten;
+ int timeout;
+ int autoselen;
+ int autosel;
+ int type;
+ char path[MAX_PATH];
+ path_node *list;
+
+ struct persistence_node *next;
+}persistence_node;
+
+typedef struct data_persistence
+{
+ persistence_node *list;
+}data_persistence;
+
+
+
+
+#define ventoy_save_plug(plug) \
+{\
+ for (i = 0; i < bios_max; i++) \
+ {\
+ scnprintf(title, sizeof(title), "%s%s", #plug, g_json_title_postfix[i]);\
+ if (ventoy_data_cmp_##plug(g_data_##plug + i, g_data_##plug + bios_max))\
+ {\
+ pos += ventoy_data_save_##plug(g_data_##plug + i, title, JSON_SAVE_BUFFER + pos, JSON_BUF_MAX - pos);\
+ }\
+ }\
+}
+
+
+
+#define api_get_func(conn, json, name) \
+{\
+ int i = 0; \
+ int pos = 0; \
+\
+ (void)json;\
+\
+ VTOY_JSON_FMT_BEGIN(pos, JSON_BUFFER, JSON_BUF_MAX);\
+ VTOY_JSON_FMT_ARY_BEGIN();\
+\
+ for (i = 0; i <= bios_max; i++)\
+ {\
+ __uiCurPos += ventoy_data_json_##name(g_data_##name + i, JSON_BUFFER + __uiCurPos, JSON_BUF_MAX - __uiCurPos);\
+ VTOY_JSON_FMT_COMA();\
+ }\
+\
+ VTOY_JSON_FMT_ARY_END();\
+ VTOY_JSON_FMT_END(pos);\
+\
+ ventoy_json_buffer(conn, JSON_BUFFER, pos);\
+}
+
+
+#define vtoy_list_free(type, list) \
+{\
+ type *__next = NULL;\
+ type *__node = list;\
+ while (__node)\
+ {\
+ __next = __node->next;\
+ free(__node);\
+ __node = __next;\
+ }\
+}
+
+#define vtoy_list_del(last, node, LIST, field) \
+for (last = node = LIST; node; node = node->next) \
+{\
+ if (strcmp(node->field, field) == 0)\
+ {\
+ if (node == LIST)\
+ {\
+ LIST = LIST->next;\
+ }\
+ else\
+ {\
+ last->next = node->next;\
+ }\
+ free(node);\
+ break;\
+ }\
+\
+ last = node;\
+}
+
+
+#define vtoy_list_del_ex(last, node, LIST, field, cb) \
+for (last = node = LIST; node; node = node->next) \
+{\
+ if (strcmp(node->field, field) == 0)\
+ {\
+ if (node == LIST)\
+ {\
+ LIST = LIST->next;\
+ }\
+ else\
+ {\
+ last->next = node->next;\
+ }\
+ cb(node->list);\
+ free(node);\
+ break;\
+ }\
+\
+ last = node;\
+}
+
+#define vtoy_list_add(LIST, cur, node) \
+if (LIST)\
+{\
+ cur = LIST;\
+ while (cur && cur->next)\
+ {\
+ cur = cur->next;\
+ }\
+ cur->next = node;\
+}\
+else\
+{\
+ LIST = node;\
+}
+
+
+
+#define ventoy_parse_json(name) \
+{\
+ int __loop;\
+ int __len = strlen(#name);\
+ if (strncmp(#name, node->pcName, __len) == 0)\
+ {\
+ for (__loop = 0; __loop < bios_max; __loop++)\
+ {\
+ if (strcmp(g_json_title_postfix[__loop], node->pcName + __len) == 0)\
+ {\
+ vlog("json parse <%s>\n", node->pcName);\
+ ventoy_parse_##name(node, g_data_##name + __loop);\
+ break;\
+ }\
+ }\
+ } \
+}
+
+#define CONTROL_PARSE_INT(node, val) \
+ if (node->unData.pcStrVal[0] == '1') val = 1
+
+
+#define VTOY_JSON_INT(key, val) vtoy_json_get_int(json, key, &val)
+#define VTOY_JSON_STR(key, buf) vtoy_json_get_string(json, key, sizeof(buf), buf)
+#define VTOY_JSON_STR_EX(key) vtoy_json_get_string_ex(json, key)
+
+typedef int (*ventoy_json_callback)(struct mg_connection *conn, VTOY_JSON *json);
+typedef struct JSON_CB
+{
+ const char *method;
+ ventoy_json_callback callback;
+}JSON_CB;
+
+int ventoy_http_init(void);
+void ventoy_http_exit(void);
+int ventoy_http_start(const char *ip, const char *port);
+int ventoy_http_stop(void);
+int ventoy_data_save_all(void);
+
+#endif /* __VENTOY_HTTP_H__ */
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <linux/limits.h>
+#include <ventoy_define.h>
+#include <ventoy_util.h>
+#include <ventoy_json.h>
+#include <ventoy_disk.h>
+#include <ventoy_http.h>
+
+char g_log_file[MAX_PATH];
+char g_cur_dir[MAX_PATH];
+char g_ventoy_dir[MAX_PATH];
+
+int ventoy_log_init(void);
+void ventoy_log_exit(void);
+
+void ventoy_signal_stop(int sig)
+{
+ vlog("ventoy server exit due to signal ...\n");
+ printf("ventoy server exit ...\n");
+
+ ventoy_http_stop();
+ ventoy_http_exit();
+#ifndef VENTOY_SIM
+ ventoy_www_exit();
+#endif
+ ventoy_disk_exit();
+ ventoy_log_exit();
+ exit(0);
+}
+
+int main(int argc, char **argv)
+{
+ int rc;
+ const char *ip = "127.0.0.1";
+ const char *port = "24681";
+
+ if (argc != 9)
+ {
+ printf("Invalid argc %d\n", argc);
+ return 1;
+ }
+
+ if (isdigit(argv[1][0]))
+ {
+ ip = argv[1];
+ }
+
+ if (isdigit(argv[2][0]))
+ {
+ port = argv[2];
+ }
+
+ strlcpy(g_ventoy_dir, argv[3]);
+ scnprintf(g_log_file, sizeof(g_log_file), "%s/%s", g_ventoy_dir, LOG_FILE);
+ ventoy_log_init();
+
+ getcwd(g_cur_dir, MAX_PATH);
+
+ if (!ventoy_is_directory_exist("./ventoy"))
+ {
+ printf("%s/ventoy directory does not exist\n", g_cur_dir);
+ return 1;
+ }
+
+ ventoy_get_disk_info(argv);
+
+ vlog("===============================================\n");
+ vlog("===== Ventoy Plugson %s:%s =====\n", ip, port);
+ vlog("===============================================\n");
+
+ ventoy_disk_init();
+#ifndef VENTOY_SIM
+ rc = ventoy_www_init();
+ if (rc)
+ {
+ printf("Failed to init web data, check log for details.\n");
+ ventoy_disk_exit();
+ ventoy_log_exit();
+ return 1;
+ }
+#endif
+ ventoy_http_init();
+
+ rc = ventoy_http_start(ip, port);
+ if (rc)
+ {
+ printf("Ventoy failed to start http server, check ./ventoy/plugson.log for detail\n");
+ }
+ else
+ {
+ signal(SIGINT, ventoy_signal_stop);
+ signal(SIGTSTP, ventoy_signal_stop);
+ signal(SIGQUIT, ventoy_signal_stop);
+ while (1)
+ {
+ sleep(100);
+ }
+ }
+
+ return 0;
+}
+
--- /dev/null
+#include <Windows.h>\r
+#include <Shlobj.h>\r
+#include <tlhelp32.h>\r
+#include <Psapi.h>\r
+#include <commctrl.h>\r
+#include <resource.h>\r
+#include <ventoy_define.h>\r
+#include <ventoy_util.h>\r
+#include <ventoy_json.h>\r
+#include <ventoy_disk.h>\r
+#include <ventoy_http.h>\r
+\r
+static BOOL g_running = FALSE;\r
+static HWND g_refresh_button;\r
+static HWND g_start_button;\r
+static HWND g_openlink_button;\r
+static HWND g_exit_button;\r
+static HWND g_ComboxHwnd;\r
+\r
+typedef enum MSGID\r
+{\r
+ MSGID_ERROR = 0,\r
+ MSGID_INFO,\r
+ MSGID_INVALID_DIR,\r
+ MSGID_NEW_DIR_FAIL,\r
+ MSGID_RENAME_VENTOY,\r
+ MSGID_INTERNAL_ERR,\r
+ MSGID_BTN_REFRESH,\r
+ MSGID_BTN_START,\r
+ MSGID_BTN_STOP,\r
+ MSGID_BTN_LINK,\r
+ MSGID_BTN_EXIT,\r
+\r
+ MSGID_BTN_STOP_TIP, \r
+ MSGID_BTN_EXIT_TIP,\r
+ MSGID_RUNNING_TIP,\r
+\r
+ MSGID_BUTT\r
+}MSGID;\r
+\r
+\r
+const WCHAR *g_msg_cn[MSGID_BUTT] =\r
+{\r
+ L"´íÎó",\r
+ L"ÌáÐÑ",\r
+ L"ÇëÔÚ Ventoy Å̸ùĿ¼ÏÂÔËÐб¾³ÌÐò£¡£¨´æ·ÅISOÎļþµÄλÖã©",\r
+ L"´´½¨ ventoy Ŀ¼ʧ°Ü£¬ÎÞ·¨¼ÌÐø£¡",\r
+ L"ventoy Ŀ¼´æÔÚ£¬µ«ÊÇ´óСд²»Æ¥Å䣬ÇëÏȽ«ÆäÖØÃüÃû£¡",\r
+ L"ÄÚ²¿´íÎ󣬳ÌÐò¼´½«Í˳ö£¡",\r
+ L"Ë¢ÐÂ",\r
+ L"Æô¶¯",\r
+ L"ֹͣ",\r
+ L"Á´½Ó",\r
+ L"Í˳ö",\r
+\r
+ L"Í£Ö¹ÔËÐкóä¯ÀÀÆ÷Ò³Ãæ½«»á¹Ø±Õ£¬ÊÇ·ñ¼ÌÐø£¿",\r
+ L"µ±Ç°·þÎñÕýÔÚÔËÐУ¬ÊÇ·ñÍ˳ö£¿",\r
+ L"ÇëÏȹرÕÕýÔÚÔËÐÐµÄ VentoyPlugson ³ÌÐò£¡",\r
+};\r
+const WCHAR *g_msg_en[MSGID_BUTT] =\r
+{\r
+ L"Error",\r
+ L"Info",\r
+ L"Please run me at the root of Ventoy partition.",\r
+ L"Failed to create ventoy directory!",\r
+ L"ventoy directory case mismatch, please rename it first!",\r
+ L"Internal error, the program will exit!",\r
+ L"Refresh",\r
+ L"Start",\r
+ L"Stop",\r
+ L"Link",\r
+ L"Exit",\r
+\r
+ L"The browser page will close after stop, continue?",\r
+ L"Service is running, continue?",\r
+ L"Please close another running VentoyPlugson instance!",\r
+};\r
+\r
+const WCHAR **g_msg_lang = NULL;\r
+\r
+HINSTANCE g_hInst;\r
+\r
+char g_log_file[MAX_PATH];\r
+char g_cur_dir[MAX_PATH];\r
+\r
+int ventoy_log_init(void);\r
+void ventoy_log_exit(void);\r
+\r
+static BOOL OnDestroyDialog()\r
+{ \r
+ ventoy_http_exit();
+ ventoy_disk_exit();\r
+#ifndef VENTOY_SIM \r
+ ventoy_www_exit();\r
+#endif\r
+ ventoy_log_exit();\r
+ return TRUE;\r
+}\r
+\r
+\r
+static void OpenURL(void)\r
+{\r
+ int i;\r
+ char url[128];\r
+ const static char * Browsers[] = \r
+ {\r
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",\r
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",\r
+ "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe",\r
+ "C:\\Program Files\\Mozilla Firefox\\firefox.exe",\r
+ NULL\r
+ };\r
+\r
+ sprintf_s(url, sizeof(url), "http://%s:%s/index.html", g_sysinfo.ip, g_sysinfo.port);\r
+\r
+ for (i = 0; Browsers[i] != NULL; i++)\r
+ {\r
+ if (ventoy_is_file_exist("%s", Browsers[i]))\r
+ {\r
+ ShellExecuteA(NULL, "open", Browsers[i], url, NULL, SW_SHOW);\r
+ return;\r
+ }\r
+ }\r
+\r
+ ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOW);\r
+}\r
+\r
+\r
+static void FillCombox(HWND hWnd)\r
+{\r
+ int i = 0;\r
+ int num = 0;\r
+ const ventoy_disk *list = NULL;\r
+ CHAR DeviceName[256];\r
+\r
+ // delete all items\r
+ SendMessage(g_ComboxHwnd, CB_RESETCONTENT, 0, 0);\r
+\r
+ list = ventoy_get_disk_list(&num);\r
+ if (NULL == list || num <= 0)\r
+ {\r
+ return;\r
+ }\r
+\r
+ for (i = 0; i < num; i++)\r
+ {\r
+ sprintf_s(DeviceName, sizeof(DeviceName),\r
+ "%C: [%s] %s",\r
+ list[i].devname[0],\r
+ list[i].cur_capacity,\r
+ list[i].cur_model);\r
+ SendMessageA(g_ComboxHwnd, CB_ADDSTRING, 0, (LPARAM)DeviceName);\r
+ }\r
+ SendMessage(g_ComboxHwnd, CB_SETCURSEL, 0, 0);\r
+}\r
+\r
+\r
+static BOOL InitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)\r
+{\r
+ HICON hIcon;\r
+\r
+ g_ComboxHwnd = GetDlgItem(hWnd, IDC_COMBO1);\r
+ g_refresh_button = GetDlgItem(hWnd, IDC_BUTTON1);\r
+ g_start_button = GetDlgItem(hWnd, IDC_BUTTON2);\r
+ g_openlink_button = GetDlgItem(hWnd, IDC_BUTTON3);\r
+ g_exit_button = GetDlgItem(hWnd, IDC_BUTTON4);\r
+ \r
+ hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ICON1));\r
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);\r
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);\r
+\r
+ SetWindowTextW(g_refresh_button, g_msg_lang[MSGID_BTN_REFRESH]);\r
+ SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_START]);\r
+ SetWindowTextW(g_openlink_button, g_msg_lang[MSGID_BTN_LINK]);\r
+ SetWindowTextW(g_exit_button, g_msg_lang[MSGID_BTN_EXIT]);\r
+\r
+ EnableWindow(g_openlink_button, FALSE);\r
+\r
+ FillCombox(hWnd);\r
+\r
+ return TRUE;\r
+}\r
+\r
+static void VentoyStopService()\r
+{\r
+ ventoy_http_stop();\r
+}\r
+\r
+static int VentoyStartService(int sel)\r
+{\r
+ int rc;\r
+ BOOL bRet;\r
+ char Path[128];\r
+ char CurDir[MAX_PATH];\r
+ const ventoy_disk *disk = NULL;\r
+\r
+ vlog("VentoyStartService ...\n");\r
+ \r
+ disk = ventoy_get_disk_node(sel);\r
+ if (disk == NULL)\r
+ {\r
+ return 1;\r
+ }\r
+\r
+ vlog("Start service at %C: %s %s ...\n", disk->devname[0], disk->cur_model, disk->cur_ventoy_ver);\r
+\r
+ g_cur_dir[0] = disk->devname[0];\r
+ g_cur_dir[1] = ':';\r
+ g_cur_dir[2] = '\\';\r
+ g_cur_dir[3] = 0;\r
+\r
+ g_sysinfo.pathcase = disk->pathcase;\r
+ g_sysinfo.cur_secureboot = disk->cur_secureboot;\r
+ g_sysinfo.cur_part_style = disk->cur_part_style;\r
+ strlcpy(g_sysinfo.cur_fsname, disk->cur_fsname);\r
+ strlcpy(g_sysinfo.cur_capacity, disk->cur_capacity);\r
+ strlcpy(g_sysinfo.cur_model, disk->cur_model);\r
+ strlcpy(g_sysinfo.cur_ventoy_ver, disk->cur_ventoy_ver);\r
+\r
+ bRet = SetCurrentDirectoryA(g_cur_dir);\r
+ vlog("SetCurrentDirectoryA %u <%s>\n", bRet, g_cur_dir);\r
+ \r
+ CurDir[0] = 0;\r
+ GetCurrentDirectoryA(sizeof(CurDir), CurDir);\r
+ vlog("CurDir=<%s>\n", CurDir);\r
+\r
+ if (strcmp(g_cur_dir, CurDir))\r
+ {\r
+ vlog("Failed to change current directory.");\r
+ }\r
+\r
+ g_cur_dir[2] = 0;\r
+\r
+ if (ventoy_is_directory_exist("ventoy"))\r
+ {\r
+ if (g_sysinfo.pathcase)\r
+ {\r
+ vlog("ventoy directory already exist, check case sensitive.\n");\r
+ strlcpy(Path, "ventoy");\r
+\r
+ rc = ventoy_path_case(Path, 0);\r
+ vlog("ventoy_path_case actual path is <%s> <count:%d>\n", Path, rc);\r
+\r
+ if (rc)\r
+ {\r
+ vlog("ventoy directory case mismatch, rename<%s>--><%s>\n", Path, "ventoy");\r
+ if (MoveFileA(Path, "ventoy"))\r
+ {\r
+ vlog("Rename <%s>--><%s> success\n", Path, "ventoy");\r
+ }\r
+ else\r
+ {\r
+ vlog("Rename <%s>--><%s> failed %u\n", Path, "ventoy", LASTERR);\r
+ MessageBoxW(NULL, g_msg_lang[MSGID_RENAME_VENTOY], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);\r
+ return 1;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ vlog("ventoy directory already exist, no need to check case sensitive.\n");\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (CreateDirectoryA("ventoy", NULL))\r
+ {\r
+ vlog("Create ventoy directory success.\n");\r
+ }\r
+ else\r
+ {\r
+ vlog("Create ventoy directory failed %u.\n", LASTERR);\r
+ MessageBoxW(NULL, g_msg_lang[MSGID_NEW_DIR_FAIL], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);\r
+ return 1;\r
+ }\r
+ }\r
+\r
+ return ventoy_http_start(g_sysinfo.ip, g_sysinfo.port);\r
+}\r
+\r
+INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)\r
+{\r
+ int rc;\r
+ int nCurSel;\r
+ WORD NotifyCode;\r
+ WORD CtrlID;\r
+\r
+ switch (Message)\r
+ {\r
+ case WM_NOTIFY:\r
+ {\r
+ UINT code = 0;\r
+ UINT_PTR idFrom = 0;\r
+\r
+ if (lParam)\r
+ {\r
+ code = ((LPNMHDR)lParam)->code;\r
+ idFrom = ((LPNMHDR)lParam)->idFrom;\r
+ }\r
+\r
+ if (idFrom == IDC_SYSLINK1 && (NM_CLICK == code || NM_RETURN == code))\r
+ {\r
+ OpenURL();\r
+ }\r
+ break;\r
+ }\r
+ case WM_COMMAND:\r
+ {\r
+ NotifyCode = HIWORD(wParam);\r
+ CtrlID = LOWORD(wParam);\r
+\r
+ if (NotifyCode == BN_CLICKED)\r
+ {\r
+ if (CtrlID == IDC_BUTTON1)\r
+ {\r
+ if (!g_running)\r
+ {\r
+ //refresh\r
+ ventoy_disk_exit();\r
+ ventoy_disk_init();\r
+ FillCombox(hWnd);\r
+ }\r
+ }\r
+ else if (CtrlID == IDC_BUTTON2)\r
+ {\r
+ if (g_running)\r
+ {\r
+ if (IDYES == MessageBoxW(NULL, g_msg_lang[MSGID_BTN_STOP_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))\r
+ {\r
+ VentoyStopService();\r
+\r
+ g_running = FALSE;\r
+ SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_START]);\r
+ EnableWindow(g_ComboxHwnd, TRUE);\r
+ EnableWindow(g_refresh_button, TRUE);\r
+ EnableWindow(g_openlink_button, FALSE);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ nCurSel = (int)SendMessage(g_ComboxHwnd, CB_GETCURSEL, 0, 0);\r
+ if (CB_ERR != nCurSel)\r
+ {\r
+ rc = VentoyStartService(nCurSel);\r
+ if (rc)\r
+ {\r
+ vlog("Ventoy failed to start http server, check %s for detail\n", g_log_file);\r
+ MessageBoxW(NULL, g_msg_lang[MSGID_INTERNAL_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);\r
+ }\r
+ else\r
+ {\r
+ g_running = TRUE;\r
+ SetWindowTextW(g_start_button, g_msg_lang[MSGID_BTN_STOP]);\r
+\r
+ EnableWindow(g_ComboxHwnd, FALSE);\r
+ EnableWindow(g_refresh_button, FALSE);\r
+ EnableWindow(g_openlink_button, TRUE);\r
+\r
+ OpenURL();\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else if (CtrlID == IDC_BUTTON3)\r
+ {\r
+ if (g_running)\r
+ {\r
+ OpenURL();\r
+ }\r
+ }\r
+ else if (CtrlID == IDC_BUTTON4)\r
+ {\r
+ if (g_running)\r
+ {\r
+ if (IDYES != MessageBoxW(NULL, g_msg_lang[MSGID_BTN_EXIT_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))\r
+ {\r
+ return 0;\r
+ }\r
+\r
+ ventoy_http_stop();\r
+ }\r
+\r
+ OnDestroyDialog();\r
+ EndDialog(hWnd, 0);\r
+ }\r
+ }\r
+ break;\r
+ }\r
+ case WM_INITDIALOG:\r
+ {\r
+ InitDialog(hWnd, wParam, lParam);\r
+ break;\r
+ } \r
+ case WM_CLOSE:\r
+ {\r
+ if (g_running)\r
+ {\r
+ if (IDYES != MessageBoxW(NULL, g_msg_lang[MSGID_BTN_EXIT_TIP], g_msg_lang[MSGID_INFO], MB_YESNO | MB_ICONINFORMATION))\r
+ {\r
+ return 0;\r
+ }\r
+\r
+ VentoyStopService();\r
+ }\r
+\r
+ OnDestroyDialog();\r
+ EndDialog(hWnd, 0);\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+static int ParseCmdLine(LPSTR lpCmdLine, char *ip, char *port)\r
+{\r
+ int portnum;\r
+ char *ipstart = ip; \r
+ char *pos;\r
+ \r
+\r
+ if (!lpCmdLine)\r
+ {\r
+ return 0;\r
+ }\r
+\r
+ pos = strstr(lpCmdLine, "-H");\r
+ if (!pos)\r
+ {\r
+ pos = strstr(lpCmdLine, "-h");\r
+ }\r
+\r
+ if (pos)\r
+ {\r
+ pos += 2;\r
+ while (*pos == ' ' || *pos == '\t')\r
+ {\r
+ pos++;\r
+ }\r
+\r
+ while (isdigit(*pos) || *pos == '.')\r
+ {\r
+ *ipstart++ = *pos++;\r
+ }\r
+ }\r
+\r
+\r
+ pos = strstr(lpCmdLine, "-P");\r
+ if (!pos)\r
+ {\r
+ pos = strstr(lpCmdLine, "-p");\r
+ }\r
+\r
+ if (pos)\r
+ {\r
+ portnum = (int)strtol(pos + 3, NULL, 10);\r
+ sprintf_s(port, 16, "%d", portnum);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)\r
+{\r
+ int rc;\r
+ HANDLE hMutex;\r
+\r
+ UNREFERENCED_PARAMETER(hPrevInstance);\r
+\r
+ if (GetUserDefaultUILanguage() == 0x0804)\r
+ {\r
+ g_sysinfo.language = LANGUAGE_CN;\r
+ g_msg_lang = g_msg_cn;\r
+ }\r
+ else\r
+ {\r
+ g_sysinfo.language = LANGUAGE_EN;\r
+ g_msg_lang = g_msg_en;\r
+ }\r
+\r
+ hMutex = CreateMutexA(NULL, TRUE, "PlugsonMUTEX");\r
+ if ((hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS))\r
+ {\r
+ MessageBoxW(NULL, g_msg_lang[MSGID_RUNNING_TIP], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);\r
+ return 1;\r
+ }\r
+\r
+ GetCurrentDirectoryA(MAX_PATH, g_cur_dir);\r
+ sprintf_s(g_log_file, sizeof(g_log_file), "%s\\%s", g_cur_dir, LOG_FILE);\r
+ ventoy_log_init();\r
+\r
+\r
+ ParseCmdLine(lpCmdLine, g_sysinfo.ip, g_sysinfo.port);\r
+ if (g_sysinfo.ip[0] == 0)\r
+ {\r
+ strlcpy(g_sysinfo.ip, "127.0.0.1");\r
+ }\r
+ if (g_sysinfo.port[0] == 0)\r
+ {\r
+ strlcpy(g_sysinfo.port, "24681");\r
+ }\r
+\r
+ vlog("===============================================\n");\r
+ vlog("===== Ventoy Plugson %s:%s =====\n", g_sysinfo.ip, g_sysinfo.port);\r
+ vlog("===============================================\n");\r
+\r
+\r
+ ventoy_disk_init();\r
+#ifndef VENTOY_SIM \r
+ rc = ventoy_www_init();\r
+ if (rc)\r
+ {\r
+ vlog("Failed to init www\n");\r
+ MessageBoxW(NULL, g_msg_lang[MSGID_INTERNAL_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);\r
+\r
+ ventoy_disk_exit();\r
+ ventoy_log_exit();\r
+ return 1;\r
+ }\r
+#endif\r
+ ventoy_http_init();\r
+\r
+ g_hInst = hInstance;\r
+ DialogBoxA(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);\r
+\r
+ return 0;\r
+}\r
+\r
--- /dev/null
+\r
+Microsoft Visual Studio Solution File, Format Version 12.00\r
+# Visual Studio 2013\r
+VisualStudioVersion = 12.0.21005.1\r
+MinimumVisualStudioVersion = 10.0.40219.1\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VentoyPlugson", "VentoyPlugson\VentoyPlugson.vcxproj", "{321D6EE2-2AB3-4103-9F05-EC4EC67A75E1}"\r
+EndProject\r
+Global\r
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+ Debug|Win32 = Debug|Win32\r
+ Release|Win32 = Release|Win32\r
+ EndGlobalSection\r
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+ {321D6EE2-2AB3-4103-9F05-EC4EC67A75E1}.Debug|Win32.ActiveCfg = Debug|Win32\r
+ {321D6EE2-2AB3-4103-9F05-EC4EC67A75E1}.Debug|Win32.Build.0 = Debug|Win32\r
+ {321D6EE2-2AB3-4103-9F05-EC4EC67A75E1}.Release|Win32.ActiveCfg = Release|Win32\r
+ {321D6EE2-2AB3-4103-9F05-EC4EC67A75E1}.Release|Win32.Build.0 = Release|Win32\r
+ EndGlobalSection\r
+ GlobalSection(SolutionProperties) = preSolution\r
+ HideSolutionNode = FALSE\r
+ EndGlobalSection\r
+EndGlobal\r
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+ <dependency> \r
+ <dependentAssembly> \r
+ <assemblyIdentity \r
+ type="win32" \r
+ name="Microsoft.Windows.Common-Controls" \r
+ version="6.0.0.0" \r
+ processorArchitecture="x86" \r
+ publicKeyToken="6595b64144ccf1df" \r
+ language="*" \r
+ /> \r
+ </dependentAssembly> \r
+ </dependency> \r
+ \r
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\r
+ <application>\r
+ <!-- Windows 10 -->\r
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\r
+ <!-- Windows 8.1 -->\r
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\r
+ <!-- Windows 8 -->\r
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\r
+ <!-- Windows 7 -->\r
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\r
+ <!-- Windows Vista -->\r
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> \r
+ </application>\r
+ </compatibility>\r
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">\r
+ <security>\r
+ <requestedPrivileges>\r
+ <requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel>\r
+ </requestedPrivileges>\r
+ </security>\r
+ </trustInfo> \r
+</assembly>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+ <dependency> \r
+ <dependentAssembly> \r
+ <assemblyIdentity \r
+ type="win32" \r
+ name="Microsoft.Windows.Common-Controls" \r
+ version="6.0.0.0" \r
+ processorArchitecture="amd64" \r
+ publicKeyToken="6595b64144ccf1df" \r
+ language="*" \r
+ /> \r
+ </dependentAssembly> \r
+ </dependency> \r
+ \r
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\r
+ <application>\r
+ <!-- Windows 10 -->\r
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\r
+ <!-- Windows 8.1 -->\r
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\r
+ <!-- Windows 8 -->\r
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\r
+ <!-- Windows 7 -->\r
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\r
+ <!-- Windows Vista -->\r
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> \r
+ </application>\r
+ </compatibility>\r
+ \r
+</assembly>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+ <dependency> \r
+ <dependentAssembly> \r
+ <assemblyIdentity \r
+ type="win32" \r
+ name="Microsoft.Windows.Common-Controls" \r
+ version="6.0.0.0" \r
+ processorArchitecture="arm" \r
+ publicKeyToken="6595b64144ccf1df" \r
+ language="*" \r
+ /> \r
+ </dependentAssembly> \r
+ </dependency> \r
+ \r
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\r
+ <application>\r
+ <!-- Windows 10 -->\r
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\r
+ <!-- Windows 8.1 -->\r
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\r
+ <!-- Windows 8 -->\r
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\r
+ <!-- Windows 7 -->\r
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\r
+ <!-- Windows Vista -->\r
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> \r
+ </application>\r
+ </compatibility>\r
+ \r
+</assembly>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\r
+ <dependency> \r
+ <dependentAssembly> \r
+ <assemblyIdentity \r
+ type="win32" \r
+ name="Microsoft.Windows.Common-Controls" \r
+ version="6.0.0.0" \r
+ processorArchitecture="arm64" \r
+ publicKeyToken="6595b64144ccf1df" \r
+ language="*" \r
+ /> \r
+ </dependentAssembly> \r
+ </dependency> \r
+ \r
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\r
+ <application>\r
+ <!-- Windows 10 -->\r
+ <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\r
+ <!-- Windows 8.1 -->\r
+ <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\r
+ <!-- Windows 8 -->\r
+ <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\r
+ <!-- Windows 7 -->\r
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\r
+ <!-- Windows Vista -->\r
+ <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/> \r
+ </application>\r
+ </compatibility>\r
+ \r
+</assembly>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <ItemGroup Label="ProjectConfigurations">\r
+ <ProjectConfiguration Include="Debug|Win32">\r
+ <Configuration>Debug</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ <ProjectConfiguration Include="Release|Win32">\r
+ <Configuration>Release</Configuration>\r
+ <Platform>Win32</Platform>\r
+ </ProjectConfiguration>\r
+ </ItemGroup>\r
+ <PropertyGroup Label="Globals">\r
+ <ProjectGuid>{321D6EE2-2AB3-4103-9F05-EC4EC67A75E1}</ProjectGuid>\r
+ <Keyword>Win32Proj</Keyword>\r
+ <RootNamespace>VentoyPlugson</RootNamespace>\r
+ </PropertyGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+ <ConfigurationType>Application</ConfigurationType>\r
+ <UseDebugLibraries>true</UseDebugLibraries>\r
+ <PlatformToolset>v120</PlatformToolset>\r
+ <CharacterSet>MultiByte</CharacterSet>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+ <ConfigurationType>Application</ConfigurationType>\r
+ <UseDebugLibraries>false</UseDebugLibraries>\r
+ <PlatformToolset>v120</PlatformToolset>\r
+ <WholeProgramOptimization>true</WholeProgramOptimization>\r
+ <CharacterSet>MultiByte</CharacterSet>\r
+ </PropertyGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+ <ImportGroup Label="ExtensionSettings">\r
+ </ImportGroup>\r
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+ </ImportGroup>\r
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+ </ImportGroup>\r
+ <PropertyGroup Label="UserMacros" />\r
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+ <LinkIncremental>true</LinkIncremental>\r
+ <IncludePath>..\..\..\src\Core;..\..\..\src\Web;..\..\..\src\Include;..\..\..\src\Lib\xz-embedded\linux\include;..\..\..\src\Lib\xz-embedded\linux\include\linux;..\..\..\src\Lib\xz-embedded\userspace;..\..\..\src\Lib\fat_io_lib;..\..\..\src\Lib\libhttp\include;$(ProjectDir);$(IncludePath)</IncludePath>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+ <LinkIncremental>false</LinkIncremental>\r
+ <IncludePath>..\..\..\src\Core;..\..\..\src\Web;..\..\..\src\Include;..\..\..\src\Lib\xz-embedded\linux\include;..\..\..\src\Lib\xz-embedded\linux\include\linux;..\..\..\src\Lib\xz-embedded\userspace;..\..\..\src\Lib\fat_io_lib;..\..\..\src\Lib\libhttp\include;$(ProjectDir);$(IncludePath);$(VC_IncludePath);$(WindowsSDK_IncludePath)</IncludePath>\r
+ </PropertyGroup>\r
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+ <ClCompile>\r
+ <PrecompiledHeader>\r
+ </PrecompiledHeader>\r
+ <WarningLevel>Level3</WarningLevel>\r
+ <Optimization>Disabled</Optimization>\r
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;INIT;STATIC=static;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <SDLCheck>true</SDLCheck>\r
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
+ </ClCompile>\r
+ <Link>\r
+ <SubSystem>Windows</SubSystem>\r
+ <GenerateDebugInformation>true</GenerateDebugInformation>\r
+ <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
+ </Link>\r
+ <Manifest>\r
+ <AdditionalManifestFiles>$(ProjectDir)\Res\Plugson32.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>\r
+ </Manifest>\r
+ </ItemDefinitionGroup>\r
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+ <ClCompile>\r
+ <WarningLevel>Level3</WarningLevel>\r
+ <PrecompiledHeader>\r
+ </PrecompiledHeader>\r
+ <Optimization>MaxSpeed</Optimization>\r
+ <FunctionLevelLinking>true</FunctionLevelLinking>\r
+ <IntrinsicFunctions>true</IntrinsicFunctions>\r
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;INIT;STATIC=static;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+ <SDLCheck>true</SDLCheck>\r
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
+ </ClCompile>\r
+ <Link>\r
+ <SubSystem>Windows</SubSystem>\r
+ <GenerateDebugInformation>true</GenerateDebugInformation>\r
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+ <OptimizeReferences>true</OptimizeReferences>\r
+ <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
+ </Link>\r
+ <Manifest>\r
+ <AdditionalManifestFiles>$(ProjectDir)\Res\Plugson32.manifest %(AdditionalManifestFiles)</AdditionalManifestFiles>\r
+ </Manifest>\r
+ </ItemDefinitionGroup>\r
+ <ItemGroup>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_crc32.c" />\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_disk.c" />\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_disk_windows.c" />\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_json.c" />\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_log.c" />\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_md5.c" />\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_util.c" />\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_util_windows.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_access.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_cache.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_filelib.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_format.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_misc.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_string.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_table.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_write.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\libhttp\include\civetweb.c" />\r
+ <ClCompile Include="..\..\..\src\Lib\xz-embedded\linux\lib\decompress_unxz.c" />\r
+ <ClCompile Include="..\..\..\src\main_windows.c" />\r
+ <ClCompile Include="..\..\..\src\Web\ventoy_http.c" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClInclude Include="..\..\..\src\Core\ventoy_define.h" />\r
+ <ClInclude Include="..\..\..\src\Core\ventoy_disk.h" />\r
+ <ClInclude Include="..\..\..\src\Core\ventoy_json.h" />\r
+ <ClInclude Include="..\..\..\src\Core\ventoy_util.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_access.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_cache.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_defs.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_filelib.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_format.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_list.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_misc.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_opts.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_string.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_table.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_types.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_write.h" />\r
+ <ClInclude Include="..\..\..\src\Lib\libhttp\include\civetweb.h" />\r
+ <ClInclude Include="..\..\..\src\Web\ventoy_http.h" />\r
+ <ClInclude Include="resource.h" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\API.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\Configuration.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\COPYRIGHT.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\History.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\License.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\Media Access API.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\version.txt" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <None Include="..\..\..\src\Lib\libhttp\include\handle_form.inl" />\r
+ <None Include="..\..\..\src\Lib\libhttp\include\md5.inl" />\r
+ <None Include="..\..\..\src\Lib\libhttp\include\mod_duktape.inl" />\r
+ <None Include="..\..\..\src\Lib\libhttp\include\mod_lua.inl" />\r
+ <None Include="..\..\..\src\Lib\libhttp\include\timer.inl" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ResourceCompile Include="VentoyPlugson.rc" />\r
+ </ItemGroup>\r
+ <ItemGroup> \r
+ <Image Include="Res\plugson.ico" />\r
+ </ItemGroup>\r
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+ <ImportGroup Label="ExtensionTargets">\r
+ </ImportGroup>\r
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <ItemGroup>\r
+ <Filter Include="源文件">\r
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
+ </Filter>\r
+ <Filter Include="头文件">\r
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
+ <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
+ </Filter>\r
+ <Filter Include="资源文件">\r
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\r
+ </Filter>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_crc32.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_disk.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_disk_windows.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_json.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_log.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_md5.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_util.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Core\ventoy_util_windows.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_access.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_cache.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_filelib.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_format.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_misc.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_string.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_table.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\fat_io_lib\fat_write.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\libhttp\include\civetweb.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Web\ventoy_http.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\Lib\xz-embedded\linux\lib\decompress_unxz.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ <ClCompile Include="..\..\..\src\main_windows.c">\r
+ <Filter>源文件</Filter>\r
+ </ClCompile>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ClInclude Include="..\..\..\src\Core\ventoy_define.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Core\ventoy_disk.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Core\ventoy_json.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Core\ventoy_util.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_access.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_cache.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_defs.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_filelib.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_format.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_list.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_misc.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_opts.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_string.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_table.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_types.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\fat_io_lib\fat_write.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Lib\libhttp\include\civetweb.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="..\..\..\src\Web\ventoy_http.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ <ClInclude Include="resource.h">\r
+ <Filter>头文件</Filter>\r
+ </ClInclude>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\API.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\Configuration.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\COPYRIGHT.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\History.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\License.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\Media Access API.txt" />\r
+ <Text Include="..\..\..\src\Lib\fat_io_lib\version.txt" />\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <None Include="..\..\..\src\Lib\libhttp\include\handle_form.inl">\r
+ <Filter>头文件</Filter>\r
+ </None>\r
+ <None Include="..\..\..\src\Lib\libhttp\include\md5.inl">\r
+ <Filter>头文件</Filter>\r
+ </None>\r
+ <None Include="..\..\..\src\Lib\libhttp\include\mod_duktape.inl">\r
+ <Filter>头文件</Filter>\r
+ </None>\r
+ <None Include="..\..\..\src\Lib\libhttp\include\mod_lua.inl">\r
+ <Filter>头文件</Filter>\r
+ </None>\r
+ <None Include="..\..\..\src\Lib\libhttp\include\timer.inl">\r
+ <Filter>头文件</Filter>\r
+ </None>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <ResourceCompile Include="VentoyPlugson.rc">\r
+ <Filter>资源文件</Filter>\r
+ </ResourceCompile>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <Image Include="Res\refresh.ico">\r
+ <Filter>资源文件</Filter>\r
+ </Image>\r
+ </ItemGroup>\r
+</Project>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+ <LocalDebuggerWorkingDirectory>E:\</LocalDebuggerWorkingDirectory>\r
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\r
+ <LocalDebuggerCommandArguments>\r
+ </LocalDebuggerCommandArguments>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+ <LocalDebuggerWorkingDirectory>E:\</LocalDebuggerWorkingDirectory>\r
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\r
+ </PropertyGroup>\r
+</Project>
\ No newline at end of file
--- /dev/null
+20211201 20:08:18
\ No newline at end of file
--- /dev/null
+<html>\r
+<head>\r
+ <meta charset="utf-8">\r
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">\r
+ <!-- HTTP 1.1 --> \r
+ <meta http-equiv="pragma" content="no-cache"> \r
+ <!-- HTTP 1.0 --> \r
+ <meta http-equiv="cache-control" content="no-cache"> \r
+ <title>Ventoy Plugson</title>\r
+ <!-- Tell the browser to be responsive to screen width -->\r
+ <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">\r
+ <!-- Bootstrap 3.3.5 -->\r
+ <link rel="stylesheet" href="static/bootstrap/css/bootstrap.min.css">\r
+ <!-- Font Awesome -->\r
+ <link rel="stylesheet" href="static/css/font-awesome.min.css">\r
+ <!-- Ionicons -->\r
+ <link rel="stylesheet" href="static/css/ionicons.min.css">\r
+ <!-- Theme style -->\r
+ <link rel="stylesheet" href="static/AdminLTE/css/AdminLTE.min.css">\r
+ <!-- AdminLTE Skins. Choose a skin from the css/skins\r
+ folder instead of downloading all of them to reduce the load. -->\r
+ <link rel="stylesheet" href="static/AdminLTE/css/skins/skin-blue.min.css">\r
+ <link rel="stylesheet" href="static/datatables/dataTables.bootstrap.css">\r
+ <link rel="stylesheet" href="static/css/vtoy.css">\r
+ \r
+ <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->\r
+ <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->\r
+ <!--[if lt IE 9]>\r
+ <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>\r
+ <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>\r
+ <![endif]-->\r
+ <style type="text/css">\r
+ * {\r
+ font-family: 'Arial','Microsoft YaHei','黑体','宋体',sans-serif;\r
+ }\r
+ .modal {\r
+ padding-top: 80px;\r
+ }\r
+ .treeview-menu a {\r
+ margin-left: 20px;\r
+ }\r
+ </style>\r
+</head>\r
+\r
+<body class="sidebar-mini skin-blue">\r
+ <div class="wrapper">\r
+\r
+ <header class="main-header" style="position: fixed; right: 0; left: 0;">\r
+ <!-- Logo -->\r
+ <a href="." class="logo">\r
+ <!-- logo for regular state and mobile devices --> \r
+ <span class="logo-lg" > <img src="/static/img/logo_32.png" > Ventoy Plugson</span>\r
+ </a>\r
+ <!-- Header Navbar: style can be found in header.less -->\r
+ <nav class="navbar navbar-static-top" role="navigation">\r
+ <!-- Navbar Right Menu -->\r
+ \r
+ <div class="navbar-custom-menu">\r
+ <ul class="nav navbar-nav">\r
+ <li class="dropdown user user-menu">\r
+ <a href="javascript:void(0)" id="id_a_language">\r
+ <span class="fa fa-language"></span> \r
+ <span id="id_span_language" class="hidden-xs">English</span>\r
+ <span class="hidden-xs"> </span>\r
+ </a> \r
+ </li>\r
+\r
+ <li class="dropdown user user-menu">\r
+ <a id="id_top_donation" href="#plugson_donation" data-href="#plugson_donation">\r
+ <span class="fa fa-paypal"></span> \r
+ <span id="id_span_donation" class="hidden-xs">捐助</span>\r
+ </a> \r
+ </li>\r
+\r
+ <!-- User Account: style can be found in dropdown.less -->\r
+ <li class="dropdown user user-menu">\r
+ <a href="https://www.ventoy.net" target="_blank" >\r
+ <span class="fa fa-link"></span> \r
+ <span class="hidden-xs">Ventoy</span>\r
+ </a> \r
+ </li>\r
+ </ul>\r
+ </div>\r
+ \r
+ \r
+ </nav>\r
+ </header>\r
+ <!-- Left side column. contains the logo and sidebar -->\r
+ <aside class="main-sidebar" style="position:fixed;">\r
+ <!-- sidebar: style can be found in sidebar.less -->\r
+ <section class="sidebar" style="height: auto;" id="plugson-menu">\r
+ <!-- 菜单 -->\r
+ <ul class="sidebar-menu">\r
+ <li>\r
+ <a href="#plugson_main" data-href="#plugson_main">\r
+ <i class="fa fa-bank"></i> <span id="id_span_menu_device">设备信息</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_control" data-href="#plugson_control">\r
+ <i class="fa fa-wrench"></i> <span id="id_span_menu_control">全局控制插件</span>\r
+ </a>\r
+ </li> \r
+ <li>\r
+ <a href="#plugson_theme" data-href="#plugson_theme">\r
+ <i class="fa fa-file-image-o"></i> <span id="id_span_menu_theme">主题插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_menu_alias" data-href="#plugson_menu_alias">\r
+ <i class="fa fa-clone"></i> <span id="id_span_menu_alias">菜单别名插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_menu_tip" data-href="#plugson_menu_tip">\r
+ <i class="fa fa-commenting"></i> <span id="id_span_menu_tip">菜单提示插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_menu_class" data-href="#plugson_menu_class">\r
+ <i class="fa fa-list-ul"></i> <span id="id_span_menu_class">菜单类型插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_auto_install" data-href="#plugson_auto_install">\r
+ <i class="fa fa-desktop"></i> <span id="id_span_menu_auto_install">自动安装插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_persistence" data-href="#plugson_persistence">\r
+ <i class="fa fa-database"></i> <span id="id_span_menu_persistence">数据持久化插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_injection" data-href="#plugson_injection">\r
+ <i class="fa fa-plus-circle"></i> <span id="id_span_menu_injection">文件注入插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_conf_replace" data-href="#plugson_conf_replace">\r
+ <i class="fa fa-retweet"></i> <span id="id_span_menu_conf_replace">启动配置替换插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_password" data-href="#plugson_password">\r
+ <i class="glyphicon glyphicon-lock"></i> <span id="id_span_menu_password">密码插件</span>\r
+ </a>\r
+ </li>\r
+ \r
+ <li>\r
+ <a href="#plugson_image_list" data-href="#plugson_image_list">\r
+ <i class="fa fa-list-alt"></i> <span id="id_span_menu_imagelist">文件列表插件</span>\r
+ </a>\r
+ </li>\r
+ \r
+ <li>\r
+ <a href="#plugson_auto_memdisk" data-href="#plugson_auto_memdisk">\r
+ <i class="fa fa-floppy-o"></i> <span id="id_span_menu_auto_memdisk">自动 Memdisk 插件</span>\r
+ </a>\r
+ </li>\r
+ <li>\r
+ <a href="#plugson_dud" data-href="#plugson_dud">\r
+ <i class="glyphicon glyphicon-cd"></i> <span id="id_span_menu_dud">Driver Update Disk 插件</span>\r
+ </a>\r
+ </li>\r
+ </ul>\r
+ </section>\r
+ <!-- /.sidebar -->\r
+ </aside>\r
+\r
+\r
+ <div class="modal" id="SetPwdModal">\r
+ <div class="modal-dialog" style="width: 800px;">\r
+ <div class="modal-content">\r
+ <form id="SetPwdForm" class="form-horizontal">\r
+ <div class="modal-header">\r
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">\r
+ <span aria-hidden="true">×</span>\r
+ </button>\r
+ <h4><b id="SetPwdForm_title"></b> </h4>\r
+ </div>\r
+ <div class="modal-body">\r
+\r
+ <div id="id_div_pwd_path">\r
+ <div class="form-group">\r
+ <div class="col-sm-3">\r
+ <label id="SetPwdForm_path" class="control-label"></label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="PwdPath" name="PwdPath" />\r
+ </div> \r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_pwdfile_cn">\r
+ <div class="col-sm-3"></div>\r
+ <div class="col-sm-9">\r
+ 请输入文件在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_pwdfile_tip1" style="color:red;"></span><br/>\r
+ <span id="id_span_pwdfile_tip2" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_pwdfile_en">\r
+ <div class="col-sm-3"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_pwdfile_tip1" style="color:red;"></span><br/>\r
+ <span id="id_span_pwdfile_tip2" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_pwddir_cn">\r
+ <div class="col-sm-3"></div>\r
+ <div class="col-sm-9">\r
+ 请输入文件夹在当前系统中的全路径(注意是完整的绝对路径),例如:<br/>\r
+ <span id="id_span_pwddir_tip" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_pwddir_en">\r
+ <div class="col-sm-3"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute directory path. For example: <br/>\r
+ <span id="id_span_pwddir_tip" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ </div>\r
+ <div class="form-group">\r
+ <div class="col-sm-3">\r
+ <label id="SetPwdForm_pwd" class="control-label">xx</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="PwdPwd" name="PwdPwd" />\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group">\r
+ <div class="col-sm-3">\r
+ <label id="SetPwdForm_type" class="control-label">xx</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_radio_pwd_type0" name="id_radio_pwd_type" selected="selected" data-type="0" value="0"/> <span style="font-weight:bold;">TXT</span>\r
+ </label>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_radio_pwd_type1" name="id_radio_pwd_type" data-type="1" value="1"/> <span style="font-weight:bold;">MD5</span>\r
+ </label>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_radio_pwd_type2" name="id_radio_pwd_type" data-type="2" value="2"/> <span style="font-weight:bold;">Salt MD5</span>\r
+ </label>\r
+ </div>\r
+ </div>\r
+ </div>\r
+ <div class="modal-footer">\r
+ <button id="SetPwdForm_ok" type="submit" class="btn btn-primary btn-flat">确定</button>\r
+ <button id="SetPwdForm_cancel" type="button" class="btn btn-default btn-flat" data-dismiss="modal">取消</button>\r
+ </div>\r
+ </form>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+\r
+\r
+ <div class="modal" id="SetFileModal">\r
+ <div class="modal-dialog" style="width: 800px;">\r
+ <div class="modal-content">\r
+ <form id="SetFileForm" class="form-horizontal">\r
+ <div class="modal-header">\r
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">\r
+ <span aria-hidden="true">×</span>\r
+ </button>\r
+ <h4><b id="SetFileForm_lang_1">设置文件路径</b> </h4>\r
+ </div>\r
+ <div class="modal-body">\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="SetFileForm_lang_2" class="control-label">文件路径</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="FilePath" name="FilePath" />\r
+ </div> \r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_setfile_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入文件在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_filepath_tip1" style="color:red;"></span><br/>\r
+ <span id="id_span_filepath_tip2" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_setfile_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_filepath_tip1" style="color:red;"></span><br/>\r
+ <span id="id_span_filepath_tip2" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group" id="id_div_file_extra">\r
+ <div class="col-sm-2">\r
+ <label id="SetFileForm_extra" class="control-label">xx</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="FileExtra" name="FileExtra" />\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group" id="id_note_tip3_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入对应文件在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_filepath_tip3" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_tip3_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_filepath_tip3" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ \r
+ </div>\r
+ <div class="modal-footer">\r
+ <button id="SetFileForm_lang_3" type="submit" class="btn btn-primary btn-flat">确定</button>\r
+ <button id="SetFileForm_lang_4" type="button" class="btn btn-default btn-flat" data-dismiss="modal">取消</button>\r
+ </div>\r
+ </form>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+\r
+ <div class="modal" id="SetFileFileModal">\r
+ <div class="modal-dialog" style="width: 800px;">\r
+ <div class="modal-content">\r
+ <form id="SetFileFileForm" class="form-horizontal">\r
+ <div class="modal-header">\r
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">\r
+ <span aria-hidden="true">×</span>\r
+ </button>\r
+ <h4><b id="SetFileFileForm_title">x</b> </h4>\r
+ </div>\r
+ <div class="modal-body">\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="SetFileFileForm_label1" class="control-label">x</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="FileFilePath1" name="FileFilePath1" />\r
+ </div> \r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_filefile_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入文件在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_filefile_tip1" style="color:red;"></span><br/>\r
+ <span id="id_span_filefile_tip2" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_filefile_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_filefile_tip1" style="color:red;"></span><br/>\r
+ <span id="id_span_filefile_tip2" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="SetFileFileForm_label2" class="control-label">xx</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="FileFilePath2" name="FileFilePath2" />\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group" id="id_note_filefile_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入对应文件在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_filefile_tip3" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_filefile_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_filefile_tip3" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ \r
+ </div>\r
+ <div class="modal-footer">\r
+ <button id="SetFileFileForm_ok" type="submit" class="btn btn-primary btn-flat">确定</button>\r
+ <button id="SetFileFileForm_cancel" type="button" class="btn btn-default btn-flat" data-dismiss="modal">取消</button>\r
+ </div>\r
+ </form>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+\r
+ <div class="modal" id="SetDirFileModal">\r
+ <div class="modal-dialog" style="width: 800px;">\r
+ <div class="modal-content">\r
+ <form id="SetDirFileForm" class="form-horizontal">\r
+ <div class="modal-header">\r
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">\r
+ <span aria-hidden="true">×</span>\r
+ </button>\r
+ <h4><b id="SetDirFileForm_title">x</b> </h4>\r
+ </div>\r
+ <div class="modal-body">\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="SetDirFileForm_label1" class="control-label">x</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="DirFilePath1" name="DirFilePath1" />\r
+ </div> \r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_dirfile_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入对应目录在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_dirfile_tip1" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_dirfile_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute directory path. For example:<br/> \r
+ <span id="id_span_dirfile_tip1" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="SetDirFileForm_label2" class="control-label">xx</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="DirFilePath2" name="DirFilePath2" />\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group" id="id_note_dirfile_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入对应文件在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_dirfile_tip2" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_dirfile_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_dirfile_tip2" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ \r
+ </div>\r
+ <div class="modal-footer">\r
+ <button id="SetDirFileForm_ok" type="submit" class="btn btn-primary btn-flat">确定</button>\r
+ <button id="SetDirFileForm_cancel" type="button" class="btn btn-default btn-flat" data-dismiss="modal">取消</button>\r
+ </div>\r
+ </form>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+\r
+\r
+ <div class="modal" id="ConfReplaceModal">\r
+ <div class="modal-dialog" style="width: 800px;">\r
+ <div class="modal-content">\r
+ <form id="ConfReplaceForm" class="form-horizontal">\r
+ <div class="modal-header">\r
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">\r
+ <span aria-hidden="true">×</span>\r
+ </button>\r
+ <h4><b>Boot Conf Replace</b> </h4>\r
+ </div>\r
+ <div class="modal-body">\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="ConfReplaceForm_lang_1" class="control-label">文件路径</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="IsoPath" name="IsoPath" />\r
+ </div> \r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_conf_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入文件在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_conf_tip1" style="color:red;"></span><br/>\r
+ <span id="id_span_conf_tip2" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_conf_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_conf_tip1" style="color:red;"></span><br/>\r
+ <span id="id_span_conf_tip2" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label class="control-label">org</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="OrgPath" name="OrgPath" />\r
+ </div> \r
+ </div>\r
+ <div class="form-group" id="id_note_conf_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 要替换的文件在 ISO 内的路径(以 / 开头),例如:\r
+ <span style="color:red;">/boot/grub/grub.cfg</span>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_conf_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ The original file path inside the ISO (start with /), for example:\r
+ <span style="color:red;">/boot/grub/grub.cfg</span>\r
+ </div>\r
+ </div>\r
+\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label class="control-label">new</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="NewPath" name="NewPath" />\r
+ </div> \r
+ </div>\r
+ <div class="form-group" id="id_note_conf_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 新文件在当前系统中的全路径(注意是完整的绝对路径)例如:<br/> \r
+ <span id="id_span_conf_tip3" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_conf_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_conf_tip3" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+\r
+ </div>\r
+ <div class="modal-footer">\r
+ <button id="ConfReplaceForm_lang_2" type="submit" class="btn btn-primary btn-flat">确定</button>\r
+ <button id="ConfReplaceForm_lang_3" type="button" class="btn btn-default btn-flat" data-dismiss="modal">取消</button>\r
+ </div>\r
+ </form>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+ \r
+ <div class="modal" id="SetDirModal">\r
+ <div class="modal-dialog" style="width: 800px;">\r
+ <div class="modal-content">\r
+ <form id="SetDirForm" class="form-horizontal">\r
+ <div class="modal-header">\r
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">\r
+ <span aria-hidden="true">×</span>\r
+ </button>\r
+ <h4><b id="SetDirForm_lang_1">设置文件夹路径</b> </h4>\r
+ </div>\r
+ <div class="modal-body">\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="SetDirForm_lang_2" class="control-label">文件夹路径</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="DirPath" name="DirPath" />\r
+ </div> \r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_setfile_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入文件夹在当前系统中的全路径(注意是完整的绝对路径),例如:<br/>\r
+ <span id="id_span_dirpath_tip" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ \r
+ <div class="form-group" id="id_note_setfile_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute directory path. For example: <br/>\r
+ <span id="id_span_dirpath_tip" style="color:red;"></span>\r
+ </div>\r
+ </div>\r
+ \r
+ <div class="form-group" id="id_div_dir_extra">\r
+ <div class="col-sm-2">\r
+ <label id="SetDirForm_extra" class="control-label">xx</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="DirExtra" name="DirExtra" />\r
+ </div> \r
+ </div>\r
+\r
+ <div class="form-group" id="id_note_tip3_cn">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ 请输入对应文件在当前系统中的全路径(注意是完整的绝对路径),例如:<br/> \r
+ <span id="id_span_dirpath_tip3" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+ <div class="form-group" id="id_note_tip3_en">\r
+ <div class="col-sm-2"></div>\r
+ <div class="col-sm-9">\r
+ Please input the full absolute file path. For example:<br/> \r
+ <span id="id_span_dirpath_tip3" style="color:red;"></span><br/>\r
+ </div>\r
+ </div>\r
+\r
+ </div>\r
+ <div class="modal-footer">\r
+ <button id="SetDirForm_lang_3" type="submit" class="btn btn-primary btn-flat">确定</button>\r
+ <button id="SetDirForm_lang_4" type="button" class="btn btn-default btn-flat" data-dismiss="modal">取消</button>\r
+ </div>\r
+ </form>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+\r
+ <div class="modal" id="SetKeyModal">\r
+ <div class="modal-dialog" style="width: 800px;">\r
+ <div class="modal-content">\r
+ <form id="SetKeyForm" class="form-horizontal">\r
+ <div class="modal-header">\r
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">\r
+ <span aria-hidden="true">×</span>\r
+ </button>\r
+ <h4><b id="SetKeyForm_lang_1">xx</b> </h4>\r
+ </div>\r
+ <div class="modal-body">\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="SetKeyForm_lang_2" class="control-label">关键字</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="SetKeyKey" name="SetKeyKey" />\r
+ </div>\r
+ </div>\r
+ <div class="form-group">\r
+ <div class="col-sm-2">\r
+ <label id="SetKeyForm_lang_3" class="control-label">菜单类型</label>\r
+ </div>\r
+ <div class="col-sm-9">\r
+ <input type="text" class="form-control" id="SetKeyValue" name="SetKeyValue" />\r
+ </div> \r
+ </div>\r
+ </div>\r
+ <div class="modal-footer">\r
+ <button id="SetKeyForm_lang_4" type="submit" class="btn btn-primary btn-flat">确定</button>\r
+ <button id="SetKeyForm_lang_5" type="button" class="btn btn-default btn-flat" data-dismiss="modal">取消</button>\r
+ </div>\r
+ </form>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+ <div class="modal" id="TypeSelectModal">\r
+ <div class="modal-dialog" style="width: 800px;">\r
+ <div class="modal-content">\r
+ <form id="TypeSelectForm" class="form-horizontal">\r
+ <div class="modal-header">\r
+ <button type="button" class="close" data-dismiss="modal" aria-label="Close">\r
+ <span aria-hidden="true">×</span>\r
+ </button>\r
+ <h4><b id="TypeSelForm_lang_1">请选择</b> </h4>\r
+ </div>\r
+ <div class="modal-body">\r
+ <div class="form-group">\r
+ <div class="col-sm-1"></div>\r
+ <div class="col-sm-10">\r
+ <table id="id_type_select_table" class="table" rules=none>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+ <div class="col-sm-1"></div>\r
+ </div>\r
+ </div>\r
+ <div class="modal-footer">\r
+ <button id="TypeSelForm_lang_2" type="submit" class="btn btn-primary btn-flat">确定</button>\r
+ <button id="TypeSelForm_lang_3" type="button" class="btn btn-default btn-flat" data-dismiss="modal">取消</button>\r
+ </div>\r
+ </form>\r
+ </div>\r
+ </div>\r
+ </div>\r
+\r
+\r
+ <!-- Content Wrapper. Contains page content -->\r
+ <div class="content-wrapper clearfix" style="min-height: 385px; margin-top: 50px;">\r
+ <!-- Main content -->\r
+ <section class="content" id="plugson-content">\r
+ </section>\r
+ <!-- /.content -->\r
+ </div>\r
+ <!-- /.content-wrapper -->\r
+\r
+ <footer class="main-footer">\r
+ <div class="pull-right hidden-xs">\r
+ <b id="plugson_build_date">20211201 20:08:18</b>
+ </div>\r
+ <strong><a href="https://www.ventoy.net" target="_blank">https://www.ventoy.net</a></strong>\r
+ </footer>\r
+\r
+ <!-- Control Sidebar -->\r
+ <!-- /.control-sidebar -->\r
+ <!-- Add the sidebar's background. This div must be placed\r
+ immediately after the control sidebar -->\r
+ <div class="control-sidebar-bg" style="position: fixed; height: auto;"></div>\r
+\r
+ </div>\r
+ <!-- ./wrapper -->\r
+\r
+ \r
+\r
+ <!-- jQuery 2.1.4 -->\r
+ <script src="/static/js/jQuery-2.1.4.min.js"></script>\r
+ <!-- jquery validate -->\r
+ <script src="/static/js/jquery.validate.min.js"></script> \r
+ <script src="/static/js/jquery.validate.vtoymethods.js"></script>\r
+\r
+ <script src="/static/js/vtoy.js"></script>\r
+ <script src="/static/js/jquery.vtoy.alert.js"></script>\r
+ <script src="/static/js/md5.min.js"></script>\r
+\r
+ <!-- Bootstrap 3.3.5 -->\r
+ <script src="/static/bootstrap/js/bootstrap.min.js"></script>\r
+ <!-- AdminLTE App -->\r
+ <script src="/static/AdminLTE/js/app.min.js"></script>\r
+ <script src="/static/AdminLTE/plugins/chartjs/Chart.min.js"></script>\r
+ \r
+ <script src="/static/datatables/jquery.dataTables.min.js"></script>\r
+ <script src="/static/datatables/dataTables.bootstrap.min.js"></script>\r
+ \r
+ <script type="text/javascript">\r
+\r
+ function VtoyLanguageClick() {\r
+ var defaultPage = window.location.hash;\r
+ \r
+ if (g_current_language === 'cn') {\r
+ g_current_language = 'en';\r
+ } else {\r
+ g_current_language = 'cn';\r
+ }\r
+\r
+ if (typeof(VtoyPageLanguageChange)==='function') {\r
+ VtoyPageLanguageChange(g_current_language);\r
+ }\r
+ }\r
+\r
+\r
+ //Main process\r
+ var m_syntax_error;\r
+ callVtoySync({\r
+ method : 'sysinfo'\r
+ }, function(data) {\r
+ g_current_language = data.language;\r
+ g_current_dir = data.curdir;\r
+ g_current_os = data.os;\r
+ m_syntax_error = data.syntax_error;\r
+\r
+ \r
+\r
+ });\r
+ \r
+ $('#id_a_language').click(VtoyLanguageClick);\r
+ \r
+ $("#plugson-menu a").click(function() {\r
+ var href = $(this).data("href");\r
+ if (href && href !== '#') {\r
+ loadContent(href.substring(1));\r
+ }\r
+ });\r
+\r
+ $('#id_top_donation').click(function() {\r
+ var href = $(this).data("href");\r
+ if (href && href !== '#') {\r
+ loadContent(href.substring(1));\r
+ }\r
+ });\r
+ \r
+ (function openDefaultPage() {\r
+ var defaultPage = window.location.hash;\r
+ if (defaultPage) {\r
+ defaultPage = defaultPage.substring(1, defaultPage.length);\r
+ }\r
+ defaultPage = defaultPage || 'plugson_main';\r
+ loadContent(defaultPage);\r
+ })();\r
+ \r
+\r
+ (function ventoy_handshake() {\r
+\r
+ if (m_syntax_error === 1) {\r
+ \r
+ }\r
+\r
+ callVtoyCatchErr({\r
+ method : 'handshake'\r
+ }, \r
+ function(data) { \r
+ \r
+ if (m_syntax_error === 1 && typeof(Modal) === 'object') {\r
+ var title = g_current_language == 'en' ? g_vtoy_cur_language_en.STR_INFO : g_vtoy_cur_language_cn.STR_INFO;\r
+ var msg = g_current_language == 'en' ? g_vtoy_cur_language_en.STR_SYNTAX_ERROR_TIP : g_vtoy_cur_language_cn.STR_SYNTAX_ERROR_TIP;\r
+ Modal.alert({title:title,msg:msg}).on(function(e) {\r
+ });\r
+ m_syntax_error = 0;\r
+ }\r
+\r
+ setTimeout(function() {\r
+ ventoy_handshake();\r
+ }, 1000);\r
+ },\r
+\r
+ function(xmlHttpRequest, textStatus, errorThrown) {\r
+ if (undefined === errorThrown)\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_REMOTE_ABNORMAL);\r
+ }\r
+ else if(undefined === errorThrown.length)\r
+ {\r
+ \r
+ }\r
+ else if('' == errorThrown.trim())\r
+ {\r
+ }\r
+ else\r
+ {\r
+ switch(errorThrown)\r
+ {\r
+ case 'timeout':\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_REQUEST_TIMEOUT);\r
+ break;\r
+ }\r
+ case 'Service Unavailable':\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_SERVICE_UNAVAILABLE);\r
+ break;\r
+ }\r
+ case 'abort':\r
+ {\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_COMMUNICATION_ERR + errorThrown);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ Modal.confirm({msg:g_vtoy_cur_language.STR_CLOSE_TIP}).on(function(e) {\r
+ if(navigator.userAgent.indexOf("Firefox") != -1 || navigator.userAgent.indexOf("Chrome") != -1){\r
+ window.location.href = "about:blank";\r
+ window.close();\r
+ }else{\r
+ window.opener = null;\r
+ window.open("", "_self");\r
+ window.close();\r
+ }\r
+ });\r
+ });\r
+ })();\r
+\r
+\r
+ </script>\r
+</body>\r
+\r
+</html>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-desktop"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">x</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_autoinstall.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_autoins">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >auto_install</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_install_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_install_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_install_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_install_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_install_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <table id="id_autoins_tbl" class="table table-bordered" >\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 5%;">#</th>\r
+ <th id="id_th_autoins_set" style="width: 80%;"></th>\r
+ <th id="id_th_operation" style="width: 10%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_AUTO_INSTALL);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ $("span[id=id_span_dir_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_EXIST);\r
+ });\r
+ \r
+ $("span[id=id_span_dir_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_NONEXIST);\r
+ });\r
+\r
+ $("th[id=id_th_template]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_AUTO_TEMPLATE);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_autoins_path').text('Absolute Path');\r
+ $('#id_th_autoins_set').text('Setting');\r
+ } else {\r
+ $('#id_th_autoins_path').text('绝对路径');\r
+ $('#id_th_autoins_set').text('设置');\r
+ \r
+ }\r
+ }\r
+ \r
+ function VtoySaveCurrentPage(index) {\r
+\r
+ var timeoutval = 0;\r
+ var autoselval = 1;\r
+\r
+ var timeouten = $('#id_timeout_en_' + index).is(':checked');\r
+ var autoselen = $('#id_autosel_en_' + index).is(':checked');\r
+\r
+ if (timeouten) {\r
+ timeoutval = parseInt($('#id_text_timeout_' + index).val());\r
+ }\r
+\r
+ if (autoselen) {\r
+ autoselval = parseInt($('#id_text_autosel_' + index).val());\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'save_auto_install',\r
+ index: current_tab_index,\r
+ id: index,\r
+ timeout: timeoutval,\r
+ autosel: autoselval,\r
+ timeouten: timeouten,\r
+ autoselen: autoselen\r
+ }, function(e) {\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnInputTextChange() {\r
+ var id = $(this).attr('id');\r
+ var value = $(this).val();\r
+ var intval;\r
+ \r
+ if (id.length <= 16) {\r
+ return;\r
+ }\r
+\r
+ var index = parseInt(id.substr(16));\r
+ var data = m_data_autoins[current_tab_index][index];\r
+\r
+ if (/^[0-9][0-9]*$/.test(value)) {\r
+ intval = parseInt(value);\r
+\r
+ if (id.startsWith('id_text_autosel_')) {\r
+ var list = m_data_autoins[current_tab_index][index].list;\r
+ if (intval > list.length) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_AUTOSEL);\r
+ $(this).val(data.autosel);\r
+ return;\r
+ }\r
+ }\r
+\r
+ VtoySaveCurrentPage(index);\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_NUMBER);\r
+\r
+ if (id.startsWith('id_text_timeout_')) {\r
+ $(this).val(data.timeout);\r
+ } else {\r
+ $(this).val(data.autosel);\r
+ }\r
+ }\r
+ }\r
+\r
+ function OnCheckBoxChange() {\r
+ var index;\r
+ var textid;\r
+ var value;\r
+ var id = $(this).attr('id');\r
+ var checked = $(this).is(':checked');\r
+\r
+ if (id.length <= 14) {\r
+ return;\r
+ }\r
+\r
+ index = parseInt(id.substr(14));\r
+ var data = m_data_autoins[current_tab_index][index];\r
+\r
+ if (id.startsWith('id_timeout_en_')) {\r
+ textid = 'input[id=id_text_timeout_' + index + ']';\r
+ value = data.timeout;\r
+ } else {\r
+ textid = 'input[id=id_text_autosel_' + index + ']';\r
+ value = data.autosel;\r
+ }\r
+ \r
+ if (checked) {\r
+ $(textid).attr("disabled", false);\r
+ $(textid).val(value);\r
+ } else {\r
+ $(textid).attr("disabled", true);\r
+ $(textid).val('');\r
+ }\r
+ \r
+ VtoySaveCurrentPage(index);\r
+ }\r
+ \r
+\r
+ function FillAutoInsInnerTable(i, data) {\r
+ var td1, td2, td3, td4;\r
+ var inner = data.list;\r
+ var tabid = '#tbl_inner_' + (i + 1);\r
+ var $inner_tbl = $(tabid + ' tbody');\r
+\r
+ var inaddbtn = ventoy_get_xslg_addbtn('AutoInsInnerAddBtn');\r
+ var indelbtn = ventoy_get_xslg_delbtn('AutoInsInnerDelBtn');\r
+\r
+ $inner_tbl.empty();\r
+ \r
+ for (var j = 0; j < inner.length; j++) {\r
+ var $tr;\r
+ td1 = '<td style="width: 5%;">'+(j+1)+'</td>';\r
+ td2 = '<td>'+inner[j].path+'</td>';\r
+ td3 = '<td style="width: 10%;">'+ventoy_get_status_line(0, inner[j].valid)+'</td>';\r
+ td4 = '<td style="width: 10%;">' + indelbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + '</tr>');\r
+ $tr.data('path', inner[j].path);\r
+ $tr.data('index', j);\r
+ $tr.data('outpath', data.path);\r
+ $tr.data('outindex', i);\r
+\r
+ $inner_tbl.append($tr);\r
+ }\r
+\r
+ $tr = $('<tr><td></td><td></td><td></td><td>'+inaddbtn+'</td></tr>');\r
+ $tr.data('outpath', data.path);\r
+ $tr.data('outindex', i);\r
+\r
+ $inner_tbl.append($tr);\r
+ }\r
+\r
+ function FillAutoInsTable(data) {\r
+ var td1, td2, td3, td4, td5;\r
+ var addbtn = ventoy_get_addbtn('AutoInsAddBtn');\r
+ var delbtn = ventoy_get_delbtn('AutoInsDelBtn');\r
+ \r
+ var $tbl = $("#id_autoins_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+\r
+ var tdtimeout, timeoutdisable, timeoutval;\r
+ var tdautosel, autoseldisable, autoselval;\r
+ if (data[i].timeouten) {\r
+ tdtimeout = '<th style="width:10%;"><input id="id_timeout_en_'+i+'" checked="checked" type="checkbox"/> timeout</th>';\r
+ timeoutval = data[i].timeout;\r
+ timeoutdisable='';\r
+ } else {\r
+ tdtimeout = '<th style="width:10%;"><input id="id_timeout_en_'+i+'" type="checkbox"/> timeout</th>';\r
+ timeoutval='';\r
+ timeoutdisable='disabled="disabled"';\r
+ }\r
+ if (data[i].autoselen) {\r
+ tdautosel = '<th style="width:10%;"><input id="id_autosel_en_'+i+'" checked="checked" type="checkbox"/> autosel</th>';\r
+ autoselval = data[i].autosel;\r
+ autoseldisable='';\r
+ } else {\r
+ tdautosel = '<th style="width:10%;"><input id="id_autosel_en_'+i+'" type="checkbox"/> autosel</th>';\r
+ autoselval='';\r
+ autoseldisable='disabled="disabled"';\r
+ }\r
+\r
+\r
+ var tdtype = (data[i].type === 0) ? "image" : "parent";\r
+ var tdtbl1 ='<table class="table table-condensed">'+\r
+ \r
+ '<thead><tr>' + \r
+ '<th>'+tdtype+'</th>'+\r
+ '<th style="width:10%;">Status</th>'+ \r
+ tdtimeout +\r
+ tdautosel +\r
+ '</tr></thread>' +\r
+\r
+ '<tbody><tr>'+\r
+ '<td style="width:70%;vertical-align: middle;">' + data[i].path + '</td>' + \r
+ '<td style="vertical-align: middle;">' + ventoy_get_status_line(data[i].type, data[i].valid) + '</td>' +\r
+ '<td><div style="padding-left:0;" class="col-sm-8"><input type="text" '+timeoutdisable+' value="'+timeoutval+'" class="form-control" id="id_text_timeout_'+i+'"/></div></td>'+\r
+ '<td><div style="padding-left:0;" class="col-sm-8"><input type="text" '+autoseldisable+' value="'+autoselval+'" class="form-control" id="id_text_autosel_'+i+'"/></div></td></tr>'+\r
+ \r
+ '<tr><td></td><td></td><td></td><td></td></tr>'+\r
+\r
+ '</tbody></table>';\r
+\r
+ var tdtbl2 = '<table class="table table-bordered" id="tbl_inner_' + (i+1) + '">'+\r
+ '<thead><tr><th>#</th><th id="id_th_template">'+g_vtoy_cur_language.STR_AUTO_TEMPLATE+'</th><th id="id_th_status">'+g_vtoy_cur_language.STR_STATUS+'</th><th id="id_th_operation">'+g_vtoy_cur_language.STR_OPERATION+'</th></tr></thead><tbody></tbody></table>';\r
+\r
+ td1 = '<td style="vertical-align: middle;">' + (i + 1) + '</td>';\r
+ td2 = '<td>' + tdtbl1 + tdtbl2 + '</td>';\r
+ td3 = '<td style="vertical-align: middle;text-align: center;">' + delbtn + '</td>';\r
+ $tr = $('<tr>' + td1 + td2 + td3 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td style="vertical-align: middle;text-align: center;">' + addbtn + '</td></tr>');\r
+\r
+ $('input[type=text]').each(function (){\r
+ var id = $(this).attr('id');\r
+ \r
+ if (id.startsWith('id_text_timeout_') || id.startsWith('id_text_autosel_')) {\r
+ $(this).change(OnInputTextChange);\r
+ }\r
+ });\r
+\r
+ $('input[type=checkbox]').each(function (){\r
+ var id = $(this).attr('id');\r
+ if (id.startsWith('id_timeout_en_') || id.startsWith('id_autosel_en_')) {\r
+ $(this).click(OnCheckBoxChange);\r
+ }\r
+ });\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ FillAutoInsInnerTable(i, data[i]); \r
+ }\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillAutoInsTable(data);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_autoins[index]);\r
+ }\r
+\r
+ function AddAutoInstallEntry(type, exist1, path1, path2) {\r
+ var list = m_data_autoins[current_tab_index];\r
+ var data_array = [\r
+ {\r
+ "path": "",\r
+ "valid": 1\r
+ }\r
+ ];\r
+ var call_array = [\r
+ ""\r
+ ];\r
+\r
+ call_array[0] = path2.substr(g_current_dir.length);\r
+ data_array[0].path = path2.substr(g_current_dir.length);\r
+\r
+ var data = {\r
+ "path": path1.substr(g_current_dir.length),\r
+ "list": data_array,\r
+ "type": type,\r
+ "valid": exist1,\r
+ "autosel": 1,\r
+ "timeout": 0\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'auto_install_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ template: call_array,\r
+ type: type\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillAutoInsTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAddImageAutoInstall(exist1, path1, path2) {\r
+ AddAutoInstallEntry(0, exist1, path1, path2);\r
+ }\r
+ \r
+ function OnAddDirAutoInstall(path1, path2) {\r
+ AddAutoInstallEntry(1, 1, path1, path2);\r
+ }\r
+\r
+ function OnAddAutoInsBtnClick(sel) {\r
+ if (sel === 0) {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\Windows11.iso' : "/ISO/CentOS-7-x86_64-DVD-1908.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\Windows**.iso' : "/ISO/CentOS-7-x86_64-DVD-****.iso";\r
+ var tip3 = (g_current_os === 'windows') ? '\\script\\Windows_unattend.xml' : "/script/centos.ks"; \r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_AUTO_INS,\r
+ "label1": g_vtoy_cur_language.STR_FILE_PATH,\r
+ "label2": g_vtoy_cur_language.STR_SET_AUTO_TEMPLATE,\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2,\r
+ "tip3": g_current_dir + tip3\r
+ };\r
+\r
+ VtoySetFileFile(OnAddImageAutoInstall, para);\r
+ } else {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\Windows' : "/ISO/Linux";\r
+ var tip2 = (g_current_os === 'windows') ? '\\script\\Windows_unattend.xml' : "/script/centos.ks"; \r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_AUTO_INS,\r
+ "label1": g_vtoy_cur_language.STR_DIR_PATH,\r
+ "label2": g_vtoy_cur_language.STR_SET_AUTO_TEMPLATE,\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2\r
+ };\r
+ VtoySetDirFile(OnAddDirAutoInstall, para);\r
+ }\r
+ }\r
+\r
+ function OnAutoInstallAddClick() {\r
+ var para = [\r
+ {\r
+ "selected": true,\r
+ "tip": g_vtoy_cur_language.STR_SET_AUTO_INSTALL_FOR_FILE\r
+ },\r
+ {\r
+ "selected": false,\r
+ "tip": g_vtoy_cur_language.STR_SET_AUTO_INSTALL_FOR_DIR\r
+ }\r
+ ];\r
+\r
+ VtoySelectType(OnAddAutoInsBtnClick, para);\r
+ }\r
+\r
+ function AutoInstallDelEntry(path, index) {\r
+ callVtoySync({\r
+ method : 'auto_install_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_autoins[current_tab_index].splice(index, 1);\r
+ FillAutoInsTable(m_data_autoins[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAutoInstallDelClick() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ AutoInstallDelEntry(path, index);\r
+ }\r
+ \r
+\r
+ var m_out_index;\r
+ var m_out_path;\r
+ function OnAddAutoTemplateScript(root, valid, extra) {\r
+ var path = root.substr(g_current_dir.length);\r
+ var data = m_data_autoins[current_tab_index][m_out_index];\r
+\r
+ for (var i = 0; i < data.list.length; i++) {\r
+ if (data.list[i].path === path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'auto_install_add_inner',\r
+ index: current_tab_index,\r
+ outpath: m_out_path,\r
+ path: path\r
+ }, function(e) {\r
+\r
+ var node = {\r
+ "path": path,\r
+ "valid": 1\r
+ };\r
+\r
+ data.list.push(node);\r
+ FillAutoInsInnerTable(m_out_index, data);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ \r
+ }\r
+\r
+ function OnAutoInstallInnerAddClick() {\r
+ var $tr = $(this).closest('tr');\r
+ var outpath = $tr.data('outpath');\r
+ var outindex = $tr.data('outindex');\r
+\r
+ var tip = (g_current_os === 'windows') ? '\\script\\Windows_unattend.xml' : "/script/centos.ks";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_ADD_AUTO_TEMPLATE,\r
+ "fuzzy": 0,\r
+ "tip1": g_current_dir + tip,\r
+ "tip2": '',\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+\r
+ m_out_index = outindex;\r
+ m_out_path = outpath;\r
+ VtoySelectFilePath(OnAddAutoTemplateScript, para);\r
+ }\r
+\r
+ function AutoInstallDelInnerEntry(outpath, outindex, path, index) {\r
+ callVtoy({\r
+ method : 'auto_install_del_inner',\r
+ index: current_tab_index,\r
+ outpath: outpath,\r
+ path: path\r
+ }, function(e) {\r
+ var data = m_data_autoins[current_tab_index][outindex];\r
+\r
+ data.list.splice(index, 1);\r
+ FillAutoInsInnerTable(outindex, m_data_autoins[current_tab_index][outindex]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAutoInstallInnerDelClick() {\r
+ var $tr = $(this).closest('tr');\r
+\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+ var outpath = $tr.data('outpath');\r
+ var outindex = $tr.data('outindex');\r
+\r
+ var list = m_data_autoins[current_tab_index][outindex].list;\r
+\r
+ if (list.length === 1) {\r
+ ventoy_confirm(g_vtoy_cur_language.STR_DEL_LAST, AutoInstallDelEntry, outpath, outindex);\r
+ } else {\r
+ AutoInstallDelInnerEntry(outpath, outindex, path, index);\r
+ }\r
+ }\r
+\r
+\r
+\r
+\r
+\r
+ //Main process\r
+ var m_data_autoins;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_auto_install'}, function(data) {\r
+ m_data_autoins = data;\r
+ });\r
+ \r
+ $("#id_autoins_tbl").on('click', '.AutoInsAddBtn', OnAutoInstallAddClick);\r
+ $("#id_autoins_tbl").on('click', '.AutoInsDelBtn', OnAutoInstallDelClick);\r
+ $("#id_autoins_tbl").on('click', '.AutoInsInnerAddBtn', OnAutoInstallInnerAddClick);\r
+ $("#id_autoins_tbl").on('click', '.AutoInsInnerDelBtn', OnAutoInstallInnerDelClick);\r
+\r
+ $('#id_tab_autoins a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_autoins a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_autoins a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_autoins a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_autoins a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_autoins a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_autoins a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_autoins[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-floppy-o"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title"></h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_automemdisk.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_auto_memdisk">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >auto_memdisk</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_memdisk_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_memdisk_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_memdisk_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_memdisk_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">auto_memdisk_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <table id="id_auto_memdisk_tbl" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 5%;">#</th>\r
+ <th id="id_th_memdisk_path" style="width: 60%;"></th>\r
+ <th id="id_th_status" style="width: 10%;"></th>\r
+ <th id="id_th_operation" style="width: 10%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_AUTO_MEMDISK);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_memdisk_path').text('Absolute Path');\r
+ } else {\r
+ $('#id_th_memdisk_path').text('绝对路径');\r
+ \r
+ }\r
+ }\r
+ \r
+ function FillMemdiskTable(data) {\r
+ var addbtn = ventoy_get_xslg_addbtn('MemdiskAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('MemdiskDelBtn');\r
+\r
+ var td1, td2, td3, td4;\r
+ var $tbl = $("#id_auto_memdisk_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = '<td>' + data[i].path + '</td>';\r
+ td3 = '<td>' + ventoy_get_status_line(0, data[i].valid) + '</td>';\r
+ td4 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillMemdiskTable(data);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_memdisk[index]);\r
+ }\r
+\r
+ //Main process\r
+ var m_data_memdisk;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_auto_memdisk'}, function(data) {\r
+ m_data_memdisk = data;\r
+ });\r
+ \r
+ function OnAddAutoMemdisk(root, valid, extra) {\r
+ var list = m_data_memdisk[current_tab_index];\r
+ var data = {\r
+ "path": root.substr(g_current_dir.length),\r
+ "valid": valid\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'auto_memdisk_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillMemdiskTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ $("#id_auto_memdisk_tbl").on('click', '.MemdiskAddBtn', function() {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\Windows11.iso' : "/ISO/Ubuntu-20.04-desktop-amd64.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\Windows**.iso' : "/ISO/Ubuntu-*****-desktop-amd64.iso";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_ADD_FILE_TO_LIST,\r
+ "fuzzy": 1,\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2,\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+ VtoySelectFilePath(OnAddAutoMemdisk, para);\r
+ });\r
+\r
+ $("#id_auto_memdisk_tbl").on('click', '.MemdiskDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'auto_memdisk_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_memdisk[current_tab_index].splice(index, 1);\r
+ FillMemdiskTable(m_data_memdisk[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+ $('#id_tab_auto_memdisk a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_auto_memdisk a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_auto_memdisk a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_auto_memdisk a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_auto_memdisk a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_auto_memdisk a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_auto_memdisk a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_memdisk[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-retweet"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">菜单别名插件</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_bootconf_replace.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_conf_replace">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >conf_replace</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">conf_replace_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">conf_replace_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">conf_replace_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">conf_replace_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">conf_replace_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <table id="id_conf_replace_tbl" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 2%;">#</th>\r
+ <th id="id_th_conf_path" style="width: 30%;"></th>\r
+ <th id="id_th_status" style="width: 5%;"></th>\r
+ <th id="id_th_conf_org" style="width: 20%;"></th>\r
+ <th id="id_th_conf_new" style="width: 30%;"></th>\r
+ <th id="id_th_status" style="width: 5%;"></th>\r
+ <th id="id_th_operation" style="width: 5%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_CONF_REPLACE);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_conf_path').text('Absolute Path');\r
+ $('#id_th_conf_org').text('org');\r
+ $('#id_th_conf_new').text('new');\r
+ } else {\r
+ $('#id_th_conf_path').text('绝对路径');\r
+ $('#id_th_conf_org').text('org');\r
+ $('#id_th_conf_new').text('new');\r
+ \r
+ }\r
+ }\r
+ \r
+ function FillConfReplaceTable(data) {\r
+ var addbtn = ventoy_get_xslg_addbtn('ConfReplaceAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('ConfReplaceDelBtn');\r
+\r
+ var td1, td2, td3, td4, td5, td6, td7;\r
+ var $tbl = $("#id_conf_replace_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = '<td>' + data[i].path + '</td>';\r
+ td3 = '<td>' + ventoy_get_status_line(0, data[i].valid) + '</td>';\r
+ td4 = '<td>' + data[i].org + '</td>';\r
+ td5 = '<td>' + data[i].new + '</td>';\r
+ td6 = '<td>' + ventoy_get_status_line(0, data[i].new_valid) + '</td>';\r
+ td7 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + td5 + td6 + td7 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillConfReplaceTable(data);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_conf_replace[index]);\r
+ }\r
+\r
+ //Main process\r
+ var m_conf_iso_path;\r
+ var m_conf_org_path;\r
+ var m_conf_new_path;\r
+ var m_data_conf_replace;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_conf_replace'}, function(data) {\r
+ m_data_conf_replace = data;\r
+ });\r
+\r
+ var m_conf_replace_validator = $("#ConfReplaceForm").validate({ \r
+ rules: { \r
+ IsoPath : {\r
+ required: true,\r
+ utfmaxlen: true \r
+ },\r
+ OrgPath : {\r
+ required: true,\r
+ utfmaxlen: true,\r
+ start_slash: true \r
+ },\r
+ NewPath: {\r
+ required: true,\r
+ utfmaxlen: true\r
+ }\r
+ },\r
+\r
+ submitHandler: function(form) {\r
+ m_conf_iso_path = $('input:text[id=IsoPath]').val();\r
+ m_conf_org_path = $('input:text[id=OrgPath]').val();\r
+ m_conf_new_path = $('input:text[id=NewPath]').val();\r
+\r
+ if ((!m_conf_iso_path) || (!m_conf_org_path) || (!m_conf_new_path))\r
+ {\r
+ return;\r
+ }\r
+\r
+ m_conf_iso_path = ventoy_replace_slash(m_conf_iso_path);\r
+ m_conf_new_path = ventoy_replace_slash(m_conf_new_path);\r
+\r
+ if (!ventoy_common_check_path(m_conf_iso_path)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ return;\r
+ }\r
+\r
+ if (!ventoy_common_check_path(m_conf_new_path)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ return;\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'check_path2',\r
+ dir1: 0,\r
+ fuzzy1: 1,\r
+ path1: m_conf_iso_path,\r
+ dir2: 0,\r
+ fuzzy2: 0,\r
+ path2: m_conf_new_path\r
+ }, function(retdata) {\r
+ if (retdata.exist1 != 0 && retdata.exist2 != 0) {\r
+ var img = 0;\r
+ var data = {\r
+ "path": m_conf_iso_path.substr(g_current_dir.length),\r
+ "valid": retdata.exist1,\r
+ "org": m_conf_org_path,\r
+ "new": m_conf_new_path.substr(g_current_dir.length),\r
+ "new_valid": 1,\r
+ "img":0\r
+ };\r
+\r
+ if (m_conf_org_path.substr(0, 8) === '/loader/') {\r
+ img = 1;\r
+ data.img = 1;\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'conf_replace_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ org: data.org,\r
+ new: data.new,\r
+ img: img\r
+ }, function(e) {\r
+ m_data_conf_replace[current_tab_index].push(data);\r
+ FillConfReplaceTable(m_data_conf_replace[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+\r
+ $("#ConfReplaceModal").modal('hide');\r
+ } else if (retdata.exist1 === 0) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_NEW_FILE_PATH);\r
+ }\r
+ });\r
+ }\r
+ });\r
+\r
+ $("#id_conf_replace_tbl").on('click', '.ConfReplaceAddBtn', function() {\r
+ if (g_current_language === 'en') {\r
+ $('#ConfReplaceForm #ConfReplaceForm_lang_1').text("ISO Path");\r
+ $('#ConfReplaceForm #ConfReplaceForm_lang_2').text(" OK");\r
+ $('#ConfReplaceForm #ConfReplaceForm_lang_3').text("Cancel");\r
+ $('#ConfReplaceForm #id_note_conf_cn').hide();\r
+ $('#ConfReplaceForm #id_note_conf_en').show();\r
+ } else {\r
+ $('#ConfReplaceForm #ConfReplaceForm_lang_1').text("ISO文件路径");\r
+ $('#ConfReplaceForm #ConfReplaceForm_lang_2').text("确定");\r
+ $('#ConfReplaceForm #ConfReplaceForm_lang_3').text("取消");\r
+ $('#ConfReplaceForm #id_note_conf_en').hide();\r
+ $('#ConfReplaceForm #id_note_conf_cn').show();\r
+ }\r
+ \r
+ $('#ConfReplaceForm #id_span_conf_tip1').each(function() {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Ubuntu-20.04-desktop-amd64.iso' : "/ISO/Ubuntu-20.04-desktop-amd64.iso";\r
+ $(this).text(g_current_dir + tip);\r
+ });\r
+\r
+ $('#ConfReplaceForm #id_span_conf_tip2').each(function() {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Ubuntu-*****-desktop-amd64.iso' : "/ISO/Ubuntu-*****-desktop-amd64.iso";\r
+ $(this).text(g_current_dir + tip);\r
+ });\r
+\r
+ $('#ConfReplaceForm #id_span_conf_tip3').each(function() {\r
+ var tip = (g_current_os === 'windows') ? '\\ventoy\\grub_new.cfg' : "/ventoy/grub_new.cfg";\r
+ $(this).text(g_current_dir + tip);\r
+ });\r
+\r
+ m_conf_replace_validator.resetForm(); \r
+ $("#ConfReplaceModal").modal();\r
+ });\r
+\r
+ $("#id_conf_replace_tbl").on('click', '.ConfReplaceDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'conf_replace_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_conf_replace[current_tab_index].splice(index, 1);\r
+ FillConfReplaceTable(m_data_conf_replace[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+\r
+ $('#id_tab_conf_replace a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_conf_replace a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_conf_replace a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_conf_replace a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_conf_replace a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_conf_replace a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_conf_replace a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_conf_replace[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-8" style="padding-top:8px;">\r
+ <i class="fa fa-wrench"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">全局控制插件</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="padding-top:2px;">\r
+ <button id="id_btn_collapse" class="btn btn-sm btn-primary"><i style="font-size: 14px;" class="fa fa-minus"></i></button>\r
+ <button id="id_btn_expand" class="btn btn-sm btn-primary"><i style="font-size: 14px;" class="fa fa-plus"></i></button>\r
+ </div>\r
+\r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/cn/plugin_control.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_control">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >control</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">control_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">control_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">control_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">control_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">control_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_DEFAULT_SEARCH_ROOT\r
+ <span id="id_span_desc_cn"> —— 指定搜索目录</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <div class="col-sm-9" style="padding-left:0px;">\r
+ <input type="text" class="form-control" id="id_ctrl_text_search_root" name="name_ctrl_text_search_root" disabled="disabled"/>\r
+ </div>\r
+ <div class="col-sm-1" id="id_ctrl_div_root_status">\r
+ <span id="id_ctrl_span_search_root_valid" style="line-height: 2;" class="badge bg-green">有效</span>\r
+ <span id="id_ctrl_span_search_root_invalid" style="line-height: 2;" class="badge bg-red">无效</span>\r
+ </div>\r
+ <div class="col-sm-1">\r
+ <button id="id_ctrl_btn_sel_root" class="btn btn-primary btn-add"><span class="fa fa-edit"></span><span id="id_span_edit"> 设置</span></button>\r
+ </div>\r
+ <div class="col-sm-1">\r
+ <button id="id_ctrl_btn_clr_root" class="btn btn-danger btn-del"><span class="fa fa-trash"></span><span id="id_span_clear"> 清除</span></button>\r
+ </div>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 指定搜索ISO文件的根目录。默认Ventoy会搜索U盘上的所有目录和子目录,当你U盘上有海量的文件时,这个过程会很慢。<br/>\r
+ 这种情况下你可以把ISO文件单独放在某个目录下,然后通过这个变量来指定搜索路径,此时Ventoy就只会搜索该目录及其子目录。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ The root path where to search the image files. By default, Ventoy will search all the directories and subdirectories in the USB. This will be very slow when you have huge number of files in the USB. \r
+ In this case, you can put all the image files in one directory and use this to specify the search path. \r
+ After that Ventoy will only search this directory and its subdirectories for image files.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_WIN11_BYPASS_CHECK\r
+ <span id="id_span_desc_cn"> —— 绕过Windows 11硬件检查</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_bypass_win11_radio0" name="id_ctrl_bypass_win11_radio" data-type="0" value="0"/> <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_bypass_win11_radio1" name="id_ctrl_bypass_win11_radio" data-type="1" value="1"/> <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> 不绕过Windows 11安装时的硬件检查。<br/>\r
+ <code style="font-weight: bold;">1</code> 绕过Windows 11安装时的硬件检查。<br/><br/>\r
+ 该选项只对标准Windows 11 ISO文件有效,对于其他镜像文件无效。\r
+ 当设置为1时,Ventoy 会在安装时创建以下几个注册表项用来绕过 Windows 11 安装程序的硬件检查。<br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassRAMCheck</code><br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassTPMCheck</code><br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassSecureBootCheck</code><br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassCPUCheck</code><br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassStorageCheck</code><br/>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> Don not bypass Windows 11 hardware check.<br/>\r
+ <code style="font-weight: bold;">1</code> Bypass Windows 11 hardware check. <br/><br/>\r
+ This option only avaliable for standard Windows 11 ISO files.\r
+ When set to 1, Ventoy will create the following registries to bypass Windows 11 hardware check when install. <br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassRAMCheck</code><br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassTPMCheck</code><br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassSecureBootCheck</code><br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassCPUCheck</code><br/>\r
+ <code>HKEY_LOCAL_MACHINE\SYSTEM\Setup\LabConfig\BypassStorageCheck</code><br/>\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+ \r
+ \r
+\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_DEFAULT_MENU_MODE\r
+ <span id="id_span_desc_cn"> —— 菜单显示模式</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_menu_mode0" name="id_ctrl_radio_menu_mode" data-type="0" value="0"> <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_menu_mode1" name="id_ctrl_radio_menu_mode" data-type="1" value="1"> <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>启动菜单默认显示模式,\r
+ <code style="font-weight: bold;">0</code> 列表模式 \r
+ <code style="font-weight: bold;">1</code> TreeView(目录树) 模式</td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ Default boot menu display mode. \r
+ <code style="font-weight: bold;">0</code> ListView Mode  \r
+ <code style="font-weight: bold;">1</code> TreeView Mode\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+\r
+\r
+\r
+\r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_MENU_TIMEOUT\r
+ <span id="id_span_desc_cn"> —— 启动倒计时</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <div class="col-sm-9" style="padding-left:0px;">\r
+ <input type="text" class="form-control" id="id_ctrl_text_timeout" name="name_ctrl_text_timeout"/>\r
+ </div> \r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 菜单倒计时(秒)。默认为0(即没有超时时间),设置之后,比如设置为10,则在倒计时10秒之后,会自动启动选中的镜像文件。在倒计时的过程中按任意键会停止倒计时,等待用户操作。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ Menu timeout (seconds). Default value is 0 (no timeout is set). <br/>\r
+ When you set it to 10 for example, the selected image will be booted automatically after 10 seconds.\r
+ During the countdown, pressing any key will stop the countdown and wait for user operation.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+\r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_DEFAULT_IMAGE\r
+ <span id="id_span_desc_cn"> —— 默认选中的镜像文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <div class="col-sm-9" style="padding-left:0px;">\r
+ <input type="text" class="form-control" id="id_ctrl_text_default_img" name="name_id_ctrl_text_default_img" disabled="disabled"/>\r
+ </div>\r
+ <div class="col-sm-1" id="id_ctrl_div_img_status">\r
+ <span id="id_ctrl_span_img_valid" style="line-height: 2;" class="badge bg-green">有效</span>\r
+ <span id="id_ctrl_span_img_invalid" style="line-height: 2;" class="badge bg-red">无效</span>\r
+ </div>\r
+ <div class="col-sm-1">\r
+ <button id="id_ctrl_btn_default_img" class="btn btn-primary btn-add"><span class="fa fa-edit"></span><span id="id_span_edit"> 设置</span></button>\r
+ </div>\r
+ <div class="col-sm-1">\r
+ <button id="id_ctrl_btn_clr_default" class="btn btn-danger btn-del"><span class="fa fa-trash"></span><span id="id_span_clear"> 清除</span></button>\r
+ </div>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 正常情况下默认选中的是第1个镜像文件。通过这个选项可以设置默认选中的镜像文件,一般和 VTOY_MENU_TIMEOUT 一起使用。<br/>\r
+ 可以设置为 WIM/VHD/IMG 等支持的文件,必须是以 / 开始的全路径,ListView模式和TreeView模式都支持。 <br/>\r
+ 注意,当同时设置了 VTOY_DEFAULT_SEARCH_ROOT 以后,VTOY_DEFAULT_IMAGE 对应的文件必须位于 VTOY_DEFAULT_SEARCH_ROOT 对应的目录下,否则不会生效。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ Default selected image path. Normally used with VTOY_MENU_TIMEOUT. <br/>It can be ISO/WIM/VHD/IMG ... and supported in both ListView mode and TreeView mode.<br/>\r
+ Attention that, when VTOY_DEFAULT_SEARCH_ROOT is set, VTOY_DEFAULT_IMAGE must be in the directory (or sub-directory) of VTOY_DEFAULT_SEARCH_ROOT, otherwise it will not take effect.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_MAX_SEARCH_LEVEL\r
+ <span id="id_span_desc_cn"> —— 最大搜索目录深度</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <select id="id_ctrl_sel_max_depth" name="name_ctrl_sel_max_depth" class="form-control">\r
+ <option title="max" selected>max</option>\r
+ <option title="0">0</option>\r
+ <option title="1">1</option>\r
+ <option title="2">2</option>\r
+ <option title="3">3</option>\r
+ <option title="4">4</option>\r
+ <option title="5">5</option>\r
+ <option title="6">6</option>\r
+ <option title="7">7</option>\r
+ <option title="8">8</option>\r
+ <option title="9">9</option>\r
+ <option title="10">10</option>\r
+ </select>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 最大搜索子目录的层数,取值为:<code>max</code> <code>0</code> <code>1</code> <code>2</code> <code>3</code> <code>...</code> \r
+ 默认值为:<code>max</code><br/>\r
+ 默认Ventoy会递归搜索磁盘上的所有目录和子目录,不管目录结构有多深都会搜索到底。你可以通过这个参数来控制搜索时的路径深度。<br/><br/>\r
+ <code>max</code> : 最大层数,也就是搜索所有子目录的意思。这也是 Ventoy 的默认值。<br/>\r
+ <code>0</code> : 搜索0层子目录,只列出根目录下的文件,不去搜索任何一个子目录。<br/>\r
+ <code>1</code> : 搜索1层子目录,除了根目录下的文件以外,再搜索根目录下的1级子目录。但是不再搜索1级子目录下的子目录(2级子目录)。<br/>\r
+ <code>2</code> : 搜索2层子目录,除了根目录下的文件以外,再搜索根目录下的1级子目录以及1级子目录下的子目录(2级子目录)。<br/>\r
+ <code>3</code> : 搜索3层子目录,......<br/>\r
+ <code>...</code><br/><br/>\r
+ 注意,如果 <code>VTOY_DEFAULT_SEARCH_ROOT</code> 参数也同时设置了的话,则就以 <code>VTOY_DEFAULT_SEARCH_ROOT</code> 指定的目录作为根目录开始计算。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ Max subdirectory level when search for image files. It's value can be: <code>max</code> <code>0</code> <code>1</code> <code>2</code> <code>3</code> <code>...</code> \r
+ default is : <code>max</code><br/>\r
+ By default, Ventoy will search all the directories and sub directories recursively no matter how deep the directory level is.<br/>\r
+ You can use this parameter to set a max-depth for the search path.<br/><br/>\r
+ <code>max</code> : Maximum, search all the directories and subdirectories. This is Ventoy's default value.<br/>\r
+ <code>0</code> : Only search files in the root and don't search any subdirectories.<br/>\r
+ <code>1</code> : Search up to level 1 of subdirectories.<br/>\r
+ <code>2</code> : Search up to level 2 of subdirectories.<br/>\r
+ <code>3</code> : Search up to level 3 of subdirectories.<br/>\r
+ <code>...</code><br/><br/>\r
+ If <code>VTOY_DEFAULT_SEARCH_ROOT</code> is set at the same time. Then the level is counted from <code>VTOY_DEFAULT_SEARCH_ROOT</code> .\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+ \r
+ \r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_DEFAULT_KBD_LAYOUT\r
+ <span id="id_span_desc_cn"> —— 默认键盘布局</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <select id="id_ctrl_sel_kbd" name="name_ctrl_sel_kbd" class="form-control">\r
+ <option title="QWERTY_USA" selected>QWERTY_USA</option>\r
+ <option title="AZERTY">AZERTY</option>\r
+ <option title="CZECH_QWERTY">CZECH_QWERTY</option>\r
+ <option title="CZECH_QWERTZ">CZECH_QWERTZ</option>\r
+ <option title="DANISH">DANISH</option>\r
+ <option title="DVORAK_USA">DVORAK_USA</option>\r
+ <option title="FRENCH">FRENCH</option>\r
+ <option title="GERMAN">GERMAN</option>\r
+ <option title="ITALIANO">ITALIANO</option>\r
+ <option title="JAPAN_106">JAPAN_106</option>\r
+ <option title="LATIN_USA">LATIN_USA</option>\r
+ <option title="PORTU_BRAZIL">PORTU_BRAZIL</option>\r
+ <option title="QWERTY_UK">QWERTY_UK</option>\r
+ <option title="QWERTZ">QWERTZ</option>\r
+ <option title="QWERTZ_HUN">QWERTZ_HUN</option>\r
+ <option title="QWERTZ_SLOV_CROAT">QWERTZ_SLOV_CROAT</option>\r
+ <option title="SPANISH">SPANISH</option>\r
+ <option title="SWEDISH">SWEDISH</option>\r
+ <option title="TURKISH_Q">TURKISH_Q</option>\r
+ <option title="VIETNAMESE">VIETNAMESE</option>\r
+ </select>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 键盘布局\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ Keyboard Layout\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+ \r
+ \r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_TREE_VIEW_MENU_STYLE\r
+ <span id="id_span_desc_cn"> —— TreeView模式显示风格</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_treestyle0" name="id_ctrl_radio_treestyle" data-type="0" value="0"> <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_treestyle1" name="id_ctrl_radio_treestyle" data-type="1" value="1"> <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>TreeView模式下的菜单风格。\r
+ <code style="font-weight: bold;">0</code> 显示DIR和文件大小 \r
+ <code style="font-weight: bold;">1</code> 不显示DIR和文件大小。只在 VTOY_DEFAULT_MENU_MODE 为1时才有效。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ Menu style in TreeView mode. \r
+ <code style="font-weight: bold;">0</code> with DIR and file size prefix \r
+ <code style="font-weight: bold;">1</code> No DIR and file size. Default is 0.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_FILT_DOT_UNDERSCORE_FILE\r
+ <span id="id_span_desc_cn"> —— 过滤以 ._ 开头的文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_underscore0" name="id_ctrl_radio_underscore" data-type="0" value="0"> <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_underscore1" name="id_ctrl_radio_underscore" data-type="1" value="1"> <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>过滤以 ._ 开头的文件。当使用苹果系统时,有时拷贝文件会产生一些 ._ 开头的文件,可以通过此选项过滤掉。\r
+ <code style="font-weight: bold;">0</code> 不过滤 \r
+ <code style="font-weight: bold;">1</code> 过滤\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ Filter for files with prefix ._ in name. This will be useful when you use macOS (a lot of ._xxx file generated when you copy files). \r
+ <code style="font-weight: bold;">0</code> Don't filt \r
+ <code style="font-weight: bold;">1</code> Filt\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_SORT_CASE_SENSITIVE\r
+ <span id="id_span_desc_cn"> —— 菜单排序时是否区分大小写</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_casesensitive0" name="id_ctrl_radio_casesensitive" data-type="0" value="0"> <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_casesensitive1" name="id_ctrl_radio_casesensitive" data-type="1" value="1"> <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>在菜单排序时是否大小写敏感。\r
+ <code style="font-weight: bold;">0</code> 不区分大小写 <code style="font-weight: bold;">1</code> 区分大小写\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ Case sensitive when sort the ISO files or directories. \r
+ <code style="font-weight: bold;">0</code> case insensitive <code style="font-weight: bold;">1</code> case sensitive\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_VHD_NO_WARNING</h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_vhd_warning0" name="id_ctrl_radio_vhd_warning" data-type="0" value="0"> <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_vhd_warning1" name="id_ctrl_radio_vhd_warning" data-type="1" value="1"> <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> 启动Windows VHD(x)时,如果U盘分区不是NTFS格式,则显示告警信息。 \r
+ <code style="font-weight: bold;">1</code> 不显示告警信息。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> Show a warning message if the partition is not NTFS when booting VHD(x) file. \r
+ <code style="font-weight: bold;">1</code> No warning message.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+\r
+ \r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_FILE_FLT_ISO\r
+ <span id="id_span_desc_cn"> —— 过滤 .iso 文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_iso0" name="id_ctrl_radio_filt_iso" data-type="0" value="0" > <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_iso1" name="id_ctrl_radio_filt_iso" data-type="1" value="1" > <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> 不过滤 .iso 文件 \r
+ <code style="font-weight: bold;">1</code> 过滤掉 .iso 文件。 \r
+ 过滤之后 .iso 文件就不会显示在启动菜单中。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> List .iso files. \r
+ <code style="font-weight: bold;">1</code> Filter .iso files. \r
+ The iso files will not be shown in the boot menu if set to 1.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_FILE_FLT_WIM\r
+ <span id="id_span_desc_cn"> —— 过滤 .wim 文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_wim0" name="id_ctrl_radio_filt_wim" data-type="0" value="0" > <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_wim1" name="id_ctrl_radio_filt_wim" data-type="1" value="1" > <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> 不过滤 .wim 文件 \r
+ <code style="font-weight: bold;">1</code> 过滤掉 .wim 文件。 \r
+ 过滤之后 .wim 文件就不会显示在启动菜单中。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> List .wim files. \r
+ <code style="font-weight: bold;">1</code> Filter .wim files. \r
+ The wim files will not be shown in the boot menu if set to 1.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_FILE_FLT_EFI\r
+ <span id="id_span_desc_cn"> —— 过滤 .efi 文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_efi0" name="id_ctrl_radio_filt_efi" data-type="0" value="0" > <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_efi1" name="id_ctrl_radio_filt_efi" data-type="1" value="1" > <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> 不过滤 .efi 文件 \r
+ <code style="font-weight: bold;">1</code> 过滤掉 .efi 文件。 \r
+ 过滤之后 .efi 文件就不会显示在启动菜单中。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> List .efi files. \r
+ <code style="font-weight: bold;">1</code> Filter .efi files. \r
+ The efi files will not be shown in the boot menu if set to 1.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_FILE_FLT_IMG\r
+ <span id="id_span_desc_cn"> —— 过滤 .img 文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_img0" name="id_ctrl_radio_filt_img" data-type="0" value="0" > <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_img1" name="id_ctrl_radio_filt_img" data-type="1" value="1" > <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> 不过滤 .img 文件 \r
+ <code style="font-weight: bold;">1</code> 过滤掉 .img 文件。 \r
+ 过滤之后 .img 文件就不会显示在启动菜单中。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> List .img files. \r
+ <code style="font-weight: bold;">1</code> Filter .img files. \r
+ The img files will not be shown in the boot menu if set to 1.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_FILE_FLT_VHD\r
+ <span id="id_span_desc_cn"> —— 过滤 .vhd(x) 文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_vhd0" name="id_ctrl_radio_filt_vhd" data-type="0" value="0" > <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_vhd1" name="id_ctrl_radio_filt_vhd" data-type="1" value="1" > <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> 不过滤 .vhd(x) 文件 \r
+ <code style="font-weight: bold;">1</code> 过滤掉 .vhd(x) 文件。 \r
+ 过滤之后 .vhd(x) 文件就不会显示在启动菜单中。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> List .vhd(x) files. \r
+ <code style="font-weight: bold;">1</code> Filter .vhd(x) files. \r
+ The vhd(x) files will not be shown in the boot menu if set to 1.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_FILE_FLT_VTOY\r
+ <span id="id_span_desc_cn"> —— 过滤 .vtoy 文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding"> \r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_vtoy0" name="id_ctrl_radio_filt_vtoy" data-type="0" value="0" > <span style="font-weight:bold;">0</span>\r
+ </label> \r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_ctrl_radio_filt_vtoy1" name="id_ctrl_radio_filt_vtoy" data-type="1" value="1" > <span style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> 不过滤 .vtoy 文件 \r
+ <code style="font-weight: bold;">1</code> 过滤掉 .vtoy 文件。 \r
+ 过滤之后 .vtoy 文件就不会显示在启动菜单中。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col" id="td_title_desc">Option Description</td>\r
+ <td>\r
+ <code style="font-weight: bold;">0</code> List .vtoy files. \r
+ <code style="font-weight: bold;">1</code> Filter .vtoy files. \r
+ The vtoy files will not be shown in the boot menu if set to 1.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">VTOY_HELP_TXT_LANGUAGE\r
+ <span id="id_span_desc_cn"> —— 帮助信息语言</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <select id="id_ctrl_sel_help_lang" name="name_ctrl_sel_help_lang" class="form-control">\r
+ \r
+ </select>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 快捷键 <code>h</code> 显示的帮助信息的语言版本。默认是 "en_US"。 \r
+ 具体请参考 <a target="_blank" href='https://www.ventoy.net/cn/plugin_control.html#vtoy_help_language'>Ventoy 帮助信息</a>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ The language of the help text when press <code>h</code>. Default is "en_US", \r
+ refer <a target="_blank" href='https://www.ventoy.net/en/plugin_control.html#vtoy_help_language'>Ventoy Help Text</a> for details.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+\r
+ </div>\r
+ \r
+</div>\r
+<script type="text/javascript">\r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_CONTROL);\r
+ $('#id_ctrl_span_search_root_valid').text(g_vtoy_cur_language.STR_VALID); \r
+ $('#id_ctrl_span_search_root_invalid').text(g_vtoy_cur_language.STR_INVALID);\r
+ $('#id_ctrl_span_img_valid').text(g_vtoy_cur_language.STR_VALID);\r
+ $('#id_ctrl_span_img_invalid').text(g_vtoy_cur_language.STR_INVALID);\r
+\r
+ $("span[id=id_span_edit]").each(function(){\r
+ $(this).text(' ' + g_vtoy_cur_language.STR_EDIT);\r
+ });\r
+\r
+ $("span[id=id_span_clear]").each(function(){\r
+ $(this).text(' ' + g_vtoy_cur_language.STR_CLEAR);\r
+ });\r
+ }\r
+\r
+ function VtoyGetCurrentPageItem(data) {\r
+ var level;\r
+\r
+ data.win11_bypass_check = parseInt($('input:radio[name=id_ctrl_bypass_win11_radio]:checked').val());\r
+ data.default_search_root = $('input:text[id=id_ctrl_text_search_root]').val();\r
+ data.menu_timeout = parseInt($('input:text[id=id_ctrl_text_timeout]').val());\r
+ data.default_image = $('input:text[id=id_ctrl_text_default_img]').val();\r
+ \r
+ level = $('select[id=id_ctrl_sel_max_depth').val();\r
+ if (level === 'max') {\r
+ data.max_search_level = -1;\r
+ } else {\r
+ data.max_search_level = parseInt(level);\r
+ }\r
+ \r
+ data.default_kbd_layout = $('select[id=id_ctrl_sel_kbd').val();\r
+ data.default_menu_mode = parseInt($('input:radio[name=id_ctrl_radio_menu_mode]:checked').val());\r
+ data.treeview_style = parseInt($('input:radio[name=id_ctrl_radio_treestyle]:checked').val());\r
+\r
+ data.filter_dot_underscore = parseInt($('input:radio[name=id_ctrl_radio_underscore]:checked').val());\r
+ data.sort_casesensitive = parseInt($('input:radio[name=id_ctrl_radio_casesensitive]:checked').val());\r
+\r
+ data.vhd_no_warning = parseInt($('input:radio[name=id_ctrl_radio_vhd_warning]:checked').val());\r
+ data.filter_iso = parseInt($('input:radio[name=id_ctrl_radio_filt_iso]:checked').val());\r
+ data.filter_wim = parseInt($('input:radio[name=id_ctrl_radio_filt_wim]:checked').val());\r
+ data.filter_efi = parseInt($('input:radio[name=id_ctrl_radio_filt_efi]:checked').val());\r
+ data.filter_img = parseInt($('input:radio[name=id_ctrl_radio_filt_img]:checked').val());\r
+ data.filter_vhd = parseInt($('input:radio[name=id_ctrl_radio_filt_vhd]:checked').val());\r
+ data.filter_vtoy = parseInt($('input:radio[name=id_ctrl_radio_filt_vtoy]:checked').val());\r
+\r
+ data.help_text_language = $('select[id=id_ctrl_sel_help_lang').val();\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ //VTOY_WIN11_BYPASS_CHECK\r
+ $('input:radio[name=id_ctrl_bypass_win11_radio]')[data.win11_bypass_check].checked = true;\r
+\r
+ //VTOY_DEFAULT_SEARCH_ROOT\r
+ $('input:text[id=id_ctrl_text_search_root]').val(data.default_search_root);\r
+ if (data.default_search_root.length === 0) {\r
+ $('div[id=id_ctrl_div_root_status]').hide();\r
+ } else {\r
+ $('div[id=id_ctrl_div_root_status]').show();\r
+ if (data.default_search_root_valid === 0) {\r
+ $('span[id=id_ctrl_span_search_root_valid]').hide();\r
+ $('span[id=id_ctrl_span_search_root_invalid]').show();\r
+ } else {\r
+ $('span[id=id_ctrl_span_search_root_valid]').show();\r
+ $('span[id=id_ctrl_span_search_root_invalid]').hide();\r
+ }\r
+ }\r
+\r
+ //VTOY_MENU_TIMEOUT\r
+ $('input:text[id=id_ctrl_text_timeout]').val(data.menu_timeout);\r
+\r
+\r
+ //VTOY_DEFAULT_IMAGE\r
+ $('input:text[id=id_ctrl_text_default_img]').val(data.default_image);\r
+ if (data.default_image.length === 0) {\r
+ $('div[id=id_ctrl_div_img_status]').hide();\r
+ } else {\r
+ $('div[id=id_ctrl_div_img_status]').show();\r
+ if (data.default_image_valid === 0) {\r
+ $('span[id=id_ctrl_span_img_valid]').hide();\r
+ $('span[id=id_ctrl_span_img_invalid]').show();\r
+ } else {\r
+ $('span[id=id_ctrl_span_img_valid]').show();\r
+ $('span[id=id_ctrl_span_img_invalid]').hide();\r
+ }\r
+ }\r
+\r
+ //VTOY_MAX_SEARCH_LEVEL\r
+ if (data.max_search_level >=0 && data.max_search_level <= 10) {\r
+ $('select[id=id_ctrl_sel_max_depth').val(data.max_search_level);\r
+ } else {\r
+ $('select[id=id_ctrl_sel_max_depth').val('max');\r
+ }\r
+\r
+ //VTOY_DEFAULT_KBD_LAYOUT\r
+ $('select[id=id_ctrl_sel_kbd').val(data.default_kbd_layout);\r
+\r
+ //VTOY_DEFAULT_MENU_MODE\r
+ $('input:radio[name=id_ctrl_radio_menu_mode]')[data.default_menu_mode].checked = true;\r
+\r
+ //VTOY_TREE_VIEW_MENU_STYLE\r
+ $('input:radio[name=id_ctrl_radio_treestyle]')[data.treeview_style].checked = true;\r
+\r
+ //VTOY_FILT_DOT_UNDERSCORE_FILE\r
+ $('input:radio[name=id_ctrl_radio_underscore]')[data.filter_dot_underscore].checked = true;\r
+\r
+ //VTOY_SORT_CASE_SENSITIVE\r
+ $('input:radio[name=id_ctrl_radio_casesensitive]')[data.sort_casesensitive].checked = true;\r
+\r
+ //VTOY_VHD_NO_WARNING\r
+ $('input:radio[name=id_ctrl_radio_vhd_warning]')[data.vhd_no_warning].checked = true;\r
+\r
+ //VTOY_FILE_FLT_ISO\r
+ $('input:radio[name=id_ctrl_radio_filt_iso]')[data.filter_iso].checked = true;\r
+\r
+ //VTOY_FILE_FLT_WIM\r
+ $('input:radio[name=id_ctrl_radio_filt_wim]')[data.filter_wim].checked = true;\r
+\r
+ //VTOY_FILE_FLT_EFI\r
+ $('input:radio[name=id_ctrl_radio_filt_efi]')[data.filter_efi].checked = true;\r
+\r
+ //VTOY_FILE_FLT_IMG\r
+ $('input:radio[name=id_ctrl_radio_filt_img]')[data.filter_img].checked = true;\r
+\r
+\r
+ //VTOY_FILE_FLT_VHD\r
+ $('input:radio[name=id_ctrl_radio_filt_vhd]')[data.filter_vhd].checked = true;\r
+\r
+\r
+ //VTOY_FILE_FLT_VTOY\r
+ $('input:radio[name=id_ctrl_radio_filt_vtoy]')[data.filter_vtoy].checked = true;\r
+\r
+ //VTOY_HELP_TXT_LANGUAGE\r
+ if ($("select[id=id_ctrl_sel_help_lang")[0].options.length === 0)\r
+ {\r
+ for (var i = 0; i < data.help_list.length; i++) {\r
+ var hlang = data.help_list[i];\r
+ var opt = '<option title="'+hlang+'">'+hlang+'</option>';\r
+ $('select[id=id_ctrl_sel_help_lang').append(opt);\r
+ }\r
+ }\r
+ \r
+ $('select[id=id_ctrl_sel_help_lang').val(data.help_text_language);\r
+ }\r
+\r
+ function VtoySaveCurrentPage() {\r
+ VtoyGetCurrentPageItem(m_data_control[current_tab_index]);\r
+ var data = m_data_control[current_tab_index];\r
+\r
+ callVtoy({\r
+ method : 'save_control',\r
+ index: current_tab_index,\r
+ win11_bypass_check: data.win11_bypass_check,\r
+ default_search_root: data.default_search_root,\r
+ menu_timeout: data.menu_timeout,\r
+ default_image: data.default_image,\r
+ max_search_level: data.max_search_level,\r
+ default_kbd_layout: data.default_kbd_layout,\r
+ default_menu_mode: data.default_menu_mode,\r
+ treeview_style: data.treeview_style,\r
+ filter_dot_underscore: data.filter_dot_underscore,\r
+ sort_casesensitive: data.sort_casesensitive,\r
+ vhd_no_warning: data.vhd_no_warning,\r
+ filter_iso: data.filter_iso,\r
+ filter_wim: data.filter_wim,\r
+ filter_efi: data.filter_efi,\r
+ filter_img: data.filter_img,\r
+ filter_vhd: data.filter_vhd,\r
+ filter_vtoy: data.filter_vtoy,\r
+ help_text_language: data.help_text_language\r
+ }, function(e) {\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_control[index]);\r
+ }\r
+\r
+ function OnSelectSearchRoot(root, extra) {\r
+ var path = root.substr(g_current_dir.length);\r
+ $('input:text[id=id_ctrl_text_search_root]').val(path);\r
+ if (path.length === 0) {\r
+ $('div[id=id_ctrl_div_root_status]').hide();\r
+ } else {\r
+ $('div[id=id_ctrl_div_root_status]').show();\r
+ $('span[id=id_ctrl_span_search_root_valid]').show();\r
+ $('span[id=id_ctrl_span_search_root_invalid]').hide();\r
+ }\r
+ VtoySaveCurrentPage();\r
+ }\r
+\r
+ function OnSelectDefaultImage(root, valid, extra) {\r
+ var path = root.substr(g_current_dir.length);\r
+ $('input:text[id=id_ctrl_text_default_img]').val(path);\r
+ if (path.length === 0) {\r
+ $('div[id=id_ctrl_div_img_status]').hide(); \r
+ } else {\r
+ $('div[id=id_ctrl_div_img_status]').show();\r
+ $('span[id=id_ctrl_span_img_valid]').show();\r
+ $('span[id=id_ctrl_span_img_invalid]').hide();\r
+ }\r
+ VtoySaveCurrentPage();\r
+ }\r
+\r
+ //Main process\r
+ var m_data_control;\r
+ var current_tab_index = 0;\r
+\r
+ callVtoySync({method : 'get_control'}, function(data) {\r
+ m_data_control = data;\r
+ });\r
+ \r
+ $('#id_ctrl_btn_sel_root').click(function() {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Windows' : "/ISO/Linux";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_SEARCH_ROOT,\r
+ "tip": g_current_dir + tip,\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+ VtoySelectDirPath(OnSelectSearchRoot, para);\r
+ });\r
+ \r
+ $('#id_ctrl_btn_clr_root').click(function() {\r
+ var old = $('input:text[id=id_ctrl_text_search_root]').val();\r
+ if (old.length != 0) {\r
+ $('input:text[id=id_ctrl_text_search_root]').val('');\r
+ $('div[id=id_ctrl_div_root_status]').hide();\r
+ VtoySaveCurrentPage();\r
+ }\r
+ });\r
+ \r
+ $('#id_ctrl_btn_default_img').click(function() {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Windows10_en.iso' : "/ISO/Windows10_en.iso";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_DEFAULT_IMAGE,\r
+ "fuzzy": 0,\r
+ "tip1": g_current_dir + tip,\r
+ "tip2": '',\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+ VtoySelectFilePath(OnSelectDefaultImage, para);\r
+ });\r
+\r
+ $('#id_ctrl_btn_clr_default').click(function() {\r
+ var old = $('input:text[id=id_ctrl_text_default_img]').val();\r
+ if (old.length != 0) {\r
+ $('input:text[id=id_ctrl_text_default_img]').val('');\r
+ $('div[id=id_ctrl_div_img_status]').hide();\r
+ VtoySaveCurrentPage();\r
+ }\r
+ });\r
+\r
+ $('input[type=radio]').each(function(){\r
+ var id = $(this).attr('id');\r
+ if (id.startsWith('id_ctrl')) {\r
+ $(this).change(VtoySaveCurrentPage);\r
+ }\r
+ });\r
+ $('select[id=id_ctrl_sel_max_depth]').change(VtoySaveCurrentPage);\r
+ $('select[id=id_ctrl_sel_kbd]').change(VtoySaveCurrentPage);\r
+ $('select[id=id_ctrl_sel_help_lang]').change(VtoySaveCurrentPage);\r
+ $('input[id=id_ctrl_text_timeout]').change(function() {\r
+ var value = $('input:text[id=id_ctrl_text_timeout]').val();\r
+ if (/^[0-9][0-9]*$/.test(value)) {\r
+ VtoySaveCurrentPage();\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_TIMEOUT);\r
+ $('input:text[id=id_ctrl_text_timeout]').val(m_data_control[current_tab_index].menu_timeout);\r
+ }\r
+ });\r
+\r
+ $('#id_tab_control a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_control a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_control a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_control a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_control a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_control a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_control a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_control[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+ $('button[id=id_btn_collapse]').click(function() {\r
+ $("button[data-widget='collapse'] i").each(function() {\r
+ if ($(this).hasClass('fa-minus')) {\r
+ $(this).click();\r
+ }\r
+ });\r
+ });\r
+\r
+ $('button[id=id_btn_expand]').click(function() {\r
+ $("button[data-widget='collapse'] i").each(function() {\r
+ if ($(this).hasClass('fa-plus')) {\r
+ $(this).click();\r
+ }\r
+ });\r
+ });\r
+\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-8" style="padding-top:8px;">\r
+ <i class="fa fa-paypal"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">捐助</h1>\r
+ </div> \r
+ </div>\r
+ <legend></legend>\r
+ <div class="box-body">\r
+ \r
+ <div id="id_donation_div_cn">\r
+ <p style="text-align:left;font-size:18px;color:#D01010;font-weight: bold;">\r
+ Ventoy是开源免费的,如果你愿意捐助来支持这个工具以及我的工作,我会非常感激。\r
+ </p>\r
+ <p style="text-align:left;font-size:16px;">\r
+ 你可以选择使用支付宝或微信进行捐助。\r
+ </p>\r
+ <div style="display:flex">\r
+ <div style="width:30%; text-align:center"> <img src="/static/img/AliPay.png?v=1" style="width:200px;height:200px;" ></img></div>\r
+ <div style="width:30%; text-align:center"> <img src="/static/img/WeChatPay.png?v=1" style="width:210px;height:210px;" ></img> </div>\r
+ </div>\r
+ </div>\r
+\r
+ <div id="id_donation_div_en">\r
+ <p style="text-align:left;font-size:18px;color:#D01010;font-weight: bold;">\r
+ It would be much appreciated if you want to make a small donation to support Ventoy!\r
+ </p>\r
+ <p style="text-align:left;font-size:16px;">\r
+ PayPal and Bitcoin are avaliable for donation. You can chose any of them. <br/><br/>\r
+ <span style="font-weight:bold;">PayPal Link </span><a target="_blank" href="https://www.paypal.me/ventoy">https://www.paypal.me/ventoy</a><br/><br/>\r
+ <span style="font-weight:bold;">PayPal Account <span style="color:blue; font-weight:bold;"> admin@ventoy.net</span></span><br/><br/>\r
+ <span style="font-weight:bold;">Bitcoin Address </span> <span style="color:blue; font-weight:bold;"> 19mZDWzZgzkHCi9YX9H3fYCUuCHq3W6wfT </span><br/>\r
+ </p>\r
+ </div>\r
+\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ \r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_DONATION);\r
+ if (newlang === 'en') {\r
+ \r
+ $('#id_donation_div_en').show();\r
+ $('#id_donation_div_cn').hide();\r
+ } else {\r
+ $('#id_donation_div_en').hide();\r
+ $('#id_donation_div_cn').show();\r
+ }\r
+ }\r
+\r
+ //Main process\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="glyphicon glyphicon-cd"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">x</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_dud.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_dud">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >dud</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">dud_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">dud_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">dud_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">dud_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">dud_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <table id="id_dud_tbl" class="table table-bordered" >\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 5%;">#</th>\r
+ <th id="id_th_persistence_set" style="width: 80%;"></th>\r
+ <th id="id_th_operation" style="width: 10%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_DUD);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ $("span[id=id_span_dir_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_EXIST);\r
+ });\r
+ \r
+ $("span[id=id_span_dir_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_NONEXIST);\r
+ });\r
+\r
+ $("th[id=id_th_dud_dat]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DUD_FILE);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_autoins_path').text('Absolute Path');\r
+ $('#id_th_persistence_set').text('Setting');\r
+ } else {\r
+ $('#id_th_autoins_path').text('绝对路径');\r
+ $('#id_th_persistence_set').text('设置');\r
+ \r
+ }\r
+ }\r
+ \r
+\r
+ function FillDudInnerTable(i, data) {\r
+ var td1, td2, td3, td4;\r
+ var inner = data.list;\r
+ var tabid = '#tbl_inner_' + (i + 1);\r
+ var $inner_tbl = $(tabid + ' tbody');\r
+\r
+ var inaddbtn = ventoy_get_xslg_addbtn('DudInnerAddBtn');\r
+ var indelbtn = ventoy_get_xslg_delbtn('DudInnerDelBtn');\r
+\r
+ $inner_tbl.empty();\r
+ \r
+ for (var j = 0; j < inner.length; j++) {\r
+ var $tr;\r
+ td1 = '<td style="width: 5%;">'+(j+1)+'</td>';\r
+ td2 = '<td>'+inner[j].path+'</td>';\r
+ td3 = '<td style="width: 10%;">'+ventoy_get_status_line(0, inner[j].valid)+'</td>';\r
+ td4 = '<td style="width: 10%;">' + indelbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + '</tr>');\r
+ $tr.data('path', inner[j].path);\r
+ $tr.data('index', j);\r
+ $tr.data('outpath', data.path);\r
+ $tr.data('outindex', i);\r
+\r
+ $inner_tbl.append($tr);\r
+ }\r
+\r
+ $tr = $('<tr><td></td><td></td><td></td><td>'+inaddbtn+'</td></tr>');\r
+ $tr.data('outpath', data.path);\r
+ $tr.data('outindex', i);\r
+\r
+ $inner_tbl.append($tr);\r
+ }\r
+\r
+ function FillDudTable(data) {\r
+ var td1, td2, td3, td4, td5;\r
+ var addbtn = ventoy_get_addbtn('DudAddBtn');\r
+ var delbtn = ventoy_get_delbtn('DudDelBtn');\r
+ \r
+ var $tbl = $("#id_dud_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+\r
+ var tdtbl1 ='<table class="table table-condensed">'+\r
+ '<tbody><tr>'+\r
+ '<td style="width:90%;vertical-align: middle;">' + data[i].path + '</td>' + \r
+ '<td style="vertical-align: middle;">' + ventoy_get_status_line(data[i].type, data[i].valid) + '</td>' +\r
+ '</tr>'+\r
+ '<tr><td></td><td></td></tr>'+\r
+ '</tbody></table>';\r
+\r
+ var tdtbl2 = '<table class="table table-bordered" id="tbl_inner_' + (i+1) + '">'+\r
+ '<thead><tr><th>#</th><th id="id_th_dud_dat">'+g_vtoy_cur_language.STR_DUD_FILE+'</th><th id="id_th_status">'+g_vtoy_cur_language.STR_STATUS+'</th><th id="id_th_operation">'+g_vtoy_cur_language.STR_OPERATION+'</th></tr></thead><tbody></tbody></table>';\r
+\r
+ td1 = '<td style="vertical-align: middle;">' + (i + 1) + '</td>';\r
+ td2 = '<td>' + tdtbl1 + tdtbl2 + '</td>';\r
+ td3 = '<td style="vertical-align: middle;text-align: center;">' + delbtn + '</td>';\r
+ $tr = $('<tr>' + td1 + td2 + td3 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td style="vertical-align: middle;text-align: center;">' + addbtn + '</td></tr>');\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ FillDudInnerTable(i, data[i]); \r
+ }\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillDudTable(data);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_dud[index]);\r
+ }\r
+\r
+ function AddDudEntry(type, exist1, path1, path2) {\r
+ var list = m_data_dud[current_tab_index];\r
+ var data_array = [\r
+ {\r
+ "path": "",\r
+ "valid": 1\r
+ }\r
+ ];\r
+ var call_array = [\r
+ ""\r
+ ];\r
+\r
+ call_array[0] = path2.substr(g_current_dir.length);\r
+ data_array[0].path = path2.substr(g_current_dir.length);\r
+\r
+ var data = {\r
+ "path": path1.substr(g_current_dir.length),\r
+ "list": data_array,\r
+ "type": type,\r
+ "valid": exist1\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'dud_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ dud: call_array,\r
+ type: type\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillDudTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAddImageDud(exist1, path1, path2) {\r
+ AddDudEntry(0, exist1, path1, path2);\r
+ }\r
+\r
+ function OnDudAddClick() {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\rhel-server-7.4-x86_64.iso' : "/ISO/rhel-server-7.4-x86_64.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\rhel-server-7.*-x86_64.iso' : "/ISO/rhel-server-7.*-x86_64.iso";\r
+ var tip3 = (g_current_os === 'windows') ? '\\ventoy\\dd.iso' : "/ventoy/dd.iso";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_DUD,\r
+ "label1": g_vtoy_cur_language.STR_FILE_PATH,\r
+ "label2": g_vtoy_cur_language.STR_SET_DUD_FILE,\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2,\r
+ "tip3": g_current_dir + tip3\r
+ };\r
+\r
+ VtoySetFileFile(OnAddImageDud, para);\r
+ }\r
+\r
+ function DudDelEntry(path, index) {\r
+ callVtoySync({\r
+ method : 'dud_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_dud[current_tab_index].splice(index, 1);\r
+ FillDudTable(m_data_dud[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnDudDelClick() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ DudDelEntry(path, index);\r
+ }\r
+ \r
+\r
+ var m_out_index;\r
+ var m_out_path;\r
+ function OnAddDudDatFile(root, valid, extra) {\r
+ var path = root.substr(g_current_dir.length);\r
+ var data = m_data_dud[current_tab_index][m_out_index];\r
+\r
+ for (var i = 0; i < data.list.length; i++) {\r
+ if (data.list[i].path === path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'dud_add_inner',\r
+ index: current_tab_index,\r
+ outpath: m_out_path,\r
+ path: path\r
+ }, function(e) {\r
+\r
+ var node = {\r
+ "path": path,\r
+ "valid": 1\r
+ };\r
+\r
+ data.list.push(node);\r
+ FillDudInnerTable(m_out_index, data);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ \r
+ }\r
+\r
+ function OnDudInnerAddClick() {\r
+ var $tr = $(this).closest('tr');\r
+ var outpath = $tr.data('outpath');\r
+ var outindex = $tr.data('outindex');\r
+\r
+ var tip = (g_current_os === 'windows') ? '\\ventoy\\dd.iso' : "/ventoy/dd.iso";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_ADD_DUD_FILE,\r
+ "fuzzy": 0,\r
+ "tip1": g_current_dir + tip,\r
+ "tip2": '',\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+\r
+ m_out_index = outindex;\r
+ m_out_path = outpath;\r
+ VtoySelectFilePath(OnAddDudDatFile, para);\r
+ }\r
+\r
+ function DudDelInnerEntry(outpath, outindex, path, index) {\r
+ callVtoy({\r
+ method : 'dud_del_inner',\r
+ index: current_tab_index,\r
+ outpath: outpath,\r
+ path: path\r
+ }, function(e) {\r
+ var data = m_data_dud[current_tab_index][outindex];\r
+\r
+ data.list.splice(index, 1);\r
+ FillDudInnerTable(outindex, m_data_dud[current_tab_index][outindex]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnDudInnerDelClick() {\r
+ var $tr = $(this).closest('tr');\r
+\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+ var outpath = $tr.data('outpath');\r
+ var outindex = $tr.data('outindex');\r
+\r
+ var list = m_data_dud[current_tab_index][outindex].list;\r
+\r
+ if (list.length === 1) {\r
+ ventoy_confirm(g_vtoy_cur_language.STR_DEL_LAST, DudDelEntry, outpath, outindex);\r
+ } else {\r
+ DudDelInnerEntry(outpath, outindex, path, index);\r
+ }\r
+ }\r
+\r
+\r
+\r
+\r
+\r
+ //Main process\r
+ var m_data_dud;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_dud'}, function(data) {\r
+ m_data_dud = data;\r
+ });\r
+ \r
+ $("#id_dud_tbl").on('click', '.DudAddBtn', OnDudAddClick);\r
+ $("#id_dud_tbl").on('click', '.DudDelBtn', OnDudDelClick);\r
+ $("#id_dud_tbl").on('click', '.DudInnerAddBtn', OnDudInnerAddClick);\r
+ $("#id_dud_tbl").on('click', '.DudInnerDelBtn', OnDudInnerDelClick);\r
+\r
+ $('#id_tab_dud a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_dud a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_dud a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_dud a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_dud a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_dud a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_dud a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_dud[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-list-alt"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title"></h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_imagelist.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_image_list">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >image_list</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">image_list_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">image_list_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">image_list_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">image_list_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">image_list_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 id="id_image_list_mode" class="box-title" style="font-size: 14px;font-weight: bold;">Mode</h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_image_list_type0" name="id_image_list_type" data-type="0" value="0"> \r
+ <span id="id_span_image_list_permit" style="font-weight:bold;">0</span>\r
+ </label>\r
+ <label class="radio-inline">\r
+ <input type="radio" id="id_image_list_type1" name="id_image_list_type" data-type="1" value="1"> \r
+ <span id="id_span_image_list_deny" style="font-weight:bold;">1</span>\r
+ </label>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col" id="td_title_desc">选项说明</td>\r
+ <td>\r
+ <span style="font-weight: bold;">白名单模式</span><br/>\r
+ 由用户自己列出文件列表,Ventoy 不再搜索而是直接使用你给出的文件列表。 同时 Ventoy 也不再对文件进行排序,而是直接按照列表给出的文件顺序来显示启动菜单。<br/>\r
+ <span style="font-weight: bold;">黑名单模式</span><br/>\r
+ Ventoy 首先还是像原来一样搜索,最后再从搜索结果中剔除这个列表中的文件。<br/>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ <span style="font-weight: bold;">Permit Mode</span><br/>\r
+ Ventoy will no longer search for the files but just use your file list. Also, Ventoy will NOT sort these files anymore, but directly display the boot menu according to the order given in the list.<br/>\r
+ <span style="font-weight: bold;">Deny Mode</span><br/>\r
+ Firstly, Ventoy will search as normal. And then remove the files in the blacklist from the search result.<br/>\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 id="id_image_list_list" class="box-title" style="font-size: 14px;font-weight: bold;">List</h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table id="id_image_list_tbl" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 5%;">#</th>\r
+ <th id="id_th_imglist_path" style="width: 60%;"></th>\r
+ <th id="id_th_status" style="width: 10%;"></th>\r
+ <th id="id_th_operation" style="width: 10%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_IMAGELIST);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('h3[id=id_image_list_mode]').text('Mode');\r
+ $('h3[id=id_image_list_list]').text('List');\r
+ $('#id_th_imglist_path').text('Absolute Path');\r
+ $('span[id=id_span_image_list_permit]').text('Permit');\r
+ $('span[id=id_span_image_list_deny]').text('Deny');\r
+ } else {\r
+ $('h3[id=id_image_list_mode]').text('模式');\r
+ $('h3[id=id_image_list_list]').text('列表');\r
+ $('#id_th_imglist_path').text('绝对路径');\r
+ $('span[id=id_span_image_list_permit]').text('白名单模式');\r
+ $('span[id=id_span_image_list_deny]').text('黑名单模式');\r
+ }\r
+ }\r
+ \r
+ function FillImageListTable(data) {\r
+ var fileexist = ventoy_get_status_line(0, 1);\r
+ var filenonexist = ventoy_get_status_line(0, 0);\r
+ var filenfuzzy = ventoy_get_status_line(0, -1);\r
+\r
+ var addbtn = ventoy_get_xslg_addbtn('ImageListAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('ImageListDelBtn');\r
+\r
+ var td1, td2, td3, td4;\r
+ var $tbl = $("#id_image_list_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = '<td>' + data[i].path + '</td>';\r
+ td3 = '<td>' + ventoy_get_status_line(0, data[i].valid) + '</td>';\r
+ td4 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ $('input:radio[name=id_image_list_type]')[data.type].checked = true;\r
+ FillImageListTable(data.list);\r
+ }\r
+\r
+ function VtoySaveCurrentPage() {\r
+ var data = m_data_imagelist[current_tab_index];\r
+\r
+ data.type = parseInt($('input:radio[name=id_image_list_type]:checked').val());\r
+\r
+ callVtoy({\r
+ method : 'save_image_list',\r
+ index: current_tab_index,\r
+ type: data.type\r
+ }, function(e) {\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ $('input[type=radio]').each(function(){\r
+ var id = $(this).attr('id');\r
+ if (id.startsWith('id_image_list_type')) {\r
+ $(this).change(VtoySaveCurrentPage);\r
+ }\r
+ });\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_imagelist[index]);\r
+ }\r
+\r
+ //Main process\r
+ var m_data_imagelist;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_image_list'}, function(data) {\r
+ m_data_imagelist = data;\r
+ });\r
+ \r
+ function OnAddImageList(root, valid, extra) {\r
+ var list = m_data_imagelist[current_tab_index].list;\r
+ var data = {\r
+ "path": root.substr(g_current_dir.length),\r
+ "valid": valid\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'image_list_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillImageListTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ $("#id_image_list_tbl").on('click', '.ImageListAddBtn', function() {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\Windows11.iso' : "/ISO/Ubuntu-20.04-desktop-amd64.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\Windows**.iso' : "/ISO/Ubuntu-*****-desktop-amd64.iso";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_ADD_FILE_TO_LIST,\r
+ "fuzzy": 1,\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2,\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+ VtoySelectFilePath(OnAddImageList, para);\r
+ });\r
+\r
+ $("#id_image_list_tbl").on('click', '.ImageListDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'image_list_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_imagelist[current_tab_index].list.splice(index, 1);\r
+ FillImageListTable(m_data_imagelist[current_tab_index].list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+ $('#id_tab_image_list a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_image_list a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_image_list a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_image_list a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_image_list a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_image_list a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_image_list a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_imagelist[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-plus-circle"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">x</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_injection.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_injection">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >injection</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">injection_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">injection_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">injection_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">injection_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">injection_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <table id="id_injection_tbl" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 2%;">#</th>\r
+ <th id="id_th_injection_type" style="width: 5%;"></th>\r
+ <th id="id_th_injection_path" style="width: 35%;"></th>\r
+ <th id="id_th_status" style="width: 5%;"></th>\r
+ <th id="id_th_injection_archive" style="width: 40%;"></th>\r
+ <th id="id_th_status" style="width: 5%;"></th> \r
+ <th id="id_th_operation" style="width: 5%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_INJECTION);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ $("span[id=id_span_dir_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_EXIST);\r
+ });\r
+ \r
+ $("span[id=id_span_dir_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_NONEXIST);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_injection_path').text('Absolute Path');\r
+ $('#id_th_injection_archive').text('Archive');\r
+ $('#id_th_injection_type').text('Type');\r
+ } else {\r
+ $('#id_th_injection_path').text('绝对路径');\r
+ $('#id_th_injection_archive').text('注入文件');\r
+ $('#id_th_injection_type').text('类型');\r
+ \r
+ }\r
+ }\r
+ \r
+ function FillInjectionTable(data) {\r
+ var addbtn = ventoy_get_xslg_addbtn('InjectionAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('InjectionDelBtn');\r
+\r
+ var td1, td2, td3, td4, td5, td6, td7;\r
+ var $tbl = $("#id_injection_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = (data[i].type === 0) ? '<td>image</td>' : '<td>parent</td>';\r
+ td3 = '<td>' + data[i].path + '</td>';\r
+ td4 = '<td>' + ventoy_get_status_line(data[i].type, data[i].valid) + '</td>';\r
+ td5 = '<td>' + data[i].archive + '</td>'; \r
+ td6 = '<td>' + ventoy_get_status_line(0, data[i].archive_valid) + '</td>';\r
+ td7 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + td5 + td6 + td7 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillInjectionTable(data);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_injection[index]);\r
+ }\r
+\r
+ //Main process\r
+ var m_injection_root;\r
+ var m_injection_extra;\r
+ var m_injection_valid;\r
+ var m_data_injection;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_injection'}, function(data) {\r
+ m_data_injection = data;\r
+ });\r
+ \r
+\r
+ function AddInjectionEntry(root, type, valid, extra) {\r
+ var list = m_data_injection[current_tab_index];\r
+ var data = {\r
+ "path": root.substr(g_current_dir.length),\r
+ "archive": extra.substr(g_current_dir.length),\r
+ "type": type,\r
+ "valid": valid,\r
+ "archive_valid": 1\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'injection_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ archive: data.archive,\r
+ type: type\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillInjectionTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAddImageInjection(exist1, path1, path2) {\r
+ AddInjectionEntry(path1, 0, exist1, path2);\r
+ }\r
+\r
+ function OnAddDirInjection(path1, path2) {\r
+ AddInjectionEntry(path1, 1, 1, path2);\r
+ }\r
+\r
+ function OnAddInjectionBtnClick(sel) {\r
+ var tip3 = (g_current_os === 'windows') ? '\\ISO\\injection.zip' : "/ISO/injection.tar.gz";\r
+ if (sel === 0) {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\Windows11.iso' : "/ISO/Ubuntu-20.04-desktop-amd64.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\Windows**.iso' : "/ISO/Ubuntu-*****-desktop-amd64.iso";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_INJECTION,\r
+ "label1": g_vtoy_cur_language.STR_FILE_PATH,\r
+ "label2": 'Archive',\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2,\r
+ "tip3": g_current_dir + tip3\r
+ };\r
+ VtoySetFileFile(OnAddImageInjection, para);\r
+ } else {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Windows' : "/ISO/Linux"; \r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_INJECTION,\r
+ "label1": g_vtoy_cur_language.STR_DIR_PATH,\r
+ "label2": 'Archive',\r
+ "tip1": g_current_dir + tip,\r
+ "tip2": g_current_dir + tip3\r
+ };\r
+ VtoySetDirFile(OnAddDirInjection, para);\r
+ }\r
+ }\r
+\r
+ $("#id_injection_tbl").on('click', '.InjectionAddBtn', function() {\r
+ var para = [\r
+ {\r
+ "selected": true,\r
+ "tip": g_vtoy_cur_language.STR_SET_INJECTION_FOR_FILE\r
+ },\r
+ {\r
+ "selected": false,\r
+ "tip": g_vtoy_cur_language.STR_SET_INJECTION_FOR_DIR\r
+ }\r
+ ];\r
+\r
+ VtoySelectType(OnAddInjectionBtnClick, para);\r
+ });\r
+\r
+ $("#id_injection_tbl").on('click', '.InjectionDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'injection_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_injection[current_tab_index].splice(index, 1);\r
+ FillInjectionTable(m_data_injection[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+\r
+\r
+\r
+ $('#id_tab_injection a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_injection a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_injection a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_injection a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_injection a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_injection a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_injection a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_injection[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="main">\r
+ <div class="box-header">\r
+ <i class="fa fa-bank"></i>\r
+ <h1 class="box-title" id="id_h1_page_title">设备信息</h1>\r
+ </div>\r
+ <div class="box-body"> \r
+\r
+ <div class="col-sm-4">\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;" id="id_dev_lang0">设备硬件信息</h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+\r
+ <table class="table table-striped no-padding" id="sysinfo-table" style="font-weight:bold;">\r
+ <tr>\r
+ <td id="id_dev_lang1"></td>\r
+ <td id="id_dev_name"></td>\r
+ </tr> \r
+ <tr>\r
+ <td id="id_dev_lang2"></td>\r
+ <td id="id_dev_capacity"></td>\r
+ </tr>\r
+ <tr>\r
+ <td id="id_dev_lang3"></td>\r
+ <td id="id_dev_fs"></td>\r
+ </tr> \r
+ </table>\r
+ \r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ </div>\r
+ \r
+ \r
+ \r
+ <div class="col-sm-4">\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;" id="id_dev_lang4">设备内 Ventoy 信息</h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+\r
+ <table class="table table-striped no-padding" id="custom-table" style="font-weight:bold;">\r
+ <tr >\r
+ <td id="id_dev_lang5">Ventoy</td>\r
+ <td id="id_ventoy_ver"></td>\r
+ </tr>\r
+ <tr>\r
+ <td id="id_dev_lang6"></td>\r
+ <td id="id_part_style"></td>\r
+ </tr>\r
+ <tr>\r
+ <td id="id_dev_lang7"></td>\r
+ <td id="id_secure_boot">开启</td>\r
+ </tr>\r
+ \r
+ </table>\r
+ \r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ </div>\r
+\r
+ </div>\r
+ \r
+</div>\r
+<script type="text/javascript">\r
+\r
+ var device_language_cn = \r
+ [\r
+ "设备硬件信息",\r
+ "设备名称",\r
+ "设备容量",\r
+ "文件系统",\r
+ "设备内 Ventoy 信息",\r
+ "Ventoy 版本号",\r
+ "分区类型",\r
+ "安全启动支持"\r
+ ];\r
+\r
+ var device_language_en = \r
+ [\r
+ "Device Hardware Information",\r
+ "Device Name",\r
+ "Device Capacity",\r
+ "File System",\r
+ "Device Ventoy Information",\r
+ "Ventoy Version",\r
+ "Partition Style",\r
+ "Secure Boot Support"\r
+ ];\r
+\r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ \r
+ $("h1[id=id_h1_page_title]").text(g_vtoy_cur_language.STR_PLUG_DEVICE);\r
+\r
+ for (i = 0; i <= 7; i++) {\r
+ var id = '#id_dev_lang' + i;\r
+ if (newlang === 'en') {\r
+ $(id).text(device_language_en[i]);\r
+ } else {\r
+ $(id).text(device_language_cn[i]);\r
+ }\r
+ }\r
+ }\r
+\r
+ //Main process\r
+ VtoyPageLanguageChange(g_current_language);\r
+ \r
+ callVtoySync({\r
+ method : 'device_info'\r
+ }, function(data) {\r
+ $('#id_dev_name').text(data.dev_name);\r
+ $('#id_dev_capacity').text(data.dev_capacity);\r
+ $('#id_dev_fs').text(data.dev_fs);\r
+ $('#id_ventoy_ver').text(data.ventoy_ver);\r
+ $('#id_part_style').text(data.part_style === 0 ? "MBR" : "GPT");\r
+ $('#id_secure_boot').text(data.secure_boot ? g_vtoy_cur_language.STR_SECURE_BOOT_ENABLE : g_vtoy_cur_language.STR_SECURE_BOOT_DISABLE);\r
+ });\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-clone"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">菜单别名插件</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_menualias.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_menu_alias">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >menu_alias</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_alias_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_alias_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_alias_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_alias_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_alias_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <table id="id_alisa_tbl" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 2%;">#</th>\r
+ <th id="id_th_alias_type" style="width: 5%;"></th>\r
+ <th id="id_th_alias_path" style="width: 35%;"></th>\r
+ <th id="id_th_status" style="width: 5%;"></th>\r
+ <th id="id_th_alias_alias" style="width: 40%;"></th>\r
+ <th id="id_th_operation" style="width: 5%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_ALIAS);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ $("span[id=id_span_dir_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_EXIST);\r
+ });\r
+ \r
+ $("span[id=id_span_dir_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_NONEXIST);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_alias_path').text('Absolute Path');\r
+ $('#id_th_alias_alias').text('Alias');\r
+ $('#id_th_alias_type').text('Type');\r
+ } else {\r
+ $('#id_th_alias_path').text('绝对路径');\r
+ $('#id_th_alias_alias').text('别名');\r
+ $('#id_th_alias_type').text('类型');\r
+ \r
+ }\r
+ }\r
+ \r
+ function FillAliasTable(data) {\r
+ var addbtn = ventoy_get_xslg_addbtn('AliasAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('AliasDelBtn');\r
+\r
+ var td1, td2, td3, td4, td5, td6;\r
+ var $tbl = $("#id_alisa_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = (data[i].type === 0) ? '<td>image</td>' : '<td>dir</td>';\r
+ td3 = '<td>' + data[i].path + '</td>';\r
+ td4 = '<td>' + ventoy_get_status_line(data[i].type, data[i].valid) + '</td>';\r
+ td5 = '<td>' + data[i].alias + '</td>';\r
+ td6 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + td5 + td6 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillAliasTable(data);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_alias[index]);\r
+ }\r
+\r
+ //Main process\r
+ var m_data_alias;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_alias'}, function(data) {\r
+ m_data_alias = data;\r
+ });\r
+ \r
+\r
+ function AddAliasEntry(root, type, valid, extra) {\r
+ var list = m_data_alias[current_tab_index];\r
+ var data = {\r
+ "path": root.substr(g_current_dir.length),\r
+ "alias": extra,\r
+ "type": type,\r
+ "valid": valid\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'alias_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ alias: data.alias,\r
+ type: type\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillAliasTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAddImageAlias(root, valid, extra) {\r
+ AddAliasEntry(root, 0, valid, extra);\r
+ }\r
+\r
+ function OnAddDirAlias(root, extra) {\r
+ AddAliasEntry(root, 1, 1, extra);\r
+ }\r
+\r
+ function OnAddAliasBtnClick(sel) {\r
+ if (sel === 0) {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\Windows11.iso' : "/ISO/Ubuntu-20.04-desktop-amd64.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\Windows**.iso' : "/ISO/Ubuntu-*****-desktop-amd64.iso";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_ALIAS,\r
+ "fuzzy": 1,\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2,\r
+ "tip3": '',\r
+ "extra": true,\r
+ "extra_title": g_vtoy_cur_language.STR_ALIAS\r
+ };\r
+ VtoySelectFilePath(OnAddImageAlias, para);\r
+ } else {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Windows' : "/ISO/Linux";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_ALIAS,\r
+ "tip": g_current_dir + tip,\r
+ "tip3": '',\r
+ "extra": true,\r
+ "extra_title": g_vtoy_cur_language.STR_ALIAS\r
+ };\r
+ VtoySelectDirPath(OnAddDirAlias, para);\r
+ }\r
+ }\r
+\r
+ $("#id_alisa_tbl").on('click', '.AliasAddBtn', function() {\r
+ var para = [\r
+ {\r
+ "selected": true,\r
+ "tip": g_vtoy_cur_language.STR_SET_ALIAS_FOR_FILE\r
+ },\r
+ {\r
+ "selected": false,\r
+ "tip": g_vtoy_cur_language.STR_SET_ALIAS_FOR_DIR\r
+ }\r
+ ];\r
+\r
+ VtoySelectType(OnAddAliasBtnClick, para);\r
+ });\r
+\r
+ $("#id_alisa_tbl").on('click', '.AliasDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'alias_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_alias[current_tab_index].splice(index, 1);\r
+ FillAliasTable(m_data_alias[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+\r
+\r
+\r
+ $('#id_tab_menu_alias a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_alias a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_alias a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_alias a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_alias a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_alias a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_menu_alias a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_alias[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-list-ul"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">xx</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_menuclass.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_menu_class">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >menu_class</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_class_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_class_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_class_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_class_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_class_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <table id="id_class_tbl" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 2%;">#</th>\r
+ <th id="id_th_class_type" style="width: 5%;"></th>\r
+ <th id="id_th_class_path" style="width: 35%;"></th>\r
+ <th id="id_th_status" style="width: 5%;"></th>\r
+ <th id="id_th_class_class" style="width: 40%;"></th>\r
+ <th id="id_th_operation" style="width: 5%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_CLASS);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ $("span[id=id_span_dir_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_EXIST);\r
+ });\r
+ \r
+ $("span[id=id_span_dir_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_NONEXIST);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_class_path').text('Key/Absolute Path');\r
+ $('#id_th_class_class').text('Menu Class');\r
+ $('#id_th_class_type').text('Type');\r
+ } else {\r
+ $('#id_th_class_path').text('关键字/绝对路径');\r
+ $('#id_th_class_class').text('菜单类型');\r
+ $('#id_th_class_type').text('类型');\r
+ \r
+ }\r
+ }\r
+ \r
+ function FillClassTable(data) {\r
+ \r
+ var direxist = ventoy_get_status_line(1, 1);\r
+ var dirnonexist = ventoy_get_status_line(1, 0);\r
+\r
+ var addbtn = ventoy_get_xslg_addbtn('ClassAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('ClassDelBtn');\r
+\r
+ var td1, td2, td3, td4, td5, td6;\r
+ var $tbl = $("#id_class_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+\r
+ td3 = '<td>' + data[i].path + '</td>';\r
+ if (data[i].type === 0) {\r
+ td2 = '<td>key</td>';\r
+ td4 = '<td></td>';\r
+ } else {\r
+ if (data[i].type === 1) {\r
+ td2 = '<td>dir</td>';\r
+ } else {\r
+ td2 = '<td>parent</td>';\r
+ }\r
+ \r
+ if (data[i].valid === 0) {\r
+ td4 = '<td>' + dirnonexist + '</td>';\r
+ } else {\r
+ td4 = '<td>' + direxist + '</td>';\r
+ }\r
+ }\r
+\r
+ td5 = '<td>' + data[i].class + '</td>';\r
+ td6 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + td5 + td6 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillClassTable(data);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_class[index]);\r
+ }\r
+\r
+ //Main process\r
+ var m_data_class;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_class'}, function(data) {\r
+ m_data_class = data;\r
+ });\r
+ \r
+\r
+ function AddClassEntry(root, type, valid, extra) {\r
+ var list = m_data_class[current_tab_index];\r
+ var data = {\r
+ "path": '',\r
+ "class": extra,\r
+ "type": type,\r
+ "valid": valid\r
+ };\r
+\r
+ if (type === 0) {\r
+ data.path = root;\r
+ } else {\r
+ data.path = root.substr(g_current_dir.length);\r
+ }\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ if (extra.indexOf("\"") >= 0) {\r
+ Message.error(g_current_language === 'en' ? "Class can not contains double quotes." : "Class 不能包含双引号。");\r
+ return;\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'class_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ class: data.class,\r
+ type: type\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillClassTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAddKeyClass(key, value) {\r
+ AddClassEntry(key, 0, 1, value);\r
+ }\r
+\r
+ function OnAddDirClassDir(root, extra) {\r
+ AddClassEntry(root, 1, 1, extra);\r
+ }\r
+ function OnAddDirClassParent(root, extra) {\r
+ AddClassEntry(root, 2, 1, extra);\r
+ }\r
+\r
+ function OnAddClassBtnClick(sel) {\r
+ if (sel === 0) {\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_CLASS,\r
+ "title1": "Key",\r
+ "title2": g_vtoy_cur_language.STR_CLASS\r
+ };\r
+\r
+ VtoySetKey(OnAddKeyClass, para);\r
+ } else {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Windows' : "/ISO/Linux";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_CLASS,\r
+ "tip": g_current_dir + tip,\r
+ "tip3": '',\r
+ "extra": true,\r
+ "extra_title": g_vtoy_cur_language.STR_CLASS\r
+ };\r
+\r
+ if (sel === 1) {\r
+ VtoySelectDirPath(OnAddDirClassDir, para);\r
+ } else {\r
+ VtoySelectDirPath(OnAddDirClassParent, para);\r
+ }\r
+ \r
+ }\r
+ }\r
+\r
+ $("#id_class_tbl").on('click', '.ClassAddBtn', function() {\r
+ var para = [\r
+ {\r
+ "selected": true,\r
+ "tip": g_vtoy_cur_language.STR_SET_CLASS_BY_KEY\r
+ },\r
+ {\r
+ "selected": false,\r
+ "tip": g_vtoy_cur_language.STR_SET_CLASS_BY_DIR\r
+ },\r
+ {\r
+ "selected": false,\r
+ "tip": g_vtoy_cur_language.STR_SET_CLASS_BY_PARENT\r
+ }\r
+ ];\r
+\r
+ VtoySelectType(OnAddClassBtnClick, para);\r
+ });\r
+\r
+ $("#id_class_tbl").on('click', '.ClassDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'class_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_class[current_tab_index].splice(index, 1);\r
+ FillClassTable(m_data_class[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+\r
+\r
+\r
+ $('#id_tab_menu_class a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_class a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_class a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_class a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_class a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_class a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_menu_class a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_class[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-commenting"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title"></h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_menutip.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_menu_tip">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >menu_tip</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_tip_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_tip_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_tip_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_tip_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">menu_tip_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">Menu Tips\r
+ <span id="id_span_desc_cn"> —— 菜单提示信息</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table id="id_tip_tbl" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 2%;">#</th>\r
+ <th id="id_th_tip_type" style="width: 5%;"></th>\r
+ <th id="id_th_tip_path" style="width: 35%;"></th>\r
+ <th id="id_th_status" style="width: 5%;"></th>\r
+ <th id="id_th_tip_tip" style="width: 40%;"></th>\r
+ <th id="id_th_operation" style="width: 5%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+ </div>\r
+ <br/><br/>\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">Tip Style\r
+ <span id="id_span_desc_cn"> —— 提示信息显示位置</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table id="id_tip_style" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th id="id_th_tip_opt" style="width: 10%;"></th>\r
+ <th id="id_th_tip_set" style="width: 20%;"></th>\r
+ <th id="id_th_tip_notes" style="width: 70%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ <tr>\r
+ <td>left</td>\r
+ <td>\r
+ <input type="text" class="form-control" id="id_tip_text_left"/>\r
+ </td>\r
+ <td>\r
+ <span id="id_span_desc_cn">提示信息显示的 X 坐标百分比(相对于左上角)</span>\r
+ <span id="id_span_desc_en">X position of the tip message. (Percentage form relative to the upper left corner)</span>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>top</td>\r
+ <td>\r
+ <input type="text" class="form-control" id="id_tip_text_top"/>\r
+ </td>\r
+ <td>\r
+ <span id="id_span_desc_cn">提示信息显示的 Y 坐标百分比(相对于左上角)</span>\r
+ <span id="id_span_desc_en">Y position of the tip message. (Percentage form relative to the upper left corner)</span>\r
+ </td>\r
+ </tr>\r
+ <tr>\r
+ <td>color</td>\r
+ <td>\r
+ <input type="text" class="form-control" id="id_tip_text_color"/>\r
+ </td>\r
+ <td>\r
+ <span id="id_span_desc_cn">提示信息的颜色。可以是 <code>blue/red/green/...</code> 等这种格式,也可以设置为 <code>#00ff00</code> 这种格式。</span>\r
+ <span id="id_span_desc_en">Color of the tip message. Can be in <code>blue/red/green/...</code> or <code>#00ff00</code> format.</span>\r
+ </td>\r
+ </tr>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+ </div>\r
+\r
+\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_TIP);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ $("span[id=id_span_dir_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_EXIST);\r
+ });\r
+ \r
+ $("span[id=id_span_dir_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_NONEXIST);\r
+ });\r
+\r
+ \r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_tip_path').text('Absolute Path');\r
+ $('#id_th_tip_tip').text('Tip');\r
+ $('#id_th_tip_type').text('Type');\r
+ $("th[id=id_th_tip_opt]").text('Option');\r
+ $("th[id=id_th_tip_set]").text('Setting');\r
+ $("th[id=id_th_tip_notes]").text('Notes');\r
+\r
+ $("span[id=id_span_desc_cn]").each(function(){\r
+ $(this).hide();\r
+ });\r
+ $("span[id=id_span_desc_en]").each(function(){\r
+ $(this).show();\r
+ });\r
+ } else {\r
+ $('#id_th_tip_path').text('绝对路径');\r
+ $('#id_th_tip_tip').text('提示');\r
+ $('#id_th_tip_type').text('类型');\r
+ $("th[id=id_th_tip_opt]").text('选项');\r
+ $("th[id=id_th_tip_set]").text('设置');\r
+ $("th[id=id_th_tip_notes]").text('说明');\r
+ $("span[id=id_span_desc_en]").each(function(){\r
+ $(this).hide();\r
+ });\r
+ $("span[id=id_span_desc_cn]").each(function(){\r
+ $(this).show();\r
+ });\r
+ }\r
+ }\r
+ \r
+ function FillTipTable(data) {\r
+ var addbtn = ventoy_get_xslg_addbtn('TipAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('TipDelBtn');\r
+\r
+ var td1, td2, td3, td4, td5, td6;\r
+ var $tbl = $("#id_tip_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = (data[i].type === 0) ? '<td>image</td>' : '<td>dir</td>';\r
+ td3 = '<td>' + data[i].path + '</td>';\r
+ td4 = '<td>' + ventoy_get_status_line(data[i].type, data[i].valid) + '</td>';\r
+ td5 = '<td>' + data[i].tip + '</td>';\r
+ td6 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + td5 + td6 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+\r
+ $('input:text[id=id_tip_text_left]').val(data.left);\r
+ $('input:text[id=id_tip_text_top]').val(data.top);\r
+ $('input:text[id=id_tip_text_color]').val(data.color);\r
+\r
+ FillTipTable(data.tips);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_tip[index].tips);\r
+ }\r
+\r
+ //Main process\r
+ var m_data_tip;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_tip'}, function(data) {\r
+ m_data_tip = data;\r
+ });\r
+ \r
+\r
+ function AddTipEntry(root, type, valid, extra) {\r
+ var list = m_data_tip[current_tab_index].tips;\r
+ var data = {\r
+ "path": root.substr(g_current_dir.length),\r
+ "tip": extra,\r
+ "type": type,\r
+ "valid": valid\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'tip_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ tip: data.tip,\r
+ type: type\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillTipTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAddImageTip(root, valid, extra) {\r
+ AddTipEntry(root, 0, valid, extra);\r
+ }\r
+\r
+ function OnAddDirTip(root, extra) {\r
+ AddTipEntry(root, 1, 1, extra);\r
+ }\r
+\r
+ function OnAddTipBtnClick(sel) {\r
+ if (sel === 0) {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\Windows11.iso' : "/ISO/Ubuntu-20.04-desktop-amd64.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\Windows**.iso' : "/ISO/Ubuntu-*****-desktop-amd64.iso";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_TIP,\r
+ "fuzzy": 1,\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2,\r
+ "tip3": '',\r
+ "extra": true,\r
+ "extra_title": g_vtoy_cur_language.STR_TIP\r
+ };\r
+ VtoySelectFilePath(OnAddImageTip, para);\r
+ } else {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Windows' : "/ISO/Linux";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_TIP,\r
+ "tip": g_current_dir + tip,\r
+ "tip3": '',\r
+ "extra": true,\r
+ "extra_title": g_vtoy_cur_language.STR_TIP\r
+ };\r
+ VtoySelectDirPath(OnAddDirTip, para);\r
+ }\r
+ }\r
+\r
+ $("#id_tip_tbl").on('click', '.TipAddBtn', function() {\r
+ var para = [\r
+ {\r
+ "selected": true,\r
+ "tip": g_vtoy_cur_language.STR_SET_TIP_FOR_FILE\r
+ },\r
+ {\r
+ "selected": false,\r
+ "tip": g_vtoy_cur_language.STR_SET_TIP_FOR_DIR\r
+ }\r
+ ];\r
+\r
+ VtoySelectType(OnAddTipBtnClick, para);\r
+ });\r
+\r
+ $("#id_tip_tbl").on('click', '.TipDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'tip_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_tip[current_tab_index].tips.splice(index, 1);\r
+ FillTipTable(m_data_tip[current_tab_index].tips);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+ function VtoySaveCurrentPage() {\r
+ var left = $('input:text[id=id_tip_text_left]').val();\r
+ var top = $('input:text[id=id_tip_text_top]').val();\r
+ var color = $('input:text[id=id_tip_text_color]').val();\r
+\r
+ callVtoy({\r
+ method : 'save_tip',\r
+ index: current_tab_index,\r
+ left: left, \r
+ top: top,\r
+ color: color\r
+ }, function(e) {\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ $('input:text[id=id_tip_text_left]').change(function() {\r
+ var value = $('input:text[id=id_tip_text_left]').val();\r
+ if (ventoy_check_percent(value)) {\r
+ VtoySaveCurrentPage();\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_PERCENT);\r
+ $('input:text[id=id_tip_text_left]').val(m_data_tip[current_tab_index].left);\r
+ }\r
+ });\r
+ $('input:text[id=id_tip_text_top]').change(function() {\r
+ var value = $('input:text[id=id_tip_text_top]').val();\r
+ if (ventoy_check_percent(value)) {\r
+ VtoySaveCurrentPage();\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_PERCENT);\r
+ $('input:text[id=id_tip_text_top]').val(m_data_tip[current_tab_index].top);\r
+ }\r
+ });\r
+ $('input:text[id=id_tip_text_color]').change(function() {\r
+ var value = $('input:text[id=id_tip_text_color]').val();\r
+ if (value.length > 0) {\r
+ if (ventoy_check_color(value)) {\r
+ VtoySaveCurrentPage();\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_COLOR);\r
+ $('input:text[id=id_tip_text_color]').val(m_data_tip[current_tab_index].color);\r
+ }\r
+ } else {\r
+ $('input:text[id=id_tip_text_color]').val(m_data_tip[current_tab_index].color);\r
+ }\r
+ });\r
+\r
+\r
+ $('#id_tab_menu_tip a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_tip a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_tip a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_tip a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_tip a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_menu_tip a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_menu_tip a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_tip[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="glyphicon glyphicon-lock"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title"></h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_password.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_password">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >password</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">password_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">password_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">password_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">password_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">password_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">Common Password\r
+ <span id="id_span_desc_cn"> —— 通用密码</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table id="id_common_pwd" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th id="id_th_pwd_opt" style="width: 10%;"></th>\r
+ <th id="id_th_pwd_set" style="width: 40%;"></th>\r
+ <th id="id_th_pwd_operate" style="width: 10%;"></th>\r
+ <th id="id_th_pwd_notes" style="width: 30%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+ </div>\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">Menu Password\r
+ <span id="id_span_desc_cn"> —— 菜单密码</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table id="id_pwd_tbl" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 2%;">#</th>\r
+ <th id="id_th_pwd_type" style="width: 5%;"></th>\r
+ <th id="id_th_pwd_path" style="width: 45%;"></th>\r
+ <th id="id_th_status" style="width: 5%;"></th>\r
+ <th id="id_th_pwd_pwd" style="width: 35%;"></th>\r
+ <th id="id_th_operation" style="width: 10%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+ </div>\r
+ <br/><br/>\r
+\r
+\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_PASSWORD);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ $("span[id=id_span_dir_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_EXIST);\r
+ });\r
+ \r
+ $("span[id=id_span_dir_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_NONEXIST);\r
+ });\r
+\r
+ $("span[id=id_span_edit]").each(function(){\r
+ $(this).text(' ' + g_vtoy_cur_language.STR_EDIT);\r
+ });\r
+\r
+ $("span[id=id_span_clear]").each(function(){\r
+ $(this).text(' ' + g_vtoy_cur_language.STR_CLEAR);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_pwd_path').text('Absolute Path');\r
+ $('#id_th_pwd_pwd').text('Password');\r
+ $('#id_th_pwd_type').text('Type');\r
+ $("th[id=id_th_pwd_opt]").text('Option');\r
+ $("th[id=id_th_pwd_set]").text('Setting');\r
+ $("th[id=id_th_pwd_operate]").text('Operation');\r
+ $("th[id=id_th_pwd_notes]").text('Notes');\r
+\r
+ $("span[id=id_span_desc_cn]").each(function(){\r
+ $(this).hide();\r
+ });\r
+ $("span[id=id_span_desc_en]").each(function(){\r
+ $(this).show();\r
+ });\r
+ } else {\r
+ $('#id_th_pwd_path').text('绝对路径');\r
+ $('#id_th_pwd_pwd').text('密码');\r
+ $('#id_th_pwd_type').text('类型');\r
+ $("th[id=id_th_pwd_opt]").text('选项');\r
+ $("th[id=id_th_pwd_set]").text('设置');\r
+ $("th[id=id_th_pwd_operate]").text('操作');\r
+ $("th[id=id_th_pwd_notes]").text('说明');\r
+ $("span[id=id_span_desc_en]").each(function(){\r
+ $(this).hide();\r
+ });\r
+ $("span[id=id_span_desc_cn]").each(function(){\r
+ $(this).show();\r
+ });\r
+ }\r
+ }\r
+ \r
+ function format_password(pwd, type) {\r
+ if (type === 0) {\r
+ return 'txt#' + pwd;\r
+ } else if (type === 1) {\r
+ return 'md5#' + md5(pwd);\r
+ } else {\r
+ var salt;\r
+ var rand = Math.round(Math.random() * 10);\r
+ if ((rand % 2) === 0) {\r
+ salt = ventoy_random_string(3);\r
+ } else {\r
+ salt = ventoy_random_string(4);\r
+ }\r
+\r
+ return 'md5#' + salt + '#' + md5(salt + pwd);\r
+ }\r
+ }\r
+\r
+ function CommonPasswordEntry(tbl, name, cn, en) {\r
+ var tr = '<tr><td>'+name+'</td><td><input type="text" class="form-control" id="id_'+name+'" disabled="disabled"/></td>' +\r
+ '<td><button id="id_btn_set_'+name+'" class="btn btn-primary btn-sm btn-add CommPwdSetBtn"><span class="fa fa-edit"></span><span id="id_span_edit"></span></button> ' +\r
+ '<button id="id_btn_clr_'+name+'" class="btn btn-danger btn-sm btn-del CommPwdClearBtn"><span class="fa fa-trash"></span><span id="id_span_clear"></span></button></td>' +\r
+ '<td><span id="id_span_desc_cn">' + cn + '</span>' +\r
+ '<span id="id_span_desc_en">' + en + '</span></td>' +\r
+ '</tr>';\r
+ tbl.append(tr);\r
+ }\r
+\r
+ function FillCommonPassword(data) {\r
+ var $tbl = $("#id_common_pwd tbody");\r
+ $tbl.empty();\r
+\r
+ CommonPasswordEntry($tbl, 'bootpwd', '启动进入 Ventoy 时的密码。', 'Password when Ventoy is booting.');\r
+ CommonPasswordEntry($tbl, 'isopwd', '所有 .iso 文件的默认密码。', 'Default password for all .iso files.');\r
+ CommonPasswordEntry($tbl, 'wimpwd', '所有 .wim 文件的默认密码。', 'Default password for all .wim files.');\r
+ CommonPasswordEntry($tbl, 'imgpwd', '所有 .img 文件的默认密码。', 'Default password for all .img files.');\r
+ CommonPasswordEntry($tbl, 'vhdpwd', '所有 .vhd(x) 文件的默认密码。', 'Default password for all .vhd(x) files.');\r
+ CommonPasswordEntry($tbl, 'efipwd', '所有 .efi 文件的默认密码。', 'Default password for all .efi files.');\r
+ CommonPasswordEntry($tbl, 'vtoypwd', '所有 .vtoy 文件的默认密码。', 'Default password for all .vtoy files.');\r
+\r
+ $('input:text[id=id_bootpwd]').val(data.bootpwd);\r
+ $('input:text[id=id_isopwd]').val(data.isopwd);\r
+ $('input:text[id=id_wimpwd]').val(data.wimpwd);\r
+ $('input:text[id=id_imgpwd]').val(data.imgpwd);\r
+ $('input:text[id=id_efipwd]').val(data.efipwd);\r
+ $('input:text[id=id_vhdpwd]').val(data.vhdpwd);\r
+ $('input:text[id=id_vtoypwd]').val(data.vtoypwd);\r
+ }\r
+\r
+ function FillMenuPwdTable(data) {\r
+ var addbtn = ventoy_get_xslg_addbtn('MenuPwdAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('MenuPwdDelBtn');\r
+\r
+ var td1, td2, td3, td4, td5, td6;\r
+ var $tbl = $("#id_pwd_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = (data[i].type === 0) ? '<td>file</td>' : '<td>parent</td>';\r
+ td3 = '<td>' + data[i].path + '</td>';\r
+ td4 = '<td>' + ventoy_get_status_line(data[i].type, data[i].valid) + '</td>';\r
+ td5 = '<td>' + data[i].pwd + '</td>';\r
+ td6 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + td5 + td6 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillCommonPassword(data);\r
+ FillMenuPwdTable(data.list);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_pwd[index].tips);\r
+ }\r
+\r
+ function VtoyGetCurrentPageItem(data) {\r
+ data.bootpwd = $('input:text[id=id_bootpwd]').val();\r
+ data.isopwd = $('input:text[id=id_isopwd]').val();\r
+ data.wimpwd = $('input:text[id=id_wimpwd]').val();\r
+ data.imgpwd = $('input:text[id=id_imgpwd]').val();\r
+ data.efipwd = $('input:text[id=id_efipwd]').val();\r
+ data.vhdpwd = $('input:text[id=id_vhdpwd]').val();\r
+ data.vtoypwd = $('input:text[id=id_vtoypwd]').val();\r
+ }\r
+\r
+ function VtoySaveCurrentPage() {\r
+ VtoyGetCurrentPageItem(m_data_pwd[current_tab_index]);\r
+ var data = m_data_pwd[current_tab_index];\r
+\r
+ callVtoy({\r
+ method : 'save_password',\r
+ index: current_tab_index,\r
+ bootpwd: data.bootpwd,\r
+ isopwd: data.isopwd,\r
+ wimpwd: data.bootpwd,\r
+ imgpwd: data.imgpwd,\r
+ efipwd: data.efipwd,\r
+ vhdpwd: data.vhdpwd,\r
+ vtoypwd: data.vtoypwd\r
+ }, function(e) {\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ var m_pwd_file_or_dir;\r
+ var m_pwd_callback_func;\r
+ var m_pwd_callback_data;\r
+ var m_pwd_validator = $("#SetPwdForm").validate({ \r
+ rules: { \r
+ PwdPath : {\r
+ required: true,\r
+ utfmaxlen: true\r
+ },\r
+ PwdPwd : {\r
+ required: true,\r
+ utfmaxlen: true,\r
+ noquotes:true,\r
+ printascii:true,\r
+ maxlength: 40\r
+ }\r
+ },\r
+\r
+ submitHandler: function(form) {\r
+ var path = $('input:text[id=PwdPath]').val();\r
+ var pwd = $('input:text[id=PwdPwd]').val();\r
+ var type = parseInt($('input:radio[name=id_radio_pwd_type]:checked').val());\r
+\r
+ if (m_pwd_validator.settings.rules.PwdPath.required) {\r
+ path = ventoy_replace_slash(path);\r
+\r
+ if (!ventoy_common_check_path(path)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ return;\r
+ }\r
+\r
+ if (path.indexOf("*") >= 0) {\r
+ callVtoySync({\r
+ method : 'check_fuzzy',\r
+ path: path\r
+ }, function(data) { \r
+ if (data.exist != 0) {\r
+ if (typeof(m_pwd_callback_func) === 'function') {\r
+ m_pwd_callback_func(path, pwd, type, m_pwd_callback_data);\r
+ }\r
+ $("#SetPwdModal").modal('hide');\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ }\r
+ });\r
+ } else {\r
+\r
+ callVtoySync({\r
+ method : 'check_path',\r
+ dir: m_pwd_file_or_dir,\r
+ path: path\r
+ }, function(data) { \r
+ if (data.exist === 1) {\r
+ if (typeof(m_pwd_callback_func) === 'function') {\r
+ m_pwd_callback_func(path, pwd, type, m_pwd_callback_data);\r
+ }\r
+ $("#SetPwdModal").modal('hide');\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ }\r
+ });\r
+ }\r
+ } else {\r
+ if (typeof(m_pwd_callback_func) === 'function') {\r
+ \r
+ m_pwd_callback_func(path, pwd, type, m_pwd_callback_data);\r
+ }\r
+ $("#SetPwdModal").modal('hide');\r
+ }\r
+ }\r
+});\r
+\r
+function VtoySetPassword(common, type, cb, data) {\r
+\r
+ $('#SetPwdForm #SetPwdForm_title').text(g_vtoy_cur_language.STR_SET_PASSWORD);\r
+ \r
+ if (type === 0) {\r
+ $('#SetPwdForm #SetPwdForm_path').text(g_vtoy_cur_language.STR_FILE_PATH);\r
+ } else {\r
+ $('#SetPwdForm #SetPwdForm_path').text(g_vtoy_cur_language.STR_DIR_PATH);\r
+ }\r
+ \r
+ $('#SetPwdForm #SetPwdForm_pwd').text(g_vtoy_cur_language.STR_PASSWORD_VALUE);\r
+ $('#SetPwdForm #SetPwdForm_type').text(g_vtoy_cur_language.STR_PASSWORD_TYPE);\r
+\r
+ if (common) {\r
+ m_pwd_validator.settings.rules.PwdPath.required = false;\r
+ $('div[id=id_div_pwd_path]').hide();\r
+\r
+ } else {\r
+ m_pwd_validator.settings.rules.PwdPath.required = true;\r
+ $('div[id=id_div_pwd_path]').show();\r
+\r
+ if (type === 0) {\r
+ if (g_current_language === 'en') {\r
+ $('div[id=id_note_pwdfile_cn]').hide();\r
+ $('div[id=id_note_pwdfile_en]').show();\r
+ } else {\r
+ $('div[id=id_note_pwdfile_cn]').show();\r
+ $('div[id=id_note_pwdfile_en]').hide();\r
+ }\r
+ $('div[id=id_note_pwddir_cn]').hide();\r
+ $('div[id=id_note_pwddir_en]').hide();\r
+ } else {\r
+ $('div[id=id_note_pwdfile_cn]').hide();\r
+ $('div[id=id_note_pwdfile_en]').hide();\r
+ if (g_current_language === 'en') {\r
+ $('div[id=id_note_pwddir_cn]').hide();\r
+ $('div[id=id_note_pwddir_en]').show();\r
+ } else {\r
+ $('div[id=id_note_pwddir_cn]').show();\r
+ $('div[id=id_note_pwddir_en]').hide();\r
+ }\r
+ }\r
+ }\r
+\r
+ $('input:radio[name=id_radio_pwd_type]')[0].checked = true;\r
+\r
+ if (g_current_language === 'en') {\r
+ $('#SetPwdForm #SetPwdForm_ok').text(" OK");\r
+ $('#SetPwdForm #SetPwdForm_cancel').text("Cancel");\r
+ } else {\r
+ $('#SetPwdForm #SetPwdForm_ok').text("确定");\r
+ $('#SetPwdForm #SetPwdForm_cancel').text("取消");\r
+ }\r
+ \r
+ m_pwd_file_or_dir = type;\r
+ m_pwd_callback_func = cb;\r
+ m_pwd_callback_data = data;\r
+ m_pwd_validator.resetForm(); \r
+ $("#SetPwdModal").modal(); \r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+ //Main process\r
+ var m_data_pwd;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_password'}, function(data) {\r
+ m_data_pwd = data;\r
+ });\r
+ \r
+ function set_common_pwd_callback(path, pwd, type, data) {\r
+ var selector = 'input:text[id=id_'+ data +']';\r
+ var value = format_password(pwd, type);\r
+\r
+ $(selector).val(value);\r
+ VtoySaveCurrentPage();\r
+ }\r
+ $("#id_common_pwd").on('click', '.CommPwdSetBtn', function() {\r
+ var id = $(this).attr('id');\r
+\r
+ //id_btn_set_\r
+ VtoySetPassword(1, 0, set_common_pwd_callback, id.substr(11));\r
+ });\r
+ $("#id_common_pwd").on('click', '.CommPwdClearBtn', function() {\r
+ var id = $(this).attr('id');\r
+\r
+ //id_btn_clr_\r
+ var selector = 'input:text[id=id_'+ id.substr(11) +']';\r
+ $(selector).val('');\r
+ VtoySaveCurrentPage();\r
+ });\r
+\r
+ function set_menu_pwd_callback(path, pwd, type, FileOrDir) {\r
+ var list = m_data_pwd[current_tab_index].list;\r
+ var value = format_password(pwd, type);\r
+ var valid = (path.indexOf("*") >= 0) ? -1 : 1;\r
+\r
+ var data = {\r
+ "type": FileOrDir,\r
+ "path": path.substr(g_current_dir.length),\r
+ "valid": valid,\r
+ "pwd": value\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'password_add',\r
+ index: current_tab_index,\r
+ type: data.type,\r
+ path: data.path,\r
+ pwd: data.pwd\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillMenuPwdTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+\r
+ }\r
+ function OnAddMenuPwdBtnClick(sel) {\r
+ if (sel === 0) {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\Windows11.iso' : "/ISO/Ubuntu-20.04-desktop-amd64.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\Windows**.iso' : "/ISO/Ubuntu-*****-desktop-amd64.iso";\r
+ \r
+ $('#SetPwdForm #id_span_pwdfile_tip1').text(g_current_dir + tip1);\r
+ $('#SetPwdForm #id_span_pwdfile_tip2').text(g_current_dir + tip2);\r
+\r
+ VtoySetPassword(0, 0, set_menu_pwd_callback, 0);\r
+\r
+ } else {\r
+ var tip = (g_current_os === 'windows') ? '\\ISO\\Windows' : "/ISO/Linux";\r
+ $('#SetPwdForm #id_span_pwddir_tip').text(g_current_dir + tip);\r
+\r
+ VtoySetPassword(0, 1, set_menu_pwd_callback, 1);\r
+\r
+ }\r
+ }\r
+\r
+ $("#id_pwd_tbl").on('click', '.MenuPwdAddBtn', function() {\r
+ var para = [\r
+ {\r
+ "selected": true,\r
+ "tip": g_vtoy_cur_language.STR_SET_PWD_FOR_FILE\r
+ },\r
+ {\r
+ "selected": false,\r
+ "tip": g_vtoy_cur_language.STR_SET_PWD_FOR_DIR\r
+ }\r
+ ];\r
+\r
+ VtoySelectType(OnAddMenuPwdBtnClick, para);\r
+ });\r
+\r
+ $("#id_pwd_tbl").on('click', '.MenuPwdDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'password_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_pwd[current_tab_index].list.splice(index, 1);\r
+ FillMenuPwdTable(m_data_pwd[current_tab_index].list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+ function VtoySaveCurrentPage() {\r
+ var bootpwd = $('input:text[id=id_bootpwd]').val();\r
+ var isopwd = $('input:text[id=id_isopwd]').val();\r
+ var wimpwd = $('input:text[id=id_wimpwd]').val();\r
+ var imgpwd = $('input:text[id=id_imgpwd]').val();\r
+ var vhdpwd = $('input:text[id=id_vhdpwd]').val();\r
+ var efipwd = $('input:text[id=id_efipwd]').val();\r
+ var vtoypwd = $('input:text[id=id_vtoypwd]').val();\r
+\r
+ callVtoy({\r
+ method : 'save_password',\r
+ index: current_tab_index,\r
+ bootpwd: bootpwd, \r
+ isopwd: isopwd,\r
+ wimpwd: wimpwd,\r
+ imgpwd: imgpwd,\r
+ vhdpwd: vhdpwd,\r
+ efipwd: efipwd,\r
+ vtoypwd: vtoypwd\r
+ }, function(e) {\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ $('input:text[id=id_bootpwd]').change(VtoySaveCurrentPage);\r
+ $('input:text[id=id_isopwd]').change(VtoySaveCurrentPage);\r
+ $('input:text[id=id_wimpwd]').change(VtoySaveCurrentPage);\r
+ $('input:text[id=id_imgpwd]').change(VtoySaveCurrentPage);\r
+ $('input:text[id=id_vhdpwd]').change(VtoySaveCurrentPage);\r
+ $('input:text[id=id_efipwd]').change(VtoySaveCurrentPage);\r
+ $('input:text[id=id_vtoypwd]').change(VtoySaveCurrentPage);\r
+\r
+ $('#id_tab_password a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_password a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_password a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_password a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_password a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_password a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_password a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_pwd[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-database"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">x</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/en/plugin_persistence.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_persistence">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >persistence</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">persistence_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">persistence_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">persistence_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">persistence_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">persistence_mips</a></li>\r
+ </ul>\r
+ </div>\r
+\r
+ <table id="id_persistence_tbl" class="table table-bordered" >\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 5%;">#</th>\r
+ <th id="id_th_persistence_set" style="width: 80%;"></th>\r
+ <th id="id_th_operation" style="width: 10%;"></th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ </tbody>\r
+ </table>\r
+ </div>\r
+</div>\r
+<script type="text/javascript">\r
+ \r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_PERSISTENCE);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+ $("span[id=id_span_file_fuzzy]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_FUZZY);\r
+ });\r
+\r
+ $("span[id=id_span_dir_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_EXIST);\r
+ });\r
+ \r
+ $("span[id=id_span_dir_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DIR_NONEXIST);\r
+ });\r
+\r
+ $("th[id=id_th_persist_dat]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_PERSISTENCE_DAT);\r
+ });\r
+\r
+ if (newlang === 'en') {\r
+ $('#id_th_autoins_path').text('Absolute Path');\r
+ $('#id_th_persistence_set').text('Setting');\r
+ } else {\r
+ $('#id_th_autoins_path').text('绝对路径');\r
+ $('#id_th_persistence_set').text('设置');\r
+ \r
+ }\r
+ }\r
+ \r
+ function VtoySaveCurrentPage(index) {\r
+\r
+ var timeoutval = 0;\r
+ var autoselval = 1;\r
+\r
+ var timeouten = $('#id_timeout_en_' + index).is(':checked');\r
+ var autoselen = $('#id_autosel_en_' + index).is(':checked');\r
+\r
+ if (timeouten) {\r
+ timeoutval = parseInt($('#id_text_timeout_' + index).val());\r
+ }\r
+\r
+ if (autoselen) {\r
+ autoselval = parseInt($('#id_text_autosel_' + index).val());\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'save_persistence',\r
+ index: current_tab_index,\r
+ id: index,\r
+ timeout: timeoutval,\r
+ autosel: autoselval,\r
+ timeouten: timeouten,\r
+ autoselen: autoselen\r
+ }, function(e) {\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnInputTextChange() {\r
+ var id = $(this).attr('id');\r
+ var value = $(this).val();\r
+ var intval;\r
+ \r
+ if (id.length <= 16) {\r
+ return;\r
+ }\r
+\r
+ var index = parseInt(id.substr(16));\r
+ var data = m_data_persistence[current_tab_index][index];\r
+\r
+ if (/^[0-9][0-9]*$/.test(value)) {\r
+ intval = parseInt(value);\r
+\r
+ if (id.startsWith('id_text_autosel_')) {\r
+ var list = m_data_persistence[current_tab_index][index].list;\r
+ if (intval > list.length) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_AUTOSEL);\r
+ $(this).val(data.autosel);\r
+ return;\r
+ }\r
+ }\r
+\r
+ VtoySaveCurrentPage(index);\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_NUMBER);\r
+\r
+ if (id.startsWith('id_text_timeout_')) {\r
+ $(this).val(data.timeout);\r
+ } else {\r
+ $(this).val(data.autosel);\r
+ }\r
+ }\r
+ }\r
+\r
+ function OnCheckBoxChange() {\r
+ var index;\r
+ var textid;\r
+ var value;\r
+ var id = $(this).attr('id');\r
+ var checked = $(this).is(':checked');\r
+\r
+ if (id.length <= 14) {\r
+ return;\r
+ }\r
+\r
+ index = parseInt(id.substr(14));\r
+ var data = m_data_persistence[current_tab_index][index];\r
+\r
+ if (id.startsWith('id_timeout_en_')) {\r
+ textid = 'input[id=id_text_timeout_' + index + ']';\r
+ value = data.timeout;\r
+ } else {\r
+ textid = 'input[id=id_text_autosel_' + index + ']';\r
+ value = data.autosel;\r
+ }\r
+ \r
+ if (checked) {\r
+ $(textid).attr("disabled", false);\r
+ $(textid).val(value);\r
+ } else {\r
+ $(textid).attr("disabled", true);\r
+ $(textid).val('');\r
+ }\r
+ \r
+ VtoySaveCurrentPage(index);\r
+ }\r
+ \r
+\r
+ function FillPersistenceInnerTable(i, data) {\r
+ var td1, td2, td3, td4;\r
+ var inner = data.list;\r
+ var tabid = '#tbl_inner_' + (i + 1);\r
+ var $inner_tbl = $(tabid + ' tbody');\r
+\r
+ var inaddbtn = ventoy_get_xslg_addbtn('PersistenceInnerAddBtn');\r
+ var indelbtn = ventoy_get_xslg_delbtn('PersistenceInnerDelBtn');\r
+\r
+ $inner_tbl.empty();\r
+ \r
+ for (var j = 0; j < inner.length; j++) {\r
+ var $tr;\r
+ td1 = '<td style="width: 5%;">'+(j+1)+'</td>';\r
+ td2 = '<td>'+inner[j].path+'</td>';\r
+ td3 = '<td style="width: 10%;">'+ventoy_get_status_line(0, inner[j].valid)+'</td>';\r
+ td4 = '<td style="width: 10%;">' + indelbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + '</tr>');\r
+ $tr.data('path', inner[j].path);\r
+ $tr.data('index', j);\r
+ $tr.data('outpath', data.path);\r
+ $tr.data('outindex', i);\r
+\r
+ $inner_tbl.append($tr);\r
+ }\r
+\r
+ $tr = $('<tr><td></td><td></td><td></td><td>'+inaddbtn+'</td></tr>');\r
+ $tr.data('outpath', data.path);\r
+ $tr.data('outindex', i);\r
+\r
+ $inner_tbl.append($tr);\r
+ }\r
+\r
+ function FillPersistenceTable(data) {\r
+ var td1, td2, td3, td4, td5;\r
+ var addbtn = ventoy_get_addbtn('PersistenceAddBtn');\r
+ var delbtn = ventoy_get_delbtn('PersistenceDelBtn');\r
+ \r
+ var $tbl = $("#id_persistence_tbl tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ var $tr;\r
+\r
+ var tdtimeout, timeoutdisable, timeoutval;\r
+ var tdautosel, autoseldisable, autoselval;\r
+ if (data[i].timeouten) {\r
+ tdtimeout = '<th style="width:10%;"><input id="id_timeout_en_'+i+'" checked="checked" type="checkbox"/> timeout</th>';\r
+ timeoutval = data[i].timeout;\r
+ timeoutdisable='';\r
+ } else {\r
+ tdtimeout = '<th style="width:10%;"><input id="id_timeout_en_'+i+'" type="checkbox"/> timeout</th>';\r
+ timeoutval='';\r
+ timeoutdisable='disabled="disabled"';\r
+ }\r
+ if (data[i].autoselen) {\r
+ tdautosel = '<th style="width:10%;"><input id="id_autosel_en_'+i+'" checked="checked" type="checkbox"/> autosel</th>';\r
+ autoselval = data[i].autosel;\r
+ autoseldisable='';\r
+ } else {\r
+ tdautosel = '<th style="width:10%;"><input id="id_autosel_en_'+i+'" type="checkbox"/> autosel</th>';\r
+ autoselval='';\r
+ autoseldisable='disabled="disabled"';\r
+ }\r
+\r
+\r
+ var tdtype = (data[i].type === 0) ? "image" : "parent";\r
+ var tdtbl1 ='<table class="table table-condensed">'+\r
+ \r
+ '<thead><tr>' + \r
+ '<th>'+tdtype+'</th>'+\r
+ '<th style="width:10%;">Status</th>'+ \r
+ tdtimeout +\r
+ tdautosel +\r
+ '</tr></thread>' +\r
+\r
+ '<tbody><tr>'+\r
+ '<td style="width:70%;vertical-align: middle;">' + data[i].path + '</td>' + \r
+ '<td style="vertical-align: middle;">' + ventoy_get_status_line(data[i].type, data[i].valid) + '</td>' +\r
+ '<td><div style="padding-left:0;" class="col-sm-8"><input type="text" '+timeoutdisable+' value="'+timeoutval+'" class="form-control" id="id_text_timeout_'+i+'"/></div></td>'+\r
+ '<td><div style="padding-left:0;" class="col-sm-8"><input type="text" '+autoseldisable+' value="'+autoselval+'" class="form-control" id="id_text_autosel_'+i+'"/></div></td></tr>'+\r
+ \r
+ '<tr><td></td><td></td><td></td><td></td></tr>'+\r
+\r
+ '</tbody></table>';\r
+\r
+ var tdtbl2 = '<table class="table table-bordered" id="tbl_inner_' + (i+1) + '">'+\r
+ '<thead><tr><th>#</th><th id="id_th_persist_dat">'+g_vtoy_cur_language.STR_PERSISTENCE_DAT+'</th><th id="id_th_status">'+g_vtoy_cur_language.STR_STATUS+'</th><th id="id_th_operation">'+g_vtoy_cur_language.STR_OPERATION+'</th></tr></thead><tbody></tbody></table>';\r
+\r
+ td1 = '<td style="vertical-align: middle;">' + (i + 1) + '</td>';\r
+ td2 = '<td>' + tdtbl1 + tdtbl2 + '</td>';\r
+ td3 = '<td style="vertical-align: middle;text-align: center;">' + delbtn + '</td>';\r
+ $tr = $('<tr>' + td1 + td2 + td3 + '</tr>');\r
+\r
+ $tr.data('path', data[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td style="vertical-align: middle;text-align: center;">' + addbtn + '</td></tr>');\r
+\r
+ $('input[type=text]').each(function (){\r
+ var id = $(this).attr('id');\r
+ \r
+ if (id.startsWith('id_text_timeout_') || id.startsWith('id_text_autosel_')) {\r
+ $(this).change(OnInputTextChange);\r
+ }\r
+ });\r
+\r
+ $('input[type=checkbox]').each(function (){\r
+ var id = $(this).attr('id'); \r
+ if (id.startsWith('id_timeout_en_') || id.startsWith('id_autosel_en_')) {\r
+ $(this).click(OnCheckBoxChange);\r
+ }\r
+ });\r
+\r
+ for (var i = 0; i < data.length; i++) {\r
+ FillPersistenceInnerTable(i, data[i]); \r
+ }\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ FillPersistenceTable(data);\r
+ }\r
+\r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_persistence[index]);\r
+ }\r
+\r
+ function AddPersistenceEntry(type, exist1, path1, path2) {\r
+ var list = m_data_persistence[current_tab_index];\r
+ var data_array = [\r
+ {\r
+ "path": "",\r
+ "valid": 1\r
+ }\r
+ ];\r
+ var call_array = [\r
+ ""\r
+ ];\r
+\r
+ call_array[0] = path2.substr(g_current_dir.length);\r
+ data_array[0].path = path2.substr(g_current_dir.length);\r
+\r
+ var data = {\r
+ "path": path1.substr(g_current_dir.length),\r
+ "list": data_array,\r
+ "type": type,\r
+ "valid": exist1,\r
+ "autosel": 1,\r
+ "timeout": 0\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'persistence_add',\r
+ index: current_tab_index,\r
+ path: data.path,\r
+ backend: call_array,\r
+ type: type\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillPersistenceTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAddImagePersistence(exist1, path1, path2) {\r
+ AddPersistenceEntry(0, exist1, path1, path2);\r
+ }\r
+\r
+ function OnPersistenceAddClick() {\r
+ var tip1 = (g_current_os === 'windows') ? '\\ISO\\ubuntu-20.04-desktop-amd64.iso' : "/ISO/ubuntu-20.04-desktop-amd64.iso";\r
+ var tip2 = (g_current_os === 'windows') ? '\\ISO\\ubuntu-*****-desktop-amd64.iso' : "/ISO/ubuntu-*****-desktop-amd64.iso";\r
+ var tip3 = (g_current_os === 'windows') ? '\\ventoy\\ubuntu_persistence.dat' : "/ventoy/ubuntu_persistence.dat"; \r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_SET_PERSISTENCE,\r
+ "label1": g_vtoy_cur_language.STR_FILE_PATH,\r
+ "label2": g_vtoy_cur_language.STR_SET_PERSISTENCE_DAT,\r
+ "tip1": g_current_dir + tip1,\r
+ "tip2": g_current_dir + tip2,\r
+ "tip3": g_current_dir + tip3\r
+ };\r
+\r
+ VtoySetFileFile(OnAddImagePersistence, para);\r
+ }\r
+\r
+ function PersistenceDelEntry(path, index) {\r
+ callVtoySync({\r
+ method : 'persistence_del',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_persistence[current_tab_index].splice(index, 1);\r
+ FillPersistenceTable(m_data_persistence[current_tab_index]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnPersistenceDelClick() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ PersistenceDelEntry(path, index);\r
+ }\r
+ \r
+\r
+ var m_out_index;\r
+ var m_out_path;\r
+ function OnAddPersistenceDatFile(root, valid, extra) {\r
+ var path = root.substr(g_current_dir.length);\r
+ var data = m_data_persistence[current_tab_index][m_out_index];\r
+\r
+ for (var i = 0; i < data.list.length; i++) {\r
+ if (data.list[i].path === path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'persistence_add_inner',\r
+ index: current_tab_index,\r
+ outpath: m_out_path,\r
+ path: path\r
+ }, function(e) {\r
+\r
+ var node = {\r
+ "path": path,\r
+ "valid": 1\r
+ };\r
+\r
+ data.list.push(node);\r
+ FillPersistenceInnerTable(m_out_index, data);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ \r
+ }\r
+\r
+ function OnPersistenceInnerAddClick() {\r
+ var $tr = $(this).closest('tr');\r
+ var outpath = $tr.data('outpath');\r
+ var outindex = $tr.data('outindex');\r
+\r
+ var tip = (g_current_os === 'windows') ? '\\ventoy\\ubuntu_persistence.dat' : "/ventoy/ubuntu_persistence.dat";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_ADD_PERSISTENCE_DAT,\r
+ "fuzzy": 0,\r
+ "tip1": g_current_dir + tip,\r
+ "tip2": '',\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+\r
+ m_out_index = outindex;\r
+ m_out_path = outpath;\r
+ VtoySelectFilePath(OnAddPersistenceDatFile, para);\r
+ }\r
+\r
+ function PersistenceDelInnerEntry(outpath, outindex, path, index) {\r
+ callVtoy({\r
+ method : 'persistence_del_inner',\r
+ index: current_tab_index,\r
+ outpath: outpath,\r
+ path: path\r
+ }, function(e) {\r
+ var data = m_data_persistence[current_tab_index][outindex];\r
+\r
+ data.list.splice(index, 1);\r
+ FillPersistenceInnerTable(outindex, m_data_persistence[current_tab_index][outindex]);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnPersistenceInnerDelClick() {\r
+ var $tr = $(this).closest('tr');\r
+\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+ var outpath = $tr.data('outpath');\r
+ var outindex = $tr.data('outindex');\r
+\r
+ var list = m_data_persistence[current_tab_index][outindex].list;\r
+\r
+ if (list.length === 1) {\r
+ ventoy_confirm(g_vtoy_cur_language.STR_DEL_LAST, PersistenceDelEntry, outpath, outindex);\r
+ } else {\r
+ PersistenceDelInnerEntry(outpath, outindex, path, index);\r
+ }\r
+ }\r
+\r
+\r
+\r
+\r
+\r
+ //Main process\r
+ var m_data_persistence;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_persistence'}, function(data) {\r
+ m_data_persistence = data;\r
+ });\r
+ \r
+ $("#id_persistence_tbl").on('click', '.PersistenceAddBtn', OnPersistenceAddClick);\r
+ $("#id_persistence_tbl").on('click', '.PersistenceDelBtn', OnPersistenceDelClick);\r
+ $("#id_persistence_tbl").on('click', '.PersistenceInnerAddBtn', OnPersistenceInnerAddClick);\r
+ $("#id_persistence_tbl").on('click', '.PersistenceInnerDelBtn', OnPersistenceInnerDelClick);\r
+\r
+ $('#id_tab_persistence a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_persistence a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_persistence a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_persistence a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_persistence a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_persistence a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_persistence a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_persistence[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+<div class="box box-primary" id="control">\r
+ <div class="box-header">\r
+ <div class="col-sm-10" style="padding-top:8px;">\r
+ <i class="fa fa-file-image-o"> </i>\r
+ <h1 class="box-title" style="font-weight:bold;" id="id_h1_page_title">主题插件</h1>\r
+ </div>\r
+ \r
+ <div class="col-sm-2" style="font-size:16px;padding-top:8px;">\r
+ <a id="id_a_official_doc" target="_blank" href="https://www.ventoy.net/cn/plugin_theme.html"><span class="fa fa-link"></span><span id="id_span_official_doc">官网文档</span></a>\r
+ </div>\r
+ </div>\r
+ <legend></legend>\r
+ \r
+ <div class="box-body">\r
+ \r
+ <div class="nav-tabs-custom">\r
+ <ul class="nav nav-tabs" id="id_tab_theme">\r
+ <li class=""><a href="#tab_0" data-toggle="tab" aria-expanded="false" style="font-weight:bold" >theme</a></li>\r
+ <li class=""><a href="#tab_1" data-toggle="tab" aria-expanded="false" style="font-weight:bold">theme_legacy</a></li>\r
+ <li class=""><a href="#tab_2" data-toggle="tab" aria-expanded="false" style="font-weight:bold">theme_uefi</a></li>\r
+ <li class=""><a href="#tab_3" data-toggle="tab" aria-expanded="false" style="font-weight:bold">theme_ia32</a></li>\r
+ <li class=""><a href="#tab_4" data-toggle="tab" aria-expanded="false" style="font-weight:bold">theme_aa64</a></li>\r
+ <li class=""><a href="#tab_5" data-toggle="tab" aria-expanded="false" style="font-weight:bold">theme_mips</a></li>\r
+ </ul>\r
+ </div>\r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">file\r
+ <span id="id_span_desc_cn"> —— 主题配置文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding" id="theme_file_table">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <table id="id_theme_tbl_file" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 5%">#</th>\r
+ <th id="id_th_file_path">文件路径</th>\r
+ <th style="width: 10%" id="id_th_default">默认</th>\r
+ <th style="width: 10%" id="id_th_status">状态</th>\r
+ <th style="width: 10%" id="id_th_operation">操作</th>\r
+ </tr>\r
+ </thead>\r
+ <tbody>\r
+ \r
+ </tbody>\r
+ </table>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ theme.txt 文件的全路径。可以设置1个或者多个。当设置为多个时,启动之后还可以通过 <code>F5 Tools --> Theme Select</code> 菜单进行切换。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ The theme.txt file path. You can add one or more files. You can switch between themes with <code>F5 Tools --> Theme Select</code> menu if you set more than one themes.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+ \r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">display_mode\r
+ <span id="id_span_desc_cn"> —— 屏幕显示模式</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <select id="id_theme_sel_dismode" name="name_theme_sel_dismode" class="form-control" >\r
+ <option title="GUI" selected>GUI</option>\r
+ <option title="CLI">CLI</option>\r
+ <option title="serial">serial</option>\r
+ <option title="serial_console">serial_console</option>\r
+ </selec\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 菜单显示模式,可以设置为 默认为 GUI 模式。GUI和CLI 分别对应图形模式和文本模式。<br/>\r
+ 在有极个别的机器上Ventoy的背景菜单无法显示,或者显示后菜单移动极其缓慢,这种情况可以默认设置为文本模式。<br/>\r
+ 不过,不管GUI还是CLI都是基于VGA显示设备的,如果你的机器上只有串口,你可以设置为 <code>serial</code> <br/>\r
+ 当然,如果既有串口也有VGA设备,则也可以设置为 <code>serial_console</code> <br/>\r
+ <span style='color:red;font-weight:bold;'>注意:如果菜单名称(文件名)里有中文的话,在文本或serial模式下是无法显示的。</span>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ Boot menu display mode, default is <code>GUI</code>. <code>GUI</code> or <code>CLI</code> corresponding to the GUI mode and TEXT mode respectively.<br/>\r
+ On very few machines Ventoy's menu can't be shown or the cursor moves extremely slow. In this case you can set the default mode to "CLI". <br/>\r
+ However, both "GUI" and "CLI" need a VGA device, if your machine only has serial, you can use <code>serial</code><br/>\r
+ Also you can use <code>serial_console</code> if you have both serial and VGA device. <br/>\r
+ <span style='color:red;font-weight:bold;'>Attention: Unicode characters will NOT be displayed normally in CLI or serial mode.</span>\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">gfxmode\r
+ <span id="id_span_desc_cn"> —— 屏幕分辨率</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <select id="id_theme_sel_gfxmode" name="name_theme_sel_gfxmode" class="form-control">\r
+ <option title="1920x1080">1920x1080</option>\r
+ <option title="1680x1050">1680x1050</option>\r
+ <option title="1600x900">1600x900</option>\r
+ <option title="1440x900">1440x900</option>\r
+ <option title="1280x1024">1280x1024</option>\r
+ <option title="1280x960">1280x960</option>\r
+ <option title="1024x768" selected>1024x768</option>\r
+ <option title="800x600">800x600</option>\r
+ </selec\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 默认使用的屏幕分辨率,默认为 "1024x768"。只有在上面的 <code>display_mode</code> 选项设置为 <code>GUI</code> 时才有效。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ Default screen resolution, default is "1024x768". Only take effect when <code>display_mode</code> option is <code>GUI</code>.\r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+ \r
+ <div class="box box-primary box-solid">\r
+ <div class="box-header with-border">\r
+ <h3 class="box-title" style="font-size: 14px;font-weight: bold;">fonts\r
+ <span id="id_span_desc_cn"> —— 字体文件</span></h3>\r
+ <div class="box-tools pull-right">\r
+ <button class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>\r
+ </div><!-- /.box-tools -->\r
+ </div><!-- /.box-header -->\r
+ <div class="box-body no-padding">\r
+ <table class="table table-bordered no-padding">\r
+ <tr style="font-weight:bold;">\r
+ <td class="td_ctrl_col" id="td_title_setting">选项设置</td>\r
+ <td>\r
+ <table id="id_theme_tbl_fonts" class="table table-bordered">\r
+ <thead>\r
+ <tr>\r
+ <th style="width: 5%">#</th>\r
+ <th id="id_th_file_path">文件路径</th>\r
+ <th style="width: 10%" id="id_th_status">状态</th>\r
+ <th style="width: 10%" id="id_th_operation">操作</th>\r
+ </tr> \r
+ </thead>\r
+ <tbody> \r
+ </tbody>\r
+ </table>\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_cn">\r
+ <td class="td_ctrl_col">选项说明</td>\r
+ <td>\r
+ 字体文件的全路径。Ventoy在启动时会依次加载这些字体文件。\r
+ </td>\r
+ </tr>\r
+ <tr id="tr_title_desc_en">\r
+ <td class="td_ctrl_col">Option Description</td>\r
+ <td>\r
+ Full path of fonts file. Ventoy will load each of them when boot. \r
+ </td>\r
+ </tr>\r
+ </table>\r
+ </div><!-- /.box-body -->\r
+ </div><!-- /.box -->\r
+\r
+\r
+ </div>\r
+ \r
+</div>\r
+<script type="text/javascript">\r
+ function VtoyPageLanguageChange(newlang) {\r
+ VtoyCommonChangeLanguage(newlang);\r
+ \r
+ $('h1[id=id_h1_page_title]').text(g_vtoy_cur_language.STR_PLUG_THEME);\r
+\r
+ $("span[id=id_span_file_exist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_EXIST);\r
+ });\r
+ $("span[id=id_span_file_nonexist]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_FILE_NONEXIST);\r
+ });\r
+\r
+ $("th[id=id_th_default]").text(g_vtoy_cur_language.STR_DEFAULT);\r
+\r
+ $("span[id=id_span_random_sel]").text(g_vtoy_cur_language.STR_RANDOM_SEL);\r
+ $("span[id=id_span_default_sel]").text(g_vtoy_cur_language.STR_DEFAULT_SEL);\r
+ }\r
+\r
+ function VtoyGetCurrentPageItem(data) {\r
+ var mode;\r
+\r
+ data.gfxmode = $('select[id=id_theme_sel_gfxmode').val();\r
+\r
+ mode = $('select[id=id_theme_sel_dismode').val();\r
+ if (mode === 'serial_console') {\r
+ data.display_mode = 3;\r
+ } else if (mode === 'serial') {\r
+ data.display_mode = 2;\r
+ } else if (mode === 'CLI') {\r
+ data.display_mode = 1;\r
+ } else {\r
+ data.display_mode = 0;\r
+ }\r
+ }\r
+\r
+ function VtoySaveCurrentPage() {\r
+ VtoyGetCurrentPageItem(m_data_theme[current_tab_index]);\r
+ var data = m_data_theme[current_tab_index];\r
+\r
+ callVtoy({\r
+ method : 'save_theme',\r
+ index: current_tab_index,\r
+ display_mode: data.display_mode,\r
+ gfxmode: data.gfxmode,\r
+ default_file: data.default_file\r
+ }, function(e) {\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+\r
+ function FillThemeFileTable(list, default_file) { \r
+ var id;\r
+ var exist = '<span id="id_span_file_exist" style="line-height: 1.5;" class="label pull-left bg-green">' + g_vtoy_cur_language.STR_FILE_EXIST + '</span>';\r
+ var nonexist = '<span id="id_span_file_nonexist" style="line-height: 1.5;" class="label pull-left bg-red">' + g_vtoy_cur_language.STR_FILE_NONEXIST + '</span>';\r
+ var addbtn = ventoy_get_xslg_addbtn('ThemeFileAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('ThemeFileDelBtn');\r
+\r
+ var default_random = '<label class="radio-inline"><input type="radio" id="id_theme_file_radio0" name="id_theme_file_radio" data-type="0" value="0"/><span id="id_span_random_sel">' + g_vtoy_cur_language.STR_RANDOM_SEL + '</span></label>';\r
+ var td1, td2, td3, td4, td5;\r
+ var $tbl = $("#id_theme_tbl_file tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = '<td>' + list[i].path + '</td>';\r
+\r
+ id = i + 1;\r
+ var sel = '<label class="radio-inline"><input type="radio" id="id_theme_file_radio'+ id + '" name="id_theme_file_radio" data-type="'+\r
+ id + '" value="'+ id +'"/><span id="id_span_default_sel">' + g_vtoy_cur_language.STR_DEFAULT_SEL + '</span></label>';\r
+ \r
+ td3 = '<td>' + sel + '</td>';\r
+ \r
+ if (list[i].valid === 1) {\r
+ td4 = '<td style="vertical-align: middle;">' + exist + '</td>';\r
+ } else {\r
+ td4 = '<td style="vertical-align: middle;">' + nonexist + '</td>';\r
+ }\r
+\r
+ td5 = '<td>' + delbtn + '</td>';\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + td5 + '</tr>');\r
+\r
+ $tr.data('path', list[i].path);\r
+ $tr.data('index', i);\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td>' + default_random + '</td><td></td><td>' + addbtn + '</td></tr>');\r
+ \r
+ var selid = 'input[type=radio][id=id_theme_file_radio' + default_file + ']';\r
+ $(selid)[0].checked = true;\r
+\r
+ $('input[type=radio]').each(function(){\r
+ var id = $(this).attr('id');\r
+ if (id.startsWith('id_theme_file')) {\r
+ $(this).change(function() {\r
+ m_data_theme[current_tab_index].default_file =parseInt(id.substr(id.length - 1));\r
+ VtoySaveCurrentPage();\r
+ });\r
+ }\r
+ });\r
+\r
+ if (list.length >= 2) {\r
+ $("th[id=id_th_default]").show();\r
+ $('#id_theme_tbl_file tr').find('td:eq(2)').show();\r
+ } else {\r
+ $("th[id=id_th_default]").hide();\r
+ $('#id_theme_tbl_file tr').find('td:eq(2)').hide();\r
+ }\r
+\r
+ }\r
+\r
+ function FillThemeFontTable(list) {\r
+ var exist = '<span id="id_span_file_exist" style="line-height: 1.5;" class="label pull-left bg-green">' + g_vtoy_cur_language.STR_FILE_EXIST + '</span>';\r
+ var nonexist = '<span id="id_span_file_nonexist" style="line-height: 1.5;" class="label pull-left bg-red">' + g_vtoy_cur_language.STR_FILE_NONEXIST + '</span>';\r
+ var addbtn = ventoy_get_xslg_addbtn('ThemeFontAddBtn');\r
+ var delbtn = ventoy_get_xslg_delbtn('ThemeFontDelBtn');\r
+ var td1, td2, td3, td4;\r
+ var $tbl = $("#id_theme_tbl_fonts tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ var $tr;\r
+ td1 = '<td>' + (i + 1) + '</td>';\r
+ td2 = '<td>' + list[i].path + '</td>';\r
+\r
+ if (list[i].valid === 1) {\r
+ td3 = '<td style="vertical-align: middle;">' + exist + '</td>';\r
+ } else {\r
+ td3 = '<td style="vertical-align: middle;">' + nonexist + '</td>';\r
+ }\r
+\r
+ td4 = '<td>' + delbtn + '</td>';\r
+\r
+ $tr = $('<tr>' + td1 + td2 + td3 + td4 + '</tr>');\r
+\r
+ $tr.data('path', list[i].path);\r
+ $tr.data('index', i);\r
+\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ $tbl.append('<tr><td></td><td></td><td></td><td>' + addbtn + '</td></tr>');\r
+ }\r
+\r
+ function VtoyFillCurrentPageItem(data) {\r
+ $('select[id=id_theme_sel_gfxmode').val(data.gfxmode);\r
+\r
+ if (data.display_mode === 3) {\r
+ $('select[id=id_theme_sel_dismode').val('serial_console');\r
+ } else if (data.display_mode === 2) {\r
+ $('select[id=id_theme_sel_dismode').val('serial');\r
+ } else if (data.display_mode === 1) {\r
+ $('select[id=id_theme_sel_dismode').val('CLI');\r
+ } else {\r
+ $('select[id=id_theme_sel_dismode').val('GUI');\r
+ }\r
+ \r
+ FillThemeFileTable(data.filelist, data.default_file);\r
+ FillThemeFontTable(data.fontslist);\r
+ }\r
+\r
+ \r
+\r
+ function OnClickMultiModeTab() {\r
+ var href = $(this).attr('href');\r
+ var index = parseInt(href.substr(5, 1));\r
+\r
+ if (index < 0 || index >= g_vtoy_data_default_index || current_tab_index === index) {\r
+ return;\r
+ }\r
+ \r
+ current_tab_index = index;\r
+ VtoyFillCurrentPageItem(m_data_theme[index]);\r
+ }\r
+\r
+\r
+ function OnAddThemeFile(root, valid, extra) {\r
+ var list = m_data_theme[current_tab_index].filelist;\r
+ var data = {\r
+ "path": root.substr(g_current_dir.length),\r
+ "valid": 1\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'theme_add_file',\r
+ index: current_tab_index,\r
+ path: data.path\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillThemeFileTable(list, m_data_theme[current_tab_index].default_file);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+ function OnAddThemeFont(root, valid, extra) {\r
+ var list = m_data_theme[current_tab_index].fontslist;\r
+ var data = {\r
+ "path": root.substr(g_current_dir.length),\r
+ "valid": 1\r
+ };\r
+\r
+ for (var i = 0; i < list.length; i++) {\r
+ if (list[i].path === data.path) {\r
+ Message.error(g_vtoy_cur_language.STR_DUPLICATE_PATH);\r
+ return;\r
+ }\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'theme_add_font',\r
+ index: current_tab_index,\r
+ path: data.path\r
+ }, function(e) {\r
+ list.push(data);\r
+ FillThemeFontTable(list);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ }\r
+\r
+\r
+ //Main process\r
+ \r
+ var m_data_theme;\r
+ var current_tab_index = 0;\r
+ callVtoySync({method : 'get_theme'}, function(data) {\r
+ m_data_theme = data;\r
+ });\r
+ \r
+ $("#theme_file_table").on('click', '.ThemeFileAddBtn', function() {\r
+ var tip = (g_current_os === 'windows') ? '\\ventoy\\themes\\test\\theme.txt' : "/ventoy/themes/test/theme.txt";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_ADD_THEME,\r
+ "fuzzy": 0,\r
+ "tip1": g_current_dir + tip,\r
+ "tip2": '',\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+\r
+ VtoySelectFilePath(OnAddThemeFile, para);\r
+ });\r
+\r
+ $("#theme_file_table").on('click', '.ThemeFileDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'theme_del_file',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_theme[current_tab_index].filelist.splice(index, 1);\r
+ FillThemeFileTable(m_data_theme[current_tab_index].filelist, m_data_theme[current_tab_index].default_file);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+ $("#id_theme_tbl_fonts").on('click', '.ThemeFontAddBtn', function() {\r
+ var tip = (g_current_os === 'windows') ? '\\ventoy\\themes\\blur\\Hack-12.pf2' : "/ventoy/themes/blur/Hack-12.pf2";\r
+ var para = {\r
+ "title": g_vtoy_cur_language.STR_ADD_FONT,\r
+ "fuzzy": 0,\r
+ "tip1": g_current_dir + tip,\r
+ "tip2": '',\r
+ "tip3": '',\r
+ "extra": false,\r
+ "extra_title": ''\r
+ };\r
+\r
+ VtoySelectFilePath(OnAddThemeFont, para);\r
+ });\r
+\r
+ $("#id_theme_tbl_fonts").on('click', '.ThemeFontDelBtn', function() {\r
+ var $tr = $(this).closest('tr');\r
+ var path = $tr.data('path');\r
+ var index = $tr.data('index');\r
+\r
+ callVtoySync({\r
+ method : 'theme_del_font',\r
+ index: current_tab_index,\r
+ path: path\r
+ }, function(data) {\r
+ m_data_theme[current_tab_index].fontslist.splice(index, 1);\r
+ FillThemeFontTable(m_data_theme[current_tab_index].fontslist);\r
+ Message.success(g_vtoy_cur_language.STR_SAVE_SUCCESS);\r
+ });\r
+ });\r
+\r
+ $('select[id=id_theme_sel_gfxmode]').change(VtoySaveCurrentPage);\r
+ $('select[id=id_theme_sel_dismode]').change(VtoySaveCurrentPage);\r
+\r
+ $('#id_tab_theme a[href="#tab_0"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_theme a[href="#tab_1"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_theme a[href="#tab_2"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_theme a[href="#tab_3"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_theme a[href="#tab_4"]').click(OnClickMultiModeTab);\r
+ $('#id_tab_theme a[href="#tab_5"]').click(OnClickMultiModeTab);\r
+\r
+ $('#id_tab_theme a[href="#tab_0"]').tab('show');\r
+ VtoyFillCurrentPageItem(m_data_theme[0]);\r
+ VtoyPageLanguageChange(g_current_language);\r
+\r
+</script>\r
--- /dev/null
+/*@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic);*/
+/*!
+ * AdminLTE v2.3.0
+ * Author: Almsaeed Studio
+ * Website: Almsaeed Studio <http://almsaeedstudio.com>
+ * License: Open source - MIT
+ * Please visit http://opensource.org/licenses/MIT for more information
+!*/
+/*
+ * Core: General Layout Style
+ * -------------------------
+ */
+html,
+body {
+ min-height: 100%;
+}
+.layout-boxed html,
+.layout-boxed body {
+ height: 100%;
+}
+body {
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-weight: 400;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+/* Layout */
+.wrapper {
+ min-height: 100%;
+ position: static;
+ overflow: hidden;
+}
+.wrapper:before,
+.wrapper:after {
+ content: " ";
+ display: table;
+}
+.wrapper:after {
+ clear: both;
+}
+.layout-boxed .wrapper {
+ max-width: 1250px;
+ margin: 0 auto;
+ min-height: 100%;
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
+ position: relative;
+}
+.layout-boxed {
+ background: url('../img/boxed-bg.jpg') repeat fixed;
+}
+/*
+ * Content Wrapper - contains the main content
+ * ```.right-side has been deprecated as of v2.0.0 in favor of .content-wrapper ```
+ */
+.content-wrapper,
+.right-side,
+.main-footer {
+ -webkit-transition: -webkit-transform 0.3s ease-in-out, margin 0.3s ease-in-out;
+ -moz-transition: -moz-transform 0.3s ease-in-out, margin 0.3s ease-in-out;
+ -o-transition: -o-transform 0.3s ease-in-out, margin 0.3s ease-in-out;
+ transition: transform 0.3s ease-in-out, margin 0.3s ease-in-out;
+ margin-left: 230px;
+ z-index: 820;
+}
+.layout-top-nav .content-wrapper,
+.layout-top-nav .right-side,
+.layout-top-nav .main-footer {
+ margin-left: 0;
+}
+@media (max-width: 767px) {
+ .content-wrapper,
+ .right-side,
+ .main-footer {
+ margin-left: 0;
+ }
+}
+@media (min-width: 768px) {
+ .sidebar-collapse .content-wrapper,
+ .sidebar-collapse .right-side,
+ .sidebar-collapse .main-footer {
+ margin-left: 0;
+ }
+}
+@media (max-width: 767px) {
+ .sidebar-open .content-wrapper,
+ .sidebar-open .right-side,
+ .sidebar-open .main-footer {
+ -webkit-transform: translate(230px, 0);
+ -ms-transform: translate(230px, 0);
+ -o-transform: translate(230px, 0);
+ transform: translate(230px, 0);
+ }
+}
+.content-wrapper,
+.right-side {
+ min-height: 100%;
+ background-color: #ecf0f5;
+ z-index: 800;
+}
+.main-footer {
+ background: #fff;
+ padding: 15px;
+ color: #444;
+ border-top: 1px solid #d2d6de;
+}
+/* Fixed layout */
+.fixed .main-header,
+.fixed .main-sidebar,
+.fixed .left-side {
+ position: fixed;
+}
+.fixed .main-header {
+ top: 0;
+ right: 0;
+ left: 0;
+}
+.fixed .content-wrapper,
+.fixed .right-side {
+ padding-top: 50px;
+}
+@media (max-width: 767px) {
+ .fixed .content-wrapper,
+ .fixed .right-side {
+ padding-top: 100px;
+ }
+}
+.fixed.layout-boxed .wrapper {
+ max-width: 100%;
+}
+body.hold-transition .content-wrapper,
+body.hold-transition .right-side,
+body.hold-transition .main-footer,
+body.hold-transition .main-sidebar,
+body.hold-transition .left-side,
+body.hold-transition .main-header > .navbar,
+body.hold-transition .main-header .logo {
+ /* Fix for IE */
+ -webkit-transition: none;
+ -o-transition: none;
+ transition: none;
+}
+/* Content */
+.content {
+ min-height: 250px;
+ padding: 15px;
+ margin-right: auto;
+ margin-left: auto;
+ padding-left: 15px;
+ padding-right: 15px;
+}
+/* H1 - H6 font */
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6 {
+ font-family: 'Source Sans Pro', sans-serif;
+}
+/* General Links */
+a {
+ color: #3c8dbc;
+}
+a:hover,
+a:active,
+a:focus {
+ outline: none;
+ text-decoration: none;
+ color: #72afd2;
+}
+/* Page Header */
+.page-header {
+ margin: 10px 0 20px 0;
+ font-size: 22px;
+}
+.page-header > small {
+ color: #666;
+ display: block;
+ margin-top: 5px;
+}
+/*
+ * Component: Main Header
+ * ----------------------
+ */
+.main-header {
+ position: relative;
+ max-height: 100px;
+ z-index: 1030;
+}
+.main-header > .navbar {
+ -webkit-transition: margin-left 0.3s ease-in-out;
+ -o-transition: margin-left 0.3s ease-in-out;
+ transition: margin-left 0.3s ease-in-out;
+ margin-bottom: 0;
+ margin-left: 230px;
+ border: none;
+ min-height: 50px;
+ border-radius: 0;
+}
+.layout-top-nav .main-header > .navbar {
+ margin-left: 0;
+}
+.main-header #navbar-search-input.form-control {
+ background: rgba(255, 255, 255, 0.2);
+ border-color: transparent;
+}
+.main-header #navbar-search-input.form-control:focus,
+.main-header #navbar-search-input.form-control:active {
+ border-color: rgba(0, 0, 0, 0.1);
+ background: rgba(255, 255, 255, 0.9);
+}
+.main-header #navbar-search-input.form-control::-moz-placeholder {
+ color: #ccc;
+ opacity: 1;
+}
+.main-header #navbar-search-input.form-control:-ms-input-placeholder {
+ color: #ccc;
+}
+.main-header #navbar-search-input.form-control::-webkit-input-placeholder {
+ color: #ccc;
+}
+.main-header .navbar-custom-menu,
+.main-header .navbar-right {
+ float: right;
+}
+@media (max-width: 991px) {
+ .main-header .navbar-custom-menu a,
+ .main-header .navbar-right a {
+ color: inherit;
+ background: transparent;
+ }
+}
+@media (max-width: 767px) {
+ .main-header .navbar-right {
+ float: none;
+ }
+ .navbar-collapse .main-header .navbar-right {
+ margin: 7.5px -15px;
+ }
+ .main-header .navbar-right > li {
+ color: inherit;
+ border: 0;
+ }
+}
+.main-header .sidebar-toggle {
+ float: left;
+ background-color: transparent;
+ background-image: none;
+ padding: 15px 15px;
+ font-family: fontAwesome;
+}
+.main-header .sidebar-toggle:before {
+ content: "\f0c9";
+}
+.main-header .sidebar-toggle:hover {
+ color: #fff;
+}
+.main-header .sidebar-toggle:focus,
+.main-header .sidebar-toggle:active {
+ background: transparent;
+}
+.main-header .sidebar-toggle .icon-bar {
+ display: none;
+}
+.main-header .navbar .nav > li.user > a > .fa,
+.main-header .navbar .nav > li.user > a > .glyphicon,
+.main-header .navbar .nav > li.user > a > .ion {
+ margin-right: 5px;
+}
+.main-header .navbar .nav > li > a > .label {
+ position: absolute;
+ top: 9px;
+ right: 7px;
+ text-align: center;
+ font-size: 9px;
+ padding: 2px 3px;
+ line-height: .9;
+}
+.main-header .logo {
+ -webkit-transition: width 0.3s ease-in-out;
+ -o-transition: width 0.3s ease-in-out;
+ transition: width 0.3s ease-in-out;
+ display: block;
+ float: left;
+ height: 50px;
+ font-size: 20px;
+ line-height: 50px;
+ text-align: center;
+ width: 230px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ padding: 0 15px;
+ font-weight: 300;
+ overflow: hidden;
+}
+.main-header .logo .logo-lg {
+ display: block;
+}
+.main-header .logo .logo-mini {
+ display: none;
+}
+.main-header .navbar-brand {
+ color: #fff;
+}
+.content-header {
+ position: relative;
+ padding: 15px 15px 0 15px;
+}
+.content-header > h1 {
+ margin: 0;
+ font-size: 24px;
+}
+.content-header > h1 > small {
+ font-size: 15px;
+ display: inline-block;
+ padding-left: 4px;
+ font-weight: 300;
+}
+.content-header > .breadcrumb {
+ float: right;
+ background: transparent;
+ margin-top: 0;
+ margin-bottom: 0;
+ font-size: 12px;
+ padding: 7px 5px;
+ position: absolute;
+ top: 15px;
+ right: 10px;
+ border-radius: 2px;
+}
+.content-header > .breadcrumb > li > a {
+ color: #444;
+ text-decoration: none;
+ display: inline-block;
+}
+.content-header > .breadcrumb > li > a > .fa,
+.content-header > .breadcrumb > li > a > .glyphicon,
+.content-header > .breadcrumb > li > a > .ion {
+ margin-right: 5px;
+}
+.content-header > .breadcrumb > li + li:before {
+ content: '>\00a0';
+}
+@media (max-width: 991px) {
+ .content-header > .breadcrumb {
+ position: relative;
+ margin-top: 5px;
+ top: 0;
+ right: 0;
+ float: none;
+ background: #d2d6de;
+ padding-left: 10px;
+ }
+ .content-header > .breadcrumb li:before {
+ color: #97a0b3;
+ }
+}
+.navbar-toggle {
+ color: #fff;
+ border: 0;
+ margin: 0;
+ padding: 15px 15px;
+}
+@media (max-width: 991px) {
+ .navbar-custom-menu .navbar-nav > li {
+ float: left;
+ }
+ .navbar-custom-menu .navbar-nav {
+ margin: 0;
+ float: left;
+ }
+ .navbar-custom-menu .navbar-nav > li > a {
+ padding-top: 15px;
+ padding-bottom: 15px;
+ line-height: 20px;
+ }
+}
+@media (max-width: 767px) {
+ .main-header {
+ position: relative;
+ }
+ .main-header .logo,
+ .main-header .navbar {
+ width: 100%;
+ float: none;
+ }
+ .main-header .navbar {
+ margin: 0;
+ }
+ .main-header .navbar-custom-menu {
+ float: right;
+ }
+}
+@media (max-width: 991px) {
+ .navbar-collapse.pull-left {
+ float: none!important;
+ }
+ .navbar-collapse.pull-left + .navbar-custom-menu {
+ display: block;
+ position: absolute;
+ top: 0;
+ right: 40px;
+ }
+}
+/*
+ * Component: Sidebar
+ * ------------------
+ */
+.main-sidebar,
+.left-side {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding-top: 50px;
+ min-height: 100%;
+ width: 230px;
+ z-index: 810;
+ -webkit-transition: -webkit-transform 0.3s ease-in-out, width 0.3s ease-in-out;
+ -moz-transition: -moz-transform 0.3s ease-in-out, width 0.3s ease-in-out;
+ -o-transition: -o-transform 0.3s ease-in-out, width 0.3s ease-in-out;
+ transition: transform 0.3s ease-in-out, width 0.3s ease-in-out;
+}
+@media (max-width: 767px) {
+ .main-sidebar,
+ .left-side {
+ padding-top: 100px;
+ }
+}
+@media (max-width: 767px) {
+ .main-sidebar,
+ .left-side {
+ -webkit-transform: translate(-230px, 0);
+ -ms-transform: translate(-230px, 0);
+ -o-transform: translate(-230px, 0);
+ transform: translate(-230px, 0);
+ }
+}
+@media (min-width: 768px) {
+ .sidebar-collapse .main-sidebar,
+ .sidebar-collapse .left-side {
+ -webkit-transform: translate(-230px, 0);
+ -ms-transform: translate(-230px, 0);
+ -o-transform: translate(-230px, 0);
+ transform: translate(-230px, 0);
+ }
+}
+@media (max-width: 767px) {
+ .sidebar-open .main-sidebar,
+ .sidebar-open .left-side {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+ }
+}
+.sidebar {
+ padding-bottom: 10px;
+}
+.sidebar-form input:focus {
+ border-color: transparent;
+}
+.user-panel {
+ position: relative;
+ width: 100%;
+ padding: 10px;
+ overflow: hidden;
+}
+.user-panel:before,
+.user-panel:after {
+ content: " ";
+ display: table;
+}
+.user-panel:after {
+ clear: both;
+}
+.user-panel > .image > img {
+ width: 100%;
+ max-width: 45px;
+ height: auto;
+}
+.user-panel > .info {
+ padding: 5px 5px 5px 15px;
+ line-height: 1;
+ position: absolute;
+ left: 55px;
+}
+.user-panel > .info > p {
+ font-weight: 600;
+ margin-bottom: 9px;
+}
+.user-panel > .info > a {
+ text-decoration: none;
+ padding-right: 5px;
+ margin-top: 3px;
+ font-size: 11px;
+}
+.user-panel > .info > a > .fa,
+.user-panel > .info > a > .ion,
+.user-panel > .info > a > .glyphicon {
+ margin-right: 3px;
+}
+.sidebar-menu {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+.sidebar-menu > li {
+ position: relative;
+ margin: 0;
+ padding: 0;
+}
+.sidebar-menu > li > a {
+ padding: 12px 5px 12px 15px;
+ display: block;
+}
+.sidebar-menu > li > a > .fa,
+.sidebar-menu > li > a > .glyphicon,
+.sidebar-menu > li > a > .ion {
+ width: 20px;
+}
+.sidebar-menu > li .label,
+.sidebar-menu > li .badge {
+ margin-top: 3px;
+ margin-right: 5px;
+}
+.sidebar-menu li.header {
+ padding: 10px 25px 10px 15px;
+ font-size: 12px;
+}
+.sidebar-menu li > a > .fa-angle-left {
+ width: auto;
+ height: auto;
+ padding: 0;
+ margin-right: 10px;
+ margin-top: 3px;
+}
+.sidebar-menu li.active > a > .fa-angle-left {
+ -webkit-transform: rotate(-90deg);
+ -ms-transform: rotate(-90deg);
+ -o-transform: rotate(-90deg);
+ transform: rotate(-90deg);
+}
+.sidebar-menu li.active > .treeview-menu {
+ display: block;
+}
+.sidebar-menu .treeview-menu {
+ display: none;
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ padding-left: 5px;
+}
+.sidebar-menu .treeview-menu .treeview-menu {
+ padding-left: 20px;
+}
+.sidebar-menu .treeview-menu > li {
+ margin: 0;
+}
+.sidebar-menu .treeview-menu > li > a {
+ padding: 5px 5px 5px 15px;
+ display: block;
+ font-size: 14px;
+}
+.sidebar-menu .treeview-menu > li > a > .fa,
+.sidebar-menu .treeview-menu > li > a > .glyphicon,
+.sidebar-menu .treeview-menu > li > a > .ion {
+ width: 20px;
+}
+.sidebar-menu .treeview-menu > li > a > .fa-angle-left,
+.sidebar-menu .treeview-menu > li > a > .fa-angle-down {
+ width: auto;
+}
+/*
+ * Component: Sidebar Mini
+ */
+@media (min-width: 768px) {
+ .sidebar-mini.sidebar-collapse .content-wrapper,
+ .sidebar-mini.sidebar-collapse .right-side,
+ .sidebar-mini.sidebar-collapse .main-footer {
+ margin-left: 50px!important;
+ z-index: 840;
+ }
+ .sidebar-mini.sidebar-collapse .main-sidebar {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+ width: 50px!important;
+ z-index: 850;
+ }
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li {
+ position: relative;
+ }
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li > a {
+ margin-right: 0;
+ }
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li > a > span {
+ border-top-right-radius: 4px;
+ }
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li:not(.treeview) > a > span {
+ border-bottom-right-radius: 4px;
+ }
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu {
+ padding-top: 5px;
+ padding-bottom: 5px;
+ border-bottom-right-radius: 4px;
+ }
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span:not(.pull-right),
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > .treeview-menu {
+ display: block!important;
+ position: absolute;
+ width: 180px;
+ left: 50px;
+ }
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > a > span {
+ top: 0;
+ margin-left: -3px;
+ padding: 12px 5px 12px 20px;
+ background-color: inherit;
+ }
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li:hover > .treeview-menu {
+ top: 44px;
+ margin-left: 0;
+ }
+ .sidebar-mini.sidebar-collapse .main-sidebar .user-panel > .info,
+ .sidebar-mini.sidebar-collapse .sidebar-form,
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li > a > span,
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li > .treeview-menu,
+ .sidebar-mini.sidebar-collapse .sidebar-menu > li > a > .pull-right,
+ .sidebar-mini.sidebar-collapse .sidebar-menu li.header {
+ display: none!important;
+ -webkit-transform: translateZ(0);
+ }
+ .sidebar-mini.sidebar-collapse .main-header .logo {
+ width: 50px;
+ }
+ .sidebar-mini.sidebar-collapse .main-header .logo > .logo-mini {
+ display: block;
+ margin-left: -15px;
+ margin-right: -15px;
+ font-size: 18px;
+ }
+ .sidebar-mini.sidebar-collapse .main-header .logo > .logo-lg {
+ display: none;
+ }
+ .sidebar-mini.sidebar-collapse .main-header .navbar {
+ margin-left: 50px;
+ }
+}
+.sidebar-menu,
+.main-sidebar .user-panel,
+.sidebar-menu > li.header {
+ white-space: nowrap;
+ overflow: hidden;
+}
+.sidebar-menu:hover {
+ overflow: visible;
+}
+.sidebar-form,
+.sidebar-menu > li.header {
+ overflow: hidden;
+ text-overflow: clip;
+}
+.sidebar-menu li > a {
+ position: relative;
+}
+.sidebar-menu li > a > .pull-right {
+ position: absolute;
+ top: 50%;
+ right: 10px;
+ margin-top: -7px;
+}
+/*
+ * Component: Control sidebar. By default, this is the right sidebar.
+ */
+.control-sidebar-bg {
+ position: fixed;
+ z-index: 1000;
+ bottom: 0;
+}
+.control-sidebar-bg,
+.control-sidebar {
+ top: 0;
+ right: -230px;
+ width: 230px;
+ -webkit-transition: right 0.3s ease-in-out;
+ -o-transition: right 0.3s ease-in-out;
+ transition: right 0.3s ease-in-out;
+}
+.control-sidebar {
+ position: absolute;
+ padding-top: 50px;
+ z-index: 1010;
+}
+@media (max-width: 768px) {
+ .control-sidebar {
+ padding-top: 100px;
+ }
+}
+.control-sidebar > .tab-content {
+ padding: 10px 15px;
+}
+.control-sidebar.control-sidebar-open,
+.control-sidebar.control-sidebar-open + .control-sidebar-bg {
+ right: 0;
+}
+.control-sidebar-open .control-sidebar-bg,
+.control-sidebar-open .control-sidebar {
+ right: 0;
+}
+@media (min-width: 768px) {
+ .control-sidebar-open .content-wrapper,
+ .control-sidebar-open .right-side,
+ .control-sidebar-open .main-footer {
+ margin-right: 230px;
+ }
+}
+.nav-tabs.control-sidebar-tabs > li:first-of-type > a,
+.nav-tabs.control-sidebar-tabs > li:first-of-type > a:hover,
+.nav-tabs.control-sidebar-tabs > li:first-of-type > a:focus {
+ border-left-width: 0;
+}
+.nav-tabs.control-sidebar-tabs > li > a {
+ border-radius: 0;
+}
+.nav-tabs.control-sidebar-tabs > li > a,
+.nav-tabs.control-sidebar-tabs > li > a:hover {
+ border-top: none;
+ border-right: none;
+ border-left: 1px solid transparent;
+ border-bottom: 1px solid transparent;
+}
+.nav-tabs.control-sidebar-tabs > li > a .icon {
+ font-size: 16px;
+}
+.nav-tabs.control-sidebar-tabs > li.active > a,
+.nav-tabs.control-sidebar-tabs > li.active > a:hover,
+.nav-tabs.control-sidebar-tabs > li.active > a:focus,
+.nav-tabs.control-sidebar-tabs > li.active > a:active {
+ border-top: none;
+ border-right: none;
+ border-bottom: none;
+}
+@media (max-width: 768px) {
+ .nav-tabs.control-sidebar-tabs {
+ display: table;
+ }
+ .nav-tabs.control-sidebar-tabs > li {
+ display: table-cell;
+ }
+}
+.control-sidebar-heading {
+ font-weight: 400;
+ font-size: 16px;
+ padding: 10px 0;
+ margin-bottom: 10px;
+}
+.control-sidebar-subheading {
+ display: block;
+ font-weight: 400;
+ font-size: 14px;
+}
+.control-sidebar-menu {
+ list-style: none;
+ padding: 0;
+ margin: 0 -15px;
+}
+.control-sidebar-menu > li > a {
+ display: block;
+ padding: 10px 15px;
+}
+.control-sidebar-menu > li > a:before,
+.control-sidebar-menu > li > a:after {
+ content: " ";
+ display: table;
+}
+.control-sidebar-menu > li > a:after {
+ clear: both;
+}
+.control-sidebar-menu > li > a > .control-sidebar-subheading {
+ margin-top: 0;
+}
+.control-sidebar-menu .menu-icon {
+ float: left;
+ width: 35px;
+ height: 35px;
+ border-radius: 50%;
+ text-align: center;
+ line-height: 35px;
+}
+.control-sidebar-menu .menu-info {
+ margin-left: 45px;
+ margin-top: 3px;
+}
+.control-sidebar-menu .menu-info > .control-sidebar-subheading {
+ margin: 0;
+}
+.control-sidebar-menu .menu-info > p {
+ margin: 0;
+ font-size: 11px;
+}
+.control-sidebar-menu .progress {
+ margin: 0;
+}
+.control-sidebar-dark {
+ color: #b8c7ce;
+}
+.control-sidebar-dark,
+.control-sidebar-dark + .control-sidebar-bg {
+ background: #222d32;
+}
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs {
+ border-bottom: #1c2529;
+}
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a {
+ background: #181f23;
+ color: #b8c7ce;
+}
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a,
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:hover,
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:focus {
+ border-left-color: #141a1d;
+ border-bottom-color: #141a1d;
+}
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:hover,
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:focus,
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:active {
+ background: #1c2529;
+}
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li > a:hover {
+ color: #fff;
+}
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li.active > a,
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li.active > a:hover,
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li.active > a:focus,
+.control-sidebar-dark .nav-tabs.control-sidebar-tabs > li.active > a:active {
+ background: #222d32;
+ color: #fff;
+}
+.control-sidebar-dark .control-sidebar-heading,
+.control-sidebar-dark .control-sidebar-subheading {
+ color: #fff;
+}
+.control-sidebar-dark .control-sidebar-menu > li > a:hover {
+ background: #1e282c;
+}
+.control-sidebar-dark .control-sidebar-menu > li > a .menu-info > p {
+ color: #b8c7ce;
+}
+.control-sidebar-light {
+ color: #5e5e5e;
+}
+.control-sidebar-light,
+.control-sidebar-light + .control-sidebar-bg {
+ background: #f9fafc;
+ border-left: 1px solid #d2d6de;
+}
+.control-sidebar-light .nav-tabs.control-sidebar-tabs {
+ border-bottom: #d2d6de;
+}
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a {
+ background: #e8ecf4;
+ color: #444444;
+}
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a,
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:hover,
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:focus {
+ border-left-color: #d2d6de;
+ border-bottom-color: #d2d6de;
+}
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:hover,
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:focus,
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li > a:active {
+ background: #eff1f7;
+}
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li.active > a,
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li.active > a:hover,
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li.active > a:focus,
+.control-sidebar-light .nav-tabs.control-sidebar-tabs > li.active > a:active {
+ background: #f9fafc;
+ color: #111;
+}
+.control-sidebar-light .control-sidebar-heading,
+.control-sidebar-light .control-sidebar-subheading {
+ color: #111;
+}
+.control-sidebar-light .control-sidebar-menu {
+ margin-left: -14px;
+}
+.control-sidebar-light .control-sidebar-menu > li > a:hover {
+ background: #f4f4f5;
+}
+.control-sidebar-light .control-sidebar-menu > li > a .menu-info > p {
+ color: #5e5e5e;
+}
+/*
+ * Component: Dropdown menus
+ * -------------------------
+ */
+/*Dropdowns in general*/
+.dropdown-menu {
+ box-shadow: none;
+ border-color: #eee;
+}
+.dropdown-menu > li > a {
+ color: #777;
+}
+.dropdown-menu > li > a > .glyphicon,
+.dropdown-menu > li > a > .fa,
+.dropdown-menu > li > a > .ion {
+ margin-right: 10px;
+}
+.dropdown-menu > li > a:hover {
+ background-color: #e1e3e9;
+ color: #333;
+}
+.dropdown-menu > .divider {
+ background-color: #eee;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu,
+.navbar-nav > .messages-menu > .dropdown-menu,
+.navbar-nav > .tasks-menu > .dropdown-menu {
+ width: 280px;
+ padding: 0 0 0 0;
+ margin: 0;
+ top: 100%;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li,
+.navbar-nav > .messages-menu > .dropdown-menu > li,
+.navbar-nav > .tasks-menu > .dropdown-menu > li {
+ position: relative;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li.header,
+.navbar-nav > .messages-menu > .dropdown-menu > li.header,
+.navbar-nav > .tasks-menu > .dropdown-menu > li.header {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+ background-color: #ffffff;
+ padding: 7px 10px;
+ border-bottom: 1px solid #f4f4f4;
+ color: #444444;
+ font-size: 14px;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li.footer > a,
+.navbar-nav > .messages-menu > .dropdown-menu > li.footer > a,
+.navbar-nav > .tasks-menu > .dropdown-menu > li.footer > a {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+ font-size: 12px;
+ background-color: #fff;
+ padding: 7px 10px;
+ border-bottom: 1px solid #eeeeee;
+ color: #444!important;
+ text-align: center;
+}
+@media (max-width: 991px) {
+ .navbar-nav > .notifications-menu > .dropdown-menu > li.footer > a,
+ .navbar-nav > .messages-menu > .dropdown-menu > li.footer > a,
+ .navbar-nav > .tasks-menu > .dropdown-menu > li.footer > a {
+ background: #fff!important;
+ color: #444!important;
+ }
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li.footer > a:hover,
+.navbar-nav > .messages-menu > .dropdown-menu > li.footer > a:hover,
+.navbar-nav > .tasks-menu > .dropdown-menu > li.footer > a:hover {
+ text-decoration: none;
+ font-weight: normal;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li .menu,
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu,
+.navbar-nav > .tasks-menu > .dropdown-menu > li .menu {
+ max-height: 200px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ overflow-x: hidden;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a,
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a,
+.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a {
+ display: block;
+ white-space: nowrap;
+ /* Prevent text from breaking */
+ border-bottom: 1px solid #f4f4f4;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a:hover,
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:hover,
+.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a:hover {
+ background: #f4f4f4;
+ text-decoration: none;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a {
+ color: #444444;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ padding: 10px;
+}
+.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .glyphicon,
+.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .fa,
+.navbar-nav > .notifications-menu > .dropdown-menu > li .menu > li > a > .ion {
+ width: 20px;
+}
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a {
+ margin: 0;
+ padding: 10px 10px;
+}
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > div > img {
+ margin: auto 10px auto auto;
+ width: 40px;
+ height: 40px;
+}
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > h4 {
+ padding: 0;
+ margin: 0 0 0 45px;
+ color: #444444;
+ font-size: 15px;
+ position: relative;
+}
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > h4 > small {
+ color: #999999;
+ font-size: 10px;
+ position: absolute;
+ top: 0;
+ right: 0;
+}
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a > p {
+ margin: 0 0 0 45px;
+ font-size: 12px;
+ color: #888888;
+}
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:before,
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:after {
+ content: " ";
+ display: table;
+}
+.navbar-nav > .messages-menu > .dropdown-menu > li .menu > li > a:after {
+ clear: both;
+}
+.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a {
+ padding: 10px;
+}
+.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a > h3 {
+ font-size: 14px;
+ padding: 0;
+ margin: 0 0 10px 0;
+ color: #666666;
+}
+.navbar-nav > .tasks-menu > .dropdown-menu > li .menu > li > a > .progress {
+ padding: 0;
+ margin: 0;
+}
+.navbar-nav > .user-menu > .dropdown-menu {
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+ padding: 1px 0 0 0;
+ border-top-width: 0;
+ width: 280px;
+}
+.navbar-nav > .user-menu > .dropdown-menu,
+.navbar-nav > .user-menu > .dropdown-menu > .user-body {
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+.navbar-nav > .user-menu > .dropdown-menu > li.user-header {
+ height: 175px;
+ padding: 10px;
+ text-align: center;
+}
+.navbar-nav > .user-menu > .dropdown-menu > li.user-header > img {
+ z-index: 5;
+ height: 90px;
+ width: 90px;
+ border: 3px solid;
+ border-color: transparent;
+ border-color: rgba(255, 255, 255, 0.2);
+}
+.navbar-nav > .user-menu > .dropdown-menu > li.user-header > p {
+ z-index: 5;
+ color: #fff;
+ color: rgba(255, 255, 255, 0.8);
+ font-size: 17px;
+ margin-top: 10px;
+}
+.navbar-nav > .user-menu > .dropdown-menu > li.user-header > p > small {
+ display: block;
+ font-size: 12px;
+}
+.navbar-nav > .user-menu > .dropdown-menu > .user-body {
+ padding: 15px;
+ border-bottom: 1px solid #f4f4f4;
+ border-top: 1px solid #dddddd;
+}
+.navbar-nav > .user-menu > .dropdown-menu > .user-body:before,
+.navbar-nav > .user-menu > .dropdown-menu > .user-body:after {
+ content: " ";
+ display: table;
+}
+.navbar-nav > .user-menu > .dropdown-menu > .user-body:after {
+ clear: both;
+}
+.navbar-nav > .user-menu > .dropdown-menu > .user-body a {
+ color: #444 !important;
+}
+@media (max-width: 991px) {
+ .navbar-nav > .user-menu > .dropdown-menu > .user-body a {
+ background: #fff !important;
+ color: #444 !important;
+ }
+}
+.navbar-nav > .user-menu > .dropdown-menu > .user-footer {
+ background-color: #f9f9f9;
+ padding: 10px;
+}
+.navbar-nav > .user-menu > .dropdown-menu > .user-footer:before,
+.navbar-nav > .user-menu > .dropdown-menu > .user-footer:after {
+ content: " ";
+ display: table;
+}
+.navbar-nav > .user-menu > .dropdown-menu > .user-footer:after {
+ clear: both;
+}
+.navbar-nav > .user-menu > .dropdown-menu > .user-footer .btn-default {
+ color: #666666;
+}
+@media (max-width: 991px) {
+ .navbar-nav > .user-menu > .dropdown-menu > .user-footer .btn-default:hover {
+ background-color: #f9f9f9;
+ }
+}
+.navbar-nav > .user-menu .user-image {
+ float: left;
+ width: 25px;
+ height: 25px;
+ border-radius: 50%;
+ margin-right: 10px;
+ margin-top: -2px;
+}
+@media (max-width: 767px) {
+ .navbar-nav > .user-menu .user-image {
+ float: none;
+ margin-right: 0;
+ margin-top: -8px;
+ line-height: 10px;
+ }
+}
+/* Add fade animation to dropdown menus by appending
+ the class .animated-dropdown-menu to the .dropdown-menu ul (or ol)*/
+.open:not(.dropup) > .animated-dropdown-menu {
+ backface-visibility: visible !important;
+ -webkit-animation: flipInX 0.7s both;
+ -o-animation: flipInX 0.7s both;
+ animation: flipInX 0.7s both;
+}
+@keyframes flipInX {
+ 0% {
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+ 40% {
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transition-timing-function: ease-in;
+ }
+ 60% {
+ transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ opacity: 1;
+ }
+ 80% {
+ transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ }
+ 100% {
+ transform: perspective(400px);
+ }
+}
+@-webkit-keyframes flipInX {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ opacity: 0;
+ }
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ }
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ opacity: 1;
+ }
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ }
+ 100% {
+ -webkit-transform: perspective(400px);
+ }
+}
+/* Fix dropdown menu in navbars */
+.navbar-custom-menu > .navbar-nav > li {
+ position: relative;
+}
+.navbar-custom-menu > .navbar-nav > li > .dropdown-menu {
+ position: absolute;
+ right: 0;
+ left: auto;
+}
+@media (max-width: 991px) {
+ .navbar-custom-menu > .navbar-nav {
+ float: right;
+ }
+ .navbar-custom-menu > .navbar-nav > li {
+ position: static;
+ }
+ .navbar-custom-menu > .navbar-nav > li > .dropdown-menu {
+ position: absolute;
+ right: 5%;
+ left: auto;
+ border: 1px solid #ddd;
+ background: #fff;
+ }
+}
+/*
+ * Component: Form
+ * ---------------
+ */
+.form-control {
+ border-radius: 0;
+ box-shadow: none;
+ border-color: #d2d6de;
+}
+.form-control:focus {
+ border-color: #3c8dbc;
+ box-shadow: none;
+}
+.form-control::-moz-placeholder,
+.form-control:-ms-input-placeholder,
+.form-control::-webkit-input-placeholder {
+ color: #bbb;
+ opacity: 1;
+}
+.form-control:not(select) {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+}
+.form-group.has-success label {
+ color: #00a65a;
+}
+.form-group.has-success .form-control {
+ border-color: #00a65a;
+ box-shadow: none;
+}
+.form-group.has-warning label {
+ color: #f39c12;
+}
+.form-group.has-warning .form-control {
+ border-color: #f39c12;
+ box-shadow: none;
+}
+.form-group.has-error label {
+ color: #dd4b39;
+}
+.form-group.has-error .form-control {
+ border-color: #dd4b39;
+ box-shadow: none;
+}
+/* Input group */
+.input-group .input-group-addon {
+ border-radius: 0;
+ border-color: #d2d6de;
+ background-color: #fff;
+}
+/* button groups */
+.btn-group-vertical .btn.btn-flat:first-of-type,
+.btn-group-vertical .btn.btn-flat:last-of-type {
+ border-radius: 0;
+}
+.icheck > label {
+ padding-left: 0;
+}
+/* support Font Awesome icons in form-control */
+.form-control-feedback.fa {
+ line-height: 34px;
+}
+.input-lg + .form-control-feedback.fa,
+.input-group-lg + .form-control-feedback.fa,
+.form-group-lg .form-control + .form-control-feedback.fa {
+ line-height: 46px;
+}
+.input-sm + .form-control-feedback.fa,
+.input-group-sm + .form-control-feedback.fa,
+.form-group-sm .form-control + .form-control-feedback.fa {
+ line-height: 30px;
+}
+/*
+ * Component: Progress Bar
+ * -----------------------
+ */
+.progress,
+.progress > .progress-bar {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.progress,
+.progress > .progress-bar,
+.progress .progress-bar,
+.progress > .progress-bar .progress-bar {
+ border-radius: 1px;
+}
+/* size variation */
+.progress.sm,
+.progress-sm {
+ height: 10px;
+}
+.progress.sm,
+.progress-sm,
+.progress.sm .progress-bar,
+.progress-sm .progress-bar {
+ border-radius: 1px;
+}
+.progress.xs,
+.progress-xs {
+ height: 7px;
+}
+.progress.xs,
+.progress-xs,
+.progress.xs .progress-bar,
+.progress-xs .progress-bar {
+ border-radius: 1px;
+}
+.progress.xxs,
+.progress-xxs {
+ height: 3px;
+}
+.progress.xxs,
+.progress-xxs,
+.progress.xxs .progress-bar,
+.progress-xxs .progress-bar {
+ border-radius: 1px;
+}
+/* Vertical bars */
+.progress.vertical {
+ position: relative;
+ width: 30px;
+ height: 200px;
+ display: inline-block;
+ margin-right: 10px;
+}
+.progress.vertical > .progress-bar {
+ width: 100%;
+ position: absolute;
+ bottom: 0;
+}
+.progress.vertical.sm,
+.progress.vertical.progress-sm {
+ width: 20px;
+}
+.progress.vertical.xs,
+.progress.vertical.progress-xs {
+ width: 10px;
+}
+.progress.vertical.xxs,
+.progress.vertical.progress-xxs {
+ width: 3px;
+}
+.progress-group .progress-text {
+ font-weight: 600;
+}
+.progress-group .progress-number {
+ float: right;
+}
+/* Remove margins from progress bars when put in a table */
+.table tr > td .progress {
+ margin: 0;
+}
+.progress-bar-light-blue,
+.progress-bar-primary {
+ background-color: #3c8dbc;
+}
+.progress-striped .progress-bar-light-blue,
+.progress-striped .progress-bar-primary {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-green,
+.progress-bar-success {
+ background-color: #00a65a;
+}
+.progress-striped .progress-bar-green,
+.progress-striped .progress-bar-success {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-aqua,
+.progress-bar-info {
+ background-color: #00c0ef;
+}
+.progress-striped .progress-bar-aqua,
+.progress-striped .progress-bar-info {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-yellow,
+.progress-bar-warning {
+ background-color: #f39c12;
+}
+.progress-striped .progress-bar-yellow,
+.progress-striped .progress-bar-warning {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-bar-red,
+.progress-bar-danger {
+ background-color: #dd4b39;
+}
+.progress-striped .progress-bar-red,
+.progress-striped .progress-bar-danger {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+/*
+ * Component: Small Box
+ * --------------------
+ */
+.small-box {
+ border-radius: 2px;
+ position: relative;
+ display: block;
+ margin-bottom: 20px;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+}
+.small-box > .inner {
+ padding: 10px;
+}
+.small-box > .small-box-footer {
+ position: relative;
+ text-align: center;
+ padding: 3px 0;
+ color: #fff;
+ color: rgba(255, 255, 255, 0.8);
+ display: block;
+ z-index: 10;
+ background: rgba(0, 0, 0, 0.1);
+ text-decoration: none;
+}
+.small-box > .small-box-footer:hover {
+ color: #fff;
+ background: rgba(0, 0, 0, 0.15);
+}
+.small-box h3 {
+ font-size: 38px;
+ font-weight: bold;
+ margin: 0 0 10px 0;
+ white-space: nowrap;
+ padding: 0;
+}
+.small-box p {
+ font-size: 15px;
+}
+.small-box p > small {
+ display: block;
+ color: #f9f9f9;
+ font-size: 13px;
+ margin-top: 5px;
+}
+.small-box h3,
+.small-box p {
+ z-index: 5px;
+}
+.small-box .icon {
+ -webkit-transition: all 0.3s linear;
+ -o-transition: all 0.3s linear;
+ transition: all 0.3s linear;
+ position: absolute;
+ top: -10px;
+ right: 10px;
+ z-index: 0;
+ font-size: 90px;
+ color: rgba(0, 0, 0, 0.15);
+}
+.small-box:hover {
+ text-decoration: none;
+ color: #f9f9f9;
+}
+.small-box:hover .icon {
+ font-size: 95px;
+}
+@media (max-width: 767px) {
+ .small-box {
+ text-align: center;
+ }
+ .small-box .icon {
+ display: none;
+ }
+ .small-box p {
+ font-size: 12px;
+ }
+}
+/*
+ * Component: Box
+ * --------------
+ */
+.box {
+ position: relative;
+ border-radius: 3px;
+ background: #ffffff;
+ border-top: 3px solid #d2d6de;
+ margin-bottom: 20px;
+ width: 100%;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+}
+.box.box-primary {
+ border-top-color: #3c8dbc;
+}
+.box.box-info {
+ border-top-color: #00c0ef;
+}
+.box.box-danger {
+ border-top-color: #dd4b39;
+}
+.box.box-warning {
+ border-top-color: #f39c12;
+}
+.box.box-success {
+ border-top-color: #00a65a;
+}
+.box.box-default {
+ border-top-color: #d2d6de;
+}
+.box.collapsed-box .box-body,
+.box.collapsed-box .box-footer {
+ display: none;
+}
+.box .nav-stacked > li {
+ border-bottom: 1px solid #f4f4f4;
+ margin: 0;
+}
+.box .nav-stacked > li:last-of-type {
+ border-bottom: none;
+}
+.box.height-control .box-body {
+ max-height: 300px;
+ overflow: auto;
+}
+.box .border-right {
+ border-right: 1px solid #f4f4f4;
+}
+.box .border-left {
+ border-left: 1px solid #f4f4f4;
+}
+.box.box-solid {
+ border-top: 0;
+}
+.box.box-solid > .box-header .btn.btn-default {
+ background: transparent;
+}
+.box.box-solid > .box-header .btn:hover,
+.box.box-solid > .box-header a:hover {
+ background: rgba(0, 0, 0, 0.1);
+}
+.box.box-solid.box-default {
+ border: 1px solid #d2d6de;
+}
+.box.box-solid.box-default > .box-header {
+ color: #444444;
+ background: #d2d6de;
+ background-color: #d2d6de;
+}
+.box.box-solid.box-default > .box-header a,
+.box.box-solid.box-default > .box-header .btn {
+ color: #444444;
+}
+.box.box-solid.box-primary {
+ border: 1px solid #3c8dbc;
+}
+.box.box-solid.box-primary > .box-header {
+ color: #ffffff;
+ background: #3c8dbc;
+ background-color: #3c8dbc;
+}
+.box.box-solid.box-primary > .box-header a,
+.box.box-solid.box-primary > .box-header .btn {
+ color: #ffffff;
+}
+.box.box-solid.box-info {
+ border: 1px solid #00c0ef;
+}
+.box.box-solid.box-info > .box-header {
+ color: #ffffff;
+ background: #00c0ef;
+ background-color: #00c0ef;
+}
+.box.box-solid.box-info > .box-header a,
+.box.box-solid.box-info > .box-header .btn {
+ color: #ffffff;
+}
+.box.box-solid.box-danger {
+ border: 1px solid #dd4b39;
+}
+.box.box-solid.box-danger > .box-header {
+ color: #ffffff;
+ background: #dd4b39;
+ background-color: #dd4b39;
+}
+.box.box-solid.box-danger > .box-header a,
+.box.box-solid.box-danger > .box-header .btn {
+ color: #ffffff;
+}
+.box.box-solid.box-warning {
+ border: 1px solid #f39c12;
+}
+.box.box-solid.box-warning > .box-header {
+ color: #ffffff;
+ background: #f39c12;
+ background-color: #f39c12;
+}
+.box.box-solid.box-warning > .box-header a,
+.box.box-solid.box-warning > .box-header .btn {
+ color: #ffffff;
+}
+.box.box-solid.box-success {
+ border: 1px solid #00a65a;
+}
+.box.box-solid.box-success > .box-header {
+ color: #ffffff;
+ background: #00a65a;
+ background-color: #00a65a;
+}
+.box.box-solid.box-success > .box-header a,
+.box.box-solid.box-success > .box-header .btn {
+ color: #ffffff;
+}
+.box.box-solid > .box-header > .box-tools .btn {
+ border: 0;
+ box-shadow: none;
+}
+.box.box-solid[class*='bg'] > .box-header {
+ color: #fff;
+}
+.box .box-group > .box {
+ margin-bottom: 5px;
+}
+.box .knob-label {
+ text-align: center;
+ color: #333;
+ font-weight: 100;
+ font-size: 12px;
+ margin-bottom: 0.3em;
+}
+.box > .overlay,
+.overlay-wrapper > .overlay,
+.box > .loading-img,
+.overlay-wrapper > .loading-img {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+.box .overlay,
+.overlay-wrapper .overlay {
+ z-index: 50;
+ background: rgba(255, 255, 255, 0.7);
+ border-radius: 3px;
+}
+.box .overlay > .fa,
+.overlay-wrapper .overlay > .fa {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin-left: -15px;
+ margin-top: -15px;
+ color: #000;
+ font-size: 30px;
+}
+.box .overlay.dark,
+.overlay-wrapper .overlay.dark {
+ background: rgba(0, 0, 0, 0.5);
+}
+.box-header:before,
+.box-body:before,
+.box-footer:before,
+.box-header:after,
+.box-body:after,
+.box-footer:after {
+ content: " ";
+ display: table;
+}
+.box-header:after,
+.box-body:after,
+.box-footer:after {
+ clear: both;
+}
+.box-header {
+ color: #444;
+ display: block;
+ padding: 10px;
+ position: relative;
+}
+.box-header.with-border {
+ border-bottom: 1px solid #f4f4f4;
+}
+.collapsed-box .box-header.with-border {
+ border-bottom: none;
+}
+.box-header > .fa,
+.box-header > .glyphicon,
+.box-header > .ion,
+.box-header .box-title {
+ display: inline-block;
+ font-size: 18px;
+ margin: 0;
+ line-height: 1;
+}
+.box-header > .fa,
+.box-header > .glyphicon,
+.box-header > .ion {
+ margin-right: 5px;
+}
+.box-header > .box-tools {
+ position: absolute;
+ right: 10px;
+ top: 5px;
+}
+.box-header > .box-tools [data-toggle="tooltip"] {
+ position: relative;
+}
+.box-header > .box-tools.pull-right .dropdown-menu {
+ right: 0;
+ left: auto;
+}
+.btn-box-tool {
+ padding: 5px;
+ font-size: 12px;
+ background: transparent;
+ color: #97a0b3;
+}
+.open .btn-box-tool,
+.btn-box-tool:hover {
+ color: #606c84;
+}
+.btn-box-tool.btn:active {
+ box-shadow: none;
+}
+.box-body {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ padding: 10px;
+}
+.no-header .box-body {
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.box-body > .table {
+ margin-bottom: 0;
+}
+.box-body .fc {
+ margin-top: 5px;
+}
+.box-body .full-width-chart {
+ margin: -19px;
+}
+.box-body.no-padding .full-width-chart {
+ margin: -9px;
+}
+.box-body .box-pane {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 3px;
+}
+.box-body .box-pane-right {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 0;
+}
+.box-footer {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ border-top: 1px solid #f4f4f4;
+ padding: 10px;
+ background-color: #ffffff;
+}
+.chart-legend {
+ margin: 10px 0;
+}
+@media (max-width: 991px) {
+ .chart-legend > li {
+ float: left;
+ margin-right: 10px;
+ }
+}
+.box-comments {
+ background: #f7f7f7;
+}
+.box-comments .box-comment {
+ padding: 8px 0;
+ border-bottom: 1px solid #eee;
+}
+.box-comments .box-comment:before,
+.box-comments .box-comment:after {
+ content: " ";
+ display: table;
+}
+.box-comments .box-comment:after {
+ clear: both;
+}
+.box-comments .box-comment:last-of-type {
+ border-bottom: 0;
+}
+.box-comments .box-comment:first-of-type {
+ padding-top: 0;
+}
+.box-comments .box-comment img {
+ float: left;
+}
+.box-comments .comment-text {
+ margin-left: 40px;
+ color: #555;
+}
+.box-comments .username {
+ color: #444;
+ display: block;
+ font-weight: 600;
+}
+.box-comments .text-muted {
+ font-weight: 400;
+ font-size: 12px;
+}
+/* Widget: TODO LIST */
+.todo-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ overflow: auto;
+}
+.todo-list > li {
+ border-radius: 2px;
+ padding: 10px;
+ background: #f4f4f4;
+ margin-bottom: 2px;
+ border-left: 2px solid #e6e7e8;
+ color: #444;
+}
+.todo-list > li:last-of-type {
+ margin-bottom: 0;
+}
+.todo-list > li > input[type='checkbox'] {
+ margin: 0 10px 0 5px;
+}
+.todo-list > li .text {
+ display: inline-block;
+ margin-left: 5px;
+ font-weight: 600;
+}
+.todo-list > li .label {
+ margin-left: 10px;
+ font-size: 9px;
+}
+.todo-list > li .tools {
+ display: none;
+ float: right;
+ color: #dd4b39;
+}
+.todo-list > li .tools > .fa,
+.todo-list > li .tools > .glyphicon,
+.todo-list > li .tools > .ion {
+ margin-right: 5px;
+ cursor: pointer;
+}
+.todo-list > li:hover .tools {
+ display: inline-block;
+}
+.todo-list > li.done {
+ color: #999;
+}
+.todo-list > li.done .text {
+ text-decoration: line-through;
+ font-weight: 500;
+}
+.todo-list > li.done .label {
+ background: #d2d6de !important;
+}
+.todo-list .danger {
+ border-left-color: #dd4b39;
+}
+.todo-list .warning {
+ border-left-color: #f39c12;
+}
+.todo-list .info {
+ border-left-color: #00c0ef;
+}
+.todo-list .success {
+ border-left-color: #00a65a;
+}
+.todo-list .primary {
+ border-left-color: #3c8dbc;
+}
+.todo-list .handle {
+ display: inline-block;
+ cursor: move;
+ margin: 0 5px;
+}
+/* Chat widget (DEPRECATED - this will be removed in the next major release. Use Direct Chat instead)*/
+.chat {
+ padding: 5px 20px 5px 10px;
+}
+.chat .item {
+ margin-bottom: 10px;
+}
+.chat .item:before,
+.chat .item:after {
+ content: " ";
+ display: table;
+}
+.chat .item:after {
+ clear: both;
+}
+.chat .item > img {
+ width: 40px;
+ height: 40px;
+ border: 2px solid transparent;
+ border-radius: 50%;
+}
+.chat .item > .online {
+ border: 2px solid #00a65a;
+}
+.chat .item > .offline {
+ border: 2px solid #dd4b39;
+}
+.chat .item > .message {
+ margin-left: 55px;
+ margin-top: -40px;
+}
+.chat .item > .message > .name {
+ display: block;
+ font-weight: 600;
+}
+.chat .item > .attachment {
+ border-radius: 3px;
+ background: #f4f4f4;
+ margin-left: 65px;
+ margin-right: 15px;
+ padding: 10px;
+}
+.chat .item > .attachment > h4 {
+ margin: 0 0 5px 0;
+ font-weight: 600;
+ font-size: 14px;
+}
+.chat .item > .attachment > p,
+.chat .item > .attachment > .filename {
+ font-weight: 600;
+ font-size: 13px;
+ font-style: italic;
+ margin: 0;
+}
+.chat .item > .attachment:before,
+.chat .item > .attachment:after {
+ content: " ";
+ display: table;
+}
+.chat .item > .attachment:after {
+ clear: both;
+}
+.box-input {
+ max-width: 200px;
+}
+.modal .panel-body {
+ color: #444;
+}
+/*
+ * Component: Info Box
+ * -------------------
+ */
+.info-box {
+ display: block;
+ min-height: 90px;
+ background: #fff;
+ width: 100%;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ border-radius: 2px;
+ margin-bottom: 15px;
+}
+.info-box small {
+ font-size: 14px;
+}
+.info-box .progress {
+ background: rgba(0, 0, 0, 0.2);
+ margin: 5px -10px 5px -10px;
+ height: 2px;
+}
+.info-box .progress,
+.info-box .progress .progress-bar {
+ border-radius: 0;
+}
+.info-box .progress .progress-bar {
+ background: #fff;
+}
+.info-box-icon {
+ border-top-left-radius: 2px;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 2px;
+ display: block;
+ float: left;
+ height: 90px;
+ width: 90px;
+ text-align: center;
+ font-size: 45px;
+ line-height: 90px;
+ background: rgba(0, 0, 0, 0.2);
+}
+.info-box-icon > img {
+ max-width: 100%;
+}
+.info-box-content {
+ padding: 5px 10px;
+ margin-left: 90px;
+}
+.info-box-number {
+ display: block;
+ font-weight: bold;
+ font-size: 18px;
+}
+.progress-description,
+.info-box-text {
+ display: block;
+ font-size: 14px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.info-box-text {
+ text-transform: uppercase;
+}
+.info-box-more {
+ display: block;
+}
+.progress-description {
+ margin: 0;
+}
+/*
+ * Component: Timeline
+ * -------------------
+ */
+.timeline {
+ position: relative;
+ margin: 0 0 30px 0;
+ padding: 0;
+ list-style: none;
+}
+.timeline:before {
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ width: 4px;
+ background: #ddd;
+ left: 31px;
+ margin: 0;
+ border-radius: 2px;
+}
+.timeline > li {
+ position: relative;
+ margin-right: 10px;
+ margin-bottom: 15px;
+}
+.timeline > li:before,
+.timeline > li:after {
+ content: " ";
+ display: table;
+}
+.timeline > li:after {
+ clear: both;
+}
+.timeline > li > .timeline-item {
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ border-radius: 3px;
+ margin-top: 0;
+ background: #fff;
+ color: #444;
+ margin-left: 60px;
+ margin-right: 15px;
+ padding: 0;
+ position: relative;
+}
+.timeline > li > .timeline-item > .time {
+ color: #999;
+ float: right;
+ padding: 10px;
+ font-size: 12px;
+}
+.timeline > li > .timeline-item > .timeline-header {
+ margin: 0;
+ color: #555;
+ border-bottom: 1px solid #f4f4f4;
+ padding: 10px;
+ font-size: 16px;
+ line-height: 1.1;
+}
+.timeline > li > .timeline-item > .timeline-header > a {
+ font-weight: 600;
+}
+.timeline > li > .timeline-item > .timeline-body,
+.timeline > li > .timeline-item > .timeline-footer {
+ padding: 10px;
+}
+.timeline > li > .fa,
+.timeline > li > .glyphicon,
+.timeline > li > .ion {
+ width: 30px;
+ height: 30px;
+ font-size: 15px;
+ line-height: 30px;
+ position: absolute;
+ color: #666;
+ background: #d2d6de;
+ border-radius: 50%;
+ text-align: center;
+ left: 18px;
+ top: 0;
+}
+.timeline > .time-label > span {
+ font-weight: 600;
+ padding: 5px;
+ display: inline-block;
+ background-color: #fff;
+ border-radius: 4px;
+}
+.timeline-inverse > li > .timeline-item {
+ background: #f0f0f0;
+ border: 1px solid #ddd;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.timeline-inverse > li > .timeline-item > .timeline-header {
+ border-bottom-color: #ddd;
+}
+/*
+ * Component: Button
+ * -----------------
+ */
+.btn {
+ border-radius: 3px;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ border: 1px solid transparent;
+}
+.btn.uppercase {
+ text-transform: uppercase;
+}
+.btn.btn-flat {
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ border-width: 1px;
+}
+.btn:active {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ -moz-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn:focus {
+ outline: none;
+}
+.btn.btn-file {
+ position: relative;
+ overflow: hidden;
+}
+.btn.btn-file > input[type='file'] {
+ position: absolute;
+ top: 0;
+ right: 0;
+ min-width: 100%;
+ min-height: 100%;
+ font-size: 100px;
+ text-align: right;
+ opacity: 0;
+ filter: alpha(opacity=0);
+ outline: none;
+ background: white;
+ cursor: inherit;
+ display: block;
+}
+.btn-default {
+ background-color: #f4f4f4;
+ color: #444;
+ border-color: #ddd;
+}
+.btn-default:hover,
+.btn-default:active,
+.btn-default.hover {
+ background-color: #e7e7e7;
+}
+.btn-primary {
+ background-color: #3c8dbc;
+ border-color: #367fa9;
+}
+.btn-primary:hover,
+.btn-primary:active,
+.btn-primary.hover {
+ background-color: #367fa9;
+}
+.btn-success {
+ background-color: #00a65a;
+ border-color: #008d4c;
+}
+.btn-success:hover,
+.btn-success:active,
+.btn-success.hover {
+ background-color: #008d4c;
+}
+.btn-info {
+ background-color: #00c0ef;
+ border-color: #00acd6;
+}
+.btn-info:hover,
+.btn-info:active,
+.btn-info.hover {
+ background-color: #00acd6;
+}
+.btn-danger {
+ background-color: #dd4b39;
+ border-color: #d73925;
+}
+.btn-danger:hover,
+.btn-danger:active,
+.btn-danger.hover {
+ background-color: #d73925;
+}
+.btn-warning {
+ background-color: #f39c12;
+ border-color: #e08e0b;
+}
+.btn-warning:hover,
+.btn-warning:active,
+.btn-warning.hover {
+ background-color: #e08e0b;
+}
+.btn-outline {
+ border: 1px solid #fff;
+ background: transparent;
+ color: #fff;
+}
+.btn-outline:hover,
+.btn-outline:focus,
+.btn-outline:active {
+ color: rgba(255, 255, 255, 0.7);
+ border-color: rgba(255, 255, 255, 0.7);
+}
+.btn-link {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn[class*='bg-']:hover {
+ -webkit-box-shadow: inset 0 0 100px rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 0 100px rgba(0, 0, 0, 0.2);
+}
+.btn-app {
+ border-radius: 3px;
+ position: relative;
+ padding: 15px 5px;
+ margin: 0 0 10px 10px;
+ min-width: 80px;
+ height: 60px;
+ text-align: center;
+ color: #666;
+ border: 1px solid #ddd;
+ background-color: #f4f4f4;
+ font-size: 12px;
+}
+.btn-app > .fa,
+.btn-app > .glyphicon,
+.btn-app > .ion {
+ font-size: 20px;
+ display: block;
+}
+.btn-app:hover {
+ background: #f4f4f4;
+ color: #444;
+ border-color: #aaa;
+}
+.btn-app:active,
+.btn-app:focus {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ -moz-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
+}
+.btn-app > .badge {
+ position: absolute;
+ top: -3px;
+ right: -10px;
+ font-size: 10px;
+ font-weight: 400;
+}
+/*
+ * Component: Callout
+ * ------------------
+ */
+.callout {
+ border-radius: 3px;
+ margin: 0 0 20px 0;
+ padding: 15px 30px 15px 15px;
+ border-left: 5px solid #eee;
+}
+.callout a {
+ color: #fff;
+ text-decoration: underline;
+}
+.callout a:hover {
+ color: #eee;
+}
+.callout h4 {
+ margin-top: 0;
+ font-weight: 600;
+}
+.callout p:last-child {
+ margin-bottom: 0;
+}
+.callout code,
+.callout .highlight {
+ background-color: #fff;
+}
+.callout.callout-danger {
+ border-color: #c23321;
+}
+.callout.callout-warning {
+ border-color: #c87f0a;
+}
+.callout.callout-info {
+ border-color: #0097bc;
+}
+.callout.callout-success {
+ border-color: #00733e;
+}
+/*
+ * Component: alert
+ * ----------------
+ */
+.alert {
+ border-radius: 3px;
+}
+.alert h4 {
+ font-weight: 600;
+}
+.alert .icon {
+ margin-right: 10px;
+}
+.alert .close {
+ color: #000;
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+}
+.alert .close:hover {
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+}
+.alert a {
+ color: #fff;
+ text-decoration: underline;
+}
+.alert-success {
+ border-color: #008d4c;
+}
+.alert-danger,
+.alert-error {
+ border-color: #d73925;
+}
+.alert-warning {
+ border-color: #e08e0b;
+}
+.alert-info {
+ border-color: #00acd6;
+}
+/*
+ * Component: Nav
+ * --------------
+ */
+.nav > li > a:hover,
+.nav > li > a:active,
+.nav > li > a:focus {
+ color: #444;
+ background: #f7f7f7;
+}
+/* NAV PILLS */
+.nav-pills > li > a {
+ border-radius: 0;
+ border-top: 3px solid transparent;
+ color: #444;
+}
+.nav-pills > li > a > .fa,
+.nav-pills > li > a > .glyphicon,
+.nav-pills > li > a > .ion {
+ margin-right: 5px;
+}
+.nav-pills > li.active > a,
+.nav-pills > li.active > a:hover,
+.nav-pills > li.active > a:focus {
+ border-top-color: #3c8dbc;
+}
+.nav-pills > li.active > a {
+ font-weight: 600;
+}
+/* NAV STACKED */
+.nav-stacked > li > a {
+ border-radius: 0;
+ border-top: 0;
+ border-left: 3px solid transparent;
+ color: #444;
+}
+.nav-stacked > li.active > a,
+.nav-stacked > li.active > a:hover {
+ background: transparent;
+ color: #444;
+ border-top: 0;
+ border-left-color: #3c8dbc;
+}
+.nav-stacked > li.header {
+ border-bottom: 1px solid #ddd;
+ color: #777;
+ margin-bottom: 10px;
+ padding: 5px 10px;
+ text-transform: uppercase;
+}
+/* NAV TABS */
+.nav-tabs-custom {
+ margin-bottom: 20px;
+ background: #fff;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ border-radius: 3px;
+}
+.nav-tabs-custom > .nav-tabs {
+ margin: 0;
+ border-bottom-color: #f4f4f4;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.nav-tabs-custom > .nav-tabs > li {
+ border-top: 3px solid transparent;
+ margin-bottom: -2px;
+ margin-right: 5px;
+}
+.nav-tabs-custom > .nav-tabs > li > a {
+ color: #444;
+ border-radius: 0;
+}
+.nav-tabs-custom > .nav-tabs > li > a.text-muted {
+ color: #999;
+}
+.nav-tabs-custom > .nav-tabs > li > a,
+.nav-tabs-custom > .nav-tabs > li > a:hover {
+ background: transparent;
+ margin: 0;
+}
+.nav-tabs-custom > .nav-tabs > li > a:hover {
+ color: #999;
+}
+.nav-tabs-custom > .nav-tabs > li:not(.active) > a:hover,
+.nav-tabs-custom > .nav-tabs > li:not(.active) > a:focus,
+.nav-tabs-custom > .nav-tabs > li:not(.active) > a:active {
+ border-color: transparent;
+}
+.nav-tabs-custom > .nav-tabs > li.active {
+ border-top-color: #3c8dbc;
+}
+.nav-tabs-custom > .nav-tabs > li.active > a,
+.nav-tabs-custom > .nav-tabs > li.active:hover > a {
+ background-color: #fff;
+ color: #444;
+}
+.nav-tabs-custom > .nav-tabs > li.active > a {
+ border-top-color: transparent;
+ border-left-color: #f4f4f4;
+ border-right-color: #f4f4f4;
+}
+.nav-tabs-custom > .nav-tabs > li:first-of-type {
+ margin-left: 0;
+}
+.nav-tabs-custom > .nav-tabs > li:first-of-type.active > a {
+ border-left-color: transparent;
+}
+.nav-tabs-custom > .nav-tabs.pull-right {
+ float: none!important;
+}
+.nav-tabs-custom > .nav-tabs.pull-right > li {
+ float: right;
+}
+.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type {
+ margin-right: 0;
+}
+.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type > a {
+ border-left-width: 1px;
+}
+.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type.active > a {
+ border-left-color: #f4f4f4;
+ border-right-color: transparent;
+}
+.nav-tabs-custom > .nav-tabs > li.header {
+ line-height: 35px;
+ padding: 0 10px;
+ font-size: 20px;
+ color: #444;
+}
+.nav-tabs-custom > .nav-tabs > li.header > .fa,
+.nav-tabs-custom > .nav-tabs > li.header > .glyphicon,
+.nav-tabs-custom > .nav-tabs > li.header > .ion {
+ margin-right: 5px;
+}
+.nav-tabs-custom > .tab-content {
+ background: #fff;
+ padding: 10px;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.nav-tabs-custom .dropdown.open > a:active,
+.nav-tabs-custom .dropdown.open > a:focus {
+ background: transparent;
+ color: #999;
+}
+/* PAGINATION */
+.pagination > li > a {
+ background: #fafafa;
+ color: #666;
+}
+.pagination.pagination-flat > li > a {
+ border-radius: 0 !important;
+}
+/*
+ * Component: Products List
+ * ------------------------
+ */
+.products-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+.products-list > .item {
+ border-radius: 3px;
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ padding: 10px 0;
+ background: #fff;
+}
+.products-list > .item:before,
+.products-list > .item:after {
+ content: " ";
+ display: table;
+}
+.products-list > .item:after {
+ clear: both;
+}
+.products-list .product-img {
+ float: left;
+}
+.products-list .product-img img {
+ width: 50px;
+ height: 50px;
+}
+.products-list .product-info {
+ margin-left: 60px;
+}
+.products-list .product-title {
+ font-weight: 600;
+}
+.products-list .product-description {
+ display: block;
+ color: #999;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+.product-list-in-box > .item {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ border-radius: 0;
+ border-bottom: 1px solid #f4f4f4;
+}
+.product-list-in-box > .item:last-of-type {
+ border-bottom-width: 0;
+}
+/*
+ * Component: Table
+ * ----------------
+ */
+.table > thead > tr > th,
+.table > tbody > tr > th,
+.table > tfoot > tr > th,
+.table > thead > tr > td,
+.table > tbody > tr > td,
+.table > tfoot > tr > td {
+ border-top: 1px solid #f4f4f4;
+}
+.table > thead > tr > th {
+ border-bottom: 2px solid #f4f4f4;
+}
+.table tr td .progress {
+ margin-top: 5px;
+}
+.table-bordered {
+ border: 1px solid #f4f4f4;
+}
+.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 #f4f4f4;
+}
+.table-bordered > thead > tr > th,
+.table-bordered > thead > tr > td {
+ border-bottom-width: 2px;
+}
+.table.no-border,
+.table.no-border td,
+.table.no-border th {
+ border: 0;
+}
+/* .text-center in tables */
+table.text-center,
+table.text-center td,
+table.text-center th {
+ text-align: center;
+}
+.table.align th {
+ text-align: left;
+}
+.table.align td {
+ text-align: right;
+}
+/*
+ * Component: Label
+ * ----------------
+ */
+.label-default {
+ background-color: #d2d6de;
+ color: #444;
+}
+/*
+ * Component: Direct Chat
+ * ----------------------
+ */
+.direct-chat .box-body {
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+ position: relative;
+ overflow-x: hidden;
+ padding: 0;
+}
+.direct-chat.chat-pane-open .direct-chat-contacts {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+}
+.direct-chat-messages {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+ padding: 10px;
+ height: 250px;
+ overflow: auto;
+}
+.direct-chat-msg,
+.direct-chat-text {
+ display: block;
+}
+.direct-chat-msg {
+ margin-bottom: 10px;
+}
+.direct-chat-msg:before,
+.direct-chat-msg:after {
+ content: " ";
+ display: table;
+}
+.direct-chat-msg:after {
+ clear: both;
+}
+.direct-chat-messages,
+.direct-chat-contacts {
+ -webkit-transition: -webkit-transform 0.5s ease-in-out;
+ -moz-transition: -moz-transform 0.5s ease-in-out;
+ -o-transition: -o-transform 0.5s ease-in-out;
+ transition: transform 0.5s ease-in-out;
+}
+.direct-chat-text {
+ border-radius: 5px;
+ position: relative;
+ padding: 5px 10px;
+ background: #d2d6de;
+ border: 1px solid #d2d6de;
+ margin: 5px 0 0 50px;
+ color: #444444;
+}
+.direct-chat-text:after,
+.direct-chat-text:before {
+ position: absolute;
+ right: 100%;
+ top: 15px;
+ border: solid transparent;
+ border-right-color: #d2d6de;
+ content: ' ';
+ height: 0;
+ width: 0;
+ pointer-events: none;
+}
+.direct-chat-text:after {
+ border-width: 5px;
+ margin-top: -5px;
+}
+.direct-chat-text:before {
+ border-width: 6px;
+ margin-top: -6px;
+}
+.right .direct-chat-text {
+ margin-right: 50px;
+ margin-left: 0;
+}
+.right .direct-chat-text:after,
+.right .direct-chat-text:before {
+ right: auto;
+ left: 100%;
+ border-right-color: transparent;
+ border-left-color: #d2d6de;
+}
+.direct-chat-img {
+ border-radius: 50%;
+ float: left;
+ width: 40px;
+ height: 40px;
+}
+.right .direct-chat-img {
+ float: right;
+}
+.direct-chat-info {
+ display: block;
+ margin-bottom: 2px;
+ font-size: 12px;
+}
+.direct-chat-name {
+ font-weight: 600;
+}
+.direct-chat-timestamp {
+ color: #999;
+}
+.direct-chat-contacts-open .direct-chat-contacts {
+ -webkit-transform: translate(0, 0);
+ -ms-transform: translate(0, 0);
+ -o-transform: translate(0, 0);
+ transform: translate(0, 0);
+}
+.direct-chat-contacts {
+ -webkit-transform: translate(101%, 0);
+ -ms-transform: translate(101%, 0);
+ -o-transform: translate(101%, 0);
+ transform: translate(101%, 0);
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ height: 250px;
+ width: 100%;
+ background: #222d32;
+ color: #fff;
+ overflow: auto;
+}
+.contacts-list > li {
+ border-bottom: 1px solid rgba(0, 0, 0, 0.2);
+ padding: 10px;
+ margin: 0;
+}
+.contacts-list > li:before,
+.contacts-list > li:after {
+ content: " ";
+ display: table;
+}
+.contacts-list > li:after {
+ clear: both;
+}
+.contacts-list > li:last-of-type {
+ border-bottom: none;
+}
+.contacts-list-img {
+ border-radius: 50%;
+ width: 40px;
+ float: left;
+}
+.contacts-list-info {
+ margin-left: 45px;
+ color: #fff;
+}
+.contacts-list-name,
+.contacts-list-status {
+ display: block;
+}
+.contacts-list-name {
+ font-weight: 600;
+}
+.contacts-list-status {
+ font-size: 12px;
+}
+.contacts-list-date {
+ color: #aaa;
+ font-weight: normal;
+}
+.contacts-list-msg {
+ color: #999;
+}
+.direct-chat-danger .right > .direct-chat-text {
+ background: #dd4b39;
+ border-color: #dd4b39;
+ color: #ffffff;
+}
+.direct-chat-danger .right > .direct-chat-text:after,
+.direct-chat-danger .right > .direct-chat-text:before {
+ border-left-color: #dd4b39;
+}
+.direct-chat-primary .right > .direct-chat-text {
+ background: #3c8dbc;
+ border-color: #3c8dbc;
+ color: #ffffff;
+}
+.direct-chat-primary .right > .direct-chat-text:after,
+.direct-chat-primary .right > .direct-chat-text:before {
+ border-left-color: #3c8dbc;
+}
+.direct-chat-warning .right > .direct-chat-text {
+ background: #f39c12;
+ border-color: #f39c12;
+ color: #ffffff;
+}
+.direct-chat-warning .right > .direct-chat-text:after,
+.direct-chat-warning .right > .direct-chat-text:before {
+ border-left-color: #f39c12;
+}
+.direct-chat-info .right > .direct-chat-text {
+ background: #00c0ef;
+ border-color: #00c0ef;
+ color: #ffffff;
+}
+.direct-chat-info .right > .direct-chat-text:after,
+.direct-chat-info .right > .direct-chat-text:before {
+ border-left-color: #00c0ef;
+}
+.direct-chat-success .right > .direct-chat-text {
+ background: #00a65a;
+ border-color: #00a65a;
+ color: #ffffff;
+}
+.direct-chat-success .right > .direct-chat-text:after,
+.direct-chat-success .right > .direct-chat-text:before {
+ border-left-color: #00a65a;
+}
+/*
+ * Component: Users List
+ * ---------------------
+ */
+.users-list > li {
+ width: 25%;
+ float: left;
+ padding: 10px;
+ text-align: center;
+}
+.users-list > li img {
+ border-radius: 50%;
+ max-width: 100%;
+ height: auto;
+}
+.users-list > li > a:hover,
+.users-list > li > a:hover .users-list-name {
+ color: #999;
+}
+.users-list-name,
+.users-list-date {
+ display: block;
+}
+.users-list-name {
+ font-weight: 600;
+ color: #444;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+.users-list-date {
+ color: #999;
+ font-size: 12px;
+}
+/*
+ * Component: Carousel
+ * -------------------
+ */
+.carousel-control.left,
+.carousel-control.right {
+ background-image: none;
+}
+.carousel-control > .fa {
+ font-size: 40px;
+ position: absolute;
+ top: 50%;
+ z-index: 5;
+ display: inline-block;
+ margin-top: -20px;
+}
+/*
+ * Component: modal
+ * ----------------
+ */
+.modal {
+ background: rgba(0, 0, 0, 0.3);
+}
+.modal-content {
+ border-radius: 0;
+ -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, 0.125);
+ box-shadow: 0 2px 3px rgba(0, 0, 0, 0.125);
+ border: 0;
+}
+@media (min-width: 768px) {
+ .modal-content {
+ -webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, 0.125);
+ box-shadow: 0 2px 3px rgba(0, 0, 0, 0.125);
+ }
+}
+.modal-header {
+ border-bottom-color: #f4f4f4;
+}
+.modal-footer {
+ border-top-color: #f4f4f4;
+}
+.modal-primary .modal-header,
+.modal-primary .modal-footer {
+ border-color: #307095;
+}
+.modal-warning .modal-header,
+.modal-warning .modal-footer {
+ border-color: #c87f0a;
+}
+.modal-info .modal-header,
+.modal-info .modal-footer {
+ border-color: #0097bc;
+}
+.modal-success .modal-header,
+.modal-success .modal-footer {
+ border-color: #00733e;
+}
+.modal-danger .modal-header,
+.modal-danger .modal-footer {
+ border-color: #c23321;
+}
+/*
+ * Component: Social Widgets
+ * -------------------------
+ */
+.box-widget {
+ border: none;
+ position: relative;
+}
+.widget-user .widget-user-header {
+ padding: 20px;
+ height: 120px;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.widget-user .widget-user-username {
+ margin-top: 0;
+ margin-bottom: 5px;
+ font-size: 25px;
+ font-weight: 300;
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
+}
+.widget-user .widget-user-desc {
+ margin-top: 0;
+}
+.widget-user .widget-user-image {
+ position: absolute;
+ top: 65px;
+ left: 50%;
+ margin-left: -45px;
+}
+.widget-user .widget-user-image > img {
+ width: 90px;
+ height: auto;
+ border: 3px solid #fff;
+}
+.widget-user .box-footer {
+ padding-top: 30px;
+}
+.widget-user-2 .widget-user-header {
+ padding: 20px;
+ border-top-right-radius: 3px;
+ border-top-left-radius: 3px;
+}
+.widget-user-2 .widget-user-username {
+ margin-top: 5px;
+ margin-bottom: 5px;
+ font-size: 25px;
+ font-weight: 300;
+}
+.widget-user-2 .widget-user-desc {
+ margin-top: 0;
+}
+.widget-user-2 .widget-user-username,
+.widget-user-2 .widget-user-desc {
+ margin-left: 75px;
+}
+.widget-user-2 .widget-user-image > img {
+ width: 65px;
+ height: auto;
+ float: left;
+}
+/*
+ * Page: Mailbox
+ * -------------
+ */
+.mailbox-messages > .table {
+ margin: 0;
+}
+.mailbox-controls {
+ padding: 5px;
+}
+.mailbox-controls.with-border {
+ border-bottom: 1px solid #f4f4f4;
+}
+.mailbox-read-info {
+ border-bottom: 1px solid #f4f4f4;
+ padding: 10px;
+}
+.mailbox-read-info h3 {
+ font-size: 20px;
+ margin: 0;
+}
+.mailbox-read-info h5 {
+ margin: 0;
+ padding: 5px 0 0 0;
+}
+.mailbox-read-time {
+ color: #999;
+ font-size: 13px;
+}
+.mailbox-read-message {
+ padding: 10px;
+}
+.mailbox-attachments li {
+ float: left;
+ width: 200px;
+ border: 1px solid #eee;
+ margin-bottom: 10px;
+ margin-right: 10px;
+}
+.mailbox-attachment-name {
+ font-weight: bold;
+ color: #666;
+}
+.mailbox-attachment-icon,
+.mailbox-attachment-info,
+.mailbox-attachment-size {
+ display: block;
+}
+.mailbox-attachment-info {
+ padding: 10px;
+ background: #f4f4f4;
+}
+.mailbox-attachment-size {
+ color: #999;
+ font-size: 12px;
+}
+.mailbox-attachment-icon {
+ text-align: center;
+ font-size: 65px;
+ color: #666;
+ padding: 20px 10px;
+}
+.mailbox-attachment-icon.has-img {
+ padding: 0;
+}
+.mailbox-attachment-icon.has-img > img {
+ max-width: 100%;
+ height: auto;
+}
+/*
+ * Page: Lock Screen
+ * -----------------
+ */
+/* ADD THIS CLASS TO THE <BODY> TAG */
+.lockscreen {
+ background: #d2d6de;
+}
+.lockscreen-logo {
+ font-size: 35px;
+ text-align: center;
+ margin-bottom: 25px;
+ font-weight: 300;
+}
+.lockscreen-logo a {
+ color: #444;
+}
+.lockscreen-wrapper {
+ max-width: 400px;
+ margin: 0 auto;
+ margin-top: 10%;
+}
+/* User name [optional] */
+.lockscreen .lockscreen-name {
+ text-align: center;
+ font-weight: 600;
+}
+/* Will contain the image and the sign in form */
+.lockscreen-item {
+ border-radius: 4px;
+ padding: 0;
+ background: #fff;
+ position: relative;
+ margin: 10px auto 30px auto;
+ width: 290px;
+}
+/* User image */
+.lockscreen-image {
+ border-radius: 50%;
+ position: absolute;
+ left: -10px;
+ top: -25px;
+ background: #fff;
+ padding: 5px;
+ z-index: 10;
+}
+.lockscreen-image > img {
+ border-radius: 50%;
+ width: 70px;
+ height: 70px;
+}
+/* Contains the password input and the login button */
+.lockscreen-credentials {
+ margin-left: 70px;
+}
+.lockscreen-credentials .form-control {
+ border: 0;
+}
+.lockscreen-credentials .btn {
+ background-color: #fff;
+ border: 0;
+ padding: 0 10px;
+}
+.lockscreen-footer {
+ margin-top: 10px;
+}
+/*
+ * Page: Login & Register
+ * ----------------------
+ */
+.login-logo,
+.register-logo {
+ font-size: 35px;
+ text-align: center;
+ margin-bottom: 25px;
+ font-weight: 300;
+}
+.login-logo a,
+.register-logo a {
+ color: #444;
+}
+.login-page,
+.register-page {
+ background: #d2d6de;
+}
+.login-box,
+.register-box {
+ width: 360px;
+ margin: 7% auto;
+}
+@media (max-width: 768px) {
+ .login-box,
+ .register-box {
+ width: 90%;
+ margin-top: 20px;
+ }
+}
+.login-box-body,
+.register-box-body {
+ background: #fff;
+ padding: 20px;
+ border-top: 0;
+ color: #666;
+}
+.login-box-body .form-control-feedback,
+.register-box-body .form-control-feedback {
+ color: #777;
+}
+.login-box-msg,
+.register-box-msg {
+ margin: 0;
+ text-align: center;
+ padding: 0 20px 20px 20px;
+}
+.social-auth-links {
+ margin: 10px 0;
+}
+/*
+ * Page: 400 and 500 error pages
+ * ------------------------------
+ */
+.error-page {
+ width: 600px;
+ margin: 20px auto 0 auto;
+}
+@media (max-width: 991px) {
+ .error-page {
+ width: 100%;
+ }
+}
+.error-page > .headline {
+ float: left;
+ font-size: 100px;
+ font-weight: 300;
+}
+@media (max-width: 991px) {
+ .error-page > .headline {
+ float: none;
+ text-align: center;
+ }
+}
+.error-page > .error-content {
+ margin-left: 190px;
+ display: block;
+}
+@media (max-width: 991px) {
+ .error-page > .error-content {
+ margin-left: 0;
+ }
+}
+.error-page > .error-content > h3 {
+ font-weight: 300;
+ font-size: 25px;
+}
+@media (max-width: 991px) {
+ .error-page > .error-content > h3 {
+ text-align: center;
+ }
+}
+/*
+ * Page: Invoice
+ * -------------
+ */
+.invoice {
+ position: relative;
+ background: #fff;
+ border: 1px solid #f4f4f4;
+ padding: 20px;
+ margin: 10px 25px;
+}
+.invoice-title {
+ margin-top: 0;
+}
+/*
+ * Page: Profile
+ * -------------
+ */
+.profile-user-img {
+ margin: 0 auto;
+ width: 100px;
+ padding: 3px;
+ border: 3px solid #d2d6de;
+}
+.profile-username {
+ font-size: 21px;
+ margin-top: 5px;
+}
+.post {
+ border-bottom: 1px solid #d2d6de;
+ margin-bottom: 15px;
+ padding-bottom: 15px;
+ color: #666;
+}
+.post:last-of-type {
+ border-bottom: 0;
+ margin-bottom: 0;
+ padding-bottom: 0;
+}
+.post .user-block {
+ margin-bottom: 15px;
+}
+/*
+ * Social Buttons for Bootstrap
+ *
+ * Copyright 2013-2015 Panayiotis Lipiridis
+ * Licensed under the MIT License
+ *
+ * https://github.com/lipis/bootstrap-social
+ */
+.btn-social {
+ position: relative;
+ padding-left: 44px;
+ text-align: left;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.btn-social > :first-child {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 32px;
+ line-height: 34px;
+ font-size: 1.6em;
+ text-align: center;
+ border-right: 1px solid rgba(0, 0, 0, 0.2);
+}
+.btn-social.btn-lg {
+ padding-left: 61px;
+}
+.btn-social.btn-lg > :first-child {
+ line-height: 45px;
+ width: 45px;
+ font-size: 1.8em;
+}
+.btn-social.btn-sm {
+ padding-left: 38px;
+}
+.btn-social.btn-sm > :first-child {
+ line-height: 28px;
+ width: 28px;
+ font-size: 1.4em;
+}
+.btn-social.btn-xs {
+ padding-left: 30px;
+}
+.btn-social.btn-xs > :first-child {
+ line-height: 20px;
+ width: 20px;
+ font-size: 1.2em;
+}
+.btn-social-icon {
+ position: relative;
+ padding-left: 44px;
+ text-align: left;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ height: 34px;
+ width: 34px;
+ padding: 0;
+}
+.btn-social-icon > :first-child {
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 32px;
+ line-height: 34px;
+ font-size: 1.6em;
+ text-align: center;
+ border-right: 1px solid rgba(0, 0, 0, 0.2);
+}
+.btn-social-icon.btn-lg {
+ padding-left: 61px;
+}
+.btn-social-icon.btn-lg > :first-child {
+ line-height: 45px;
+ width: 45px;
+ font-size: 1.8em;
+}
+.btn-social-icon.btn-sm {
+ padding-left: 38px;
+}
+.btn-social-icon.btn-sm > :first-child {
+ line-height: 28px;
+ width: 28px;
+ font-size: 1.4em;
+}
+.btn-social-icon.btn-xs {
+ padding-left: 30px;
+}
+.btn-social-icon.btn-xs > :first-child {
+ line-height: 20px;
+ width: 20px;
+ font-size: 1.2em;
+}
+.btn-social-icon > :first-child {
+ border: none;
+ text-align: center;
+ width: 100%;
+}
+.btn-social-icon.btn-lg {
+ height: 45px;
+ width: 45px;
+ padding-left: 0;
+ padding-right: 0;
+}
+.btn-social-icon.btn-sm {
+ height: 30px;
+ width: 30px;
+ padding-left: 0;
+ padding-right: 0;
+}
+.btn-social-icon.btn-xs {
+ height: 22px;
+ width: 22px;
+ padding-left: 0;
+ padding-right: 0;
+}
+.btn-adn {
+ color: #ffffff;
+ background-color: #d87a68;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-adn:hover,
+.btn-adn:focus,
+.btn-adn.focus,
+.btn-adn:active,
+.btn-adn.active,
+.open > .dropdown-toggle.btn-adn {
+ color: #ffffff;
+ background-color: #ce563f;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-adn:active,
+.btn-adn.active,
+.open > .dropdown-toggle.btn-adn {
+ background-image: none;
+}
+.btn-adn .badge {
+ color: #d87a68;
+ background-color: #ffffff;
+}
+.btn-bitbucket {
+ color: #ffffff;
+ background-color: #205081;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-bitbucket:hover,
+.btn-bitbucket:focus,
+.btn-bitbucket.focus,
+.btn-bitbucket:active,
+.btn-bitbucket.active,
+.open > .dropdown-toggle.btn-bitbucket {
+ color: #ffffff;
+ background-color: #163758;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-bitbucket:active,
+.btn-bitbucket.active,
+.open > .dropdown-toggle.btn-bitbucket {
+ background-image: none;
+}
+.btn-bitbucket .badge {
+ color: #205081;
+ background-color: #ffffff;
+}
+.btn-dropbox {
+ color: #ffffff;
+ background-color: #1087dd;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-dropbox:hover,
+.btn-dropbox:focus,
+.btn-dropbox.focus,
+.btn-dropbox:active,
+.btn-dropbox.active,
+.open > .dropdown-toggle.btn-dropbox {
+ color: #ffffff;
+ background-color: #0d6aad;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-dropbox:active,
+.btn-dropbox.active,
+.open > .dropdown-toggle.btn-dropbox {
+ background-image: none;
+}
+.btn-dropbox .badge {
+ color: #1087dd;
+ background-color: #ffffff;
+}
+.btn-facebook {
+ color: #ffffff;
+ background-color: #3b5998;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-facebook:hover,
+.btn-facebook:focus,
+.btn-facebook.focus,
+.btn-facebook:active,
+.btn-facebook.active,
+.open > .dropdown-toggle.btn-facebook {
+ color: #ffffff;
+ background-color: #2d4373;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-facebook:active,
+.btn-facebook.active,
+.open > .dropdown-toggle.btn-facebook {
+ background-image: none;
+}
+.btn-facebook .badge {
+ color: #3b5998;
+ background-color: #ffffff;
+}
+.btn-flickr {
+ color: #ffffff;
+ background-color: #ff0084;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-flickr:hover,
+.btn-flickr:focus,
+.btn-flickr.focus,
+.btn-flickr:active,
+.btn-flickr.active,
+.open > .dropdown-toggle.btn-flickr {
+ color: #ffffff;
+ background-color: #cc006a;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-flickr:active,
+.btn-flickr.active,
+.open > .dropdown-toggle.btn-flickr {
+ background-image: none;
+}
+.btn-flickr .badge {
+ color: #ff0084;
+ background-color: #ffffff;
+}
+.btn-foursquare {
+ color: #ffffff;
+ background-color: #f94877;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-foursquare:hover,
+.btn-foursquare:focus,
+.btn-foursquare.focus,
+.btn-foursquare:active,
+.btn-foursquare.active,
+.open > .dropdown-toggle.btn-foursquare {
+ color: #ffffff;
+ background-color: #f71752;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-foursquare:active,
+.btn-foursquare.active,
+.open > .dropdown-toggle.btn-foursquare {
+ background-image: none;
+}
+.btn-foursquare .badge {
+ color: #f94877;
+ background-color: #ffffff;
+}
+.btn-github {
+ color: #ffffff;
+ background-color: #444444;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-github:hover,
+.btn-github:focus,
+.btn-github.focus,
+.btn-github:active,
+.btn-github.active,
+.open > .dropdown-toggle.btn-github {
+ color: #ffffff;
+ background-color: #2b2b2b;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-github:active,
+.btn-github.active,
+.open > .dropdown-toggle.btn-github {
+ background-image: none;
+}
+.btn-github .badge {
+ color: #444444;
+ background-color: #ffffff;
+}
+.btn-google {
+ color: #ffffff;
+ background-color: #dd4b39;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-google:hover,
+.btn-google:focus,
+.btn-google.focus,
+.btn-google:active,
+.btn-google.active,
+.open > .dropdown-toggle.btn-google {
+ color: #ffffff;
+ background-color: #c23321;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-google:active,
+.btn-google.active,
+.open > .dropdown-toggle.btn-google {
+ background-image: none;
+}
+.btn-google .badge {
+ color: #dd4b39;
+ background-color: #ffffff;
+}
+.btn-instagram {
+ color: #ffffff;
+ background-color: #3f729b;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-instagram:hover,
+.btn-instagram:focus,
+.btn-instagram.focus,
+.btn-instagram:active,
+.btn-instagram.active,
+.open > .dropdown-toggle.btn-instagram {
+ color: #ffffff;
+ background-color: #305777;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-instagram:active,
+.btn-instagram.active,
+.open > .dropdown-toggle.btn-instagram {
+ background-image: none;
+}
+.btn-instagram .badge {
+ color: #3f729b;
+ background-color: #ffffff;
+}
+.btn-linkedin {
+ color: #ffffff;
+ background-color: #007bb6;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-linkedin:hover,
+.btn-linkedin:focus,
+.btn-linkedin.focus,
+.btn-linkedin:active,
+.btn-linkedin.active,
+.open > .dropdown-toggle.btn-linkedin {
+ color: #ffffff;
+ background-color: #005983;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-linkedin:active,
+.btn-linkedin.active,
+.open > .dropdown-toggle.btn-linkedin {
+ background-image: none;
+}
+.btn-linkedin .badge {
+ color: #007bb6;
+ background-color: #ffffff;
+}
+.btn-microsoft {
+ color: #ffffff;
+ background-color: #2672ec;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-microsoft:hover,
+.btn-microsoft:focus,
+.btn-microsoft.focus,
+.btn-microsoft:active,
+.btn-microsoft.active,
+.open > .dropdown-toggle.btn-microsoft {
+ color: #ffffff;
+ background-color: #125acd;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-microsoft:active,
+.btn-microsoft.active,
+.open > .dropdown-toggle.btn-microsoft {
+ background-image: none;
+}
+.btn-microsoft .badge {
+ color: #2672ec;
+ background-color: #ffffff;
+}
+.btn-openid {
+ color: #ffffff;
+ background-color: #f7931e;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-openid:hover,
+.btn-openid:focus,
+.btn-openid.focus,
+.btn-openid:active,
+.btn-openid.active,
+.open > .dropdown-toggle.btn-openid {
+ color: #ffffff;
+ background-color: #da7908;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-openid:active,
+.btn-openid.active,
+.open > .dropdown-toggle.btn-openid {
+ background-image: none;
+}
+.btn-openid .badge {
+ color: #f7931e;
+ background-color: #ffffff;
+}
+.btn-pinterest {
+ color: #ffffff;
+ background-color: #cb2027;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-pinterest:hover,
+.btn-pinterest:focus,
+.btn-pinterest.focus,
+.btn-pinterest:active,
+.btn-pinterest.active,
+.open > .dropdown-toggle.btn-pinterest {
+ color: #ffffff;
+ background-color: #9f191f;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-pinterest:active,
+.btn-pinterest.active,
+.open > .dropdown-toggle.btn-pinterest {
+ background-image: none;
+}
+.btn-pinterest .badge {
+ color: #cb2027;
+ background-color: #ffffff;
+}
+.btn-reddit {
+ color: #000000;
+ background-color: #eff7ff;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-reddit:hover,
+.btn-reddit:focus,
+.btn-reddit.focus,
+.btn-reddit:active,
+.btn-reddit.active,
+.open > .dropdown-toggle.btn-reddit {
+ color: #000000;
+ background-color: #bcddff;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-reddit:active,
+.btn-reddit.active,
+.open > .dropdown-toggle.btn-reddit {
+ background-image: none;
+}
+.btn-reddit .badge {
+ color: #eff7ff;
+ background-color: #000000;
+}
+.btn-soundcloud {
+ color: #ffffff;
+ background-color: #ff5500;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-soundcloud:hover,
+.btn-soundcloud:focus,
+.btn-soundcloud.focus,
+.btn-soundcloud:active,
+.btn-soundcloud.active,
+.open > .dropdown-toggle.btn-soundcloud {
+ color: #ffffff;
+ background-color: #cc4400;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-soundcloud:active,
+.btn-soundcloud.active,
+.open > .dropdown-toggle.btn-soundcloud {
+ background-image: none;
+}
+.btn-soundcloud .badge {
+ color: #ff5500;
+ background-color: #ffffff;
+}
+.btn-tumblr {
+ color: #ffffff;
+ background-color: #2c4762;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-tumblr:hover,
+.btn-tumblr:focus,
+.btn-tumblr.focus,
+.btn-tumblr:active,
+.btn-tumblr.active,
+.open > .dropdown-toggle.btn-tumblr {
+ color: #ffffff;
+ background-color: #1c2d3f;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-tumblr:active,
+.btn-tumblr.active,
+.open > .dropdown-toggle.btn-tumblr {
+ background-image: none;
+}
+.btn-tumblr .badge {
+ color: #2c4762;
+ background-color: #ffffff;
+}
+.btn-twitter {
+ color: #ffffff;
+ background-color: #55acee;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-twitter:hover,
+.btn-twitter:focus,
+.btn-twitter.focus,
+.btn-twitter:active,
+.btn-twitter.active,
+.open > .dropdown-toggle.btn-twitter {
+ color: #ffffff;
+ background-color: #2795e9;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-twitter:active,
+.btn-twitter.active,
+.open > .dropdown-toggle.btn-twitter {
+ background-image: none;
+}
+.btn-twitter .badge {
+ color: #55acee;
+ background-color: #ffffff;
+}
+.btn-vimeo {
+ color: #ffffff;
+ background-color: #1ab7ea;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-vimeo:hover,
+.btn-vimeo:focus,
+.btn-vimeo.focus,
+.btn-vimeo:active,
+.btn-vimeo.active,
+.open > .dropdown-toggle.btn-vimeo {
+ color: #ffffff;
+ background-color: #1295bf;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-vimeo:active,
+.btn-vimeo.active,
+.open > .dropdown-toggle.btn-vimeo {
+ background-image: none;
+}
+.btn-vimeo .badge {
+ color: #1ab7ea;
+ background-color: #ffffff;
+}
+.btn-vk {
+ color: #ffffff;
+ background-color: #587ea3;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-vk:hover,
+.btn-vk:focus,
+.btn-vk.focus,
+.btn-vk:active,
+.btn-vk.active,
+.open > .dropdown-toggle.btn-vk {
+ color: #ffffff;
+ background-color: #466482;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-vk:active,
+.btn-vk.active,
+.open > .dropdown-toggle.btn-vk {
+ background-image: none;
+}
+.btn-vk .badge {
+ color: #587ea3;
+ background-color: #ffffff;
+}
+.btn-yahoo {
+ color: #ffffff;
+ background-color: #720e9e;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-yahoo:hover,
+.btn-yahoo:focus,
+.btn-yahoo.focus,
+.btn-yahoo:active,
+.btn-yahoo.active,
+.open > .dropdown-toggle.btn-yahoo {
+ color: #ffffff;
+ background-color: #500a6f;
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.btn-yahoo:active,
+.btn-yahoo.active,
+.open > .dropdown-toggle.btn-yahoo {
+ background-image: none;
+}
+.btn-yahoo .badge {
+ color: #720e9e;
+ background-color: #ffffff;
+}
+/*
+ * Plugin: Full Calendar
+ * ---------------------
+ */
+.fc-button {
+ background: #f4f4f4;
+ background-image: none;
+ color: #444;
+ border-color: #ddd;
+ border-bottom-color: #ddd;
+}
+.fc-button:hover,
+.fc-button:active,
+.fc-button.hover {
+ background-color: #e9e9e9;
+}
+.fc-header-title h2 {
+ font-size: 15px;
+ line-height: 1.6em;
+ color: #666;
+ margin-left: 10px;
+}
+.fc-header-right {
+ padding-right: 10px;
+}
+.fc-header-left {
+ padding-left: 10px;
+}
+.fc-widget-header {
+ background: #fafafa;
+}
+.fc-grid {
+ width: 100%;
+ border: 0;
+}
+.fc-widget-header:first-of-type,
+.fc-widget-content:first-of-type {
+ border-left: 0;
+ border-right: 0;
+}
+.fc-widget-header:last-of-type,
+.fc-widget-content:last-of-type {
+ border-right: 0;
+}
+.fc-toolbar {
+ padding: 10px;
+ margin: 0;
+}
+.fc-day-number {
+ font-size: 20px;
+ font-weight: 300;
+ padding-right: 10px;
+}
+.fc-color-picker {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+.fc-color-picker > li {
+ float: left;
+ font-size: 30px;
+ margin-right: 5px;
+ line-height: 30px;
+}
+.fc-color-picker > li .fa {
+ -webkit-transition: -webkit-transform linear 0.3s;
+ -moz-transition: -moz-transform linear 0.3s;
+ -o-transition: -o-transform linear 0.3s;
+ transition: transform linear 0.3s;
+}
+.fc-color-picker > li .fa:hover {
+ -webkit-transform: rotate(30deg);
+ -ms-transform: rotate(30deg);
+ -o-transform: rotate(30deg);
+ transform: rotate(30deg);
+}
+#add-new-event {
+ -webkit-transition: all linear 0.3s;
+ -o-transition: all linear 0.3s;
+ transition: all linear 0.3s;
+}
+.external-event {
+ padding: 5px 10px;
+ font-weight: bold;
+ margin-bottom: 4px;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ border-radius: 3px;
+ cursor: move;
+}
+.external-event:hover {
+ box-shadow: inset 0 0 90px rgba(0, 0, 0, 0.2);
+}
+/*
+ * Plugin: Select2
+ * ---------------
+ */
+.select2-container--default.select2-container--focus,
+.select2-selection.select2-container--focus,
+.select2-container--default:focus,
+.select2-selection:focus,
+.select2-container--default:active,
+.select2-selection:active {
+ outline: none;
+}
+.select2-container--default .select2-selection--single,
+.select2-selection .select2-selection--single {
+ border: 1px solid #d2d6de;
+ border-radius: 0;
+ padding: 6px 12px;
+ height: 34px;
+}
+.select2-container--default.select2-container--open {
+ border-color: #3c8dbc;
+}
+.select2-dropdown {
+ border: 1px solid #d2d6de;
+ border-radius: 0;
+}
+.select2-container--default .select2-results__option--highlighted[aria-selected] {
+ background-color: #3c8dbc;
+ color: white;
+}
+.select2-results__option {
+ padding: 6px 12px;
+ user-select: none;
+ -webkit-user-select: none;
+}
+.select2-container .select2-selection--single .select2-selection__rendered {
+ padding-left: 0;
+ padding-right: 0;
+ height: auto;
+ margin-top: -4px;
+}
+.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
+ padding-right: 6px;
+ padding-left: 20px;
+}
+.select2-container--default .select2-selection--single .select2-selection__arrow {
+ height: 28px;
+ right: 3px;
+}
+.select2-container--default .select2-selection--single .select2-selection__arrow b {
+ margin-top: 0;
+}
+.select2-dropdown .select2-search__field,
+.select2-search--inline .select2-search__field {
+ border: 1px solid #d2d6de;
+}
+.select2-dropdown .select2-search__field:focus,
+.select2-search--inline .select2-search__field:focus {
+ outline: none;
+ border: 1px solid #3c8dbc;
+}
+.select2-container--default .select2-results__option[aria-disabled=true] {
+ color: #999;
+}
+.select2-container--default .select2-results__option[aria-selected=true] {
+ background-color: #ddd;
+}
+.select2-container--default .select2-results__option[aria-selected=true],
+.select2-container--default .select2-results__option[aria-selected=true]:hover {
+ color: #444;
+}
+.select2-container--default .select2-selection--multiple {
+ border: 1px solid #d2d6de;
+ border-radius: 0;
+}
+.select2-container--default .select2-selection--multiple:focus {
+ border-color: #3c8dbc;
+}
+.select2-container--default.select2-container--focus .select2-selection--multiple {
+ border-color: #d2d6de;
+}
+.select2-container--default .select2-selection--multiple .select2-selection__choice {
+ background-color: #3c8dbc;
+ border-color: #367fa9;
+ padding: 1px 10px;
+ color: #fff;
+}
+.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
+ margin-right: 5px;
+ color: rgba(255, 255, 255, 0.7);
+}
+.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #fff;
+}
+.select2-container .select2-selection--single .select2-selection__rendered {
+ padding-right: 10px;
+}
+/*
+ * General: Miscellaneous
+ * ----------------------
+ */
+.pad {
+ padding: 10px;
+}
+.margin {
+ margin: 10px;
+}
+.margin-bottom {
+ margin-bottom: 20px;
+}
+.margin-bottom-none {
+ margin-bottom: 0;
+}
+.margin-r-5 {
+ margin-right: 5px;
+}
+.inline {
+ display: inline;
+}
+.description-block {
+ display: block;
+ margin: 10px 0;
+ text-align: center;
+}
+.description-block.margin-bottom {
+ margin-bottom: 25px;
+}
+.description-block > .description-header {
+ margin: 0;
+ padding: 0;
+ font-weight: 600;
+ font-size: 16px;
+}
+.description-block > .description-text {
+ text-transform: uppercase;
+}
+.bg-red,
+.bg-yellow,
+.bg-aqua,
+.bg-blue,
+.bg-light-blue,
+.bg-green,
+.bg-navy,
+.bg-teal,
+.bg-olive,
+.bg-lime,
+.bg-orange,
+.bg-fuchsia,
+.bg-purple,
+.bg-maroon,
+.bg-black,
+.bg-red-active,
+.bg-yellow-active,
+.bg-aqua-active,
+.bg-blue-active,
+.bg-light-blue-active,
+.bg-green-active,
+.bg-navy-active,
+.bg-teal-active,
+.bg-olive-active,
+.bg-lime-active,
+.bg-orange-active,
+.bg-fuchsia-active,
+.bg-purple-active,
+.bg-maroon-active,
+.bg-black-active,
+.callout.callout-danger,
+.callout.callout-warning,
+.callout.callout-info,
+.callout.callout-success,
+.alert-success,
+.alert-danger,
+.alert-error,
+.alert-warning,
+.alert-info,
+.label-danger,
+.label-info,
+.label-warning,
+.label-primary,
+.label-success,
+.modal-primary .modal-body,
+.modal-primary .modal-header,
+.modal-primary .modal-footer,
+.modal-warning .modal-body,
+.modal-warning .modal-header,
+.modal-warning .modal-footer,
+.modal-info .modal-body,
+.modal-info .modal-header,
+.modal-info .modal-footer,
+.modal-success .modal-body,
+.modal-success .modal-header,
+.modal-success .modal-footer,
+.modal-danger .modal-body,
+.modal-danger .modal-header,
+.modal-danger .modal-footer {
+ color: #fff !important;
+}
+.bg-gray {
+ color: #000;
+ background-color: #d2d6de !important;
+}
+.bg-gray-light {
+ background-color: #f7f7f7;
+}
+.bg-black {
+ background-color: #111111 !important;
+}
+.bg-red,
+.callout.callout-danger,
+.alert-danger,
+.alert-error,
+.label-danger,
+.modal-danger .modal-body {
+ background-color: #dd4b39 !important;
+}
+.bg-yellow,
+.callout.callout-warning,
+.alert-warning,
+.label-warning,
+.modal-warning .modal-body {
+ background-color: #f39c12 !important;
+}
+.bg-aqua,
+.callout.callout-info,
+.alert-info,
+.label-info,
+.modal-info .modal-body {
+ background-color: #00c0ef !important;
+}
+.bg-blue {
+ background-color: #0073b7 !important;
+}
+.bg-light-blue,
+.label-primary,
+.modal-primary .modal-body {
+ background-color: #3c8dbc !important;
+}
+.bg-green,
+.callout.callout-success,
+.alert-success,
+.label-success,
+.modal-success .modal-body {
+ background-color: #00a65a !important;
+}
+.bg-navy {
+ background-color: #001f3f !important;
+}
+.bg-teal {
+ background-color: #39cccc !important;
+}
+.bg-olive {
+ background-color: #3d9970 !important;
+}
+.bg-lime {
+ background-color: #01ff70 !important;
+}
+.bg-orange {
+ background-color: #ff851b !important;
+}
+.bg-fuchsia {
+ background-color: #f012be !important;
+}
+.bg-purple {
+ background-color: #605ca8 !important;
+}
+.bg-maroon {
+ background-color: #d81b60 !important;
+}
+.bg-gray-active {
+ color: #000;
+ background-color: #b5bbc8 !important;
+}
+.bg-black-active {
+ background-color: #000000 !important;
+}
+.bg-red-active,
+.modal-danger .modal-header,
+.modal-danger .modal-footer {
+ background-color: #d33724 !important;
+}
+.bg-yellow-active,
+.modal-warning .modal-header,
+.modal-warning .modal-footer {
+ background-color: #db8b0b !important;
+}
+.bg-aqua-active,
+.modal-info .modal-header,
+.modal-info .modal-footer {
+ background-color: #00a7d0 !important;
+}
+.bg-blue-active {
+ background-color: #005384 !important;
+}
+.bg-light-blue-active,
+.modal-primary .modal-header,
+.modal-primary .modal-footer {
+ background-color: #357ca5 !important;
+}
+.bg-green-active,
+.modal-success .modal-header,
+.modal-success .modal-footer {
+ background-color: #008d4c !important;
+}
+.bg-navy-active {
+ background-color: #001a35 !important;
+}
+.bg-teal-active {
+ background-color: #30bbbb !important;
+}
+.bg-olive-active {
+ background-color: #368763 !important;
+}
+.bg-lime-active {
+ background-color: #00e765 !important;
+}
+.bg-orange-active {
+ background-color: #ff7701 !important;
+}
+.bg-fuchsia-active {
+ background-color: #db0ead !important;
+}
+.bg-purple-active {
+ background-color: #555299 !important;
+}
+.bg-maroon-active {
+ background-color: #ca195a !important;
+}
+[class^="bg-"].disabled {
+ opacity: 0.65;
+ filter: alpha(opacity=65);
+}
+.text-red {
+ color: #dd4b39 !important;
+}
+.text-yellow {
+ color: #f39c12 !important;
+}
+.text-aqua {
+ color: #00c0ef !important;
+}
+.text-blue {
+ color: #0073b7 !important;
+}
+.text-black {
+ color: #111111 !important;
+}
+.text-light-blue {
+ color: #3c8dbc !important;
+}
+.text-green {
+ color: #00a65a !important;
+}
+.text-gray {
+ color: #d2d6de !important;
+}
+.text-navy {
+ color: #001f3f !important;
+}
+.text-teal {
+ color: #39cccc !important;
+}
+.text-olive {
+ color: #3d9970 !important;
+}
+.text-lime {
+ color: #01ff70 !important;
+}
+.text-orange {
+ color: #ff851b !important;
+}
+.text-fuchsia {
+ color: #f012be !important;
+}
+.text-purple {
+ color: #605ca8 !important;
+}
+.text-maroon {
+ color: #d81b60 !important;
+}
+.link-muted {
+ color: #7a869d;
+}
+.link-muted:hover,
+.link-muted:focus {
+ color: #606c84;
+}
+.link-black {
+ color: #666;
+}
+.link-black:hover,
+.link-black:focus {
+ color: #999;
+}
+.hide {
+ display: none !important;
+}
+.no-border {
+ border: 0 !important;
+}
+.no-padding {
+ padding: 0 !important;
+}
+.no-margin {
+ margin: 0 !important;
+}
+.no-shadow {
+ box-shadow: none!important;
+}
+.list-unstyled,
+.chart-legend,
+.contacts-list,
+.users-list,
+.mailbox-attachments {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+.list-group-unbordered > .list-group-item {
+ border-left: 0;
+ border-right: 0;
+ border-radius: 0;
+ padding-left: 0;
+ padding-right: 0;
+}
+.flat {
+ border-radius: 0 !important;
+}
+.text-bold,
+.text-bold.table td,
+.text-bold.table th {
+ font-weight: 700;
+}
+.text-sm {
+ font-size: 12px;
+}
+.jqstooltip {
+ padding: 5px!important;
+ width: auto!important;
+ height: auto!important;
+}
+.bg-teal-gradient {
+ background: #39cccc !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #39cccc), color-stop(1, #7adddd)) !important;
+ background: -ms-linear-gradient(bottom, #39cccc, #7adddd) !important;
+ background: -moz-linear-gradient(center bottom, #39cccc 0%, #7adddd 100%) !important;
+ background: -o-linear-gradient(#7adddd, #39cccc) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#7adddd', endColorstr='#39cccc', GradientType=0) !important;
+ color: #fff;
+}
+.bg-light-blue-gradient {
+ background: #3c8dbc !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #3c8dbc), color-stop(1, #67a8ce)) !important;
+ background: -ms-linear-gradient(bottom, #3c8dbc, #67a8ce) !important;
+ background: -moz-linear-gradient(center bottom, #3c8dbc 0%, #67a8ce 100%) !important;
+ background: -o-linear-gradient(#67a8ce, #3c8dbc) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#67a8ce', endColorstr='#3c8dbc', GradientType=0) !important;
+ color: #fff;
+}
+.bg-blue-gradient {
+ background: #0073b7 !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0073b7), color-stop(1, #0089db)) !important;
+ background: -ms-linear-gradient(bottom, #0073b7, #0089db) !important;
+ background: -moz-linear-gradient(center bottom, #0073b7 0%, #0089db 100%) !important;
+ background: -o-linear-gradient(#0089db, #0073b7) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0089db', endColorstr='#0073b7', GradientType=0) !important;
+ color: #fff;
+}
+.bg-aqua-gradient {
+ background: #00c0ef !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #00c0ef), color-stop(1, #14d1ff)) !important;
+ background: -ms-linear-gradient(bottom, #00c0ef, #14d1ff) !important;
+ background: -moz-linear-gradient(center bottom, #00c0ef 0%, #14d1ff 100%) !important;
+ background: -o-linear-gradient(#14d1ff, #00c0ef) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#14d1ff', endColorstr='#00c0ef', GradientType=0) !important;
+ color: #fff;
+}
+.bg-yellow-gradient {
+ background: #f39c12 !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #f39c12), color-stop(1, #f7bc60)) !important;
+ background: -ms-linear-gradient(bottom, #f39c12, #f7bc60) !important;
+ background: -moz-linear-gradient(center bottom, #f39c12 0%, #f7bc60 100%) !important;
+ background: -o-linear-gradient(#f7bc60, #f39c12) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f7bc60', endColorstr='#f39c12', GradientType=0) !important;
+ color: #fff;
+}
+.bg-purple-gradient {
+ background: #605ca8 !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #605ca8), color-stop(1, #9491c4)) !important;
+ background: -ms-linear-gradient(bottom, #605ca8, #9491c4) !important;
+ background: -moz-linear-gradient(center bottom, #605ca8 0%, #9491c4 100%) !important;
+ background: -o-linear-gradient(#9491c4, #605ca8) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#9491c4', endColorstr='#605ca8', GradientType=0) !important;
+ color: #fff;
+}
+.bg-green-gradient {
+ background: #00a65a !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #00a65a), color-stop(1, #00ca6d)) !important;
+ background: -ms-linear-gradient(bottom, #00a65a, #00ca6d) !important;
+ background: -moz-linear-gradient(center bottom, #00a65a 0%, #00ca6d 100%) !important;
+ background: -o-linear-gradient(#00ca6d, #00a65a) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ca6d', endColorstr='#00a65a', GradientType=0) !important;
+ color: #fff;
+}
+.bg-red-gradient {
+ background: #dd4b39 !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #dd4b39), color-stop(1, #e47365)) !important;
+ background: -ms-linear-gradient(bottom, #dd4b39, #e47365) !important;
+ background: -moz-linear-gradient(center bottom, #dd4b39 0%, #e47365 100%) !important;
+ background: -o-linear-gradient(#e47365, #dd4b39) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e47365', endColorstr='#dd4b39', GradientType=0) !important;
+ color: #fff;
+}
+.bg-black-gradient {
+ background: #111111 !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #111111), color-stop(1, #2b2b2b)) !important;
+ background: -ms-linear-gradient(bottom, #111111, #2b2b2b) !important;
+ background: -moz-linear-gradient(center bottom, #111111 0%, #2b2b2b 100%) !important;
+ background: -o-linear-gradient(#2b2b2b, #111111) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#2b2b2b', endColorstr='#111111', GradientType=0) !important;
+ color: #fff;
+}
+.bg-maroon-gradient {
+ background: #d81b60 !important;
+ background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #d81b60), color-stop(1, #e73f7c)) !important;
+ background: -ms-linear-gradient(bottom, #d81b60, #e73f7c) !important;
+ background: -moz-linear-gradient(center bottom, #d81b60 0%, #e73f7c 100%) !important;
+ background: -o-linear-gradient(#e73f7c, #d81b60) !important;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e73f7c', endColorstr='#d81b60', GradientType=0) !important;
+ color: #fff;
+}
+.description-block .description-icon {
+ font-size: 16px;
+}
+.no-pad-top {
+ padding-top: 0;
+}
+.position-static {
+ position: static!important;
+}
+.list-header {
+ font-size: 15px;
+ padding: 10px 4px;
+ font-weight: bold;
+ color: #666;
+}
+.list-seperator {
+ height: 1px;
+ background: #f4f4f4;
+ margin: 15px 0 9px 0;
+}
+.list-link > a {
+ padding: 4px;
+ color: #777;
+}
+.list-link > a:hover {
+ color: #222;
+}
+.font-light {
+ font-weight: 300;
+}
+.user-block:before,
+.user-block:after {
+ content: " ";
+ display: table;
+}
+.user-block:after {
+ clear: both;
+}
+.user-block img {
+ width: 40px;
+ height: 40px;
+ float: left;
+}
+.user-block .username,
+.user-block .description,
+.user-block .comment {
+ display: block;
+ margin-left: 50px;
+}
+.user-block .username {
+ font-size: 16px;
+ font-weight: 600;
+}
+.user-block .description {
+ color: #999;
+ font-size: 13px;
+}
+.user-block.user-block-sm .username,
+.user-block.user-block-sm .description,
+.user-block.user-block-sm .comment {
+ margin-left: 40px;
+}
+.user-block.user-block-sm .username {
+ font-size: 14px;
+}
+.img-sm,
+.img-md,
+.img-lg,
+.box-comments .box-comment img,
+.user-block.user-block-sm img {
+ float: left;
+}
+.img-sm,
+.box-comments .box-comment img,
+.user-block.user-block-sm img {
+ width: 30px!important;
+ height: 30px!important;
+}
+.img-sm + .img-push {
+ margin-left: 40px;
+}
+.img-md {
+ width: 60px;
+ height: 60px;
+}
+.img-md + .img-push {
+ margin-left: 70px;
+}
+.img-lg {
+ width: 100px;
+ height: 100px;
+}
+.img-lg + .img-push {
+ margin-left: 110px;
+}
+.img-bordered {
+ border: 3px solid #d2d6de;
+ padding: 3px;
+}
+.img-bordered-sm {
+ border: 2px solid #d2d6de;
+ padding: 2px;
+}
+.attachment-block {
+ border: 1px solid #f4f4f4;
+ padding: 5px;
+ margin-bottom: 10px;
+ background: #f7f7f7;
+}
+.attachment-block .attachment-img {
+ max-width: 100px;
+ max-height: 100px;
+ height: auto;
+ float: left;
+}
+.attachment-block .attachment-pushed {
+ margin-left: 110px;
+}
+.attachment-block .attachment-heading {
+ margin: 0;
+}
+.attachment-block .attachment-text {
+ color: #555;
+}
+.connectedSortable {
+ min-height: 100px;
+}
+.ui-helper-hidden-accessible {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.sort-highlight {
+ background: #f4f4f4;
+ border: 1px dashed #ddd;
+ margin-bottom: 10px;
+}
+.full-opacity-hover {
+ opacity: 0.65;
+ filter: alpha(opacity=65);
+}
+.full-opacity-hover:hover {
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+.chart {
+ position: relative;
+ overflow: hidden;
+ width: 100%;
+}
+.chart svg,
+.chart canvas {
+ width: 100%!important;
+}
+/*
+ * Misc: print
+ * -----------
+ */
+@media print {
+ .no-print,
+ .main-sidebar,
+ .left-side,
+ .main-header,
+ .content-header {
+ display: none!important;
+ }
+ .content-wrapper,
+ .right-side,
+ .main-footer {
+ margin-left: 0!important;
+ min-height: 0!important;
+ -webkit-transform: translate(0, 0) !important;
+ -ms-transform: translate(0, 0) !important;
+ -o-transform: translate(0, 0) !important;
+ transform: translate(0, 0) !important;
+ }
+ .fixed .content-wrapper,
+ .fixed .right-side {
+ padding-top: 0!important;
+ }
+ .invoice {
+ width: 100%;
+ border: 0;
+ margin: 0;
+ padding: 0;
+ }
+ .invoice-col {
+ float: left;
+ width: 33.3333333%;
+ }
+ .table-responsive {
+ overflow: auto;
+ }
+ .table-responsive > .table tr th,
+ .table-responsive > .table tr td {
+ white-space: normal!important;
+ }
+}
--- /dev/null
+/**@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic); **/
+/*!
+ * AdminLTE v2.3.0
+ * Author: Almsaeed Studio
+ * Website: Almsaeed Studio <http://almsaeedstudio.com>
+ * License: Open source - MIT
+ * Please visit http://opensource.org/licenses/MIT for more information
+!*/html,body{/*min-height:100%*/}.layout-boxed html,.layout-boxed body{height:100%}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:'Arial','Microsoft YaHei','ºÚÌå','ËÎÌå',sans-serif;font-weight:400;overflow-x:hidden;overflow-y:auto}.wrapper{min-height:100%;position:static;overflow:hidden}.wrapper:before,.wrapper:after{content:" ";display:table}.wrapper:after{clear:both}.layout-boxed .wrapper{max-width:1250px;margin:0 auto;min-height:100%;box-shadow:0 0 8px rgba(0,0,0,0.5);position:relative}.layout-boxed{background:url('../img/boxed-bg.jpg') repeat fixed}.content-wrapper,.right-side,.main-footer{-webkit-transition:-webkit-transform .3s ease-in-out,margin .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,margin .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,margin .3s ease-in-out;transition:transform .3s ease-in-out,margin .3s ease-in-out;margin-left:230px;z-index:820}.layout-top-nav .content-wrapper,.layout-top-nav .right-side,.layout-top-nav .main-footer{margin-left:0}@media (max-width:767px){.content-wrapper,.right-side,.main-footer{margin-left:0}}@media (min-width:768px){.sidebar-collapse .content-wrapper,.sidebar-collapse .right-side,.sidebar-collapse .main-footer{margin-left:0}}@media (max-width:767px){.sidebar-open .content-wrapper,.sidebar-open .right-side,.sidebar-open .main-footer{-webkit-transform:translate(230px, 0);-ms-transform:translate(230px, 0);-o-transform:translate(230px, 0);transform:translate(230px, 0)}}.content-wrapper,.right-side{min-height:100%;background-color:#ecf0f5;z-index:800}.main-footer{background:#fff;padding:15px;color:#444;border-top:1px solid #d2d6de}.fixed .main-header,.fixed .main-sidebar,.fixed .left-side{position:fixed}.fixed .main-header{top:0;right:0;left:0}.fixed .content-wrapper,.fixed .right-side{padding-top:50px}@media (max-width:767px){.fixed .content-wrapper,.fixed .right-side{padding-top:100px}}.fixed.layout-boxed .wrapper{max-width:100%}body.hold-transition .content-wrapper,body.hold-transition .right-side,body.hold-transition .main-footer,body.hold-transition .main-sidebar,body.hold-transition .left-side,body.hold-transition .main-header>.navbar,body.hold-transition .main-header .logo{-webkit-transition:none;-o-transition:none;transition:none}.content{min-height:250px;padding:15px;margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:'Arial','Microsoft YaHei','ºÚÌå','ËÎÌå',sans-serif}a{color:#3c8dbc}a:hover,a:active,a:focus{outline:none;text-decoration:none;color:#72afd2}.page-header{margin:10px 0 20px 0;font-size:22px}.page-header>small{color:#666;display:block;margin-top:5px}.main-header{position:relative;max-height:100px;z-index:1030}.main-header>.navbar{-webkit-transition:margin-left .3s ease-in-out;-o-transition:margin-left .3s ease-in-out;transition:margin-left .3s ease-in-out;margin-bottom:0;margin-left:230px;border:none;min-height:50px;border-radius:0}.layout-top-nav .main-header>.navbar{margin-left:0}.main-header #navbar-search-input.form-control{background:rgba(255,255,255,0.2);border-color:transparent}.main-header #navbar-search-input.form-control:focus,.main-header #navbar-search-input.form-control:active{border-color:rgba(0,0,0,0.1);background:rgba(255,255,255,0.9)}.main-header #navbar-search-input.form-control::-moz-placeholder{color:#ccc;opacity:1}.main-header #navbar-search-input.form-control:-ms-input-placeholder{color:#ccc}.main-header #navbar-search-input.form-control::-webkit-input-placeholder{color:#ccc}.main-header .navbar-custom-menu,.main-header .navbar-right{float:right}@media (max-width:991px){.main-header .navbar-custom-menu a,.main-header .navbar-right a{color:inherit;background:transparent}}@media (max-width:767px){.main-header .navbar-right{float:none}.navbar-collapse .main-header .navbar-right{margin:7.5px -15px}.main-header .navbar-right>li{color:inherit;border:0}}.main-header .sidebar-toggle{float:left;background-color:transparent;background-image:none;padding:15px 15px;font-family:fontAwesome}.main-header .sidebar-toggle:before{content:"\f0c9"}.main-header .sidebar-toggle:hover{color:#fff}.main-header .sidebar-toggle:focus,.main-header .sidebar-toggle:active{background:transparent}.main-header .sidebar-toggle .icon-bar{display:none}.main-header .navbar .nav>li.user>a>.fa,.main-header .navbar .nav>li.user>a>.glyphicon,.main-header .navbar .nav>li.user>a>.ion{margin-right:5px}.main-header .navbar .nav>li>a>.label{position:absolute;top:9px;right:7px;text-align:center;font-size:9px;padding:2px 3px;line-height:.9}.main-header .logo{-webkit-transition:width .3s ease-in-out;-o-transition:width .3s ease-in-out;transition:width .3s ease-in-out;display:block;float:left;height:50px;font-size:20px;line-height:50px;text-align:center;width:230px;font-family:'Arial','Microsoft YaHei','ºÚÌå','ËÎÌå',sans-serif;padding:0 15px;font-weight:300;overflow:hidden}.main-header .logo .logo-lg{display:block}.main-header .logo .logo-mini{display:none}.main-header .navbar-brand{color:#fff}.content-header{position:relative;padding:15px 15px 0 15px}.content-header>h1{margin:0;font-size:24px}.content-header>h1>small{font-size:15px;display:inline-block;padding-left:4px;font-weight:300}.content-header>.breadcrumb{float:right;background:transparent;margin-top:0;margin-bottom:0;font-size:12px;padding:7px 5px;position:absolute;top:15px;right:10px;border-radius:2px}.content-header>.breadcrumb>li>a{color:#444;text-decoration:none;display:inline-block}.content-header>.breadcrumb>li>a>.fa,.content-header>.breadcrumb>li>a>.glyphicon,.content-header>.breadcrumb>li>a>.ion{margin-right:5px}.content-header>.breadcrumb>li+li:before{content:'>\00a0'}@media (max-width:991px){.content-header>.breadcrumb{position:relative;margin-top:5px;top:0;right:0;float:none;background:#d2d6de;padding-left:10px}.content-header>.breadcrumb li:before{color:#97a0b3}}.navbar-toggle{color:#fff;border:0;margin:0;padding:15px 15px}@media (max-width:991px){.navbar-custom-menu .navbar-nav>li{float:left}.navbar-custom-menu .navbar-nav{margin:0;float:left}.navbar-custom-menu .navbar-nav>li>a{padding-top:15px;padding-bottom:15px;line-height:20px}}@media (max-width:767px){.main-header{position:relative}.main-header .logo,.main-header .navbar{width:100%;float:none}.main-header .navbar{margin:0}.main-header .navbar-custom-menu{float:right}}@media (max-width:991px){.navbar-collapse.pull-left{float:none!important}.navbar-collapse.pull-left+.navbar-custom-menu{display:block;position:absolute;top:0;right:40px}}.main-sidebar,.left-side{position:absolute;top:0;left:0;padding-top:50px;min-height:100%;width:230px;z-index:810;-webkit-transition:-webkit-transform .3s ease-in-out,width .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,width .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,width .3s ease-in-out;transition:transform .3s ease-in-out,width .3s ease-in-out}@media (max-width:767px){.main-sidebar,.left-side{padding-top:100px}}@media (max-width:767px){.main-sidebar,.left-side{-webkit-transform:translate(-230px, 0);-ms-transform:translate(-230px, 0);-o-transform:translate(-230px, 0);transform:translate(-230px, 0)}}@media (min-width:768px){.sidebar-collapse .main-sidebar,.sidebar-collapse .left-side{-webkit-transform:translate(-230px, 0);-ms-transform:translate(-230px, 0);-o-transform:translate(-230px, 0);transform:translate(-230px, 0)}}@media (max-width:767px){.sidebar-open .main-sidebar,.sidebar-open .left-side{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}}.sidebar{padding-bottom:10px}.sidebar-form input:focus{border-color:transparent}.user-panel{position:relative;width:100%;padding:10px;overflow:hidden}.user-panel:before,.user-panel:after{content:" ";display:table}.user-panel:after{clear:both}.user-panel>.image>img{width:100%;max-width:45px;height:auto}.user-panel>.info{padding:5px 5px 5px 15px;line-height:1;position:absolute;left:55px}.user-panel>.info>p{font-weight:600;margin-bottom:9px}.user-panel>.info>a{text-decoration:none;padding-right:5px;margin-top:3px;font-size:11px}.user-panel>.info>a>.fa,.user-panel>.info>a>.ion,.user-panel>.info>a>.glyphicon{margin-right:3px}.sidebar-menu{list-style:none;margin:0;padding:0}.sidebar-menu>li{position:relative;margin:0;padding:0}.sidebar-menu>li>a{padding:12px 5px 12px 15px;display:block}.sidebar-menu>li>a>.fa,.sidebar-menu>li>a>.glyphicon,.sidebar-menu>li>a>.ion{width:20px}.sidebar-menu>li .label,.sidebar-menu>li .badge{margin-top:3px;margin-right:5px}.sidebar-menu li.header{padding:10px 25px 10px 15px;font-size:12px}.sidebar-menu li>a>.fa-angle-left{width:auto;height:auto;padding:0;margin-right:10px;margin-top:3px}.sidebar-menu li.active>a>.fa-angle-left{-webkit-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.sidebar-menu li.active>.treeview-menu{display:block}.sidebar-menu .treeview-menu{display:none;list-style:none;padding:0;margin:0;padding-left:5px}.sidebar-menu .treeview-menu .treeview-menu{padding-left:20px}.sidebar-menu .treeview-menu>li{margin:0}.sidebar-menu .treeview-menu>li>a{padding:5px 5px 5px 15px;display:block;font-size:14px}.sidebar-menu .treeview-menu>li>a>.fa,.sidebar-menu .treeview-menu>li>a>.glyphicon,.sidebar-menu .treeview-menu>li>a>.ion{width:20px}.sidebar-menu .treeview-menu>li>a>.fa-angle-left,.sidebar-menu .treeview-menu>li>a>.fa-angle-down{width:auto}@media (min-width:768px){.sidebar-mini.sidebar-collapse .content-wrapper,.sidebar-mini.sidebar-collapse .right-side,.sidebar-mini.sidebar-collapse .main-footer{margin-left:50px!important;z-index:840}.sidebar-mini.sidebar-collapse .main-sidebar{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0);width:50px!important;z-index:850}.sidebar-mini.sidebar-collapse .sidebar-menu>li{position:relative}.sidebar-mini.sidebar-collapse .sidebar-menu>li>a{margin-right:0}.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span{border-top-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:not(.treeview)>a>span{border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{padding-top:5px;padding-bottom:5px;border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>a>span:not(.pull-right),.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>.treeview-menu{display:block!important;position:absolute;width:180px;left:50px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>a>span{top:0;margin-left:-3px;padding:12px 5px 12px 20px;background-color:inherit}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>.treeview-menu{top:44px;margin-left:0}.sidebar-mini.sidebar-collapse .main-sidebar .user-panel>.info,.sidebar-mini.sidebar-collapse .sidebar-form,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span,.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>.pull-right,.sidebar-mini.sidebar-collapse .sidebar-menu li.header{display:none!important;-webkit-transform:translateZ(0)}.sidebar-mini.sidebar-collapse .main-header .logo{width:50px}.sidebar-mini.sidebar-collapse .main-header .logo>.logo-mini{display:block;margin-left:-15px;margin-right:-15px;font-size:18px}.sidebar-mini.sidebar-collapse .main-header .logo>.logo-lg{display:none}.sidebar-mini.sidebar-collapse .main-header .navbar{margin-left:50px}}.sidebar-menu,.main-sidebar .user-panel,.sidebar-menu>li.header{white-space:nowrap;overflow:hidden}.sidebar-menu:hover{overflow:visible}.sidebar-form,.sidebar-menu>li.header{overflow:hidden;text-overflow:clip}.sidebar-menu li>a{position:relative}.sidebar-menu li>a>.pull-right{position:absolute;top:50%;right:10px;margin-top:-7px}.control-sidebar-bg{position:fixed;z-index:1000;bottom:0}.control-sidebar-bg,.control-sidebar{top:0;right:-230px;width:230px;-webkit-transition:right .3s ease-in-out;-o-transition:right .3s ease-in-out;transition:right .3s ease-in-out}.control-sidebar{position:absolute;padding-top:50px;z-index:1010}@media (max-width:768px){.control-sidebar{padding-top:100px}}.control-sidebar>.tab-content{padding:10px 15px}.control-sidebar.control-sidebar-open,.control-sidebar.control-sidebar-open+.control-sidebar-bg{right:0}.control-sidebar-open .control-sidebar-bg,.control-sidebar-open .control-sidebar{right:0}@media (min-width:768px){.control-sidebar-open .content-wrapper,.control-sidebar-open .right-side,.control-sidebar-open .main-footer{margin-right:230px}}.nav-tabs.control-sidebar-tabs>li:first-of-type>a,.nav-tabs.control-sidebar-tabs>li:first-of-type>a:hover,.nav-tabs.control-sidebar-tabs>li:first-of-type>a:focus{border-left-width:0}.nav-tabs.control-sidebar-tabs>li>a{border-radius:0}.nav-tabs.control-sidebar-tabs>li>a,.nav-tabs.control-sidebar-tabs>li>a:hover{border-top:none;border-right:none;border-left:1px solid transparent;border-bottom:1px solid transparent}.nav-tabs.control-sidebar-tabs>li>a .icon{font-size:16px}.nav-tabs.control-sidebar-tabs>li.active>a,.nav-tabs.control-sidebar-tabs>li.active>a:hover,.nav-tabs.control-sidebar-tabs>li.active>a:focus,.nav-tabs.control-sidebar-tabs>li.active>a:active{border-top:none;border-right:none;border-bottom:none}@media (max-width:768px){.nav-tabs.control-sidebar-tabs{display:table}.nav-tabs.control-sidebar-tabs>li{display:table-cell}}.control-sidebar-heading{font-weight:400;font-size:16px;padding:10px 0;margin-bottom:10px}.control-sidebar-subheading{display:block;font-weight:400;font-size:14px}.control-sidebar-menu{list-style:none;padding:0;margin:0 -15px}.control-sidebar-menu>li>a{display:block;padding:10px 15px}.control-sidebar-menu>li>a:before,.control-sidebar-menu>li>a:after{content:" ";display:table}.control-sidebar-menu>li>a:after{clear:both}.control-sidebar-menu>li>a>.control-sidebar-subheading{margin-top:0}.control-sidebar-menu .menu-icon{float:left;width:35px;height:35px;border-radius:50%;text-align:center;line-height:35px}.control-sidebar-menu .menu-info{margin-left:45px;margin-top:3px}.control-sidebar-menu .menu-info>.control-sidebar-subheading{margin:0}.control-sidebar-menu .menu-info>p{margin:0;font-size:11px}.control-sidebar-menu .progress{margin:0}.control-sidebar-dark{color:#b8c7ce}.control-sidebar-dark,.control-sidebar-dark+.control-sidebar-bg{background:#222d32}.control-sidebar-dark .nav-tabs.control-sidebar-tabs{border-bottom:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a{background:#181f23;color:#b8c7ce}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:focus{border-left-color:#141a1d;border-bottom-color:#141a1d}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:active{background:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover{color:#fff}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:active{background:#222d32;color:#fff}.control-sidebar-dark .control-sidebar-heading,.control-sidebar-dark .control-sidebar-subheading{color:#fff}.control-sidebar-dark .control-sidebar-menu>li>a:hover{background:#1e282c}.control-sidebar-dark .control-sidebar-menu>li>a .menu-info>p{color:#b8c7ce}.control-sidebar-light{color:#5e5e5e}.control-sidebar-light,.control-sidebar-light+.control-sidebar-bg{background:#f9fafc;border-left:1px solid #d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs{border-bottom:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a{background:#e8ecf4;color:#444}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:focus{border-left-color:#d2d6de;border-bottom-color:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:active{background:#eff1f7}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:active{background:#f9fafc;color:#111}.control-sidebar-light .control-sidebar-heading,.control-sidebar-light .control-sidebar-subheading{color:#111}.control-sidebar-light .control-sidebar-menu{margin-left:-14px}.control-sidebar-light .control-sidebar-menu>li>a:hover{background:#f4f4f5}.control-sidebar-light .control-sidebar-menu>li>a .menu-info>p{color:#5e5e5e}.dropdown-menu{box-shadow:none;border-color:#eee}.dropdown-menu>li>a{color:#777}.dropdown-menu>li>a>.glyphicon,.dropdown-menu>li>a>.fa,.dropdown-menu>li>a>.ion{margin-right:10px}.dropdown-menu>li>a:hover{background-color:#e1e3e9;color:#333}.dropdown-menu>.divider{background-color:#eee}.navbar-nav>.notifications-menu>.dropdown-menu,.navbar-nav>.messages-menu>.dropdown-menu,.navbar-nav>.tasks-menu>.dropdown-menu{width:280px;padding:0 0 0 0;margin:0;top:100%}.navbar-nav>.notifications-menu>.dropdown-menu>li,.navbar-nav>.messages-menu>.dropdown-menu>li,.navbar-nav>.tasks-menu>.dropdown-menu>li{position:relative}.navbar-nav>.notifications-menu>.dropdown-menu>li.header,.navbar-nav>.messages-menu>.dropdown-menu>li.header,.navbar-nav>.tasks-menu>.dropdown-menu>li.header{border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:#ffffff;padding:7px 10px;border-bottom:1px solid #f4f4f4;color:#444444;font-size:14px}.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;font-size:12px;background-color:#fff;padding:7px 10px;border-bottom:1px solid #eeeeee;color:#444!important;text-align:center}@media (max-width:991px){.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a{background:#fff!important;color:#444!important}}.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a:hover,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a:hover,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a:hover{text-decoration:none;font-weight:normal}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu,.navbar-nav>.messages-menu>.dropdown-menu>li .menu,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu{max-height:200px;margin:0;padding:0;list-style:none;overflow-x:hidden}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a{display:block;white-space:nowrap;border-bottom:1px solid #f4f4f4}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a:hover,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:hover,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a:hover{background:#f4f4f4;text-decoration:none}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a{color:#444444;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:10px}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.glyphicon,.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.fa,.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.ion{width:20px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a{margin:0;padding:10px 10px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>div>img{margin:auto 10px auto auto;width:40px;height:40px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>h4{padding:0;margin:0 0 0 45px;color:#444444;font-size:15px;position:relative}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>h4>small{color:#999999;font-size:10px;position:absolute;top:0;right:0}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>p{margin:0 0 0 45px;font-size:12px;color:#888888}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:before,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:after{content:" ";display:table}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:after{clear:both}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a{padding:10px}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a>h3{font-size:14px;padding:0;margin:0 0 10px 0;color:#666666}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a>.progress{padding:0;margin:0}.navbar-nav>.user-menu>.dropdown-menu{border-top-right-radius:0;border-top-left-radius:0;padding:1px 0 0 0;border-top-width:0;width:280px}.navbar-nav>.user-menu>.dropdown-menu,.navbar-nav>.user-menu>.dropdown-menu>.user-body{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.navbar-nav>.user-menu>.dropdown-menu>li.user-header{height:175px;padding:10px;text-align:center}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>img{z-index:5;height:90px;width:90px;border:3px solid;border-color:transparent;border-color:rgba(255,255,255,0.2)}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>p{z-index:5;color:#fff;color:rgba(255,255,255,0.8);font-size:17px;margin-top:10px}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>p>small{display:block;font-size:12px}.navbar-nav>.user-menu>.dropdown-menu>.user-body{padding:15px;border-bottom:1px solid #f4f4f4;border-top:1px solid #dddddd}.navbar-nav>.user-menu>.dropdown-menu>.user-body:before,.navbar-nav>.user-menu>.dropdown-menu>.user-body:after{content:" ";display:table}.navbar-nav>.user-menu>.dropdown-menu>.user-body:after{clear:both}.navbar-nav>.user-menu>.dropdown-menu>.user-body a{color:#444 !important}@media (max-width:991px){.navbar-nav>.user-menu>.dropdown-menu>.user-body a{background:#fff !important;color:#444 !important}}.navbar-nav>.user-menu>.dropdown-menu>.user-footer{background-color:#f9f9f9;padding:10px}.navbar-nav>.user-menu>.dropdown-menu>.user-footer:before,.navbar-nav>.user-menu>.dropdown-menu>.user-footer:after{content:" ";display:table}.navbar-nav>.user-menu>.dropdown-menu>.user-footer:after{clear:both}.navbar-nav>.user-menu>.dropdown-menu>.user-footer .btn-default{color:#666666}@media (max-width:991px){.navbar-nav>.user-menu>.dropdown-menu>.user-footer .btn-default:hover{background-color:#f9f9f9}}.navbar-nav>.user-menu .user-image{float:left;width:25px;height:25px;border-radius:50%;margin-right:10px;margin-top:-2px}@media (max-width:767px){.navbar-nav>.user-menu .user-image{float:none;margin-right:0;margin-top:-8px;line-height:10px}}.open:not(.dropup)>.animated-dropdown-menu{backface-visibility:visible !important;-webkit-animation:flipInX .7s both;-o-animation:flipInX .7s both;animation:flipInX .7s both}@keyframes flipInX{0%{transform:perspective(400px) rotate3d(1, 0, 0, 90deg);transition-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(1, 0, 0, -20deg);transition-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(1, 0, 0, 10deg);opacity:1}80%{transform:perspective(400px) rotate3d(1, 0, 0, -5deg)}100%{transform:perspective(400px)}}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, 90deg);-webkit-transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, -20deg);-webkit-transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, 10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, -5deg)}100%{-webkit-transform:perspective(400px)}}.navbar-custom-menu>.navbar-nav>li{position:relative}.navbar-custom-menu>.navbar-nav>li>.dropdown-menu{position:absolute;right:0;left:auto}@media (max-width:991px){.navbar-custom-menu>.navbar-nav{float:right}.navbar-custom-menu>.navbar-nav>li{position:static}.navbar-custom-menu>.navbar-nav>li>.dropdown-menu{position:absolute;right:5%;left:auto;border:1px solid #ddd;background:#fff}}.form-control{border-radius:0;box-shadow:none;border-color:#d2d6de}.form-control:focus{border-color:#3c8dbc;box-shadow:none}.form-control::-moz-placeholder,.form-control:-ms-input-placeholder,.form-control::-webkit-input-placeholder{color:#bbb;opacity:1}.form-control:not(select){-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-group.has-success label{color:#00a65a}.form-group.has-success .form-control{border-color:#00a65a;box-shadow:none}.form-group.has-warning label{color:#f39c12}.form-group.has-warning .form-control{border-color:#f39c12;box-shadow:none}.form-group.has-error label{color:#dd4b39}.form-group.has-error .form-control{border-color:#dd4b39;box-shadow:none}.input-group .input-group-addon{border-radius:0;border-color:#d2d6de;background-color:#fff}.btn-group-vertical .btn.btn-flat:first-of-type,.btn-group-vertical .btn.btn-flat:last-of-type{border-radius:0}.icheck>label{padding-left:0}.form-control-feedback.fa{line-height:34px}.input-lg+.form-control-feedback.fa,.input-group-lg+.form-control-feedback.fa,.form-group-lg .form-control+.form-control-feedback.fa{line-height:46px}.input-sm+.form-control-feedback.fa,.input-group-sm+.form-control-feedback.fa,.form-group-sm .form-control+.form-control-feedback.fa{line-height:30px}.progress,.progress>.progress-bar{-webkit-box-shadow:none;box-shadow:none}.progress,.progress>.progress-bar,.progress .progress-bar,.progress>.progress-bar .progress-bar{border-radius:1px}.progress.sm,.progress-sm{height:10px}.progress.sm,.progress-sm,.progress.sm .progress-bar,.progress-sm .progress-bar{border-radius:1px}.progress.xs,.progress-xs{height:7px}.progress.xs,.progress-xs,.progress.xs .progress-bar,.progress-xs .progress-bar{border-radius:1px}.progress.xxs,.progress-xxs{height:3px}.progress.xxs,.progress-xxs,.progress.xxs .progress-bar,.progress-xxs .progress-bar{border-radius:1px}.progress.vertical{position:relative;width:30px;height:200px;display:inline-block;margin-right:10px}.progress.vertical>.progress-bar{width:100%;position:absolute;bottom:0}.progress.vertical.sm,.progress.vertical.progress-sm{width:20px}.progress.vertical.xs,.progress.vertical.progress-xs{width:10px}.progress.vertical.xxs,.progress.vertical.progress-xxs{width:3px}.progress-group .progress-text{font-weight:600}.progress-group .progress-number{float:right}.table tr>td .progress{margin:0}.progress-bar-light-blue,.progress-bar-primary{background-color:#3c8dbc}.progress-striped .progress-bar-light-blue,.progress-striped .progress-bar-primary{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-green,.progress-bar-success{background-color:#00a65a}.progress-striped .progress-bar-green,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-aqua,.progress-bar-info{background-color:#00c0ef}.progress-striped .progress-bar-aqua,.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-yellow,.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-yellow,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-red,.progress-bar-danger{background-color:#dd4b39}.progress-striped .progress-bar-red,.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.small-box{border-radius:2px;position:relative;display:block;margin-bottom:20px;box-shadow:0 1px 1px rgba(0,0,0,0.1)}.small-box>.inner{padding:10px}.small-box>.small-box-footer{position:relative;text-align:center;padding:3px 0;color:#fff;color:rgba(255,255,255,0.8);display:block;z-index:10;background:rgba(0,0,0,0.1);text-decoration:none}.small-box>.small-box-footer:hover{color:#fff;background:rgba(0,0,0,0.15)}.small-box h3{font-size:38px;font-weight:bold;margin:0 0 10px 0;white-space:nowrap;padding:0}.small-box p{font-size:15px}.small-box p>small{display:block;color:#f9f9f9;font-size:13px;margin-top:5px}.small-box h3,.small-box p{z-index:5px}.small-box .icon{-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;position:absolute;top:-10px;right:10px;z-index:0;font-size:90px;color:rgba(0,0,0,0.15)}.small-box:hover{text-decoration:none;color:#f9f9f9}.small-box:hover .icon{font-size:95px}@media (max-width:767px){.small-box{text-align:center}.small-box .icon{display:none}.small-box p{font-size:12px}}.box{position:relative;border-radius:3px;background:#ffffff;border-top:3px solid #d2d6de;margin-bottom:20px;width:100%;box-shadow:0 1px 1px rgba(0,0,0,0.1)}.box.box-primary{border-top-color:#3c8dbc}.box.box-info{border-top-color:#00c0ef}.box.box-danger{border-top-color:#dd4b39}.box.box-warning{border-top-color:#f39c12}.box.box-success{border-top-color:#00a65a}.box.box-default{border-top-color:#d2d6de}.box.collapsed-box .box-body,.box.collapsed-box .box-footer{display:none}.box .nav-stacked>li{border-bottom:1px solid #f4f4f4;margin:0}.box .nav-stacked>li:last-of-type{border-bottom:none}.box.height-control .box-body{max-height:300px;overflow:auto}.box .border-right{border-right:1px solid #f4f4f4}.box .border-left{border-left:1px solid #f4f4f4}.box.box-solid{border-top:0}.box.box-solid>.box-header .btn.btn-default{background:transparent}.box.box-solid>.box-header .btn:hover,.box.box-solid>.box-header a:hover{background:rgba(0,0,0,0.1)}.box.box-solid.box-default{border:1px solid #d2d6de}.box.box-solid.box-default>.box-header{color:#444;background:#d2d6de;background-color:#d2d6de}.box.box-solid.box-default>.box-header a,.box.box-solid.box-default>.box-header .btn{color:#444}.box.box-solid.box-primary{border:1px solid #3c8dbc}.box.box-solid.box-primary>.box-header{color:#fff;background:#3c8dbc;background-color:#3c8dbc}.box.box-solid.box-primary>.box-header a,.box.box-solid.box-primary>.box-header .btn{color:#fff}.box.box-solid.box-info{border:1px solid #00c0ef}.box.box-solid.box-info>.box-header{color:#fff;background:#00c0ef;background-color:#00c0ef}.box.box-solid.box-info>.box-header a,.box.box-solid.box-info>.box-header .btn{color:#fff}.box.box-solid.box-danger{border:1px solid #dd4b39}.box.box-solid.box-danger>.box-header{color:#fff;background:#dd4b39;background-color:#dd4b39}.box.box-solid.box-danger>.box-header a,.box.box-solid.box-danger>.box-header .btn{color:#fff}.box.box-solid.box-warning{border:1px solid #f39c12}.box.box-solid.box-warning>.box-header{color:#fff;background:#f39c12;background-color:#f39c12}.box.box-solid.box-warning>.box-header a,.box.box-solid.box-warning>.box-header .btn{color:#fff}.box.box-solid.box-success{border:1px solid #00a65a}.box.box-solid.box-success>.box-header{color:#fff;background:#00a65a;background-color:#00a65a}.box.box-solid.box-success>.box-header a,.box.box-solid.box-success>.box-header .btn{color:#fff}.box.box-solid>.box-header>.box-tools .btn{border:0;box-shadow:none}.box.box-solid[class*='bg']>.box-header{color:#fff}.box .box-group>.box{margin-bottom:5px}.box .knob-label{text-align:center;color:#333;font-weight:100;font-size:12px;margin-bottom:0.3em}.box>.overlay,.overlay-wrapper>.overlay,.box>.loading-img,.overlay-wrapper>.loading-img{position:absolute;top:0;left:0;width:100%;height:100%}.box .overlay,.overlay-wrapper .overlay{z-index:50;background:rgba(255,255,255,0.7);border-radius:3px}.box .overlay>.fa,.overlay-wrapper .overlay>.fa{position:absolute;top:50%;left:50%;margin-left:-15px;margin-top:-15px;color:#000;font-size:30px}.box .overlay.dark,.overlay-wrapper .overlay.dark{background:rgba(0,0,0,0.5)}.box-header:before,.box-body:before,.box-footer:before,.box-header:after,.box-body:after,.box-footer:after{content:" ";display:table}.box-header:after,.box-body:after,.box-footer:after{clear:both}.box-header{color:#444;display:block;padding:10px;position:relative}.box-header.with-border{border-bottom:1px solid #f4f4f4}.collapsed-box .box-header.with-border{border-bottom:none}.box-header>.fa,.box-header>.glyphicon,.box-header>.ion,.box-header .box-title{display:inline-block;font-size:18px;margin:0;line-height:1}.box-header>.fa,.box-header>.glyphicon,.box-header>.ion{margin-right:5px}.box-header>.box-tools{position:absolute;right:10px;top:5px}.box-header>.box-tools [data-toggle="tooltip"]{position:relative}.box-header>.box-tools.pull-right .dropdown-menu{right:0;left:auto}.btn-box-tool{padding:5px;font-size:12px;background:transparent;color:#97a0b3}.open .btn-box-tool,.btn-box-tool:hover{color:#606c84}.btn-box-tool.btn:active{box-shadow:none}.box-body{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;padding:10px}.no-header .box-body{border-top-right-radius:3px;border-top-left-radius:3px}.box-body>.table{margin-bottom:0}.box-body .fc{margin-top:5px}.box-body .full-width-chart{margin:-19px}.box-body.no-padding .full-width-chart{margin:-9px}.box-body .box-pane{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:3px}.box-body .box-pane-right{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:0}.box-footer{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border-top:1px solid #f4f4f4;padding:10px;background-color:#fff}.chart-legend{margin:10px 0}@media (max-width:991px){.chart-legend>li{float:left;margin-right:10px}}.box-comments{background:#f7f7f7}.box-comments .box-comment{padding:8px 0;border-bottom:1px solid #eee}.box-comments .box-comment:before,.box-comments .box-comment:after{content:" ";display:table}.box-comments .box-comment:after{clear:both}.box-comments .box-comment:last-of-type{border-bottom:0}.box-comments .box-comment:first-of-type{padding-top:0}.box-comments .box-comment img{float:left}.box-comments .comment-text{margin-left:40px;color:#555}.box-comments .username{color:#444;display:block;font-weight:600}.box-comments .text-muted{font-weight:400;font-size:12px}.todo-list{margin:0;padding:0;list-style:none;overflow:auto}.todo-list>li{border-radius:2px;padding:10px;background:#f4f4f4;margin-bottom:2px;border-left:2px solid #e6e7e8;color:#444}.todo-list>li:last-of-type{margin-bottom:0}.todo-list>li>input[type='checkbox']{margin:0 10px 0 5px}.todo-list>li .text{display:inline-block;margin-left:5px;font-weight:600}.todo-list>li .label{margin-left:10px;font-size:9px}.todo-list>li .tools{display:none;float:right;color:#dd4b39}.todo-list>li .tools>.fa,.todo-list>li .tools>.glyphicon,.todo-list>li .tools>.ion{margin-right:5px;cursor:pointer}.todo-list>li:hover .tools{display:inline-block}.todo-list>li.done{color:#999}.todo-list>li.done .text{text-decoration:line-through;font-weight:500}.todo-list>li.done .label{background:#d2d6de !important}.todo-list .danger{border-left-color:#dd4b39}.todo-list .warning{border-left-color:#f39c12}.todo-list .info{border-left-color:#00c0ef}.todo-list .success{border-left-color:#00a65a}.todo-list .primary{border-left-color:#3c8dbc}.todo-list .handle{display:inline-block;cursor:move;margin:0 5px}.chat{padding:5px 20px 5px 10px}.chat .item{margin-bottom:10px}.chat .item:before,.chat .item:after{content:" ";display:table}.chat .item:after{clear:both}.chat .item>img{width:40px;height:40px;border:2px solid transparent;border-radius:50%}.chat .item>.online{border:2px solid #00a65a}.chat .item>.offline{border:2px solid #dd4b39}.chat .item>.message{margin-left:55px;margin-top:-40px}.chat .item>.message>.name{display:block;font-weight:600}.chat .item>.attachment{border-radius:3px;background:#f4f4f4;margin-left:65px;margin-right:15px;padding:10px}.chat .item>.attachment>h4{margin:0 0 5px 0;font-weight:600;font-size:14px}.chat .item>.attachment>p,.chat .item>.attachment>.filename{font-weight:600;font-size:13px;font-style:italic;margin:0}.chat .item>.attachment:before,.chat .item>.attachment:after{content:" ";display:table}.chat .item>.attachment:after{clear:both}.box-input{max-width:200px}.modal .panel-body{color:#444}.info-box{display:block;min-height:90px;background:#fff;width:100%;box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:2px;margin-bottom:15px}.info-box small{font-size:14px}.info-box .progress{background:rgba(0,0,0,0.2);margin:5px -10px 5px -10px;height:2px}.info-box .progress,.info-box .progress .progress-bar{border-radius:0}.info-box .progress .progress-bar{background:#fff}.info-box-icon{border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px;display:block;float:left;height:90px;width:90px;text-align:center;font-size:45px;line-height:90px;background:rgba(0,0,0,0.2)}.info-box-icon>img{max-width:100%}.info-box-content{padding:5px 10px;margin-left:90px}.info-box-number{display:block;font-weight:bold;font-size:18px}.progress-description,.info-box-text{display:block;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.info-box-text{text-transform:uppercase}.info-box-more{display:block}.progress-description{margin:0}.timeline{position:relative;margin:0 0 30px 0;padding:0;list-style:none}.timeline:before{content:'';position:absolute;top:0;bottom:0;width:4px;background:#ddd;left:31px;margin:0;border-radius:2px}.timeline>li{position:relative;margin-right:10px;margin-bottom:15px}.timeline>li:before,.timeline>li:after{content:" ";display:table}.timeline>li:after{clear:both}.timeline>li>.timeline-item{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px;margin-top:0;background:#fff;color:#444;margin-left:60px;margin-right:15px;padding:0;position:relative}.timeline>li>.timeline-item>.time{color:#999;float:right;padding:10px;font-size:12px}.timeline>li>.timeline-item>.timeline-header{margin:0;color:#555;border-bottom:1px solid #f4f4f4;padding:10px;font-size:16px;line-height:1.1}.timeline>li>.timeline-item>.timeline-header>a{font-weight:600}.timeline>li>.timeline-item>.timeline-body,.timeline>li>.timeline-item>.timeline-footer{padding:10px}.timeline>li>.fa,.timeline>li>.glyphicon,.timeline>li>.ion{width:30px;height:30px;font-size:15px;line-height:30px;position:absolute;color:#666;background:#d2d6de;border-radius:50%;text-align:center;left:18px;top:0}.timeline>.time-label>span{font-weight:600;padding:5px;display:inline-block;background-color:#fff;border-radius:4px}.timeline-inverse>li>.timeline-item{background:#f0f0f0;border:1px solid #ddd;-webkit-box-shadow:none;box-shadow:none}.timeline-inverse>li>.timeline-item>.timeline-header{border-bottom-color:#ddd}.btn{border-radius:3px;-webkit-box-shadow:none;box-shadow:none;border:1px solid transparent}.btn.uppercase{text-transform:uppercase}.btn.btn-flat{border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border-width:1px}.btn:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:focus{outline:none}.btn.btn-file{position:relative;overflow:hidden}.btn.btn-file>input[type='file']{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;opacity:0;filter:alpha(opacity=0);outline:none;background:white;cursor:inherit;display:block}.btn-default{background-color:#f4f4f4;color:#444;border-color:#ddd}.btn-default:hover,.btn-default:active,.btn-default.hover{background-color:#e7e7e7}.btn-primary{background-color:#3c8dbc;border-color:#367fa9}.btn-primary:hover,.btn-primary:active,.btn-primary.hover{background-color:#367fa9}.btn-success{background-color:#00a65a;border-color:#008d4c}.btn-success:hover,.btn-success:active,.btn-success.hover{background-color:#008d4c}.btn-info{background-color:#00c0ef;border-color:#00acd6}.btn-info:hover,.btn-info:active,.btn-info.hover{background-color:#00acd6}.btn-danger{background-color:#dd4b39;border-color:#d73925}.btn-danger:hover,.btn-danger:active,.btn-danger.hover{background-color:#d73925}.btn-warning{background-color:#f39c12;border-color:#e08e0b}.btn-warning:hover,.btn-warning:active,.btn-warning.hover{background-color:#e08e0b}.btn-outline{border:1px solid #fff;background:transparent;color:#fff}.btn-outline:hover,.btn-outline:focus,.btn-outline:active{color:rgba(255,255,255,0.7);border-color:rgba(255,255,255,0.7)}.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn[class*='bg-']:hover{-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,0.2);box-shadow:inset 0 0 100px rgba(0,0,0,0.2)}.btn-app{border-radius:3px;position:relative;padding:15px 5px;margin:0 0 10px 10px;min-width:80px;height:60px;text-align:center;color:#666;border:1px solid #ddd;background-color:#f4f4f4;font-size:12px}.btn-app>.fa,.btn-app>.glyphicon,.btn-app>.ion{font-size:20px;display:block}.btn-app:hover{background:#f4f4f4;color:#444;border-color:#aaa}.btn-app:active,.btn-app:focus{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-app>.badge{position:absolute;top:-3px;right:-10px;font-size:10px;font-weight:400}.callout{border-radius:3px;margin:0 0 20px 0;padding:15px 30px 15px 15px;border-left:5px solid #eee}.callout a{color:#fff;text-decoration:underline}.callout a:hover{color:#eee}.callout h4{margin-top:0;font-weight:600}.callout p:last-child{margin-bottom:0}.callout code,.callout .highlight{background-color:#fff}.callout.callout-danger{border-color:#c23321}.callout.callout-warning{border-color:#c87f0a}.callout.callout-info{border-color:#0097bc}.callout.callout-success{border-color:#00733e}.alert{border-radius:3px}.alert h4{font-weight:600}.alert .icon{margin-right:10px}.alert .close{color:#000;opacity:.2;filter:alpha(opacity=20)}.alert .close:hover{opacity:.5;filter:alpha(opacity=50)}.alert a{color:#fff;text-decoration:underline}.alert-success{border-color:#008d4c}.alert-danger,.alert-error{border-color:#d73925}.alert-warning{border-color:#e08e0b}.alert-info{border-color:#00acd6}.nav>li>a:hover,.nav>li>a:active,.nav>li>a:focus{color:#444;background:#f7f7f7}.nav-pills>li>a{border-radius:0;border-top:3px solid transparent;color:#444}.nav-pills>li>a>.fa,.nav-pills>li>a>.glyphicon,.nav-pills>li>a>.ion{margin-right:5px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{border-top-color:#3c8dbc}.nav-pills>li.active>a{font-weight:600}.nav-stacked>li>a{border-radius:0;border-top:0;border-left:3px solid transparent;color:#444}.nav-stacked>li.active>a,.nav-stacked>li.active>a:hover{background:transparent;color:#444;border-top:0;border-left-color:#3c8dbc}.nav-stacked>li.header{border-bottom:1px solid #ddd;color:#777;margin-bottom:10px;padding:5px 10px;text-transform:uppercase}.nav-tabs-custom{margin-bottom:20px;background:#fff;box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px}.nav-tabs-custom>.nav-tabs{margin:0;/* border-bottom-color: #3C8DBC /*#f4f4f4*/; */border-top-right-radius:3px;border-top-left-radius:3px}.nav-tabs-custom>.nav-tabs>li{border-top:3px solid transparent;/*margin-bottom:-2px;*/margin-right:5px}.nav-tabs-custom>.nav-tabs>li>a{color:#444;border-radius:0}.nav-tabs-custom>.nav-tabs>li>a.text-muted{color:#999}.nav-tabs-custom>.nav-tabs>li>a,.nav-tabs-custom>.nav-tabs>li>a:hover{background:transparent;margin:0}.nav-tabs-custom>.nav-tabs>li>a:hover{color:#999}.nav-tabs-custom>.nav-tabs>li:not(.active)>a:hover,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:focus,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:active{border-color:transparent}.nav-tabs-custom>.nav-tabs>li.active{border-top-color:#3c8dbc}.nav-tabs-custom>.nav-tabs>li.active>a,.nav-tabs-custom>.nav-tabs>li.active:hover>a{background-color:#fff;color:#444}.nav-tabs-custom>.nav-tabs>li.active>a{border-top:1px solid #3C8DBC;border-left:1px solid #3C8DBC;border-right:1px solid #3C8DBC;}.nav-tabs-custom>.nav-tabs>li:first-of-type{margin-left:0}.nav-tabs-custom>.nav-tabs>li:first-of-type.active>a{border-left-color:transparent}.nav-tabs-custom>.nav-tabs.pull-right{float:none!important}.nav-tabs-custom>.nav-tabs.pull-right>li{float:right}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type{margin-right:0}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type>a{border-left-width:1px}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type.active>a{border-left-color:#f4f4f4;border-right-color:transparent}.nav-tabs-custom>.nav-tabs>li.header{line-height:35px;padding:0 10px;font-size:20px;color:#444}.nav-tabs-custom>.nav-tabs>li.header>.fa,.nav-tabs-custom>.nav-tabs>li.header>.glyphicon,.nav-tabs-custom>.nav-tabs>li.header>.ion{margin-right:5px}.nav-tabs-custom>.tab-content{background:#fff;padding:10px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.nav-tabs-custom .dropdown.open>a:active,.nav-tabs-custom .dropdown.open>a:focus{background:transparent;color:#999}.pagination>li>a{background:#fafafa;color:#666}.pagination.pagination-flat>li>a{border-radius:0 !important}.products-list{list-style:none;margin:0;padding:0}.products-list>.item{border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);padding:10px 0;background:#fff}.products-list>.item:before,.products-list>.item:after{content:" ";display:table}.products-list>.item:after{clear:both}.products-list .product-img{float:left}.products-list .product-img img{width:50px;height:50px}.products-list .product-info{margin-left:60px}.products-list .product-title{font-weight:600}.products-list .product-description{display:block;color:#999;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.product-list-in-box>.item{-webkit-box-shadow:none;box-shadow:none;border-radius:0;border-bottom:1px solid #f4f4f4}.product-list-in-box>.item:last-of-type{border-bottom-width:0}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{border-top:1px solid #f4f4f4}.table>thead>tr>th{border-bottom:2px solid #f4f4f4}.table tr td .progress{margin-top:5px}.table-bordered{border:1px solid #f4f4f4}.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 #f4f4f4}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table.no-border,.table.no-border td,.table.no-border th{border:0}table.text-center,table.text-center td,table.text-center th{text-align:center}.table.align th{text-align:left}.table.align td{text-align:right}.label-default{background-color:#d2d6de;color:#444}.direct-chat .box-body{border-bottom-right-radius:0;border-bottom-left-radius:0;position:relative;overflow-x:hidden;padding:0}.direct-chat.chat-pane-open .direct-chat-contacts{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.direct-chat-messages{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0);padding:10px;height:250px;overflow:auto}.direct-chat-msg,.direct-chat-text{display:block}.direct-chat-msg{margin-bottom:10px}.direct-chat-msg:before,.direct-chat-msg:after{content:" ";display:table}.direct-chat-msg:after{clear:both}.direct-chat-messages,.direct-chat-contacts{-webkit-transition:-webkit-transform .5s ease-in-out;-moz-transition:-moz-transform .5s ease-in-out;-o-transition:-o-transform .5s ease-in-out;transition:transform .5s ease-in-out}.direct-chat-text{border-radius:5px;position:relative;padding:5px 10px;background:#d2d6de;border:1px solid #d2d6de;margin:5px 0 0 50px;color:#444}.direct-chat-text:after,.direct-chat-text:before{position:absolute;right:100%;top:15px;border:solid transparent;border-right-color:#d2d6de;content:' ';height:0;width:0;pointer-events:none}.direct-chat-text:after{border-width:5px;margin-top:-5px}.direct-chat-text:before{border-width:6px;margin-top:-6px}.right .direct-chat-text{margin-right:50px;margin-left:0}.right .direct-chat-text:after,.right .direct-chat-text:before{right:auto;left:100%;border-right-color:transparent;border-left-color:#d2d6de}.direct-chat-img{border-radius:50%;float:left;width:40px;height:40px}.right .direct-chat-img{float:right}.direct-chat-info{display:block;margin-bottom:2px;font-size:12px}.direct-chat-name{font-weight:600}.direct-chat-timestamp{color:#999}.direct-chat-contacts-open .direct-chat-contacts{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.direct-chat-contacts{-webkit-transform:translate(101%, 0);-ms-transform:translate(101%, 0);-o-transform:translate(101%, 0);transform:translate(101%, 0);position:absolute;top:0;bottom:0;height:250px;width:100%;background:#222d32;color:#fff;overflow:auto}.contacts-list>li{border-bottom:1px solid rgba(0,0,0,0.2);padding:10px;margin:0}.contacts-list>li:before,.contacts-list>li:after{content:" ";display:table}.contacts-list>li:after{clear:both}.contacts-list>li:last-of-type{border-bottom:none}.contacts-list-img{border-radius:50%;width:40px;float:left}.contacts-list-info{margin-left:45px;color:#fff}.contacts-list-name,.contacts-list-status{display:block}.contacts-list-name{font-weight:600}.contacts-list-status{font-size:12px}.contacts-list-date{color:#aaa;font-weight:normal}.contacts-list-msg{color:#999}.direct-chat-danger .right>.direct-chat-text{background:#dd4b39;border-color:#dd4b39;color:#fff}.direct-chat-danger .right>.direct-chat-text:after,.direct-chat-danger .right>.direct-chat-text:before{border-left-color:#dd4b39}.direct-chat-primary .right>.direct-chat-text{background:#3c8dbc;border-color:#3c8dbc;color:#fff}.direct-chat-primary .right>.direct-chat-text:after,.direct-chat-primary .right>.direct-chat-text:before{border-left-color:#3c8dbc}.direct-chat-warning .right>.direct-chat-text{background:#f39c12;border-color:#f39c12;color:#fff}.direct-chat-warning .right>.direct-chat-text:after,.direct-chat-warning .right>.direct-chat-text:before{border-left-color:#f39c12}.direct-chat-info .right>.direct-chat-text{background:#00c0ef;border-color:#00c0ef;color:#fff}.direct-chat-info .right>.direct-chat-text:after,.direct-chat-info .right>.direct-chat-text:before{border-left-color:#00c0ef}.direct-chat-success .right>.direct-chat-text{background:#00a65a;border-color:#00a65a;color:#fff}.direct-chat-success .right>.direct-chat-text:after,.direct-chat-success .right>.direct-chat-text:before{border-left-color:#00a65a}.users-list>li{width:25%;float:left;padding:10px;text-align:center}.users-list>li img{border-radius:50%;max-width:100%;height:auto}.users-list>li>a:hover,.users-list>li>a:hover .users-list-name{color:#999}.users-list-name,.users-list-date{display:block}.users-list-name{font-weight:600;color:#444;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.users-list-date{color:#999;font-size:12px}.carousel-control.left,.carousel-control.right{background-image:none}.carousel-control>.fa{font-size:40px;position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-20px}.modal{background:rgba(0,0,0,0.3)}.modal-content{border-radius:0;-webkit-box-shadow:0 2px 3px rgba(0,0,0,0.125);box-shadow:0 2px 3px rgba(0,0,0,0.125);border:0}@media (min-width:768px){.modal-content{-webkit-box-shadow:0 2px 3px rgba(0,0,0,0.125);box-shadow:0 2px 3px rgba(0,0,0,0.125)}}.modal-header{border-bottom-color:#f4f4f4}.modal-footer{border-top-color:#f4f4f4}.modal-primary .modal-header,.modal-primary .modal-footer{border-color:#307095}.modal-warning .modal-header,.modal-warning .modal-footer{border-color:#c87f0a}.modal-info .modal-header,.modal-info .modal-footer{border-color:#0097bc}.modal-success .modal-header,.modal-success .modal-footer{border-color:#00733e}.modal-danger .modal-header,.modal-danger .modal-footer{border-color:#c23321}.box-widget{border:none;position:relative}.widget-user .widget-user-header{padding:20px;height:120px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user .widget-user-username{margin-top:0;margin-bottom:5px;font-size:25px;font-weight:300;text-shadow:0 1px 1px rgba(0,0,0,0.2)}.widget-user .widget-user-desc{margin-top:0}.widget-user .widget-user-image{position:absolute;top:65px;left:50%;margin-left:-45px}.widget-user .widget-user-image>img{width:90px;height:auto;border:3px solid #fff}.widget-user .box-footer{padding-top:30px}.widget-user-2 .widget-user-header{padding:20px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user-2 .widget-user-username{margin-top:5px;margin-bottom:5px;font-size:25px;font-weight:300}.widget-user-2 .widget-user-desc{margin-top:0}.widget-user-2 .widget-user-username,.widget-user-2 .widget-user-desc{margin-left:75px}.widget-user-2 .widget-user-image>img{width:65px;height:auto;float:left}.mailbox-messages>.table{margin:0}.mailbox-controls{padding:5px}.mailbox-controls.with-border{border-bottom:1px solid #f4f4f4}.mailbox-read-info{border-bottom:1px solid #f4f4f4;padding:10px}.mailbox-read-info h3{font-size:20px;margin:0}.mailbox-read-info h5{margin:0;padding:5px 0 0 0}.mailbox-read-time{color:#999;font-size:13px}.mailbox-read-message{padding:10px}.mailbox-attachments li{float:left;width:200px;border:1px solid #eee;margin-bottom:10px;margin-right:10px}.mailbox-attachment-name{font-weight:bold;color:#666}.mailbox-attachment-icon,.mailbox-attachment-info,.mailbox-attachment-size{display:block}.mailbox-attachment-info{padding:10px;background:#f4f4f4}.mailbox-attachment-size{color:#999;font-size:12px}.mailbox-attachment-icon{text-align:center;font-size:65px;color:#666;padding:20px 10px}.mailbox-attachment-icon.has-img{padding:0}.mailbox-attachment-icon.has-img>img{max-width:100%;height:auto}.lockscreen{background:#d2d6de}.lockscreen-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.lockscreen-logo a{color:#444}.lockscreen-wrapper{max-width:400px;margin:0 auto;margin-top:10%}.lockscreen .lockscreen-name{text-align:center;font-weight:600}.lockscreen-item{border-radius:4px;padding:0;background:#fff;position:relative;margin:10px auto 30px auto;width:290px}.lockscreen-image{border-radius:50%;position:absolute;left:-10px;top:-25px;background:#fff;padding:5px;z-index:10}.lockscreen-image>img{border-radius:50%;width:70px;height:70px}.lockscreen-credentials{margin-left:70px}.lockscreen-credentials .form-control{border:0}.lockscreen-credentials .btn{background-color:#fff;border:0;padding:0 10px}.lockscreen-footer{margin-top:10px}.login-logo,.register-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.login-logo a,.register-logo a{color:#444}.login-page,.register-page{background:#d2d6de}.login-box,.register-box{width:360px;margin:7% auto}@media (max-width:768px){.login-box,.register-box{width:90%;margin-top:20px}}.login-box-body,.register-box-body{background:#fff;padding:20px;border-top:0;color:#666}.login-box-body .form-control-feedback,.register-box-body .form-control-feedback{color:#777}.login-box-msg,.register-box-msg{margin:0;text-align:center;padding:0 20px 20px 20px}.social-auth-links{margin:10px 0}.error-page{width:600px;margin:20px auto 0 auto}@media (max-width:991px){.error-page{width:100%}}.error-page>.headline{float:left;font-size:100px;font-weight:300}@media (max-width:991px){.error-page>.headline{float:none;text-align:center}}.error-page>.error-content{margin-left:190px;display:block}@media (max-width:991px){.error-page>.error-content{margin-left:0}}.error-page>.error-content>h3{font-weight:300;font-size:25px}@media (max-width:991px){.error-page>.error-content>h3{text-align:center}}.invoice{position:relative;background:#fff;border:1px solid #f4f4f4;padding:20px;margin:10px 25px}.invoice-title{margin-top:0}.profile-user-img{margin:0 auto;width:100px;padding:3px;border:3px solid #d2d6de}.profile-username{font-size:21px;margin-top:5px}.post{border-bottom:1px solid #d2d6de;margin-bottom:15px;padding-bottom:15px;color:#666}.post:last-of-type{border-bottom:0;margin-bottom:0;padding-bottom:0}.post .user-block{margin-bottom:15px}.btn-social{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.btn-social>:first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)}.btn-social.btn-lg{padding-left:61px}.btn-social.btn-lg>:first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social.btn-sm{padding-left:38px}.btn-social.btn-sm>:first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social.btn-xs{padding-left:30px}.btn-social.btn-xs>:first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:34px;width:34px;padding:0}.btn-social-icon>:first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)}.btn-social-icon.btn-lg{padding-left:61px}.btn-social-icon.btn-lg>:first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social-icon.btn-sm{padding-left:38px}.btn-social-icon.btn-sm>:first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social-icon.btn-xs{padding-left:30px}.btn-social-icon.btn-xs>:first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon>:first-child{border:none;text-align:center;width:100%}.btn-social-icon.btn-lg{height:45px;width:45px;padding-left:0;padding-right:0}.btn-social-icon.btn-sm{height:30px;width:30px;padding-left:0;padding-right:0}.btn-social-icon.btn-xs{height:22px;width:22px;padding-left:0;padding-right:0}.btn-adn{color:#fff;background-color:#d87a68;border-color:rgba(0,0,0,0.2)}.btn-adn:hover,.btn-adn:focus,.btn-adn.focus,.btn-adn:active,.btn-adn.active,.open>.dropdown-toggle.btn-adn{color:#fff;background-color:#ce563f;border-color:rgba(0,0,0,0.2)}.btn-adn:active,.btn-adn.active,.open>.dropdown-toggle.btn-adn{background-image:none}.btn-adn .badge{color:#d87a68;background-color:#fff}.btn-bitbucket{color:#fff;background-color:#205081;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:hover,.btn-bitbucket:focus,.btn-bitbucket.focus,.btn-bitbucket:active,.btn-bitbucket.active,.open>.dropdown-toggle.btn-bitbucket{color:#fff;background-color:#163758;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:active,.btn-bitbucket.active,.open>.dropdown-toggle.btn-bitbucket{background-image:none}.btn-bitbucket .badge{color:#205081;background-color:#fff}.btn-dropbox{color:#fff;background-color:#1087dd;border-color:rgba(0,0,0,0.2)}.btn-dropbox:hover,.btn-dropbox:focus,.btn-dropbox.focus,.btn-dropbox:active,.btn-dropbox.active,.open>.dropdown-toggle.btn-dropbox{color:#fff;background-color:#0d6aad;border-color:rgba(0,0,0,0.2)}.btn-dropbox:active,.btn-dropbox.active,.open>.dropdown-toggle.btn-dropbox{background-image:none}.btn-dropbox .badge{color:#1087dd;background-color:#fff}.btn-facebook{color:#fff;background-color:#3b5998;border-color:rgba(0,0,0,0.2)}.btn-facebook:hover,.btn-facebook:focus,.btn-facebook.focus,.btn-facebook:active,.btn-facebook.active,.open>.dropdown-toggle.btn-facebook{color:#fff;background-color:#2d4373;border-color:rgba(0,0,0,0.2)}.btn-facebook:active,.btn-facebook.active,.open>.dropdown-toggle.btn-facebook{background-image:none}.btn-facebook .badge{color:#3b5998;background-color:#fff}.btn-flickr{color:#fff;background-color:#ff0084;border-color:rgba(0,0,0,0.2)}.btn-flickr:hover,.btn-flickr:focus,.btn-flickr.focus,.btn-flickr:active,.btn-flickr.active,.open>.dropdown-toggle.btn-flickr{color:#fff;background-color:#cc006a;border-color:rgba(0,0,0,0.2)}.btn-flickr:active,.btn-flickr.active,.open>.dropdown-toggle.btn-flickr{background-image:none}.btn-flickr .badge{color:#ff0084;background-color:#fff}.btn-foursquare{color:#fff;background-color:#f94877;border-color:rgba(0,0,0,0.2)}.btn-foursquare:hover,.btn-foursquare:focus,.btn-foursquare.focus,.btn-foursquare:active,.btn-foursquare.active,.open>.dropdown-toggle.btn-foursquare{color:#fff;background-color:#f71752;border-color:rgba(0,0,0,0.2)}.btn-foursquare:active,.btn-foursquare.active,.open>.dropdown-toggle.btn-foursquare{background-image:none}.btn-foursquare .badge{color:#f94877;background-color:#fff}.btn-github{color:#fff;background-color:#444;border-color:rgba(0,0,0,0.2)}.btn-github:hover,.btn-github:focus,.btn-github.focus,.btn-github:active,.btn-github.active,.open>.dropdown-toggle.btn-github{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-github:active,.btn-github.active,.open>.dropdown-toggle.btn-github{background-image:none}.btn-github .badge{color:#444;background-color:#fff}.btn-google{color:#fff;background-color:#dd4b39;border-color:rgba(0,0,0,0.2)}.btn-google:hover,.btn-google:focus,.btn-google.focus,.btn-google:active,.btn-google.active,.open>.dropdown-toggle.btn-google{color:#fff;background-color:#c23321;border-color:rgba(0,0,0,0.2)}.btn-google:active,.btn-google.active,.open>.dropdown-toggle.btn-google{background-image:none}.btn-google .badge{color:#dd4b39;background-color:#fff}.btn-instagram{color:#fff;background-color:#3f729b;border-color:rgba(0,0,0,0.2)}.btn-instagram:hover,.btn-instagram:focus,.btn-instagram.focus,.btn-instagram:active,.btn-instagram.active,.open>.dropdown-toggle.btn-instagram{color:#fff;background-color:#305777;border-color:rgba(0,0,0,0.2)}.btn-instagram:active,.btn-instagram.active,.open>.dropdown-toggle.btn-instagram{background-image:none}.btn-instagram .badge{color:#3f729b;background-color:#fff}.btn-linkedin{color:#fff;background-color:#007bb6;border-color:rgba(0,0,0,0.2)}.btn-linkedin:hover,.btn-linkedin:focus,.btn-linkedin.focus,.btn-linkedin:active,.btn-linkedin.active,.open>.dropdown-toggle.btn-linkedin{color:#fff;background-color:#005983;border-color:rgba(0,0,0,0.2)}.btn-linkedin:active,.btn-linkedin.active,.open>.dropdown-toggle.btn-linkedin{background-image:none}.btn-linkedin .badge{color:#007bb6;background-color:#fff}.btn-microsoft{color:#fff;background-color:#2672ec;border-color:rgba(0,0,0,0.2)}.btn-microsoft:hover,.btn-microsoft:focus,.btn-microsoft.focus,.btn-microsoft:active,.btn-microsoft.active,.open>.dropdown-toggle.btn-microsoft{color:#fff;background-color:#125acd;border-color:rgba(0,0,0,0.2)}.btn-microsoft:active,.btn-microsoft.active,.open>.dropdown-toggle.btn-microsoft{background-image:none}.btn-microsoft .badge{color:#2672ec;background-color:#fff}.btn-openid{color:#fff;background-color:#f7931e;border-color:rgba(0,0,0,0.2)}.btn-openid:hover,.btn-openid:focus,.btn-openid.focus,.btn-openid:active,.btn-openid.active,.open>.dropdown-toggle.btn-openid{color:#fff;background-color:#da7908;border-color:rgba(0,0,0,0.2)}.btn-openid:active,.btn-openid.active,.open>.dropdown-toggle.btn-openid{background-image:none}.btn-openid .badge{color:#f7931e;background-color:#fff}.btn-pinterest{color:#fff;background-color:#cb2027;border-color:rgba(0,0,0,0.2)}.btn-pinterest:hover,.btn-pinterest:focus,.btn-pinterest.focus,.btn-pinterest:active,.btn-pinterest.active,.open>.dropdown-toggle.btn-pinterest{color:#fff;background-color:#9f191f;border-color:rgba(0,0,0,0.2)}.btn-pinterest:active,.btn-pinterest.active,.open>.dropdown-toggle.btn-pinterest{background-image:none}.btn-pinterest .badge{color:#cb2027;background-color:#fff}.btn-reddit{color:#000;background-color:#eff7ff;border-color:rgba(0,0,0,0.2)}.btn-reddit:hover,.btn-reddit:focus,.btn-reddit.focus,.btn-reddit:active,.btn-reddit.active,.open>.dropdown-toggle.btn-reddit{color:#000;background-color:#bcddff;border-color:rgba(0,0,0,0.2)}.btn-reddit:active,.btn-reddit.active,.open>.dropdown-toggle.btn-reddit{background-image:none}.btn-reddit .badge{color:#eff7ff;background-color:#000}.btn-soundcloud{color:#fff;background-color:#f50;border-color:rgba(0,0,0,0.2)}.btn-soundcloud:hover,.btn-soundcloud:focus,.btn-soundcloud.focus,.btn-soundcloud:active,.btn-soundcloud.active,.open>.dropdown-toggle.btn-soundcloud{color:#fff;background-color:#c40;border-color:rgba(0,0,0,0.2)}.btn-soundcloud:active,.btn-soundcloud.active,.open>.dropdown-toggle.btn-soundcloud{background-image:none}.btn-soundcloud .badge{color:#f50;background-color:#fff}.btn-tumblr{color:#fff;background-color:#2c4762;border-color:rgba(0,0,0,0.2)}.btn-tumblr:hover,.btn-tumblr:focus,.btn-tumblr.focus,.btn-tumblr:active,.btn-tumblr.active,.open>.dropdown-toggle.btn-tumblr{color:#fff;background-color:#1c2d3f;border-color:rgba(0,0,0,0.2)}.btn-tumblr:active,.btn-tumblr.active,.open>.dropdown-toggle.btn-tumblr{background-image:none}.btn-tumblr .badge{color:#2c4762;background-color:#fff}.btn-twitter{color:#fff;background-color:#55acee;border-color:rgba(0,0,0,0.2)}.btn-twitter:hover,.btn-twitter:focus,.btn-twitter.focus,.btn-twitter:active,.btn-twitter.active,.open>.dropdown-toggle.btn-twitter{color:#fff;background-color:#2795e9;border-color:rgba(0,0,0,0.2)}.btn-twitter:active,.btn-twitter.active,.open>.dropdown-toggle.btn-twitter{background-image:none}.btn-twitter .badge{color:#55acee;background-color:#fff}.btn-vimeo{color:#fff;background-color:#1ab7ea;border-color:rgba(0,0,0,0.2)}.btn-vimeo:hover,.btn-vimeo:focus,.btn-vimeo.focus,.btn-vimeo:active,.btn-vimeo.active,.open>.dropdown-toggle.btn-vimeo{color:#fff;background-color:#1295bf;border-color:rgba(0,0,0,0.2)}.btn-vimeo:active,.btn-vimeo.active,.open>.dropdown-toggle.btn-vimeo{background-image:none}.btn-vimeo .badge{color:#1ab7ea;background-color:#fff}.btn-vk{color:#fff;background-color:#587ea3;border-color:rgba(0,0,0,0.2)}.btn-vk:hover,.btn-vk:focus,.btn-vk.focus,.btn-vk:active,.btn-vk.active,.open>.dropdown-toggle.btn-vk{color:#fff;background-color:#466482;border-color:rgba(0,0,0,0.2)}.btn-vk:active,.btn-vk.active,.open>.dropdown-toggle.btn-vk{background-image:none}.btn-vk .badge{color:#587ea3;background-color:#fff}.btn-yahoo{color:#fff;background-color:#720e9e;border-color:rgba(0,0,0,0.2)}.btn-yahoo:hover,.btn-yahoo:focus,.btn-yahoo.focus,.btn-yahoo:active,.btn-yahoo.active,.open>.dropdown-toggle.btn-yahoo{color:#fff;background-color:#500a6f;border-color:rgba(0,0,0,0.2)}.btn-yahoo:active,.btn-yahoo.active,.open>.dropdown-toggle.btn-yahoo{background-image:none}.btn-yahoo .badge{color:#720e9e;background-color:#fff}.fc-button{background:#f4f4f4;background-image:none;color:#444;border-color:#ddd;border-bottom-color:#ddd}.fc-button:hover,.fc-button:active,.fc-button.hover{background-color:#e9e9e9}.fc-header-title h2{font-size:15px;line-height:1.6em;color:#666;margin-left:10px}.fc-header-right{padding-right:10px}.fc-header-left{padding-left:10px}.fc-widget-header{background:#fafafa}.fc-grid{width:100%;border:0}.fc-widget-header:first-of-type,.fc-widget-content:first-of-type{border-left:0;border-right:0}.fc-widget-header:last-of-type,.fc-widget-content:last-of-type{border-right:0}.fc-toolbar{padding:10px;margin:0}.fc-day-number{font-size:20px;font-weight:300;padding-right:10px}.fc-color-picker{list-style:none;margin:0;padding:0}.fc-color-picker>li{float:left;font-size:30px;margin-right:5px;line-height:30px}.fc-color-picker>li .fa{-webkit-transition:-webkit-transform linear .3s;-moz-transition:-moz-transform linear .3s;-o-transition:-o-transform linear .3s;transition:transform linear .3s}.fc-color-picker>li .fa:hover{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);-o-transform:rotate(30deg);transform:rotate(30deg)}#add-new-event{-webkit-transition:all linear .3s;-o-transition:all linear .3s;transition:all linear .3s}.external-event{padding:5px 10px;font-weight:bold;margin-bottom:4px;box-shadow:0 1px 1px rgba(0,0,0,0.1);text-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px;cursor:move}.external-event:hover{box-shadow:inset 0 0 90px rgba(0,0,0,0.2)}.select2-container--default.select2-container--focus,.select2-selection.select2-container--focus,.select2-container--default:focus,.select2-selection:focus,.select2-container--default:active,.select2-selection:active{outline:none}.select2-container--default .select2-selection--single,.select2-selection .select2-selection--single{border:1px solid #d2d6de;border-radius:0;padding:6px 12px;height:34px}.select2-container--default.select2-container--open{border-color:#3c8dbc}.select2-dropdown{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#3c8dbc;color:white}.select2-results__option{padding:6px 12px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{padding-left:0;padding-right:0;height:auto;margin-top:-4px}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:6px;padding-left:20px}.select2-container--default .select2-selection--single .select2-selection__arrow{height:28px;right:3px}.select2-container--default .select2-selection--single .select2-selection__arrow b{margin-top:0}.select2-dropdown .select2-search__field,.select2-search--inline .select2-search__field{border:1px solid #d2d6de}.select2-dropdown .select2-search__field:focus,.select2-search--inline .select2-search__field:focus{outline:none;border:1px solid #3c8dbc}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option[aria-selected=true],.select2-container--default .select2-results__option[aria-selected=true]:hover{color:#444}.select2-container--default .select2-selection--multiple{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-selection--multiple:focus{border-color:#3c8dbc}.select2-container--default.select2-container--focus .select2-selection--multiple{border-color:#d2d6de}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#3c8dbc;border-color:#367fa9;padding:1px 10px;color:#fff}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{margin-right:5px;color:rgba(255,255,255,0.7)}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#fff}.select2-container .select2-selection--single .select2-selection__rendered{padding-right:10px}.pad{padding:10px}.margin{margin:10px}.margin-bottom{margin-bottom:20px}.margin-bottom-none{margin-bottom:0}.margin-r-5{margin-right:5px}.inline{display:inline}.description-block{display:block;margin:10px 0;text-align:center}.description-block.margin-bottom{margin-bottom:25px}.description-block>.description-header{margin:0;padding:0;font-weight:600;font-size:16px}.description-block>.description-text{text-transform:uppercase}.bg-red,.bg-yellow,.bg-aqua,.bg-blue,.bg-light-blue,.bg-green,.bg-navy,.bg-teal,.bg-olive,.bg-lime,.bg-orange,.bg-fuchsia,.bg-purple,.bg-maroon,.bg-black,.bg-red-active,.bg-yellow-active,.bg-aqua-active,.bg-blue-active,.bg-light-blue-active,.bg-green-active,.bg-navy-active,.bg-teal-active,.bg-olive-active,.bg-lime-active,.bg-orange-active,.bg-fuchsia-active,.bg-purple-active,.bg-maroon-active,.bg-black-active,.callout.callout-danger,.callout.callout-warning,.callout.callout-info,.callout.callout-success,.alert-success,.alert-danger,.alert-error,.alert-warning,.alert-info,.label-danger,.label-info,.label-warning,.label-primary,.label-success,.modal-primary .modal-body,.modal-primary .modal-header,.modal-primary .modal-footer,.modal-warning .modal-body,.modal-warning .modal-header,.modal-warning .modal-footer,.modal-info .modal-body,.modal-info .modal-header,.modal-info .modal-footer,.modal-success .modal-body,.modal-success .modal-header,.modal-success .modal-footer,.modal-danger .modal-body,.modal-danger .modal-header,.modal-danger .modal-footer{color:#fff !important}.bg-gray{color:#000;background-color:#d2d6de !important}.bg-gray-light{background-color:#f7f7f7}.bg-black{background-color:#111 !important}.bg-red,.callout.callout-danger,.alert-danger,.alert-error,.label-danger,.modal-danger .modal-body{background-color:#dd4b39 !important}.bg-yellow,.callout.callout-warning,.alert-warning,.label-warning,.modal-warning .modal-body{background-color:#f39c12 !important}.bg-aqua,.callout.callout-info,.alert-info,.label-info,.modal-info .modal-body{background-color:#00c0ef !important}.bg-blue{background-color:#0073b7 !important}.bg-light-blue,.label-primary,.modal-primary .modal-body{background-color:#3c8dbc !important}.bg-green,.callout.callout-success,.alert-success,.label-success,.modal-success .modal-body{background-color:#00a65a !important}.bg-navy{background-color:#001f3f !important}.bg-teal{background-color:#39cccc !important}.bg-olive{background-color:#3d9970 !important}.bg-lime{background-color:#01ff70 !important}.bg-orange{background-color:#ff851b !important}.bg-fuchsia{background-color:#f012be !important}.bg-purple{background-color:#605ca8 !important}.bg-maroon{background-color:#d81b60 !important}.bg-gray-active{color:#000;background-color:#b5bbc8 !important}.bg-black-active{background-color:#000 !important}.bg-red-active,.modal-danger .modal-header,.modal-danger .modal-footer{background-color:#d33724 !important}.bg-yellow-active,.modal-warning .modal-header,.modal-warning .modal-footer{background-color:#db8b0b !important}.bg-aqua-active,.modal-info .modal-header,.modal-info .modal-footer{background-color:#00a7d0 !important}.bg-blue-active{background-color:#005384 !important}.bg-light-blue-active,.modal-primary .modal-header,.modal-primary .modal-footer{background-color:#357ca5 !important}.bg-green-active,.modal-success .modal-header,.modal-success .modal-footer{background-color:#008d4c !important}.bg-navy-active{background-color:#001a35 !important}.bg-teal-active{background-color:#30bbbb !important}.bg-olive-active{background-color:#368763 !important}.bg-lime-active{background-color:#00e765 !important}.bg-orange-active{background-color:#ff7701 !important}.bg-fuchsia-active{background-color:#db0ead !important}.bg-purple-active{background-color:#555299 !important}.bg-maroon-active{background-color:#ca195a !important}[class^="bg-"].disabled{opacity:.65;filter:alpha(opacity=65)}.text-red{color:#dd4b39 !important}.text-yellow{color:#f39c12 !important}.text-aqua{color:#00c0ef !important}.text-blue{color:#0073b7 !important}.text-black{color:#111 !important}.text-light-blue{color:#3c8dbc !important}.text-green{color:#00a65a !important}.text-gray{color:#d2d6de !important}.text-navy{color:#001f3f !important}.text-teal{color:#39cccc !important}.text-olive{color:#3d9970 !important}.text-lime{color:#01ff70 !important}.text-orange{color:#ff851b !important}.text-fuchsia{color:#f012be !important}.text-purple{color:#605ca8 !important}.text-maroon{color:#d81b60 !important}.link-muted{color:#7a869d}.link-muted:hover,.link-muted:focus{color:#606c84}.link-black{color:#666}.link-black:hover,.link-black:focus{color:#999}.hide{display:none !important}.no-border{border:0 !important}.no-padding{padding:0 !important}.no-margin{margin:0 !important}.no-shadow{box-shadow:none!important}.list-unstyled,.chart-legend,.contacts-list,.users-list,.mailbox-attachments{list-style:none;margin:0;padding:0}.list-group-unbordered>.list-group-item{border-left:0;border-right:0;border-radius:0;padding-left:0;padding-right:0}.flat{border-radius:0 !important}.text-bold,.text-bold.table td,.text-bold.table th{font-weight:700}.text-sm{font-size:12px}.jqstooltip{padding:5px!important;width:auto!important;height:auto!important}.bg-teal-gradient{background:#39cccc !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #39cccc), color-stop(1, #7adddd)) !important;background:-ms-linear-gradient(bottom, #39cccc, #7adddd) !important;background:-moz-linear-gradient(center bottom, #39cccc 0, #7adddd 100%) !important;background:-o-linear-gradient(#7adddd, #39cccc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#7adddd', endColorstr='#39cccc', GradientType=0) !important;color:#fff}.bg-light-blue-gradient{background:#3c8dbc !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #3c8dbc), color-stop(1, #67a8ce)) !important;background:-ms-linear-gradient(bottom, #3c8dbc, #67a8ce) !important;background:-moz-linear-gradient(center bottom, #3c8dbc 0, #67a8ce 100%) !important;background:-o-linear-gradient(#67a8ce, #3c8dbc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#67a8ce', endColorstr='#3c8dbc', GradientType=0) !important;color:#fff}.bg-blue-gradient{background:#0073b7 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #0073b7), color-stop(1, #0089db)) !important;background:-ms-linear-gradient(bottom, #0073b7, #0089db) !important;background:-moz-linear-gradient(center bottom, #0073b7 0, #0089db 100%) !important;background:-o-linear-gradient(#0089db, #0073b7) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0089db', endColorstr='#0073b7', GradientType=0) !important;color:#fff}.bg-aqua-gradient{background:#00c0ef !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #00c0ef), color-stop(1, #14d1ff)) !important;background:-ms-linear-gradient(bottom, #00c0ef, #14d1ff) !important;background:-moz-linear-gradient(center bottom, #00c0ef 0, #14d1ff 100%) !important;background:-o-linear-gradient(#14d1ff, #00c0ef) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#14d1ff', endColorstr='#00c0ef', GradientType=0) !important;color:#fff}.bg-yellow-gradient{background:#f39c12 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #f39c12), color-stop(1, #f7bc60)) !important;background:-ms-linear-gradient(bottom, #f39c12, #f7bc60) !important;background:-moz-linear-gradient(center bottom, #f39c12 0, #f7bc60 100%) !important;background:-o-linear-gradient(#f7bc60, #f39c12) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f7bc60', endColorstr='#f39c12', GradientType=0) !important;color:#fff}.bg-purple-gradient{background:#605ca8 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #605ca8), color-stop(1, #9491c4)) !important;background:-ms-linear-gradient(bottom, #605ca8, #9491c4) !important;background:-moz-linear-gradient(center bottom, #605ca8 0, #9491c4 100%) !important;background:-o-linear-gradient(#9491c4, #605ca8) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#9491c4', endColorstr='#605ca8', GradientType=0) !important;color:#fff}.bg-green-gradient{background:#00a65a !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #00a65a), color-stop(1, #00ca6d)) !important;background:-ms-linear-gradient(bottom, #00a65a, #00ca6d) !important;background:-moz-linear-gradient(center bottom, #00a65a 0, #00ca6d 100%) !important;background:-o-linear-gradient(#00ca6d, #00a65a) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ca6d', endColorstr='#00a65a', GradientType=0) !important;color:#fff}.bg-red-gradient{background:#dd4b39 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #dd4b39), color-stop(1, #e47365)) !important;background:-ms-linear-gradient(bottom, #dd4b39, #e47365) !important;background:-moz-linear-gradient(center bottom, #dd4b39 0, #e47365 100%) !important;background:-o-linear-gradient(#e47365, #dd4b39) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e47365', endColorstr='#dd4b39', GradientType=0) !important;color:#fff}.bg-black-gradient{background:#111 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #111), color-stop(1, #2b2b2b)) !important;background:-ms-linear-gradient(bottom, #111, #2b2b2b) !important;background:-moz-linear-gradient(center bottom, #111 0, #2b2b2b 100%) !important;background:-o-linear-gradient(#2b2b2b, #111) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#2b2b2b', endColorstr='#111111', GradientType=0) !important;color:#fff}.bg-maroon-gradient{background:#d81b60 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #d81b60), color-stop(1, #e73f7c)) !important;background:-ms-linear-gradient(bottom, #d81b60, #e73f7c) !important;background:-moz-linear-gradient(center bottom, #d81b60 0, #e73f7c 100%) !important;background:-o-linear-gradient(#e73f7c, #d81b60) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e73f7c', endColorstr='#d81b60', GradientType=0) !important;color:#fff}.description-block .description-icon{font-size:16px}.no-pad-top{padding-top:0}.position-static{position:static!important}.list-header{font-size:15px;padding:10px 4px;font-weight:bold;color:#666}.list-seperator{height:1px;background:#f4f4f4;margin:15px 0 9px 0}.list-link>a{padding:4px;color:#777}.list-link>a:hover{color:#222}.font-light{font-weight:300}.user-block:before,.user-block:after{content:" ";display:table}.user-block:after{clear:both}.user-block img{width:40px;height:40px;float:left}.user-block .username,.user-block .description,.user-block .comment{display:block;margin-left:50px}.user-block .username{font-size:16px;font-weight:600}.user-block .description{color:#999;font-size:13px}.user-block.user-block-sm .username,.user-block.user-block-sm .description,.user-block.user-block-sm .comment{margin-left:40px}.user-block.user-block-sm .username{font-size:14px}.img-sm,.img-md,.img-lg,.box-comments .box-comment img,.user-block.user-block-sm img{float:left}.img-sm,.box-comments .box-comment img,.user-block.user-block-sm img{width:30px!important;height:30px!important}.img-sm+.img-push{margin-left:40px}.img-md{width:60px;height:60px}.img-md+.img-push{margin-left:70px}.img-lg{width:100px;height:100px}.img-lg+.img-push{margin-left:110px}.img-bordered{border:3px solid #d2d6de;padding:3px}.img-bordered-sm{border:2px solid #d2d6de;padding:2px}.attachment-block{border:1px solid #f4f4f4;padding:5px;margin-bottom:10px;background:#f7f7f7}.attachment-block .attachment-img{max-width:100px;max-height:100px;height:auto;float:left}.attachment-block .attachment-pushed{margin-left:110px}.attachment-block .attachment-heading{margin:0}.attachment-block .attachment-text{color:#555}.connectedSortable{min-height:100px}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sort-highlight{background:#f4f4f4;border:1px dashed #ddd;margin-bottom:10px}.full-opacity-hover{opacity:.65;filter:alpha(opacity=65)}.full-opacity-hover:hover{opacity:1;filter:alpha(opacity=100)}.chart{position:relative;overflow:hidden;width:100%}.chart svg,.chart canvas{width:100%!important}@media print{.no-print,.main-sidebar,.left-side,.main-header,.content-header{display:none!important}.content-wrapper,.right-side,.main-footer{margin-left:0!important;min-height:0!important;-webkit-transform:translate(0, 0) !important;-ms-transform:translate(0, 0) !important;-o-transform:translate(0, 0) !important;transform:translate(0, 0) !important}.fixed .content-wrapper,.fixed .right-side{padding-top:0!important}.invoice{width:100%;border:0;margin:0;padding:0}.invoice-col{float:left;width:33.3333333%}.table-responsive{overflow:auto}.table-responsive>.table tr th,.table-responsive>.table tr td{white-space:normal!important}}
\ No newline at end of file
--- /dev/null
+/*
+ * Skin: Blue
+ * ----------
+ */
+.skin-blue .main-header .navbar {
+ background-color: #3c8dbc;
+}
+.skin-blue .main-header .navbar .nav > li > a {
+ color: #ffffff;
+}
+.skin-blue .main-header .navbar .nav > li > a:hover,
+.skin-blue .main-header .navbar .nav > li > a:active,
+.skin-blue .main-header .navbar .nav > li > a:focus,
+.skin-blue .main-header .navbar .nav .open > a,
+.skin-blue .main-header .navbar .nav .open > a:hover,
+.skin-blue .main-header .navbar .nav .open > a:focus,
+.skin-blue .main-header .navbar .nav > .active > a {
+ background: rgba(0, 0, 0, 0.1);
+ color: #f6f6f6;
+}
+.skin-blue .main-header .navbar .sidebar-toggle {
+ color: #ffffff;
+}
+.skin-blue .main-header .navbar .sidebar-toggle:hover {
+ color: #f6f6f6;
+ background: rgba(0, 0, 0, 0.1);
+}
+.skin-blue .main-header .navbar .sidebar-toggle {
+ color: #fff;
+}
+.skin-blue .main-header .navbar .sidebar-toggle:hover {
+ background-color: #367fa9;
+}
+@media (max-width: 767px) {
+ .skin-blue .main-header .navbar .dropdown-menu li.divider {
+ background-color: rgba(255, 255, 255, 0.1);
+ }
+ .skin-blue .main-header .navbar .dropdown-menu li a {
+ color: #fff;
+ }
+ .skin-blue .main-header .navbar .dropdown-menu li a:hover {
+ background: #367fa9;
+ }
+}
+.skin-blue .main-header .logo {
+ background-color: #367fa9;
+ color: #ffffff;
+ border-bottom: 0 solid transparent;
+}
+.skin-blue .main-header .logo:hover {
+ background-color: #357ca5;
+}
+.skin-blue .main-header li.user-header {
+ background-color: #3c8dbc;
+}
+.skin-blue .content-header {
+ background: transparent;
+}
+.skin-blue .wrapper,
+.skin-blue .main-sidebar,
+.skin-blue .left-side {
+ background-color: #222d32;
+}
+.skin-blue .user-panel > .info,
+.skin-blue .user-panel > .info > a {
+ color: #fff;
+}
+.skin-blue .sidebar-menu > li.header {
+ color: #4b646f;
+ background: #1a2226;
+}
+.skin-blue .sidebar-menu > li > a {
+ border-left: 3px solid transparent;
+}
+.skin-blue .sidebar-menu > li:hover > a,
+.skin-blue .sidebar-menu > li.active > a {
+ color: #ffffff;
+ background: #1e282c;
+ border-left-color: #3c8dbc;
+}
+.skin-blue .sidebar-menu > li > .treeview-menu {
+ margin: 0 1px;
+ background: #2c3b41;
+}
+.skin-blue .sidebar a {
+ color: #b8c7ce;
+}
+.skin-blue .sidebar a:hover {
+ text-decoration: none;
+}
+.skin-blue .treeview-menu > li > a {
+ color: #8aa4af;
+}
+.skin-blue .treeview-menu > li.active > a,
+.skin-blue .treeview-menu > li > a:hover {
+ color: #ffffff;
+}
+.skin-blue .sidebar-form {
+ border-radius: 3px;
+ border: 1px solid #374850;
+ margin: 10px 10px;
+}
+.skin-blue .sidebar-form input[type="text"],
+.skin-blue .sidebar-form .btn {
+ box-shadow: none;
+ background-color: #374850;
+ border: 1px solid transparent;
+ height: 35px;
+ -webkit-transition: all 0.3s ease-in-out;
+ -o-transition: all 0.3s ease-in-out;
+ transition: all 0.3s ease-in-out;
+}
+.skin-blue .sidebar-form input[type="text"] {
+ color: #666;
+ border-top-left-radius: 2px;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 2px;
+}
+.skin-blue .sidebar-form input[type="text"]:focus,
+.skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
+ background-color: #fff;
+ color: #666;
+}
+.skin-blue .sidebar-form input[type="text"]:focus + .input-group-btn .btn {
+ border-left-color: #fff;
+}
+.skin-blue .sidebar-form .btn {
+ color: #999;
+ border-top-left-radius: 0;
+ border-top-right-radius: 2px;
+ border-bottom-right-radius: 2px;
+ border-bottom-left-radius: 0;
+}
+.skin-blue.layout-top-nav .main-header > .logo {
+ background-color: #3c8dbc;
+ color: #ffffff;
+ border-bottom: 0 solid transparent;
+}
+.skin-blue.layout-top-nav .main-header > .logo:hover {
+ background-color: #3b8ab8;
+}
--- /dev/null
+.skin-blue .main-header .navbar{background-color:#3c8dbc}.skin-blue .main-header .navbar .nav>li>a{color:#fff}.skin-blue .main-header .navbar .nav>li>a:hover,.skin-blue .main-header .navbar .nav>li>a:active,.skin-blue .main-header .navbar .nav>li>a:focus,.skin-blue .main-header .navbar .nav .open>a,.skin-blue .main-header .navbar .nav .open>a:hover,.skin-blue .main-header .navbar .nav .open>a:focus,.skin-blue .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-blue .main-header .navbar .dropdown-menu li a{color:#fff}.skin-blue .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue .main-header .logo{background-color:#367fa9;color:#fff;border-bottom:0 solid transparent}.skin-blue .main-header .logo:hover{background-color:#357ca5}.skin-blue .main-header li.user-header{background-color:#3c8dbc}.skin-blue .content-header{background:transparent}.skin-blue .wrapper,.skin-blue .main-sidebar,.skin-blue .left-side{background-color:#222d32}.skin-blue .user-panel>.info,.skin-blue .user-panel>.info>a{color:#fff}.skin-blue .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-blue .sidebar-menu>li>a{border-left:3px solid transparent}.skin-blue .sidebar-menu>li:hover>a,.skin-blue .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#3c8dbc}.skin-blue .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-blue .sidebar a{color:#b8c7ce}.skin-blue .sidebar a:hover{text-decoration:none}.skin-blue .treeview-menu>li>a{color:#8aa4af}.skin-blue .treeview-menu>li.active>a,.skin-blue .treeview-menu>li>a:hover{color:#fff}.skin-blue .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-blue .sidebar-form input[type="text"],.skin-blue .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-blue .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-blue .sidebar-form input[type="text"]:focus,.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-blue.layout-top-nav .main-header>.logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue.layout-top-nav .main-header>.logo:hover{background-color:#3b8ab8}
\ No newline at end of file
--- /dev/null
+/*! AdminLTE app.js
+ * ================
+ * Main JS application file for AdminLTE v2. This file
+ * should be included in all pages. It controls some layout
+ * options and implements exclusive AdminLTE plugins.
+ *
+ * @Author Almsaeed Studio
+ * @Support <http://www.almsaeedstudio.com>
+ * @Email <support@almsaeedstudio.com>
+ * @version 2.3.0
+ * @license MIT <http://opensource.org/licenses/MIT>
+ */
+
+//Make sure jQuery has been loaded before app.js
+if (typeof jQuery === "undefined") {
+ throw new Error("AdminLTE requires jQuery");
+}
+
+/* AdminLTE
+ *
+ * @type Object
+ * @description $.AdminLTE is the main object for the template's app.
+ * It's used for implementing functions and options related
+ * to the template. Keeping everything wrapped in an object
+ * prevents conflict with other plugins and is a better
+ * way to organize our code.
+ */
+$.AdminLTE = {};
+
+/* --------------------
+ * - AdminLTE Options -
+ * --------------------
+ * Modify these options to suit your implementation
+ */
+$.AdminLTE.options = {
+ //Add slimscroll to navbar menus
+ //This requires you to load the slimscroll plugin
+ //in every page before app.js
+ navbarMenuSlimscroll: true,
+ navbarMenuSlimscrollWidth: "3px", //The width of the scroll bar
+ navbarMenuHeight: "200px", //The height of the inner menu
+ //General animation speed for JS animated elements such as box collapse/expand and
+ //sidebar treeview slide up/down. This options accepts an integer as milliseconds,
+ //'fast', 'normal', or 'slow'
+ animationSpeed: 500,
+ //Sidebar push menu toggle button selector
+ sidebarToggleSelector: "[data-toggle='offcanvas']",
+ //Activate sidebar push menu
+ sidebarPushMenu: true,
+ //Activate sidebar slimscroll if the fixed layout is set (requires SlimScroll Plugin)
+ sidebarSlimScroll: true,
+ //Enable sidebar expand on hover effect for sidebar mini
+ //This option is forced to true if both the fixed layout and sidebar mini
+ //are used together
+ sidebarExpandOnHover: false,
+ //BoxRefresh Plugin
+ enableBoxRefresh: true,
+ //Bootstrap.js tooltip
+ enableBSToppltip: true,
+ BSTooltipSelector: "[data-toggle='tooltip']",
+ //Enable Fast Click. Fastclick.js creates a more
+ //native touch experience with touch devices. If you
+ //choose to enable the plugin, make sure you load the script
+ //before AdminLTE's app.js
+ enableFastclick: true,
+ //Control Sidebar Options
+ enableControlSidebar: true,
+ controlSidebarOptions: {
+ //Which button should trigger the open/close event
+ toggleBtnSelector: "[data-toggle='control-sidebar']",
+ //The sidebar selector
+ selector: ".control-sidebar",
+ //Enable slide over content
+ slide: true
+ },
+ //Box Widget Plugin. Enable this plugin
+ //to allow boxes to be collapsed and/or removed
+ enableBoxWidget: true,
+ //Box Widget plugin options
+ boxWidgetOptions: {
+ boxWidgetIcons: {
+ //Collapse icon
+ collapse: 'fa-minus',
+ //Open icon
+ open: 'fa-plus',
+ //Remove icon
+ remove: 'fa-times'
+ },
+ boxWidgetSelectors: {
+ //Remove button selector
+ remove: '[data-widget="remove"]',
+ //Collapse button selector
+ collapse: '[data-widget="collapse"]'
+ }
+ },
+ //Direct Chat plugin options
+ directChat: {
+ //Enable direct chat by default
+ enable: true,
+ //The button to open and close the chat contacts pane
+ contactToggleSelector: '[data-widget="chat-pane-toggle"]'
+ },
+ //Define the set of colors to use globally around the website
+ colors: {
+ lightBlue: "#3c8dbc",
+ red: "#f56954",
+ green: "#00a65a",
+ aqua: "#00c0ef",
+ yellow: "#f39c12",
+ blue: "#0073b7",
+ navy: "#001F3F",
+ teal: "#39CCCC",
+ olive: "#3D9970",
+ lime: "#01FF70",
+ orange: "#FF851B",
+ fuchsia: "#F012BE",
+ purple: "#8E24AA",
+ maroon: "#D81B60",
+ black: "#222222",
+ gray: "#d2d6de"
+ },
+ //The standard screen sizes that bootstrap uses.
+ //If you change these in the variables.less file, change
+ //them here too.
+ screenSizes: {
+ xs: 480,
+ sm: 768,
+ md: 992,
+ lg: 1200
+ }
+};
+
+/* ------------------
+ * - Implementation -
+ * ------------------
+ * The next block of code implements AdminLTE's
+ * functions and plugins as specified by the
+ * options above.
+ */
+$(function () {
+ "use strict";
+
+ //Fix for IE page transitions
+ $("body").removeClass("hold-transition");
+
+ //Extend options if external options exist
+ if (typeof AdminLTEOptions !== "undefined") {
+ $.extend(true,
+ $.AdminLTE.options,
+ AdminLTEOptions);
+ }
+
+ //Easy access to options
+ var o = $.AdminLTE.options;
+
+ //Set up the object
+ _init();
+
+ //Activate the layout maker
+ $.AdminLTE.layout.activate();
+
+ //Enable sidebar tree view controls
+ $.AdminLTE.tree('.sidebar');
+
+ //Enable control sidebar
+ if (o.enableControlSidebar) {
+ $.AdminLTE.controlSidebar.activate();
+ }
+
+ //Add slimscroll to navbar dropdown
+ if (o.navbarMenuSlimscroll && typeof $.fn.slimscroll != 'undefined') {
+ $(".navbar .menu").slimscroll({
+ height: o.navbarMenuHeight,
+ alwaysVisible: false,
+ size: o.navbarMenuSlimscrollWidth
+ }).css("width", "100%");
+ }
+
+ //Activate sidebar push menu
+ if (o.sidebarPushMenu) {
+ $.AdminLTE.pushMenu.activate(o.sidebarToggleSelector);
+ }
+
+ //Activate Bootstrap tooltip
+ if (o.enableBSToppltip) {
+ $('body').tooltip({
+ selector: o.BSTooltipSelector
+ });
+ }
+
+ //Activate box widget
+ if (o.enableBoxWidget) {
+ $.AdminLTE.boxWidget.activate();
+ }
+
+ //Activate fast click
+ if (o.enableFastclick && typeof FastClick != 'undefined') {
+ FastClick.attach(document.body);
+ }
+
+ //Activate direct chat widget
+ if (o.directChat.enable) {
+ $(document).on('click', o.directChat.contactToggleSelector, function () {
+ var box = $(this).parents('.direct-chat').first();
+ box.toggleClass('direct-chat-contacts-open');
+ });
+ }
+
+ /*
+ * INITIALIZE BUTTON TOGGLE
+ * ------------------------
+ */
+ $('.btn-group[data-toggle="btn-toggle"]').each(function () {
+ var group = $(this);
+ $(this).find(".btn").on('click', function (e) {
+ group.find(".btn.active").removeClass("active");
+ $(this).addClass("active");
+ e.preventDefault();
+ });
+
+ });
+});
+
+/* ----------------------------------
+ * - Initialize the AdminLTE Object -
+ * ----------------------------------
+ * All AdminLTE functions are implemented below.
+ */
+function _init() {
+ 'use strict';
+ /* Layout
+ * ======
+ * Fixes the layout height in case min-height fails.
+ *
+ * @type Object
+ * @usage $.AdminLTE.layout.activate()
+ * $.AdminLTE.layout.fix()
+ * $.AdminLTE.layout.fixSidebar()
+ */
+ $.AdminLTE.layout = {
+ activate: function () {
+ var _this = this;
+ _this.fix();
+ _this.fixSidebar();
+ $(window, ".wrapper").resize(function () {
+ _this.fix();
+ _this.fixSidebar();
+ });
+ },
+ fix: function () {
+ //Get window height and the wrapper height
+ var neg = $('.main-header').outerHeight() + $('.main-footer').outerHeight();
+ var window_height = $(window).height();
+ var sidebar_height = $(".sidebar").height();
+ //Set the min-height of the content and sidebar based on the
+ //the height of the document.
+ if ($("body").hasClass("fixed")) {
+ $(".content-wrapper, .right-side").css('min-height', window_height - $('.main-footer').outerHeight());
+ } else {
+ var postSetWidth;
+ if (window_height >= sidebar_height) {
+ $(".content-wrapper, .right-side").css('min-height', window_height - neg);
+ postSetWidth = window_height - neg;
+ } else {
+ $(".content-wrapper, .right-side").css('min-height', sidebar_height);
+ postSetWidth = sidebar_height;
+ }
+
+ //Fix for the control sidebar height
+ var controlSidebar = $($.AdminLTE.options.controlSidebarOptions.selector);
+ if (typeof controlSidebar !== "undefined") {
+ if (controlSidebar.height() > postSetWidth)
+ $(".content-wrapper, .right-side").css('min-height', controlSidebar.height());
+ }
+
+ }
+ },
+ fixSidebar: function () {
+ //Make sure the body tag has the .fixed class
+ if (!$("body").hasClass("fixed")) {
+ if (typeof $.fn.slimScroll != 'undefined') {
+ $(".sidebar").slimScroll({destroy: true}).height("auto");
+ }
+ return;
+ } else if (typeof $.fn.slimScroll == 'undefined' && window.console) {
+ window.console.error("Error: the fixed layout requires the slimscroll plugin!");
+ }
+ //Enable slimscroll for fixed layout
+ if ($.AdminLTE.options.sidebarSlimScroll) {
+ if (typeof $.fn.slimScroll != 'undefined') {
+ //Destroy if it exists
+ $(".sidebar").slimScroll({destroy: true}).height("auto");
+ //Add slimscroll
+ $(".sidebar").slimscroll({
+ height: ($(window).height() - $(".main-header").height()) + "px",
+ color: "rgba(0,0,0,0.2)",
+ size: "3px"
+ });
+ }
+ }
+ }
+ };
+
+ /* PushMenu()
+ * ==========
+ * Adds the push menu functionality to the sidebar.
+ *
+ * @type Function
+ * @usage: $.AdminLTE.pushMenu("[data-toggle='offcanvas']")
+ */
+ $.AdminLTE.pushMenu = {
+ activate: function (toggleBtn) {
+ //Get the screen sizes
+ var screenSizes = $.AdminLTE.options.screenSizes;
+
+ //Enable sidebar toggle
+ $(toggleBtn).on('click', function (e) {
+ e.preventDefault();
+
+ //Enable sidebar push menu
+ if ($(window).width() > (screenSizes.sm - 1)) {
+ if ($("body").hasClass('sidebar-collapse')) {
+ $("body").removeClass('sidebar-collapse').trigger('expanded.pushMenu');
+ } else {
+ $("body").addClass('sidebar-collapse').trigger('collapsed.pushMenu');
+ }
+ }
+ //Handle sidebar push menu for small screens
+ else {
+ if ($("body").hasClass('sidebar-open')) {
+ $("body").removeClass('sidebar-open').removeClass('sidebar-collapse').trigger('collapsed.pushMenu');
+ } else {
+ $("body").addClass('sidebar-open').trigger('expanded.pushMenu');
+ }
+ }
+ });
+
+ $(".content-wrapper").click(function () {
+ //Enable hide menu when clicking on the content-wrapper on small screens
+ if ($(window).width() <= (screenSizes.sm - 1) && $("body").hasClass("sidebar-open")) {
+ $("body").removeClass('sidebar-open');
+ }
+ });
+
+ //Enable expand on hover for sidebar mini
+ if ($.AdminLTE.options.sidebarExpandOnHover
+ || ($('body').hasClass('fixed')
+ && $('body').hasClass('sidebar-mini'))) {
+ this.expandOnHover();
+ }
+ },
+ expandOnHover: function () {
+ var _this = this;
+ var screenWidth = $.AdminLTE.options.screenSizes.sm - 1;
+ //Expand sidebar on hover
+ $('.main-sidebar').hover(function () {
+ if ($('body').hasClass('sidebar-mini')
+ && $("body").hasClass('sidebar-collapse')
+ && $(window).width() > screenWidth) {
+ _this.expand();
+ }
+ }, function () {
+ if ($('body').hasClass('sidebar-mini')
+ && $('body').hasClass('sidebar-expanded-on-hover')
+ && $(window).width() > screenWidth) {
+ _this.collapse();
+ }
+ });
+ },
+ expand: function () {
+ $("body").removeClass('sidebar-collapse').addClass('sidebar-expanded-on-hover');
+ },
+ collapse: function () {
+ if ($('body').hasClass('sidebar-expanded-on-hover')) {
+ $('body').removeClass('sidebar-expanded-on-hover').addClass('sidebar-collapse');
+ }
+ }
+ };
+
+ /* Tree()
+ * ======
+ * Converts the sidebar into a multilevel
+ * tree view menu.
+ *
+ * @type Function
+ * @Usage: $.AdminLTE.tree('.sidebar')
+ */
+ $.AdminLTE.tree = function (menu) {
+ var _this = this;
+ var animationSpeed = $.AdminLTE.options.animationSpeed;
+ $(document).on('click', menu + ' li a', function (e) {
+ //Get the clicked link and the next element
+ var $this = $(this);
+ var checkElement = $this.next();
+
+ //Check if the next element is a menu and is visible
+ if ((checkElement.is('.treeview-menu')) && (checkElement.is(':visible'))) {
+ //Close the menu
+ checkElement.slideUp(animationSpeed, function () {
+ checkElement.removeClass('menu-open');
+ //Fix the layout in case the sidebar stretches over the height of the window
+ //_this.layout.fix();
+ });
+ checkElement.parent("li").removeClass("active");
+ }
+ //If the menu is not visible
+ else if ((checkElement.is('.treeview-menu')) && (!checkElement.is(':visible'))) {
+ //Get the parent menu
+ var parent = $this.parents('ul').first();
+ //Close all open menus within the parent
+ var ul = parent.find('ul:visible').slideUp(animationSpeed);
+ //Remove the menu-open class from the parent
+ ul.removeClass('menu-open');
+ //Get the parent li
+ var parent_li = $this.parent("li");
+
+ //Open the target menu and add the menu-open class
+ checkElement.slideDown(animationSpeed, function () {
+ //Add the class active to the parent li
+ checkElement.addClass('menu-open');
+ parent.find('li.active').removeClass('active');
+ parent_li.addClass('active');
+ //Fix the layout in case the sidebar stretches over the height of the window
+ _this.layout.fix();
+ });
+ }
+ //if this isn't a link, prevent the page from being redirected
+ if (checkElement.is('.treeview-menu')) {
+ e.preventDefault();
+ }
+ });
+ };
+
+ /* ControlSidebar
+ * ==============
+ * Adds functionality to the right sidebar
+ *
+ * @type Object
+ * @usage $.AdminLTE.controlSidebar.activate(options)
+ */
+ $.AdminLTE.controlSidebar = {
+ //instantiate the object
+ activate: function () {
+ //Get the object
+ var _this = this;
+ //Update options
+ var o = $.AdminLTE.options.controlSidebarOptions;
+ //Get the sidebar
+ var sidebar = $(o.selector);
+ //The toggle button
+ var btn = $(o.toggleBtnSelector);
+
+ //Listen to the click event
+ btn.on('click', function (e) {
+ e.preventDefault();
+ //If the sidebar is not open
+ if (!sidebar.hasClass('control-sidebar-open')
+ && !$('body').hasClass('control-sidebar-open')) {
+ //Open the sidebar
+ _this.open(sidebar, o.slide);
+ } else {
+ _this.close(sidebar, o.slide);
+ }
+ });
+
+ //If the body has a boxed layout, fix the sidebar bg position
+ var bg = $(".control-sidebar-bg");
+ _this._fix(bg);
+
+ //If the body has a fixed layout, make the control sidebar fixed
+ if ($('body').hasClass('fixed')) {
+ _this._fixForFixed(sidebar);
+ } else {
+ //If the content height is less than the sidebar's height, force max height
+ if ($('.content-wrapper, .right-side').height() < sidebar.height()) {
+ _this._fixForContent(sidebar);
+ }
+ }
+ },
+ //Open the control sidebar
+ open: function (sidebar, slide) {
+ //Slide over content
+ if (slide) {
+ sidebar.addClass('control-sidebar-open');
+ } else {
+ //Push the content by adding the open class to the body instead
+ //of the sidebar itself
+ $('body').addClass('control-sidebar-open');
+ }
+ },
+ //Close the control sidebar
+ close: function (sidebar, slide) {
+ if (slide) {
+ sidebar.removeClass('control-sidebar-open');
+ } else {
+ $('body').removeClass('control-sidebar-open');
+ }
+ },
+ _fix: function (sidebar) {
+ var _this = this;
+ if ($("body").hasClass('layout-boxed')) {
+ sidebar.css('position', 'absolute');
+ sidebar.height($(".wrapper").height());
+ $(window).resize(function () {
+ _this._fix(sidebar);
+ });
+ } else {
+ sidebar.css({
+ 'position': 'fixed',
+ 'height': 'auto'
+ });
+ }
+ },
+ _fixForFixed: function (sidebar) {
+ sidebar.css({
+ 'position': 'fixed',
+ 'max-height': '100%',
+ 'overflow': 'auto',
+ 'padding-bottom': '50px'
+ });
+ },
+ _fixForContent: function (sidebar) {
+ $(".content-wrapper, .right-side").css('min-height', sidebar.height());
+ }
+ };
+
+ /* BoxWidget
+ * =========
+ * BoxWidget is a plugin to handle collapsing and
+ * removing boxes from the screen.
+ *
+ * @type Object
+ * @usage $.AdminLTE.boxWidget.activate()
+ * Set all your options in the main $.AdminLTE.options object
+ */
+ $.AdminLTE.boxWidget = {
+ selectors: $.AdminLTE.options.boxWidgetOptions.boxWidgetSelectors,
+ icons: $.AdminLTE.options.boxWidgetOptions.boxWidgetIcons,
+ animationSpeed: $.AdminLTE.options.animationSpeed,
+ activate: function (_box) {
+ var _this = this;
+ if (!_box) {
+ _box = document; // activate all boxes per default
+ }
+ //Listen for collapse event triggers
+ $(_box).on('click', _this.selectors.collapse, function (e) {
+ e.preventDefault();
+ _this.collapse($(this));
+ });
+
+ //Listen for remove event triggers
+ $(_box).on('click', _this.selectors.remove, function (e) {
+ e.preventDefault();
+ _this.remove($(this));
+ });
+ },
+ collapse: function (element) {
+ var _this = this;
+ //Find the box parent
+ var box = element.parents(".box").first();
+ //Find the body and the footer
+ var box_content = box.find("> .box-body, > .box-footer, > form >.box-body, > form > .box-footer");
+ if (!box.hasClass("collapsed-box")) {
+ //Convert minus into plus
+ element.children(":first")
+ .removeClass(_this.icons.collapse)
+ .addClass(_this.icons.open);
+ //Hide the content
+ box_content.slideUp(_this.animationSpeed, function () {
+ box.addClass("collapsed-box");
+ });
+ } else {
+ //Convert plus into minus
+ element.children(":first")
+ .removeClass(_this.icons.open)
+ .addClass(_this.icons.collapse);
+ //Show the content
+ box_content.slideDown(_this.animationSpeed, function () {
+ box.removeClass("collapsed-box");
+ });
+ }
+ },
+ remove: function (element) {
+ //Find the box parent
+ var box = element.parents(".box").first();
+ box.slideUp(this.animationSpeed);
+ }
+ };
+}
+
+/* ------------------
+ * - Custom Plugins -
+ * ------------------
+ * All custom plugins are defined below.
+ */
+
+/*
+ * BOX REFRESH BUTTON
+ * ------------------
+ * This is a custom plugin to use with the component BOX. It allows you to add
+ * a refresh button to the box. It converts the box's state to a loading state.
+ *
+ * @type plugin
+ * @usage $("#box-widget").boxRefresh( options );
+ */
+(function ($) {
+
+ "use strict";
+
+ $.fn.boxRefresh = function (options) {
+
+ // Render options
+ var settings = $.extend({
+ //Refresh button selector
+ trigger: ".refresh-btn",
+ //File source to be loaded (e.g: ajax/src.php)
+ source: "",
+ //Callbacks
+ onLoadStart: function (box) {
+ return box;
+ }, //Right after the button has been clicked
+ onLoadDone: function (box) {
+ return box;
+ } //When the source has been loaded
+
+ }, options);
+
+ //The overlay
+ var overlay = $('<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>');
+
+ return this.each(function () {
+ //if a source is specified
+ if (settings.source === "") {
+ if (window.console) {
+ window.console.log("Please specify a source first - boxRefresh()");
+ }
+ return;
+ }
+ //the box
+ var box = $(this);
+ //the button
+ var rBtn = box.find(settings.trigger).first();
+
+ //On trigger click
+ rBtn.on('click', function (e) {
+ e.preventDefault();
+ //Add loading overlay
+ start(box);
+
+ //Perform ajax call
+ box.find(".box-body").load(settings.source, function () {
+ done(box);
+ });
+ });
+ });
+
+ function start(box) {
+ //Add overlay and loading img
+ box.append(overlay);
+
+ settings.onLoadStart.call(box);
+ }
+
+ function done(box) {
+ //Remove overlay and loading img
+ box.find(overlay).remove();
+
+ settings.onLoadDone.call(box);
+ }
+
+ };
+
+})(jQuery);
+
+/*
+ * EXPLICIT BOX ACTIVATION
+ * -----------------------
+ * This is a custom plugin to use with the component BOX. It allows you to activate
+ * a box inserted in the DOM after the app.js was loaded.
+ *
+ * @type plugin
+ * @usage $("#box-widget").activateBox();
+ */
+(function ($) {
+
+ 'use strict';
+
+ $.fn.activateBox = function () {
+ $.AdminLTE.boxWidget.activate(this);
+ };
+
+})(jQuery);
+
+/*
+ * TODO LIST CUSTOM PLUGIN
+ * -----------------------
+ * This plugin depends on iCheck plugin for checkbox and radio inputs
+ *
+ * @type plugin
+ * @usage $("#todo-widget").todolist( options );
+ */
+(function ($) {
+
+ 'use strict';
+
+ $.fn.todolist = function (options) {
+ // Render options
+ var settings = $.extend({
+ //When the user checks the input
+ onCheck: function (ele) {
+ return ele;
+ },
+ //When the user unchecks the input
+ onUncheck: function (ele) {
+ return ele;
+ }
+ }, options);
+
+ return this.each(function () {
+
+ if (typeof $.fn.iCheck != 'undefined') {
+ $('input', this).on('ifChecked', function () {
+ var ele = $(this).parents("li").first();
+ ele.toggleClass("done");
+ settings.onCheck.call(ele);
+ });
+
+ $('input', this).on('ifUnchecked', function () {
+ var ele = $(this).parents("li").first();
+ ele.toggleClass("done");
+ settings.onUncheck.call(ele);
+ });
+ } else {
+ $('input', this).on('change', function () {
+ var ele = $(this).parents("li").first();
+ ele.toggleClass("done");
+ if ($('input', ele).is(":checked")) {
+ settings.onCheck.call(ele);
+ } else {
+ settings.onUncheck.call(ele);
+ }
+ });
+ }
+ });
+ };
+}(jQuery));
\ No newline at end of file
--- /dev/null
+/*! AdminLTE app.js
+ * ================
+ * Main JS application file for AdminLTE v2. This file
+ * should be included in all pages. It controls some layout
+ * options and implements exclusive AdminLTE plugins.
+ *
+ * @Author Almsaeed Studio
+ * @Support <http://www.almsaeedstudio.com>
+ * @Email <support@almsaeedstudio.com>
+ * @version 2.3.0
+ * @license MIT <http://opensource.org/licenses/MIT>
+ */
+function _init(){"use strict";$.AdminLTE.layout={activate:function(){var a=this;a.fix(),a.fixSidebar(),$(window,".wrapper").resize(function(){a.fix(),a.fixSidebar()})},fix:function(){var a=$(".main-header").outerHeight()+$(".main-footer").outerHeight(),b=$(window).height(),c=$(".sidebar").height();if($("body").hasClass("fixed"))$(".content-wrapper, .right-side").css("min-height",b-$(".main-footer").outerHeight());else{var d;b>=c?($(".content-wrapper, .right-side").css("min-height",b-a),d=b-a):($(".content-wrapper, .right-side").css("min-height",c),d=c);var e=$($.AdminLTE.options.controlSidebarOptions.selector);"undefined"!=typeof e&&e.height()>d&&$(".content-wrapper, .right-side").css("min-height",e.height())}},fixSidebar:function(){return $("body").hasClass("fixed")?("undefined"==typeof $.fn.slimScroll&&window.console&&window.console.error("Error: the fixed layout requires the slimscroll plugin!"),void($.AdminLTE.options.sidebarSlimScroll&&"undefined"!=typeof $.fn.slimScroll&&($(".sidebar").slimScroll({destroy:!0}).height("auto"),$(".sidebar").slimscroll({height:$(window).height()-$(".main-header").height()+"px",color:"rgba(0,0,0,0.2)",size:"3px"})))):void("undefined"!=typeof $.fn.slimScroll&&$(".sidebar").slimScroll({destroy:!0}).height("auto"))}},$.AdminLTE.pushMenu={activate:function(a){var b=$.AdminLTE.options.screenSizes;$(a).on("click",function(a){a.preventDefault(),$(window).width()>b.sm-1?$("body").hasClass("sidebar-collapse")?$("body").removeClass("sidebar-collapse").trigger("expanded.pushMenu"):$("body").addClass("sidebar-collapse").trigger("collapsed.pushMenu"):$("body").hasClass("sidebar-open")?$("body").removeClass("sidebar-open").removeClass("sidebar-collapse").trigger("collapsed.pushMenu"):$("body").addClass("sidebar-open").trigger("expanded.pushMenu")}),$(".content-wrapper").click(function(){$(window).width()<=b.sm-1&&$("body").hasClass("sidebar-open")&&$("body").removeClass("sidebar-open")}),($.AdminLTE.options.sidebarExpandOnHover||$("body").hasClass("fixed")&&$("body").hasClass("sidebar-mini"))&&this.expandOnHover()},expandOnHover:function(){var a=this,b=$.AdminLTE.options.screenSizes.sm-1;$(".main-sidebar").hover(function(){$("body").hasClass("sidebar-mini")&&$("body").hasClass("sidebar-collapse")&&$(window).width()>b&&a.expand()},function(){$("body").hasClass("sidebar-mini")&&$("body").hasClass("sidebar-expanded-on-hover")&&$(window).width()>b&&a.collapse()})},expand:function(){$("body").removeClass("sidebar-collapse").addClass("sidebar-expanded-on-hover")},collapse:function(){$("body").hasClass("sidebar-expanded-on-hover")&&$("body").removeClass("sidebar-expanded-on-hover").addClass("sidebar-collapse")}},$.AdminLTE.tree=function(a){var b=this,c=$.AdminLTE.options.animationSpeed;$(document).on("click",a+" li a",function(a){var d=$(this),e=d.next();if(e.is(".treeview-menu")&&e.is(":visible"))e.slideUp(c,function(){e.removeClass("menu-open")}),e.parent("li").removeClass("active");else if(e.is(".treeview-menu")&&!e.is(":visible")){var f=d.parents("ul").first(),g=f.find("ul:visible").slideUp(c);g.removeClass("menu-open");var h=d.parent("li");e.slideDown(c,function(){e.addClass("menu-open"),f.find("li.active").removeClass("active"),h.addClass("active"),b.layout.fix()})}e.is(".treeview-menu")&&a.preventDefault()})},$.AdminLTE.controlSidebar={activate:function(){var a=this,b=$.AdminLTE.options.controlSidebarOptions,c=$(b.selector),d=$(b.toggleBtnSelector);d.on("click",function(d){d.preventDefault(),c.hasClass("control-sidebar-open")||$("body").hasClass("control-sidebar-open")?a.close(c,b.slide):a.open(c,b.slide)});var e=$(".control-sidebar-bg");a._fix(e),$("body").hasClass("fixed")?a._fixForFixed(c):$(".content-wrapper, .right-side").height()<c.height()&&a._fixForContent(c)},open:function(a,b){b?a.addClass("control-sidebar-open"):$("body").addClass("control-sidebar-open")},close:function(a,b){b?a.removeClass("control-sidebar-open"):$("body").removeClass("control-sidebar-open")},_fix:function(a){var b=this;$("body").hasClass("layout-boxed")?(a.css("position","absolute"),a.height($(".wrapper").height()),$(window).resize(function(){b._fix(a)})):a.css({position:"fixed",height:"auto"})},_fixForFixed:function(a){a.css({position:"fixed","max-height":"100%",overflow:"auto","padding-bottom":"50px"})},_fixForContent:function(a){$(".content-wrapper, .right-side").css("min-height",a.height())}},$.AdminLTE.boxWidget={selectors:$.AdminLTE.options.boxWidgetOptions.boxWidgetSelectors,icons:$.AdminLTE.options.boxWidgetOptions.boxWidgetIcons,animationSpeed:$.AdminLTE.options.animationSpeed,activate:function(a){var b=this;a||(a=document),$(a).on("click",b.selectors.collapse,function(a){a.preventDefault(),b.collapse($(this))}),$(a).on("click",b.selectors.remove,function(a){a.preventDefault(),b.remove($(this))})},collapse:function(a){var b=this,c=a.parents(".box").first(),d=c.find("> .box-body, > .box-footer, > form >.box-body, > form > .box-footer");c.hasClass("collapsed-box")?(a.children(":first").removeClass(b.icons.open).addClass(b.icons.collapse),d.slideDown(b.animationSpeed,function(){c.removeClass("collapsed-box")})):(a.children(":first").removeClass(b.icons.collapse).addClass(b.icons.open),d.slideUp(b.animationSpeed,function(){c.addClass("collapsed-box")}))},remove:function(a){var b=a.parents(".box").first();b.slideUp(this.animationSpeed)}}}if("undefined"==typeof jQuery)throw new Error("AdminLTE requires jQuery");$.AdminLTE={},$.AdminLTE.options={navbarMenuSlimscroll:!0,navbarMenuSlimscrollWidth:"3px",navbarMenuHeight:"200px",animationSpeed:500,sidebarToggleSelector:"[data-toggle='offcanvas']",sidebarPushMenu:!0,sidebarSlimScroll:!0,sidebarExpandOnHover:!1,enableBoxRefresh:!0,enableBSToppltip:!0,BSTooltipSelector:"[data-toggle='tooltip']",enableFastclick:!0,enableControlSidebar:!0,controlSidebarOptions:{toggleBtnSelector:"[data-toggle='control-sidebar']",selector:".control-sidebar",slide:!0},enableBoxWidget:!0,boxWidgetOptions:{boxWidgetIcons:{collapse:"fa-minus",open:"fa-plus",remove:"fa-times"},boxWidgetSelectors:{remove:'[data-widget="remove"]',collapse:'[data-widget="collapse"]'}},directChat:{enable:!0,contactToggleSelector:'[data-widget="chat-pane-toggle"]'},colors:{lightBlue:"#3c8dbc",red:"#f56954",green:"#00a65a",aqua:"#00c0ef",yellow:"#f39c12",blue:"#0073b7",navy:"#001F3F",teal:"#39CCCC",olive:"#3D9970",lime:"#01FF70",orange:"#FF851B",fuchsia:"#F012BE",purple:"#8E24AA",maroon:"#D81B60",black:"#222222",gray:"#d2d6de"},screenSizes:{xs:480,sm:768,md:992,lg:1200}},$(function(){"use strict";$("body").removeClass("hold-transition"),"undefined"!=typeof AdminLTEOptions&&$.extend(!0,$.AdminLTE.options,AdminLTEOptions);var a=$.AdminLTE.options;_init(),$.AdminLTE.layout.activate(),$.AdminLTE.tree(".sidebar"),a.enableControlSidebar&&$.AdminLTE.controlSidebar.activate(),a.navbarMenuSlimscroll&&"undefined"!=typeof $.fn.slimscroll&&$(".navbar .menu").slimscroll({height:a.navbarMenuHeight,alwaysVisible:!1,size:a.navbarMenuSlimscrollWidth}).css("width","100%"),a.sidebarPushMenu&&$.AdminLTE.pushMenu.activate(a.sidebarToggleSelector),a.enableBSToppltip&&$("body").tooltip({selector:a.BSTooltipSelector}),a.enableBoxWidget&&$.AdminLTE.boxWidget.activate(),a.enableFastclick&&"undefined"!=typeof FastClick&&FastClick.attach(document.body),a.directChat.enable&&$(document).on("click",a.directChat.contactToggleSelector,function(){var a=$(this).parents(".direct-chat").first();a.toggleClass("direct-chat-contacts-open")}),$('.btn-group[data-toggle="btn-toggle"]').each(function(){var a=$(this);$(this).find(".btn").on("click",function(b){a.find(".btn.active").removeClass("active"),$(this).addClass("active"),b.preventDefault()})})}),function(a){"use strict";a.fn.boxRefresh=function(b){function c(a){a.append(f),e.onLoadStart.call(a)}function d(a){a.find(f).remove(),e.onLoadDone.call(a)}var e=a.extend({trigger:".refresh-btn",source:"",onLoadStart:function(a){return a},onLoadDone:function(a){return a}},b),f=a('<div class="overlay"><div class="fa fa-refresh fa-spin"></div></div>');return this.each(function(){if(""===e.source)return void(window.console&&window.console.log("Please specify a source first - boxRefresh()"));var b=a(this),f=b.find(e.trigger).first();f.on("click",function(a){a.preventDefault(),c(b),b.find(".box-body").load(e.source,function(){d(b)})})})}}(jQuery),function(a){"use strict";a.fn.activateBox=function(){a.AdminLTE.boxWidget.activate(this)}}(jQuery),function(a){"use strict";a.fn.todolist=function(b){var c=a.extend({onCheck:function(a){return a},onUncheck:function(a){return a}},b);return this.each(function(){"undefined"!=typeof a.fn.iCheck?(a("input",this).on("ifChecked",function(){var b=a(this).parents("li").first();b.toggleClass("done"),c.onCheck.call(b)}),a("input",this).on("ifUnchecked",function(){var b=a(this).parents("li").first();b.toggleClass("done"),c.onUncheck.call(b)})):a("input",this).on("change",function(){var b=a(this).parents("li").first();b.toggleClass("done"),a("input",b).is(":checked")?c.onCheck.call(b):c.onUncheck.call(b)})})}}(jQuery);
\ No newline at end of file
--- /dev/null
+/*
+ * Author: Abdullah A Almsaeed
+ * Date: 4 Jan 2014
+ * Description:
+ * This is a demo file used only for the main dashboard (index.html)
+ **/
+
+$(function () {
+
+ "use strict";
+
+ //Make the dashboard widgets sortable Using jquery UI
+ $(".connectedSortable").sortable({
+ placeholder: "sort-highlight",
+ connectWith: ".connectedSortable",
+ handle: ".box-header, .nav-tabs",
+ forcePlaceholderSize: true,
+ zIndex: 999999
+ });
+ $(".connectedSortable .box-header, .connectedSortable .nav-tabs-custom").css("cursor", "move");
+
+ //jQuery UI sortable for the todo list
+ $(".todo-list").sortable({
+ placeholder: "sort-highlight",
+ handle: ".handle",
+ forcePlaceholderSize: true,
+ zIndex: 999999
+ });
+
+ //bootstrap WYSIHTML5 - text editor
+ $(".textarea").wysihtml5();
+
+ $('.daterange').daterangepicker({
+ ranges: {
+ 'Today': [moment(), moment()],
+ 'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
+ 'Last 7 Days': [moment().subtract(6, 'days'), moment()],
+ 'Last 30 Days': [moment().subtract(29, 'days'), moment()],
+ 'This Month': [moment().startOf('month'), moment().endOf('month')],
+ 'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
+ },
+ startDate: moment().subtract(29, 'days'),
+ endDate: moment()
+ }, function (start, end) {
+ window.alert("You chose: " + start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'));
+ });
+
+ /* jQueryKnob */
+ $(".knob").knob();
+
+ //jvectormap data
+ var visitorsData = {
+ "US": 398, //USA
+ "SA": 400, //Saudi Arabia
+ "CA": 1000, //Canada
+ "DE": 500, //Germany
+ "FR": 760, //France
+ "CN": 300, //China
+ "AU": 700, //Australia
+ "BR": 600, //Brazil
+ "IN": 800, //India
+ "GB": 320, //Great Britain
+ "RU": 3000 //Russia
+ };
+ //World map by jvectormap
+ $('#world-map').vectorMap({
+ map: 'world_mill_en',
+ backgroundColor: "transparent",
+ regionStyle: {
+ initial: {
+ fill: '#e4e4e4',
+ "fill-opacity": 1,
+ stroke: 'none',
+ "stroke-width": 0,
+ "stroke-opacity": 1
+ }
+ },
+ series: {
+ regions: [{
+ values: visitorsData,
+ scale: ["#92c1dc", "#ebf4f9"],
+ normalizeFunction: 'polynomial'
+ }]
+ },
+ onRegionLabelShow: function (e, el, code) {
+ if (typeof visitorsData[code] != "undefined")
+ el.html(el.html() + ': ' + visitorsData[code] + ' new visitors');
+ }
+ });
+
+ //Sparkline charts
+ var myvalues = [1000, 1200, 920, 927, 931, 1027, 819, 930, 1021];
+ $('#sparkline-1').sparkline(myvalues, {
+ type: 'line',
+ lineColor: '#92c1dc',
+ fillColor: "#ebf4f9",
+ height: '50',
+ width: '80'
+ });
+ myvalues = [515, 519, 520, 522, 652, 810, 370, 627, 319, 630, 921];
+ $('#sparkline-2').sparkline(myvalues, {
+ type: 'line',
+ lineColor: '#92c1dc',
+ fillColor: "#ebf4f9",
+ height: '50',
+ width: '80'
+ });
+ myvalues = [15, 19, 20, 22, 33, 27, 31, 27, 19, 30, 21];
+ $('#sparkline-3').sparkline(myvalues, {
+ type: 'line',
+ lineColor: '#92c1dc',
+ fillColor: "#ebf4f9",
+ height: '50',
+ width: '80'
+ });
+
+ //The Calender
+ $("#calendar").datepicker();
+
+ //SLIMSCROLL FOR CHAT WIDGET
+ $('#chat-box').slimScroll({
+ height: '250px'
+ });
+
+ /* Morris.js Charts */
+ // Sales chart
+ var area = new Morris.Area({
+ element: 'revenue-chart',
+ resize: true,
+ data: [
+ {y: '2011 Q1', item1: 2666, item2: 2666},
+ {y: '2011 Q2', item1: 2778, item2: 2294},
+ {y: '2011 Q3', item1: 4912, item2: 1969},
+ {y: '2011 Q4', item1: 3767, item2: 3597},
+ {y: '2012 Q1', item1: 6810, item2: 1914},
+ {y: '2012 Q2', item1: 5670, item2: 4293},
+ {y: '2012 Q3', item1: 4820, item2: 3795},
+ {y: '2012 Q4', item1: 15073, item2: 5967},
+ {y: '2013 Q1', item1: 10687, item2: 4460},
+ {y: '2013 Q2', item1: 8432, item2: 5713}
+ ],
+ xkey: 'y',
+ ykeys: ['item1', 'item2'],
+ labels: ['Item 1', 'Item 2'],
+ lineColors: ['#a0d0e0', '#3c8dbc'],
+ hideHover: 'auto'
+ });
+ var line = new Morris.Line({
+ element: 'line-chart',
+ resize: true,
+ data: [
+ {y: '2011 Q1', item1: 2666},
+ {y: '2011 Q2', item1: 2778},
+ {y: '2011 Q3', item1: 4912},
+ {y: '2011 Q4', item1: 3767},
+ {y: '2012 Q1', item1: 6810},
+ {y: '2012 Q2', item1: 5670},
+ {y: '2012 Q3', item1: 4820},
+ {y: '2012 Q4', item1: 15073},
+ {y: '2013 Q1', item1: 10687},
+ {y: '2013 Q2', item1: 8432}
+ ],
+ xkey: 'y',
+ ykeys: ['item1'],
+ labels: ['Item 1'],
+ lineColors: ['#efefef'],
+ lineWidth: 2,
+ hideHover: 'auto',
+ gridTextColor: "#fff",
+ gridStrokeWidth: 0.4,
+ pointSize: 4,
+ pointStrokeColors: ["#efefef"],
+ gridLineColor: "#efefef",
+ gridTextFamily: "Open Sans",
+ gridTextSize: 10
+ });
+
+ //Donut Chart
+ var donut = new Morris.Donut({
+ element: 'sales-chart',
+ resize: true,
+ colors: ["#3c8dbc", "#f56954", "#00a65a"],
+ data: [
+ {label: "Download Sales", value: 12},
+ {label: "In-Store Sales", value: 30},
+ {label: "Mail-Order Sales", value: 20}
+ ],
+ hideHover: 'auto'
+ });
+
+ //Fix for charts under tabs
+ $('.box ul.nav a').on('shown.bs.tab', function () {
+ area.redraw();
+ donut.redraw();
+ line.redraw();
+ });
+
+ /* The todo list plugin */
+ $(".todo-list").todolist({
+ onCheck: function (ele) {
+ window.console.log("The element has been checked");
+ return ele;
+ },
+ onUncheck: function (ele) {
+ window.console.log("The element has been unchecked");
+ return ele;
+ }
+ });
+
+});
--- /dev/null
+$(function () {
+
+ 'use strict';
+
+ /* ChartJS
+ * -------
+ * Here we will create a few charts using ChartJS
+ */
+
+ //-----------------------
+ //- MONTHLY SALES CHART -
+ //-----------------------
+
+ // Get context with jQuery - using jQuery's .get() method.
+ var salesChartCanvas = $("#salesChart").get(0).getContext("2d");
+ // This will get the first returned node in the jQuery collection.
+ var salesChart = new Chart(salesChartCanvas);
+
+ var salesChartData = {
+ labels: ["January", "February", "March", "April", "May", "June", "July"],
+ datasets: [
+ {
+ label: "Electronics",
+ fillColor: "rgb(210, 214, 222)",
+ strokeColor: "rgb(210, 214, 222)",
+ pointColor: "rgb(210, 214, 222)",
+ pointStrokeColor: "#c1c7d1",
+ pointHighlightFill: "#fff",
+ pointHighlightStroke: "rgb(220,220,220)",
+ data: [65, 59, 80, 81, 56, 55, 40]
+ },
+ {
+ label: "Digital Goods",
+ fillColor: "rgba(60,141,188,0.9)",
+ strokeColor: "rgba(60,141,188,0.8)",
+ pointColor: "#3b8bba",
+ pointStrokeColor: "rgba(60,141,188,1)",
+ pointHighlightFill: "#fff",
+ pointHighlightStroke: "rgba(60,141,188,1)",
+ data: [28, 48, 40, 19, 86, 27, 90]
+ }
+ ]
+ };
+
+ var salesChartOptions = {
+ //Boolean - If we should show the scale at all
+ showScale: true,
+ //Boolean - Whether grid lines are shown across the chart
+ scaleShowGridLines: false,
+ //String - Colour of the grid lines
+ scaleGridLineColor: "rgba(0,0,0,.05)",
+ //Number - Width of the grid lines
+ scaleGridLineWidth: 1,
+ //Boolean - Whether to show horizontal lines (except X axis)
+ scaleShowHorizontalLines: true,
+ //Boolean - Whether to show vertical lines (except Y axis)
+ scaleShowVerticalLines: true,
+ //Boolean - Whether the line is curved between points
+ bezierCurve: true,
+ //Number - Tension of the bezier curve between points
+ bezierCurveTension: 0.3,
+ //Boolean - Whether to show a dot for each point
+ pointDot: false,
+ //Number - Radius of each point dot in pixels
+ pointDotRadius: 4,
+ //Number - Pixel width of point dot stroke
+ pointDotStrokeWidth: 1,
+ //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
+ pointHitDetectionRadius: 20,
+ //Boolean - Whether to show a stroke for datasets
+ datasetStroke: true,
+ //Number - Pixel width of dataset stroke
+ datasetStrokeWidth: 2,
+ //Boolean - Whether to fill the dataset with a color
+ datasetFill: true,
+ //String - A legend template
+ legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].lineColor%>\"></span><%=datasets[i].label%></li><%}%></ul>",
+ //Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
+ maintainAspectRatio: true,
+ //Boolean - whether to make the chart responsive to window resizing
+ responsive: true
+ };
+
+ //Create the line chart
+ salesChart.Line(salesChartData, salesChartOptions);
+
+ //---------------------------
+ //- END MONTHLY SALES CHART -
+ //---------------------------
+
+ //-------------
+ //- PIE CHART -
+ //-------------
+ // Get context with jQuery - using jQuery's .get() method.
+ var pieChartCanvas = $("#pieChart").get(0).getContext("2d");
+ var pieChart = new Chart(pieChartCanvas);
+ var PieData = [
+ {
+ value: 700,
+ color: "#f56954",
+ highlight: "#f56954",
+ label: "Chrome"
+ },
+ {
+ value: 500,
+ color: "#00a65a",
+ highlight: "#00a65a",
+ label: "IE"
+ },
+ {
+ value: 400,
+ color: "#f39c12",
+ highlight: "#f39c12",
+ label: "FireFox"
+ },
+ {
+ value: 600,
+ color: "#00c0ef",
+ highlight: "#00c0ef",
+ label: "Safari"
+ },
+ {
+ value: 300,
+ color: "#3c8dbc",
+ highlight: "#3c8dbc",
+ label: "Opera"
+ },
+ {
+ value: 100,
+ color: "#d2d6de",
+ highlight: "#d2d6de",
+ label: "Navigator"
+ }
+ ];
+ var pieOptions = {
+ //Boolean - Whether we should show a stroke on each segment
+ segmentShowStroke: true,
+ //String - The colour of each segment stroke
+ segmentStrokeColor: "#fff",
+ //Number - The width of each segment stroke
+ segmentStrokeWidth: 1,
+ //Number - The percentage of the chart that we cut out of the middle
+ percentageInnerCutout: 50, // This is 0 for Pie charts
+ //Number - Amount of animation steps
+ animationSteps: 100,
+ //String - Animation easing effect
+ animationEasing: "easeOutBounce",
+ //Boolean - Whether we animate the rotation of the Doughnut
+ animateRotate: true,
+ //Boolean - Whether we animate scaling the Doughnut from the centre
+ animateScale: false,
+ //Boolean - whether to make the chart responsive to window resizing
+ responsive: true,
+ // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
+ maintainAspectRatio: false,
+ //String - A legend template
+ legendTemplate: "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>",
+ //String - A tooltip template
+ tooltipTemplate: "<%=value %> <%=label%> users"
+ };
+ //Create pie or douhnut chart
+ // You can switch between pie and douhnut using the method below.
+ pieChart.Doughnut(PieData, pieOptions);
+ //-----------------
+ //- END PIE CHART -
+ //-----------------
+
+ /* jVector Maps
+ * ------------
+ * Create a world map with markers
+ */
+ $('#world-map-markers').vectorMap({
+ map: 'world_mill_en',
+ normalizeFunction: 'polynomial',
+ hoverOpacity: 0.7,
+ hoverColor: false,
+ backgroundColor: 'transparent',
+ regionStyle: {
+ initial: {
+ fill: 'rgba(210, 214, 222, 1)',
+ "fill-opacity": 1,
+ stroke: 'none',
+ "stroke-width": 0,
+ "stroke-opacity": 1
+ },
+ hover: {
+ "fill-opacity": 0.7,
+ cursor: 'pointer'
+ },
+ selected: {
+ fill: 'yellow'
+ },
+ selectedHover: {
+ }
+ },
+ markerStyle: {
+ initial: {
+ fill: '#00a65a',
+ stroke: '#111'
+ }
+ },
+ markers: [
+ {latLng: [41.90, 12.45], name: 'Vatican City'},
+ {latLng: [43.73, 7.41], name: 'Monaco'},
+ {latLng: [-0.52, 166.93], name: 'Nauru'},
+ {latLng: [-8.51, 179.21], name: 'Tuvalu'},
+ {latLng: [43.93, 12.46], name: 'San Marino'},
+ {latLng: [47.14, 9.52], name: 'Liechtenstein'},
+ {latLng: [7.11, 171.06], name: 'Marshall Islands'},
+ {latLng: [17.3, -62.73], name: 'Saint Kitts and Nevis'},
+ {latLng: [3.2, 73.22], name: 'Maldives'},
+ {latLng: [35.88, 14.5], name: 'Malta'},
+ {latLng: [12.05, -61.75], name: 'Grenada'},
+ {latLng: [13.16, -61.23], name: 'Saint Vincent and the Grenadines'},
+ {latLng: [13.16, -59.55], name: 'Barbados'},
+ {latLng: [17.11, -61.85], name: 'Antigua and Barbuda'},
+ {latLng: [-4.61, 55.45], name: 'Seychelles'},
+ {latLng: [7.35, 134.46], name: 'Palau'},
+ {latLng: [42.5, 1.51], name: 'Andorra'},
+ {latLng: [14.01, -60.98], name: 'Saint Lucia'},
+ {latLng: [6.91, 158.18], name: 'Federated States of Micronesia'},
+ {latLng: [1.3, 103.8], name: 'Singapore'},
+ {latLng: [1.46, 173.03], name: 'Kiribati'},
+ {latLng: [-21.13, -175.2], name: 'Tonga'},
+ {latLng: [15.3, -61.38], name: 'Dominica'},
+ {latLng: [-20.2, 57.5], name: 'Mauritius'},
+ {latLng: [26.02, 50.55], name: 'Bahrain'},
+ {latLng: [0.33, 6.73], name: 'São Tomé and Príncipe'}
+ ]
+ });
+
+ /* SPARKLINE CHARTS
+ * ----------------
+ * Create a inline charts with spark line
+ */
+
+ //-----------------
+ //- SPARKLINE BAR -
+ //-----------------
+ $('.sparkbar').each(function () {
+ var $this = $(this);
+ $this.sparkline('html', {
+ type: 'bar',
+ height: $this.data('height') ? $this.data('height') : '30',
+ barColor: $this.data('color')
+ });
+ });
+
+ //-----------------
+ //- SPARKLINE PIE -
+ //-----------------
+ $('.sparkpie').each(function () {
+ var $this = $(this);
+ $this.sparkline('html', {
+ type: 'pie',
+ height: $this.data('height') ? $this.data('height') : '90',
+ sliceColors: $this.data('color')
+ });
+ });
+
+ //------------------
+ //- SPARKLINE LINE -
+ //------------------
+ $('.sparkline').each(function () {
+ var $this = $(this);
+ $this.sparkline('html', {
+ type: 'line',
+ height: $this.data('height') ? $this.data('height') : '90',
+ width: '100%',
+ lineColor: $this.data('linecolor'),
+ fillColor: $this.data('fillcolor'),
+ spotColor: $this.data('spotcolor')
+ });
+ });
+});
--- /dev/null
+/*!
+ * Chart.js
+ * http://chartjs.org/
+ * Version: 1.0.2
+ *
+ * Copyright 2015 Nick Downie
+ * Released under the MIT license
+ * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
+ */
+(function(){"use strict";var t=this,i=t.Chart,e=function(t){this.canvas=t.canvas,this.ctx=t;var i=function(t,i){return t["offset"+i]?t["offset"+i]:document.defaultView.getComputedStyle(t).getPropertyValue(i)},e=this.width=i(t.canvas,"Width"),n=this.height=i(t.canvas,"Height");t.canvas.width=e,t.canvas.height=n;var e=this.width=t.canvas.width,n=this.height=t.canvas.height;return this.aspectRatio=this.width/this.height,s.retinaScale(this),this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= value %>",multiTooltipKeyBackground:"#fff",onAnimationProgress:function(){},onAnimationComplete:function(){}}},e.types={};var s=e.helpers={},n=s.each=function(t,i,e){var s=Array.prototype.slice.call(arguments,3);if(t)if(t.length===+t.length){var n;for(n=0;n<t.length;n++)i.apply(e,[t[n],n].concat(s))}else for(var o in t)i.apply(e,[t[o],o].concat(s))},o=s.clone=function(t){var i={};return n(t,function(e,s){t.hasOwnProperty(s)&&(i[s]=e)}),i},a=s.extend=function(t){return n(Array.prototype.slice.call(arguments,1),function(i){n(i,function(e,s){i.hasOwnProperty(s)&&(t[s]=e)})}),t},h=s.merge=function(){var t=Array.prototype.slice.call(arguments,0);return t.unshift({}),a.apply(null,t)},l=s.indexOf=function(t,i){if(Array.prototype.indexOf)return t.indexOf(i);for(var e=0;e<t.length;e++)if(t[e]===i)return e;return-1},r=(s.where=function(t,i){var e=[];return s.each(t,function(t){i(t)&&e.push(t)}),e},s.findNextWhere=function(t,i,e){e||(e=-1);for(var s=e+1;s<t.length;s++){var n=t[s];if(i(n))return n}},s.findPreviousWhere=function(t,i,e){e||(e=t.length);for(var s=e-1;s>=0;s--){var n=t[s];if(i(n))return n}},s.inherits=function(t){var i=this,e=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return i.apply(this,arguments)},s=function(){this.constructor=e};return s.prototype=i.prototype,e.prototype=new s,e.extend=r,t&&a(e.prototype,t),e.__super__=i.prototype,e}),c=s.noop=function(){},u=s.uid=function(){var t=0;return function(){return"chart-"+t++}}(),d=s.warn=function(t){window.console&&"function"==typeof window.console.warn&&console.warn(t)},p=s.amd="function"==typeof define&&define.amd,f=s.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},g=s.max=function(t){return Math.max.apply(Math,t)},m=s.min=function(t){return Math.min.apply(Math,t)},v=(s.cap=function(t,i,e){if(f(i)){if(t>i)return i}else if(f(e)&&e>t)return e;return t},s.getDecimalPlaces=function(t){return t%1!==0&&f(t)?t.toString().split(".")[1].length:0}),S=s.radians=function(t){return t*(Math.PI/180)},x=(s.getAngleFromPoint=function(t,i){var e=i.x-t.x,s=i.y-t.y,n=Math.sqrt(e*e+s*s),o=2*Math.PI+Math.atan2(s,e);return 0>e&&0>s&&(o+=2*Math.PI),{angle:o,distance:n}},s.aliasPixel=function(t){return t%2===0?0:.5}),y=(s.splineCurve=function(t,i,e,s){var n=Math.sqrt(Math.pow(i.x-t.x,2)+Math.pow(i.y-t.y,2)),o=Math.sqrt(Math.pow(e.x-i.x,2)+Math.pow(e.y-i.y,2)),a=s*n/(n+o),h=s*o/(n+o);return{inner:{x:i.x-a*(e.x-t.x),y:i.y-a*(e.y-t.y)},outer:{x:i.x+h*(e.x-t.x),y:i.y+h*(e.y-t.y)}}},s.calculateOrderOfMagnitude=function(t){return Math.floor(Math.log(t)/Math.LN10)}),C=(s.calculateScaleRange=function(t,i,e,s,n){var o=2,a=Math.floor(i/(1.5*e)),h=o>=a,l=g(t),r=m(t);l===r&&(l+=.5,r>=.5&&!s?r-=.5:l+=.5);for(var c=Math.abs(l-r),u=y(c),d=Math.ceil(l/(1*Math.pow(10,u)))*Math.pow(10,u),p=s?0:Math.floor(r/(1*Math.pow(10,u)))*Math.pow(10,u),f=d-p,v=Math.pow(10,u),S=Math.round(f/v);(S>a||a>2*S)&&!h;)if(S>a)v*=2,S=Math.round(f/v),S%1!==0&&(h=!0);else if(n&&u>=0){if(v/2%1!==0)break;v/=2,S=Math.round(f/v)}else v/=2,S=Math.round(f/v);return h&&(S=o,v=f/S),{steps:S,stepValue:v,min:p,max:p+S*v}},s.template=function(t,i){function e(t,i){var e=/\W/.test(t)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+t.replace(/[\r\t\n]/g," ").split("<%").join(" ").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split(" ").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):s[t]=s[t];return i?e(i):e}if(t instanceof Function)return t(i);var s={};return e(t,i)}),w=(s.generateLabels=function(t,i,e,s){var o=new Array(i);return labelTemplateString&&n(o,function(i,n){o[n]=C(t,{value:e+s*(n+1)})}),o},s.easingEffects={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-1*t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-0.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return 1*((t=t/1-1)*t*t+1)},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-1*((t=t/1-1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-0.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return 1*(t/=1)*t*t*t*t},easeOutQuint:function(t){return 1*((t=t/1-1)*t*t*t*t+1)},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return-1*Math.cos(t/1*(Math.PI/2))+1},easeOutSine:function(t){return 1*Math.sin(t/1*(Math.PI/2))},easeInOutSine:function(t){return-0.5*(Math.cos(Math.PI*t/1)-1)},easeInExpo:function(t){return 0===t?1:1*Math.pow(2,10*(t/1-1))},easeOutExpo:function(t){return 1===t?1:1*(-Math.pow(2,-10*t/1)+1)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(-Math.pow(2,-10*--t)+2)},easeInCirc:function(t){return t>=1?t:-1*(Math.sqrt(1-(t/=1)*t)-1)},easeOutCirc:function(t){return 1*Math.sqrt(1-(t=t/1-1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-0.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),-(s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)))},easeOutElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:1==(t/=1)?1:(e||(e=.3),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),s*Math.pow(2,-10*t)*Math.sin(2*(1*t-i)*Math.PI/e)+1)},easeInOutElastic:function(t){var i=1.70158,e=0,s=1;return 0===t?0:2==(t/=.5)?1:(e||(e=.3*1.5),s<Math.abs(1)?(s=1,i=e/4):i=e/(2*Math.PI)*Math.asin(1/s),1>t?-.5*s*Math.pow(2,10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e):s*Math.pow(2,-10*(t-=1))*Math.sin(2*(1*t-i)*Math.PI/e)*.5+1)},easeInBack:function(t){var i=1.70158;return 1*(t/=1)*t*((i+1)*t-i)},easeOutBack:function(t){var i=1.70158;return 1*((t=t/1-1)*t*((i+1)*t+i)+1)},easeInOutBack:function(t){var i=1.70158;return(t/=.5)<1?.5*t*t*(((i*=1.525)+1)*t-i):.5*((t-=2)*t*(((i*=1.525)+1)*t+i)+2)},easeInBounce:function(t){return 1-w.easeOutBounce(1-t)},easeOutBounce:function(t){return(t/=1)<1/2.75?7.5625*t*t:2/2.75>t?1*(7.5625*(t-=1.5/2.75)*t+.75):2.5/2.75>t?1*(7.5625*(t-=2.25/2.75)*t+.9375):1*(7.5625*(t-=2.625/2.75)*t+.984375)},easeInOutBounce:function(t){return.5>t?.5*w.easeInBounce(2*t):.5*w.easeOutBounce(2*t-1)+.5}}),b=s.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)}}(),P=s.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(t){return window.clearTimeout(t,1e3/60)}}(),L=(s.animationLoop=function(t,i,e,s,n,o){var a=0,h=w[e]||w.linear,l=function(){a++;var e=a/i,r=h(e);t.call(o,r,e,a),s.call(o,r,e),i>a?o.animationFrame=b(l):n.apply(o)};b(l)},s.getRelativePosition=function(t){var i,e,s=t.originalEvent||t,n=t.currentTarget||t.srcElement,o=n.getBoundingClientRect();return s.touches?(i=s.touches[0].clientX-o.left,e=s.touches[0].clientY-o.top):(i=s.clientX-o.left,e=s.clientY-o.top),{x:i,y:e}},s.addEvent=function(t,i,e){t.addEventListener?t.addEventListener(i,e):t.attachEvent?t.attachEvent("on"+i,e):t["on"+i]=e}),k=s.removeEvent=function(t,i,e){t.removeEventListener?t.removeEventListener(i,e,!1):t.detachEvent?t.detachEvent("on"+i,e):t["on"+i]=c},F=(s.bindEvents=function(t,i,e){t.events||(t.events={}),n(i,function(i){t.events[i]=function(){e.apply(t,arguments)},L(t.chart.canvas,i,t.events[i])})},s.unbindEvents=function(t,i){n(i,function(i,e){k(t.chart.canvas,e,i)})}),R=s.getMaximumWidth=function(t){var i=t.parentNode;return i.clientWidth},T=s.getMaximumHeight=function(t){var i=t.parentNode;return i.clientHeight},A=(s.getMaximumSize=s.getMaximumWidth,s.retinaScale=function(t){var i=t.ctx,e=t.canvas.width,s=t.canvas.height;window.devicePixelRatio&&(i.canvas.style.width=e+"px",i.canvas.style.height=s+"px",i.canvas.height=s*window.devicePixelRatio,i.canvas.width=e*window.devicePixelRatio,i.scale(window.devicePixelRatio,window.devicePixelRatio))}),M=s.clear=function(t){t.ctx.clearRect(0,0,t.width,t.height)},W=s.fontString=function(t,i,e){return i+" "+t+"px "+e},z=s.longestText=function(t,i,e){t.font=i;var s=0;return n(e,function(i){var e=t.measureText(i).width;s=e>s?e:s}),s},B=s.drawRoundedRectangle=function(t,i,e,s,n,o){t.beginPath(),t.moveTo(i+o,e),t.lineTo(i+s-o,e),t.quadraticCurveTo(i+s,e,i+s,e+o),t.lineTo(i+s,e+n-o),t.quadraticCurveTo(i+s,e+n,i+s-o,e+n),t.lineTo(i+o,e+n),t.quadraticCurveTo(i,e+n,i,e+n-o),t.lineTo(i,e+o),t.quadraticCurveTo(i,e,i+o,e),t.closePath()};e.instances={},e.Type=function(t,i,s){this.options=i,this.chart=s,this.id=u(),e.instances[this.id]=this,i.responsive&&this.resize(),this.initialize.call(this,t)},a(e.Type.prototype,{initialize:function(){return this},clear:function(){return M(this.chart),this},stop:function(){return P(this.animationFrame),this},resize:function(t){this.stop();var i=this.chart.canvas,e=R(this.chart.canvas),s=this.options.maintainAspectRatio?e/this.chart.aspectRatio:T(this.chart.canvas);return i.width=this.chart.width=e,i.height=this.chart.height=s,A(this.chart),"function"==typeof t&&t.apply(this,Array.prototype.slice.call(arguments,1)),this},reflow:c,render:function(t){return t&&this.reflow(),this.options.animation&&!t?s.animationLoop(this.draw,this.options.animationSteps,this.options.animationEasing,this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this.draw(),this.options.onAnimationComplete.call(this)),this},generateLegend:function(){return C(this.options.legendTemplate,this)},destroy:function(){this.clear(),F(this,this.events);var t=this.chart.canvas;t.width=this.chart.width,t.height=this.chart.height,t.style.removeProperty?(t.style.removeProperty("width"),t.style.removeProperty("height")):(t.style.removeAttribute("width"),t.style.removeAttribute("height")),delete e.instances[this.id]},showTooltip:function(t,i){"undefined"==typeof this.activeElements&&(this.activeElements=[]);var o=function(t){var i=!1;return t.length!==this.activeElements.length?i=!0:(n(t,function(t,e){t!==this.activeElements[e]&&(i=!0)},this),i)}.call(this,t);if(o||i){if(this.activeElements=t,this.draw(),this.options.customTooltips&&this.options.customTooltips(!1),t.length>0)if(this.datasets&&this.datasets.length>1){for(var a,h,r=this.datasets.length-1;r>=0&&(a=this.datasets[r].points||this.datasets[r].bars||this.datasets[r].segments,h=l(a,t[0]),-1===h);r--);var c=[],u=[],d=function(){var t,i,e,n,o,a=[],l=[],r=[];return s.each(this.datasets,function(i){t=i.points||i.bars||i.segments,t[h]&&t[h].hasValue()&&a.push(t[h])}),s.each(a,function(t){l.push(t.x),r.push(t.y),c.push(s.template(this.options.multiTooltipTemplate,t)),u.push({fill:t._saved.fillColor||t.fillColor,stroke:t._saved.strokeColor||t.strokeColor})},this),o=m(r),e=g(r),n=m(l),i=g(l),{x:n>this.chart.width/2?n:i,y:(o+e)/2}}.call(this,h);new e.MultiTooltip({x:d.x,y:d.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:c,legendColors:u,legendColorBackground:this.options.multiTooltipKeyBackground,title:t[0].label,chart:this.chart,ctx:this.chart.ctx,custom:this.options.customTooltips}).draw()}else n(t,function(t){var i=t.tooltipPosition();new e.Tooltip({x:Math.round(i.x),y:Math.round(i.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,text:C(this.options.tooltipTemplate,t),chart:this.chart,custom:this.options.customTooltips}).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}}),e.Type.extend=function(t){var i=this,s=function(){return i.apply(this,arguments)};if(s.prototype=o(i.prototype),a(s.prototype,t),s.extend=e.Type.extend,t.name||i.prototype.name){var n=t.name||i.prototype.name,l=e.defaults[i.prototype.name]?o(e.defaults[i.prototype.name]):{};e.defaults[n]=a(l,t.defaults),e.types[n]=s,e.prototype[n]=function(t,i){var o=h(e.defaults.global,e.defaults[n],i||{});return new s(t,o,this)}}else d("Name not provided for this chart, so it hasn't been registered");return i},e.Element=function(t){a(this,t),this.initialize.apply(this,arguments),this.save()},a(e.Element.prototype,{initialize:function(){},restore:function(t){return t?n(t,function(t){this[t]=this._saved[t]},this):a(this,this._saved),this},save:function(){return this._saved=o(this),delete this._saved._saved,this},update:function(t){return n(t,function(t,i){this._saved[i]=this[i],this[i]=t},this),this},transition:function(t,i){return n(t,function(t,e){this[e]=(t-this._saved[e])*i+this._saved[e]},this),this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return f(this.value)}}),e.Element.extend=r,e.Point=e.Element.extend({display:!0,inRange:function(t,i){var e=this.hitDetectionRadius+this.radius;return Math.pow(t-this.x,2)+Math.pow(i-this.y,2)<Math.pow(e,2)},draw:function(){if(this.display){var t=this.ctx;t.beginPath(),t.arc(this.x,this.y,this.radius,0,2*Math.PI),t.closePath(),t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.fillStyle=this.fillColor,t.fill(),t.stroke()}}}),e.Arc=e.Element.extend({inRange:function(t,i){var e=s.getAngleFromPoint(this,{x:t,y:i}),n=e.angle>=this.startAngle&&e.angle<=this.endAngle,o=e.distance>=this.innerRadius&&e.distance<=this.outerRadius;return n&&o},tooltipPosition:function(){var t=this.startAngle+(this.endAngle-this.startAngle)/2,i=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(t)*i,y:this.y+Math.sin(t)*i}},draw:function(t){var i=this.ctx;i.beginPath(),i.arc(this.x,this.y,this.outerRadius,this.startAngle,this.endAngle),i.arc(this.x,this.y,this.innerRadius,this.endAngle,this.startAngle,!0),i.closePath(),i.strokeStyle=this.strokeColor,i.lineWidth=this.strokeWidth,i.fillStyle=this.fillColor,i.fill(),i.lineJoin="bevel",this.showStroke&&i.stroke()}}),e.Rectangle=e.Element.extend({draw:function(){var t=this.ctx,i=this.width/2,e=this.x-i,s=this.x+i,n=this.base-(this.base-this.y),o=this.strokeWidth/2;this.showStroke&&(e+=o,s-=o,n+=o),t.beginPath(),t.fillStyle=this.fillColor,t.strokeStyle=this.strokeColor,t.lineWidth=this.strokeWidth,t.moveTo(e,this.base),t.lineTo(e,n),t.lineTo(s,n),t.lineTo(s,this.base),t.fill(),this.showStroke&&t.stroke()},height:function(){return this.base-this.y},inRange:function(t,i){return t>=this.x-this.width/2&&t<=this.x+this.width/2&&i>=this.y&&i<=this.base}}),e.Tooltip=e.Element.extend({draw:function(){var t=this.chart.ctx;t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.xAlign="center",this.yAlign="above";var i=this.caretPadding=2,e=t.measureText(this.text).width+2*this.xPadding,s=this.fontSize+2*this.yPadding,n=s+this.caretHeight+i;this.x+e/2>this.chart.width?this.xAlign="left":this.x-e/2<0&&(this.xAlign="right"),this.y-n<0&&(this.yAlign="below");var o=this.x-e/2,a=this.y-n;if(t.fillStyle=this.fillColor,this.custom)this.custom(this);else{switch(this.yAlign){case"above":t.beginPath(),t.moveTo(this.x,this.y-i),t.lineTo(this.x+this.caretHeight,this.y-(i+this.caretHeight)),t.lineTo(this.x-this.caretHeight,this.y-(i+this.caretHeight)),t.closePath(),t.fill();break;case"below":a=this.y+i+this.caretHeight,t.beginPath(),t.moveTo(this.x,this.y+i),t.lineTo(this.x+this.caretHeight,this.y+i+this.caretHeight),t.lineTo(this.x-this.caretHeight,this.y+i+this.caretHeight),t.closePath(),t.fill()}switch(this.xAlign){case"left":o=this.x-e+(this.cornerRadius+this.caretHeight);break;case"right":o=this.x-(this.cornerRadius+this.caretHeight)}B(t,o,a,e,s,this.cornerRadius),t.fill(),t.fillStyle=this.textColor,t.textAlign="center",t.textBaseline="middle",t.fillText(this.text,o+e/2,a+s/2)}}}),e.MultiTooltip=e.Element.extend({initialize:function(){this.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.titleFont=W(this.titleFontSize,this.titleFontStyle,this.titleFontFamily),this.height=this.labels.length*this.fontSize+(this.labels.length-1)*(this.fontSize/2)+2*this.yPadding+1.5*this.titleFontSize,this.ctx.font=this.titleFont;var t=this.ctx.measureText(this.title).width,i=z(this.ctx,this.font,this.labels)+this.fontSize+3,e=g([i,t]);this.width=e+2*this.xPadding;var s=this.height/2;this.y-s<0?this.y=s:this.y+s>this.chart.height&&(this.y=this.chart.height-s),this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this.xOffset},getLineHeight:function(t){var i=this.y-this.height/2+this.yPadding,e=t-1;return 0===t?i+this.titleFontSize/2:i+(1.5*this.fontSize*e+this.fontSize/2)+1.5*this.titleFontSize},draw:function(){if(this.custom)this.custom(this);else{B(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var t=this.ctx;t.fillStyle=this.fillColor,t.fill(),t.closePath(),t.textAlign="left",t.textBaseline="middle",t.fillStyle=this.titleTextColor,t.font=this.titleFont,t.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0)),t.font=this.font,s.each(this.labels,function(i,e){t.fillStyle=this.textColor,t.fillText(i,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(e+1)),t.fillStyle=this.legendColorBackground,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize),t.fillStyle=this.legendColors[e].fill,t.fillRect(this.x+this.xPadding,this.getLineHeight(e+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}}),e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}));this.yLabelWidth=this.display&&this.showLabels?z(this.ctx,this.font,this.yLabels):0},addXLabel:function(t){this.xLabels.push(t),this.valuesCount++,this.fit()},removeXLabel:function(){this.xLabels.shift(),this.valuesCount--,this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0,this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height,this.startPoint+=this.padding,this.endPoint-=this.padding;var t,i=this.endPoint-this.startPoint;for(this.calculateYRange(i),this.buildYLabels(),this.calculateXLabelRotation();i>this.endPoint-this.startPoint;)i=this.endPoint-this.startPoint,t=this.yLabelWidth,this.calculateYRange(i),this.buildYLabels(),t<this.yLabelWidth&&this.calculateXLabelRotation()},calculateXLabelRotation:function(){this.ctx.font=this.font;var t,i,e=this.ctx.measureText(this.xLabels[0]).width,s=this.ctx.measureText(this.xLabels[this.xLabels.length-1]).width;if(this.xScalePaddingRight=s/2+3,this.xScalePaddingLeft=e/2>this.yLabelWidth+10?e/2:this.yLabelWidth+10,this.xLabelRotation=0,this.display){var n,o=z(this.ctx,this.font,this.xLabels);this.xLabelWidth=o;for(var a=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>a&&0===this.xLabelRotation||this.xLabelWidth>a&&this.xLabelRotation<=90&&this.xLabelRotation>0;)n=Math.cos(S(this.xLabelRotation)),t=n*e,i=n*s,t+this.fontSize/2>this.yLabelWidth+8&&(this.xScalePaddingLeft=t+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=n*o;this.xLabelRotation>0&&(this.endPoint-=Math.sin(S(this.xLabelRotation))*o+3)}else this.xLabelWidth=0,this.xScalePaddingRight=this.padding,this.xScalePaddingLeft=this.padding},calculateYRange:c,drawingArea:function(){return this.startPoint-this.endPoint},calculateY:function(t){var i=this.drawingArea()/(this.min-this.max);return this.endPoint-i*(t-this.min)},calculateX:function(t){var i=(this.xLabelRotation>0,this.width-(this.xScalePaddingLeft+this.xScalePaddingRight)),e=i/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1),s=e*t+this.xScalePaddingLeft;return this.offsetGridLines&&(s+=e/2),Math.round(s)},update:function(t){s.extend(this,t),this.fit()},draw:function(){var t=this.ctx,i=(this.endPoint-this.startPoint)/this.steps,e=Math.round(this.xScalePaddingLeft);this.display&&(t.fillStyle=this.textColor,t.font=this.font,n(this.yLabels,function(n,o){var a=this.endPoint-i*o,h=Math.round(a),l=this.showHorizontalLines;t.textAlign="right",t.textBaseline="middle",this.showLabels&&t.fillText(n,e-10,a),0!==o||l||(l=!0),l&&t.beginPath(),o>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),h+=s.aliasPixel(t.lineWidth),l&&(t.moveTo(e,h),t.lineTo(this.width,h),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(e-5,h),t.lineTo(e,h),t.stroke(),t.closePath()},this),n(this.xLabels,function(i,e){var s=this.calculateX(e)+x(this.lineWidth),n=this.calculateX(e-(this.offsetGridLines?.5:0))+x(this.lineWidth),o=this.xLabelRotation>0,a=this.showVerticalLines;0!==e||a||(a=!0),a&&t.beginPath(),e>0?(t.lineWidth=this.gridLineWidth,t.strokeStyle=this.gridLineColor):(t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor),a&&(t.moveTo(n,this.endPoint),t.lineTo(n,this.startPoint-3),t.stroke(),t.closePath()),t.lineWidth=this.lineWidth,t.strokeStyle=this.lineColor,t.beginPath(),t.moveTo(n,this.endPoint),t.lineTo(n,this.endPoint+5),t.stroke(),t.closePath(),t.save(),t.translate(s,o?this.endPoint+12:this.endPoint+8),t.rotate(-1*S(this.xLabelRotation)),t.font=this.font,t.textAlign=o?"right":"center",t.textBaseline=o?"middle":"top",t.fillText(i,0,0),t.restore()},this))}}),e.RadialScale=e.Element.extend({initialize:function(){this.size=m([this.height,this.width]),this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(t){var i=this.drawingArea/(this.max-this.min);return(t-this.min)*i},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize(),this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var t=v(this.stepValue),i=0;i<=this.steps;i++)this.yLabels.push(C(this.templateString,{value:(this.min+i*this.stepValue).toFixed(t)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var t,i,e,s,n,o,a,h,l,r,c,u,d=m([this.height/2-this.pointLabelFontSize-5,this.width/2]),p=this.width,g=0;for(this.ctx.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),i=0;i<this.valuesCount;i++)t=this.getPointPosition(i,d),e=this.ctx.measureText(C(this.templateString,{value:this.labels[i]})).width+5,0===i||i===this.valuesCount/2?(s=e/2,t.x+s>p&&(p=t.x+s,n=i),t.x-s<g&&(g=t.x-s,a=i)):i<this.valuesCount/2?t.x+e>p&&(p=t.x+e,n=i):i>this.valuesCount/2&&t.x-e<g&&(g=t.x-e,a=i);l=g,r=Math.ceil(p-this.width),o=this.getIndexAngle(n),h=this.getIndexAngle(a),c=r/Math.sin(o+Math.PI/2),u=l/Math.sin(h+Math.PI/2),c=f(c)?c:0,u=f(u)?u:0,this.drawingArea=d-(u+c)/2,this.setCenterPoint(u,c)},setCenterPoint:function(t,i){var e=this.width-i-this.drawingArea,s=t+this.drawingArea;this.xCenter=(s+e)/2,this.yCenter=this.height/2},getIndexAngle:function(t){var i=2*Math.PI/this.valuesCount;return t*i-Math.PI/2},getPointPosition:function(t,i){var e=this.getIndexAngle(t);return{x:Math.cos(e)*i+this.xCenter,y:Math.sin(e)*i+this.yCenter}},draw:function(){if(this.display){var t=this.ctx;if(n(this.yLabels,function(i,e){if(e>0){var s,n=e*(this.drawingArea/this.steps),o=this.yCenter-n;if(this.lineWidth>0)if(t.strokeStyle=this.lineColor,t.lineWidth=this.lineWidth,this.lineArc)t.beginPath(),t.arc(this.xCenter,this.yCenter,n,0,2*Math.PI),t.closePath(),t.stroke();else{t.beginPath();for(var a=0;a<this.valuesCount;a++)s=this.getPointPosition(a,this.calculateCenterOffset(this.min+e*this.stepValue)),0===a?t.moveTo(s.x,s.y):t.lineTo(s.x,s.y);t.closePath(),t.stroke()}if(this.showLabels){if(t.font=W(this.fontSize,this.fontStyle,this.fontFamily),this.showLabelBackdrop){var h=t.measureText(i).width;t.fillStyle=this.backdropColor,t.fillRect(this.xCenter-h/2-this.backdropPaddingX,o-this.fontSize/2-this.backdropPaddingY,h+2*this.backdropPaddingX,this.fontSize+2*this.backdropPaddingY)}t.textAlign="center",t.textBaseline="middle",t.fillStyle=this.fontColor,t.fillText(i,this.xCenter,o)}}},this),!this.lineArc){t.lineWidth=this.angleLineWidth,t.strokeStyle=this.angleLineColor;for(var i=this.valuesCount-1;i>=0;i--){if(this.angleLineWidth>0){var e=this.getPointPosition(i,this.calculateCenterOffset(this.max));t.beginPath(),t.moveTo(this.xCenter,this.yCenter),t.lineTo(e.x,e.y),t.stroke(),t.closePath()}var s=this.getPointPosition(i,this.calculateCenterOffset(this.max)+5);t.font=W(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily),t.fillStyle=this.pointLabelFontColor;var o=this.labels.length,a=this.labels.length/2,h=a/2,l=h>i||i>o-h,r=i===h||i===o-h;t.textAlign=0===i?"center":i===a?"center":a>i?"left":"right",t.textBaseline=r?"middle":l?"bottom":"top",t.fillText(this.labels[i],s.x,s.y)}}}}}),s.addEvent(window,"resize",function(){var t;return function(){clearTimeout(t),t=setTimeout(function(){n(e.instances,function(t){t.options.responsive&&t.resize(t.render,!0)})},50)}}()),p?define(function(){return e}):"object"==typeof module&&module.exports&&(module.exports=e),t.Chart=e,e.noConflict=function(){return t.Chart=i,e}}).call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleBeginAtZero:!0,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5,barDatasetSpacing:1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].fillColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"Bar",defaults:s,initialize:function(t){var s=this.options;this.ScaleClass=i.Scale.extend({offsetGridLines:!0,calculateBarX:function(t,i,e){var n=this.calculateBaseWidth(),o=this.calculateX(e)-n/2,a=this.calculateBarWidth(t);return o+a*i+i*s.barDatasetSpacing+a/2},calculateBaseWidth:function(){return this.calculateX(1)-this.calculateX(0)-2*s.barValueSpacing},calculateBarWidth:function(t){var i=this.calculateBaseWidth()-(t-1)*s.barDatasetSpacing;return i/t}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getBarsAtEvent(t):[];this.eachBars(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),this.BarClass=i.Rectangle.extend({strokeWidth:this.options.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,bars:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.bars.push(new this.BarClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.strokeColor,fillColor:i.fillColor,highlightFill:i.highlightFill||i.fillColor,highlightStroke:i.highlightStroke||i.strokeColor}))},this)},this),this.buildScale(t.labels),this.BarClass.prototype.base=this.scale.endPoint,this.eachBars(function(t,i,s){e.extend(t,{width:this.scale.calculateBarWidth(this.datasets.length),x:this.scale.calculateBarX(this.datasets.length,s,i),y:this.scale.endPoint}),t.save()},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachBars(function(t){t.save()}),this.render()},eachBars:function(t){e.each(this.datasets,function(i,s){e.each(i.bars,t,this,s)},this)},getBarsAtEvent:function(t){for(var i,s=[],n=e.getRelativePosition(t),o=function(t){s.push(t.bars[i])},a=0;a<this.datasets.length;a++)for(i=0;i<this.datasets[a].bars.length;i++)if(this.datasets[a].bars[i].inRange(n.x,n.y))return e.each(this.datasets,o),s;return s},buildScale:function(t){var i=this,s=function(){var t=[];return i.eachBars(function(i){t.push(i.value)}),t},n={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var i=e.calculateScaleRange(s(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,i)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.barShowStroke?this.options.barStrokeWidth:0,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(n,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new this.ScaleClass(n)},addData:function(t,i){e.each(t,function(t,e){this.datasets[e].bars.push(new this.BarClass({value:t,label:i,x:this.scale.calculateBarX(this.datasets.length,e,this.scale.valuesCount+1),y:this.scale.endPoint,width:this.scale.calculateBarWidth(this.datasets.length),base:this.scale.endPoint,strokeColor:this.datasets[e].strokeColor,fillColor:this.datasets[e].fillColor}))
+},this),this.scale.addXLabel(i),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.bars.shift()},this),this.update()},reflow:function(){e.extend(this.BarClass.prototype,{y:this.scale.endPoint,base:this.scale.endPoint});var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var i=t||1;this.clear();this.chart.ctx;this.scale.draw(i),e.each(this.datasets,function(t,s){e.each(t.bars,function(t,e){t.hasValue()&&(t.base=this.scale.endPoint,t.transition({x:this.scale.calculateBarX(this.datasets.length,s,e),y:this.scale.calculateY(t.value),width:this.scale.calculateBarWidth(this.datasets.length)},i).draw())},this)},this)}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"Doughnut",defaults:s,initialize:function(t){this.segments=[],this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,this.SegmentArc=i.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2}),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.calculateTotal(t),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({value:t.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:t.color,highlightColor:t.highlight||t.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?0:this.calculateCircumference(t.value),label:t.label})),e||(this.reflow(),this.update())},calculateCircumference:function(t){return 2*Math.PI*(Math.abs(t)/this.total)},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=Math.abs(t.value)},this)},update:function(){this.calculateTotal(this.segments),e.each(this.activeElements,function(t){t.restore(["fillColor"])}),e.each(this.segments,function(t){t.save()}),this.render()},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.outerRadius=(e.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2,e.each(this.segments,function(t){t.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(t){var i=t?t:1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.calculateCircumference(t.value),outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},i),t.endAngle=t.startAngle+t.circumference,t.draw(),0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle)},this)}}),i.types.Doughnut.extend({name:"Pie",defaults:e.merge(s,{percentageInnerCutout:0})})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,scaleShowHorizontalLines:!0,scaleShowVerticalLines:!0,bezierCurve:!0,bezierCurveTension:.4,pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].strokeColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"Line",defaults:s,initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(t){return Math.pow(t-this.x,2)<Math.pow(this.radius+this.hitDetectionRadius,2)}}),this.datasets=[],this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this),this.buildScale(t.labels),this.eachPoints(function(t,i){e.extend(t,{x:this.scale.calculateX(i),y:this.scale.endPoint}),t.save()},this)},this),this.render()},update:function(){this.scale.update(),e.each(this.activeElements,function(t){t.restore(["fillColor","strokeColor"])}),this.eachPoints(function(t){t.save()}),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.datasets,function(t){e.each(t.points,function(t){t.inRange(s.x,s.y)&&i.push(t)})},this),i},buildScale:function(t){var s=this,n=function(){var t=[];return s.eachPoints(function(i){t.push(i.value)}),t},o={templateString:this.options.scaleLabel,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:t.length,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(t){var i=e.calculateScaleRange(n(),t,this.fontSize,this.beginAtZero,this.integersOnly);e.extend(this,i)},xLabels:t,font:e.fontString(this.options.scaleFontSize,this.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options.scaleLineColor,showHorizontalLines:this.options.scaleShowHorizontalLines,showVerticalLines:this.options.scaleShowVerticalLines,gridLineWidth:this.options.scaleShowGridLines?this.options.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?0:this.options.pointDotRadius+this.options.pointDotStrokeWidth,showLabels:this.options.scaleShowLabels,display:this.options.showScale};this.options.scaleOverride&&e.extend(o,{calculateYRange:e.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}),this.scale=new i.Scale(o)},addData:function(t,i){e.each(t,function(t,e){this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:this.scale.calculateX(this.scale.valuesCount+1),y:this.scale.endPoint,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.addXLabel(i),this.update()},removeData:function(){this.scale.removeXLabel(),e.each(this.datasets,function(t){t.points.shift()},this),this.update()},reflow:function(){var t=e.extend({height:this.chart.height,width:this.chart.width});this.scale.update(t)},draw:function(t){var i=t||1;this.clear();var s=this.chart.ctx,n=function(t){return null!==t.value},o=function(t,i,s){return e.findNextWhere(i,n,s)||t},a=function(t,i,s){return e.findPreviousWhere(i,n,s)||t};this.scale.draw(i),e.each(this.datasets,function(t){var h=e.where(t.points,n);e.each(t.points,function(t,e){t.hasValue()&&t.transition({y:this.scale.calculateY(t.value),x:this.scale.calculateX(e)},i)},this),this.options.bezierCurve&&e.each(h,function(t,i){var s=i>0&&i<h.length-1?this.options.bezierCurveTension:0;t.controlPoints=e.splineCurve(a(t,h,i),t,o(t,h,i),s),t.controlPoints.outer.y>this.scale.endPoint?t.controlPoints.outer.y=this.scale.endPoint:t.controlPoints.outer.y<this.scale.startPoint&&(t.controlPoints.outer.y=this.scale.startPoint),t.controlPoints.inner.y>this.scale.endPoint?t.controlPoints.inner.y=this.scale.endPoint:t.controlPoints.inner.y<this.scale.startPoint&&(t.controlPoints.inner.y=this.scale.startPoint)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(h,function(t,i){if(0===i)s.moveTo(t.x,t.y);else if(this.options.bezierCurve){var e=a(t,h,i);s.bezierCurveTo(e.controlPoints.outer.x,e.controlPoints.outer.y,t.controlPoints.inner.x,t.controlPoints.inner.y,t.x,t.y)}else s.lineTo(t.x,t.y)},this),s.stroke(),this.options.datasetFill&&h.length>0&&(s.lineTo(h[h.length-1].x,this.scale.endPoint),s.lineTo(h[0].x,this.scale.endPoint),s.fillStyle=t.fillColor,s.closePath(),s.fill()),e.each(h,function(t){t.draw()})},this)}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers,s={scaleShowLabelBackdrop:!0,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>'};i.Type.extend({name:"PolarArea",defaults:s,initialize:function(t){this.segments=[],this.SegmentArc=i.Arc.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2}),this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,valuesCount:t.length}),this.updateScaleRange(t),this.scale.update(),e.each(t,function(t,i){this.addData(t,i,!0)},this),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getSegmentsAtEvent(t):[];e.each(this.segments,function(t){t.restore(["fillColor"])}),e.each(i,function(t){t.fillColor=t.highlightColor}),this.showTooltip(i)}),this.render()},getSegmentsAtEvent:function(t){var i=[],s=e.getRelativePosition(t);return e.each(this.segments,function(t){t.inRange(s.x,s.y)&&i.push(t)},this),i},addData:function(t,i,e){var s=i||this.segments.length;this.segments.splice(s,0,new this.SegmentArc({fillColor:t.color,highlightColor:t.highlight||t.color,label:t.label,value:t.value,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(t.value),circumference:this.options.animateRotate?0:this.scale.getCircumference(),startAngle:1.5*Math.PI})),e||(this.reflow(),this.update())},removeData:function(t){var i=e.isNumber(t)?t:this.segments.length-1;this.segments.splice(i,1),this.reflow(),this.update()},calculateTotal:function(t){this.total=0,e.each(t,function(t){this.total+=t.value},this),this.scale.valuesCount=this.segments.length},updateScaleRange:function(t){var i=[];e.each(t,function(t){i.push(t.value)});var s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s,{size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2})},update:function(){this.calculateTotal(this.segments),e.each(this.segments,function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2}),this.updateScaleRange(this.segments),this.scale.update(),e.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2}),e.each(this.segments,function(t){t.update({outerRadius:this.scale.calculateCenterOffset(t.value)})},this)},draw:function(t){var i=t||1;this.clear(),e.each(this.segments,function(t,e){t.transition({circumference:this.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(t.value)},i),t.endAngle=t.startAngle+t.circumference,0===e&&(t.startAngle=1.5*Math.PI),e<this.segments.length-1&&(this.segments[e+1].startAngle=t.endAngle),t.draw()},this),this.scale.draw()}})}.call(this),function(){"use strict";var t=this,i=t.Chart,e=i.helpers;i.Type.extend({name:"Radar",defaults:{scaleShowLine:!0,angleShowLineOut:!0,scaleShowLabels:!1,scaleBeginAtZero:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal",pointLabelFontSize:10,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span style="background-color:<%=datasets[i].strokeColor%>"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>'},initialize:function(t){this.PointClass=i.Point.extend({strokeWidth:this.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius,ctx:this.chart.ctx}),this.datasets=[],this.buildScale(t),this.options.showTooltips&&e.bindEvents(this,this.options.tooltipEvents,function(t){var i="mouseout"!==t.type?this.getPointsAtEvent(t):[];this.eachPoints(function(t){t.restore(["fillColor","strokeColor"])}),e.each(i,function(t){t.fillColor=t.highlightFill,t.strokeColor=t.highlightStroke}),this.showTooltip(i)}),e.each(t.datasets,function(i){var s={label:i.label||null,fillColor:i.fillColor,strokeColor:i.strokeColor,pointColor:i.pointColor,pointStrokeColor:i.pointStrokeColor,points:[]};this.datasets.push(s),e.each(i.data,function(e,n){var o;this.scale.animation||(o=this.scale.getPointPosition(n,this.scale.calculateCenterOffset(e))),s.points.push(new this.PointClass({value:e,label:t.labels[n],datasetLabel:i.label,x:this.options.animation?this.scale.xCenter:o.x,y:this.options.animation?this.scale.yCenter:o.y,strokeColor:i.pointStrokeColor,fillColor:i.pointColor,highlightFill:i.pointHighlightFill||i.pointColor,highlightStroke:i.pointHighlightStroke||i.pointStrokeColor}))},this)},this),this.render()},eachPoints:function(t){e.each(this.datasets,function(i){e.each(i.points,t,this)},this)},getPointsAtEvent:function(t){var i=e.getRelativePosition(t),s=e.getAngleFromPoint({x:this.scale.xCenter,y:this.scale.yCenter},i),n=2*Math.PI/this.scale.valuesCount,o=Math.round((s.angle-1.5*Math.PI)/n),a=[];return(o>=this.scale.valuesCount||0>o)&&(o=0),s.distance<=this.scale.drawingArea&&e.each(this.datasets,function(t){a.push(t.points[o])}),a},buildScale:function(t){this.scale=new i.RadialScale({display:this.options.showScale,fontStyle:this.options.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,angleLineColor:this.options.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this.options.pointLabelFontFamily,pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:t.labels,valuesCount:t.datasets[0].data.length}),this.scale.setScaleSize(),this.updateScaleRange(t.datasets),this.scale.buildYLabels()},updateScaleRange:function(t){var i=function(){var i=[];return e.each(t,function(t){t.data?i=i.concat(t.data):e.each(t.points,function(t){i.push(t.value)})}),i}(),s=this.options.scaleOverride?{steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this.options.scaleStepWidth}:e.calculateScaleRange(i,e.min([this.chart.width,this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this.options.scaleIntegersOnly);e.extend(this.scale,s)},addData:function(t,i){this.scale.valuesCount++,e.each(t,function(t,e){var s=this.scale.getPointPosition(this.scale.valuesCount,this.scale.calculateCenterOffset(t));this.datasets[e].points.push(new this.PointClass({value:t,label:i,x:s.x,y:s.y,strokeColor:this.datasets[e].pointStrokeColor,fillColor:this.datasets[e].pointColor}))},this),this.scale.labels.push(i),this.reflow(),this.update()},removeData:function(){this.scale.valuesCount--,this.scale.labels.shift(),e.each(this.datasets,function(t){t.points.shift()},this),this.reflow(),this.update()},update:function(){this.eachPoints(function(t){t.save()}),this.reflow(),this.render()},reflow:function(){e.extend(this.scale,{width:this.chart.width,height:this.chart.height,size:e.min([this.chart.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart.height/2}),this.updateScaleRange(this.datasets),this.scale.setScaleSize(),this.scale.buildYLabels()},draw:function(t){var i=t||1,s=this.chart.ctx;this.clear(),this.scale.draw(),e.each(this.datasets,function(t){e.each(t.points,function(t,e){t.hasValue()&&t.transition(this.scale.getPointPosition(e,this.scale.calculateCenterOffset(t.value)),i)},this),s.lineWidth=this.options.datasetStrokeWidth,s.strokeStyle=t.strokeColor,s.beginPath(),e.each(t.points,function(t,i){0===i?s.moveTo(t.x,t.y):s.lineTo(t.x,t.y)},this),s.closePath(),s.stroke(),s.fillStyle=t.fillColor,s.fill(),e.each(t.points,function(t){t.hasValue()&&t.draw()})},this)}})}.call(this);
--- /dev/null
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn-default.disabled,
+.btn-primary.disabled,
+.btn-success.disabled,
+.btn-info.disabled,
+.btn-warning.disabled,
+.btn-danger.disabled,
+.btn-default[disabled],
+.btn-primary[disabled],
+.btn-success[disabled],
+.btn-info[disabled],
+.btn-warning[disabled],
+.btn-danger[disabled],
+fieldset[disabled] .btn-default,
+fieldset[disabled] .btn-primary,
+fieldset[disabled] .btn-success,
+fieldset[disabled] .btn-info,
+fieldset[disabled] .btn-warning,
+fieldset[disabled] .btn-danger {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+.btn-default .badge,
+.btn-primary .badge,
+.btn-success .badge,
+.btn-info .badge,
+.btn-warning .badge,
+.btn-danger .badge {
+ text-shadow: none;
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+}
+.btn-default {
+ text-shadow: 0 1px 0 #fff;
+ background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
+ background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #dbdbdb;
+ border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+ background-color: #e0e0e0;
+ background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+ background-color: #e0e0e0;
+ border-color: #dbdbdb;
+}
+.btn-default.disabled,
+.btn-default[disabled],
+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: #e0e0e0;
+ background-image: none;
+}
+.btn-primary {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #245580;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+ background-color: #265a88;
+ background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+ background-color: #265a88;
+ border-color: #245580;
+}
+.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: #265a88;
+ background-image: none;
+}
+.btn-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #3e8f3e;
+}
+.btn-success:hover,
+.btn-success:focus {
+ background-color: #419641;
+ background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+ background-color: #419641;
+ border-color: #3e8f3e;
+}
+.btn-success.disabled,
+.btn-success[disabled],
+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: #419641;
+ background-image: none;
+}
+.btn-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #28a4c9;
+}
+.btn-info:hover,
+.btn-info:focus {
+ background-color: #2aabd2;
+ background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+ background-color: #2aabd2;
+ border-color: #28a4c9;
+}
+.btn-info.disabled,
+.btn-info[disabled],
+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: #2aabd2;
+ background-image: none;
+}
+.btn-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #e38d13;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+ background-color: #eb9316;
+ background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+ background-color: #eb9316;
+ border-color: #e38d13;
+}
+.btn-warning.disabled,
+.btn-warning[disabled],
+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: #eb9316;
+ background-image: none;
+}
+.btn-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #b92c28;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+ background-color: #c12e2a;
+ background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+ background-color: #c12e2a;
+ border-color: #b92c28;
+}
+.btn-danger.disabled,
+.btn-danger[disabled],
+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: #c12e2a;
+ background-image: none;
+}
+.thumbnail,
+.img-thumbnail {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ background-color: #e8e8e8;
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ background-color: #2e6da4;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+}
+.navbar-default {
+ background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8));
+ background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .open > a,
+.navbar-default .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+ background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
+ background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+ background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
+ background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+}
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+ background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
+ background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ border-radius: 0;
+}
+@media (max-width: 767px) {
+ .navbar .navbar-nav .open .dropdown-menu > .active > a,
+ .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
+ .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
+ color: #fff;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+ }
+}
+.alert {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #b2dba1;
+}
+.alert-info {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #9acfea;
+}
+.alert-warning {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #f5e79e;
+}
+.alert-danger {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dca7a7;
+}
+.progress {
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-striped {
+ background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent);
+}
+.list-group {
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ text-shadow: 0 -1px 0 #286090;
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #2b669a;
+}
+.list-group-item.active .badge,
+.list-group-item.active:hover .badge,
+.list-group-item.active:focus .badge {
+ text-shadow: none;
+}
+.panel {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
+ background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.well {
+ background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
+ background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dcdcdc;
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */
--- /dev/null
+{"version":3,"sources":["bootstrap-theme.css","less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":"AAAA;;;;GAIG;ACeH;;;;;;EAME,yCAAA;EC2CA,4FAAA;EACQ,oFAAA;CFvDT;ACgBC;;;;;;;;;;;;ECsCA,yDAAA;EACQ,iDAAA;CFxCT;ACMC;;;;;;;;;;;;;;;;;;ECiCA,yBAAA;EACQ,iBAAA;CFnBT;AC/BD;;;;;;EAuBI,kBAAA;CDgBH;ACyBC;;EAEE,uBAAA;CDvBH;AC4BD;EErEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;EAuC2C,0BAAA;EAA2B,mBAAA;CDjBvE;ACpBC;;EAEE,0BAAA;EACA,6BAAA;CDsBH;ACnBC;;EAEE,0BAAA;EACA,sBAAA;CDqBH;ACfG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6BL;ACbD;EEtEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8DD;AC5DC;;EAEE,0BAAA;EACA,6BAAA;CD8DH;AC3DC;;EAEE,0BAAA;EACA,sBAAA;CD6DH;ACvDG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqEL;ACpDD;EEvEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CDsGD;ACpGC;;EAEE,0BAAA;EACA,6BAAA;CDsGH;ACnGC;;EAEE,0BAAA;EACA,sBAAA;CDqGH;AC/FG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6GL;AC3FD;EExEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8ID;AC5IC;;EAEE,0BAAA;EACA,6BAAA;CD8IH;AC3IC;;EAEE,0BAAA;EACA,sBAAA;CD6IH;ACvIG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqJL;AClID;EEzEI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CDsLD;ACpLC;;EAEE,0BAAA;EACA,6BAAA;CDsLH;ACnLC;;EAEE,0BAAA;EACA,sBAAA;CDqLH;AC/KG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CD6LL;ACzKD;EE1EI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EAEA,uHAAA;ECnBF,oEAAA;EH4CA,4BAAA;EACA,sBAAA;CD8ND;AC5NC;;EAEE,0BAAA;EACA,6BAAA;CD8NH;AC3NC;;EAEE,0BAAA;EACA,sBAAA;CD6NH;ACvNG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACA,uBAAA;CDqOL;AC1MD;;EClCE,mDAAA;EACQ,2CAAA;CFgPT;ACrMD;;EE3FI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF0FF,0BAAA;CD2MD;ACzMD;;;EEhGI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFgGF,0BAAA;CD+MD;ACtMD;EE7GI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ECnBF,oEAAA;EH+HA,mBAAA;ECjEA,4FAAA;EACQ,oFAAA;CF8QT;ACjND;;EE7GI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ED2CF,yDAAA;EACQ,iDAAA;CFwRT;AC9MD;;EAEE,+CAAA;CDgND;AC5MD;EEhII,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ECnBF,oEAAA;EHkJA,mBAAA;CDkND;ACrND;;EEhII,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;ED2CF,wDAAA;EACQ,gDAAA;CF+ST;AC/ND;;EAYI,0CAAA;CDuNH;AClND;;;EAGE,iBAAA;CDoND;AC/LD;EAfI;;;IAGE,YAAA;IE7JF,yEAAA;IACA,oEAAA;IACA,8FAAA;IAAA,uEAAA;IACA,4BAAA;IACA,uHAAA;GH+WD;CACF;AC3MD;EACE,8CAAA;EC3HA,2FAAA;EACQ,mFAAA;CFyUT;ACnMD;EEtLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CD+MD;AC1MD;EEvLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CDuND;ACjND;EExLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CD+ND;ACxND;EEzLI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EF8KF,sBAAA;CDuOD;ACxND;EEjMI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH4ZH;ACrND;EE3MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHmaH;AC3ND;EE5MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH0aH;ACjOD;EE7MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHibH;ACvOD;EE9MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHwbH;AC7OD;EE/MI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH+bH;AChPD;EElLI,8MAAA;EACA,yMAAA;EACA,sMAAA;CHqaH;AC5OD;EACE,mBAAA;EC9KA,mDAAA;EACQ,2CAAA;CF6ZT;AC7OD;;;EAGE,8BAAA;EEnOE,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFiOF,sBAAA;CDmPD;ACxPD;;;EAQI,kBAAA;CDqPH;AC3OD;ECnME,kDAAA;EACQ,0CAAA;CFibT;ACrOD;EE5PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHoeH;AC3OD;EE7PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CH2eH;ACjPD;EE9PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHkfH;ACvPD;EE/PI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHyfH;AC7PD;EEhQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHggBH;ACnQD;EEjQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;CHugBH;ACnQD;EExQI,yEAAA;EACA,oEAAA;EACA,8FAAA;EAAA,uEAAA;EACA,4BAAA;EACA,uHAAA;EFsQF,sBAAA;EC3NA,0FAAA;EACQ,kFAAA;CFqeT","file":"bootstrap-theme.css","sourcesContent":["/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.btn-default:active,\n.btn-primary:active,\n.btn-success:active,\n.btn-info:active,\n.btn-warning:active,\n.btn-danger:active,\n.btn-default.active,\n.btn-primary.active,\n.btn-success.active,\n.btn-info.active,\n.btn-warning.active,\n.btn-danger.active {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-default.disabled,\n.btn-primary.disabled,\n.btn-success.disabled,\n.btn-info.disabled,\n.btn-warning.disabled,\n.btn-danger.disabled,\n.btn-default[disabled],\n.btn-primary[disabled],\n.btn-success[disabled],\n.btn-info[disabled],\n.btn-warning[disabled],\n.btn-danger[disabled],\nfieldset[disabled] .btn-default,\nfieldset[disabled] .btn-primary,\nfieldset[disabled] .btn-success,\nfieldset[disabled] .btn-info,\nfieldset[disabled] .btn-warning,\nfieldset[disabled] .btn-danger {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-default .badge,\n.btn-primary .badge,\n.btn-success .badge,\n.btn-info .badge,\n.btn-warning .badge,\n.btn-danger .badge {\n text-shadow: none;\n}\n.btn:active,\n.btn.active {\n background-image: none;\n}\n.btn-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #dbdbdb;\n text-shadow: 0 1px 0 #fff;\n border-color: #ccc;\n}\n.btn-default:hover,\n.btn-default:focus {\n background-color: #e0e0e0;\n background-position: 0 -15px;\n}\n.btn-default:active,\n.btn-default.active {\n background-color: #e0e0e0;\n border-color: #dbdbdb;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #e0e0e0;\n background-image: none;\n}\n.btn-primary {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #245580;\n}\n.btn-primary:hover,\n.btn-primary:focus {\n background-color: #265a88;\n background-position: 0 -15px;\n}\n.btn-primary:active,\n.btn-primary.active {\n background-color: #265a88;\n border-color: #245580;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #265a88;\n background-image: none;\n}\n.btn-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #3e8f3e;\n}\n.btn-success:hover,\n.btn-success:focus {\n background-color: #419641;\n background-position: 0 -15px;\n}\n.btn-success:active,\n.btn-success.active {\n background-color: #419641;\n border-color: #3e8f3e;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #419641;\n background-image: none;\n}\n.btn-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #28a4c9;\n}\n.btn-info:hover,\n.btn-info:focus {\n background-color: #2aabd2;\n background-position: 0 -15px;\n}\n.btn-info:active,\n.btn-info.active {\n background-color: #2aabd2;\n border-color: #28a4c9;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #2aabd2;\n background-image: none;\n}\n.btn-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #e38d13;\n}\n.btn-warning:hover,\n.btn-warning:focus {\n background-color: #eb9316;\n background-position: 0 -15px;\n}\n.btn-warning:active,\n.btn-warning.active {\n background-color: #eb9316;\n border-color: #e38d13;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #eb9316;\n background-image: none;\n}\n.btn-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n background-repeat: repeat-x;\n border-color: #b92c28;\n}\n.btn-danger:hover,\n.btn-danger:focus {\n background-color: #c12e2a;\n background-position: 0 -15px;\n}\n.btn-danger:active,\n.btn-danger.active {\n background-color: #c12e2a;\n border-color: #b92c28;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #c12e2a;\n background-image: none;\n}\n.thumbnail,\n.img-thumbnail {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n background-color: #e8e8e8;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n background-color: #2e6da4;\n}\n.navbar-default {\n background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);\n background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);\n background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);\n}\n.navbar-inverse {\n background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: -o-linear-gradient(top, #3c3c3c 0%, #222222 100%);\n background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n border-radius: 4px;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .active > a {\n background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);\n background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);\n -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);\n}\n.navbar-inverse .navbar-brand,\n.navbar-inverse .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n@media (max-width: 767px) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #fff;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n }\n}\n.alert {\n text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.alert-success {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);\n border-color: #b2dba1;\n}\n.alert-info {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);\n border-color: #9acfea;\n}\n.alert-warning {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);\n border-color: #f5e79e;\n}\n.alert-danger {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);\n border-color: #dca7a7;\n}\n.progress {\n background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);\n}\n.progress-bar {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);\n}\n.progress-bar-success {\n background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);\n background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);\n}\n.progress-bar-info {\n background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);\n background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);\n}\n.progress-bar-warning {\n background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);\n background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);\n}\n.progress-bar-danger {\n background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);\n background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);\n}\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.list-group {\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 #286090;\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);\n border-color: #2b669a;\n}\n.list-group-item.active .badge,\n.list-group-item.active:hover .badge,\n.list-group-item.active:focus .badge {\n text-shadow: none;\n}\n.panel {\n -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);\n}\n.panel-default > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);\n background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);\n}\n.panel-primary > .panel-heading {\n background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);\n background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);\n}\n.panel-success > .panel-heading {\n background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);\n background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);\n}\n.panel-info > .panel-heading {\n background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);\n background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);\n}\n.panel-warning > .panel-heading {\n background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);\n background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);\n}\n.panel-danger > .panel-heading {\n background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);\n background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);\n}\n.well {\n background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);\n background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);\n border-color: #dcdcdc;\n -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);\n}\n/*# sourceMappingURL=bootstrap-theme.css.map */","/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]}
\ No newline at end of file
--- /dev/null
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
\ No newline at end of file
--- /dev/null
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
+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;
+ }
+ .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.woff2') format('woff2'), 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";
+}
+.glyphicon-cd:before {
+ content: "\e201";
+}
+.glyphicon-save-file:before {
+ content: "\e202";
+}
+.glyphicon-open-file:before {
+ content: "\e203";
+}
+.glyphicon-level-up:before {
+ content: "\e204";
+}
+.glyphicon-copy:before {
+ content: "\e205";
+}
+.glyphicon-paste:before {
+ content: "\e206";
+}
+.glyphicon-alert:before {
+ content: "\e209";
+}
+.glyphicon-equalizer:before {
+ content: "\e210";
+}
+.glyphicon-king:before {
+ content: "\e211";
+}
+.glyphicon-queen:before {
+ content: "\e212";
+}
+.glyphicon-pawn:before {
+ content: "\e213";
+}
+.glyphicon-bishop:before {
+ content: "\e214";
+}
+.glyphicon-knight:before {
+ content: "\e215";
+}
+.glyphicon-baby-formula:before {
+ content: "\e216";
+}
+.glyphicon-tent:before {
+ content: "\26fa";
+}
+.glyphicon-blackboard:before {
+ content: "\e218";
+}
+.glyphicon-bed:before {
+ content: "\e219";
+}
+.glyphicon-apple:before {
+ content: "\f8ff";
+}
+.glyphicon-erase:before {
+ content: "\e221";
+}
+.glyphicon-hourglass:before {
+ content: "\231b";
+}
+.glyphicon-lamp:before {
+ content: "\e223";
+}
+.glyphicon-duplicate:before {
+ content: "\e224";
+}
+.glyphicon-piggy-bank:before {
+ content: "\e225";
+}
+.glyphicon-scissors:before {
+ content: "\e226";
+}
+.glyphicon-bitcoin:before {
+ content: "\e227";
+}
+.glyphicon-btc:before {
+ content: "\e227";
+}
+.glyphicon-xbt:before {
+ content: "\e227";
+}
+.glyphicon-yen:before {
+ content: "\00a5";
+}
+.glyphicon-jpy:before {
+ content: "\00a5";
+}
+.glyphicon-ruble:before {
+ content: "\20bd";
+}
+.glyphicon-rub:before {
+ content: "\20bd";
+}
+.glyphicon-scale:before {
+ content: "\e230";
+}
+.glyphicon-ice-lolly:before {
+ content: "\e231";
+}
+.glyphicon-ice-lolly-tasted:before {
+ content: "\e232";
+}
+.glyphicon-education:before {
+ content: "\e233";
+}
+.glyphicon-option-horizontal:before {
+ content: "\e234";
+}
+.glyphicon-option-vertical:before {
+ content: "\e235";
+}
+.glyphicon-menu-hamburger:before {
+ content: "\e236";
+}
+.glyphicon-modal-window:before {
+ content: "\e237";
+}
+.glyphicon-oil:before {
+ content: "\e238";
+}
+.glyphicon-grain:before {
+ content: "\e239";
+}
+.glyphicon-sunglasses:before {
+ content: "\e240";
+}
+.glyphicon-text-size:before {
+ content: "\e241";
+}
+.glyphicon-text-color:before {
+ content: "\e242";
+}
+.glyphicon-text-background:before {
+ content: "\e243";
+}
+.glyphicon-object-align-top:before {
+ content: "\e244";
+}
+.glyphicon-object-align-bottom:before {
+ content: "\e245";
+}
+.glyphicon-object-align-horizontal:before {
+ content: "\e246";
+}
+.glyphicon-object-align-left:before {
+ content: "\e247";
+}
+.glyphicon-object-align-vertical:before {
+ content: "\e248";
+}
+.glyphicon-object-align-right:before {
+ content: "\e249";
+}
+.glyphicon-triangle-right:before {
+ content: "\e250";
+}
+.glyphicon-triangle-left:before {
+ content: "\e251";
+}
+.glyphicon-triangle-bottom:before {
+ content: "\e252";
+}
+.glyphicon-triangle-top:before {
+ content: "\e253";
+}
+.glyphicon-console:before {
+ content: "\e254";
+}
+.glyphicon-superscript:before {
+ content: "\e255";
+}
+.glyphicon-subscript:before {
+ content: "\e256";
+}
+.glyphicon-menu-left:before {
+ content: "\e257";
+}
+.glyphicon-menu-right:before {
+ content: "\e258";
+}
+.glyphicon-menu-down:before {
+ content: "\e259";
+}
+.glyphicon-menu-up:before {
+ content: "\e260";
+}
+* {
+ -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: #337ab7;
+ text-decoration: none;
+}
+a:hover,
+a:focus {
+ color: #23527c;
+ 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;
+}
+[role="button"] {
+ cursor: pointer;
+}
+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: #337ab7;
+}
+a.text-primary:hover,
+a.text-primary:focus {
+ color: #286090;
+}
+.text-success {
+ color: #3c763d;
+}
+a.text-success:hover,
+a.text-success:focus {
+ color: #2b542c;
+}
+.text-info {
+ color: #31708f;
+}
+a.text-info:hover,
+a.text-info:focus {
+ color: #245269;
+}
+.text-warning {
+ color: #8a6d3b;
+}
+a.text-warning:hover,
+a.text-warning:focus {
+ color: #66512c;
+}
+.text-danger {
+ color: #a94442;
+}
+a.text-danger:hover,
+a.text-danger:focus {
+ color: #843534;
+}
+.bg-primary {
+ color: #fff;
+ background-color: #337ab7;
+}
+a.bg-primary:hover,
+a.bg-primary:focus {
+ background-color: #286090;
+}
+.bg-success {
+ background-color: #dff0d8;
+}
+a.bg-success:hover,
+a.bg-success:focus {
+ background-color: #c1e2b3;
+}
+.bg-info {
+ background-color: #d9edf7;
+}
+a.bg-info:hover,
+a.bg-info:focus {
+ background-color: #afd9ee;
+}
+.bg-warning {
+ background-color: #fcf8e3;
+}
+a.bg-warning:hover,
+a.bg-warning:focus {
+ background-color: #f7ecb5;
+}
+.bg-danger {
+ background-color: #f2dede;
+}
+a.bg-danger:hover,
+a.bg-danger:focus {
+ 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-of-type(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 {
+ background-color: #eee;
+ opacity: 1;
+}
+.form-control[disabled],
+fieldset[disabled] .form-control {
+ cursor: not-allowed;
+}
+textarea.form-control {
+ height: auto;
+}
+input[type="search"] {
+ -webkit-appearance: none;
+}
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ input[type="date"].form-control,
+ input[type="time"].form-control,
+ input[type="datetime-local"].form-control,
+ input[type="month"].form-control {
+ line-height: 34px;
+ }
+ input[type="date"].input-sm,
+ input[type="time"].input-sm,
+ input[type="datetime-local"].input-sm,
+ input[type="month"].input-sm,
+ .input-group-sm input[type="date"],
+ .input-group-sm input[type="time"],
+ .input-group-sm input[type="datetime-local"],
+ .input-group-sm input[type="month"] {
+ line-height: 30px;
+ }
+ input[type="date"].input-lg,
+ input[type="time"].input-lg,
+ input[type="datetime-local"].input-lg,
+ input[type="month"].input-lg,
+ .input-group-lg input[type="date"],
+ .input-group-lg input[type="time"],
+ .input-group-lg input[type="datetime-local"],
+ .input-group-lg input[type="month"] {
+ line-height: 46px;
+ }
+}
+.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 {
+ position: relative;
+ 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 {
+ min-height: 34px;
+ 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 {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+select.input-sm {
+ height: 30px;
+ line-height: 30px;
+}
+textarea.input-sm,
+select[multiple].input-sm {
+ height: auto;
+}
+.form-group-sm .form-control {
+ height: 30px;
+ padding: 5px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+ border-radius: 3px;
+}
+.form-group-sm select.form-control {
+ height: 30px;
+ line-height: 30px;
+}
+.form-group-sm textarea.form-control,
+.form-group-sm select[multiple].form-control {
+ height: auto;
+}
+.form-group-sm .form-control-static {
+ height: 30px;
+ min-height: 32px;
+ padding: 6px 10px;
+ font-size: 12px;
+ line-height: 1.5;
+}
+.input-lg {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+select.input-lg {
+ height: 46px;
+ line-height: 46px;
+}
+textarea.input-lg,
+select[multiple].input-lg {
+ height: auto;
+}
+.form-group-lg .form-control {
+ height: 46px;
+ padding: 10px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+ border-radius: 6px;
+}
+.form-group-lg select.form-control {
+ height: 46px;
+ line-height: 46px;
+}
+.form-group-lg textarea.form-control,
+.form-group-lg select[multiple].form-control {
+ height: auto;
+}
+.form-group-lg .form-control-static {
+ height: 46px;
+ min-height: 38px;
+ padding: 11px 16px;
+ font-size: 18px;
+ line-height: 1.3333333;
+}
+.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,
+.input-group-lg + .form-control-feedback,
+.form-group-lg .form-control + .form-control-feedback {
+ width: 46px;
+ height: 46px;
+ line-height: 46px;
+}
+.input-sm + .form-control-feedback,
+.input-group-sm + .form-control-feedback,
+.form-group-sm .form-control + .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.333333px;
+ font-size: 18px;
+ }
+}
+@media (min-width: 768px) {
+ .form-horizontal .form-group-sm .control-label {
+ padding-top: 6px;
+ font-size: 12px;
+ }
+}
+.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 {
+ cursor: not-allowed;
+ filter: alpha(opacity=65);
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ opacity: .65;
+}
+a.btn.disabled,
+fieldset[disabled] a.btn {
+ pointer-events: none;
+}
+.btn-default {
+ color: #333;
+ background-color: #fff;
+ border-color: #ccc;
+}
+.btn-default:focus,
+.btn-default.focus {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #8c8c8c;
+}
+.btn-default:hover {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active,
+.btn-default.active,
+.open > .dropdown-toggle.btn-default {
+ color: #333;
+ background-color: #e6e6e6;
+ border-color: #adadad;
+}
+.btn-default:active:hover,
+.btn-default.active:hover,
+.open > .dropdown-toggle.btn-default:hover,
+.btn-default:active:focus,
+.btn-default.active:focus,
+.open > .dropdown-toggle.btn-default:focus,
+.btn-default:active.focus,
+.btn-default.active.focus,
+.open > .dropdown-toggle.btn-default.focus {
+ color: #333;
+ background-color: #d4d4d4;
+ border-color: #8c8c8c;
+}
+.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: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary:focus,
+.btn-primary.focus {
+ color: #fff;
+ background-color: #286090;
+ border-color: #122b40;
+}
+.btn-primary:hover {
+ color: #fff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active,
+.btn-primary.active,
+.open > .dropdown-toggle.btn-primary {
+ color: #fff;
+ background-color: #286090;
+ border-color: #204d74;
+}
+.btn-primary:active:hover,
+.btn-primary.active:hover,
+.open > .dropdown-toggle.btn-primary:hover,
+.btn-primary:active:focus,
+.btn-primary.active:focus,
+.open > .dropdown-toggle.btn-primary:focus,
+.btn-primary:active.focus,
+.btn-primary.active.focus,
+.open > .dropdown-toggle.btn-primary.focus {
+ color: #fff;
+ background-color: #204d74;
+ border-color: #122b40;
+}
+.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: #337ab7;
+ border-color: #2e6da4;
+}
+.btn-primary .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.btn-success {
+ color: #fff;
+ background-color: #5cb85c;
+ border-color: #4cae4c;
+}
+.btn-success:focus,
+.btn-success.focus {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #255625;
+}
+.btn-success:hover {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active,
+.btn-success.active,
+.open > .dropdown-toggle.btn-success {
+ color: #fff;
+ background-color: #449d44;
+ border-color: #398439;
+}
+.btn-success:active:hover,
+.btn-success.active:hover,
+.open > .dropdown-toggle.btn-success:hover,
+.btn-success:active:focus,
+.btn-success.active:focus,
+.open > .dropdown-toggle.btn-success:focus,
+.btn-success:active.focus,
+.btn-success.active.focus,
+.open > .dropdown-toggle.btn-success.focus {
+ color: #fff;
+ background-color: #398439;
+ border-color: #255625;
+}
+.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:focus,
+.btn-info.focus {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #1b6d85;
+}
+.btn-info:hover {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active,
+.btn-info.active,
+.open > .dropdown-toggle.btn-info {
+ color: #fff;
+ background-color: #31b0d5;
+ border-color: #269abc;
+}
+.btn-info:active:hover,
+.btn-info.active:hover,
+.open > .dropdown-toggle.btn-info:hover,
+.btn-info:active:focus,
+.btn-info.active:focus,
+.open > .dropdown-toggle.btn-info:focus,
+.btn-info:active.focus,
+.btn-info.active.focus,
+.open > .dropdown-toggle.btn-info.focus {
+ color: #fff;
+ background-color: #269abc;
+ border-color: #1b6d85;
+}
+.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:focus,
+.btn-warning.focus {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #985f0d;
+}
+.btn-warning:hover {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active,
+.btn-warning.active,
+.open > .dropdown-toggle.btn-warning {
+ color: #fff;
+ background-color: #ec971f;
+ border-color: #d58512;
+}
+.btn-warning:active:hover,
+.btn-warning.active:hover,
+.open > .dropdown-toggle.btn-warning:hover,
+.btn-warning:active:focus,
+.btn-warning.active:focus,
+.open > .dropdown-toggle.btn-warning:focus,
+.btn-warning:active.focus,
+.btn-warning.active.focus,
+.open > .dropdown-toggle.btn-warning.focus {
+ color: #fff;
+ background-color: #d58512;
+ border-color: #985f0d;
+}
+.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:focus,
+.btn-danger.focus {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #761c19;
+}
+.btn-danger:hover {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active,
+.btn-danger.active,
+.open > .dropdown-toggle.btn-danger {
+ color: #fff;
+ background-color: #c9302c;
+ border-color: #ac2925;
+}
+.btn-danger:active:hover,
+.btn-danger.active:hover,
+.open > .dropdown-toggle.btn-danger:hover,
+.btn-danger:active:focus,
+.btn-danger.active:focus,
+.open > .dropdown-toggle.btn-danger:focus,
+.btn-danger:active.focus,
+.btn-danger.active.focus,
+.open > .dropdown-toggle.btn-danger.focus {
+ color: #fff;
+ background-color: #ac2925;
+ border-color: #761c19;
+}
+.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: #337ab7;
+ 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: #23527c;
+ 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.3333333;
+ 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;
+}
+.collapse.in {
+ display: block;
+}
+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 dashed;
+ border-top: 4px solid \9;
+ border-right: 4px solid transparent;
+ border-left: 4px solid transparent;
+}
+.dropup,
+.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: #337ab7;
+ 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 dashed;
+ border-bottom: 4px solid \9;
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 2px;
+}
+@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 + .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,
+.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:not(:last-child) > .btn:last-child,
+.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+.btn-group > .btn-group:last-child:not(:first-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.3333333;
+ 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 {
+ z-index: 2;
+ 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: #337ab7;
+}
+.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: #337ab7;
+}
+.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;
+}
+.tab-content > .active {
+ display: block;
+}
+.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;
+ }
+ .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 {
+ margin-bottom: 0;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ 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: #337ab7;
+ 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 {
+ z-index: 3;
+ color: #23527c;
+ 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: #337ab7;
+ border-color: #337ab7;
+}
+.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;
+ line-height: 1.3333333;
+}
+.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;
+ line-height: 1.5;
+}
+.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: #337ab7;
+}
+.label-primary[href]:hover,
+.label-primary[href]:focus {
+ background-color: #286090;
+}
+.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: middle;
+ background-color: #777;
+ border-radius: 10px;
+}
+.badge:empty {
+ display: none;
+}
+.btn .badge {
+ position: relative;
+ top: -1px;
+}
+.btn-xs .badge,
+.btn-group-xs > .btn .badge {
+ top: 0;
+ padding: 1px 5px;
+}
+a.badge:hover,
+a.badge:focus {
+ color: #fff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.list-group-item.active > .badge,
+.nav-pills > .active > a > .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.list-group-item > .badge {
+ float: right;
+}
+.list-group-item > .badge + .badge {
+ margin-right: 5px;
+}
+.nav-pills > li > a > .badge {
+ margin-left: 3px;
+}
+.jumbotron {
+ padding-top: 30px;
+ padding-bottom: 30px;
+ 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-top: 48px;
+ padding-bottom: 48px;
+ }
+ .container .jumbotron,
+ .container-fluid .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: #337ab7;
+}
+.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: #337ab7;
+ -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,
+.media-body {
+ overflow: hidden;
+ zoom: 1;
+}
+.media-body {
+ width: 10000px;
+}
+.media-object {
+ display: block;
+}
+.media-object.img-thumbnail {
+ max-width: none;
+}
+.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;
+}
+a.list-group-item,
+button.list-group-item {
+ color: #555;
+}
+a.list-group-item .list-group-item-heading,
+button.list-group-item .list-group-item-heading {
+ color: #333;
+}
+a.list-group-item:hover,
+button.list-group-item:hover,
+a.list-group-item:focus,
+button.list-group-item:focus {
+ color: #555;
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+button.list-group-item {
+ width: 100%;
+ text-align: left;
+}
+.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: #337ab7;
+ border-color: #337ab7;
+}
+.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: #c7ddef;
+}
+.list-group-item-success {
+ color: #3c763d;
+ background-color: #dff0d8;
+}
+a.list-group-item-success,
+button.list-group-item-success {
+ color: #3c763d;
+}
+a.list-group-item-success .list-group-item-heading,
+button.list-group-item-success .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-success:hover,
+button.list-group-item-success:hover,
+a.list-group-item-success:focus,
+button.list-group-item-success:focus {
+ color: #3c763d;
+ background-color: #d0e9c6;
+}
+a.list-group-item-success.active,
+button.list-group-item-success.active,
+a.list-group-item-success.active:hover,
+button.list-group-item-success.active:hover,
+a.list-group-item-success.active:focus,
+button.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,
+button.list-group-item-info {
+ color: #31708f;
+}
+a.list-group-item-info .list-group-item-heading,
+button.list-group-item-info .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-info:hover,
+button.list-group-item-info:hover,
+a.list-group-item-info:focus,
+button.list-group-item-info:focus {
+ color: #31708f;
+ background-color: #c4e3f3;
+}
+a.list-group-item-info.active,
+button.list-group-item-info.active,
+a.list-group-item-info.active:hover,
+button.list-group-item-info.active:hover,
+a.list-group-item-info.active:focus,
+button.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,
+button.list-group-item-warning {
+ color: #8a6d3b;
+}
+a.list-group-item-warning .list-group-item-heading,
+button.list-group-item-warning .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-warning:hover,
+button.list-group-item-warning:hover,
+a.list-group-item-warning:focus,
+button.list-group-item-warning:focus {
+ color: #8a6d3b;
+ background-color: #faf2cc;
+}
+a.list-group-item-warning.active,
+button.list-group-item-warning.active,
+a.list-group-item-warning.active:hover,
+button.list-group-item-warning.active:hover,
+a.list-group-item-warning.active:focus,
+button.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,
+button.list-group-item-danger {
+ color: #a94442;
+}
+a.list-group-item-danger .list-group-item-heading,
+button.list-group-item-danger .list-group-item-heading {
+ color: inherit;
+}
+a.list-group-item-danger:hover,
+button.list-group-item-danger:hover,
+a.list-group-item-danger:focus,
+button.list-group-item-danger:focus {
+ color: #a94442;
+ background-color: #ebcccc;
+}
+a.list-group-item-danger.active,
+button.list-group-item-danger.active,
+a.list-group-item-danger.active:hover,
+button.list-group-item-danger.active:hover,
+a.list-group-item-danger.active:focus,
+button.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,
+.panel-title > small,
+.panel-title > .small,
+.panel-title > small > a,
+.panel-title > .small > 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 > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+.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: #337ab7;
+}
+.panel-primary > .panel-heading {
+ color: #fff;
+ background-color: #337ab7;
+ border-color: #337ab7;
+}
+.panel-primary > .panel-heading + .panel-collapse > .panel-body {
+ border-top-color: #337ab7;
+}
+.panel-primary > .panel-heading .badge {
+ color: #337ab7;
+ background-color: #fff;
+}
+.panel-primary > .panel-footer + .panel-collapse > .panel-body {
+ border-bottom-color: #337ab7;
+}
+.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-16by9 {
+ padding-bottom: 56.25%;
+}
+.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: 1050;
+ 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;
+ z-index: 1040;
+ 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-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 12px;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ word-wrap: normal;
+ white-space: normal;
+ filter: alpha(opacity=0);
+ opacity: 0;
+
+ line-break: auto;
+}
+.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;
+ 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 {
+ right: 5px;
+ bottom: 0;
+ margin-bottom: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+ bottom: 0;
+ left: 5px;
+ margin-bottom: -5px;
+ 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;
+ right: 5px;
+ margin-top: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+ top: 0;
+ left: 5px;
+ margin-top: -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-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: normal;
+ line-height: 1.42857143;
+ text-align: left;
+ text-align: start;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-break: normal;
+ word-spacing: normal;
+ word-wrap: normal;
+ 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);
+
+ line-break: auto;
+}
+.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: 1000px;
+ perspective: 1000px;
+ }
+ .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;
+ margin-top: -10px;
+}
+.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;
+ font-family: serif;
+ line-height: 1;
+}
+.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;
+}
+.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 !important;
+ }
+ 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 !important;
+ }
+ 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 !important;
+ }
+ 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 !important;
+ }
+ 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 !important;
+ }
+ 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 */
--- /dev/null
+{"version":3,"sources":["bootstrap.css","less/normalize.less","less/print.less","less/glyphicons.less","less/scaffolding.less","less/mixins/vendor-prefixes.less","less/mixins/tab-focus.less","less/mixins/image.less","less/type.less","less/mixins/text-emphasis.less","less/mixins/background-variant.less","less/mixins/text-overflow.less","less/code.less","less/grid.less","less/mixins/grid.less","less/mixins/grid-framework.less","less/tables.less","less/mixins/table-row.less","less/forms.less","less/mixins/forms.less","less/buttons.less","less/mixins/buttons.less","less/mixins/opacity.less","less/component-animations.less","less/dropdowns.less","less/mixins/nav-divider.less","less/mixins/reset-filter.less","less/button-groups.less","less/mixins/border-radius.less","less/input-groups.less","less/navs.less","less/navbar.less","less/mixins/nav-vertical-align.less","less/utilities.less","less/breadcrumbs.less","less/pagination.less","less/mixins/pagination.less","less/pager.less","less/labels.less","less/mixins/labels.less","less/badges.less","less/jumbotron.less","less/thumbnails.less","less/alerts.less","less/mixins/alerts.less","less/progress-bars.less","less/mixins/gradients.less","less/mixins/progress-bar.less","less/media.less","less/list-group.less","less/mixins/list-group.less","less/panels.less","less/mixins/panels.less","less/responsive-embed.less","less/wells.less","less/close.less","less/modals.less","less/tooltip.less","less/mixins/reset-text.less","less/popovers.less","less/carousel.less","less/mixins/clearfix.less","less/mixins/center-block.less","less/mixins/hide-text.less","less/responsive-utilities.less","less/mixins/responsive-visibility.less"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,4EAA4E;ACG5E;EACE,wBAAA;EACA,2BAAA;EACA,+BAAA;CDDD;ACQD;EACE,UAAA;CDND;ACmBD;;;;;;;;;;;;;EAaE,eAAA;CDjBD;ACyBD;;;;EAIE,sBAAA;EACA,yBAAA;CDvBD;AC+BD;EACE,cAAA;EACA,UAAA;CD7BD;ACqCD;;EAEE,cAAA;CDnCD;AC6CD;EACE,8BAAA;CD3CD;ACmDD;;EAEE,WAAA;CDjDD;AC2DD;EACE,0BAAA;CDzDD;ACgED;;EAEE,kBAAA;CD9DD;ACqED;EACE,mBAAA;CDnED;AC2ED;EACE,eAAA;EACA,iBAAA;CDzED;ACgFD;EACE,iBAAA;EACA,YAAA;CD9ED;ACqFD;EACE,eAAA;CDnFD;AC0FD;;EAEE,eAAA;EACA,eAAA;EACA,mBAAA;EACA,yBAAA;CDxFD;AC2FD;EACE,YAAA;CDzFD;AC4FD;EACE,gBAAA;CD1FD;ACoGD;EACE,UAAA;CDlGD;ACyGD;EACE,iBAAA;CDvGD;ACiHD;EACE,iBAAA;CD/GD;ACsHD;EACE,gCAAA;KAAA,6BAAA;UAAA,wBAAA;EACA,UAAA;CDpHD;AC2HD;EACE,eAAA;CDzHD;ACgID;;;;EAIE,kCAAA;EACA,eAAA;CD9HD;ACgJD;;;;;EAKE,eAAA;EACA,cAAA;EACA,UAAA;CD9ID;ACqJD;EACE,kBAAA;CDnJD;AC6JD;;EAEE,qBAAA;CD3JD;ACsKD;;;;EAIE,2BAAA;EACA,gBAAA;CDpKD;AC2KD;;EAEE,gBAAA;CDzKD;ACgLD;;EAEE,UAAA;EACA,WAAA;CD9KD;ACsLD;EACE,oBAAA;CDpLD;AC+LD;;EAEE,+BAAA;KAAA,4BAAA;UAAA,uBAAA;EACA,WAAA;CD7LD;ACsMD;;EAEE,aAAA;CDpMD;AC4MD;EACE,8BAAA;EACA,gCAAA;KAAA,6BAAA;UAAA,wBAAA;CD1MD;ACmND;;EAEE,yBAAA;CDjND;ACwND;EACE,0BAAA;EACA,cAAA;EACA,+BAAA;CDtND;AC8ND;EACE,UAAA;EACA,WAAA;CD5ND;ACmOD;EACE,eAAA;CDjOD;ACyOD;EACE,kBAAA;CDvOD;ACiPD;EACE,0BAAA;EACA,kBAAA;CD/OD;ACkPD;;EAEE,WAAA;CDhPD;AACD,qFAAqF;AElFrF;EA7FI;;;IAGI,mCAAA;IACA,uBAAA;IACA,oCAAA;YAAA,4BAAA;IACA,6BAAA;GFkLL;EE/KC;;IAEI,2BAAA;GFiLL;EE9KC;IACI,6BAAA;GFgLL;EE7KC;IACI,8BAAA;GF+KL;EE1KC;;IAEI,YAAA;GF4KL;EEzKC;;IAEI,uBAAA;IACA,yBAAA;GF2KL;EExKC;IACI,4BAAA;GF0KL;EEvKC;;IAEI,yBAAA;GFyKL;EEtKC;IACI,2BAAA;GFwKL;EErKC;;;IAGI,WAAA;IACA,UAAA;GFuKL;EEpKC;;IAEI,wBAAA;GFsKL;EEhKC;IACI,cAAA;GFkKL;EEhKC;;IAGQ,kCAAA;GFiKT;EE9JC;IACI,uBAAA;GFgKL;EE7JC;IACI,qCAAA;GF+JL;EEhKC;;IAKQ,kCAAA;GF+JT;EE5JC;;IAGQ,kCAAA;GF6JT;CACF;AGnPD;EACE,oCAAA;EACA,sDAAA;EACA,gYAAA;CHqPD;AG7OD;EACE,mBAAA;EACA,SAAA;EACA,sBAAA;EACA,oCAAA;EACA,mBAAA;EACA,oBAAA;EACA,eAAA;EACA,oCAAA;EACA,mCAAA;CH+OD;AG3OmC;EAAW,eAAA;CH8O9C;AG7OmC;EAAW,eAAA;CHgP9C;AG9OmC;;EAAW,iBAAA;CHkP9C;AGjPmC;EAAW,iBAAA;CHoP9C;AGnPmC;EAAW,iBAAA;CHsP9C;AGrPmC;EAAW,iBAAA;CHwP9C;AGvPmC;EAAW,iBAAA;CH0P9C;AGzPmC;EAAW,iBAAA;CH4P9C;AG3PmC;EAAW,iBAAA;CH8P9C;AG7PmC;EAAW,iBAAA;CHgQ9C;AG/PmC;EAAW,iBAAA;CHkQ9C;AGjQmC;EAAW,iBAAA;CHoQ9C;AGnQmC;EAAW,iBAAA;CHsQ9C;AGrQmC;EAAW,iBAAA;CHwQ9C;AGvQmC;EAAW,iBAAA;CH0Q9C;AGzQmC;EAAW,iBAAA;CH4Q9C;AG3QmC;EAAW,iBAAA;CH8Q9C;AG7QmC;EAAW,iBAAA;CHgR9C;AG/QmC;EAAW,iBAAA;CHkR9C;AGjRmC;EAAW,iBAAA;CHoR9C;AGnRmC;EAAW,iBAAA;CHsR9C;AGrRmC;EAAW,iBAAA;CHwR9C;AGvRmC;EAAW,iBAAA;CH0R9C;AGzRmC;EAAW,iBAAA;CH4R9C;AG3RmC;EAAW,iBAAA;CH8R9C;AG7RmC;EAAW,iBAAA;CHgS9C;AG/RmC;EAAW,iBAAA;CHkS9C;AGjSmC;EAAW,iBAAA;CHoS9C;AGnSmC;EAAW,iBAAA;CHsS9C;AGrSmC;EAAW,iBAAA;CHwS9C;AGvSmC;EAAW,iBAAA;CH0S9C;AGzSmC;EAAW,iBAAA;CH4S9C;AG3SmC;EAAW,iBAAA;CH8S9C;AG7SmC;EAAW,iBAAA;CHgT9C;AG/SmC;EAAW,iBAAA;CHkT9C;AGjTmC;EAAW,iBAAA;CHoT9C;AGnTmC;EAAW,iBAAA;CHsT9C;AGrTmC;EAAW,iBAAA;CHwT9C;AGvTmC;EAAW,iBAAA;CH0T9C;AGzTmC;EAAW,iBAAA;CH4T9C;AG3TmC;EAAW,iBAAA;CH8T9C;AG7TmC;EAAW,iBAAA;CHgU9C;AG/TmC;EAAW,iBAAA;CHkU9C;AGjUmC;EAAW,iBAAA;CHoU9C;AGnUmC;EAAW,iBAAA;CHsU9C;AGrUmC;EAAW,iBAAA;CHwU9C;AGvUmC;EAAW,iBAAA;CH0U9C;AGzUmC;EAAW,iBAAA;CH4U9C;AG3UmC;EAAW,iBAAA;CH8U9C;AG7UmC;EAAW,iBAAA;CHgV9C;AG/UmC;EAAW,iBAAA;CHkV9C;AGjVmC;EAAW,iBAAA;CHoV9C;AGnVmC;EAAW,iBAAA;CHsV9C;AGrVmC;EAAW,iBAAA;CHwV9C;AGvVmC;EAAW,iBAAA;CH0V9C;AGzVmC;EAAW,iBAAA;CH4V9C;AG3VmC;EAAW,iBAAA;CH8V9C;AG7VmC;EAAW,iBAAA;CHgW9C;AG/VmC;EAAW,iBAAA;CHkW9C;AGjWmC;EAAW,iBAAA;CHoW9C;AGnWmC;EAAW,iBAAA;CHsW9C;AGrWmC;EAAW,iBAAA;CHwW9C;AGvWmC;EAAW,iBAAA;CH0W9C;AGzWmC;EAAW,iBAAA;CH4W9C;AG3WmC;EAAW,iBAAA;CH8W9C;AG7WmC;EAAW,iBAAA;CHgX9C;AG/WmC;EAAW,iBAAA;CHkX9C;AGjXmC;EAAW,iBAAA;CHoX9C;AGnXmC;EAAW,iBAAA;CHsX9C;AGrXmC;EAAW,iBAAA;CHwX9C;AGvXmC;EAAW,iBAAA;CH0X9C;AGzXmC;EAAW,iBAAA;CH4X9C;AG3XmC;EAAW,iBAAA;CH8X9C;AG7XmC;EAAW,iBAAA;CHgY9C;AG/XmC;EAAW,iBAAA;CHkY9C;AGjYmC;EAAW,iBAAA;CHoY9C;AGnYmC;EAAW,iBAAA;CHsY9C;AGrYmC;EAAW,iBAAA;CHwY9C;AGvYmC;EAAW,iBAAA;CH0Y9C;AGzYmC;EAAW,iBAAA;CH4Y9C;AG3YmC;EAAW,iBAAA;CH8Y9C;AG7YmC;EAAW,iBAAA;CHgZ9C;AG/YmC;EAAW,iBAAA;CHkZ9C;AGjZmC;EAAW,iBAAA;CHoZ9C;AGnZmC;EAAW,iBAAA;CHsZ9C;AGrZmC;EAAW,iBAAA;CHwZ9C;AGvZmC;EAAW,iBAAA;CH0Z9C;AGzZmC;EAAW,iBAAA;CH4Z9C;AG3ZmC;EAAW,iBAAA;CH8Z9C;AG7ZmC;EAAW,iBAAA;CHga9C;AG/ZmC;EAAW,iBAAA;CHka9C;AGjamC;EAAW,iBAAA;CHoa9C;AGnamC;EAAW,iBAAA;CHsa9C;AGramC;EAAW,iBAAA;CHwa9C;AGvamC;EAAW,iBAAA;CH0a9C;AGzamC;EAAW,iBAAA;CH4a9C;AG3amC;EAAW,iBAAA;CH8a9C;AG7amC;EAAW,iBAAA;CHgb9C;AG/amC;EAAW,iBAAA;CHkb9C;AGjbmC;EAAW,iBAAA;CHob9C;AGnbmC;EAAW,iBAAA;CHsb9C;AGrbmC;EAAW,iBAAA;CHwb9C;AGvbmC;EAAW,iBAAA;CH0b9C;AGzbmC;EAAW,iBAAA;CH4b9C;AG3bmC;EAAW,iBAAA;CH8b9C;AG7bmC;EAAW,iBAAA;CHgc9C;AG/bmC;EAAW,iBAAA;CHkc9C;AGjcmC;EAAW,iBAAA;CHoc9C;AGncmC;EAAW,iBAAA;CHsc9C;AGrcmC;EAAW,iBAAA;CHwc9C;AGvcmC;EAAW,iBAAA;CH0c9C;AGzcmC;EAAW,iBAAA;CH4c9C;AG3cmC;EAAW,iBAAA;CH8c9C;AG7cmC;EAAW,iBAAA;CHgd9C;AG/cmC;EAAW,iBAAA;CHkd9C;AGjdmC;EAAW,iBAAA;CHod9C;AGndmC;EAAW,iBAAA;CHsd9C;AGrdmC;EAAW,iBAAA;CHwd9C;AGvdmC;EAAW,iBAAA;CH0d9C;AGzdmC;EAAW,iBAAA;CH4d9C;AG3dmC;EAAW,iBAAA;CH8d9C;AG7dmC;EAAW,iBAAA;CHge9C;AG/dmC;EAAW,iBAAA;CHke9C;AGjemC;EAAW,iBAAA;CHoe9C;AGnemC;EAAW,iBAAA;CHse9C;AGremC;EAAW,iBAAA;CHwe9C;AGvemC;EAAW,iBAAA;CH0e9C;AGzemC;EAAW,iBAAA;CH4e9C;AG3emC;EAAW,iBAAA;CH8e9C;AG7emC;EAAW,iBAAA;CHgf9C;AG/emC;EAAW,iBAAA;CHkf9C;AGjfmC;EAAW,iBAAA;CHof9C;AGnfmC;EAAW,iBAAA;CHsf9C;AGrfmC;EAAW,iBAAA;CHwf9C;AGvfmC;EAAW,iBAAA;CH0f9C;AGzfmC;EAAW,iBAAA;CH4f9C;AG3fmC;EAAW,iBAAA;CH8f9C;AG7fmC;EAAW,iBAAA;CHggB9C;AG/fmC;EAAW,iBAAA;CHkgB9C;AGjgBmC;EAAW,iBAAA;CHogB9C;AGngBmC;EAAW,iBAAA;CHsgB9C;AGrgBmC;EAAW,iBAAA;CHwgB9C;AGvgBmC;EAAW,iBAAA;CH0gB9C;AGzgBmC;EAAW,iBAAA;CH4gB9C;AG3gBmC;EAAW,iBAAA;CH8gB9C;AG7gBmC;EAAW,iBAAA;CHghB9C;AG/gBmC;EAAW,iBAAA;CHkhB9C;AGjhBmC;EAAW,iBAAA;CHohB9C;AGnhBmC;EAAW,iBAAA;CHshB9C;AGrhBmC;EAAW,iBAAA;CHwhB9C;AGvhBmC;EAAW,iBAAA;CH0hB9C;AGzhBmC;EAAW,iBAAA;CH4hB9C;AG3hBmC;EAAW,iBAAA;CH8hB9C;AG7hBmC;EAAW,iBAAA;CHgiB9C;AG/hBmC;EAAW,iBAAA;CHkiB9C;AGjiBmC;EAAW,iBAAA;CHoiB9C;AGniBmC;EAAW,iBAAA;CHsiB9C;AGriBmC;EAAW,iBAAA;CHwiB9C;AGviBmC;EAAW,iBAAA;CH0iB9C;AGziBmC;EAAW,iBAAA;CH4iB9C;AG3iBmC;EAAW,iBAAA;CH8iB9C;AG7iBmC;EAAW,iBAAA;CHgjB9C;AG/iBmC;EAAW,iBAAA;CHkjB9C;AGjjBmC;EAAW,iBAAA;CHojB9C;AGnjBmC;EAAW,iBAAA;CHsjB9C;AGrjBmC;EAAW,iBAAA;CHwjB9C;AGvjBmC;EAAW,iBAAA;CH0jB9C;AGzjBmC;EAAW,iBAAA;CH4jB9C;AG3jBmC;EAAW,iBAAA;CH8jB9C;AG7jBmC;EAAW,iBAAA;CHgkB9C;AG/jBmC;EAAW,iBAAA;CHkkB9C;AGjkBmC;EAAW,iBAAA;CHokB9C;AGnkBmC;EAAW,iBAAA;CHskB9C;AGrkBmC;EAAW,iBAAA;CHwkB9C;AGvkBmC;EAAW,iBAAA;CH0kB9C;AGzkBmC;EAAW,iBAAA;CH4kB9C;AG3kBmC;EAAW,iBAAA;CH8kB9C;AG7kBmC;EAAW,iBAAA;CHglB9C;AG/kBmC;EAAW,iBAAA;CHklB9C;AGjlBmC;EAAW,iBAAA;CHolB9C;AGnlBmC;EAAW,iBAAA;CHslB9C;AGrlBmC;EAAW,iBAAA;CHwlB9C;AGvlBmC;EAAW,iBAAA;CH0lB9C;AGzlBmC;EAAW,iBAAA;CH4lB9C;AG3lBmC;EAAW,iBAAA;CH8lB9C;AG7lBmC;EAAW,iBAAA;CHgmB9C;AG/lBmC;EAAW,iBAAA;CHkmB9C;AGjmBmC;EAAW,iBAAA;CHomB9C;AGnmBmC;EAAW,iBAAA;CHsmB9C;AGrmBmC;EAAW,iBAAA;CHwmB9C;AGvmBmC;EAAW,iBAAA;CH0mB9C;AGzmBmC;EAAW,iBAAA;CH4mB9C;AG3mBmC;EAAW,iBAAA;CH8mB9C;AG7mBmC;EAAW,iBAAA;CHgnB9C;AG/mBmC;EAAW,iBAAA;CHknB9C;AGjnBmC;EAAW,iBAAA;CHonB9C;AGnnBmC;EAAW,iBAAA;CHsnB9C;AGrnBmC;EAAW,iBAAA;CHwnB9C;AGvnBmC;EAAW,iBAAA;CH0nB9C;AGznBmC;EAAW,iBAAA;CH4nB9C;AG3nBmC;EAAW,iBAAA;CH8nB9C;AG7nBmC;EAAW,iBAAA;CHgoB9C;AG/nBmC;EAAW,iBAAA;CHkoB9C;AGjoBmC;EAAW,iBAAA;CHooB9C;AGnoBmC;EAAW,iBAAA;CHsoB9C;AGroBmC;EAAW,iBAAA;CHwoB9C;AG/nBmC;EAAW,iBAAA;CHkoB9C;AGjoBmC;EAAW,iBAAA;CHooB9C;AGnoBmC;EAAW,iBAAA;CHsoB9C;AGroBmC;EAAW,iBAAA;CHwoB9C;AGvoBmC;EAAW,iBAAA;CH0oB9C;AGzoBmC;EAAW,iBAAA;CH4oB9C;AG3oBmC;EAAW,iBAAA;CH8oB9C;AG7oBmC;EAAW,iBAAA;CHgpB9C;AG/oBmC;EAAW,iBAAA;CHkpB9C;AGjpBmC;EAAW,iBAAA;CHopB9C;AGnpBmC;EAAW,iBAAA;CHspB9C;AGrpBmC;EAAW,iBAAA;CHwpB9C;AGvpBmC;EAAW,iBAAA;CH0pB9C;AGzpBmC;EAAW,iBAAA;CH4pB9C;AG3pBmC;EAAW,iBAAA;CH8pB9C;AG7pBmC;EAAW,iBAAA;CHgqB9C;AG/pBmC;EAAW,iBAAA;CHkqB9C;AGjqBmC;EAAW,iBAAA;CHoqB9C;AGnqBmC;EAAW,iBAAA;CHsqB9C;AGrqBmC;EAAW,iBAAA;CHwqB9C;AGvqBmC;EAAW,iBAAA;CH0qB9C;AGzqBmC;EAAW,iBAAA;CH4qB9C;AG3qBmC;EAAW,iBAAA;CH8qB9C;AG7qBmC;EAAW,iBAAA;CHgrB9C;AG/qBmC;EAAW,iBAAA;CHkrB9C;AGjrBmC;EAAW,iBAAA;CHorB9C;AGnrBmC;EAAW,iBAAA;CHsrB9C;AGrrBmC;EAAW,iBAAA;CHwrB9C;AGvrBmC;EAAW,iBAAA;CH0rB9C;AGzrBmC;EAAW,iBAAA;CH4rB9C;AG3rBmC;EAAW,iBAAA;CH8rB9C;AG7rBmC;EAAW,iBAAA;CHgsB9C;AG/rBmC;EAAW,iBAAA;CHksB9C;AGjsBmC;EAAW,iBAAA;CHosB9C;AGnsBmC;EAAW,iBAAA;CHssB9C;AGrsBmC;EAAW,iBAAA;CHwsB9C;AGvsBmC;EAAW,iBAAA;CH0sB9C;AGzsBmC;EAAW,iBAAA;CH4sB9C;AG3sBmC;EAAW,iBAAA;CH8sB9C;AG7sBmC;EAAW,iBAAA;CHgtB9C;AG/sBmC;EAAW,iBAAA;CHktB9C;AGjtBmC;EAAW,iBAAA;CHotB9C;AGntBmC;EAAW,iBAAA;CHstB9C;AGrtBmC;EAAW,iBAAA;CHwtB9C;AGvtBmC;EAAW,iBAAA;CH0tB9C;AGztBmC;EAAW,iBAAA;CH4tB9C;AG3tBmC;EAAW,iBAAA;CH8tB9C;AG7tBmC;EAAW,iBAAA;CHguB9C;AG/tBmC;EAAW,iBAAA;CHkuB9C;AGjuBmC;EAAW,iBAAA;CHouB9C;AGnuBmC;EAAW,iBAAA;CHsuB9C;AGruBmC;EAAW,iBAAA;CHwuB9C;AGvuBmC;EAAW,iBAAA;CH0uB9C;AGzuBmC;EAAW,iBAAA;CH4uB9C;AG3uBmC;EAAW,iBAAA;CH8uB9C;AG7uBmC;EAAW,iBAAA;CHgvB9C;AIthCD;ECgEE,+BAAA;EACG,4BAAA;EACK,uBAAA;CLy9BT;AIxhCD;;EC6DE,+BAAA;EACG,4BAAA;EACK,uBAAA;CL+9BT;AIthCD;EACE,gBAAA;EACA,8CAAA;CJwhCD;AIrhCD;EACE,4DAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,0BAAA;CJuhCD;AInhCD;;;;EAIE,qBAAA;EACA,mBAAA;EACA,qBAAA;CJqhCD;AI/gCD;EACE,eAAA;EACA,sBAAA;CJihCD;AI/gCC;;EAEE,eAAA;EACA,2BAAA;CJihCH;AI9gCC;EErDA,qBAAA;EAEA,2CAAA;EACA,qBAAA;CNqkCD;AIxgCD;EACE,UAAA;CJ0gCD;AIpgCD;EACE,uBAAA;CJsgCD;AIlgCD;;;;;EGvEE,eAAA;EACA,gBAAA;EACA,aAAA;CPglCD;AItgCD;EACE,mBAAA;CJwgCD;AIlgCD;EACE,aAAA;EACA,wBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;EC6FA,yCAAA;EACK,oCAAA;EACG,iCAAA;EEvLR,sBAAA;EACA,gBAAA;EACA,aAAA;CPgmCD;AIlgCD;EACE,mBAAA;CJogCD;AI9/BD;EACE,iBAAA;EACA,oBAAA;EACA,UAAA;EACA,8BAAA;CJggCD;AIx/BD;EACE,mBAAA;EACA,WAAA;EACA,YAAA;EACA,aAAA;EACA,WAAA;EACA,iBAAA;EACA,uBAAA;EACA,UAAA;CJ0/BD;AIl/BC;;EAEE,iBAAA;EACA,YAAA;EACA,aAAA;EACA,UAAA;EACA,kBAAA;EACA,WAAA;CJo/BH;AIz+BD;EACE,gBAAA;CJ2+BD;AQloCD;;;;;;;;;;;;EAEE,qBAAA;EACA,iBAAA;EACA,iBAAA;EACA,eAAA;CR8oCD;AQnpCD;;;;;;;;;;;;;;;;;;;;;;;;EASI,oBAAA;EACA,eAAA;EACA,eAAA;CRoqCH;AQhqCD;;;;;;EAGE,iBAAA;EACA,oBAAA;CRqqCD;AQzqCD;;;;;;;;;;;;EAQI,eAAA;CR+qCH;AQ5qCD;;;;;;EAGE,iBAAA;EACA,oBAAA;CRirCD;AQrrCD;;;;;;;;;;;;EAQI,eAAA;CR2rCH;AQvrCD;;EAAU,gBAAA;CR2rCT;AQ1rCD;;EAAU,gBAAA;CR8rCT;AQ7rCD;;EAAU,gBAAA;CRisCT;AQhsCD;;EAAU,gBAAA;CRosCT;AQnsCD;;EAAU,gBAAA;CRusCT;AQtsCD;;EAAU,gBAAA;CR0sCT;AQpsCD;EACE,iBAAA;CRssCD;AQnsCD;EACE,oBAAA;EACA,gBAAA;EACA,iBAAA;EACA,iBAAA;CRqsCD;AQhsCD;EAAA;IAFI,gBAAA;GRssCD;CACF;AQ9rCD;;EAEE,eAAA;CRgsCD;AQ7rCD;;EAEE,0BAAA;EACA,cAAA;CR+rCD;AQ3rCD;EAAuB,iBAAA;CR8rCtB;AQ7rCD;EAAuB,kBAAA;CRgsCtB;AQ/rCD;EAAuB,mBAAA;CRksCtB;AQjsCD;EAAuB,oBAAA;CRosCtB;AQnsCD;EAAuB,oBAAA;CRssCtB;AQnsCD;EAAuB,0BAAA;CRssCtB;AQrsCD;EAAuB,0BAAA;CRwsCtB;AQvsCD;EAAuB,2BAAA;CR0sCtB;AQvsCD;EACE,eAAA;CRysCD;AQvsCD;ECrGE,eAAA;CT+yCD;AS9yCC;;EAEE,eAAA;CTgzCH;AQ3sCD;ECxGE,eAAA;CTszCD;ASrzCC;;EAEE,eAAA;CTuzCH;AQ/sCD;EC3GE,eAAA;CT6zCD;AS5zCC;;EAEE,eAAA;CT8zCH;AQntCD;EC9GE,eAAA;CTo0CD;ASn0CC;;EAEE,eAAA;CTq0CH;AQvtCD;ECjHE,eAAA;CT20CD;AS10CC;;EAEE,eAAA;CT40CH;AQvtCD;EAGE,YAAA;EE3HA,0BAAA;CVm1CD;AUl1CC;;EAEE,0BAAA;CVo1CH;AQztCD;EE9HE,0BAAA;CV01CD;AUz1CC;;EAEE,0BAAA;CV21CH;AQ7tCD;EEjIE,0BAAA;CVi2CD;AUh2CC;;EAEE,0BAAA;CVk2CH;AQjuCD;EEpIE,0BAAA;CVw2CD;AUv2CC;;EAEE,0BAAA;CVy2CH;AQruCD;EEvIE,0BAAA;CV+2CD;AU92CC;;EAEE,0BAAA;CVg3CH;AQpuCD;EACE,oBAAA;EACA,oBAAA;EACA,iCAAA;CRsuCD;AQ9tCD;;EAEE,cAAA;EACA,oBAAA;CRguCD;AQnuCD;;;;EAMI,iBAAA;CRmuCH;AQ5tCD;EACE,gBAAA;EACA,iBAAA;CR8tCD;AQ1tCD;EALE,gBAAA;EACA,iBAAA;EAMA,kBAAA;CR6tCD;AQ/tCD;EAKI,sBAAA;EACA,kBAAA;EACA,mBAAA;CR6tCH;AQxtCD;EACE,cAAA;EACA,oBAAA;CR0tCD;AQxtCD;;EAEE,wBAAA;CR0tCD;AQxtCD;EACE,kBAAA;CR0tCD;AQxtCD;EACE,eAAA;CR0tCD;AQjsCD;EAAA;IAVM,YAAA;IACA,aAAA;IACA,YAAA;IACA,kBAAA;IGtNJ,iBAAA;IACA,wBAAA;IACA,oBAAA;GXs6CC;EQ3sCH;IAHM,mBAAA;GRitCH;CACF;AQxsCD;;EAGE,aAAA;EACA,kCAAA;CRysCD;AQvsCD;EACE,eAAA;EA9IqB,0BAAA;CRw1CtB;AQrsCD;EACE,mBAAA;EACA,iBAAA;EACA,kBAAA;EACA,+BAAA;CRusCD;AQlsCG;;;EACE,iBAAA;CRssCL;AQhtCD;;;EAmBI,eAAA;EACA,eAAA;EACA,wBAAA;EACA,eAAA;CRksCH;AQhsCG;;;EACE,uBAAA;CRosCL;AQ5rCD;;EAEE,oBAAA;EACA,gBAAA;EACA,gCAAA;EACA,eAAA;EACA,kBAAA;CR8rCD;AQxrCG;;;;;;EAAW,YAAA;CRgsCd;AQ/rCG;;;;;;EACE,uBAAA;CRssCL;AQhsCD;EACE,oBAAA;EACA,mBAAA;EACA,wBAAA;CRksCD;AYx+CD;;;;EAIE,+DAAA;CZ0+CD;AYt+CD;EACE,iBAAA;EACA,eAAA;EACA,eAAA;EACA,0BAAA;EACA,mBAAA;CZw+CD;AYp+CD;EACE,iBAAA;EACA,eAAA;EACA,eAAA;EACA,0BAAA;EACA,mBAAA;EACA,uDAAA;UAAA,+CAAA;CZs+CD;AY5+CD;EASI,WAAA;EACA,gBAAA;EACA,kBAAA;EACA,yBAAA;UAAA,iBAAA;CZs+CH;AYj+CD;EACE,eAAA;EACA,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,wBAAA;EACA,sBAAA;EACA,sBAAA;EACA,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;CZm+CD;AY9+CD;EAeI,WAAA;EACA,mBAAA;EACA,eAAA;EACA,sBAAA;EACA,8BAAA;EACA,iBAAA;CZk+CH;AY79CD;EACE,kBAAA;EACA,mBAAA;CZ+9CD;AazhDD;ECHE,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,oBAAA;Cd+hDD;AazhDC;EAAA;IAFE,aAAA;Gb+hDD;CACF;Aa3hDC;EAAA;IAFE,aAAA;GbiiDD;CACF;Aa7hDD;EAAA;IAFI,cAAA;GbmiDD;CACF;Aa1hDD;ECvBE,mBAAA;EACA,kBAAA;EACA,mBAAA;EACA,oBAAA;CdojDD;AavhDD;ECvBE,mBAAA;EACA,oBAAA;CdijDD;AejjDG;EACE,mBAAA;EAEA,gBAAA;EAEA,mBAAA;EACA,oBAAA;CfijDL;AejiDG;EACE,YAAA;CfmiDL;Ae5hDC;EACE,YAAA;Cf8hDH;Ae/hDC;EACE,oBAAA;CfiiDH;AeliDC;EACE,oBAAA;CfoiDH;AeriDC;EACE,WAAA;CfuiDH;AexiDC;EACE,oBAAA;Cf0iDH;Ae3iDC;EACE,oBAAA;Cf6iDH;Ae9iDC;EACE,WAAA;CfgjDH;AejjDC;EACE,oBAAA;CfmjDH;AepjDC;EACE,oBAAA;CfsjDH;AevjDC;EACE,WAAA;CfyjDH;Ae1jDC;EACE,oBAAA;Cf4jDH;Ae7jDC;EACE,mBAAA;Cf+jDH;AejjDC;EACE,YAAA;CfmjDH;AepjDC;EACE,oBAAA;CfsjDH;AevjDC;EACE,oBAAA;CfyjDH;Ae1jDC;EACE,WAAA;Cf4jDH;Ae7jDC;EACE,oBAAA;Cf+jDH;AehkDC;EACE,oBAAA;CfkkDH;AenkDC;EACE,WAAA;CfqkDH;AetkDC;EACE,oBAAA;CfwkDH;AezkDC;EACE,oBAAA;Cf2kDH;Ae5kDC;EACE,WAAA;Cf8kDH;Ae/kDC;EACE,oBAAA;CfilDH;AellDC;EACE,mBAAA;CfolDH;AehlDC;EACE,YAAA;CfklDH;AelmDC;EACE,WAAA;CfomDH;AermDC;EACE,mBAAA;CfumDH;AexmDC;EACE,mBAAA;Cf0mDH;Ae3mDC;EACE,UAAA;Cf6mDH;Ae9mDC;EACE,mBAAA;CfgnDH;AejnDC;EACE,mBAAA;CfmnDH;AepnDC;EACE,UAAA;CfsnDH;AevnDC;EACE,mBAAA;CfynDH;Ae1nDC;EACE,mBAAA;Cf4nDH;Ae7nDC;EACE,UAAA;Cf+nDH;AehoDC;EACE,mBAAA;CfkoDH;AenoDC;EACE,kBAAA;CfqoDH;AejoDC;EACE,WAAA;CfmoDH;AernDC;EACE,kBAAA;CfunDH;AexnDC;EACE,0BAAA;Cf0nDH;Ae3nDC;EACE,0BAAA;Cf6nDH;Ae9nDC;EACE,iBAAA;CfgoDH;AejoDC;EACE,0BAAA;CfmoDH;AepoDC;EACE,0BAAA;CfsoDH;AevoDC;EACE,iBAAA;CfyoDH;Ae1oDC;EACE,0BAAA;Cf4oDH;Ae7oDC;EACE,0BAAA;Cf+oDH;AehpDC;EACE,iBAAA;CfkpDH;AenpDC;EACE,0BAAA;CfqpDH;AetpDC;EACE,yBAAA;CfwpDH;AezpDC;EACE,gBAAA;Cf2pDH;Aa3pDD;EElCI;IACE,YAAA;GfgsDH;EezrDD;IACE,YAAA;Gf2rDD;Ee5rDD;IACE,oBAAA;Gf8rDD;Ee/rDD;IACE,oBAAA;GfisDD;EelsDD;IACE,WAAA;GfosDD;EersDD;IACE,oBAAA;GfusDD;EexsDD;IACE,oBAAA;Gf0sDD;Ee3sDD;IACE,WAAA;Gf6sDD;Ee9sDD;IACE,oBAAA;GfgtDD;EejtDD;IACE,oBAAA;GfmtDD;EeptDD;IACE,WAAA;GfstDD;EevtDD;IACE,oBAAA;GfytDD;Ee1tDD;IACE,mBAAA;Gf4tDD;Ee9sDD;IACE,YAAA;GfgtDD;EejtDD;IACE,oBAAA;GfmtDD;EeptDD;IACE,oBAAA;GfstDD;EevtDD;IACE,WAAA;GfytDD;Ee1tDD;IACE,oBAAA;Gf4tDD;Ee7tDD;IACE,oBAAA;Gf+tDD;EehuDD;IACE,WAAA;GfkuDD;EenuDD;IACE,oBAAA;GfquDD;EetuDD;IACE,oBAAA;GfwuDD;EezuDD;IACE,WAAA;Gf2uDD;Ee5uDD;IACE,oBAAA;Gf8uDD;Ee/uDD;IACE,mBAAA;GfivDD;Ee7uDD;IACE,YAAA;Gf+uDD;Ee/vDD;IACE,WAAA;GfiwDD;EelwDD;IACE,mBAAA;GfowDD;EerwDD;IACE,mBAAA;GfuwDD;EexwDD;IACE,UAAA;Gf0wDD;Ee3wDD;IACE,mBAAA;Gf6wDD;Ee9wDD;IACE,mBAAA;GfgxDD;EejxDD;IACE,UAAA;GfmxDD;EepxDD;IACE,mBAAA;GfsxDD;EevxDD;IACE,mBAAA;GfyxDD;Ee1xDD;IACE,UAAA;Gf4xDD;Ee7xDD;IACE,mBAAA;Gf+xDD;EehyDD;IACE,kBAAA;GfkyDD;Ee9xDD;IACE,WAAA;GfgyDD;EelxDD;IACE,kBAAA;GfoxDD;EerxDD;IACE,0BAAA;GfuxDD;EexxDD;IACE,0BAAA;Gf0xDD;Ee3xDD;IACE,iBAAA;Gf6xDD;Ee9xDD;IACE,0BAAA;GfgyDD;EejyDD;IACE,0BAAA;GfmyDD;EepyDD;IACE,iBAAA;GfsyDD;EevyDD;IACE,0BAAA;GfyyDD;Ee1yDD;IACE,0BAAA;Gf4yDD;Ee7yDD;IACE,iBAAA;Gf+yDD;EehzDD;IACE,0BAAA;GfkzDD;EenzDD;IACE,yBAAA;GfqzDD;EetzDD;IACE,gBAAA;GfwzDD;CACF;AahzDD;EE3CI;IACE,YAAA;Gf81DH;Eev1DD;IACE,YAAA;Gfy1DD;Ee11DD;IACE,oBAAA;Gf41DD;Ee71DD;IACE,oBAAA;Gf+1DD;Eeh2DD;IACE,WAAA;Gfk2DD;Een2DD;IACE,oBAAA;Gfq2DD;Eet2DD;IACE,oBAAA;Gfw2DD;Eez2DD;IACE,WAAA;Gf22DD;Ee52DD;IACE,oBAAA;Gf82DD;Ee/2DD;IACE,oBAAA;Gfi3DD;Eel3DD;IACE,WAAA;Gfo3DD;Eer3DD;IACE,oBAAA;Gfu3DD;Eex3DD;IACE,mBAAA;Gf03DD;Ee52DD;IACE,YAAA;Gf82DD;Ee/2DD;IACE,oBAAA;Gfi3DD;Eel3DD;IACE,oBAAA;Gfo3DD;Eer3DD;IACE,WAAA;Gfu3DD;Eex3DD;IACE,oBAAA;Gf03DD;Ee33DD;IACE,oBAAA;Gf63DD;Ee93DD;IACE,WAAA;Gfg4DD;Eej4DD;IACE,oBAAA;Gfm4DD;Eep4DD;IACE,oBAAA;Gfs4DD;Eev4DD;IACE,WAAA;Gfy4DD;Ee14DD;IACE,oBAAA;Gf44DD;Ee74DD;IACE,mBAAA;Gf+4DD;Ee34DD;IACE,YAAA;Gf64DD;Ee75DD;IACE,WAAA;Gf+5DD;Eeh6DD;IACE,mBAAA;Gfk6DD;Een6DD;IACE,mBAAA;Gfq6DD;Eet6DD;IACE,UAAA;Gfw6DD;Eez6DD;IACE,mBAAA;Gf26DD;Ee56DD;IACE,mBAAA;Gf86DD;Ee/6DD;IACE,UAAA;Gfi7DD;Eel7DD;IACE,mBAAA;Gfo7DD;Eer7DD;IACE,mBAAA;Gfu7DD;Eex7DD;IACE,UAAA;Gf07DD;Ee37DD;IACE,mBAAA;Gf67DD;Ee97DD;IACE,kBAAA;Gfg8DD;Ee57DD;IACE,WAAA;Gf87DD;Eeh7DD;IACE,kBAAA;Gfk7DD;Een7DD;IACE,0BAAA;Gfq7DD;Eet7DD;IACE,0BAAA;Gfw7DD;Eez7DD;IACE,iBAAA;Gf27DD;Ee57DD;IACE,0BAAA;Gf87DD;Ee/7DD;IACE,0BAAA;Gfi8DD;Eel8DD;IACE,iBAAA;Gfo8DD;Eer8DD;IACE,0BAAA;Gfu8DD;Eex8DD;IACE,0BAAA;Gf08DD;Ee38DD;IACE,iBAAA;Gf68DD;Ee98DD;IACE,0BAAA;Gfg9DD;Eej9DD;IACE,yBAAA;Gfm9DD;Eep9DD;IACE,gBAAA;Gfs9DD;CACF;Aa38DD;EE9CI;IACE,YAAA;Gf4/DH;Eer/DD;IACE,YAAA;Gfu/DD;Eex/DD;IACE,oBAAA;Gf0/DD;Ee3/DD;IACE,oBAAA;Gf6/DD;Ee9/DD;IACE,WAAA;GfggED;EejgED;IACE,oBAAA;GfmgED;EepgED;IACE,oBAAA;GfsgED;EevgED;IACE,WAAA;GfygED;Ee1gED;IACE,oBAAA;Gf4gED;Ee7gED;IACE,oBAAA;Gf+gED;EehhED;IACE,WAAA;GfkhED;EenhED;IACE,oBAAA;GfqhED;EethED;IACE,mBAAA;GfwhED;Ee1gED;IACE,YAAA;Gf4gED;Ee7gED;IACE,oBAAA;Gf+gED;EehhED;IACE,oBAAA;GfkhED;EenhED;IACE,WAAA;GfqhED;EethED;IACE,oBAAA;GfwhED;EezhED;IACE,oBAAA;Gf2hED;Ee5hED;IACE,WAAA;Gf8hED;Ee/hED;IACE,oBAAA;GfiiED;EeliED;IACE,oBAAA;GfoiED;EeriED;IACE,WAAA;GfuiED;EexiED;IACE,oBAAA;Gf0iED;Ee3iED;IACE,mBAAA;Gf6iED;EeziED;IACE,YAAA;Gf2iED;Ee3jED;IACE,WAAA;Gf6jED;Ee9jED;IACE,mBAAA;GfgkED;EejkED;IACE,mBAAA;GfmkED;EepkED;IACE,UAAA;GfskED;EevkED;IACE,mBAAA;GfykED;Ee1kED;IACE,mBAAA;Gf4kED;Ee7kED;IACE,UAAA;Gf+kED;EehlED;IACE,mBAAA;GfklED;EenlED;IACE,mBAAA;GfqlED;EetlED;IACE,UAAA;GfwlED;EezlED;IACE,mBAAA;Gf2lED;Ee5lED;IACE,kBAAA;Gf8lED;Ee1lED;IACE,WAAA;Gf4lED;Ee9kED;IACE,kBAAA;GfglED;EejlED;IACE,0BAAA;GfmlED;EeplED;IACE,0BAAA;GfslED;EevlED;IACE,iBAAA;GfylED;Ee1lED;IACE,0BAAA;Gf4lED;Ee7lED;IACE,0BAAA;Gf+lED;EehmED;IACE,iBAAA;GfkmED;EenmED;IACE,0BAAA;GfqmED;EetmED;IACE,0BAAA;GfwmED;EezmED;IACE,iBAAA;Gf2mED;Ee5mED;IACE,0BAAA;Gf8mED;Ee/mED;IACE,yBAAA;GfinED;EelnED;IACE,gBAAA;GfonED;CACF;AgBxrED;EACE,8BAAA;ChB0rED;AgBxrED;EACE,iBAAA;EACA,oBAAA;EACA,eAAA;EACA,iBAAA;ChB0rED;AgBxrED;EACE,iBAAA;ChB0rED;AgBprED;EACE,YAAA;EACA,gBAAA;EACA,oBAAA;ChBsrED;AgBzrED;;;;;;EAWQ,aAAA;EACA,wBAAA;EACA,oBAAA;EACA,8BAAA;ChBsrEP;AgBpsED;EAoBI,uBAAA;EACA,iCAAA;ChBmrEH;AgBxsED;;;;;;EA8BQ,cAAA;ChBkrEP;AgBhtED;EAoCI,8BAAA;ChB+qEH;AgBntED;EAyCI,0BAAA;ChB6qEH;AgBtqED;;;;;;EAOQ,aAAA;ChBuqEP;AgB5pED;EACE,0BAAA;ChB8pED;AgB/pED;;;;;;EAQQ,0BAAA;ChB+pEP;AgBvqED;;EAeM,yBAAA;ChB4pEL;AgBlpED;EAEI,0BAAA;ChBmpEH;AgB1oED;EAEI,0BAAA;ChB2oEH;AgBloED;EACE,iBAAA;EACA,YAAA;EACA,sBAAA;ChBooED;AgB/nEG;;EACE,iBAAA;EACA,YAAA;EACA,oBAAA;ChBkoEL;AiB9wEC;;;;;;;;;;;;EAOI,0BAAA;CjBqxEL;AiB/wEC;;;;;EAMI,0BAAA;CjBgxEL;AiBnyEC;;;;;;;;;;;;EAOI,0BAAA;CjB0yEL;AiBpyEC;;;;;EAMI,0BAAA;CjBqyEL;AiBxzEC;;;;;;;;;;;;EAOI,0BAAA;CjB+zEL;AiBzzEC;;;;;EAMI,0BAAA;CjB0zEL;AiB70EC;;;;;;;;;;;;EAOI,0BAAA;CjBo1EL;AiB90EC;;;;;EAMI,0BAAA;CjB+0EL;AiBl2EC;;;;;;;;;;;;EAOI,0BAAA;CjBy2EL;AiBn2EC;;;;;EAMI,0BAAA;CjBo2EL;AgBltED;EACE,iBAAA;EACA,kBAAA;ChBotED;AgBvpED;EAAA;IA1DI,YAAA;IACA,oBAAA;IACA,mBAAA;IACA,6CAAA;IACA,0BAAA;GhBqtED;EgB/pEH;IAlDM,iBAAA;GhBotEH;EgBlqEH;;;;;;IAzCY,oBAAA;GhBmtET;EgB1qEH;IAjCM,UAAA;GhB8sEH;EgB7qEH;;;;;;IAxBY,eAAA;GhB6sET;EgBrrEH;;;;;;IApBY,gBAAA;GhBitET;EgB7rEH;;;;IAPY,iBAAA;GhB0sET;CACF;AkBp6ED;EACE,WAAA;EACA,UAAA;EACA,UAAA;EAIA,aAAA;ClBm6ED;AkBh6ED;EACE,eAAA;EACA,YAAA;EACA,WAAA;EACA,oBAAA;EACA,gBAAA;EACA,qBAAA;EACA,eAAA;EACA,UAAA;EACA,iCAAA;ClBk6ED;AkB/5ED;EACE,sBAAA;EACA,gBAAA;EACA,mBAAA;EACA,kBAAA;ClBi6ED;AkBt5ED;Eb4BE,+BAAA;EACG,4BAAA;EACK,uBAAA;CL63ET;AkBt5ED;;EAEE,gBAAA;EACA,mBAAA;EACA,oBAAA;ClBw5ED;AkBr5ED;EACE,eAAA;ClBu5ED;AkBn5ED;EACE,eAAA;EACA,YAAA;ClBq5ED;AkBj5ED;;EAEE,aAAA;ClBm5ED;AkB/4ED;;;EZvEE,qBAAA;EAEA,2CAAA;EACA,qBAAA;CN09ED;AkB/4ED;EACE,eAAA;EACA,iBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;ClBi5ED;AkBv3ED;EACE,eAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,0BAAA;EACA,uBAAA;EACA,0BAAA;EACA,mBAAA;EbxDA,yDAAA;EACQ,iDAAA;EAyHR,uFAAA;EACK,0EAAA;EACG,uEAAA;CL0zET;AmBl8EC;EACE,sBAAA;EACA,WAAA;EdUF,uFAAA;EACQ,+EAAA;CL27ET;AK15EC;EACE,eAAA;EACA,WAAA;CL45EH;AK15EC;EAA0B,eAAA;CL65E3B;AK55EC;EAAgC,eAAA;CL+5EjC;AkB/3EC;;;EAGE,0BAAA;EACA,WAAA;ClBi4EH;AkB93EC;;EAEE,oBAAA;ClBg4EH;AkB53EC;EACE,aAAA;ClB83EH;AkBl3ED;EACE,yBAAA;ClBo3ED;AkB50ED;EAtBI;;;;IACE,kBAAA;GlBw2EH;EkBr2EC;;;;;;;;IAEE,kBAAA;GlB62EH;EkB12EC;;;;;;;;IAEE,kBAAA;GlBk3EH;CACF;AkBx2ED;EACE,oBAAA;ClB02ED;AkBl2ED;;EAEE,mBAAA;EACA,eAAA;EACA,iBAAA;EACA,oBAAA;ClBo2ED;AkBz2ED;;EAQI,iBAAA;EACA,mBAAA;EACA,iBAAA;EACA,oBAAA;EACA,gBAAA;ClBq2EH;AkBl2ED;;;;EAIE,mBAAA;EACA,mBAAA;EACA,mBAAA;ClBo2ED;AkBj2ED;;EAEE,iBAAA;ClBm2ED;AkB/1ED;;EAEE,mBAAA;EACA,sBAAA;EACA,mBAAA;EACA,iBAAA;EACA,uBAAA;EACA,oBAAA;EACA,gBAAA;ClBi2ED;AkB/1ED;;EAEE,cAAA;EACA,kBAAA;ClBi2ED;AkBx1EC;;;;;;EAGE,oBAAA;ClB61EH;AkBv1EC;;;;EAEE,oBAAA;ClB21EH;AkBr1EC;;;;EAGI,oBAAA;ClBw1EL;AkB70ED;EAEE,iBAAA;EACA,oBAAA;EAEA,iBAAA;EACA,iBAAA;ClB60ED;AkB30EC;;EAEE,gBAAA;EACA,iBAAA;ClB60EH;AkBh0ED;EC7PE,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CnBgkFD;AmB9jFC;EACE,aAAA;EACA,kBAAA;CnBgkFH;AmB7jFC;;EAEE,aAAA;CnB+jFH;AkB50ED;EAEI,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;ClB60EH;AkBn1ED;EASI,aAAA;EACA,kBAAA;ClB60EH;AkBv1ED;;EAcI,aAAA;ClB60EH;AkB31ED;EAiBI,aAAA;EACA,iBAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;ClB60EH;AkBz0ED;ECzRE,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CnBqmFD;AmBnmFC;EACE,aAAA;EACA,kBAAA;CnBqmFH;AmBlmFC;;EAEE,aAAA;CnBomFH;AkBr1ED;EAEI,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;ClBs1EH;AkB51ED;EASI,aAAA;EACA,kBAAA;ClBs1EH;AkBh2ED;;EAcI,aAAA;ClBs1EH;AkBp2ED;EAiBI,aAAA;EACA,iBAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;ClBs1EH;AkB70ED;EAEE,mBAAA;ClB80ED;AkBh1ED;EAMI,sBAAA;ClB60EH;AkBz0ED;EACE,mBAAA;EACA,OAAA;EACA,SAAA;EACA,WAAA;EACA,eAAA;EACA,YAAA;EACA,aAAA;EACA,kBAAA;EACA,mBAAA;EACA,qBAAA;ClB20ED;AkBz0ED;;;EAGE,YAAA;EACA,aAAA;EACA,kBAAA;ClB20ED;AkBz0ED;;;EAGE,YAAA;EACA,aAAA;EACA,kBAAA;ClB20ED;AkBv0ED;;;;;;;;;;ECpZI,eAAA;CnBuuFH;AkBn1ED;EChZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLwrFT;AmBtuFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL6rFT;AkB71ED;ECtYI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBsuFH;AkBl2ED;EChYI,eAAA;CnBquFH;AkBl2ED;;;;;;;;;;ECvZI,eAAA;CnBqwFH;AkB92ED;ECnZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLstFT;AmBpwFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CL2tFT;AkBx3ED;ECzYI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBowFH;AkB73ED;ECnYI,eAAA;CnBmwFH;AkB73ED;;;;;;;;;;EC1ZI,eAAA;CnBmyFH;AkBz4ED;ECtZI,sBAAA;Ed+CF,yDAAA;EACQ,iDAAA;CLovFT;AmBlyFG;EACE,sBAAA;Ed4CJ,0EAAA;EACQ,kEAAA;CLyvFT;AkBn5ED;EC5YI,eAAA;EACA,sBAAA;EACA,0BAAA;CnBkyFH;AkBx5ED;ECtYI,eAAA;CnBiyFH;AkBp5EC;EACG,UAAA;ClBs5EJ;AkBp5EC;EACG,OAAA;ClBs5EJ;AkB54ED;EACE,eAAA;EACA,gBAAA;EACA,oBAAA;EACA,eAAA;ClB84ED;AkB3zED;EAAA;IA9DM,sBAAA;IACA,iBAAA;IACA,uBAAA;GlB63EH;EkBj0EH;IAvDM,sBAAA;IACA,YAAA;IACA,uBAAA;GlB23EH;EkBt0EH;IAhDM,sBAAA;GlBy3EH;EkBz0EH;IA5CM,sBAAA;IACA,uBAAA;GlBw3EH;EkB70EH;;;IAtCQ,YAAA;GlBw3EL;EkBl1EH;IAhCM,YAAA;GlBq3EH;EkBr1EH;IA5BM,iBAAA;IACA,uBAAA;GlBo3EH;EkBz1EH;;IApBM,sBAAA;IACA,cAAA;IACA,iBAAA;IACA,uBAAA;GlBi3EH;EkBh2EH;;IAdQ,gBAAA;GlBk3EL;EkBp2EH;;IATM,mBAAA;IACA,eAAA;GlBi3EH;EkBz2EH;IAHM,OAAA;GlB+2EH;CACF;AkBr2ED;;;;EASI,cAAA;EACA,iBAAA;EACA,iBAAA;ClBk2EH;AkB72ED;;EAiBI,iBAAA;ClBg2EH;AkBj3ED;EJhhBE,mBAAA;EACA,oBAAA;Cdo4FD;AkB90EC;EAAA;IAVI,kBAAA;IACA,iBAAA;IACA,iBAAA;GlB41EH;CACF;AkB53ED;EAwCI,YAAA;ClBu1EH;AkBz0EC;EAAA;IAJM,yBAAA;IACA,gBAAA;GlBi1EL;CACF;AkBv0EC;EAAA;IAJM,iBAAA;IACA,gBAAA;GlB+0EL;CACF;AoBl6FD;EACE,sBAAA;EACA,iBAAA;EACA,oBAAA;EACA,mBAAA;EACA,uBAAA;EACA,+BAAA;MAAA,2BAAA;EACA,gBAAA;EACA,uBAAA;EACA,8BAAA;EACA,oBAAA;EC6CA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,mBAAA;EhB4JA,0BAAA;EACG,uBAAA;EACC,sBAAA;EACI,kBAAA;CL6tFT;AoBr6FG;;;;;;EdrBF,qBAAA;EAEA,2CAAA;EACA,qBAAA;CNi8FD;AoBz6FC;;;EAGE,eAAA;EACA,sBAAA;CpB26FH;AoBx6FC;;EAEE,WAAA;EACA,uBAAA;Ef2BF,yDAAA;EACQ,iDAAA;CLg5FT;AoBx6FC;;;EAGE,oBAAA;EE7CF,cAAA;EAGA,0BAAA;EjB8DA,yBAAA;EACQ,iBAAA;CLy5FT;AoBx6FG;;EAEE,qBAAA;CpB06FL;AoBj6FD;EC3DE,eAAA;EACA,0BAAA;EACA,sBAAA;CrB+9FD;AqB79FC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+9FP;AqB79FG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBq+FT;AqBl+FC;;;EAGE,uBAAA;CrBo+FH;AqB/9FG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrB6+FT;AoB/9FD;ECTI,eAAA;EACA,0BAAA;CrB2+FH;AoBh+FD;EC9DE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBiiGD;AqB/hGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBiiGP;AqB/hGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuiGT;AqBpiGC;;;EAGE,uBAAA;CrBsiGH;AqBjiGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrB+iGT;AoB9hGD;ECZI,eAAA;EACA,0BAAA;CrB6iGH;AoB9hGD;EClEE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBmmGD;AqBjmGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBmmGP;AqBjmGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBymGT;AqBtmGC;;;EAGE,uBAAA;CrBwmGH;AqBnmGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBinGT;AoB5lGD;EChBI,eAAA;EACA,0BAAA;CrB+mGH;AoB5lGD;ECtEE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBqqGD;AqBnqGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBqqGP;AqBnqGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB2qGT;AqBxqGC;;;EAGE,uBAAA;CrB0qGH;AqBrqGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBmrGT;AoB1pGD;ECpBI,eAAA;EACA,0BAAA;CrBirGH;AoB1pGD;EC1EE,eAAA;EACA,0BAAA;EACA,sBAAA;CrBuuGD;AqBruGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrBuuGP;AqBruGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB6uGT;AqB1uGC;;;EAGE,uBAAA;CrB4uGH;AqBvuGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBqvGT;AoBxtGD;ECxBI,eAAA;EACA,0BAAA;CrBmvGH;AoBxtGD;EC9EE,eAAA;EACA,0BAAA;EACA,sBAAA;CrByyGD;AqBvyGC;;EAEE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGC;EACE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGC;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrByyGP;AqBvyGG;;;;;;;;;EAGE,eAAA;EACA,0BAAA;EACI,sBAAA;CrB+yGT;AqB5yGC;;;EAGE,uBAAA;CrB8yGH;AqBzyGG;;;;;;;;;;;;;;;;;;EAME,0BAAA;EACI,sBAAA;CrBuzGT;AoBtxGD;EC5BI,eAAA;EACA,0BAAA;CrBqzGH;AoBjxGD;EACE,eAAA;EACA,oBAAA;EACA,iBAAA;CpBmxGD;AoBjxGC;;;;;EAKE,8BAAA;EfnCF,yBAAA;EACQ,iBAAA;CLuzGT;AoBlxGC;;;;EAIE,0BAAA;CpBoxGH;AoBlxGC;;EAEE,eAAA;EACA,2BAAA;EACA,8BAAA;CpBoxGH;AoBhxGG;;;;EAEE,eAAA;EACA,sBAAA;CpBoxGL;AoB3wGD;;ECrEE,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CrBo1GD;AoB9wGD;;ECzEE,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CrB21GD;AoBjxGD;;EC7EE,iBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CrBk2GD;AoBhxGD;EACE,eAAA;EACA,YAAA;CpBkxGD;AoB9wGD;EACE,gBAAA;CpBgxGD;AoBzwGC;;;EACE,YAAA;CpB6wGH;AuBv6GD;EACE,WAAA;ElBoLA,yCAAA;EACK,oCAAA;EACG,iCAAA;CLsvGT;AuB16GC;EACE,WAAA;CvB46GH;AuBx6GD;EACE,cAAA;CvB06GD;AuBx6GC;EAAY,eAAA;CvB26Gb;AuB16GC;EAAY,mBAAA;CvB66Gb;AuB56GC;EAAY,yBAAA;CvB+6Gb;AuB56GD;EACE,mBAAA;EACA,UAAA;EACA,iBAAA;ElBuKA,gDAAA;EACQ,2CAAA;KAAA,wCAAA;EAOR,mCAAA;EACQ,8BAAA;KAAA,2BAAA;EAGR,yCAAA;EACQ,oCAAA;KAAA,iCAAA;CLgwGT;AwB18GD;EACE,sBAAA;EACA,SAAA;EACA,UAAA;EACA,iBAAA;EACA,uBAAA;EACA,uBAAA;EACA,yBAAA;EACA,oCAAA;EACA,mCAAA;CxB48GD;AwBx8GD;;EAEE,mBAAA;CxB08GD;AwBt8GD;EACE,WAAA;CxBw8GD;AwBp8GD;EACE,mBAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,cAAA;EACA,YAAA;EACA,iBAAA;EACA,eAAA;EACA,gBAAA;EACA,iBAAA;EACA,gBAAA;EACA,iBAAA;EACA,0BAAA;EACA,0BAAA;EACA,sCAAA;EACA,mBAAA;EnBsBA,oDAAA;EACQ,4CAAA;EmBrBR,qCAAA;UAAA,6BAAA;CxBu8GD;AwBl8GC;EACE,SAAA;EACA,WAAA;CxBo8GH;AwB79GD;ECzBE,YAAA;EACA,cAAA;EACA,iBAAA;EACA,0BAAA;CzBy/GD;AwBn+GD;EAmCI,eAAA;EACA,kBAAA;EACA,YAAA;EACA,oBAAA;EACA,wBAAA;EACA,eAAA;EACA,oBAAA;CxBm8GH;AwB77GC;;EAEE,sBAAA;EACA,eAAA;EACA,0BAAA;CxB+7GH;AwBz7GC;;;EAGE,eAAA;EACA,sBAAA;EACA,WAAA;EACA,0BAAA;CxB27GH;AwBl7GC;;;EAGE,eAAA;CxBo7GH;AwBh7GC;;EAEE,sBAAA;EACA,8BAAA;EACA,uBAAA;EE3GF,oEAAA;EF6GE,oBAAA;CxBk7GH;AwB76GD;EAGI,eAAA;CxB66GH;AwBh7GD;EAQI,WAAA;CxB26GH;AwBn6GD;EACE,WAAA;EACA,SAAA;CxBq6GD;AwB75GD;EACE,QAAA;EACA,YAAA;CxB+5GD;AwB35GD;EACE,eAAA;EACA,kBAAA;EACA,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,oBAAA;CxB65GD;AwBz5GD;EACE,gBAAA;EACA,QAAA;EACA,SAAA;EACA,UAAA;EACA,OAAA;EACA,aAAA;CxB25GD;AwBv5GD;EACE,SAAA;EACA,WAAA;CxBy5GD;AwBj5GD;;EAII,cAAA;EACA,0BAAA;EACA,4BAAA;EACA,YAAA;CxBi5GH;AwBx5GD;;EAWI,UAAA;EACA,aAAA;EACA,mBAAA;CxBi5GH;AwB53GD;EAXE;IApEA,WAAA;IACA,SAAA;GxB+8GC;EwB54GD;IA1DA,QAAA;IACA,YAAA;GxBy8GC;CACF;A2BzlHD;;EAEE,mBAAA;EACA,sBAAA;EACA,uBAAA;C3B2lHD;A2B/lHD;;EAMI,mBAAA;EACA,YAAA;C3B6lHH;A2B3lHG;;;;;;;;EAIE,WAAA;C3BimHL;A2B3lHD;;;;EAKI,kBAAA;C3B4lHH;A2BvlHD;EACE,kBAAA;C3BylHD;A2B1lHD;;;EAOI,YAAA;C3BwlHH;A2B/lHD;;;EAYI,iBAAA;C3BwlHH;A2BplHD;EACE,iBAAA;C3BslHD;A2BllHD;EACE,eAAA;C3BolHD;A2BnlHC;EClDA,8BAAA;EACG,2BAAA;C5BwoHJ;A2BllHD;;EC/CE,6BAAA;EACG,0BAAA;C5BqoHJ;A2BjlHD;EACE,YAAA;C3BmlHD;A2BjlHD;EACE,iBAAA;C3BmlHD;A2BjlHD;;ECnEE,8BAAA;EACG,2BAAA;C5BwpHJ;A2BhlHD;ECjEE,6BAAA;EACG,0BAAA;C5BopHJ;A2B/kHD;;EAEE,WAAA;C3BilHD;A2BhkHD;EACE,kBAAA;EACA,mBAAA;C3BkkHD;A2BhkHD;EACE,mBAAA;EACA,oBAAA;C3BkkHD;A2B7jHD;EtB/CE,yDAAA;EACQ,iDAAA;CL+mHT;A2B7jHC;EtBnDA,yBAAA;EACQ,iBAAA;CLmnHT;A2B1jHD;EACE,eAAA;C3B4jHD;A2BzjHD;EACE,wBAAA;EACA,uBAAA;C3B2jHD;A2BxjHD;EACE,wBAAA;C3B0jHD;A2BnjHD;;;EAII,eAAA;EACA,YAAA;EACA,YAAA;EACA,gBAAA;C3BojHH;A2B3jHD;EAcM,YAAA;C3BgjHL;A2B9jHD;;;;EAsBI,iBAAA;EACA,eAAA;C3B8iHH;A2BziHC;EACE,iBAAA;C3B2iHH;A2BziHC;EACE,6BAAA;ECpKF,8BAAA;EACC,6BAAA;C5BgtHF;A2B1iHC;EACE,+BAAA;EChLF,2BAAA;EACC,0BAAA;C5B6tHF;A2B1iHD;EACE,iBAAA;C3B4iHD;A2B1iHD;;EC/KE,8BAAA;EACC,6BAAA;C5B6tHF;A2BziHD;EC7LE,2BAAA;EACC,0BAAA;C5ByuHF;A2BriHD;EACE,eAAA;EACA,YAAA;EACA,oBAAA;EACA,0BAAA;C3BuiHD;A2B3iHD;;EAOI,YAAA;EACA,oBAAA;EACA,UAAA;C3BwiHH;A2BjjHD;EAYI,YAAA;C3BwiHH;A2BpjHD;EAgBI,WAAA;C3BuiHH;A2BthHD;;;;EAKM,mBAAA;EACA,uBAAA;EACA,qBAAA;C3BuhHL;A6BjwHD;EACE,mBAAA;EACA,eAAA;EACA,0BAAA;C7BmwHD;A6BhwHC;EACE,YAAA;EACA,gBAAA;EACA,iBAAA;C7BkwHH;A6B3wHD;EAeI,mBAAA;EACA,WAAA;EAKA,YAAA;EAEA,YAAA;EACA,iBAAA;C7B0vHH;A6BjvHD;;;EV8BE,aAAA;EACA,mBAAA;EACA,gBAAA;EACA,uBAAA;EACA,mBAAA;CnBwtHD;AmBttHC;;;EACE,aAAA;EACA,kBAAA;CnB0tHH;AmBvtHC;;;;;;EAEE,aAAA;CnB6tHH;A6BnwHD;;;EVyBE,aAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;CnB+uHD;AmB7uHC;;;EACE,aAAA;EACA,kBAAA;CnBivHH;AmB9uHC;;;;;;EAEE,aAAA;CnBovHH;A6BjxHD;;;EAGE,oBAAA;C7BmxHD;A6BjxHC;;;EACE,iBAAA;C7BqxHH;A6BjxHD;;EAEE,UAAA;EACA,oBAAA;EACA,uBAAA;C7BmxHD;A6B9wHD;EACE,kBAAA;EACA,gBAAA;EACA,oBAAA;EACA,eAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;C7BgxHD;A6B7wHC;EACE,kBAAA;EACA,gBAAA;EACA,mBAAA;C7B+wHH;A6B7wHC;EACE,mBAAA;EACA,gBAAA;EACA,mBAAA;C7B+wHH;A6BnyHD;;EA0BI,cAAA;C7B6wHH;A6BxwHD;;;;;;;EDhGE,8BAAA;EACG,2BAAA;C5Bi3HJ;A6BzwHD;EACE,gBAAA;C7B2wHD;A6BzwHD;;;;;;;EDpGE,6BAAA;EACG,0BAAA;C5Bs3HJ;A6B1wHD;EACE,eAAA;C7B4wHD;A6BvwHD;EACE,mBAAA;EAGA,aAAA;EACA,oBAAA;C7BuwHD;A6B5wHD;EAUI,mBAAA;C7BqwHH;A6B/wHD;EAYM,kBAAA;C7BswHL;A6BnwHG;;;EAGE,WAAA;C7BqwHL;A6BhwHC;;EAGI,mBAAA;C7BiwHL;A6B9vHC;;EAGI,WAAA;EACA,kBAAA;C7B+vHL;A8B15HD;EACE,iBAAA;EACA,gBAAA;EACA,iBAAA;C9B45HD;A8B/5HD;EAOI,mBAAA;EACA,eAAA;C9B25HH;A8Bn6HD;EAWM,mBAAA;EACA,eAAA;EACA,mBAAA;C9B25HL;A8B15HK;;EAEE,sBAAA;EACA,0BAAA;C9B45HP;A8Bv5HG;EACE,eAAA;C9By5HL;A8Bv5HK;;EAEE,eAAA;EACA,sBAAA;EACA,8BAAA;EACA,oBAAA;C9By5HP;A8Bl5HG;;;EAGE,0BAAA;EACA,sBAAA;C9Bo5HL;A8B77HD;ELHE,YAAA;EACA,cAAA;EACA,iBAAA;EACA,0BAAA;CzBm8HD;A8Bn8HD;EA0DI,gBAAA;C9B44HH;A8Bn4HD;EACE,iCAAA;C9Bq4HD;A8Bt4HD;EAGI,YAAA;EAEA,oBAAA;C9Bq4HH;A8B14HD;EASM,kBAAA;EACA,wBAAA;EACA,8BAAA;EACA,2BAAA;C9Bo4HL;A8Bn4HK;EACE,sCAAA;C9Bq4HP;A8B/3HK;;;EAGE,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,iCAAA;EACA,gBAAA;C9Bi4HP;A8B53HC;EAqDA,YAAA;EA8BA,iBAAA;C9B6yHD;A8Bh4HC;EAwDE,YAAA;C9B20HH;A8Bn4HC;EA0DI,mBAAA;EACA,mBAAA;C9B40HL;A8Bv4HC;EAgEE,UAAA;EACA,WAAA;C9B00HH;A8B9zHD;EAAA;IAPM,oBAAA;IACA,UAAA;G9By0HH;E8Bn0HH;IAJQ,iBAAA;G9B00HL;CACF;A8Bp5HC;EAuFE,gBAAA;EACA,mBAAA;C9Bg0HH;A8Bx5HC;;;EA8FE,0BAAA;C9B+zHH;A8BjzHD;EAAA;IATM,iCAAA;IACA,2BAAA;G9B8zHH;E8BtzHH;;;IAHM,6BAAA;G9B8zHH;CACF;A8B/5HD;EAEI,YAAA;C9Bg6HH;A8Bl6HD;EAMM,mBAAA;C9B+5HL;A8Br6HD;EASM,iBAAA;C9B+5HL;A8B15HK;;;EAGE,eAAA;EACA,0BAAA;C9B45HP;A8Bp5HD;EAEI,YAAA;C9Bq5HH;A8Bv5HD;EAIM,gBAAA;EACA,eAAA;C9Bs5HL;A8B14HD;EACE,YAAA;C9B44HD;A8B74HD;EAII,YAAA;C9B44HH;A8Bh5HD;EAMM,mBAAA;EACA,mBAAA;C9B64HL;A8Bp5HD;EAYI,UAAA;EACA,WAAA;C9B24HH;A8B/3HD;EAAA;IAPM,oBAAA;IACA,UAAA;G9B04HH;E8Bp4HH;IAJQ,iBAAA;G9B24HL;CACF;A8Bn4HD;EACE,iBAAA;C9Bq4HD;A8Bt4HD;EAKI,gBAAA;EACA,mBAAA;C9Bo4HH;A8B14HD;;;EAYI,0BAAA;C9Bm4HH;A8Br3HD;EAAA;IATM,iCAAA;IACA,2BAAA;G9Bk4HH;E8B13HH;;;IAHM,6BAAA;G9Bk4HH;CACF;A8Bz3HD;EAEI,cAAA;C9B03HH;A8B53HD;EAKI,eAAA;C9B03HH;A8Bj3HD;EAEE,iBAAA;EF3OA,2BAAA;EACC,0BAAA;C5B8lIF;A+BxlID;EACE,mBAAA;EACA,iBAAA;EACA,oBAAA;EACA,8BAAA;C/B0lID;A+BllID;EAAA;IAFI,mBAAA;G/BwlID;CACF;A+BzkID;EAAA;IAFI,YAAA;G/B+kID;CACF;A+BjkID;EACE,oBAAA;EACA,oBAAA;EACA,mBAAA;EACA,kCAAA;EACA,2DAAA;UAAA,mDAAA;EAEA,kCAAA;C/BkkID;A+BhkIC;EACE,iBAAA;C/BkkIH;A+BtiID;EAAA;IAxBI,YAAA;IACA,cAAA;IACA,yBAAA;YAAA,iBAAA;G/BkkID;E+BhkIC;IACE,0BAAA;IACA,wBAAA;IACA,kBAAA;IACA,6BAAA;G/BkkIH;E+B/jIC;IACE,oBAAA;G/BikIH;E+B5jIC;;;IAGE,gBAAA;IACA,iBAAA;G/B8jIH;CACF;A+B1jID;;EAGI,kBAAA;C/B2jIH;A+BtjIC;EAAA;;IAFI,kBAAA;G/B6jIH;CACF;A+BpjID;;;;EAII,oBAAA;EACA,mBAAA;C/BsjIH;A+BhjIC;EAAA;;;;IAHI,gBAAA;IACA,eAAA;G/B0jIH;CACF;A+B9iID;EACE,cAAA;EACA,sBAAA;C/BgjID;A+B3iID;EAAA;IAFI,iBAAA;G/BijID;CACF;A+B7iID;;EAEE,gBAAA;EACA,SAAA;EACA,QAAA;EACA,cAAA;C/B+iID;A+BziID;EAAA;;IAFI,iBAAA;G/BgjID;CACF;A+B9iID;EACE,OAAA;EACA,sBAAA;C/BgjID;A+B9iID;EACE,UAAA;EACA,iBAAA;EACA,sBAAA;C/BgjID;A+B1iID;EACE,YAAA;EACA,mBAAA;EACA,gBAAA;EACA,kBAAA;EACA,aAAA;C/B4iID;A+B1iIC;;EAEE,sBAAA;C/B4iIH;A+BrjID;EAaI,eAAA;C/B2iIH;A+BliID;EALI;;IAEE,mBAAA;G/B0iIH;CACF;A+BhiID;EACE,mBAAA;EACA,aAAA;EACA,mBAAA;EACA,kBAAA;EC9LA,gBAAA;EACA,mBAAA;ED+LA,8BAAA;EACA,uBAAA;EACA,8BAAA;EACA,mBAAA;C/BmiID;A+B/hIC;EACE,WAAA;C/BiiIH;A+B/iID;EAmBI,eAAA;EACA,YAAA;EACA,YAAA;EACA,mBAAA;C/B+hIH;A+BrjID;EAyBI,gBAAA;C/B+hIH;A+BzhID;EAAA;IAFI,cAAA;G/B+hID;CACF;A+BthID;EACE,oBAAA;C/BwhID;A+BzhID;EAII,kBAAA;EACA,qBAAA;EACA,kBAAA;C/BwhIH;A+B5/HC;EAAA;IAtBI,iBAAA;IACA,YAAA;IACA,YAAA;IACA,cAAA;IACA,8BAAA;IACA,UAAA;IACA,yBAAA;YAAA,iBAAA;G/BshIH;E+BtgID;;IAbM,2BAAA;G/BuhIL;E+B1gID;IAVM,kBAAA;G/BuhIL;E+BthIK;;IAEE,uBAAA;G/BwhIP;CACF;A+BtgID;EAAA;IAXI,YAAA;IACA,UAAA;G/BqhID;E+B3gIH;IAPM,YAAA;G/BqhIH;E+B9gIH;IALQ,kBAAA;IACA,qBAAA;G/BshIL;CACF;A+B3gID;EACE,mBAAA;EACA,oBAAA;EACA,mBAAA;EACA,kCAAA;EACA,qCAAA;E1B9NA,6FAAA;EACQ,qFAAA;E2B/DR,gBAAA;EACA,mBAAA;ChC4yID;AkB5xHD;EAAA;IA9DM,sBAAA;IACA,iBAAA;IACA,uBAAA;GlB81HH;EkBlyHH;IAvDM,sBAAA;IACA,YAAA;IACA,uBAAA;GlB41HH;EkBvyHH;IAhDM,sBAAA;GlB01HH;EkB1yHH;IA5CM,sBAAA;IACA,uBAAA;GlBy1HH;EkB9yHH;;;IAtCQ,YAAA;GlBy1HL;EkBnzHH;IAhCM,YAAA;GlBs1HH;EkBtzHH;IA5BM,iBAAA;IACA,uBAAA;GlBq1HH;EkB1zHH;;IApBM,sBAAA;IACA,cAAA;IACA,iBAAA;IACA,uBAAA;GlBk1HH;EkBj0HH;;IAdQ,gBAAA;GlBm1HL;EkBr0HH;;IATM,mBAAA;IACA,eAAA;GlBk1HH;EkB10HH;IAHM,OAAA;GlBg1HH;CACF;A+BpjIC;EAAA;IANI,mBAAA;G/B8jIH;E+B5jIG;IACE,iBAAA;G/B8jIL;CACF;A+B7iID;EAAA;IARI,YAAA;IACA,UAAA;IACA,eAAA;IACA,gBAAA;IACA,eAAA;IACA,kBAAA;I1BzPF,yBAAA;IACQ,iBAAA;GLmzIP;CACF;A+BnjID;EACE,cAAA;EHpUA,2BAAA;EACC,0BAAA;C5B03IF;A+BnjID;EACE,iBAAA;EHzUA,6BAAA;EACC,4BAAA;EAOD,8BAAA;EACC,6BAAA;C5By3IF;A+B/iID;EChVE,gBAAA;EACA,mBAAA;ChCk4ID;A+BhjIC;ECnVA,iBAAA;EACA,oBAAA;ChCs4ID;A+BjjIC;ECtVA,iBAAA;EACA,oBAAA;ChC04ID;A+B3iID;EChWE,iBAAA;EACA,oBAAA;ChC84ID;A+BviID;EAAA;IAJI,YAAA;IACA,kBAAA;IACA,mBAAA;G/B+iID;CACF;A+BlhID;EAhBE;IExWA,uBAAA;GjC84IC;E+BriID;IE5WA,wBAAA;IF8WE,oBAAA;G/BuiID;E+BziID;IAKI,gBAAA;G/BuiIH;CACF;A+B9hID;EACE,0BAAA;EACA,sBAAA;C/BgiID;A+BliID;EAKI,eAAA;C/BgiIH;A+B/hIG;;EAEE,eAAA;EACA,8BAAA;C/BiiIL;A+B1iID;EAcI,eAAA;C/B+hIH;A+B7iID;EAmBM,eAAA;C/B6hIL;A+B3hIK;;EAEE,eAAA;EACA,8BAAA;C/B6hIP;A+BzhIK;;;EAGE,eAAA;EACA,0BAAA;C/B2hIP;A+BvhIK;;;EAGE,eAAA;EACA,8BAAA;C/ByhIP;A+BjkID;EA8CI,sBAAA;C/BshIH;A+BrhIG;;EAEE,0BAAA;C/BuhIL;A+BxkID;EAoDM,0BAAA;C/BuhIL;A+B3kID;;EA0DI,sBAAA;C/BqhIH;A+B9gIK;;;EAGE,0BAAA;EACA,eAAA;C/BghIP;A+B/+HC;EAAA;IAzBQ,eAAA;G/B4gIP;E+B3gIO;;IAEE,eAAA;IACA,8BAAA;G/B6gIT;E+BzgIO;;;IAGE,eAAA;IACA,0BAAA;G/B2gIT;E+BvgIO;;;IAGE,eAAA;IACA,8BAAA;G/BygIT;CACF;A+B3mID;EA8GI,eAAA;C/BggIH;A+B//HG;EACE,eAAA;C/BigIL;A+BjnID;EAqHI,eAAA;C/B+/HH;A+B9/HG;;EAEE,eAAA;C/BggIL;A+B5/HK;;;;EAEE,eAAA;C/BggIP;A+Bx/HD;EACE,0BAAA;EACA,sBAAA;C/B0/HD;A+B5/HD;EAKI,eAAA;C/B0/HH;A+Bz/HG;;EAEE,eAAA;EACA,8BAAA;C/B2/HL;A+BpgID;EAcI,eAAA;C/By/HH;A+BvgID;EAmBM,eAAA;C/Bu/HL;A+Br/HK;;EAEE,eAAA;EACA,8BAAA;C/Bu/HP;A+Bn/HK;;;EAGE,eAAA;EACA,0BAAA;C/Bq/HP;A+Bj/HK;;;EAGE,eAAA;EACA,8BAAA;C/Bm/HP;A+B3hID;EA+CI,sBAAA;C/B++HH;A+B9+HG;;EAEE,0BAAA;C/Bg/HL;A+BliID;EAqDM,0BAAA;C/Bg/HL;A+BriID;;EA2DI,sBAAA;C/B8+HH;A+Bx+HK;;;EAGE,0BAAA;EACA,eAAA;C/B0+HP;A+Bn8HC;EAAA;IA/BQ,sBAAA;G/Bs+HP;E+Bv8HD;IA5BQ,0BAAA;G/Bs+HP;E+B18HD;IAzBQ,eAAA;G/Bs+HP;E+Br+HO;;IAEE,eAAA;IACA,8BAAA;G/Bu+HT;E+Bn+HO;;;IAGE,eAAA;IACA,0BAAA;G/Bq+HT;E+Bj+HO;;;IAGE,eAAA;IACA,8BAAA;G/Bm+HT;CACF;A+B3kID;EA+GI,eAAA;C/B+9HH;A+B99HG;EACE,eAAA;C/Bg+HL;A+BjlID;EAsHI,eAAA;C/B89HH;A+B79HG;;EAEE,eAAA;C/B+9HL;A+B39HK;;;;EAEE,eAAA;C/B+9HP;AkCzmJD;EACE,kBAAA;EACA,oBAAA;EACA,iBAAA;EACA,0BAAA;EACA,mBAAA;ClC2mJD;AkChnJD;EAQI,sBAAA;ClC2mJH;AkCnnJD;EAWM,kBAAA;EACA,eAAA;EACA,eAAA;ClC2mJL;AkCxnJD;EAkBI,eAAA;ClCymJH;AmC7nJD;EACE,sBAAA;EACA,gBAAA;EACA,eAAA;EACA,mBAAA;CnC+nJD;AmCnoJD;EAOI,gBAAA;CnC+nJH;AmCtoJD;;EAUM,mBAAA;EACA,YAAA;EACA,kBAAA;EACA,wBAAA;EACA,sBAAA;EACA,eAAA;EACA,0BAAA;EACA,0BAAA;EACA,kBAAA;CnCgoJL;AmC9nJG;;EAGI,eAAA;EPXN,+BAAA;EACG,4BAAA;C5B2oJJ;AmC7nJG;;EPvBF,gCAAA;EACG,6BAAA;C5BwpJJ;AmCxnJG;;;;EAEE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;CnC4nJL;AmCtnJG;;;;;;EAGE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;EACA,gBAAA;CnC2nJL;AmClrJD;;;;;;EAkEM,eAAA;EACA,0BAAA;EACA,sBAAA;EACA,oBAAA;CnCwnJL;AmC/mJD;;EC3EM,mBAAA;EACA,gBAAA;EACA,uBAAA;CpC8rJL;AoC5rJG;;ERKF,+BAAA;EACG,4BAAA;C5B2rJJ;AoC3rJG;;ERTF,gCAAA;EACG,6BAAA;C5BwsJJ;AmC1nJD;;EChFM,kBAAA;EACA,gBAAA;EACA,iBAAA;CpC8sJL;AoC5sJG;;ERKF,+BAAA;EACG,4BAAA;C5B2sJJ;AoC3sJG;;ERTF,gCAAA;EACG,6BAAA;C5BwtJJ;AqC3tJD;EACE,gBAAA;EACA,eAAA;EACA,iBAAA;EACA,mBAAA;CrC6tJD;AqCjuJD;EAOI,gBAAA;CrC6tJH;AqCpuJD;;EAUM,sBAAA;EACA,kBAAA;EACA,0BAAA;EACA,0BAAA;EACA,oBAAA;CrC8tJL;AqC5uJD;;EAmBM,sBAAA;EACA,0BAAA;CrC6tJL;AqCjvJD;;EA2BM,aAAA;CrC0tJL;AqCrvJD;;EAkCM,YAAA;CrCutJL;AqCzvJD;;;;EA2CM,eAAA;EACA,0BAAA;EACA,oBAAA;CrCotJL;AsClwJD;EACE,gBAAA;EACA,wBAAA;EACA,eAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,mBAAA;EACA,oBAAA;EACA,yBAAA;EACA,qBAAA;CtCowJD;AsChwJG;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;CtCkwJL;AsC7vJC;EACE,cAAA;CtC+vJH;AsC3vJC;EACE,mBAAA;EACA,UAAA;CtC6vJH;AsCtvJD;ECtCE,0BAAA;CvC+xJD;AuC5xJG;;EAEE,0BAAA;CvC8xJL;AsCzvJD;EC1CE,0BAAA;CvCsyJD;AuCnyJG;;EAEE,0BAAA;CvCqyJL;AsC5vJD;EC9CE,0BAAA;CvC6yJD;AuC1yJG;;EAEE,0BAAA;CvC4yJL;AsC/vJD;EClDE,0BAAA;CvCozJD;AuCjzJG;;EAEE,0BAAA;CvCmzJL;AsClwJD;ECtDE,0BAAA;CvC2zJD;AuCxzJG;;EAEE,0BAAA;CvC0zJL;AsCrwJD;EC1DE,0BAAA;CvCk0JD;AuC/zJG;;EAEE,0BAAA;CvCi0JL;AwCn0JD;EACE,sBAAA;EACA,gBAAA;EACA,iBAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,uBAAA;EACA,oBAAA;EACA,mBAAA;EACA,0BAAA;EACA,oBAAA;CxCq0JD;AwCl0JC;EACE,cAAA;CxCo0JH;AwCh0JC;EACE,mBAAA;EACA,UAAA;CxCk0JH;AwC/zJC;;EAEE,OAAA;EACA,iBAAA;CxCi0JH;AwC5zJG;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;CxC8zJL;AwCzzJC;;EAEE,eAAA;EACA,0BAAA;CxC2zJH;AwCxzJC;EACE,aAAA;CxC0zJH;AwCvzJC;EACE,kBAAA;CxCyzJH;AwCtzJC;EACE,iBAAA;CxCwzJH;AyCl3JD;EACE,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,eAAA;EACA,0BAAA;CzCo3JD;AyCz3JD;;EASI,eAAA;CzCo3JH;AyC73JD;EAaI,oBAAA;EACA,gBAAA;EACA,iBAAA;CzCm3JH;AyCl4JD;EAmBI,0BAAA;CzCk3JH;AyC/2JC;;EAEE,mBAAA;CzCi3JH;AyCz4JD;EA4BI,gBAAA;CzCg3JH;AyC91JD;EAAA;IAdI,kBAAA;IACA,qBAAA;GzCg3JD;EyC92JC;;IAEE,mBAAA;IACA,oBAAA;GzCg3JH;EyCx2JH;;IAHM,gBAAA;GzC+2JH;CACF;A0C15JD;EACE,eAAA;EACA,aAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;ErCiLA,4CAAA;EACK,uCAAA;EACG,oCAAA;CL4uJT;A0Ct6JD;;EAaI,kBAAA;EACA,mBAAA;C1C65JH;A0Cz5JC;;;EAGE,sBAAA;C1C25JH;A0Ch7JD;EA0BI,aAAA;EACA,eAAA;C1Cy5JH;A2Cl7JD;EACE,cAAA;EACA,oBAAA;EACA,8BAAA;EACA,mBAAA;C3Co7JD;A2Cx7JD;EAQI,cAAA;EAEA,eAAA;C3Ck7JH;A2C57JD;EAeI,kBAAA;C3Cg7JH;A2C/7JD;;EAqBI,iBAAA;C3C86JH;A2Cn8JD;EAyBI,gBAAA;C3C66JH;A2Cr6JD;;EAEE,oBAAA;C3Cu6JD;A2Cz6JD;;EAMI,mBAAA;EACA,UAAA;EACA,aAAA;EACA,eAAA;C3Cu6JH;A2C/5JD;ECvDE,0BAAA;EACA,sBAAA;EACA,eAAA;C5Cy9JD;A2Cp6JD;EClDI,0BAAA;C5Cy9JH;A2Cv6JD;EC/CI,eAAA;C5Cy9JH;A2Ct6JD;EC3DE,0BAAA;EACA,sBAAA;EACA,eAAA;C5Co+JD;A2C36JD;ECtDI,0BAAA;C5Co+JH;A2C96JD;ECnDI,eAAA;C5Co+JH;A2C76JD;EC/DE,0BAAA;EACA,sBAAA;EACA,eAAA;C5C++JD;A2Cl7JD;EC1DI,0BAAA;C5C++JH;A2Cr7JD;ECvDI,eAAA;C5C++JH;A2Cp7JD;ECnEE,0BAAA;EACA,sBAAA;EACA,eAAA;C5C0/JD;A2Cz7JD;EC9DI,0BAAA;C5C0/JH;A2C57JD;EC3DI,eAAA;C5C0/JH;A6C5/JD;EACE;IAAQ,4BAAA;G7C+/JP;E6C9/JD;IAAQ,yBAAA;G7CigKP;CACF;A6C9/JD;EACE;IAAQ,4BAAA;G7CigKP;E6ChgKD;IAAQ,yBAAA;G7CmgKP;CACF;A6CtgKD;EACE;IAAQ,4BAAA;G7CigKP;E6ChgKD;IAAQ,yBAAA;G7CmgKP;CACF;A6C5/JD;EACE,iBAAA;EACA,aAAA;EACA,oBAAA;EACA,0BAAA;EACA,mBAAA;ExCsCA,uDAAA;EACQ,+CAAA;CLy9JT;A6C3/JD;EACE,YAAA;EACA,UAAA;EACA,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;ExCyBA,uDAAA;EACQ,+CAAA;EAyHR,oCAAA;EACK,+BAAA;EACG,4BAAA;CL62JT;A6Cx/JD;;ECCI,8MAAA;EACA,yMAAA;EACA,sMAAA;EDAF,mCAAA;UAAA,2BAAA;C7C4/JD;A6Cr/JD;;ExC5CE,2DAAA;EACK,sDAAA;EACG,mDAAA;CLqiKT;A6Cl/JD;EErEE,0BAAA;C/C0jKD;A+CvjKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9C0gKH;A6Ct/JD;EEzEE,0BAAA;C/CkkKD;A+C/jKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9CkhKH;A6C1/JD;EE7EE,0BAAA;C/C0kKD;A+CvkKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9C0hKH;A6C9/JD;EEjFE,0BAAA;C/CklKD;A+C/kKC;EDgDE,8MAAA;EACA,yMAAA;EACA,sMAAA;C9CkiKH;AgD1lKD;EAEE,iBAAA;ChD2lKD;AgDzlKC;EACE,cAAA;ChD2lKH;AgDvlKD;;EAEE,QAAA;EACA,iBAAA;ChDylKD;AgDtlKD;EACE,eAAA;ChDwlKD;AgDrlKD;EACE,eAAA;ChDulKD;AgDplKC;EACE,gBAAA;ChDslKH;AgDllKD;;EAEE,mBAAA;ChDolKD;AgDjlKD;;EAEE,oBAAA;ChDmlKD;AgDhlKD;;;EAGE,oBAAA;EACA,oBAAA;ChDklKD;AgD/kKD;EACE,uBAAA;ChDilKD;AgD9kKD;EACE,uBAAA;ChDglKD;AgD5kKD;EACE,cAAA;EACA,mBAAA;ChD8kKD;AgDxkKD;EACE,gBAAA;EACA,iBAAA;ChD0kKD;AiDjoKD;EAEE,oBAAA;EACA,gBAAA;CjDkoKD;AiD1nKD;EACE,mBAAA;EACA,eAAA;EACA,mBAAA;EAEA,oBAAA;EACA,0BAAA;EACA,0BAAA;CjD2nKD;AiDxnKC;ErB3BA,6BAAA;EACC,4BAAA;C5BspKF;AiDznKC;EACE,iBAAA;ErBvBF,gCAAA;EACC,+BAAA;C5BmpKF;AiDlnKD;;EAEE,eAAA;CjDonKD;AiDtnKD;;EAKI,eAAA;CjDqnKH;AiDjnKC;;;;EAEE,sBAAA;EACA,eAAA;EACA,0BAAA;CjDqnKH;AiDjnKD;EACE,YAAA;EACA,iBAAA;CjDmnKD;AiD9mKC;;;EAGE,0BAAA;EACA,eAAA;EACA,oBAAA;CjDgnKH;AiDrnKC;;;EASI,eAAA;CjDinKL;AiD1nKC;;;EAYI,eAAA;CjDmnKL;AiD9mKC;;;EAGE,WAAA;EACA,eAAA;EACA,0BAAA;EACA,sBAAA;CjDgnKH;AiDtnKC;;;;;;;;;EAYI,eAAA;CjDqnKL;AiDjoKC;;;EAeI,eAAA;CjDunKL;AkDztKC;EACE,eAAA;EACA,0BAAA;ClD2tKH;AkDztKG;;EAEE,eAAA;ClD2tKL;AkD7tKG;;EAKI,eAAA;ClD4tKP;AkDztKK;;;;EAEE,eAAA;EACA,0BAAA;ClD6tKP;AkD3tKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClDguKP;AkDtvKC;EACE,eAAA;EACA,0BAAA;ClDwvKH;AkDtvKG;;EAEE,eAAA;ClDwvKL;AkD1vKG;;EAKI,eAAA;ClDyvKP;AkDtvKK;;;;EAEE,eAAA;EACA,0BAAA;ClD0vKP;AkDxvKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClD6vKP;AkDnxKC;EACE,eAAA;EACA,0BAAA;ClDqxKH;AkDnxKG;;EAEE,eAAA;ClDqxKL;AkDvxKG;;EAKI,eAAA;ClDsxKP;AkDnxKK;;;;EAEE,eAAA;EACA,0BAAA;ClDuxKP;AkDrxKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClD0xKP;AkDhzKC;EACE,eAAA;EACA,0BAAA;ClDkzKH;AkDhzKG;;EAEE,eAAA;ClDkzKL;AkDpzKG;;EAKI,eAAA;ClDmzKP;AkDhzKK;;;;EAEE,eAAA;EACA,0BAAA;ClDozKP;AkDlzKK;;;;;;EAGE,YAAA;EACA,0BAAA;EACA,sBAAA;ClDuzKP;AiDttKD;EACE,cAAA;EACA,mBAAA;CjDwtKD;AiDttKD;EACE,iBAAA;EACA,iBAAA;CjDwtKD;AmDl1KD;EACE,oBAAA;EACA,0BAAA;EACA,8BAAA;EACA,mBAAA;E9C0DA,kDAAA;EACQ,0CAAA;CL2xKT;AmDj1KD;EACE,cAAA;CnDm1KD;AmD90KD;EACE,mBAAA;EACA,qCAAA;EvBpBA,6BAAA;EACC,4BAAA;C5Bq2KF;AmDp1KD;EAMI,eAAA;CnDi1KH;AmD50KD;EACE,cAAA;EACA,iBAAA;EACA,gBAAA;EACA,eAAA;CnD80KD;AmDl1KD;;;;;EAWI,eAAA;CnD80KH;AmDz0KD;EACE,mBAAA;EACA,0BAAA;EACA,8BAAA;EvBxCA,gCAAA;EACC,+BAAA;C5Bo3KF;AmDn0KD;;EAGI,iBAAA;CnDo0KH;AmDv0KD;;EAMM,oBAAA;EACA,iBAAA;CnDq0KL;AmDj0KG;;EAEI,cAAA;EvBvEN,6BAAA;EACC,4BAAA;C5B24KF;AmD/zKG;;EAEI,iBAAA;EvBvEN,gCAAA;EACC,+BAAA;C5By4KF;AmDx1KD;EvB1DE,2BAAA;EACC,0BAAA;C5Bq5KF;AmD3zKD;EAEI,oBAAA;CnD4zKH;AmDzzKD;EACE,oBAAA;CnD2zKD;AmDnzKD;;;EAII,iBAAA;CnDozKH;AmDxzKD;;;EAOM,mBAAA;EACA,oBAAA;CnDszKL;AmD9zKD;;EvBzGE,6BAAA;EACC,4BAAA;C5B26KF;AmDn0KD;;;;EAmBQ,4BAAA;EACA,6BAAA;CnDszKP;AmD10KD;;;;;;;;EAwBU,4BAAA;CnD4zKT;AmDp1KD;;;;;;;;EA4BU,6BAAA;CnDk0KT;AmD91KD;;EvBjGE,gCAAA;EACC,+BAAA;C5Bm8KF;AmDn2KD;;;;EAyCQ,+BAAA;EACA,gCAAA;CnDg0KP;AmD12KD;;;;;;;;EA8CU,+BAAA;CnDs0KT;AmDp3KD;;;;;;;;EAkDU,gCAAA;CnD40KT;AmD93KD;;;;EA2DI,8BAAA;CnDy0KH;AmDp4KD;;EA+DI,cAAA;CnDy0KH;AmDx4KD;;EAmEI,UAAA;CnDy0KH;AmD54KD;;;;;;;;;;;;EA0EU,eAAA;CnDg1KT;AmD15KD;;;;;;;;;;;;EA8EU,gBAAA;CnD01KT;AmDx6KD;;;;;;;;EAuFU,iBAAA;CnD21KT;AmDl7KD;;;;;;;;EAgGU,iBAAA;CnD41KT;AmD57KD;EAsGI,UAAA;EACA,iBAAA;CnDy1KH;AmD/0KD;EACE,oBAAA;CnDi1KD;AmDl1KD;EAKI,iBAAA;EACA,mBAAA;CnDg1KH;AmDt1KD;EASM,gBAAA;CnDg1KL;AmDz1KD;EAcI,iBAAA;CnD80KH;AmD51KD;;EAkBM,8BAAA;CnD80KL;AmDh2KD;EAuBI,cAAA;CnD40KH;AmDn2KD;EAyBM,iCAAA;CnD60KL;AmDt0KD;EC1PE,sBAAA;CpDmkLD;AoDjkLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDmkLH;AoDtkLC;EAMI,0BAAA;CpDmkLL;AoDzkLC;EASI,eAAA;EACA,0BAAA;CpDmkLL;AoDhkLC;EAEI,6BAAA;CpDikLL;AmDr1KD;EC7PE,sBAAA;CpDqlLD;AoDnlLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDqlLH;AoDxlLC;EAMI,0BAAA;CpDqlLL;AoD3lLC;EASI,eAAA;EACA,0BAAA;CpDqlLL;AoDllLC;EAEI,6BAAA;CpDmlLL;AmDp2KD;EChQE,sBAAA;CpDumLD;AoDrmLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDumLH;AoD1mLC;EAMI,0BAAA;CpDumLL;AoD7mLC;EASI,eAAA;EACA,0BAAA;CpDumLL;AoDpmLC;EAEI,6BAAA;CpDqmLL;AmDn3KD;ECnQE,sBAAA;CpDynLD;AoDvnLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpDynLH;AoD5nLC;EAMI,0BAAA;CpDynLL;AoD/nLC;EASI,eAAA;EACA,0BAAA;CpDynLL;AoDtnLC;EAEI,6BAAA;CpDunLL;AmDl4KD;ECtQE,sBAAA;CpD2oLD;AoDzoLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD2oLH;AoD9oLC;EAMI,0BAAA;CpD2oLL;AoDjpLC;EASI,eAAA;EACA,0BAAA;CpD2oLL;AoDxoLC;EAEI,6BAAA;CpDyoLL;AmDj5KD;ECzQE,sBAAA;CpD6pLD;AoD3pLC;EACE,eAAA;EACA,0BAAA;EACA,sBAAA;CpD6pLH;AoDhqLC;EAMI,0BAAA;CpD6pLL;AoDnqLC;EASI,eAAA;EACA,0BAAA;CpD6pLL;AoD1pLC;EAEI,6BAAA;CpD2pLL;AqD3qLD;EACE,mBAAA;EACA,eAAA;EACA,UAAA;EACA,WAAA;EACA,iBAAA;CrD6qLD;AqDlrLD;;;;;EAYI,mBAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;EACA,aAAA;EACA,YAAA;EACA,UAAA;CrD6qLH;AqDxqLD;EACE,uBAAA;CrD0qLD;AqDtqLD;EACE,oBAAA;CrDwqLD;AsDnsLD;EACE,iBAAA;EACA,cAAA;EACA,oBAAA;EACA,0BAAA;EACA,0BAAA;EACA,mBAAA;EjDwDA,wDAAA;EACQ,gDAAA;CL8oLT;AsD7sLD;EASI,mBAAA;EACA,kCAAA;CtDusLH;AsDlsLD;EACE,cAAA;EACA,mBAAA;CtDosLD;AsDlsLD;EACE,aAAA;EACA,mBAAA;CtDosLD;AuD1tLD;EACE,aAAA;EACA,gBAAA;EACA,kBAAA;EACA,eAAA;EACA,eAAA;EACA,6BAAA;EjCRA,aAAA;EAGA,0BAAA;CtBmuLD;AuD3tLC;;EAEE,eAAA;EACA,sBAAA;EACA,gBAAA;EjCfF,aAAA;EAGA,0BAAA;CtB2uLD;AuDvtLC;EACE,WAAA;EACA,gBAAA;EACA,wBAAA;EACA,UAAA;EACA,yBAAA;CvDytLH;AwD9uLD;EACE,iBAAA;CxDgvLD;AwD5uLD;EACE,cAAA;EACA,iBAAA;EACA,gBAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,kCAAA;EAIA,WAAA;CxD2uLD;AwDxuLC;EnD+GA,sCAAA;EACI,kCAAA;EACC,iCAAA;EACG,8BAAA;EAkER,oDAAA;EAEK,0CAAA;EACG,oCAAA;CL2jLT;AwD9uLC;EnD2GA,mCAAA;EACI,+BAAA;EACC,8BAAA;EACG,2BAAA;CLsoLT;AwDlvLD;EACE,mBAAA;EACA,iBAAA;CxDovLD;AwDhvLD;EACE,mBAAA;EACA,YAAA;EACA,aAAA;CxDkvLD;AwD9uLD;EACE,mBAAA;EACA,0BAAA;EACA,0BAAA;EACA,qCAAA;EACA,mBAAA;EnDaA,iDAAA;EACQ,yCAAA;EmDZR,qCAAA;UAAA,6BAAA;EAEA,WAAA;CxDgvLD;AwD5uLD;EACE,gBAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,QAAA;EACA,cAAA;EACA,0BAAA;CxD8uLD;AwD5uLC;ElCrEA,WAAA;EAGA,yBAAA;CtBkzLD;AwD/uLC;ElCtEA,aAAA;EAGA,0BAAA;CtBszLD;AwD9uLD;EACE,cAAA;EACA,iCAAA;EACA,0BAAA;CxDgvLD;AwD7uLD;EACE,iBAAA;CxD+uLD;AwD3uLD;EACE,UAAA;EACA,wBAAA;CxD6uLD;AwDxuLD;EACE,mBAAA;EACA,cAAA;CxD0uLD;AwDtuLD;EACE,cAAA;EACA,kBAAA;EACA,8BAAA;CxDwuLD;AwD3uLD;EAQI,iBAAA;EACA,iBAAA;CxDsuLH;AwD/uLD;EAaI,kBAAA;CxDquLH;AwDlvLD;EAiBI,eAAA;CxDouLH;AwD/tLD;EACE,mBAAA;EACA,aAAA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;CxDiuLD;AwD/sLD;EAZE;IACE,aAAA;IACA,kBAAA;GxD8tLD;EwD5tLD;InDvEA,kDAAA;IACQ,0CAAA;GLsyLP;EwD3tLD;IAAY,aAAA;GxD8tLX;CACF;AwDztLD;EAFE;IAAY,aAAA;GxD+tLX;CACF;AyD92LD;EACE,mBAAA;EACA,cAAA;EACA,eAAA;ECRA,4DAAA;EAEA,mBAAA;EACA,oBAAA;EACA,uBAAA;EACA,iBAAA;EACA,wBAAA;EACA,iBAAA;EACA,kBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mBAAA;EACA,qBAAA;EACA,kBAAA;EDHA,gBAAA;EnCVA,WAAA;EAGA,yBAAA;CtBq4LD;AyD13LC;EnCdA,aAAA;EAGA,0BAAA;CtBy4LD;AyD73LC;EAAW,iBAAA;EAAmB,eAAA;CzDi4L/B;AyDh4LC;EAAW,iBAAA;EAAmB,eAAA;CzDo4L/B;AyDn4LC;EAAW,gBAAA;EAAmB,eAAA;CzDu4L/B;AyDt4LC;EAAW,kBAAA;EAAmB,eAAA;CzD04L/B;AyDt4LD;EACE,iBAAA;EACA,iBAAA;EACA,eAAA;EACA,mBAAA;EACA,0BAAA;EACA,mBAAA;CzDw4LD;AyDp4LD;EACE,mBAAA;EACA,SAAA;EACA,UAAA;EACA,0BAAA;EACA,oBAAA;CzDs4LD;AyDl4LC;EACE,UAAA;EACA,UAAA;EACA,kBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,UAAA;EACA,WAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,UAAA;EACA,UAAA;EACA,oBAAA;EACA,wBAAA;EACA,0BAAA;CzDo4LH;AyDl4LC;EACE,SAAA;EACA,QAAA;EACA,iBAAA;EACA,4BAAA;EACA,4BAAA;CzDo4LH;AyDl4LC;EACE,SAAA;EACA,SAAA;EACA,iBAAA;EACA,4BAAA;EACA,2BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,UAAA;EACA,kBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,WAAA;EACA,iBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;AyDl4LC;EACE,OAAA;EACA,UAAA;EACA,iBAAA;EACA,wBAAA;EACA,6BAAA;CzDo4LH;A2Dj+LD;EACE,mBAAA;EACA,OAAA;EACA,QAAA;EACA,cAAA;EACA,cAAA;EACA,iBAAA;EACA,aAAA;EDXA,4DAAA;EAEA,mBAAA;EACA,oBAAA;EACA,uBAAA;EACA,iBAAA;EACA,wBAAA;EACA,iBAAA;EACA,kBAAA;EACA,sBAAA;EACA,kBAAA;EACA,qBAAA;EACA,oBAAA;EACA,mBAAA;EACA,qBAAA;EACA,kBAAA;ECAA,gBAAA;EAEA,0BAAA;EACA,qCAAA;UAAA,6BAAA;EACA,0BAAA;EACA,qCAAA;EACA,mBAAA;EtD8CA,kDAAA;EACQ,0CAAA;CLi8LT;A2D5+LC;EAAY,kBAAA;C3D++Lb;A2D9+LC;EAAY,kBAAA;C3Di/Lb;A2Dh/LC;EAAY,iBAAA;C3Dm/Lb;A2Dl/LC;EAAY,mBAAA;C3Dq/Lb;A2Dl/LD;EACE,UAAA;EACA,kBAAA;EACA,gBAAA;EACA,0BAAA;EACA,iCAAA;EACA,2BAAA;C3Do/LD;A2Dj/LD;EACE,kBAAA;C3Dm/LD;A2D3+LC;;EAEE,mBAAA;EACA,eAAA;EACA,SAAA;EACA,UAAA;EACA,0BAAA;EACA,oBAAA;C3D6+LH;A2D1+LD;EACE,mBAAA;C3D4+LD;A2D1+LD;EACE,mBAAA;EACA,YAAA;C3D4+LD;A2Dx+LC;EACE,UAAA;EACA,mBAAA;EACA,uBAAA;EACA,0BAAA;EACA,sCAAA;EACA,cAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,YAAA;EACA,mBAAA;EACA,uBAAA;EACA,0BAAA;C3D2+LL;A2Dx+LC;EACE,SAAA;EACA,YAAA;EACA,kBAAA;EACA,qBAAA;EACA,4BAAA;EACA,wCAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,UAAA;EACA,cAAA;EACA,qBAAA;EACA,4BAAA;C3D2+LL;A2Dx+LC;EACE,UAAA;EACA,mBAAA;EACA,oBAAA;EACA,6BAAA;EACA,yCAAA;EACA,WAAA;C3D0+LH;A2Dz+LG;EACE,aAAA;EACA,SAAA;EACA,mBAAA;EACA,oBAAA;EACA,6BAAA;C3D2+LL;A2Dv+LC;EACE,SAAA;EACA,aAAA;EACA,kBAAA;EACA,sBAAA;EACA,2BAAA;EACA,uCAAA;C3Dy+LH;A2Dx+LG;EACE,aAAA;EACA,WAAA;EACA,sBAAA;EACA,2BAAA;EACA,cAAA;C3D0+LL;A4DnmMD;EACE,mBAAA;C5DqmMD;A4DlmMD;EACE,mBAAA;EACA,iBAAA;EACA,YAAA;C5DomMD;A4DvmMD;EAMI,cAAA;EACA,mBAAA;EvD6KF,0CAAA;EACK,qCAAA;EACG,kCAAA;CLw7LT;A4D9mMD;;EAcM,eAAA;C5DomML;A4D1kMC;EAAA;IvDiKA,uDAAA;IAEK,6CAAA;IACG,uCAAA;IA7JR,oCAAA;IAEQ,4BAAA;IA+GR,4BAAA;IAEQ,oBAAA;GL69LP;E4DxmMG;;IvDmHJ,2CAAA;IACQ,mCAAA;IuDjHF,QAAA;G5D2mML;E4DzmMG;;IvD8GJ,4CAAA;IACQ,oCAAA;IuD5GF,QAAA;G5D4mML;E4D1mMG;;;IvDyGJ,wCAAA;IACQ,gCAAA;IuDtGF,QAAA;G5D6mML;CACF;A4DnpMD;;;EA6CI,eAAA;C5D2mMH;A4DxpMD;EAiDI,QAAA;C5D0mMH;A4D3pMD;;EAsDI,mBAAA;EACA,OAAA;EACA,YAAA;C5DymMH;A4DjqMD;EA4DI,WAAA;C5DwmMH;A4DpqMD;EA+DI,YAAA;C5DwmMH;A4DvqMD;;EAmEI,QAAA;C5DwmMH;A4D3qMD;EAuEI,YAAA;C5DumMH;A4D9qMD;EA0EI,WAAA;C5DumMH;A4D/lMD;EACE,mBAAA;EACA,OAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EtC9FA,aAAA;EAGA,0BAAA;EsC6FA,gBAAA;EACA,eAAA;EACA,mBAAA;EACA,0CAAA;C5DkmMD;A4D7lMC;EdlGE,mGAAA;EACA,8FAAA;EACA,qHAAA;EAAA,+FAAA;EACA,4BAAA;EACA,uHAAA;C9CksMH;A4DjmMC;EACE,WAAA;EACA,SAAA;EdvGA,mGAAA;EACA,8FAAA;EACA,qHAAA;EAAA,+FAAA;EACA,4BAAA;EACA,uHAAA;C9C2sMH;A4DnmMC;;EAEE,WAAA;EACA,eAAA;EACA,sBAAA;EtCtHF,aAAA;EAGA,0BAAA;CtB0tMD;A4DpoMD;;;;EAsCI,mBAAA;EACA,SAAA;EACA,kBAAA;EACA,WAAA;EACA,sBAAA;C5DomMH;A4D9oMD;;EA8CI,UAAA;EACA,mBAAA;C5DomMH;A4DnpMD;;EAmDI,WAAA;EACA,oBAAA;C5DomMH;A4DxpMD;;EAwDI,YAAA;EACA,aAAA;EACA,eAAA;EACA,mBAAA;C5DomMH;A4D/lMG;EACE,iBAAA;C5DimML;A4D7lMG;EACE,iBAAA;C5D+lML;A4DrlMD;EACE,mBAAA;EACA,aAAA;EACA,UAAA;EACA,YAAA;EACA,WAAA;EACA,kBAAA;EACA,gBAAA;EACA,iBAAA;EACA,mBAAA;C5DulMD;A4DhmMD;EAYI,sBAAA;EACA,YAAA;EACA,aAAA;EACA,YAAA;EACA,oBAAA;EACA,0BAAA;EACA,oBAAA;EACA,gBAAA;EAWA,0BAAA;EACA,mCAAA;C5D6kMH;A4D5mMD;EAkCI,UAAA;EACA,YAAA;EACA,aAAA;EACA,0BAAA;C5D6kMH;A4DtkMD;EACE,mBAAA;EACA,UAAA;EACA,WAAA;EACA,aAAA;EACA,YAAA;EACA,kBAAA;EACA,qBAAA;EACA,eAAA;EACA,mBAAA;EACA,0CAAA;C5DwkMD;A4DvkMC;EACE,kBAAA;C5DykMH;A4DhiMD;EAhCE;;;;IAKI,YAAA;IACA,aAAA;IACA,kBAAA;IACA,gBAAA;G5DkkMH;E4D1kMD;;IAYI,mBAAA;G5DkkMH;E4D9kMD;;IAgBI,oBAAA;G5DkkMH;E4D7jMD;IACE,UAAA;IACA,WAAA;IACA,qBAAA;G5D+jMD;E4D3jMD;IACE,aAAA;G5D6jMD;CACF;A6D3zMC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEE,aAAA;EACA,eAAA;C7Dy1MH;A6Dv1MC;;;;;;;;;;;;;;;EACE,YAAA;C7Du2MH;AiC/2MD;E6BRE,eAAA;EACA,kBAAA;EACA,mBAAA;C9D03MD;AiCj3MD;EACE,wBAAA;CjCm3MD;AiCj3MD;EACE,uBAAA;CjCm3MD;AiC32MD;EACE,yBAAA;CjC62MD;AiC32MD;EACE,0BAAA;CjC62MD;AiC32MD;EACE,mBAAA;CjC62MD;AiC32MD;E8BzBE,YAAA;EACA,mBAAA;EACA,kBAAA;EACA,8BAAA;EACA,UAAA;C/Du4MD;AiCz2MD;EACE,yBAAA;CjC22MD;AiCp2MD;EACE,gBAAA;CjCs2MD;AgEv4MD;EACE,oBAAA;ChEy4MD;AgEn4MD;;;;ECdE,yBAAA;CjEu5MD;AgEl4MD;;;;;;;;;;;;EAYE,yBAAA;ChEo4MD;AgE73MD;EAAA;IChDE,0BAAA;GjEi7MC;EiEh7MD;IAAU,0BAAA;GjEm7MT;EiEl7MD;IAAU,8BAAA;GjEq7MT;EiEp7MD;;IACU,+BAAA;GjEu7MT;CACF;AgEv4MD;EAAA;IAFI,0BAAA;GhE64MD;CACF;AgEv4MD;EAAA;IAFI,2BAAA;GhE64MD;CACF;AgEv4MD;EAAA;IAFI,iCAAA;GhE64MD;CACF;AgEt4MD;EAAA;ICrEE,0BAAA;GjE+8MC;EiE98MD;IAAU,0BAAA;GjEi9MT;EiEh9MD;IAAU,8BAAA;GjEm9MT;EiEl9MD;;IACU,+BAAA;GjEq9MT;CACF;AgEh5MD;EAAA;IAFI,0BAAA;GhEs5MD;CACF;AgEh5MD;EAAA;IAFI,2BAAA;GhEs5MD;CACF;AgEh5MD;EAAA;IAFI,iCAAA;GhEs5MD;CACF;AgE/4MD;EAAA;IC1FE,0BAAA;GjE6+MC;EiE5+MD;IAAU,0BAAA;GjE++MT;EiE9+MD;IAAU,8BAAA;GjEi/MT;EiEh/MD;;IACU,+BAAA;GjEm/MT;CACF;AgEz5MD;EAAA;IAFI,0BAAA;GhE+5MD;CACF;AgEz5MD;EAAA;IAFI,2BAAA;GhE+5MD;CACF;AgEz5MD;EAAA;IAFI,iCAAA;GhE+5MD;CACF;AgEx5MD;EAAA;IC/GE,0BAAA;GjE2gNC;EiE1gND;IAAU,0BAAA;GjE6gNT;EiE5gND;IAAU,8BAAA;GjE+gNT;EiE9gND;;IACU,+BAAA;GjEihNT;CACF;AgEl6MD;EAAA;IAFI,0BAAA;GhEw6MD;CACF;AgEl6MD;EAAA;IAFI,2BAAA;GhEw6MD;CACF;AgEl6MD;EAAA;IAFI,iCAAA;GhEw6MD;CACF;AgEj6MD;EAAA;IC5HE,yBAAA;GjEiiNC;CACF;AgEj6MD;EAAA;ICjIE,yBAAA;GjEsiNC;CACF;AgEj6MD;EAAA;ICtIE,yBAAA;GjE2iNC;CACF;AgEj6MD;EAAA;IC3IE,yBAAA;GjEgjNC;CACF;AgE95MD;ECnJE,yBAAA;CjEojND;AgE35MD;EAAA;ICjKE,0BAAA;GjEgkNC;EiE/jND;IAAU,0BAAA;GjEkkNT;EiEjkND;IAAU,8BAAA;GjEokNT;EiEnkND;;IACU,+BAAA;GjEskNT;CACF;AgEz6MD;EACE,yBAAA;ChE26MD;AgEt6MD;EAAA;IAFI,0BAAA;GhE46MD;CACF;AgE16MD;EACE,yBAAA;ChE46MD;AgEv6MD;EAAA;IAFI,2BAAA;GhE66MD;CACF;AgE36MD;EACE,yBAAA;ChE66MD;AgEx6MD;EAAA;IAFI,iCAAA;GhE86MD;CACF;AgEv6MD;EAAA;ICpLE,yBAAA;GjE+lNC;CACF","file":"bootstrap.css","sourcesContent":["/*!\n * Bootstrap v3.3.5 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\nhtml {\n font-family: sans-serif;\n -ms-text-size-adjust: 100%;\n -webkit-text-size-adjust: 100%;\n}\nbody {\n margin: 0;\n}\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block;\n vertical-align: baseline;\n}\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n[hidden],\ntemplate {\n display: none;\n}\na {\n background-color: transparent;\n}\na:active,\na:hover {\n outline: 0;\n}\nabbr[title] {\n border-bottom: 1px dotted;\n}\nb,\nstrong {\n font-weight: bold;\n}\ndfn {\n font-style: italic;\n}\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\nmark {\n background: #ff0;\n color: #000;\n}\nsmall {\n font-size: 80%;\n}\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\nsup {\n top: -0.5em;\n}\nsub {\n bottom: -0.25em;\n}\nimg {\n border: 0;\n}\nsvg:not(:root) {\n overflow: hidden;\n}\nfigure {\n margin: 1em 40px;\n}\nhr {\n box-sizing: content-box;\n height: 0;\n}\npre {\n overflow: auto;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit;\n font: inherit;\n margin: 0;\n}\nbutton {\n overflow: visible;\n}\nbutton,\nselect {\n text-transform: none;\n}\nbutton,\nhtml input[type=\"button\"],\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button;\n cursor: pointer;\n}\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\ninput {\n line-height: normal;\n}\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box;\n padding: 0;\n}\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: textfield;\n box-sizing: content-box;\n}\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\nlegend {\n border: 0;\n padding: 0;\n}\ntextarea {\n overflow: auto;\n}\noptgroup {\n font-weight: bold;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\ntd,\nth {\n padding: 0;\n}\n/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important;\n box-shadow: none !important;\n text-shadow: none !important;\n }\n a,\n a:visited {\n text-decoration: underline;\n }\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n thead {\n display: table-header-group;\n }\n tr,\n img {\n page-break-inside: avoid;\n }\n img {\n max-width: 100% !important;\n }\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n h2,\n h3 {\n page-break-after: avoid;\n }\n .navbar {\n display: none;\n }\n .btn > .caret,\n .dropup > .btn > .caret {\n border-top-color: #000 !important;\n }\n .label {\n border: 1px solid #000;\n }\n .table {\n border-collapse: collapse !important;\n }\n .table td,\n .table th {\n background-color: #fff !important;\n }\n .table-bordered th,\n .table-bordered td {\n border: 1px solid #ddd !important;\n }\n}\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('../fonts/glyphicons-halflings-regular.eot');\n src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff2') format('woff2'), 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');\n}\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.glyphicon-asterisk:before {\n content: \"\\2a\";\n}\n.glyphicon-plus:before {\n content: \"\\2b\";\n}\n.glyphicon-euro:before,\n.glyphicon-eur:before {\n content: \"\\20ac\";\n}\n.glyphicon-minus:before {\n content: \"\\2212\";\n}\n.glyphicon-cloud:before {\n content: \"\\2601\";\n}\n.glyphicon-envelope:before {\n content: \"\\2709\";\n}\n.glyphicon-pencil:before {\n content: \"\\270f\";\n}\n.glyphicon-glass:before {\n content: \"\\e001\";\n}\n.glyphicon-music:before {\n content: \"\\e002\";\n}\n.glyphicon-search:before {\n content: \"\\e003\";\n}\n.glyphicon-heart:before {\n content: \"\\e005\";\n}\n.glyphicon-star:before {\n content: \"\\e006\";\n}\n.glyphicon-star-empty:before {\n content: \"\\e007\";\n}\n.glyphicon-user:before {\n content: \"\\e008\";\n}\n.glyphicon-film:before {\n content: \"\\e009\";\n}\n.glyphicon-th-large:before {\n content: \"\\e010\";\n}\n.glyphicon-th:before {\n content: \"\\e011\";\n}\n.glyphicon-th-list:before {\n content: \"\\e012\";\n}\n.glyphicon-ok:before {\n content: \"\\e013\";\n}\n.glyphicon-remove:before {\n content: \"\\e014\";\n}\n.glyphicon-zoom-in:before {\n content: \"\\e015\";\n}\n.glyphicon-zoom-out:before {\n content: \"\\e016\";\n}\n.glyphicon-off:before {\n content: \"\\e017\";\n}\n.glyphicon-signal:before {\n content: \"\\e018\";\n}\n.glyphicon-cog:before {\n content: \"\\e019\";\n}\n.glyphicon-trash:before {\n content: \"\\e020\";\n}\n.glyphicon-home:before {\n content: \"\\e021\";\n}\n.glyphicon-file:before {\n content: \"\\e022\";\n}\n.glyphicon-time:before {\n content: \"\\e023\";\n}\n.glyphicon-road:before {\n content: \"\\e024\";\n}\n.glyphicon-download-alt:before {\n content: \"\\e025\";\n}\n.glyphicon-download:before {\n content: \"\\e026\";\n}\n.glyphicon-upload:before {\n content: \"\\e027\";\n}\n.glyphicon-inbox:before {\n content: \"\\e028\";\n}\n.glyphicon-play-circle:before {\n content: \"\\e029\";\n}\n.glyphicon-repeat:before {\n content: \"\\e030\";\n}\n.glyphicon-refresh:before {\n content: \"\\e031\";\n}\n.glyphicon-list-alt:before {\n content: \"\\e032\";\n}\n.glyphicon-lock:before {\n content: \"\\e033\";\n}\n.glyphicon-flag:before {\n content: \"\\e034\";\n}\n.glyphicon-headphones:before {\n content: \"\\e035\";\n}\n.glyphicon-volume-off:before {\n content: \"\\e036\";\n}\n.glyphicon-volume-down:before {\n content: \"\\e037\";\n}\n.glyphicon-volume-up:before {\n content: \"\\e038\";\n}\n.glyphicon-qrcode:before {\n content: \"\\e039\";\n}\n.glyphicon-barcode:before {\n content: \"\\e040\";\n}\n.glyphicon-tag:before {\n content: \"\\e041\";\n}\n.glyphicon-tags:before {\n content: \"\\e042\";\n}\n.glyphicon-book:before {\n content: \"\\e043\";\n}\n.glyphicon-bookmark:before {\n content: \"\\e044\";\n}\n.glyphicon-print:before {\n content: \"\\e045\";\n}\n.glyphicon-camera:before {\n content: \"\\e046\";\n}\n.glyphicon-font:before {\n content: \"\\e047\";\n}\n.glyphicon-bold:before {\n content: \"\\e048\";\n}\n.glyphicon-italic:before {\n content: \"\\e049\";\n}\n.glyphicon-text-height:before {\n content: \"\\e050\";\n}\n.glyphicon-text-width:before {\n content: \"\\e051\";\n}\n.glyphicon-align-left:before {\n content: \"\\e052\";\n}\n.glyphicon-align-center:before {\n content: \"\\e053\";\n}\n.glyphicon-align-right:before {\n content: \"\\e054\";\n}\n.glyphicon-align-justify:before {\n content: \"\\e055\";\n}\n.glyphicon-list:before {\n content: \"\\e056\";\n}\n.glyphicon-indent-left:before {\n content: \"\\e057\";\n}\n.glyphicon-indent-right:before {\n content: \"\\e058\";\n}\n.glyphicon-facetime-video:before {\n content: \"\\e059\";\n}\n.glyphicon-picture:before {\n content: \"\\e060\";\n}\n.glyphicon-map-marker:before {\n content: \"\\e062\";\n}\n.glyphicon-adjust:before {\n content: \"\\e063\";\n}\n.glyphicon-tint:before {\n content: \"\\e064\";\n}\n.glyphicon-edit:before {\n content: \"\\e065\";\n}\n.glyphicon-share:before {\n content: \"\\e066\";\n}\n.glyphicon-check:before {\n content: \"\\e067\";\n}\n.glyphicon-move:before {\n content: \"\\e068\";\n}\n.glyphicon-step-backward:before {\n content: \"\\e069\";\n}\n.glyphicon-fast-backward:before {\n content: \"\\e070\";\n}\n.glyphicon-backward:before {\n content: \"\\e071\";\n}\n.glyphicon-play:before {\n content: \"\\e072\";\n}\n.glyphicon-pause:before {\n content: \"\\e073\";\n}\n.glyphicon-stop:before {\n content: \"\\e074\";\n}\n.glyphicon-forward:before {\n content: \"\\e075\";\n}\n.glyphicon-fast-forward:before {\n content: \"\\e076\";\n}\n.glyphicon-step-forward:before {\n content: \"\\e077\";\n}\n.glyphicon-eject:before {\n content: \"\\e078\";\n}\n.glyphicon-chevron-left:before {\n content: \"\\e079\";\n}\n.glyphicon-chevron-right:before {\n content: \"\\e080\";\n}\n.glyphicon-plus-sign:before {\n content: \"\\e081\";\n}\n.glyphicon-minus-sign:before {\n content: \"\\e082\";\n}\n.glyphicon-remove-sign:before {\n content: \"\\e083\";\n}\n.glyphicon-ok-sign:before {\n content: \"\\e084\";\n}\n.glyphicon-question-sign:before {\n content: \"\\e085\";\n}\n.glyphicon-info-sign:before {\n content: \"\\e086\";\n}\n.glyphicon-screenshot:before {\n content: \"\\e087\";\n}\n.glyphicon-remove-circle:before {\n content: \"\\e088\";\n}\n.glyphicon-ok-circle:before {\n content: \"\\e089\";\n}\n.glyphicon-ban-circle:before {\n content: \"\\e090\";\n}\n.glyphicon-arrow-left:before {\n content: \"\\e091\";\n}\n.glyphicon-arrow-right:before {\n content: \"\\e092\";\n}\n.glyphicon-arrow-up:before {\n content: \"\\e093\";\n}\n.glyphicon-arrow-down:before {\n content: \"\\e094\";\n}\n.glyphicon-share-alt:before {\n content: \"\\e095\";\n}\n.glyphicon-resize-full:before {\n content: \"\\e096\";\n}\n.glyphicon-resize-small:before {\n content: \"\\e097\";\n}\n.glyphicon-exclamation-sign:before {\n content: \"\\e101\";\n}\n.glyphicon-gift:before {\n content: \"\\e102\";\n}\n.glyphicon-leaf:before {\n content: \"\\e103\";\n}\n.glyphicon-fire:before {\n content: \"\\e104\";\n}\n.glyphicon-eye-open:before {\n content: \"\\e105\";\n}\n.glyphicon-eye-close:before {\n content: \"\\e106\";\n}\n.glyphicon-warning-sign:before {\n content: \"\\e107\";\n}\n.glyphicon-plane:before {\n content: \"\\e108\";\n}\n.glyphicon-calendar:before {\n content: \"\\e109\";\n}\n.glyphicon-random:before {\n content: \"\\e110\";\n}\n.glyphicon-comment:before {\n content: \"\\e111\";\n}\n.glyphicon-magnet:before {\n content: \"\\e112\";\n}\n.glyphicon-chevron-up:before {\n content: \"\\e113\";\n}\n.glyphicon-chevron-down:before {\n content: \"\\e114\";\n}\n.glyphicon-retweet:before {\n content: \"\\e115\";\n}\n.glyphicon-shopping-cart:before {\n content: \"\\e116\";\n}\n.glyphicon-folder-close:before {\n content: \"\\e117\";\n}\n.glyphicon-folder-open:before {\n content: \"\\e118\";\n}\n.glyphicon-resize-vertical:before {\n content: \"\\e119\";\n}\n.glyphicon-resize-horizontal:before {\n content: \"\\e120\";\n}\n.glyphicon-hdd:before {\n content: \"\\e121\";\n}\n.glyphicon-bullhorn:before {\n content: \"\\e122\";\n}\n.glyphicon-bell:before {\n content: \"\\e123\";\n}\n.glyphicon-certificate:before {\n content: \"\\e124\";\n}\n.glyphicon-thumbs-up:before {\n content: \"\\e125\";\n}\n.glyphicon-thumbs-down:before {\n content: \"\\e126\";\n}\n.glyphicon-hand-right:before {\n content: \"\\e127\";\n}\n.glyphicon-hand-left:before {\n content: \"\\e128\";\n}\n.glyphicon-hand-up:before {\n content: \"\\e129\";\n}\n.glyphicon-hand-down:before {\n content: \"\\e130\";\n}\n.glyphicon-circle-arrow-right:before {\n content: \"\\e131\";\n}\n.glyphicon-circle-arrow-left:before {\n content: \"\\e132\";\n}\n.glyphicon-circle-arrow-up:before {\n content: \"\\e133\";\n}\n.glyphicon-circle-arrow-down:before {\n content: \"\\e134\";\n}\n.glyphicon-globe:before {\n content: \"\\e135\";\n}\n.glyphicon-wrench:before {\n content: \"\\e136\";\n}\n.glyphicon-tasks:before {\n content: \"\\e137\";\n}\n.glyphicon-filter:before {\n content: \"\\e138\";\n}\n.glyphicon-briefcase:before {\n content: \"\\e139\";\n}\n.glyphicon-fullscreen:before {\n content: \"\\e140\";\n}\n.glyphicon-dashboard:before {\n content: \"\\e141\";\n}\n.glyphicon-paperclip:before {\n content: \"\\e142\";\n}\n.glyphicon-heart-empty:before {\n content: \"\\e143\";\n}\n.glyphicon-link:before {\n content: \"\\e144\";\n}\n.glyphicon-phone:before {\n content: \"\\e145\";\n}\n.glyphicon-pushpin:before {\n content: \"\\e146\";\n}\n.glyphicon-usd:before {\n content: \"\\e148\";\n}\n.glyphicon-gbp:before {\n content: \"\\e149\";\n}\n.glyphicon-sort:before {\n content: \"\\e150\";\n}\n.glyphicon-sort-by-alphabet:before {\n content: \"\\e151\";\n}\n.glyphicon-sort-by-alphabet-alt:before {\n content: \"\\e152\";\n}\n.glyphicon-sort-by-order:before {\n content: \"\\e153\";\n}\n.glyphicon-sort-by-order-alt:before {\n content: \"\\e154\";\n}\n.glyphicon-sort-by-attributes:before {\n content: \"\\e155\";\n}\n.glyphicon-sort-by-attributes-alt:before {\n content: \"\\e156\";\n}\n.glyphicon-unchecked:before {\n content: \"\\e157\";\n}\n.glyphicon-expand:before {\n content: \"\\e158\";\n}\n.glyphicon-collapse-down:before {\n content: \"\\e159\";\n}\n.glyphicon-collapse-up:before {\n content: \"\\e160\";\n}\n.glyphicon-log-in:before {\n content: \"\\e161\";\n}\n.glyphicon-flash:before {\n content: \"\\e162\";\n}\n.glyphicon-log-out:before {\n content: \"\\e163\";\n}\n.glyphicon-new-window:before {\n content: \"\\e164\";\n}\n.glyphicon-record:before {\n content: \"\\e165\";\n}\n.glyphicon-save:before {\n content: \"\\e166\";\n}\n.glyphicon-open:before {\n content: \"\\e167\";\n}\n.glyphicon-saved:before {\n content: \"\\e168\";\n}\n.glyphicon-import:before {\n content: \"\\e169\";\n}\n.glyphicon-export:before {\n content: \"\\e170\";\n}\n.glyphicon-send:before {\n content: \"\\e171\";\n}\n.glyphicon-floppy-disk:before {\n content: \"\\e172\";\n}\n.glyphicon-floppy-saved:before {\n content: \"\\e173\";\n}\n.glyphicon-floppy-remove:before {\n content: \"\\e174\";\n}\n.glyphicon-floppy-save:before {\n content: \"\\e175\";\n}\n.glyphicon-floppy-open:before {\n content: \"\\e176\";\n}\n.glyphicon-credit-card:before {\n content: \"\\e177\";\n}\n.glyphicon-transfer:before {\n content: \"\\e178\";\n}\n.glyphicon-cutlery:before {\n content: \"\\e179\";\n}\n.glyphicon-header:before {\n content: \"\\e180\";\n}\n.glyphicon-compressed:before {\n content: \"\\e181\";\n}\n.glyphicon-earphone:before {\n content: \"\\e182\";\n}\n.glyphicon-phone-alt:before {\n content: \"\\e183\";\n}\n.glyphicon-tower:before {\n content: \"\\e184\";\n}\n.glyphicon-stats:before {\n content: \"\\e185\";\n}\n.glyphicon-sd-video:before {\n content: \"\\e186\";\n}\n.glyphicon-hd-video:before {\n content: \"\\e187\";\n}\n.glyphicon-subtitles:before {\n content: \"\\e188\";\n}\n.glyphicon-sound-stereo:before {\n content: \"\\e189\";\n}\n.glyphicon-sound-dolby:before {\n content: \"\\e190\";\n}\n.glyphicon-sound-5-1:before {\n content: \"\\e191\";\n}\n.glyphicon-sound-6-1:before {\n content: \"\\e192\";\n}\n.glyphicon-sound-7-1:before {\n content: \"\\e193\";\n}\n.glyphicon-copyright-mark:before {\n content: \"\\e194\";\n}\n.glyphicon-registration-mark:before {\n content: \"\\e195\";\n}\n.glyphicon-cloud-download:before {\n content: \"\\e197\";\n}\n.glyphicon-cloud-upload:before {\n content: \"\\e198\";\n}\n.glyphicon-tree-conifer:before {\n content: \"\\e199\";\n}\n.glyphicon-tree-deciduous:before {\n content: \"\\e200\";\n}\n.glyphicon-cd:before {\n content: \"\\e201\";\n}\n.glyphicon-save-file:before {\n content: \"\\e202\";\n}\n.glyphicon-open-file:before {\n content: \"\\e203\";\n}\n.glyphicon-level-up:before {\n content: \"\\e204\";\n}\n.glyphicon-copy:before {\n content: \"\\e205\";\n}\n.glyphicon-paste:before {\n content: \"\\e206\";\n}\n.glyphicon-alert:before {\n content: \"\\e209\";\n}\n.glyphicon-equalizer:before {\n content: \"\\e210\";\n}\n.glyphicon-king:before {\n content: \"\\e211\";\n}\n.glyphicon-queen:before {\n content: \"\\e212\";\n}\n.glyphicon-pawn:before {\n content: \"\\e213\";\n}\n.glyphicon-bishop:before {\n content: \"\\e214\";\n}\n.glyphicon-knight:before {\n content: \"\\e215\";\n}\n.glyphicon-baby-formula:before {\n content: \"\\e216\";\n}\n.glyphicon-tent:before {\n content: \"\\26fa\";\n}\n.glyphicon-blackboard:before {\n content: \"\\e218\";\n}\n.glyphicon-bed:before {\n content: \"\\e219\";\n}\n.glyphicon-apple:before {\n content: \"\\f8ff\";\n}\n.glyphicon-erase:before {\n content: \"\\e221\";\n}\n.glyphicon-hourglass:before {\n content: \"\\231b\";\n}\n.glyphicon-lamp:before {\n content: \"\\e223\";\n}\n.glyphicon-duplicate:before {\n content: \"\\e224\";\n}\n.glyphicon-piggy-bank:before {\n content: \"\\e225\";\n}\n.glyphicon-scissors:before {\n content: \"\\e226\";\n}\n.glyphicon-bitcoin:before {\n content: \"\\e227\";\n}\n.glyphicon-btc:before {\n content: \"\\e227\";\n}\n.glyphicon-xbt:before {\n content: \"\\e227\";\n}\n.glyphicon-yen:before {\n content: \"\\00a5\";\n}\n.glyphicon-jpy:before {\n content: \"\\00a5\";\n}\n.glyphicon-ruble:before {\n content: \"\\20bd\";\n}\n.glyphicon-rub:before {\n content: \"\\20bd\";\n}\n.glyphicon-scale:before {\n content: \"\\e230\";\n}\n.glyphicon-ice-lolly:before {\n content: \"\\e231\";\n}\n.glyphicon-ice-lolly-tasted:before {\n content: \"\\e232\";\n}\n.glyphicon-education:before {\n content: \"\\e233\";\n}\n.glyphicon-option-horizontal:before {\n content: \"\\e234\";\n}\n.glyphicon-option-vertical:before {\n content: \"\\e235\";\n}\n.glyphicon-menu-hamburger:before {\n content: \"\\e236\";\n}\n.glyphicon-modal-window:before {\n content: \"\\e237\";\n}\n.glyphicon-oil:before {\n content: \"\\e238\";\n}\n.glyphicon-grain:before {\n content: \"\\e239\";\n}\n.glyphicon-sunglasses:before {\n content: \"\\e240\";\n}\n.glyphicon-text-size:before {\n content: \"\\e241\";\n}\n.glyphicon-text-color:before {\n content: \"\\e242\";\n}\n.glyphicon-text-background:before {\n content: \"\\e243\";\n}\n.glyphicon-object-align-top:before {\n content: \"\\e244\";\n}\n.glyphicon-object-align-bottom:before {\n content: \"\\e245\";\n}\n.glyphicon-object-align-horizontal:before {\n content: \"\\e246\";\n}\n.glyphicon-object-align-left:before {\n content: \"\\e247\";\n}\n.glyphicon-object-align-vertical:before {\n content: \"\\e248\";\n}\n.glyphicon-object-align-right:before {\n content: \"\\e249\";\n}\n.glyphicon-triangle-right:before {\n content: \"\\e250\";\n}\n.glyphicon-triangle-left:before {\n content: \"\\e251\";\n}\n.glyphicon-triangle-bottom:before {\n content: \"\\e252\";\n}\n.glyphicon-triangle-top:before {\n content: \"\\e253\";\n}\n.glyphicon-console:before {\n content: \"\\e254\";\n}\n.glyphicon-superscript:before {\n content: \"\\e255\";\n}\n.glyphicon-subscript:before {\n content: \"\\e256\";\n}\n.glyphicon-menu-left:before {\n content: \"\\e257\";\n}\n.glyphicon-menu-right:before {\n content: \"\\e258\";\n}\n.glyphicon-menu-down:before {\n content: \"\\e259\";\n}\n.glyphicon-menu-up:before {\n content: \"\\e260\";\n}\n* {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n*:before,\n*:after {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\nbody {\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.42857143;\n color: #333333;\n background-color: #ffffff;\n}\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\na {\n color: #337ab7;\n text-decoration: none;\n}\na:hover,\na:focus {\n color: #23527c;\n text-decoration: underline;\n}\na:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\nfigure {\n margin: 0;\n}\nimg {\n vertical-align: middle;\n}\n.img-responsive,\n.thumbnail > img,\n.thumbnail a > img,\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n display: block;\n max-width: 100%;\n height: auto;\n}\n.img-rounded {\n border-radius: 6px;\n}\n.img-thumbnail {\n padding: 4px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: all 0.2s ease-in-out;\n -o-transition: all 0.2s ease-in-out;\n transition: all 0.2s ease-in-out;\n display: inline-block;\n max-width: 100%;\n height: auto;\n}\n.img-circle {\n border-radius: 50%;\n}\nhr {\n margin-top: 20px;\n margin-bottom: 20px;\n border: 0;\n border-top: 1px solid #eeeeee;\n}\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n border: 0;\n}\n.sr-only-focusable:active,\n.sr-only-focusable:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n}\n[role=\"button\"] {\n cursor: pointer;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\n.h1,\n.h2,\n.h3,\n.h4,\n.h5,\n.h6 {\n font-family: inherit;\n font-weight: 500;\n line-height: 1.1;\n color: inherit;\n}\nh1 small,\nh2 small,\nh3 small,\nh4 small,\nh5 small,\nh6 small,\n.h1 small,\n.h2 small,\n.h3 small,\n.h4 small,\n.h5 small,\n.h6 small,\nh1 .small,\nh2 .small,\nh3 .small,\nh4 .small,\nh5 .small,\nh6 .small,\n.h1 .small,\n.h2 .small,\n.h3 .small,\n.h4 .small,\n.h5 .small,\n.h6 .small {\n font-weight: normal;\n line-height: 1;\n color: #777777;\n}\nh1,\n.h1,\nh2,\n.h2,\nh3,\n.h3 {\n margin-top: 20px;\n margin-bottom: 10px;\n}\nh1 small,\n.h1 small,\nh2 small,\n.h2 small,\nh3 small,\n.h3 small,\nh1 .small,\n.h1 .small,\nh2 .small,\n.h2 .small,\nh3 .small,\n.h3 .small {\n font-size: 65%;\n}\nh4,\n.h4,\nh5,\n.h5,\nh6,\n.h6 {\n margin-top: 10px;\n margin-bottom: 10px;\n}\nh4 small,\n.h4 small,\nh5 small,\n.h5 small,\nh6 small,\n.h6 small,\nh4 .small,\n.h4 .small,\nh5 .small,\n.h5 .small,\nh6 .small,\n.h6 .small {\n font-size: 75%;\n}\nh1,\n.h1 {\n font-size: 36px;\n}\nh2,\n.h2 {\n font-size: 30px;\n}\nh3,\n.h3 {\n font-size: 24px;\n}\nh4,\n.h4 {\n font-size: 18px;\n}\nh5,\n.h5 {\n font-size: 14px;\n}\nh6,\n.h6 {\n font-size: 12px;\n}\np {\n margin: 0 0 10px;\n}\n.lead {\n margin-bottom: 20px;\n font-size: 16px;\n font-weight: 300;\n line-height: 1.4;\n}\n@media (min-width: 768px) {\n .lead {\n font-size: 21px;\n }\n}\nsmall,\n.small {\n font-size: 85%;\n}\nmark,\n.mark {\n background-color: #fcf8e3;\n padding: .2em;\n}\n.text-left {\n text-align: left;\n}\n.text-right {\n text-align: right;\n}\n.text-center {\n text-align: center;\n}\n.text-justify {\n text-align: justify;\n}\n.text-nowrap {\n white-space: nowrap;\n}\n.text-lowercase {\n text-transform: lowercase;\n}\n.text-uppercase {\n text-transform: uppercase;\n}\n.text-capitalize {\n text-transform: capitalize;\n}\n.text-muted {\n color: #777777;\n}\n.text-primary {\n color: #337ab7;\n}\na.text-primary:hover,\na.text-primary:focus {\n color: #286090;\n}\n.text-success {\n color: #3c763d;\n}\na.text-success:hover,\na.text-success:focus {\n color: #2b542c;\n}\n.text-info {\n color: #31708f;\n}\na.text-info:hover,\na.text-info:focus {\n color: #245269;\n}\n.text-warning {\n color: #8a6d3b;\n}\na.text-warning:hover,\na.text-warning:focus {\n color: #66512c;\n}\n.text-danger {\n color: #a94442;\n}\na.text-danger:hover,\na.text-danger:focus {\n color: #843534;\n}\n.bg-primary {\n color: #fff;\n background-color: #337ab7;\n}\na.bg-primary:hover,\na.bg-primary:focus {\n background-color: #286090;\n}\n.bg-success {\n background-color: #dff0d8;\n}\na.bg-success:hover,\na.bg-success:focus {\n background-color: #c1e2b3;\n}\n.bg-info {\n background-color: #d9edf7;\n}\na.bg-info:hover,\na.bg-info:focus {\n background-color: #afd9ee;\n}\n.bg-warning {\n background-color: #fcf8e3;\n}\na.bg-warning:hover,\na.bg-warning:focus {\n background-color: #f7ecb5;\n}\n.bg-danger {\n background-color: #f2dede;\n}\na.bg-danger:hover,\na.bg-danger:focus {\n background-color: #e4b9b9;\n}\n.page-header {\n padding-bottom: 9px;\n margin: 40px 0 20px;\n border-bottom: 1px solid #eeeeee;\n}\nul,\nol {\n margin-top: 0;\n margin-bottom: 10px;\n}\nul ul,\nol ul,\nul ol,\nol ol {\n margin-bottom: 0;\n}\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n.list-inline {\n padding-left: 0;\n list-style: none;\n margin-left: -5px;\n}\n.list-inline > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n}\ndl {\n margin-top: 0;\n margin-bottom: 20px;\n}\ndt,\ndd {\n line-height: 1.42857143;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0;\n}\n@media (min-width: 768px) {\n .dl-horizontal dt {\n float: left;\n width: 160px;\n clear: left;\n text-align: right;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .dl-horizontal dd {\n margin-left: 180px;\n }\n}\nabbr[title],\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted #777777;\n}\n.initialism {\n font-size: 90%;\n text-transform: uppercase;\n}\nblockquote {\n padding: 10px 20px;\n margin: 0 0 20px;\n font-size: 17.5px;\n border-left: 5px solid #eeeeee;\n}\nblockquote p:last-child,\nblockquote ul:last-child,\nblockquote ol:last-child {\n margin-bottom: 0;\n}\nblockquote footer,\nblockquote small,\nblockquote .small {\n display: block;\n font-size: 80%;\n line-height: 1.42857143;\n color: #777777;\n}\nblockquote footer:before,\nblockquote small:before,\nblockquote .small:before {\n content: '\\2014 \\00A0';\n}\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid #eeeeee;\n border-left: 0;\n text-align: right;\n}\n.blockquote-reverse footer:before,\nblockquote.pull-right footer:before,\n.blockquote-reverse small:before,\nblockquote.pull-right small:before,\n.blockquote-reverse .small:before,\nblockquote.pull-right .small:before {\n content: '';\n}\n.blockquote-reverse footer:after,\nblockquote.pull-right footer:after,\n.blockquote-reverse small:after,\nblockquote.pull-right small:after,\n.blockquote-reverse .small:after,\nblockquote.pull-right .small:after {\n content: '\\00A0 \\2014';\n}\naddress {\n margin-bottom: 20px;\n font-style: normal;\n line-height: 1.42857143;\n}\ncode,\nkbd,\npre,\nsamp {\n font-family: Menlo, Monaco, Consolas, \"Courier New\", monospace;\n}\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: #c7254e;\n background-color: #f9f2f4;\n border-radius: 4px;\n}\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: #ffffff;\n background-color: #333333;\n border-radius: 3px;\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);\n}\nkbd kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n}\npre {\n display: block;\n padding: 9.5px;\n margin: 0 0 10px;\n font-size: 13px;\n line-height: 1.42857143;\n word-break: break-all;\n word-wrap: break-word;\n color: #333333;\n background-color: #f5f5f5;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\npre code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n}\n.pre-scrollable {\n max-height: 340px;\n overflow-y: scroll;\n}\n.container {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n@media (min-width: 768px) {\n .container {\n width: 750px;\n }\n}\n@media (min-width: 992px) {\n .container {\n width: 970px;\n }\n}\n@media (min-width: 1200px) {\n .container {\n width: 1170px;\n }\n}\n.container-fluid {\n margin-right: auto;\n margin-left: auto;\n padding-left: 15px;\n padding-right: 15px;\n}\n.row {\n margin-left: -15px;\n margin-right: -15px;\n}\n.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 {\n position: relative;\n min-height: 1px;\n padding-left: 15px;\n padding-right: 15px;\n}\n.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 {\n float: left;\n}\n.col-xs-12 {\n width: 100%;\n}\n.col-xs-11 {\n width: 91.66666667%;\n}\n.col-xs-10 {\n width: 83.33333333%;\n}\n.col-xs-9 {\n width: 75%;\n}\n.col-xs-8 {\n width: 66.66666667%;\n}\n.col-xs-7 {\n width: 58.33333333%;\n}\n.col-xs-6 {\n width: 50%;\n}\n.col-xs-5 {\n width: 41.66666667%;\n}\n.col-xs-4 {\n width: 33.33333333%;\n}\n.col-xs-3 {\n width: 25%;\n}\n.col-xs-2 {\n width: 16.66666667%;\n}\n.col-xs-1 {\n width: 8.33333333%;\n}\n.col-xs-pull-12 {\n right: 100%;\n}\n.col-xs-pull-11 {\n right: 91.66666667%;\n}\n.col-xs-pull-10 {\n right: 83.33333333%;\n}\n.col-xs-pull-9 {\n right: 75%;\n}\n.col-xs-pull-8 {\n right: 66.66666667%;\n}\n.col-xs-pull-7 {\n right: 58.33333333%;\n}\n.col-xs-pull-6 {\n right: 50%;\n}\n.col-xs-pull-5 {\n right: 41.66666667%;\n}\n.col-xs-pull-4 {\n right: 33.33333333%;\n}\n.col-xs-pull-3 {\n right: 25%;\n}\n.col-xs-pull-2 {\n right: 16.66666667%;\n}\n.col-xs-pull-1 {\n right: 8.33333333%;\n}\n.col-xs-pull-0 {\n right: auto;\n}\n.col-xs-push-12 {\n left: 100%;\n}\n.col-xs-push-11 {\n left: 91.66666667%;\n}\n.col-xs-push-10 {\n left: 83.33333333%;\n}\n.col-xs-push-9 {\n left: 75%;\n}\n.col-xs-push-8 {\n left: 66.66666667%;\n}\n.col-xs-push-7 {\n left: 58.33333333%;\n}\n.col-xs-push-6 {\n left: 50%;\n}\n.col-xs-push-5 {\n left: 41.66666667%;\n}\n.col-xs-push-4 {\n left: 33.33333333%;\n}\n.col-xs-push-3 {\n left: 25%;\n}\n.col-xs-push-2 {\n left: 16.66666667%;\n}\n.col-xs-push-1 {\n left: 8.33333333%;\n}\n.col-xs-push-0 {\n left: auto;\n}\n.col-xs-offset-12 {\n margin-left: 100%;\n}\n.col-xs-offset-11 {\n margin-left: 91.66666667%;\n}\n.col-xs-offset-10 {\n margin-left: 83.33333333%;\n}\n.col-xs-offset-9 {\n margin-left: 75%;\n}\n.col-xs-offset-8 {\n margin-left: 66.66666667%;\n}\n.col-xs-offset-7 {\n margin-left: 58.33333333%;\n}\n.col-xs-offset-6 {\n margin-left: 50%;\n}\n.col-xs-offset-5 {\n margin-left: 41.66666667%;\n}\n.col-xs-offset-4 {\n margin-left: 33.33333333%;\n}\n.col-xs-offset-3 {\n margin-left: 25%;\n}\n.col-xs-offset-2 {\n margin-left: 16.66666667%;\n}\n.col-xs-offset-1 {\n margin-left: 8.33333333%;\n}\n.col-xs-offset-0 {\n margin-left: 0%;\n}\n@media (min-width: 768px) {\n .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 {\n float: left;\n }\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666667%;\n }\n .col-sm-10 {\n width: 83.33333333%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666667%;\n }\n .col-sm-7 {\n width: 58.33333333%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666667%;\n }\n .col-sm-4 {\n width: 33.33333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.66666667%;\n }\n .col-sm-1 {\n width: 8.33333333%;\n }\n .col-sm-pull-12 {\n right: 100%;\n }\n .col-sm-pull-11 {\n right: 91.66666667%;\n }\n .col-sm-pull-10 {\n right: 83.33333333%;\n }\n .col-sm-pull-9 {\n right: 75%;\n }\n .col-sm-pull-8 {\n right: 66.66666667%;\n }\n .col-sm-pull-7 {\n right: 58.33333333%;\n }\n .col-sm-pull-6 {\n right: 50%;\n }\n .col-sm-pull-5 {\n right: 41.66666667%;\n }\n .col-sm-pull-4 {\n right: 33.33333333%;\n }\n .col-sm-pull-3 {\n right: 25%;\n }\n .col-sm-pull-2 {\n right: 16.66666667%;\n }\n .col-sm-pull-1 {\n right: 8.33333333%;\n }\n .col-sm-pull-0 {\n right: auto;\n }\n .col-sm-push-12 {\n left: 100%;\n }\n .col-sm-push-11 {\n left: 91.66666667%;\n }\n .col-sm-push-10 {\n left: 83.33333333%;\n }\n .col-sm-push-9 {\n left: 75%;\n }\n .col-sm-push-8 {\n left: 66.66666667%;\n }\n .col-sm-push-7 {\n left: 58.33333333%;\n }\n .col-sm-push-6 {\n left: 50%;\n }\n .col-sm-push-5 {\n left: 41.66666667%;\n }\n .col-sm-push-4 {\n left: 33.33333333%;\n }\n .col-sm-push-3 {\n left: 25%;\n }\n .col-sm-push-2 {\n left: 16.66666667%;\n }\n .col-sm-push-1 {\n left: 8.33333333%;\n }\n .col-sm-push-0 {\n left: auto;\n }\n .col-sm-offset-12 {\n margin-left: 100%;\n }\n .col-sm-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-sm-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-sm-offset-9 {\n margin-left: 75%;\n }\n .col-sm-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-sm-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-sm-offset-6 {\n margin-left: 50%;\n }\n .col-sm-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-sm-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-sm-offset-3 {\n margin-left: 25%;\n }\n .col-sm-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-sm-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-sm-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 992px) {\n .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 {\n float: left;\n }\n .col-md-12 {\n width: 100%;\n }\n .col-md-11 {\n width: 91.66666667%;\n }\n .col-md-10 {\n width: 83.33333333%;\n }\n .col-md-9 {\n width: 75%;\n }\n .col-md-8 {\n width: 66.66666667%;\n }\n .col-md-7 {\n width: 58.33333333%;\n }\n .col-md-6 {\n width: 50%;\n }\n .col-md-5 {\n width: 41.66666667%;\n }\n .col-md-4 {\n width: 33.33333333%;\n }\n .col-md-3 {\n width: 25%;\n }\n .col-md-2 {\n width: 16.66666667%;\n }\n .col-md-1 {\n width: 8.33333333%;\n }\n .col-md-pull-12 {\n right: 100%;\n }\n .col-md-pull-11 {\n right: 91.66666667%;\n }\n .col-md-pull-10 {\n right: 83.33333333%;\n }\n .col-md-pull-9 {\n right: 75%;\n }\n .col-md-pull-8 {\n right: 66.66666667%;\n }\n .col-md-pull-7 {\n right: 58.33333333%;\n }\n .col-md-pull-6 {\n right: 50%;\n }\n .col-md-pull-5 {\n right: 41.66666667%;\n }\n .col-md-pull-4 {\n right: 33.33333333%;\n }\n .col-md-pull-3 {\n right: 25%;\n }\n .col-md-pull-2 {\n right: 16.66666667%;\n }\n .col-md-pull-1 {\n right: 8.33333333%;\n }\n .col-md-pull-0 {\n right: auto;\n }\n .col-md-push-12 {\n left: 100%;\n }\n .col-md-push-11 {\n left: 91.66666667%;\n }\n .col-md-push-10 {\n left: 83.33333333%;\n }\n .col-md-push-9 {\n left: 75%;\n }\n .col-md-push-8 {\n left: 66.66666667%;\n }\n .col-md-push-7 {\n left: 58.33333333%;\n }\n .col-md-push-6 {\n left: 50%;\n }\n .col-md-push-5 {\n left: 41.66666667%;\n }\n .col-md-push-4 {\n left: 33.33333333%;\n }\n .col-md-push-3 {\n left: 25%;\n }\n .col-md-push-2 {\n left: 16.66666667%;\n }\n .col-md-push-1 {\n left: 8.33333333%;\n }\n .col-md-push-0 {\n left: auto;\n }\n .col-md-offset-12 {\n margin-left: 100%;\n }\n .col-md-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-md-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-md-offset-9 {\n margin-left: 75%;\n }\n .col-md-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-md-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-md-offset-6 {\n margin-left: 50%;\n }\n .col-md-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-md-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-md-offset-3 {\n margin-left: 25%;\n }\n .col-md-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-md-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-md-offset-0 {\n margin-left: 0%;\n }\n}\n@media (min-width: 1200px) {\n .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 {\n float: left;\n }\n .col-lg-12 {\n width: 100%;\n }\n .col-lg-11 {\n width: 91.66666667%;\n }\n .col-lg-10 {\n width: 83.33333333%;\n }\n .col-lg-9 {\n width: 75%;\n }\n .col-lg-8 {\n width: 66.66666667%;\n }\n .col-lg-7 {\n width: 58.33333333%;\n }\n .col-lg-6 {\n width: 50%;\n }\n .col-lg-5 {\n width: 41.66666667%;\n }\n .col-lg-4 {\n width: 33.33333333%;\n }\n .col-lg-3 {\n width: 25%;\n }\n .col-lg-2 {\n width: 16.66666667%;\n }\n .col-lg-1 {\n width: 8.33333333%;\n }\n .col-lg-pull-12 {\n right: 100%;\n }\n .col-lg-pull-11 {\n right: 91.66666667%;\n }\n .col-lg-pull-10 {\n right: 83.33333333%;\n }\n .col-lg-pull-9 {\n right: 75%;\n }\n .col-lg-pull-8 {\n right: 66.66666667%;\n }\n .col-lg-pull-7 {\n right: 58.33333333%;\n }\n .col-lg-pull-6 {\n right: 50%;\n }\n .col-lg-pull-5 {\n right: 41.66666667%;\n }\n .col-lg-pull-4 {\n right: 33.33333333%;\n }\n .col-lg-pull-3 {\n right: 25%;\n }\n .col-lg-pull-2 {\n right: 16.66666667%;\n }\n .col-lg-pull-1 {\n right: 8.33333333%;\n }\n .col-lg-pull-0 {\n right: auto;\n }\n .col-lg-push-12 {\n left: 100%;\n }\n .col-lg-push-11 {\n left: 91.66666667%;\n }\n .col-lg-push-10 {\n left: 83.33333333%;\n }\n .col-lg-push-9 {\n left: 75%;\n }\n .col-lg-push-8 {\n left: 66.66666667%;\n }\n .col-lg-push-7 {\n left: 58.33333333%;\n }\n .col-lg-push-6 {\n left: 50%;\n }\n .col-lg-push-5 {\n left: 41.66666667%;\n }\n .col-lg-push-4 {\n left: 33.33333333%;\n }\n .col-lg-push-3 {\n left: 25%;\n }\n .col-lg-push-2 {\n left: 16.66666667%;\n }\n .col-lg-push-1 {\n left: 8.33333333%;\n }\n .col-lg-push-0 {\n left: auto;\n }\n .col-lg-offset-12 {\n margin-left: 100%;\n }\n .col-lg-offset-11 {\n margin-left: 91.66666667%;\n }\n .col-lg-offset-10 {\n margin-left: 83.33333333%;\n }\n .col-lg-offset-9 {\n margin-left: 75%;\n }\n .col-lg-offset-8 {\n margin-left: 66.66666667%;\n }\n .col-lg-offset-7 {\n margin-left: 58.33333333%;\n }\n .col-lg-offset-6 {\n margin-left: 50%;\n }\n .col-lg-offset-5 {\n margin-left: 41.66666667%;\n }\n .col-lg-offset-4 {\n margin-left: 33.33333333%;\n }\n .col-lg-offset-3 {\n margin-left: 25%;\n }\n .col-lg-offset-2 {\n margin-left: 16.66666667%;\n }\n .col-lg-offset-1 {\n margin-left: 8.33333333%;\n }\n .col-lg-offset-0 {\n margin-left: 0%;\n }\n}\ntable {\n background-color: transparent;\n}\ncaption {\n padding-top: 8px;\n padding-bottom: 8px;\n color: #777777;\n text-align: left;\n}\nth {\n text-align: left;\n}\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: 20px;\n}\n.table > thead > tr > th,\n.table > tbody > tr > th,\n.table > tfoot > tr > th,\n.table > thead > tr > td,\n.table > tbody > tr > td,\n.table > tfoot > tr > td {\n padding: 8px;\n line-height: 1.42857143;\n vertical-align: top;\n border-top: 1px solid #dddddd;\n}\n.table > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid #dddddd;\n}\n.table > caption + thead > tr:first-child > th,\n.table > colgroup + thead > tr:first-child > th,\n.table > thead:first-child > tr:first-child > th,\n.table > caption + thead > tr:first-child > td,\n.table > colgroup + thead > tr:first-child > td,\n.table > thead:first-child > tr:first-child > td {\n border-top: 0;\n}\n.table > tbody + tbody {\n border-top: 2px solid #dddddd;\n}\n.table .table {\n background-color: #ffffff;\n}\n.table-condensed > thead > tr > th,\n.table-condensed > tbody > tr > th,\n.table-condensed > tfoot > tr > th,\n.table-condensed > thead > tr > td,\n.table-condensed > tbody > tr > td,\n.table-condensed > tfoot > tr > td {\n padding: 5px;\n}\n.table-bordered {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > tbody > tr > th,\n.table-bordered > tfoot > tr > th,\n.table-bordered > thead > tr > td,\n.table-bordered > tbody > tr > td,\n.table-bordered > tfoot > tr > td {\n border: 1px solid #dddddd;\n}\n.table-bordered > thead > tr > th,\n.table-bordered > thead > tr > td {\n border-bottom-width: 2px;\n}\n.table-striped > tbody > tr:nth-of-type(odd) {\n background-color: #f9f9f9;\n}\n.table-hover > tbody > tr:hover {\n background-color: #f5f5f5;\n}\ntable col[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-column;\n}\ntable td[class*=\"col-\"],\ntable th[class*=\"col-\"] {\n position: static;\n float: none;\n display: table-cell;\n}\n.table > thead > tr > td.active,\n.table > tbody > tr > td.active,\n.table > tfoot > tr > td.active,\n.table > thead > tr > th.active,\n.table > tbody > tr > th.active,\n.table > tfoot > tr > th.active,\n.table > thead > tr.active > td,\n.table > tbody > tr.active > td,\n.table > tfoot > tr.active > td,\n.table > thead > tr.active > th,\n.table > tbody > tr.active > th,\n.table > tfoot > tr.active > th {\n background-color: #f5f5f5;\n}\n.table-hover > tbody > tr > td.active:hover,\n.table-hover > tbody > tr > th.active:hover,\n.table-hover > tbody > tr.active:hover > td,\n.table-hover > tbody > tr:hover > .active,\n.table-hover > tbody > tr.active:hover > th {\n background-color: #e8e8e8;\n}\n.table > thead > tr > td.success,\n.table > tbody > tr > td.success,\n.table > tfoot > tr > td.success,\n.table > thead > tr > th.success,\n.table > tbody > tr > th.success,\n.table > tfoot > tr > th.success,\n.table > thead > tr.success > td,\n.table > tbody > tr.success > td,\n.table > tfoot > tr.success > td,\n.table > thead > tr.success > th,\n.table > tbody > tr.success > th,\n.table > tfoot > tr.success > th {\n background-color: #dff0d8;\n}\n.table-hover > tbody > tr > td.success:hover,\n.table-hover > tbody > tr > th.success:hover,\n.table-hover > tbody > tr.success:hover > td,\n.table-hover > tbody > tr:hover > .success,\n.table-hover > tbody > tr.success:hover > th {\n background-color: #d0e9c6;\n}\n.table > thead > tr > td.info,\n.table > tbody > tr > td.info,\n.table > tfoot > tr > td.info,\n.table > thead > tr > th.info,\n.table > tbody > tr > th.info,\n.table > tfoot > tr > th.info,\n.table > thead > tr.info > td,\n.table > tbody > tr.info > td,\n.table > tfoot > tr.info > td,\n.table > thead > tr.info > th,\n.table > tbody > tr.info > th,\n.table > tfoot > tr.info > th {\n background-color: #d9edf7;\n}\n.table-hover > tbody > tr > td.info:hover,\n.table-hover > tbody > tr > th.info:hover,\n.table-hover > tbody > tr.info:hover > td,\n.table-hover > tbody > tr:hover > .info,\n.table-hover > tbody > tr.info:hover > th {\n background-color: #c4e3f3;\n}\n.table > thead > tr > td.warning,\n.table > tbody > tr > td.warning,\n.table > tfoot > tr > td.warning,\n.table > thead > tr > th.warning,\n.table > tbody > tr > th.warning,\n.table > tfoot > tr > th.warning,\n.table > thead > tr.warning > td,\n.table > tbody > tr.warning > td,\n.table > tfoot > tr.warning > td,\n.table > thead > tr.warning > th,\n.table > tbody > tr.warning > th,\n.table > tfoot > tr.warning > th {\n background-color: #fcf8e3;\n}\n.table-hover > tbody > tr > td.warning:hover,\n.table-hover > tbody > tr > th.warning:hover,\n.table-hover > tbody > tr.warning:hover > td,\n.table-hover > tbody > tr:hover > .warning,\n.table-hover > tbody > tr.warning:hover > th {\n background-color: #faf2cc;\n}\n.table > thead > tr > td.danger,\n.table > tbody > tr > td.danger,\n.table > tfoot > tr > td.danger,\n.table > thead > tr > th.danger,\n.table > tbody > tr > th.danger,\n.table > tfoot > tr > th.danger,\n.table > thead > tr.danger > td,\n.table > tbody > tr.danger > td,\n.table > tfoot > tr.danger > td,\n.table > thead > tr.danger > th,\n.table > tbody > tr.danger > th,\n.table > tfoot > tr.danger > th {\n background-color: #f2dede;\n}\n.table-hover > tbody > tr > td.danger:hover,\n.table-hover > tbody > tr > th.danger:hover,\n.table-hover > tbody > tr.danger:hover > td,\n.table-hover > tbody > tr:hover > .danger,\n.table-hover > tbody > tr.danger:hover > th {\n background-color: #ebcccc;\n}\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%;\n}\n@media screen and (max-width: 767px) {\n .table-responsive {\n width: 100%;\n margin-bottom: 15px;\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid #dddddd;\n }\n .table-responsive > .table {\n margin-bottom: 0;\n }\n .table-responsive > .table > thead > tr > th,\n .table-responsive > .table > tbody > tr > th,\n .table-responsive > .table > tfoot > tr > th,\n .table-responsive > .table > thead > tr > td,\n .table-responsive > .table > tbody > tr > td,\n .table-responsive > .table > tfoot > tr > td {\n white-space: nowrap;\n }\n .table-responsive > .table-bordered {\n border: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:first-child,\n .table-responsive > .table-bordered > tbody > tr > th:first-child,\n .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n .table-responsive > .table-bordered > thead > tr > td:first-child,\n .table-responsive > .table-bordered > tbody > tr > td:first-child,\n .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n }\n .table-responsive > .table-bordered > thead > tr > th:last-child,\n .table-responsive > .table-bordered > tbody > tr > th:last-child,\n .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n .table-responsive > .table-bordered > thead > tr > td:last-child,\n .table-responsive > .table-bordered > tbody > tr > td:last-child,\n .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n }\n .table-responsive > .table-bordered > tbody > tr:last-child > th,\n .table-responsive > .table-bordered > tfoot > tr:last-child > th,\n .table-responsive > .table-bordered > tbody > tr:last-child > td,\n .table-responsive > .table-bordered > tfoot > tr:last-child > td {\n border-bottom: 0;\n }\n}\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n min-width: 0;\n}\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: 20px;\n font-size: 21px;\n line-height: inherit;\n color: #333333;\n border: 0;\n border-bottom: 1px solid #e5e5e5;\n}\nlabel {\n display: inline-block;\n max-width: 100%;\n margin-bottom: 5px;\n font-weight: bold;\n}\ninput[type=\"search\"] {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9;\n line-height: normal;\n}\ninput[type=\"file\"] {\n display: block;\n}\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\nselect[multiple],\nselect[size] {\n height: auto;\n}\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\noutput {\n display: block;\n padding-top: 7px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n}\n.form-control {\n display: block;\n width: 100%;\n height: 34px;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n color: #555555;\n background-color: #ffffff;\n background-image: none;\n border: 1px solid #cccccc;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;\n}\n.form-control:focus {\n border-color: #66afe9;\n outline: 0;\n -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);\n}\n.form-control::-moz-placeholder {\n color: #999999;\n opacity: 1;\n}\n.form-control:-ms-input-placeholder {\n color: #999999;\n}\n.form-control::-webkit-input-placeholder {\n color: #999999;\n}\n.form-control[disabled],\n.form-control[readonly],\nfieldset[disabled] .form-control {\n background-color: #eeeeee;\n opacity: 1;\n}\n.form-control[disabled],\nfieldset[disabled] .form-control {\n cursor: not-allowed;\n}\ntextarea.form-control {\n height: auto;\n}\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"].form-control,\n input[type=\"time\"].form-control,\n input[type=\"datetime-local\"].form-control,\n input[type=\"month\"].form-control {\n line-height: 34px;\n }\n input[type=\"date\"].input-sm,\n input[type=\"time\"].input-sm,\n input[type=\"datetime-local\"].input-sm,\n input[type=\"month\"].input-sm,\n .input-group-sm input[type=\"date\"],\n .input-group-sm input[type=\"time\"],\n .input-group-sm input[type=\"datetime-local\"],\n .input-group-sm input[type=\"month\"] {\n line-height: 30px;\n }\n input[type=\"date\"].input-lg,\n input[type=\"time\"].input-lg,\n input[type=\"datetime-local\"].input-lg,\n input[type=\"month\"].input-lg,\n .input-group-lg input[type=\"date\"],\n .input-group-lg input[type=\"time\"],\n .input-group-lg input[type=\"datetime-local\"],\n .input-group-lg input[type=\"month\"] {\n line-height: 46px;\n }\n}\n.form-group {\n margin-bottom: 15px;\n}\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.radio label,\n.checkbox label {\n min-height: 20px;\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px;\n}\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px;\n}\ninput[type=\"radio\"][disabled],\ninput[type=\"checkbox\"][disabled],\ninput[type=\"radio\"].disabled,\ninput[type=\"checkbox\"].disabled,\nfieldset[disabled] input[type=\"radio\"],\nfieldset[disabled] input[type=\"checkbox\"] {\n cursor: not-allowed;\n}\n.radio-inline.disabled,\n.checkbox-inline.disabled,\nfieldset[disabled] .radio-inline,\nfieldset[disabled] .checkbox-inline {\n cursor: not-allowed;\n}\n.radio.disabled label,\n.checkbox.disabled label,\nfieldset[disabled] .radio label,\nfieldset[disabled] .checkbox label {\n cursor: not-allowed;\n}\n.form-control-static {\n padding-top: 7px;\n padding-bottom: 7px;\n margin-bottom: 0;\n min-height: 34px;\n}\n.form-control-static.input-lg,\n.form-control-static.input-sm {\n padding-left: 0;\n padding-right: 0;\n}\n.input-sm {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-sm {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-sm,\nselect[multiple].input-sm {\n height: auto;\n}\n.form-group-sm .form-control {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.form-group-sm select.form-control {\n height: 30px;\n line-height: 30px;\n}\n.form-group-sm textarea.form-control,\n.form-group-sm select[multiple].form-control {\n height: auto;\n}\n.form-group-sm .form-control-static {\n height: 30px;\n min-height: 32px;\n padding: 6px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.input-lg {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-lg {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-lg,\nselect[multiple].input-lg {\n height: auto;\n}\n.form-group-lg .form-control {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.form-group-lg select.form-control {\n height: 46px;\n line-height: 46px;\n}\n.form-group-lg textarea.form-control,\n.form-group-lg select[multiple].form-control {\n height: auto;\n}\n.form-group-lg .form-control-static {\n height: 46px;\n min-height: 38px;\n padding: 11px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.has-feedback {\n position: relative;\n}\n.has-feedback .form-control {\n padding-right: 42.5px;\n}\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: 34px;\n height: 34px;\n line-height: 34px;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: 46px;\n height: 46px;\n line-height: 46px;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: 30px;\n height: 30px;\n line-height: 30px;\n}\n.has-success .help-block,\n.has-success .control-label,\n.has-success .radio,\n.has-success .checkbox,\n.has-success .radio-inline,\n.has-success .checkbox-inline,\n.has-success.radio label,\n.has-success.checkbox label,\n.has-success.radio-inline label,\n.has-success.checkbox-inline label {\n color: #3c763d;\n}\n.has-success .form-control {\n border-color: #3c763d;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-success .form-control:focus {\n border-color: #2b542c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;\n}\n.has-success .input-group-addon {\n color: #3c763d;\n border-color: #3c763d;\n background-color: #dff0d8;\n}\n.has-success .form-control-feedback {\n color: #3c763d;\n}\n.has-warning .help-block,\n.has-warning .control-label,\n.has-warning .radio,\n.has-warning .checkbox,\n.has-warning .radio-inline,\n.has-warning .checkbox-inline,\n.has-warning.radio label,\n.has-warning.checkbox label,\n.has-warning.radio-inline label,\n.has-warning.checkbox-inline label {\n color: #8a6d3b;\n}\n.has-warning .form-control {\n border-color: #8a6d3b;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-warning .form-control:focus {\n border-color: #66512c;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;\n}\n.has-warning .input-group-addon {\n color: #8a6d3b;\n border-color: #8a6d3b;\n background-color: #fcf8e3;\n}\n.has-warning .form-control-feedback {\n color: #8a6d3b;\n}\n.has-error .help-block,\n.has-error .control-label,\n.has-error .radio,\n.has-error .checkbox,\n.has-error .radio-inline,\n.has-error .checkbox-inline,\n.has-error.radio label,\n.has-error.checkbox label,\n.has-error.radio-inline label,\n.has-error.checkbox-inline label {\n color: #a94442;\n}\n.has-error .form-control {\n border-color: #a94442;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n}\n.has-error .form-control:focus {\n border-color: #843534;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;\n}\n.has-error .input-group-addon {\n color: #a94442;\n border-color: #a94442;\n background-color: #f2dede;\n}\n.has-error .form-control-feedback {\n color: #a94442;\n}\n.has-feedback label ~ .form-control-feedback {\n top: 25px;\n}\n.has-feedback label.sr-only ~ .form-control-feedback {\n top: 0;\n}\n.help-block {\n display: block;\n margin-top: 5px;\n margin-bottom: 10px;\n color: #737373;\n}\n@media (min-width: 768px) {\n .form-inline .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .form-inline .form-control-static {\n display: inline-block;\n }\n .form-inline .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .form-inline .input-group .input-group-addon,\n .form-inline .input-group .input-group-btn,\n .form-inline .input-group .form-control {\n width: auto;\n }\n .form-inline .input-group > .form-control {\n width: 100%;\n }\n .form-inline .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio,\n .form-inline .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .form-inline .radio label,\n .form-inline .checkbox label {\n padding-left: 0;\n }\n .form-inline .radio input[type=\"radio\"],\n .form-inline .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .form-inline .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox,\n.form-horizontal .radio-inline,\n.form-horizontal .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: 7px;\n}\n.form-horizontal .radio,\n.form-horizontal .checkbox {\n min-height: 27px;\n}\n.form-horizontal .form-group {\n margin-left: -15px;\n margin-right: -15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: 7px;\n }\n}\n.form-horizontal .has-feedback .form-control-feedback {\n right: 15px;\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-lg .control-label {\n padding-top: 14.333333px;\n font-size: 18px;\n }\n}\n@media (min-width: 768px) {\n .form-horizontal .form-group-sm .control-label {\n padding-top: 6px;\n font-size: 12px;\n }\n}\n.btn {\n display: inline-block;\n margin-bottom: 0;\n font-weight: normal;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none;\n border: 1px solid transparent;\n white-space: nowrap;\n padding: 6px 12px;\n font-size: 14px;\n line-height: 1.42857143;\n border-radius: 4px;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.btn:focus,\n.btn:active:focus,\n.btn.active:focus,\n.btn.focus,\n.btn:active.focus,\n.btn.active.focus {\n outline: thin dotted;\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n.btn:hover,\n.btn:focus,\n.btn.focus {\n color: #333333;\n text-decoration: none;\n}\n.btn:active,\n.btn.active {\n outline: 0;\n background-image: none;\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn.disabled,\n.btn[disabled],\nfieldset[disabled] .btn {\n cursor: not-allowed;\n opacity: 0.65;\n filter: alpha(opacity=65);\n -webkit-box-shadow: none;\n box-shadow: none;\n}\na.btn.disabled,\nfieldset[disabled] a.btn {\n pointer-events: none;\n}\n.btn-default {\n color: #333333;\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default:focus,\n.btn-default.focus {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #8c8c8c;\n}\n.btn-default:hover {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n color: #333333;\n background-color: #e6e6e6;\n border-color: #adadad;\n}\n.btn-default:active:hover,\n.btn-default.active:hover,\n.open > .dropdown-toggle.btn-default:hover,\n.btn-default:active:focus,\n.btn-default.active:focus,\n.open > .dropdown-toggle.btn-default:focus,\n.btn-default:active.focus,\n.btn-default.active.focus,\n.open > .dropdown-toggle.btn-default.focus {\n color: #333333;\n background-color: #d4d4d4;\n border-color: #8c8c8c;\n}\n.btn-default:active,\n.btn-default.active,\n.open > .dropdown-toggle.btn-default {\n background-image: none;\n}\n.btn-default.disabled,\n.btn-default[disabled],\nfieldset[disabled] .btn-default,\n.btn-default.disabled:hover,\n.btn-default[disabled]:hover,\nfieldset[disabled] .btn-default:hover,\n.btn-default.disabled:focus,\n.btn-default[disabled]:focus,\nfieldset[disabled] .btn-default:focus,\n.btn-default.disabled.focus,\n.btn-default[disabled].focus,\nfieldset[disabled] .btn-default.focus,\n.btn-default.disabled:active,\n.btn-default[disabled]:active,\nfieldset[disabled] .btn-default:active,\n.btn-default.disabled.active,\n.btn-default[disabled].active,\nfieldset[disabled] .btn-default.active {\n background-color: #ffffff;\n border-color: #cccccc;\n}\n.btn-default .badge {\n color: #ffffff;\n background-color: #333333;\n}\n.btn-primary {\n color: #ffffff;\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary:focus,\n.btn-primary.focus {\n color: #ffffff;\n background-color: #286090;\n border-color: #122b40;\n}\n.btn-primary:hover {\n color: #ffffff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n color: #ffffff;\n background-color: #286090;\n border-color: #204d74;\n}\n.btn-primary:active:hover,\n.btn-primary.active:hover,\n.open > .dropdown-toggle.btn-primary:hover,\n.btn-primary:active:focus,\n.btn-primary.active:focus,\n.open > .dropdown-toggle.btn-primary:focus,\n.btn-primary:active.focus,\n.btn-primary.active.focus,\n.open > .dropdown-toggle.btn-primary.focus {\n color: #ffffff;\n background-color: #204d74;\n border-color: #122b40;\n}\n.btn-primary:active,\n.btn-primary.active,\n.open > .dropdown-toggle.btn-primary {\n background-image: none;\n}\n.btn-primary.disabled,\n.btn-primary[disabled],\nfieldset[disabled] .btn-primary,\n.btn-primary.disabled:hover,\n.btn-primary[disabled]:hover,\nfieldset[disabled] .btn-primary:hover,\n.btn-primary.disabled:focus,\n.btn-primary[disabled]:focus,\nfieldset[disabled] .btn-primary:focus,\n.btn-primary.disabled.focus,\n.btn-primary[disabled].focus,\nfieldset[disabled] .btn-primary.focus,\n.btn-primary.disabled:active,\n.btn-primary[disabled]:active,\nfieldset[disabled] .btn-primary:active,\n.btn-primary.disabled.active,\n.btn-primary[disabled].active,\nfieldset[disabled] .btn-primary.active {\n background-color: #337ab7;\n border-color: #2e6da4;\n}\n.btn-primary .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.btn-success {\n color: #ffffff;\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success:focus,\n.btn-success.focus {\n color: #ffffff;\n background-color: #449d44;\n border-color: #255625;\n}\n.btn-success:hover {\n color: #ffffff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n color: #ffffff;\n background-color: #449d44;\n border-color: #398439;\n}\n.btn-success:active:hover,\n.btn-success.active:hover,\n.open > .dropdown-toggle.btn-success:hover,\n.btn-success:active:focus,\n.btn-success.active:focus,\n.open > .dropdown-toggle.btn-success:focus,\n.btn-success:active.focus,\n.btn-success.active.focus,\n.open > .dropdown-toggle.btn-success.focus {\n color: #ffffff;\n background-color: #398439;\n border-color: #255625;\n}\n.btn-success:active,\n.btn-success.active,\n.open > .dropdown-toggle.btn-success {\n background-image: none;\n}\n.btn-success.disabled,\n.btn-success[disabled],\nfieldset[disabled] .btn-success,\n.btn-success.disabled:hover,\n.btn-success[disabled]:hover,\nfieldset[disabled] .btn-success:hover,\n.btn-success.disabled:focus,\n.btn-success[disabled]:focus,\nfieldset[disabled] .btn-success:focus,\n.btn-success.disabled.focus,\n.btn-success[disabled].focus,\nfieldset[disabled] .btn-success.focus,\n.btn-success.disabled:active,\n.btn-success[disabled]:active,\nfieldset[disabled] .btn-success:active,\n.btn-success.disabled.active,\n.btn-success[disabled].active,\nfieldset[disabled] .btn-success.active {\n background-color: #5cb85c;\n border-color: #4cae4c;\n}\n.btn-success .badge {\n color: #5cb85c;\n background-color: #ffffff;\n}\n.btn-info {\n color: #ffffff;\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info:focus,\n.btn-info.focus {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #1b6d85;\n}\n.btn-info:hover {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n color: #ffffff;\n background-color: #31b0d5;\n border-color: #269abc;\n}\n.btn-info:active:hover,\n.btn-info.active:hover,\n.open > .dropdown-toggle.btn-info:hover,\n.btn-info:active:focus,\n.btn-info.active:focus,\n.open > .dropdown-toggle.btn-info:focus,\n.btn-info:active.focus,\n.btn-info.active.focus,\n.open > .dropdown-toggle.btn-info.focus {\n color: #ffffff;\n background-color: #269abc;\n border-color: #1b6d85;\n}\n.btn-info:active,\n.btn-info.active,\n.open > .dropdown-toggle.btn-info {\n background-image: none;\n}\n.btn-info.disabled,\n.btn-info[disabled],\nfieldset[disabled] .btn-info,\n.btn-info.disabled:hover,\n.btn-info[disabled]:hover,\nfieldset[disabled] .btn-info:hover,\n.btn-info.disabled:focus,\n.btn-info[disabled]:focus,\nfieldset[disabled] .btn-info:focus,\n.btn-info.disabled.focus,\n.btn-info[disabled].focus,\nfieldset[disabled] .btn-info.focus,\n.btn-info.disabled:active,\n.btn-info[disabled]:active,\nfieldset[disabled] .btn-info:active,\n.btn-info.disabled.active,\n.btn-info[disabled].active,\nfieldset[disabled] .btn-info.active {\n background-color: #5bc0de;\n border-color: #46b8da;\n}\n.btn-info .badge {\n color: #5bc0de;\n background-color: #ffffff;\n}\n.btn-warning {\n color: #ffffff;\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning:focus,\n.btn-warning.focus {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #985f0d;\n}\n.btn-warning:hover {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n color: #ffffff;\n background-color: #ec971f;\n border-color: #d58512;\n}\n.btn-warning:active:hover,\n.btn-warning.active:hover,\n.open > .dropdown-toggle.btn-warning:hover,\n.btn-warning:active:focus,\n.btn-warning.active:focus,\n.open > .dropdown-toggle.btn-warning:focus,\n.btn-warning:active.focus,\n.btn-warning.active.focus,\n.open > .dropdown-toggle.btn-warning.focus {\n color: #ffffff;\n background-color: #d58512;\n border-color: #985f0d;\n}\n.btn-warning:active,\n.btn-warning.active,\n.open > .dropdown-toggle.btn-warning {\n background-image: none;\n}\n.btn-warning.disabled,\n.btn-warning[disabled],\nfieldset[disabled] .btn-warning,\n.btn-warning.disabled:hover,\n.btn-warning[disabled]:hover,\nfieldset[disabled] .btn-warning:hover,\n.btn-warning.disabled:focus,\n.btn-warning[disabled]:focus,\nfieldset[disabled] .btn-warning:focus,\n.btn-warning.disabled.focus,\n.btn-warning[disabled].focus,\nfieldset[disabled] .btn-warning.focus,\n.btn-warning.disabled:active,\n.btn-warning[disabled]:active,\nfieldset[disabled] .btn-warning:active,\n.btn-warning.disabled.active,\n.btn-warning[disabled].active,\nfieldset[disabled] .btn-warning.active {\n background-color: #f0ad4e;\n border-color: #eea236;\n}\n.btn-warning .badge {\n color: #f0ad4e;\n background-color: #ffffff;\n}\n.btn-danger {\n color: #ffffff;\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger:focus,\n.btn-danger.focus {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #761c19;\n}\n.btn-danger:hover {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n color: #ffffff;\n background-color: #c9302c;\n border-color: #ac2925;\n}\n.btn-danger:active:hover,\n.btn-danger.active:hover,\n.open > .dropdown-toggle.btn-danger:hover,\n.btn-danger:active:focus,\n.btn-danger.active:focus,\n.open > .dropdown-toggle.btn-danger:focus,\n.btn-danger:active.focus,\n.btn-danger.active.focus,\n.open > .dropdown-toggle.btn-danger.focus {\n color: #ffffff;\n background-color: #ac2925;\n border-color: #761c19;\n}\n.btn-danger:active,\n.btn-danger.active,\n.open > .dropdown-toggle.btn-danger {\n background-image: none;\n}\n.btn-danger.disabled,\n.btn-danger[disabled],\nfieldset[disabled] .btn-danger,\n.btn-danger.disabled:hover,\n.btn-danger[disabled]:hover,\nfieldset[disabled] .btn-danger:hover,\n.btn-danger.disabled:focus,\n.btn-danger[disabled]:focus,\nfieldset[disabled] .btn-danger:focus,\n.btn-danger.disabled.focus,\n.btn-danger[disabled].focus,\nfieldset[disabled] .btn-danger.focus,\n.btn-danger.disabled:active,\n.btn-danger[disabled]:active,\nfieldset[disabled] .btn-danger:active,\n.btn-danger.disabled.active,\n.btn-danger[disabled].active,\nfieldset[disabled] .btn-danger.active {\n background-color: #d9534f;\n border-color: #d43f3a;\n}\n.btn-danger .badge {\n color: #d9534f;\n background-color: #ffffff;\n}\n.btn-link {\n color: #337ab7;\n font-weight: normal;\n border-radius: 0;\n}\n.btn-link,\n.btn-link:active,\n.btn-link.active,\n.btn-link[disabled],\nfieldset[disabled] .btn-link {\n background-color: transparent;\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn-link,\n.btn-link:hover,\n.btn-link:focus,\n.btn-link:active {\n border-color: transparent;\n}\n.btn-link:hover,\n.btn-link:focus {\n color: #23527c;\n text-decoration: underline;\n background-color: transparent;\n}\n.btn-link[disabled]:hover,\nfieldset[disabled] .btn-link:hover,\n.btn-link[disabled]:focus,\nfieldset[disabled] .btn-link:focus {\n color: #777777;\n text-decoration: none;\n}\n.btn-lg,\n.btn-group-lg > .btn {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\n.btn-sm,\n.btn-group-sm > .btn {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-xs,\n.btn-group-xs > .btn {\n padding: 1px 5px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\n.btn-block {\n display: block;\n width: 100%;\n}\n.btn-block + .btn-block {\n margin-top: 5px;\n}\ninput[type=\"submit\"].btn-block,\ninput[type=\"reset\"].btn-block,\ninput[type=\"button\"].btn-block {\n width: 100%;\n}\n.fade {\n opacity: 0;\n -webkit-transition: opacity 0.15s linear;\n -o-transition: opacity 0.15s linear;\n transition: opacity 0.15s linear;\n}\n.fade.in {\n opacity: 1;\n}\n.collapse {\n display: none;\n}\n.collapse.in {\n display: block;\n}\ntr.collapse.in {\n display: table-row;\n}\ntbody.collapse.in {\n display: table-row-group;\n}\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n -webkit-transition-property: height, visibility;\n transition-property: height, visibility;\n -webkit-transition-duration: 0.35s;\n transition-duration: 0.35s;\n -webkit-transition-timing-function: ease;\n transition-timing-function: ease;\n}\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: 4px dashed;\n border-top: 4px solid \\9;\n border-right: 4px solid transparent;\n border-left: 4px solid transparent;\n}\n.dropup,\n.dropdown {\n position: relative;\n}\n.dropdown-toggle:focus {\n outline: 0;\n}\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: 1000;\n display: none;\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0;\n list-style: none;\n font-size: 14px;\n text-align: left;\n background-color: #ffffff;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.15);\n border-radius: 4px;\n -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);\n background-clip: padding-box;\n}\n.dropdown-menu.pull-right {\n right: 0;\n left: auto;\n}\n.dropdown-menu .divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.dropdown-menu > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: 1.42857143;\n color: #333333;\n white-space: nowrap;\n}\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n text-decoration: none;\n color: #262626;\n background-color: #f5f5f5;\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n color: #ffffff;\n text-decoration: none;\n outline: 0;\n background-color: #337ab7;\n}\n.dropdown-menu > .disabled > a,\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n color: #777777;\n}\n.dropdown-menu > .disabled > a:hover,\n.dropdown-menu > .disabled > a:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none;\n filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);\n cursor: not-allowed;\n}\n.open > .dropdown-menu {\n display: block;\n}\n.open > a {\n outline: 0;\n}\n.dropdown-menu-right {\n left: auto;\n right: 0;\n}\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: 12px;\n line-height: 1.42857143;\n color: #777777;\n white-space: nowrap;\n}\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: 990;\n}\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n.dropup .caret,\n.navbar-fixed-bottom .dropdown .caret {\n border-top: 0;\n border-bottom: 4px dashed;\n border-bottom: 4px solid \\9;\n content: \"\";\n}\n.dropup .dropdown-menu,\n.navbar-fixed-bottom .dropdown .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n}\n@media (min-width: 768px) {\n .navbar-right .dropdown-menu {\n left: auto;\n right: 0;\n }\n .navbar-right .dropdown-menu-left {\n left: 0;\n right: auto;\n }\n}\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n.btn-group > .btn,\n.btn-group-vertical > .btn {\n position: relative;\n float: left;\n}\n.btn-group > .btn:hover,\n.btn-group-vertical > .btn:hover,\n.btn-group > .btn:focus,\n.btn-group-vertical > .btn:focus,\n.btn-group > .btn:active,\n.btn-group-vertical > .btn:active,\n.btn-group > .btn.active,\n.btn-group-vertical > .btn.active {\n z-index: 2;\n}\n.btn-group .btn + .btn,\n.btn-group .btn + .btn-group,\n.btn-group .btn-group + .btn,\n.btn-group .btn-group + .btn-group {\n margin-left: -1px;\n}\n.btn-toolbar {\n margin-left: -5px;\n}\n.btn-toolbar .btn,\n.btn-toolbar .btn-group,\n.btn-toolbar .input-group {\n float: left;\n}\n.btn-toolbar > .btn,\n.btn-toolbar > .btn-group,\n.btn-toolbar > .input-group {\n margin-left: 5px;\n}\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n.btn-group > .btn:first-child {\n margin-left: 0;\n}\n.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n.btn-group.open .dropdown-toggle {\n -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);\n}\n.btn-group.open .dropdown-toggle.btn-link {\n -webkit-box-shadow: none;\n box-shadow: none;\n}\n.btn .caret {\n margin-left: 0;\n}\n.btn-lg .caret {\n border-width: 5px 5px 0;\n border-bottom-width: 0;\n}\n.dropup .btn-lg .caret {\n border-width: 0 5px 5px;\n}\n.btn-group-vertical > .btn,\n.btn-group-vertical > .btn-group,\n.btn-group-vertical > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n}\n.btn-group-vertical > .btn-group > .btn {\n float: none;\n}\n.btn-group-vertical > .btn + .btn,\n.btn-group-vertical > .btn + .btn-group,\n.btn-group-vertical > .btn-group + .btn,\n.btn-group-vertical > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n}\n.btn-group-vertical > .btn:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.btn-group-vertical > .btn:first-child:not(:last-child) {\n border-top-right-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn:last-child:not(:first-child) {\n border-bottom-left-radius: 4px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child,\n.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n}\n.btn-group-justified > .btn,\n.btn-group-justified > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n}\n.btn-group-justified > .btn-group .btn {\n width: 100%;\n}\n.btn-group-justified > .btn-group .dropdown-menu {\n left: auto;\n}\n[data-toggle=\"buttons\"] > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"radio\"],\n[data-toggle=\"buttons\"] > .btn input[type=\"checkbox\"],\n[data-toggle=\"buttons\"] > .btn-group > .btn input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0, 0, 0, 0);\n pointer-events: none;\n}\n.input-group {\n position: relative;\n display: table;\n border-collapse: separate;\n}\n.input-group[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n}\n.input-group .form-control {\n position: relative;\n z-index: 2;\n float: left;\n width: 100%;\n margin-bottom: 0;\n}\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n border-radius: 6px;\n}\nselect.input-group-lg > .form-control,\nselect.input-group-lg > .input-group-addon,\nselect.input-group-lg > .input-group-btn > .btn {\n height: 46px;\n line-height: 46px;\n}\ntextarea.input-group-lg > .form-control,\ntextarea.input-group-lg > .input-group-addon,\ntextarea.input-group-lg > .input-group-btn > .btn,\nselect[multiple].input-group-lg > .form-control,\nselect[multiple].input-group-lg > .input-group-addon,\nselect[multiple].input-group-lg > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n border-radius: 3px;\n}\nselect.input-group-sm > .form-control,\nselect.input-group-sm > .input-group-addon,\nselect.input-group-sm > .input-group-btn > .btn {\n height: 30px;\n line-height: 30px;\n}\ntextarea.input-group-sm > .form-control,\ntextarea.input-group-sm > .input-group-addon,\ntextarea.input-group-sm > .input-group-btn > .btn,\nselect[multiple].input-group-sm > .form-control,\nselect[multiple].input-group-sm > .input-group-addon,\nselect[multiple].input-group-sm > .input-group-btn > .btn {\n height: auto;\n}\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n}\n.input-group-addon:not(:first-child):not(:last-child),\n.input-group-btn:not(:first-child):not(:last-child),\n.input-group .form-control:not(:first-child):not(:last-child) {\n border-radius: 0;\n}\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle;\n}\n.input-group-addon {\n padding: 6px 12px;\n font-size: 14px;\n font-weight: normal;\n line-height: 1;\n color: #555555;\n text-align: center;\n background-color: #eeeeee;\n border: 1px solid #cccccc;\n border-radius: 4px;\n}\n.input-group-addon.input-sm {\n padding: 5px 10px;\n font-size: 12px;\n border-radius: 3px;\n}\n.input-group-addon.input-lg {\n padding: 10px 16px;\n font-size: 18px;\n border-radius: 6px;\n}\n.input-group-addon input[type=\"radio\"],\n.input-group-addon input[type=\"checkbox\"] {\n margin-top: 0;\n}\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n border-bottom-right-radius: 0;\n border-top-right-radius: 0;\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n border-bottom-left-radius: 0;\n border-top-left-radius: 0;\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n.input-group-btn {\n position: relative;\n font-size: 0;\n white-space: nowrap;\n}\n.input-group-btn > .btn {\n position: relative;\n}\n.input-group-btn > .btn + .btn {\n margin-left: -1px;\n}\n.input-group-btn > .btn:hover,\n.input-group-btn > .btn:focus,\n.input-group-btn > .btn:active {\n z-index: 2;\n}\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group {\n margin-right: -1px;\n}\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group {\n z-index: 2;\n margin-left: -1px;\n}\n.nav {\n margin-bottom: 0;\n padding-left: 0;\n list-style: none;\n}\n.nav > li {\n position: relative;\n display: block;\n}\n.nav > li > a {\n position: relative;\n display: block;\n padding: 10px 15px;\n}\n.nav > li > a:hover,\n.nav > li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.nav > li.disabled > a {\n color: #777777;\n}\n.nav > li.disabled > a:hover,\n.nav > li.disabled > a:focus {\n color: #777777;\n text-decoration: none;\n background-color: transparent;\n cursor: not-allowed;\n}\n.nav .open > a,\n.nav .open > a:hover,\n.nav .open > a:focus {\n background-color: #eeeeee;\n border-color: #337ab7;\n}\n.nav .nav-divider {\n height: 1px;\n margin: 9px 0;\n overflow: hidden;\n background-color: #e5e5e5;\n}\n.nav > li > a > img {\n max-width: none;\n}\n.nav-tabs {\n border-bottom: 1px solid #dddddd;\n}\n.nav-tabs > li {\n float: left;\n margin-bottom: -1px;\n}\n.nav-tabs > li > a {\n margin-right: 2px;\n line-height: 1.42857143;\n border: 1px solid transparent;\n border-radius: 4px 4px 0 0;\n}\n.nav-tabs > li > a:hover {\n border-color: #eeeeee #eeeeee #dddddd;\n}\n.nav-tabs > li.active > a,\n.nav-tabs > li.active > a:hover,\n.nav-tabs > li.active > a:focus {\n color: #555555;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-bottom-color: transparent;\n cursor: default;\n}\n.nav-tabs.nav-justified {\n width: 100%;\n border-bottom: 0;\n}\n.nav-tabs.nav-justified > li {\n float: none;\n}\n.nav-tabs.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-tabs.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-tabs.nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs.nav-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs.nav-justified > .active > a,\n.nav-tabs.nav-justified > .active > a:hover,\n.nav-tabs.nav-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs.nav-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs.nav-justified > .active > a,\n .nav-tabs.nav-justified > .active > a:hover,\n .nav-tabs.nav-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.nav-pills > li {\n float: left;\n}\n.nav-pills > li > a {\n border-radius: 4px;\n}\n.nav-pills > li + li {\n margin-left: 2px;\n}\n.nav-pills > li.active > a,\n.nav-pills > li.active > a:hover,\n.nav-pills > li.active > a:focus {\n color: #ffffff;\n background-color: #337ab7;\n}\n.nav-stacked > li {\n float: none;\n}\n.nav-stacked > li + li {\n margin-top: 2px;\n margin-left: 0;\n}\n.nav-justified {\n width: 100%;\n}\n.nav-justified > li {\n float: none;\n}\n.nav-justified > li > a {\n text-align: center;\n margin-bottom: 5px;\n}\n.nav-justified > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n}\n@media (min-width: 768px) {\n .nav-justified > li {\n display: table-cell;\n width: 1%;\n }\n .nav-justified > li > a {\n margin-bottom: 0;\n }\n}\n.nav-tabs-justified {\n border-bottom: 0;\n}\n.nav-tabs-justified > li > a {\n margin-right: 0;\n border-radius: 4px;\n}\n.nav-tabs-justified > .active > a,\n.nav-tabs-justified > .active > a:hover,\n.nav-tabs-justified > .active > a:focus {\n border: 1px solid #dddddd;\n}\n@media (min-width: 768px) {\n .nav-tabs-justified > li > a {\n border-bottom: 1px solid #dddddd;\n border-radius: 4px 4px 0 0;\n }\n .nav-tabs-justified > .active > a,\n .nav-tabs-justified > .active > a:hover,\n .nav-tabs-justified > .active > a:focus {\n border-bottom-color: #ffffff;\n }\n}\n.tab-content > .tab-pane {\n display: none;\n}\n.tab-content > .active {\n display: block;\n}\n.nav-tabs .dropdown-menu {\n margin-top: -1px;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar {\n position: relative;\n min-height: 50px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n}\n@media (min-width: 768px) {\n .navbar {\n border-radius: 4px;\n }\n}\n@media (min-width: 768px) {\n .navbar-header {\n float: left;\n }\n}\n.navbar-collapse {\n overflow-x: visible;\n padding-right: 15px;\n padding-left: 15px;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);\n -webkit-overflow-scrolling: touch;\n}\n.navbar-collapse.in {\n overflow-y: auto;\n}\n@media (min-width: 768px) {\n .navbar-collapse {\n width: auto;\n border-top: 0;\n box-shadow: none;\n }\n .navbar-collapse.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0;\n overflow: visible !important;\n }\n .navbar-collapse.in {\n overflow-y: visible;\n }\n .navbar-fixed-top .navbar-collapse,\n .navbar-static-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n padding-left: 0;\n padding-right: 0;\n }\n}\n.navbar-fixed-top .navbar-collapse,\n.navbar-fixed-bottom .navbar-collapse {\n max-height: 340px;\n}\n@media (max-device-width: 480px) and (orientation: landscape) {\n .navbar-fixed-top .navbar-collapse,\n .navbar-fixed-bottom .navbar-collapse {\n max-height: 200px;\n }\n}\n.container > .navbar-header,\n.container-fluid > .navbar-header,\n.container > .navbar-collapse,\n.container-fluid > .navbar-collapse {\n margin-right: -15px;\n margin-left: -15px;\n}\n@media (min-width: 768px) {\n .container > .navbar-header,\n .container-fluid > .navbar-header,\n .container > .navbar-collapse,\n .container-fluid > .navbar-collapse {\n margin-right: 0;\n margin-left: 0;\n }\n}\n.navbar-static-top {\n z-index: 1000;\n border-width: 0 0 1px;\n}\n@media (min-width: 768px) {\n .navbar-static-top {\n border-radius: 0;\n }\n}\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: 1030;\n}\n@media (min-width: 768px) {\n .navbar-fixed-top,\n .navbar-fixed-bottom {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0;\n border-width: 1px 0 0;\n}\n.navbar-brand {\n float: left;\n padding: 15px 15px;\n font-size: 18px;\n line-height: 20px;\n height: 50px;\n}\n.navbar-brand:hover,\n.navbar-brand:focus {\n text-decoration: none;\n}\n.navbar-brand > img {\n display: block;\n}\n@media (min-width: 768px) {\n .navbar > .container .navbar-brand,\n .navbar > .container-fluid .navbar-brand {\n margin-left: -15px;\n }\n}\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: 15px;\n padding: 9px 10px;\n margin-top: 8px;\n margin-bottom: 8px;\n background-color: transparent;\n background-image: none;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.navbar-toggle:focus {\n outline: 0;\n}\n.navbar-toggle .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n}\n.navbar-toggle .icon-bar + .icon-bar {\n margin-top: 4px;\n}\n@media (min-width: 768px) {\n .navbar-toggle {\n display: none;\n }\n}\n.navbar-nav {\n margin: 7.5px -15px;\n}\n.navbar-nav > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: 20px;\n}\n@media (max-width: 767px) {\n .navbar-nav .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n }\n .navbar-nav .open .dropdown-menu > li > a,\n .navbar-nav .open .dropdown-menu .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n .navbar-nav .open .dropdown-menu > li > a {\n line-height: 20px;\n }\n .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-nav .open .dropdown-menu > li > a:focus {\n background-image: none;\n }\n}\n@media (min-width: 768px) {\n .navbar-nav {\n float: left;\n margin: 0;\n }\n .navbar-nav > li {\n float: left;\n }\n .navbar-nav > li > a {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n}\n.navbar-form {\n margin-left: -15px;\n margin-right: -15px;\n padding: 10px 15px;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);\n margin-top: 8px;\n margin-bottom: 8px;\n}\n@media (min-width: 768px) {\n .navbar-form .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .form-control {\n display: inline-block;\n width: auto;\n vertical-align: middle;\n }\n .navbar-form .form-control-static {\n display: inline-block;\n }\n .navbar-form .input-group {\n display: inline-table;\n vertical-align: middle;\n }\n .navbar-form .input-group .input-group-addon,\n .navbar-form .input-group .input-group-btn,\n .navbar-form .input-group .form-control {\n width: auto;\n }\n .navbar-form .input-group > .form-control {\n width: 100%;\n }\n .navbar-form .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio,\n .navbar-form .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n }\n .navbar-form .radio label,\n .navbar-form .checkbox label {\n padding-left: 0;\n }\n .navbar-form .radio input[type=\"radio\"],\n .navbar-form .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n .navbar-form .has-feedback .form-control-feedback {\n top: 0;\n }\n}\n@media (max-width: 767px) {\n .navbar-form .form-group {\n margin-bottom: 5px;\n }\n .navbar-form .form-group:last-child {\n margin-bottom: 0;\n }\n}\n@media (min-width: 768px) {\n .navbar-form {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n -webkit-box-shadow: none;\n box-shadow: none;\n }\n}\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n}\n.navbar-btn {\n margin-top: 8px;\n margin-bottom: 8px;\n}\n.navbar-btn.btn-sm {\n margin-top: 10px;\n margin-bottom: 10px;\n}\n.navbar-btn.btn-xs {\n margin-top: 14px;\n margin-bottom: 14px;\n}\n.navbar-text {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n@media (min-width: 768px) {\n .navbar-text {\n float: left;\n margin-left: 15px;\n margin-right: 15px;\n }\n}\n@media (min-width: 768px) {\n .navbar-left {\n float: left !important;\n }\n .navbar-right {\n float: right !important;\n margin-right: -15px;\n }\n .navbar-right ~ .navbar-right {\n margin-right: 0;\n }\n}\n.navbar-default {\n background-color: #f8f8f8;\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-brand {\n color: #777777;\n}\n.navbar-default .navbar-brand:hover,\n.navbar-default .navbar-brand:focus {\n color: #5e5e5e;\n background-color: transparent;\n}\n.navbar-default .navbar-text {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a {\n color: #777777;\n}\n.navbar-default .navbar-nav > li > a:hover,\n.navbar-default .navbar-nav > li > a:focus {\n color: #333333;\n background-color: transparent;\n}\n.navbar-default .navbar-nav > .active > a,\n.navbar-default .navbar-nav > .active > a:hover,\n.navbar-default .navbar-nav > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .disabled > a,\n.navbar-default .navbar-nav > .disabled > a:hover,\n.navbar-default .navbar-nav > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n}\n.navbar-default .navbar-toggle {\n border-color: #dddddd;\n}\n.navbar-default .navbar-toggle:hover,\n.navbar-default .navbar-toggle:focus {\n background-color: #dddddd;\n}\n.navbar-default .navbar-toggle .icon-bar {\n background-color: #888888;\n}\n.navbar-default .navbar-collapse,\n.navbar-default .navbar-form {\n border-color: #e7e7e7;\n}\n.navbar-default .navbar-nav > .open > a,\n.navbar-default .navbar-nav > .open > a:hover,\n.navbar-default .navbar-nav > .open > a:focus {\n background-color: #e7e7e7;\n color: #555555;\n}\n@media (max-width: 767px) {\n .navbar-default .navbar-nav .open .dropdown-menu > li > a {\n color: #777777;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #333333;\n background-color: transparent;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #555555;\n background-color: #e7e7e7;\n }\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #cccccc;\n background-color: transparent;\n }\n}\n.navbar-default .navbar-link {\n color: #777777;\n}\n.navbar-default .navbar-link:hover {\n color: #333333;\n}\n.navbar-default .btn-link {\n color: #777777;\n}\n.navbar-default .btn-link:hover,\n.navbar-default .btn-link:focus {\n color: #333333;\n}\n.navbar-default .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-default .btn-link:hover,\n.navbar-default .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-default .btn-link:focus {\n color: #cccccc;\n}\n.navbar-inverse {\n background-color: #222222;\n border-color: #080808;\n}\n.navbar-inverse .navbar-brand {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-brand:hover,\n.navbar-inverse .navbar-brand:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-text {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-nav > li > a:hover,\n.navbar-inverse .navbar-nav > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n}\n.navbar-inverse .navbar-nav > .active > a,\n.navbar-inverse .navbar-nav > .active > a:hover,\n.navbar-inverse .navbar-nav > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n}\n.navbar-inverse .navbar-nav > .disabled > a,\n.navbar-inverse .navbar-nav > .disabled > a:hover,\n.navbar-inverse .navbar-nav > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n}\n.navbar-inverse .navbar-toggle {\n border-color: #333333;\n}\n.navbar-inverse .navbar-toggle:hover,\n.navbar-inverse .navbar-toggle:focus {\n background-color: #333333;\n}\n.navbar-inverse .navbar-toggle .icon-bar {\n background-color: #ffffff;\n}\n.navbar-inverse .navbar-collapse,\n.navbar-inverse .navbar-form {\n border-color: #101010;\n}\n.navbar-inverse .navbar-nav > .open > a,\n.navbar-inverse .navbar-nav > .open > a:hover,\n.navbar-inverse .navbar-nav > .open > a:focus {\n background-color: #080808;\n color: #ffffff;\n}\n@media (max-width: 767px) {\n .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header {\n border-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu .divider {\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a {\n color: #9d9d9d;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus {\n color: #ffffff;\n background-color: transparent;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus {\n color: #ffffff;\n background-color: #080808;\n }\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover,\n .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus {\n color: #444444;\n background-color: transparent;\n }\n}\n.navbar-inverse .navbar-link {\n color: #9d9d9d;\n}\n.navbar-inverse .navbar-link:hover {\n color: #ffffff;\n}\n.navbar-inverse .btn-link {\n color: #9d9d9d;\n}\n.navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link:focus {\n color: #ffffff;\n}\n.navbar-inverse .btn-link[disabled]:hover,\nfieldset[disabled] .navbar-inverse .btn-link:hover,\n.navbar-inverse .btn-link[disabled]:focus,\nfieldset[disabled] .navbar-inverse .btn-link:focus {\n color: #444444;\n}\n.breadcrumb {\n padding: 8px 15px;\n margin-bottom: 20px;\n list-style: none;\n background-color: #f5f5f5;\n border-radius: 4px;\n}\n.breadcrumb > li {\n display: inline-block;\n}\n.breadcrumb > li + li:before {\n content: \"/\\00a0\";\n padding: 0 5px;\n color: #cccccc;\n}\n.breadcrumb > .active {\n color: #777777;\n}\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: 20px 0;\n border-radius: 4px;\n}\n.pagination > li {\n display: inline;\n}\n.pagination > li > a,\n.pagination > li > span {\n position: relative;\n float: left;\n padding: 6px 12px;\n line-height: 1.42857143;\n text-decoration: none;\n color: #337ab7;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n margin-left: -1px;\n}\n.pagination > li:first-child > a,\n.pagination > li:first-child > span {\n margin-left: 0;\n border-bottom-left-radius: 4px;\n border-top-left-radius: 4px;\n}\n.pagination > li:last-child > a,\n.pagination > li:last-child > span {\n border-bottom-right-radius: 4px;\n border-top-right-radius: 4px;\n}\n.pagination > li > a:hover,\n.pagination > li > span:hover,\n.pagination > li > a:focus,\n.pagination > li > span:focus {\n z-index: 3;\n color: #23527c;\n background-color: #eeeeee;\n border-color: #dddddd;\n}\n.pagination > .active > a,\n.pagination > .active > span,\n.pagination > .active > a:hover,\n.pagination > .active > span:hover,\n.pagination > .active > a:focus,\n.pagination > .active > span:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n cursor: default;\n}\n.pagination > .disabled > span,\n.pagination > .disabled > span:hover,\n.pagination > .disabled > span:focus,\n.pagination > .disabled > a,\n.pagination > .disabled > a:hover,\n.pagination > .disabled > a:focus {\n color: #777777;\n background-color: #ffffff;\n border-color: #dddddd;\n cursor: not-allowed;\n}\n.pagination-lg > li > a,\n.pagination-lg > li > span {\n padding: 10px 16px;\n font-size: 18px;\n line-height: 1.3333333;\n}\n.pagination-lg > li:first-child > a,\n.pagination-lg > li:first-child > span {\n border-bottom-left-radius: 6px;\n border-top-left-radius: 6px;\n}\n.pagination-lg > li:last-child > a,\n.pagination-lg > li:last-child > span {\n border-bottom-right-radius: 6px;\n border-top-right-radius: 6px;\n}\n.pagination-sm > li > a,\n.pagination-sm > li > span {\n padding: 5px 10px;\n font-size: 12px;\n line-height: 1.5;\n}\n.pagination-sm > li:first-child > a,\n.pagination-sm > li:first-child > span {\n border-bottom-left-radius: 3px;\n border-top-left-radius: 3px;\n}\n.pagination-sm > li:last-child > a,\n.pagination-sm > li:last-child > span {\n border-bottom-right-radius: 3px;\n border-top-right-radius: 3px;\n}\n.pager {\n padding-left: 0;\n margin: 20px 0;\n list-style: none;\n text-align: center;\n}\n.pager li {\n display: inline;\n}\n.pager li > a,\n.pager li > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 15px;\n}\n.pager li > a:hover,\n.pager li > a:focus {\n text-decoration: none;\n background-color: #eeeeee;\n}\n.pager .next > a,\n.pager .next > span {\n float: right;\n}\n.pager .previous > a,\n.pager .previous > span {\n float: left;\n}\n.pager .disabled > a,\n.pager .disabled > a:hover,\n.pager .disabled > a:focus,\n.pager .disabled > span {\n color: #777777;\n background-color: #ffffff;\n cursor: not-allowed;\n}\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: #ffffff;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n}\na.label:hover,\na.label:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.label:empty {\n display: none;\n}\n.btn .label {\n position: relative;\n top: -1px;\n}\n.label-default {\n background-color: #777777;\n}\n.label-default[href]:hover,\n.label-default[href]:focus {\n background-color: #5e5e5e;\n}\n.label-primary {\n background-color: #337ab7;\n}\n.label-primary[href]:hover,\n.label-primary[href]:focus {\n background-color: #286090;\n}\n.label-success {\n background-color: #5cb85c;\n}\n.label-success[href]:hover,\n.label-success[href]:focus {\n background-color: #449d44;\n}\n.label-info {\n background-color: #5bc0de;\n}\n.label-info[href]:hover,\n.label-info[href]:focus {\n background-color: #31b0d5;\n}\n.label-warning {\n background-color: #f0ad4e;\n}\n.label-warning[href]:hover,\n.label-warning[href]:focus {\n background-color: #ec971f;\n}\n.label-danger {\n background-color: #d9534f;\n}\n.label-danger[href]:hover,\n.label-danger[href]:focus {\n background-color: #c9302c;\n}\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: 12px;\n font-weight: bold;\n color: #ffffff;\n line-height: 1;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: #777777;\n border-radius: 10px;\n}\n.badge:empty {\n display: none;\n}\n.btn .badge {\n position: relative;\n top: -1px;\n}\n.btn-xs .badge,\n.btn-group-xs > .btn .badge {\n top: 0;\n padding: 1px 5px;\n}\na.badge:hover,\na.badge:focus {\n color: #ffffff;\n text-decoration: none;\n cursor: pointer;\n}\n.list-group-item.active > .badge,\n.nav-pills > .active > a > .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.list-group-item > .badge {\n float: right;\n}\n.list-group-item > .badge + .badge {\n margin-right: 5px;\n}\n.nav-pills > li > a > .badge {\n margin-left: 3px;\n}\n.jumbotron {\n padding-top: 30px;\n padding-bottom: 30px;\n margin-bottom: 30px;\n color: inherit;\n background-color: #eeeeee;\n}\n.jumbotron h1,\n.jumbotron .h1 {\n color: inherit;\n}\n.jumbotron p {\n margin-bottom: 15px;\n font-size: 21px;\n font-weight: 200;\n}\n.jumbotron > hr {\n border-top-color: #d5d5d5;\n}\n.container .jumbotron,\n.container-fluid .jumbotron {\n border-radius: 6px;\n}\n.jumbotron .container {\n max-width: 100%;\n}\n@media screen and (min-width: 768px) {\n .jumbotron {\n padding-top: 48px;\n padding-bottom: 48px;\n }\n .container .jumbotron,\n .container-fluid .jumbotron {\n padding-left: 60px;\n padding-right: 60px;\n }\n .jumbotron h1,\n .jumbotron .h1 {\n font-size: 63px;\n }\n}\n.thumbnail {\n display: block;\n padding: 4px;\n margin-bottom: 20px;\n line-height: 1.42857143;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n border-radius: 4px;\n -webkit-transition: border 0.2s ease-in-out;\n -o-transition: border 0.2s ease-in-out;\n transition: border 0.2s ease-in-out;\n}\n.thumbnail > img,\n.thumbnail a > img {\n margin-left: auto;\n margin-right: auto;\n}\na.thumbnail:hover,\na.thumbnail:focus,\na.thumbnail.active {\n border-color: #337ab7;\n}\n.thumbnail .caption {\n padding: 9px;\n color: #333333;\n}\n.alert {\n padding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n}\n.alert h4 {\n margin-top: 0;\n color: inherit;\n}\n.alert .alert-link {\n font-weight: bold;\n}\n.alert > p,\n.alert > ul {\n margin-bottom: 0;\n}\n.alert > p + p {\n margin-top: 5px;\n}\n.alert-dismissable,\n.alert-dismissible {\n padding-right: 35px;\n}\n.alert-dismissable .close,\n.alert-dismissible .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n}\n.alert-success {\n background-color: #dff0d8;\n border-color: #d6e9c6;\n color: #3c763d;\n}\n.alert-success hr {\n border-top-color: #c9e2b3;\n}\n.alert-success .alert-link {\n color: #2b542c;\n}\n.alert-info {\n background-color: #d9edf7;\n border-color: #bce8f1;\n color: #31708f;\n}\n.alert-info hr {\n border-top-color: #a6e1ec;\n}\n.alert-info .alert-link {\n color: #245269;\n}\n.alert-warning {\n background-color: #fcf8e3;\n border-color: #faebcc;\n color: #8a6d3b;\n}\n.alert-warning hr {\n border-top-color: #f7e1b5;\n}\n.alert-warning .alert-link {\n color: #66512c;\n}\n.alert-danger {\n background-color: #f2dede;\n border-color: #ebccd1;\n color: #a94442;\n}\n.alert-danger hr {\n border-top-color: #e4b9c0;\n}\n.alert-danger .alert-link {\n color: #843534;\n}\n@-webkit-keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n@keyframes progress-bar-stripes {\n from {\n background-position: 40px 0;\n }\n to {\n background-position: 0 0;\n }\n}\n.progress {\n overflow: hidden;\n height: 20px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);\n}\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: 12px;\n line-height: 20px;\n color: #ffffff;\n text-align: center;\n background-color: #337ab7;\n -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);\n -webkit-transition: width 0.6s ease;\n -o-transition: width 0.6s ease;\n transition: width 0.6s ease;\n}\n.progress-striped .progress-bar,\n.progress-bar-striped {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-size: 40px 40px;\n}\n.progress.active .progress-bar,\n.progress-bar.active {\n -webkit-animation: progress-bar-stripes 2s linear infinite;\n -o-animation: progress-bar-stripes 2s linear infinite;\n animation: progress-bar-stripes 2s linear infinite;\n}\n.progress-bar-success {\n background-color: #5cb85c;\n}\n.progress-striped .progress-bar-success {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-info {\n background-color: #5bc0de;\n}\n.progress-striped .progress-bar-info {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-warning {\n background-color: #f0ad4e;\n}\n.progress-striped .progress-bar-warning {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.progress-bar-danger {\n background-color: #d9534f;\n}\n.progress-striped .progress-bar-danger {\n background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);\n}\n.media {\n margin-top: 15px;\n}\n.media:first-child {\n margin-top: 0;\n}\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n.media-body {\n width: 10000px;\n}\n.media-object {\n display: block;\n}\n.media-object.img-thumbnail {\n max-width: none;\n}\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n.media-middle {\n vertical-align: middle;\n}\n.media-bottom {\n vertical-align: bottom;\n}\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n.list-group {\n margin-bottom: 20px;\n padding-left: 0;\n}\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n margin-bottom: -1px;\n background-color: #ffffff;\n border: 1px solid #dddddd;\n}\n.list-group-item:first-child {\n border-top-right-radius: 4px;\n border-top-left-radius: 4px;\n}\n.list-group-item:last-child {\n margin-bottom: 0;\n border-bottom-right-radius: 4px;\n border-bottom-left-radius: 4px;\n}\na.list-group-item,\nbutton.list-group-item {\n color: #555555;\n}\na.list-group-item .list-group-item-heading,\nbutton.list-group-item .list-group-item-heading {\n color: #333333;\n}\na.list-group-item:hover,\nbutton.list-group-item:hover,\na.list-group-item:focus,\nbutton.list-group-item:focus {\n text-decoration: none;\n color: #555555;\n background-color: #f5f5f5;\n}\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n.list-group-item.disabled,\n.list-group-item.disabled:hover,\n.list-group-item.disabled:focus {\n background-color: #eeeeee;\n color: #777777;\n cursor: not-allowed;\n}\n.list-group-item.disabled .list-group-item-heading,\n.list-group-item.disabled:hover .list-group-item-heading,\n.list-group-item.disabled:focus .list-group-item-heading {\n color: inherit;\n}\n.list-group-item.disabled .list-group-item-text,\n.list-group-item.disabled:hover .list-group-item-text,\n.list-group-item.disabled:focus .list-group-item-text {\n color: #777777;\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n z-index: 2;\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.list-group-item.active .list-group-item-heading,\n.list-group-item.active:hover .list-group-item-heading,\n.list-group-item.active:focus .list-group-item-heading,\n.list-group-item.active .list-group-item-heading > small,\n.list-group-item.active:hover .list-group-item-heading > small,\n.list-group-item.active:focus .list-group-item-heading > small,\n.list-group-item.active .list-group-item-heading > .small,\n.list-group-item.active:hover .list-group-item-heading > .small,\n.list-group-item.active:focus .list-group-item-heading > .small {\n color: inherit;\n}\n.list-group-item.active .list-group-item-text,\n.list-group-item.active:hover .list-group-item-text,\n.list-group-item.active:focus .list-group-item-text {\n color: #c7ddef;\n}\n.list-group-item-success {\n color: #3c763d;\n background-color: #dff0d8;\n}\na.list-group-item-success,\nbutton.list-group-item-success {\n color: #3c763d;\n}\na.list-group-item-success .list-group-item-heading,\nbutton.list-group-item-success .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-success:hover,\nbutton.list-group-item-success:hover,\na.list-group-item-success:focus,\nbutton.list-group-item-success:focus {\n color: #3c763d;\n background-color: #d0e9c6;\n}\na.list-group-item-success.active,\nbutton.list-group-item-success.active,\na.list-group-item-success.active:hover,\nbutton.list-group-item-success.active:hover,\na.list-group-item-success.active:focus,\nbutton.list-group-item-success.active:focus {\n color: #fff;\n background-color: #3c763d;\n border-color: #3c763d;\n}\n.list-group-item-info {\n color: #31708f;\n background-color: #d9edf7;\n}\na.list-group-item-info,\nbutton.list-group-item-info {\n color: #31708f;\n}\na.list-group-item-info .list-group-item-heading,\nbutton.list-group-item-info .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-info:hover,\nbutton.list-group-item-info:hover,\na.list-group-item-info:focus,\nbutton.list-group-item-info:focus {\n color: #31708f;\n background-color: #c4e3f3;\n}\na.list-group-item-info.active,\nbutton.list-group-item-info.active,\na.list-group-item-info.active:hover,\nbutton.list-group-item-info.active:hover,\na.list-group-item-info.active:focus,\nbutton.list-group-item-info.active:focus {\n color: #fff;\n background-color: #31708f;\n border-color: #31708f;\n}\n.list-group-item-warning {\n color: #8a6d3b;\n background-color: #fcf8e3;\n}\na.list-group-item-warning,\nbutton.list-group-item-warning {\n color: #8a6d3b;\n}\na.list-group-item-warning .list-group-item-heading,\nbutton.list-group-item-warning .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-warning:hover,\nbutton.list-group-item-warning:hover,\na.list-group-item-warning:focus,\nbutton.list-group-item-warning:focus {\n color: #8a6d3b;\n background-color: #faf2cc;\n}\na.list-group-item-warning.active,\nbutton.list-group-item-warning.active,\na.list-group-item-warning.active:hover,\nbutton.list-group-item-warning.active:hover,\na.list-group-item-warning.active:focus,\nbutton.list-group-item-warning.active:focus {\n color: #fff;\n background-color: #8a6d3b;\n border-color: #8a6d3b;\n}\n.list-group-item-danger {\n color: #a94442;\n background-color: #f2dede;\n}\na.list-group-item-danger,\nbutton.list-group-item-danger {\n color: #a94442;\n}\na.list-group-item-danger .list-group-item-heading,\nbutton.list-group-item-danger .list-group-item-heading {\n color: inherit;\n}\na.list-group-item-danger:hover,\nbutton.list-group-item-danger:hover,\na.list-group-item-danger:focus,\nbutton.list-group-item-danger:focus {\n color: #a94442;\n background-color: #ebcccc;\n}\na.list-group-item-danger.active,\nbutton.list-group-item-danger.active,\na.list-group-item-danger.active:hover,\nbutton.list-group-item-danger.active:hover,\na.list-group-item-danger.active:focus,\nbutton.list-group-item-danger.active:focus {\n color: #fff;\n background-color: #a94442;\n border-color: #a94442;\n}\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n.panel {\n margin-bottom: 20px;\n background-color: #ffffff;\n border: 1px solid transparent;\n border-radius: 4px;\n -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.panel-body {\n padding: 15px;\n}\n.panel-heading {\n padding: 10px 15px;\n border-bottom: 1px solid transparent;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel-heading > .dropdown .dropdown-toggle {\n color: inherit;\n}\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: 16px;\n color: inherit;\n}\n.panel-title > a,\n.panel-title > small,\n.panel-title > .small,\n.panel-title > small > a,\n.panel-title > .small > a {\n color: inherit;\n}\n.panel-footer {\n padding: 10px 15px;\n background-color: #f5f5f5;\n border-top: 1px solid #dddddd;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .list-group,\n.panel > .panel-collapse > .list-group {\n margin-bottom: 0;\n}\n.panel > .list-group .list-group-item,\n.panel > .panel-collapse > .list-group .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n}\n.panel > .list-group:first-child .list-group-item:first-child,\n.panel > .panel-collapse > .list-group:first-child .list-group-item:first-child {\n border-top: 0;\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .list-group:last-child .list-group-item:last-child,\n.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child {\n border-bottom: 0;\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .panel-heading + .panel-collapse > .list-group .list-group-item:first-child {\n border-top-right-radius: 0;\n border-top-left-radius: 0;\n}\n.panel-heading + .list-group .list-group-item:first-child {\n border-top-width: 0;\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n.panel > .table,\n.panel > .table-responsive > .table,\n.panel > .panel-collapse > .table {\n margin-bottom: 0;\n}\n.panel > .table caption,\n.panel > .table-responsive > .table caption,\n.panel > .panel-collapse > .table caption {\n padding-left: 15px;\n padding-right: 15px;\n}\n.panel > .table:first-child,\n.panel > .table-responsive:first-child > .table:first-child {\n border-top-right-radius: 3px;\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child {\n border-top-left-radius: 3px;\n border-top-right-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child {\n border-top-left-radius: 3px;\n}\n.panel > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child,\n.panel > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child,\n.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child,\n.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:last-child {\n border-top-right-radius: 3px;\n}\n.panel > .table:last-child,\n.panel > .table-responsive:last-child > .table:last-child {\n border-bottom-right-radius: 3px;\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child {\n border-bottom-left-radius: 3px;\n border-bottom-right-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child {\n border-bottom-left-radius: 3px;\n}\n.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child,\n.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child,\n.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child,\n.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child {\n border-bottom-right-radius: 3px;\n}\n.panel > .panel-body + .table,\n.panel > .panel-body + .table-responsive,\n.panel > .table + .panel-body,\n.panel > .table-responsive + .panel-body {\n border-top: 1px solid #dddddd;\n}\n.panel > .table > tbody:first-child > tr:first-child th,\n.panel > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n}\n.panel > .table-bordered,\n.panel > .table-responsive > .table-bordered {\n border: 0;\n}\n.panel > .table-bordered > thead > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:first-child,\n.panel > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child,\n.panel > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child,\n.panel > .table-bordered > thead > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:first-child,\n.panel > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child,\n.panel > .table-bordered > tfoot > tr > td:first-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child {\n border-left: 0;\n}\n.panel > .table-bordered > thead > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > th:last-child,\n.panel > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child,\n.panel > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child,\n.panel > .table-bordered > thead > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > thead > tr > td:last-child,\n.panel > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child,\n.panel > .table-bordered > tfoot > tr > td:last-child,\n.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child {\n border-right: 0;\n}\n.panel > .table-bordered > thead > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > td,\n.panel > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > td,\n.panel > .table-bordered > thead > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > thead > tr:first-child > th,\n.panel > .table-bordered > tbody > tr:first-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:first-child > th {\n border-bottom: 0;\n}\n.panel > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td,\n.panel > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td,\n.panel > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th,\n.panel > .table-bordered > tfoot > tr:last-child > th,\n.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th {\n border-bottom: 0;\n}\n.panel > .table-responsive {\n border: 0;\n margin-bottom: 0;\n}\n.panel-group {\n margin-bottom: 20px;\n}\n.panel-group .panel {\n margin-bottom: 0;\n border-radius: 4px;\n}\n.panel-group .panel + .panel {\n margin-top: 5px;\n}\n.panel-group .panel-heading {\n border-bottom: 0;\n}\n.panel-group .panel-heading + .panel-collapse > .panel-body,\n.panel-group .panel-heading + .panel-collapse > .list-group {\n border-top: 1px solid #dddddd;\n}\n.panel-group .panel-footer {\n border-top: 0;\n}\n.panel-group .panel-footer + .panel-collapse .panel-body {\n border-bottom: 1px solid #dddddd;\n}\n.panel-default {\n border-color: #dddddd;\n}\n.panel-default > .panel-heading {\n color: #333333;\n background-color: #f5f5f5;\n border-color: #dddddd;\n}\n.panel-default > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #dddddd;\n}\n.panel-default > .panel-heading .badge {\n color: #f5f5f5;\n background-color: #333333;\n}\n.panel-default > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #dddddd;\n}\n.panel-primary {\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading {\n color: #ffffff;\n background-color: #337ab7;\n border-color: #337ab7;\n}\n.panel-primary > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #337ab7;\n}\n.panel-primary > .panel-heading .badge {\n color: #337ab7;\n background-color: #ffffff;\n}\n.panel-primary > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #337ab7;\n}\n.panel-success {\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading {\n color: #3c763d;\n background-color: #dff0d8;\n border-color: #d6e9c6;\n}\n.panel-success > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #d6e9c6;\n}\n.panel-success > .panel-heading .badge {\n color: #dff0d8;\n background-color: #3c763d;\n}\n.panel-success > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #d6e9c6;\n}\n.panel-info {\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading {\n color: #31708f;\n background-color: #d9edf7;\n border-color: #bce8f1;\n}\n.panel-info > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #bce8f1;\n}\n.panel-info > .panel-heading .badge {\n color: #d9edf7;\n background-color: #31708f;\n}\n.panel-info > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #bce8f1;\n}\n.panel-warning {\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading {\n color: #8a6d3b;\n background-color: #fcf8e3;\n border-color: #faebcc;\n}\n.panel-warning > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #faebcc;\n}\n.panel-warning > .panel-heading .badge {\n color: #fcf8e3;\n background-color: #8a6d3b;\n}\n.panel-warning > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #faebcc;\n}\n.panel-danger {\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading {\n color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n}\n.panel-danger > .panel-heading + .panel-collapse > .panel-body {\n border-top-color: #ebccd1;\n}\n.panel-danger > .panel-heading .badge {\n color: #f2dede;\n background-color: #a94442;\n}\n.panel-danger > .panel-footer + .panel-collapse > .panel-body {\n border-bottom-color: #ebccd1;\n}\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n}\n.embed-responsive .embed-responsive-item,\n.embed-responsive iframe,\n.embed-responsive embed,\n.embed-responsive object,\n.embed-responsive video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n}\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: #f5f5f5;\n border: 1px solid #e3e3e3;\n border-radius: 4px;\n -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);\n}\n.well blockquote {\n border-color: #ddd;\n border-color: rgba(0, 0, 0, 0.15);\n}\n.well-lg {\n padding: 24px;\n border-radius: 6px;\n}\n.well-sm {\n padding: 9px;\n border-radius: 3px;\n}\n.close {\n float: right;\n font-size: 21px;\n font-weight: bold;\n line-height: 1;\n color: #000000;\n text-shadow: 0 1px 0 #ffffff;\n opacity: 0.2;\n filter: alpha(opacity=20);\n}\n.close:hover,\n.close:focus {\n color: #000000;\n text-decoration: none;\n cursor: pointer;\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\nbutton.close {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n}\n.modal-open {\n overflow: hidden;\n}\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1050;\n -webkit-overflow-scrolling: touch;\n outline: 0;\n}\n.modal.fade .modal-dialog {\n -webkit-transform: translate(0, -25%);\n -ms-transform: translate(0, -25%);\n -o-transform: translate(0, -25%);\n transform: translate(0, -25%);\n -webkit-transition: -webkit-transform 0.3s ease-out;\n -moz-transition: -moz-transform 0.3s ease-out;\n -o-transition: -o-transform 0.3s ease-out;\n transition: transform 0.3s ease-out;\n}\n.modal.in .modal-dialog {\n -webkit-transform: translate(0, 0);\n -ms-transform: translate(0, 0);\n -o-transform: translate(0, 0);\n transform: translate(0, 0);\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n.modal-content {\n position: relative;\n background-color: #ffffff;\n border: 1px solid #999999;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5);\n background-clip: padding-box;\n outline: 0;\n}\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: 1040;\n background-color: #000000;\n}\n.modal-backdrop.fade {\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.modal-backdrop.in {\n opacity: 0.5;\n filter: alpha(opacity=50);\n}\n.modal-header {\n padding: 15px;\n border-bottom: 1px solid #e5e5e5;\n min-height: 16.42857143px;\n}\n.modal-header .close {\n margin-top: -2px;\n}\n.modal-title {\n margin: 0;\n line-height: 1.42857143;\n}\n.modal-body {\n position: relative;\n padding: 15px;\n}\n.modal-footer {\n padding: 15px;\n text-align: right;\n border-top: 1px solid #e5e5e5;\n}\n.modal-footer .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0;\n}\n.modal-footer .btn-group .btn + .btn {\n margin-left: -1px;\n}\n.modal-footer .btn-block + .btn-block {\n margin-left: 0;\n}\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n@media (min-width: 768px) {\n .modal-dialog {\n width: 600px;\n margin: 30px auto;\n }\n .modal-content {\n -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n .modal-sm {\n width: 300px;\n }\n}\n@media (min-width: 992px) {\n .modal-lg {\n width: 900px;\n }\n}\n.tooltip {\n position: absolute;\n z-index: 1070;\n display: block;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 12px;\n opacity: 0;\n filter: alpha(opacity=0);\n}\n.tooltip.in {\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.tooltip.top {\n margin-top: -3px;\n padding: 5px 0;\n}\n.tooltip.right {\n margin-left: 3px;\n padding: 0 5px;\n}\n.tooltip.bottom {\n margin-top: 3px;\n padding: 5px 0;\n}\n.tooltip.left {\n margin-left: -3px;\n padding: 0 5px;\n}\n.tooltip-inner {\n max-width: 200px;\n padding: 3px 8px;\n color: #ffffff;\n text-align: center;\n background-color: #000000;\n border-radius: 4px;\n}\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.tooltip.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-left .tooltip-arrow {\n bottom: 0;\n right: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.top-right .tooltip-arrow {\n bottom: 0;\n left: 5px;\n margin-bottom: -5px;\n border-width: 5px 5px 0;\n border-top-color: #000000;\n}\n.tooltip.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -5px;\n border-width: 5px 5px 5px 0;\n border-right-color: #000000;\n}\n.tooltip.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -5px;\n border-width: 5px 0 5px 5px;\n border-left-color: #000000;\n}\n.tooltip.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-left .tooltip-arrow {\n top: 0;\n right: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.tooltip.bottom-right .tooltip-arrow {\n top: 0;\n left: 5px;\n margin-top: -5px;\n border-width: 0 5px 5px;\n border-bottom-color: #000000;\n}\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 1060;\n display: none;\n max-width: 276px;\n padding: 1px;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: 1.42857143;\n text-align: left;\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n font-size: 14px;\n background-color: #ffffff;\n background-clip: padding-box;\n border: 1px solid #cccccc;\n border: 1px solid rgba(0, 0, 0, 0.2);\n border-radius: 6px;\n -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);\n}\n.popover.top {\n margin-top: -10px;\n}\n.popover.right {\n margin-left: 10px;\n}\n.popover.bottom {\n margin-top: 10px;\n}\n.popover.left {\n margin-left: -10px;\n}\n.popover-title {\n margin: 0;\n padding: 8px 14px;\n font-size: 14px;\n background-color: #f7f7f7;\n border-bottom: 1px solid #ebebeb;\n border-radius: 5px 5px 0 0;\n}\n.popover-content {\n padding: 9px 14px;\n}\n.popover > .arrow,\n.popover > .arrow:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n.popover > .arrow {\n border-width: 11px;\n}\n.popover > .arrow:after {\n border-width: 10px;\n content: \"\";\n}\n.popover.top > .arrow {\n left: 50%;\n margin-left: -11px;\n border-bottom-width: 0;\n border-top-color: #999999;\n border-top-color: rgba(0, 0, 0, 0.25);\n bottom: -11px;\n}\n.popover.top > .arrow:after {\n content: \" \";\n bottom: 1px;\n margin-left: -10px;\n border-bottom-width: 0;\n border-top-color: #ffffff;\n}\n.popover.right > .arrow {\n top: 50%;\n left: -11px;\n margin-top: -11px;\n border-left-width: 0;\n border-right-color: #999999;\n border-right-color: rgba(0, 0, 0, 0.25);\n}\n.popover.right > .arrow:after {\n content: \" \";\n left: 1px;\n bottom: -10px;\n border-left-width: 0;\n border-right-color: #ffffff;\n}\n.popover.bottom > .arrow {\n left: 50%;\n margin-left: -11px;\n border-top-width: 0;\n border-bottom-color: #999999;\n border-bottom-color: rgba(0, 0, 0, 0.25);\n top: -11px;\n}\n.popover.bottom > .arrow:after {\n content: \" \";\n top: 1px;\n margin-left: -10px;\n border-top-width: 0;\n border-bottom-color: #ffffff;\n}\n.popover.left > .arrow {\n top: 50%;\n right: -11px;\n margin-top: -11px;\n border-right-width: 0;\n border-left-color: #999999;\n border-left-color: rgba(0, 0, 0, 0.25);\n}\n.popover.left > .arrow:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: #ffffff;\n bottom: -10px;\n}\n.carousel {\n position: relative;\n}\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n}\n.carousel-inner > .item {\n display: none;\n position: relative;\n -webkit-transition: 0.6s ease-in-out left;\n -o-transition: 0.6s ease-in-out left;\n transition: 0.6s ease-in-out left;\n}\n.carousel-inner > .item > img,\n.carousel-inner > .item > a > img {\n line-height: 1;\n}\n@media all and (transform-3d), (-webkit-transform-3d) {\n .carousel-inner > .item {\n -webkit-transition: -webkit-transform 0.6s ease-in-out;\n -moz-transition: -moz-transform 0.6s ease-in-out;\n -o-transition: -o-transform 0.6s ease-in-out;\n transition: transform 0.6s ease-in-out;\n -webkit-backface-visibility: hidden;\n -moz-backface-visibility: hidden;\n backface-visibility: hidden;\n -webkit-perspective: 1000px;\n -moz-perspective: 1000px;\n perspective: 1000px;\n }\n .carousel-inner > .item.next,\n .carousel-inner > .item.active.right {\n -webkit-transform: translate3d(100%, 0, 0);\n transform: translate3d(100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.prev,\n .carousel-inner > .item.active.left {\n -webkit-transform: translate3d(-100%, 0, 0);\n transform: translate3d(-100%, 0, 0);\n left: 0;\n }\n .carousel-inner > .item.next.left,\n .carousel-inner > .item.prev.right,\n .carousel-inner > .item.active {\n -webkit-transform: translate3d(0, 0, 0);\n transform: translate3d(0, 0, 0);\n left: 0;\n }\n}\n.carousel-inner > .active,\n.carousel-inner > .next,\n.carousel-inner > .prev {\n display: block;\n}\n.carousel-inner > .active {\n left: 0;\n}\n.carousel-inner > .next,\n.carousel-inner > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n}\n.carousel-inner > .next {\n left: 100%;\n}\n.carousel-inner > .prev {\n left: -100%;\n}\n.carousel-inner > .next.left,\n.carousel-inner > .prev.right {\n left: 0;\n}\n.carousel-inner > .active.left {\n left: -100%;\n}\n.carousel-inner > .active.right {\n left: 100%;\n}\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: 15%;\n opacity: 0.5;\n filter: alpha(opacity=50);\n font-size: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-control.left {\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.5) 0%, rgba(0, 0, 0, 0.0001) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1);\n}\n.carousel-control.right {\n left: auto;\n right: 0;\n background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: -o-linear-gradient(left, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-image: linear-gradient(to right, rgba(0, 0, 0, 0.0001) 0%, rgba(0, 0, 0, 0.5) 100%);\n background-repeat: repeat-x;\n filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1);\n}\n.carousel-control:hover,\n.carousel-control:focus {\n outline: 0;\n color: #ffffff;\n text-decoration: none;\n opacity: 0.9;\n filter: alpha(opacity=90);\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-left,\n.carousel-control .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n margin-top: -10px;\n z-index: 5;\n display: inline-block;\n}\n.carousel-control .icon-prev,\n.carousel-control .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n}\n.carousel-control .icon-next,\n.carousel-control .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n}\n.carousel-control .icon-prev,\n.carousel-control .icon-next {\n width: 20px;\n height: 20px;\n line-height: 1;\n font-family: serif;\n}\n.carousel-control .icon-prev:before {\n content: '\\2039';\n}\n.carousel-control .icon-next:before {\n content: '\\203a';\n}\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n}\n.carousel-indicators li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid #ffffff;\n border-radius: 10px;\n cursor: pointer;\n background-color: #000 \\9;\n background-color: rgba(0, 0, 0, 0);\n}\n.carousel-indicators .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: #ffffff;\n}\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: #ffffff;\n text-align: center;\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);\n}\n.carousel-caption .btn {\n text-shadow: none;\n}\n@media screen and (min-width: 768px) {\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-prev,\n .carousel-control .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .carousel-control .glyphicon-chevron-left,\n .carousel-control .icon-prev {\n margin-left: -15px;\n }\n .carousel-control .glyphicon-chevron-right,\n .carousel-control .icon-next {\n margin-right: -15px;\n }\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n .carousel-indicators {\n bottom: 20px;\n }\n}\n.clearfix:before,\n.clearfix:after,\n.dl-horizontal dd:before,\n.dl-horizontal dd:after,\n.container:before,\n.container:after,\n.container-fluid:before,\n.container-fluid:after,\n.row:before,\n.row:after,\n.form-horizontal .form-group:before,\n.form-horizontal .form-group:after,\n.btn-toolbar:before,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:before,\n.btn-group-vertical > .btn-group:after,\n.nav:before,\n.nav:after,\n.navbar:before,\n.navbar:after,\n.navbar-header:before,\n.navbar-header:after,\n.navbar-collapse:before,\n.navbar-collapse:after,\n.pager:before,\n.pager:after,\n.panel-body:before,\n.panel-body:after,\n.modal-footer:before,\n.modal-footer:after {\n content: \" \";\n display: table;\n}\n.clearfix:after,\n.dl-horizontal dd:after,\n.container:after,\n.container-fluid:after,\n.row:after,\n.form-horizontal .form-group:after,\n.btn-toolbar:after,\n.btn-group-vertical > .btn-group:after,\n.nav:after,\n.navbar:after,\n.navbar-header:after,\n.navbar-collapse:after,\n.pager:after,\n.panel-body:after,\n.modal-footer:after {\n clear: both;\n}\n.center-block {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n font: 0/0 a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n.hidden {\n display: none !important;\n}\n.affix {\n position: fixed;\n}\n@-ms-viewport {\n width: device-width;\n}\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n display: none !important;\n}\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n@media (max-width: 767px) {\n .visible-xs {\n display: block !important;\n }\n table.visible-xs {\n display: table !important;\n }\n tr.visible-xs {\n display: table-row !important;\n }\n th.visible-xs,\n td.visible-xs {\n display: table-cell !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-block {\n display: block !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline {\n display: inline !important;\n }\n}\n@media (max-width: 767px) {\n .visible-xs-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm {\n display: block !important;\n }\n table.visible-sm {\n display: table !important;\n }\n tr.visible-sm {\n display: table-row !important;\n }\n th.visible-sm,\n td.visible-sm {\n display: table-cell !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-block {\n display: block !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline {\n display: inline !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .visible-sm-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md {\n display: block !important;\n }\n table.visible-md {\n display: table !important;\n }\n tr.visible-md {\n display: table-row !important;\n }\n th.visible-md,\n td.visible-md {\n display: table-cell !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-block {\n display: block !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline {\n display: inline !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .visible-md-inline-block {\n display: inline-block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg {\n display: block !important;\n }\n table.visible-lg {\n display: table !important;\n }\n tr.visible-lg {\n display: table-row !important;\n }\n th.visible-lg,\n td.visible-lg {\n display: table-cell !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-block {\n display: block !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline {\n display: inline !important;\n }\n}\n@media (min-width: 1200px) {\n .visible-lg-inline-block {\n display: inline-block !important;\n }\n}\n@media (max-width: 767px) {\n .hidden-xs {\n display: none !important;\n }\n}\n@media (min-width: 768px) and (max-width: 991px) {\n .hidden-sm {\n display: none !important;\n }\n}\n@media (min-width: 992px) and (max-width: 1199px) {\n .hidden-md {\n display: none !important;\n }\n}\n@media (min-width: 1200px) {\n .hidden-lg {\n display: none !important;\n }\n}\n.visible-print {\n display: none !important;\n}\n@media print {\n .visible-print {\n display: block !important;\n }\n table.visible-print {\n display: table !important;\n }\n tr.visible-print {\n display: table-row !important;\n }\n th.visible-print,\n td.visible-print {\n display: table-cell !important;\n }\n}\n.visible-print-block {\n display: none !important;\n}\n@media print {\n .visible-print-block {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n}\n@media print {\n .visible-print-inline {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n}\n@media print {\n .visible-print-inline-block {\n display: inline-block !important;\n }\n}\n@media print {\n .hidden-print {\n display: none !important;\n }\n}\n/*# sourceMappingURL=bootstrap.css.map */","/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */\n\n//\n// 1. Set default font family to sans-serif.\n// 2. Prevent iOS and IE text size adjust after device orientation change,\n// without disabling user zoom.\n//\n\nhtml {\n font-family: sans-serif; // 1\n -ms-text-size-adjust: 100%; // 2\n -webkit-text-size-adjust: 100%; // 2\n}\n\n//\n// Remove default margin.\n//\n\nbody {\n margin: 0;\n}\n\n// HTML5 display definitions\n// ==========================================================================\n\n//\n// Correct `block` display not defined for any HTML5 element in IE 8/9.\n// Correct `block` display not defined for `details` or `summary` in IE 10/11\n// and Firefox.\n// Correct `block` display not defined for `main` in IE 11.\n//\n\narticle,\naside,\ndetails,\nfigcaption,\nfigure,\nfooter,\nheader,\nhgroup,\nmain,\nmenu,\nnav,\nsection,\nsummary {\n display: block;\n}\n\n//\n// 1. Correct `inline-block` display not defined in IE 8/9.\n// 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.\n//\n\naudio,\ncanvas,\nprogress,\nvideo {\n display: inline-block; // 1\n vertical-align: baseline; // 2\n}\n\n//\n// Prevent modern browsers from displaying `audio` without controls.\n// Remove excess height in iOS 5 devices.\n//\n\naudio:not([controls]) {\n display: none;\n height: 0;\n}\n\n//\n// Address `[hidden]` styling not present in IE 8/9/10.\n// Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.\n//\n\n[hidden],\ntemplate {\n display: none;\n}\n\n// Links\n// ==========================================================================\n\n//\n// Remove the gray background color from active links in IE 10.\n//\n\na {\n background-color: transparent;\n}\n\n//\n// Improve readability of focused elements when they are also in an\n// active/hover state.\n//\n\na:active,\na:hover {\n outline: 0;\n}\n\n// Text-level semantics\n// ==========================================================================\n\n//\n// Address styling not present in IE 8/9/10/11, Safari, and Chrome.\n//\n\nabbr[title] {\n border-bottom: 1px dotted;\n}\n\n//\n// Address style set to `bolder` in Firefox 4+, Safari, and Chrome.\n//\n\nb,\nstrong {\n font-weight: bold;\n}\n\n//\n// Address styling not present in Safari and Chrome.\n//\n\ndfn {\n font-style: italic;\n}\n\n//\n// Address variable `h1` font-size and margin within `section` and `article`\n// contexts in Firefox 4+, Safari, and Chrome.\n//\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n//\n// Address styling not present in IE 8/9.\n//\n\nmark {\n background: #ff0;\n color: #000;\n}\n\n//\n// Address inconsistent and variable font size in all browsers.\n//\n\nsmall {\n font-size: 80%;\n}\n\n//\n// Prevent `sub` and `sup` affecting `line-height` in all browsers.\n//\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsup {\n top: -0.5em;\n}\n\nsub {\n bottom: -0.25em;\n}\n\n// Embedded content\n// ==========================================================================\n\n//\n// Remove border when inside `a` element in IE 8/9/10.\n//\n\nimg {\n border: 0;\n}\n\n//\n// Correct overflow not hidden in IE 9/10/11.\n//\n\nsvg:not(:root) {\n overflow: hidden;\n}\n\n// Grouping content\n// ==========================================================================\n\n//\n// Address margin not present in IE 8/9 and Safari.\n//\n\nfigure {\n margin: 1em 40px;\n}\n\n//\n// Address differences between Firefox and other browsers.\n//\n\nhr {\n box-sizing: content-box;\n height: 0;\n}\n\n//\n// Contain overflow in all browsers.\n//\n\npre {\n overflow: auto;\n}\n\n//\n// Address odd `em`-unit font size rendering in all browsers.\n//\n\ncode,\nkbd,\npre,\nsamp {\n font-family: monospace, monospace;\n font-size: 1em;\n}\n\n// Forms\n// ==========================================================================\n\n//\n// Known limitation: by default, Chrome and Safari on OS X allow very limited\n// styling of `select`, unless a `border` property is set.\n//\n\n//\n// 1. Correct color not being inherited.\n// Known issue: affects color of disabled elements.\n// 2. Correct font properties not being inherited.\n// 3. Address margins set differently in Firefox 4+, Safari, and Chrome.\n//\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n color: inherit; // 1\n font: inherit; // 2\n margin: 0; // 3\n}\n\n//\n// Address `overflow` set to `hidden` in IE 8/9/10/11.\n//\n\nbutton {\n overflow: visible;\n}\n\n//\n// Address inconsistent `text-transform` inheritance for `button` and `select`.\n// All other form control elements do not inherit `text-transform` values.\n// Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.\n// Correct `select` style inheritance in Firefox.\n//\n\nbutton,\nselect {\n text-transform: none;\n}\n\n//\n// 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\n// and `video` controls.\n// 2. Correct inability to style clickable `input` types in iOS.\n// 3. Improve usability and consistency of cursor style between image-type\n// `input` and others.\n//\n\nbutton,\nhtml input[type=\"button\"], // 1\ninput[type=\"reset\"],\ninput[type=\"submit\"] {\n -webkit-appearance: button; // 2\n cursor: pointer; // 3\n}\n\n//\n// Re-set default cursor for disabled elements.\n//\n\nbutton[disabled],\nhtml input[disabled] {\n cursor: default;\n}\n\n//\n// Remove inner padding and border in Firefox 4+.\n//\n\nbutton::-moz-focus-inner,\ninput::-moz-focus-inner {\n border: 0;\n padding: 0;\n}\n\n//\n// Address Firefox 4+ setting `line-height` on `input` using `!important` in\n// the UA stylesheet.\n//\n\ninput {\n line-height: normal;\n}\n\n//\n// It's recommended that you don't attempt to style these elements.\n// Firefox's implementation doesn't respect box-sizing, padding, or width.\n//\n// 1. Address box sizing set to `content-box` in IE 8/9/10.\n// 2. Remove excess padding in IE 8/9/10.\n//\n\ninput[type=\"checkbox\"],\ninput[type=\"radio\"] {\n box-sizing: border-box; // 1\n padding: 0; // 2\n}\n\n//\n// Fix the cursor style for Chrome's increment/decrement buttons. For certain\n// `font-size` values of the `input`, it causes the cursor style of the\n// decrement button to change from `default` to `text`.\n//\n\ninput[type=\"number\"]::-webkit-inner-spin-button,\ninput[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n//\n// 1. Address `appearance` set to `searchfield` in Safari and Chrome.\n// 2. Address `box-sizing` set to `border-box` in Safari and Chrome.\n//\n\ninput[type=\"search\"] {\n -webkit-appearance: textfield; // 1\n box-sizing: content-box; //2\n}\n\n//\n// Remove inner padding and search cancel button in Safari and Chrome on OS X.\n// Safari (but not Chrome) clips the cancel button when the search input has\n// padding (and `textfield` appearance).\n//\n\ninput[type=\"search\"]::-webkit-search-cancel-button,\ninput[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n//\n// Define consistent border, margin, and padding.\n//\n\nfieldset {\n border: 1px solid #c0c0c0;\n margin: 0 2px;\n padding: 0.35em 0.625em 0.75em;\n}\n\n//\n// 1. Correct `color` not being inherited in IE 8/9/10/11.\n// 2. Remove padding so people aren't caught out if they zero out fieldsets.\n//\n\nlegend {\n border: 0; // 1\n padding: 0; // 2\n}\n\n//\n// Remove default vertical scrollbar in IE 8/9/10/11.\n//\n\ntextarea {\n overflow: auto;\n}\n\n//\n// Don't inherit the `font-weight` (applied by a rule above).\n// NOTE: the default cannot safely be changed in Chrome and Safari on OS X.\n//\n\noptgroup {\n font-weight: bold;\n}\n\n// Tables\n// ==========================================================================\n\n//\n// Remove most spacing between table cells.\n//\n\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\n\ntd,\nth {\n padding: 0;\n}\n","/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */\n\n// ==========================================================================\n// Print styles.\n// Inlined to avoid the additional HTTP request: h5bp.com/r\n// ==========================================================================\n\n@media print {\n *,\n *:before,\n *:after {\n background: transparent !important;\n color: #000 !important; // Black prints faster: h5bp.com/s\n box-shadow: none !important;\n text-shadow: none !important;\n }\n\n a,\n a:visited {\n text-decoration: underline;\n }\n\n a[href]:after {\n content: \" (\" attr(href) \")\";\n }\n\n abbr[title]:after {\n content: \" (\" attr(title) \")\";\n }\n\n // Don't show links that are fragment identifiers,\n // or use the `javascript:` pseudo protocol\n a[href^=\"#\"]:after,\n a[href^=\"javascript:\"]:after {\n content: \"\";\n }\n\n pre,\n blockquote {\n border: 1px solid #999;\n page-break-inside: avoid;\n }\n\n thead {\n display: table-header-group; // h5bp.com/t\n }\n\n tr,\n img {\n page-break-inside: avoid;\n }\n\n img {\n max-width: 100% !important;\n }\n\n p,\n h2,\n h3 {\n orphans: 3;\n widows: 3;\n }\n\n h2,\n h3 {\n page-break-after: avoid;\n }\n\n // Bootstrap specific changes start\n\n // Bootstrap components\n .navbar {\n display: none;\n }\n .btn,\n .dropup > .btn {\n > .caret {\n border-top-color: #000 !important;\n }\n }\n .label {\n border: 1px solid #000;\n }\n\n .table {\n border-collapse: collapse !important;\n\n td,\n th {\n background-color: #fff !important;\n }\n }\n .table-bordered {\n th,\n td {\n border: 1px solid #ddd !important;\n }\n }\n\n // Bootstrap specific changes end\n}\n","//\n// Glyphicons for Bootstrap\n//\n// Since icons are fonts, they can be placed anywhere text is placed and are\n// thus automatically sized to match the surrounding child. To use, create an\n// inline element with the appropriate classes, like so:\n//\n// <a href=\"#\"><span class=\"glyphicon glyphicon-star\"></span> Star</a>\n\n// Import the fonts\n@font-face {\n font-family: 'Glyphicons Halflings';\n src: url('@{icon-font-path}@{icon-font-name}.eot');\n src: url('@{icon-font-path}@{icon-font-name}.eot?#iefix') format('embedded-opentype'),\n url('@{icon-font-path}@{icon-font-name}.woff2') format('woff2'),\n url('@{icon-font-path}@{icon-font-name}.woff') format('woff'),\n url('@{icon-font-path}@{icon-font-name}.ttf') format('truetype'),\n url('@{icon-font-path}@{icon-font-name}.svg#@{icon-font-svg-id}') format('svg');\n}\n\n// Catchall baseclass\n.glyphicon {\n position: relative;\n top: 1px;\n display: inline-block;\n font-family: 'Glyphicons Halflings';\n font-style: normal;\n font-weight: normal;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Individual icons\n.glyphicon-asterisk { &:before { content: \"\\2a\"; } }\n.glyphicon-plus { &:before { content: \"\\2b\"; } }\n.glyphicon-euro,\n.glyphicon-eur { &:before { content: \"\\20ac\"; } }\n.glyphicon-minus { &:before { content: \"\\2212\"; } }\n.glyphicon-cloud { &:before { content: \"\\2601\"; } }\n.glyphicon-envelope { &:before { content: \"\\2709\"; } }\n.glyphicon-pencil { &:before { content: \"\\270f\"; } }\n.glyphicon-glass { &:before { content: \"\\e001\"; } }\n.glyphicon-music { &:before { content: \"\\e002\"; } }\n.glyphicon-search { &:before { content: \"\\e003\"; } }\n.glyphicon-heart { &:before { content: \"\\e005\"; } }\n.glyphicon-star { &:before { content: \"\\e006\"; } }\n.glyphicon-star-empty { &:before { content: \"\\e007\"; } }\n.glyphicon-user { &:before { content: \"\\e008\"; } }\n.glyphicon-film { &:before { content: \"\\e009\"; } }\n.glyphicon-th-large { &:before { content: \"\\e010\"; } }\n.glyphicon-th { &:before { content: \"\\e011\"; } }\n.glyphicon-th-list { &:before { content: \"\\e012\"; } }\n.glyphicon-ok { &:before { content: \"\\e013\"; } }\n.glyphicon-remove { &:before { content: \"\\e014\"; } }\n.glyphicon-zoom-in { &:before { content: \"\\e015\"; } }\n.glyphicon-zoom-out { &:before { content: \"\\e016\"; } }\n.glyphicon-off { &:before { content: \"\\e017\"; } }\n.glyphicon-signal { &:before { content: \"\\e018\"; } }\n.glyphicon-cog { &:before { content: \"\\e019\"; } }\n.glyphicon-trash { &:before { content: \"\\e020\"; } }\n.glyphicon-home { &:before { content: \"\\e021\"; } }\n.glyphicon-file { &:before { content: \"\\e022\"; } }\n.glyphicon-time { &:before { content: \"\\e023\"; } }\n.glyphicon-road { &:before { content: \"\\e024\"; } }\n.glyphicon-download-alt { &:before { content: \"\\e025\"; } }\n.glyphicon-download { &:before { content: \"\\e026\"; } }\n.glyphicon-upload { &:before { content: \"\\e027\"; } }\n.glyphicon-inbox { &:before { content: \"\\e028\"; } }\n.glyphicon-play-circle { &:before { content: \"\\e029\"; } }\n.glyphicon-repeat { &:before { content: \"\\e030\"; } }\n.glyphicon-refresh { &:before { content: \"\\e031\"; } }\n.glyphicon-list-alt { &:before { content: \"\\e032\"; } }\n.glyphicon-lock { &:before { content: \"\\e033\"; } }\n.glyphicon-flag { &:before { content: \"\\e034\"; } }\n.glyphicon-headphones { &:before { content: \"\\e035\"; } }\n.glyphicon-volume-off { &:before { content: \"\\e036\"; } }\n.glyphicon-volume-down { &:before { content: \"\\e037\"; } }\n.glyphicon-volume-up { &:before { content: \"\\e038\"; } }\n.glyphicon-qrcode { &:before { content: \"\\e039\"; } }\n.glyphicon-barcode { &:before { content: \"\\e040\"; } }\n.glyphicon-tag { &:before { content: \"\\e041\"; } }\n.glyphicon-tags { &:before { content: \"\\e042\"; } }\n.glyphicon-book { &:before { content: \"\\e043\"; } }\n.glyphicon-bookmark { &:before { content: \"\\e044\"; } }\n.glyphicon-print { &:before { content: \"\\e045\"; } }\n.glyphicon-camera { &:before { content: \"\\e046\"; } }\n.glyphicon-font { &:before { content: \"\\e047\"; } }\n.glyphicon-bold { &:before { content: \"\\e048\"; } }\n.glyphicon-italic { &:before { content: \"\\e049\"; } }\n.glyphicon-text-height { &:before { content: \"\\e050\"; } }\n.glyphicon-text-width { &:before { content: \"\\e051\"; } }\n.glyphicon-align-left { &:before { content: \"\\e052\"; } }\n.glyphicon-align-center { &:before { content: \"\\e053\"; } }\n.glyphicon-align-right { &:before { content: \"\\e054\"; } }\n.glyphicon-align-justify { &:before { content: \"\\e055\"; } }\n.glyphicon-list { &:before { content: \"\\e056\"; } }\n.glyphicon-indent-left { &:before { content: \"\\e057\"; } }\n.glyphicon-indent-right { &:before { content: \"\\e058\"; } }\n.glyphicon-facetime-video { &:before { content: \"\\e059\"; } }\n.glyphicon-picture { &:before { content: \"\\e060\"; } }\n.glyphicon-map-marker { &:before { content: \"\\e062\"; } }\n.glyphicon-adjust { &:before { content: \"\\e063\"; } }\n.glyphicon-tint { &:before { content: \"\\e064\"; } }\n.glyphicon-edit { &:before { content: \"\\e065\"; } }\n.glyphicon-share { &:before { content: \"\\e066\"; } }\n.glyphicon-check { &:before { content: \"\\e067\"; } }\n.glyphicon-move { &:before { content: \"\\e068\"; } }\n.glyphicon-step-backward { &:before { content: \"\\e069\"; } }\n.glyphicon-fast-backward { &:before { content: \"\\e070\"; } }\n.glyphicon-backward { &:before { content: \"\\e071\"; } }\n.glyphicon-play { &:before { content: \"\\e072\"; } }\n.glyphicon-pause { &:before { content: \"\\e073\"; } }\n.glyphicon-stop { &:before { content: \"\\e074\"; } }\n.glyphicon-forward { &:before { content: \"\\e075\"; } }\n.glyphicon-fast-forward { &:before { content: \"\\e076\"; } }\n.glyphicon-step-forward { &:before { content: \"\\e077\"; } }\n.glyphicon-eject { &:before { content: \"\\e078\"; } }\n.glyphicon-chevron-left { &:before { content: \"\\e079\"; } }\n.glyphicon-chevron-right { &:before { content: \"\\e080\"; } }\n.glyphicon-plus-sign { &:before { content: \"\\e081\"; } }\n.glyphicon-minus-sign { &:before { content: \"\\e082\"; } }\n.glyphicon-remove-sign { &:before { content: \"\\e083\"; } }\n.glyphicon-ok-sign { &:before { content: \"\\e084\"; } }\n.glyphicon-question-sign { &:before { content: \"\\e085\"; } }\n.glyphicon-info-sign { &:before { content: \"\\e086\"; } }\n.glyphicon-screenshot { &:before { content: \"\\e087\"; } }\n.glyphicon-remove-circle { &:before { content: \"\\e088\"; } }\n.glyphicon-ok-circle { &:before { content: \"\\e089\"; } }\n.glyphicon-ban-circle { &:before { content: \"\\e090\"; } }\n.glyphicon-arrow-left { &:before { content: \"\\e091\"; } }\n.glyphicon-arrow-right { &:before { content: \"\\e092\"; } }\n.glyphicon-arrow-up { &:before { content: \"\\e093\"; } }\n.glyphicon-arrow-down { &:before { content: \"\\e094\"; } }\n.glyphicon-share-alt { &:before { content: \"\\e095\"; } }\n.glyphicon-resize-full { &:before { content: \"\\e096\"; } }\n.glyphicon-resize-small { &:before { content: \"\\e097\"; } }\n.glyphicon-exclamation-sign { &:before { content: \"\\e101\"; } }\n.glyphicon-gift { &:before { content: \"\\e102\"; } }\n.glyphicon-leaf { &:before { content: \"\\e103\"; } }\n.glyphicon-fire { &:before { content: \"\\e104\"; } }\n.glyphicon-eye-open { &:before { content: \"\\e105\"; } }\n.glyphicon-eye-close { &:before { content: \"\\e106\"; } }\n.glyphicon-warning-sign { &:before { content: \"\\e107\"; } }\n.glyphicon-plane { &:before { content: \"\\e108\"; } }\n.glyphicon-calendar { &:before { content: \"\\e109\"; } }\n.glyphicon-random { &:before { content: \"\\e110\"; } }\n.glyphicon-comment { &:before { content: \"\\e111\"; } }\n.glyphicon-magnet { &:before { content: \"\\e112\"; } }\n.glyphicon-chevron-up { &:before { content: \"\\e113\"; } }\n.glyphicon-chevron-down { &:before { content: \"\\e114\"; } }\n.glyphicon-retweet { &:before { content: \"\\e115\"; } }\n.glyphicon-shopping-cart { &:before { content: \"\\e116\"; } }\n.glyphicon-folder-close { &:before { content: \"\\e117\"; } }\n.glyphicon-folder-open { &:before { content: \"\\e118\"; } }\n.glyphicon-resize-vertical { &:before { content: \"\\e119\"; } }\n.glyphicon-resize-horizontal { &:before { content: \"\\e120\"; } }\n.glyphicon-hdd { &:before { content: \"\\e121\"; } }\n.glyphicon-bullhorn { &:before { content: \"\\e122\"; } }\n.glyphicon-bell { &:before { content: \"\\e123\"; } }\n.glyphicon-certificate { &:before { content: \"\\e124\"; } }\n.glyphicon-thumbs-up { &:before { content: \"\\e125\"; } }\n.glyphicon-thumbs-down { &:before { content: \"\\e126\"; } }\n.glyphicon-hand-right { &:before { content: \"\\e127\"; } }\n.glyphicon-hand-left { &:before { content: \"\\e128\"; } }\n.glyphicon-hand-up { &:before { content: \"\\e129\"; } }\n.glyphicon-hand-down { &:before { content: \"\\e130\"; } }\n.glyphicon-circle-arrow-right { &:before { content: \"\\e131\"; } }\n.glyphicon-circle-arrow-left { &:before { content: \"\\e132\"; } }\n.glyphicon-circle-arrow-up { &:before { content: \"\\e133\"; } }\n.glyphicon-circle-arrow-down { &:before { content: \"\\e134\"; } }\n.glyphicon-globe { &:before { content: \"\\e135\"; } }\n.glyphicon-wrench { &:before { content: \"\\e136\"; } }\n.glyphicon-tasks { &:before { content: \"\\e137\"; } }\n.glyphicon-filter { &:before { content: \"\\e138\"; } }\n.glyphicon-briefcase { &:before { content: \"\\e139\"; } }\n.glyphicon-fullscreen { &:before { content: \"\\e140\"; } }\n.glyphicon-dashboard { &:before { content: \"\\e141\"; } }\n.glyphicon-paperclip { &:before { content: \"\\e142\"; } }\n.glyphicon-heart-empty { &:before { content: \"\\e143\"; } }\n.glyphicon-link { &:before { content: \"\\e144\"; } }\n.glyphicon-phone { &:before { content: \"\\e145\"; } }\n.glyphicon-pushpin { &:before { content: \"\\e146\"; } }\n.glyphicon-usd { &:before { content: \"\\e148\"; } }\n.glyphicon-gbp { &:before { content: \"\\e149\"; } }\n.glyphicon-sort { &:before { content: \"\\e150\"; } }\n.glyphicon-sort-by-alphabet { &:before { content: \"\\e151\"; } }\n.glyphicon-sort-by-alphabet-alt { &:before { content: \"\\e152\"; } }\n.glyphicon-sort-by-order { &:before { content: \"\\e153\"; } }\n.glyphicon-sort-by-order-alt { &:before { content: \"\\e154\"; } }\n.glyphicon-sort-by-attributes { &:before { content: \"\\e155\"; } }\n.glyphicon-sort-by-attributes-alt { &:before { content: \"\\e156\"; } }\n.glyphicon-unchecked { &:before { content: \"\\e157\"; } }\n.glyphicon-expand { &:before { content: \"\\e158\"; } }\n.glyphicon-collapse-down { &:before { content: \"\\e159\"; } }\n.glyphicon-collapse-up { &:before { content: \"\\e160\"; } }\n.glyphicon-log-in { &:before { content: \"\\e161\"; } }\n.glyphicon-flash { &:before { content: \"\\e162\"; } }\n.glyphicon-log-out { &:before { content: \"\\e163\"; } }\n.glyphicon-new-window { &:before { content: \"\\e164\"; } }\n.glyphicon-record { &:before { content: \"\\e165\"; } }\n.glyphicon-save { &:before { content: \"\\e166\"; } }\n.glyphicon-open { &:before { content: \"\\e167\"; } }\n.glyphicon-saved { &:before { content: \"\\e168\"; } }\n.glyphicon-import { &:before { content: \"\\e169\"; } }\n.glyphicon-export { &:before { content: \"\\e170\"; } }\n.glyphicon-send { &:before { content: \"\\e171\"; } }\n.glyphicon-floppy-disk { &:before { content: \"\\e172\"; } }\n.glyphicon-floppy-saved { &:before { content: \"\\e173\"; } }\n.glyphicon-floppy-remove { &:before { content: \"\\e174\"; } }\n.glyphicon-floppy-save { &:before { content: \"\\e175\"; } }\n.glyphicon-floppy-open { &:before { content: \"\\e176\"; } }\n.glyphicon-credit-card { &:before { content: \"\\e177\"; } }\n.glyphicon-transfer { &:before { content: \"\\e178\"; } }\n.glyphicon-cutlery { &:before { content: \"\\e179\"; } }\n.glyphicon-header { &:before { content: \"\\e180\"; } }\n.glyphicon-compressed { &:before { content: \"\\e181\"; } }\n.glyphicon-earphone { &:before { content: \"\\e182\"; } }\n.glyphicon-phone-alt { &:before { content: \"\\e183\"; } }\n.glyphicon-tower { &:before { content: \"\\e184\"; } }\n.glyphicon-stats { &:before { content: \"\\e185\"; } }\n.glyphicon-sd-video { &:before { content: \"\\e186\"; } }\n.glyphicon-hd-video { &:before { content: \"\\e187\"; } }\n.glyphicon-subtitles { &:before { content: \"\\e188\"; } }\n.glyphicon-sound-stereo { &:before { content: \"\\e189\"; } }\n.glyphicon-sound-dolby { &:before { content: \"\\e190\"; } }\n.glyphicon-sound-5-1 { &:before { content: \"\\e191\"; } }\n.glyphicon-sound-6-1 { &:before { content: \"\\e192\"; } }\n.glyphicon-sound-7-1 { &:before { content: \"\\e193\"; } }\n.glyphicon-copyright-mark { &:before { content: \"\\e194\"; } }\n.glyphicon-registration-mark { &:before { content: \"\\e195\"; } }\n.glyphicon-cloud-download { &:before { content: \"\\e197\"; } }\n.glyphicon-cloud-upload { &:before { content: \"\\e198\"; } }\n.glyphicon-tree-conifer { &:before { content: \"\\e199\"; } }\n.glyphicon-tree-deciduous { &:before { content: \"\\e200\"; } }\n.glyphicon-cd { &:before { content: \"\\e201\"; } }\n.glyphicon-save-file { &:before { content: \"\\e202\"; } }\n.glyphicon-open-file { &:before { content: \"\\e203\"; } }\n.glyphicon-level-up { &:before { content: \"\\e204\"; } }\n.glyphicon-copy { &:before { content: \"\\e205\"; } }\n.glyphicon-paste { &:before { content: \"\\e206\"; } }\n// The following 2 Glyphicons are omitted for the time being because\n// they currently use Unicode codepoints that are outside the\n// Basic Multilingual Plane (BMP). Older buggy versions of WebKit can't handle\n// non-BMP codepoints in CSS string escapes, and thus can't display these two icons.\n// Notably, the bug affects some older versions of the Android Browser.\n// More info: https://github.com/twbs/bootstrap/issues/10106\n// .glyphicon-door { &:before { content: \"\\1f6aa\"; } }\n// .glyphicon-key { &:before { content: \"\\1f511\"; } }\n.glyphicon-alert { &:before { content: \"\\e209\"; } }\n.glyphicon-equalizer { &:before { content: \"\\e210\"; } }\n.glyphicon-king { &:before { content: \"\\e211\"; } }\n.glyphicon-queen { &:before { content: \"\\e212\"; } }\n.glyphicon-pawn { &:before { content: \"\\e213\"; } }\n.glyphicon-bishop { &:before { content: \"\\e214\"; } }\n.glyphicon-knight { &:before { content: \"\\e215\"; } }\n.glyphicon-baby-formula { &:before { content: \"\\e216\"; } }\n.glyphicon-tent { &:before { content: \"\\26fa\"; } }\n.glyphicon-blackboard { &:before { content: \"\\e218\"; } }\n.glyphicon-bed { &:before { content: \"\\e219\"; } }\n.glyphicon-apple { &:before { content: \"\\f8ff\"; } }\n.glyphicon-erase { &:before { content: \"\\e221\"; } }\n.glyphicon-hourglass { &:before { content: \"\\231b\"; } }\n.glyphicon-lamp { &:before { content: \"\\e223\"; } }\n.glyphicon-duplicate { &:before { content: \"\\e224\"; } }\n.glyphicon-piggy-bank { &:before { content: \"\\e225\"; } }\n.glyphicon-scissors { &:before { content: \"\\e226\"; } }\n.glyphicon-bitcoin { &:before { content: \"\\e227\"; } }\n.glyphicon-btc { &:before { content: \"\\e227\"; } }\n.glyphicon-xbt { &:before { content: \"\\e227\"; } }\n.glyphicon-yen { &:before { content: \"\\00a5\"; } }\n.glyphicon-jpy { &:before { content: \"\\00a5\"; } }\n.glyphicon-ruble { &:before { content: \"\\20bd\"; } }\n.glyphicon-rub { &:before { content: \"\\20bd\"; } }\n.glyphicon-scale { &:before { content: \"\\e230\"; } }\n.glyphicon-ice-lolly { &:before { content: \"\\e231\"; } }\n.glyphicon-ice-lolly-tasted { &:before { content: \"\\e232\"; } }\n.glyphicon-education { &:before { content: \"\\e233\"; } }\n.glyphicon-option-horizontal { &:before { content: \"\\e234\"; } }\n.glyphicon-option-vertical { &:before { content: \"\\e235\"; } }\n.glyphicon-menu-hamburger { &:before { content: \"\\e236\"; } }\n.glyphicon-modal-window { &:before { content: \"\\e237\"; } }\n.glyphicon-oil { &:before { content: \"\\e238\"; } }\n.glyphicon-grain { &:before { content: \"\\e239\"; } }\n.glyphicon-sunglasses { &:before { content: \"\\e240\"; } }\n.glyphicon-text-size { &:before { content: \"\\e241\"; } }\n.glyphicon-text-color { &:before { content: \"\\e242\"; } }\n.glyphicon-text-background { &:before { content: \"\\e243\"; } }\n.glyphicon-object-align-top { &:before { content: \"\\e244\"; } }\n.glyphicon-object-align-bottom { &:before { content: \"\\e245\"; } }\n.glyphicon-object-align-horizontal{ &:before { content: \"\\e246\"; } }\n.glyphicon-object-align-left { &:before { content: \"\\e247\"; } }\n.glyphicon-object-align-vertical { &:before { content: \"\\e248\"; } }\n.glyphicon-object-align-right { &:before { content: \"\\e249\"; } }\n.glyphicon-triangle-right { &:before { content: \"\\e250\"; } }\n.glyphicon-triangle-left { &:before { content: \"\\e251\"; } }\n.glyphicon-triangle-bottom { &:before { content: \"\\e252\"; } }\n.glyphicon-triangle-top { &:before { content: \"\\e253\"; } }\n.glyphicon-console { &:before { content: \"\\e254\"; } }\n.glyphicon-superscript { &:before { content: \"\\e255\"; } }\n.glyphicon-subscript { &:before { content: \"\\e256\"; } }\n.glyphicon-menu-left { &:before { content: \"\\e257\"; } }\n.glyphicon-menu-right { &:before { content: \"\\e258\"; } }\n.glyphicon-menu-down { &:before { content: \"\\e259\"; } }\n.glyphicon-menu-up { &:before { content: \"\\e260\"; } }\n","//\n// Scaffolding\n// --------------------------------------------------\n\n\n// Reset the box-sizing\n//\n// Heads up! This reset may cause conflicts with some third-party widgets.\n// For recommendations on resolving such conflicts, see\n// http://getbootstrap.com/getting-started/#third-box-sizing\n* {\n .box-sizing(border-box);\n}\n*:before,\n*:after {\n .box-sizing(border-box);\n}\n\n\n// Body reset\n\nhtml {\n font-size: 10px;\n -webkit-tap-highlight-color: rgba(0,0,0,0);\n}\n\nbody {\n font-family: @font-family-base;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @text-color;\n background-color: @body-bg;\n}\n\n// Reset fonts for relevant elements\ninput,\nbutton,\nselect,\ntextarea {\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n}\n\n\n// Links\n\na {\n color: @link-color;\n text-decoration: none;\n\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n }\n\n &:focus {\n .tab-focus();\n }\n}\n\n\n// Figures\n//\n// We reset this here because previously Normalize had no `figure` margins. This\n// ensures we don't break anyone's use of the element.\n\nfigure {\n margin: 0;\n}\n\n\n// Images\n\nimg {\n vertical-align: middle;\n}\n\n// Responsive images (ensure images don't scale beyond their parents)\n.img-responsive {\n .img-responsive();\n}\n\n// Rounded corners\n.img-rounded {\n border-radius: @border-radius-large;\n}\n\n// Image thumbnails\n//\n// Heads up! This is mixin-ed into thumbnails.less for `.thumbnail`.\n.img-thumbnail {\n padding: @thumbnail-padding;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(all .2s ease-in-out);\n\n // Keep them at most 100% wide\n .img-responsive(inline-block);\n}\n\n// Perfect circle\n.img-circle {\n border-radius: 50%; // set radius in percents\n}\n\n\n// Horizontal rules\n\nhr {\n margin-top: @line-height-computed;\n margin-bottom: @line-height-computed;\n border: 0;\n border-top: 1px solid @hr-border;\n}\n\n\n// Only display content to screen readers\n//\n// See: http://a11yproject.com/posts/how-to-hide-content/\n\n.sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n overflow: hidden;\n clip: rect(0,0,0,0);\n border: 0;\n}\n\n// Use in conjunction with .sr-only to only display content when it's focused.\n// Useful for \"Skip to main content\" links; see http://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n// Credit: HTML5 Boilerplate\n\n.sr-only-focusable {\n &:active,\n &:focus {\n position: static;\n width: auto;\n height: auto;\n margin: 0;\n overflow: visible;\n clip: auto;\n }\n}\n\n\n// iOS \"clickable elements\" fix for role=\"button\"\n//\n// Fixes \"clickability\" issue (and more generally, the firing of events such as focus as well)\n// for traditionally non-focusable elements with role=\"button\"\n// see https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n\n[role=\"button\"] {\n cursor: pointer;\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They will be removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// WebKit-style focus\n\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n","// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// Retina image\n//\n// Short retina mixin for setting background-image and -size. Note that the\n// spelling of `min--moz-device-pixel-ratio` is intentional.\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n","//\n// Typography\n// --------------------------------------------------\n\n\n// Headings\n// -------------------------\n\nh1, h2, h3, h4, h5, h6,\n.h1, .h2, .h3, .h4, .h5, .h6 {\n font-family: @headings-font-family;\n font-weight: @headings-font-weight;\n line-height: @headings-line-height;\n color: @headings-color;\n\n small,\n .small {\n font-weight: normal;\n line-height: 1;\n color: @headings-small-color;\n }\n}\n\nh1, .h1,\nh2, .h2,\nh3, .h3 {\n margin-top: @line-height-computed;\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 65%;\n }\n}\nh4, .h4,\nh5, .h5,\nh6, .h6 {\n margin-top: (@line-height-computed / 2);\n margin-bottom: (@line-height-computed / 2);\n\n small,\n .small {\n font-size: 75%;\n }\n}\n\nh1, .h1 { font-size: @font-size-h1; }\nh2, .h2 { font-size: @font-size-h2; }\nh3, .h3 { font-size: @font-size-h3; }\nh4, .h4 { font-size: @font-size-h4; }\nh5, .h5 { font-size: @font-size-h5; }\nh6, .h6 { font-size: @font-size-h6; }\n\n\n// Body text\n// -------------------------\n\np {\n margin: 0 0 (@line-height-computed / 2);\n}\n\n.lead {\n margin-bottom: @line-height-computed;\n font-size: floor((@font-size-base * 1.15));\n font-weight: 300;\n line-height: 1.4;\n\n @media (min-width: @screen-sm-min) {\n font-size: (@font-size-base * 1.5);\n }\n}\n\n\n// Emphasis & misc\n// -------------------------\n\n// Ex: (12px small font / 14px base font) * 100% = about 85%\nsmall,\n.small {\n font-size: floor((100% * @font-size-small / @font-size-base));\n}\n\nmark,\n.mark {\n background-color: @state-warning-bg;\n padding: .2em;\n}\n\n// Alignment\n.text-left { text-align: left; }\n.text-right { text-align: right; }\n.text-center { text-align: center; }\n.text-justify { text-align: justify; }\n.text-nowrap { white-space: nowrap; }\n\n// Transformation\n.text-lowercase { text-transform: lowercase; }\n.text-uppercase { text-transform: uppercase; }\n.text-capitalize { text-transform: capitalize; }\n\n// Contextual colors\n.text-muted {\n color: @text-muted;\n}\n.text-primary {\n .text-emphasis-variant(@brand-primary);\n}\n.text-success {\n .text-emphasis-variant(@state-success-text);\n}\n.text-info {\n .text-emphasis-variant(@state-info-text);\n}\n.text-warning {\n .text-emphasis-variant(@state-warning-text);\n}\n.text-danger {\n .text-emphasis-variant(@state-danger-text);\n}\n\n// Contextual backgrounds\n// For now we'll leave these alongside the text classes until v4 when we can\n// safely shift things around (per SemVer rules).\n.bg-primary {\n // Given the contrast here, this is the only class to have its color inverted\n // automatically.\n color: #fff;\n .bg-variant(@brand-primary);\n}\n.bg-success {\n .bg-variant(@state-success-bg);\n}\n.bg-info {\n .bg-variant(@state-info-bg);\n}\n.bg-warning {\n .bg-variant(@state-warning-bg);\n}\n.bg-danger {\n .bg-variant(@state-danger-bg);\n}\n\n\n// Page header\n// -------------------------\n\n.page-header {\n padding-bottom: ((@line-height-computed / 2) - 1);\n margin: (@line-height-computed * 2) 0 @line-height-computed;\n border-bottom: 1px solid @page-header-border-color;\n}\n\n\n// Lists\n// -------------------------\n\n// Unordered and Ordered lists\nul,\nol {\n margin-top: 0;\n margin-bottom: (@line-height-computed / 2);\n ul,\n ol {\n margin-bottom: 0;\n }\n}\n\n// List options\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n.list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n\n// Inline turns list items into inline-block\n.list-inline {\n .list-unstyled();\n margin-left: -5px;\n\n > li {\n display: inline-block;\n padding-left: 5px;\n padding-right: 5px;\n }\n}\n\n// Description Lists\ndl {\n margin-top: 0; // Remove browser default\n margin-bottom: @line-height-computed;\n}\ndt,\ndd {\n line-height: @line-height-base;\n}\ndt {\n font-weight: bold;\n}\ndd {\n margin-left: 0; // Undo browser default\n}\n\n// Horizontal description lists\n//\n// Defaults to being stacked without any of the below styles applied, until the\n// grid breakpoint is reached (default of ~768px).\n\n.dl-horizontal {\n dd {\n &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present\n }\n\n @media (min-width: @grid-float-breakpoint) {\n dt {\n float: left;\n width: (@dl-horizontal-offset - 20);\n clear: left;\n text-align: right;\n .text-overflow();\n }\n dd {\n margin-left: @dl-horizontal-offset;\n }\n }\n}\n\n\n// Misc\n// -------------------------\n\n// Abbreviations and acronyms\nabbr[title],\n// Add data-* attribute to help out our tooltip plugin, per https://github.com/twbs/bootstrap/issues/5257\nabbr[data-original-title] {\n cursor: help;\n border-bottom: 1px dotted @abbr-border-color;\n}\n.initialism {\n font-size: 90%;\n .text-uppercase();\n}\n\n// Blockquotes\nblockquote {\n padding: (@line-height-computed / 2) @line-height-computed;\n margin: 0 0 @line-height-computed;\n font-size: @blockquote-font-size;\n border-left: 5px solid @blockquote-border-color;\n\n p,\n ul,\n ol {\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Note: Deprecated small and .small as of v3.1.0\n // Context: https://github.com/twbs/bootstrap/issues/11660\n footer,\n small,\n .small {\n display: block;\n font-size: 80%; // back to default font-size\n line-height: @line-height-base;\n color: @blockquote-small-color;\n\n &:before {\n content: '\\2014 \\00A0'; // em dash, nbsp\n }\n }\n}\n\n// Opposite alignment of blockquote\n//\n// Heads up: `blockquote.pull-right` has been deprecated as of v3.1.0.\n.blockquote-reverse,\nblockquote.pull-right {\n padding-right: 15px;\n padding-left: 0;\n border-right: 5px solid @blockquote-border-color;\n border-left: 0;\n text-align: right;\n\n // Account for citation\n footer,\n small,\n .small {\n &:before { content: ''; }\n &:after {\n content: '\\00A0 \\2014'; // nbsp, em dash\n }\n }\n}\n\n// Addresses\naddress {\n margin-bottom: @line-height-computed;\n font-style: normal;\n line-height: @line-height-base;\n}\n","// Typography\n\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover,\n a&:focus {\n color: darken(@color, 10%);\n }\n}\n","// Contextual backgrounds\n\n.bg-variant(@color) {\n background-color: @color;\n a&:hover,\n a&:focus {\n background-color: darken(@color, 10%);\n }\n}\n","// Text overflow\n// Requires inline-block or block for proper styling\n\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n","//\n// Code (inline and block)\n// --------------------------------------------------\n\n\n// Inline and block code styles\ncode,\nkbd,\npre,\nsamp {\n font-family: @font-family-monospace;\n}\n\n// Inline code\ncode {\n padding: 2px 4px;\n font-size: 90%;\n color: @code-color;\n background-color: @code-bg;\n border-radius: @border-radius-base;\n}\n\n// User input typically entered via keyboard\nkbd {\n padding: 2px 4px;\n font-size: 90%;\n color: @kbd-color;\n background-color: @kbd-bg;\n border-radius: @border-radius-small;\n box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);\n\n kbd {\n padding: 0;\n font-size: 100%;\n font-weight: bold;\n box-shadow: none;\n }\n}\n\n// Blocks of code\npre {\n display: block;\n padding: ((@line-height-computed - 1) / 2);\n margin: 0 0 (@line-height-computed / 2);\n font-size: (@font-size-base - 1); // 14px to 13px\n line-height: @line-height-base;\n word-break: break-all;\n word-wrap: break-word;\n color: @pre-color;\n background-color: @pre-bg;\n border: 1px solid @pre-border-color;\n border-radius: @border-radius-base;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n padding: 0;\n font-size: inherit;\n color: inherit;\n white-space: pre-wrap;\n background-color: transparent;\n border-radius: 0;\n }\n}\n\n// Enable scrollable blocks of code\n.pre-scrollable {\n max-height: @pre-scrollable-max-height;\n overflow-y: scroll;\n}\n","//\n// Grid system\n// --------------------------------------------------\n\n\n// Container widths\n//\n// Set the container width, and override it for fixed navbars in media queries.\n\n.container {\n .container-fixed();\n\n @media (min-width: @screen-sm-min) {\n width: @container-sm;\n }\n @media (min-width: @screen-md-min) {\n width: @container-md;\n }\n @media (min-width: @screen-lg-min) {\n width: @container-lg;\n }\n}\n\n\n// Fluid container\n//\n// Utilizes the mixin meant for fixed width containers, but without any defined\n// width for fluid, full width layouts.\n\n.container-fluid {\n .container-fixed();\n}\n\n\n// Row\n//\n// Rows contain and clear the floats of your columns.\n\n.row {\n .make-row();\n}\n\n\n// Columns\n//\n// Common styles for small and large grid columns\n\n.make-grid-columns();\n\n\n// Extra small grid\n//\n// Columns, offsets, pushes, and pulls for extra small devices like\n// smartphones.\n\n.make-grid(xs);\n\n\n// Small grid\n//\n// Columns, offsets, pushes, and pulls for the small device range, from phones\n// to tablets.\n\n@media (min-width: @screen-sm-min) {\n .make-grid(sm);\n}\n\n\n// Medium grid\n//\n// Columns, offsets, pushes, and pulls for the desktop device range.\n\n@media (min-width: @screen-md-min) {\n .make-grid(md);\n}\n\n\n// Large grid\n//\n// Columns, offsets, pushes, and pulls for the large desktop device range.\n\n@media (min-width: @screen-lg-min) {\n .make-grid(lg);\n}\n","// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n// Centered container element\n.container-fixed(@gutter: @grid-gutter-width) {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: ceil((@gutter / -2));\n margin-right: floor((@gutter / -2));\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n margin-left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-push(@columns) {\n left: percentage((@columns / @grid-columns));\n}\n.make-xs-column-pull(@columns) {\n right: percentage((@columns / @grid-columns));\n}\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n","// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: ceil((@grid-gutter-width / 2));\n padding-right: floor((@grid-gutter-width / 2));\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index > 0) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) and (@index = 0) {\n .col-@{class}-push-0 {\n left: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index > 0) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) and (@index = 0) {\n .col-@{class}-pull-0 {\n right: auto;\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n","//\n// Tables\n// --------------------------------------------------\n\n\ntable {\n background-color: @table-bg;\n}\ncaption {\n padding-top: @table-cell-padding;\n padding-bottom: @table-cell-padding;\n color: @text-muted;\n text-align: left;\n}\nth {\n text-align: left;\n}\n\n\n// Baseline styles\n\n.table {\n width: 100%;\n max-width: 100%;\n margin-bottom: @line-height-computed;\n // Cells\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-cell-padding;\n line-height: @line-height-base;\n vertical-align: top;\n border-top: 1px solid @table-border-color;\n }\n }\n }\n // Bottom align for column headings\n > thead > tr > th {\n vertical-align: bottom;\n border-bottom: 2px solid @table-border-color;\n }\n // Remove top border from thead by default\n > caption + thead,\n > colgroup + thead,\n > thead:first-child {\n > tr:first-child {\n > th,\n > td {\n border-top: 0;\n }\n }\n }\n // Account for multiple tbody instances\n > tbody + tbody {\n border-top: 2px solid @table-border-color;\n }\n\n // Nesting\n .table {\n background-color: @body-bg;\n }\n}\n\n\n// Condensed table w/ half padding\n\n.table-condensed {\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n padding: @table-condensed-cell-padding;\n }\n }\n }\n}\n\n\n// Bordered version\n//\n// Add borders all around the table and between all the columns.\n\n.table-bordered {\n border: 1px solid @table-border-color;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n border: 1px solid @table-border-color;\n }\n }\n }\n > thead > tr {\n > th,\n > td {\n border-bottom-width: 2px;\n }\n }\n}\n\n\n// Zebra-striping\n//\n// Default zebra-stripe styles (alternating gray and transparent backgrounds)\n\n.table-striped {\n > tbody > tr:nth-of-type(odd) {\n background-color: @table-bg-accent;\n }\n}\n\n\n// Hover effect\n//\n// Placed here since it has to come after the potential zebra striping\n\n.table-hover {\n > tbody > tr:hover {\n background-color: @table-bg-hover;\n }\n}\n\n\n// Table cell sizing\n//\n// Reset default table behavior\n\ntable col[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-column;\n}\ntable {\n td,\n th {\n &[class*=\"col-\"] {\n position: static; // Prevent border hiding in Firefox and IE9-11 (see https://github.com/twbs/bootstrap/issues/11623)\n float: none;\n display: table-cell;\n }\n }\n}\n\n\n// Table backgrounds\n//\n// Exact selectors below required to override `.table-striped` and prevent\n// inheritance to nested tables.\n\n// Generate the contextual variants\n.table-row-variant(active; @table-bg-active);\n.table-row-variant(success; @state-success-bg);\n.table-row-variant(info; @state-info-bg);\n.table-row-variant(warning; @state-warning-bg);\n.table-row-variant(danger; @state-danger-bg);\n\n\n// Responsive tables\n//\n// Wrap your tables in `.table-responsive` and we'll make them mobile friendly\n// by enabling horizontal scrolling. Only applies <768px. Everything above that\n// will display normally.\n\n.table-responsive {\n overflow-x: auto;\n min-height: 0.01%; // Workaround for IE9 bug (see https://github.com/twbs/bootstrap/issues/14837)\n\n @media screen and (max-width: @screen-xs-max) {\n width: 100%;\n margin-bottom: (@line-height-computed * 0.75);\n overflow-y: hidden;\n -ms-overflow-style: -ms-autohiding-scrollbar;\n border: 1px solid @table-border-color;\n\n // Tighten up spacing\n > .table {\n margin-bottom: 0;\n\n // Ensure the content doesn't wrap\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th,\n > td {\n white-space: nowrap;\n }\n }\n }\n }\n\n // Special overrides for the bordered tables\n > .table-bordered {\n border: 0;\n\n // Nuke the appropriate borders so that the parent can handle them\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n\n // Only nuke the last row's bottom-border in `tbody` and `tfoot` since\n // chances are there will be only one `tr` in a `thead` and that would\n // remove the border altogether.\n > tbody,\n > tfoot {\n > tr:last-child {\n > th,\n > td {\n border-bottom: 0;\n }\n }\n }\n\n }\n }\n}\n","// Tables\n\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &:hover > .@{state},\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n","//\n// Forms\n// --------------------------------------------------\n\n\n// Normalize non-controls\n//\n// Restyle and baseline non-control form elements.\n\nfieldset {\n padding: 0;\n margin: 0;\n border: 0;\n // Chrome and Firefox set a `min-width: min-content;` on fieldsets,\n // so we reset that to ensure it behaves more like a standard block element.\n // See https://github.com/twbs/bootstrap/issues/12359.\n min-width: 0;\n}\n\nlegend {\n display: block;\n width: 100%;\n padding: 0;\n margin-bottom: @line-height-computed;\n font-size: (@font-size-base * 1.5);\n line-height: inherit;\n color: @legend-color;\n border: 0;\n border-bottom: 1px solid @legend-border-color;\n}\n\nlabel {\n display: inline-block;\n max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)\n margin-bottom: 5px;\n font-weight: bold;\n}\n\n\n// Normalize form controls\n//\n// While most of our form styles require extra classes, some basic normalization\n// is required to ensure optimum display with or without those classes to better\n// address browser inconsistencies.\n\n// Override content-box in Normalize (* isn't specific enough)\ninput[type=\"search\"] {\n .box-sizing(border-box);\n}\n\n// Position radios and checkboxes better\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n margin: 4px 0 0;\n margin-top: 1px \\9; // IE8-9\n line-height: normal;\n}\n\ninput[type=\"file\"] {\n display: block;\n}\n\n// Make range inputs behave like textual form controls\ninput[type=\"range\"] {\n display: block;\n width: 100%;\n}\n\n// Make multiple select elements height not fixed\nselect[multiple],\nselect[size] {\n height: auto;\n}\n\n// Focus for file, radio, and checkbox\ninput[type=\"file\"]:focus,\ninput[type=\"radio\"]:focus,\ninput[type=\"checkbox\"]:focus {\n .tab-focus();\n}\n\n// Adjust output element\noutput {\n display: block;\n padding-top: (@padding-base-vertical + 1);\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n}\n\n\n// Common form controls\n//\n// Shared size and type resets for form controls. Apply `.form-control` to any\n// of the following form controls:\n//\n// select\n// textarea\n// input[type=\"text\"]\n// input[type=\"password\"]\n// input[type=\"datetime\"]\n// input[type=\"datetime-local\"]\n// input[type=\"date\"]\n// input[type=\"month\"]\n// input[type=\"time\"]\n// input[type=\"week\"]\n// input[type=\"number\"]\n// input[type=\"email\"]\n// input[type=\"url\"]\n// input[type=\"search\"]\n// input[type=\"tel\"]\n// input[type=\"color\"]\n\n.form-control {\n display: block;\n width: 100%;\n height: @input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n line-height: @line-height-base;\n color: @input-color;\n background-color: @input-bg;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid @input-border;\n border-radius: @input-border-radius; // Note: This has no effect on <select>s in some browsers, due to the limited stylability of <select>s in CSS.\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075));\n .transition(~\"border-color ease-in-out .15s, box-shadow ease-in-out .15s\");\n\n // Customize the `:focus` state to imitate native WebKit styles.\n .form-control-focus();\n\n // Placeholder\n .placeholder();\n\n // Disabled and read-only inputs\n //\n // HTML5 says that controls under a fieldset > legend:first-child won't be\n // disabled if the fieldset is disabled. Due to implementation difficulty, we\n // don't honor that edge case; we style them as disabled anyway.\n &[disabled],\n &[readonly],\n fieldset[disabled] & {\n background-color: @input-bg-disabled;\n opacity: 1; // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655\n }\n\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n\n // Reset height for `textarea`s\n textarea& {\n height: auto;\n }\n}\n\n\n// Search inputs in iOS\n//\n// This overrides the extra rounded corners on search inputs in iOS so that our\n// `.form-control` class can properly style them. Note that this cannot simply\n// be added to `.form-control` as it's not specific enough. For details, see\n// https://github.com/twbs/bootstrap/issues/11586.\n\ninput[type=\"search\"] {\n -webkit-appearance: none;\n}\n\n\n// Special styles for iOS temporal inputs\n//\n// In Mobile Safari, setting `display: block` on temporal inputs causes the\n// text within the input to become vertically misaligned. As a workaround, we\n// set a pixel line-height that matches the given height of the input, but only\n// for Safari. See https://bugs.webkit.org/show_bug.cgi?id=139848\n//\n// Note that as of 8.3, iOS doesn't support `datetime` or `week`.\n\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\n input[type=\"date\"],\n input[type=\"time\"],\n input[type=\"datetime-local\"],\n input[type=\"month\"] {\n &.form-control {\n line-height: @input-height-base;\n }\n\n &.input-sm,\n .input-group-sm & {\n line-height: @input-height-small;\n }\n\n &.input-lg,\n .input-group-lg & {\n line-height: @input-height-large;\n }\n }\n}\n\n\n// Form groups\n//\n// Designed to help with the organization and spacing of vertical forms. For\n// horizontal forms, use the predefined grid classes.\n\n.form-group {\n margin-bottom: @form-group-margin-bottom;\n}\n\n\n// Checkboxes and radios\n//\n// Indent the labels to position radios/checkboxes as hanging controls.\n\n.radio,\n.checkbox {\n position: relative;\n display: block;\n margin-top: 10px;\n margin-bottom: 10px;\n\n label {\n min-height: @line-height-computed; // Ensure the input doesn't jump when there is no text\n padding-left: 20px;\n margin-bottom: 0;\n font-weight: normal;\n cursor: pointer;\n }\n}\n.radio input[type=\"radio\"],\n.radio-inline input[type=\"radio\"],\n.checkbox input[type=\"checkbox\"],\n.checkbox-inline input[type=\"checkbox\"] {\n position: absolute;\n margin-left: -20px;\n margin-top: 4px \\9;\n}\n\n.radio + .radio,\n.checkbox + .checkbox {\n margin-top: -5px; // Move up sibling radios or checkboxes for tighter spacing\n}\n\n// Radios and checkboxes on same line\n.radio-inline,\n.checkbox-inline {\n position: relative;\n display: inline-block;\n padding-left: 20px;\n margin-bottom: 0;\n vertical-align: middle;\n font-weight: normal;\n cursor: pointer;\n}\n.radio-inline + .radio-inline,\n.checkbox-inline + .checkbox-inline {\n margin-top: 0;\n margin-left: 10px; // space out consecutive inline controls\n}\n\n// Apply same disabled cursor tweak as for inputs\n// Some special care is needed because <label>s don't inherit their parent's `cursor`.\n//\n// Note: Neither radios nor checkboxes can be readonly.\ninput[type=\"radio\"],\ninput[type=\"checkbox\"] {\n &[disabled],\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n// These classes are used directly on <label>s\n.radio-inline,\n.checkbox-inline {\n &.disabled,\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n }\n}\n// These classes are used on elements with <label> descendants\n.radio,\n.checkbox {\n &.disabled,\n fieldset[disabled] & {\n label {\n cursor: @cursor-disabled;\n }\n }\n}\n\n\n// Static form control text\n//\n// Apply class to a `p` element to make any string of text align with labels in\n// a horizontal form layout.\n\n.form-control-static {\n // Size it appropriately next to real form controls\n padding-top: (@padding-base-vertical + 1);\n padding-bottom: (@padding-base-vertical + 1);\n // Remove default margin from `p`\n margin-bottom: 0;\n min-height: (@line-height-computed + @font-size-base);\n\n &.input-lg,\n &.input-sm {\n padding-left: 0;\n padding-right: 0;\n }\n}\n\n\n// Form control sizing\n//\n// Build on `.form-control` with modifier classes to decrease or increase the\n// height and font-size of form controls.\n//\n// The `.form-group-* form-control` variations are sadly duplicated to avoid the\n// issue documented in https://github.com/twbs/bootstrap/issues/15074.\n\n.input-sm {\n .input-size(@input-height-small; @padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @input-border-radius-small);\n}\n.form-group-sm {\n .form-control {\n height: @input-height-small;\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n line-height: @line-height-small;\n border-radius: @input-border-radius-small;\n }\n select.form-control {\n height: @input-height-small;\n line-height: @input-height-small;\n }\n textarea.form-control,\n select[multiple].form-control {\n height: auto;\n }\n .form-control-static {\n height: @input-height-small;\n min-height: (@line-height-computed + @font-size-small);\n padding: (@padding-small-vertical + 1) @padding-small-horizontal;\n font-size: @font-size-small;\n line-height: @line-height-small;\n }\n}\n\n.input-lg {\n .input-size(@input-height-large; @padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @input-border-radius-large);\n}\n.form-group-lg {\n .form-control {\n height: @input-height-large;\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-large;\n border-radius: @input-border-radius-large;\n }\n select.form-control {\n height: @input-height-large;\n line-height: @input-height-large;\n }\n textarea.form-control,\n select[multiple].form-control {\n height: auto;\n }\n .form-control-static {\n height: @input-height-large;\n min-height: (@line-height-computed + @font-size-large);\n padding: (@padding-large-vertical + 1) @padding-large-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-large;\n }\n}\n\n\n// Form control feedback states\n//\n// Apply contextual and semantic states to individual form controls.\n\n.has-feedback {\n // Enable absolute positioning\n position: relative;\n\n // Ensure icons don't overlap text\n .form-control {\n padding-right: (@input-height-base * 1.25);\n }\n}\n// Feedback icon (requires .glyphicon classes)\n.form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2; // Ensure icon is above input groups\n display: block;\n width: @input-height-base;\n height: @input-height-base;\n line-height: @input-height-base;\n text-align: center;\n pointer-events: none;\n}\n.input-lg + .form-control-feedback,\n.input-group-lg + .form-control-feedback,\n.form-group-lg .form-control + .form-control-feedback {\n width: @input-height-large;\n height: @input-height-large;\n line-height: @input-height-large;\n}\n.input-sm + .form-control-feedback,\n.input-group-sm + .form-control-feedback,\n.form-group-sm .form-control + .form-control-feedback {\n width: @input-height-small;\n height: @input-height-small;\n line-height: @input-height-small;\n}\n\n// Feedback states\n.has-success {\n .form-control-validation(@state-success-text; @state-success-text; @state-success-bg);\n}\n.has-warning {\n .form-control-validation(@state-warning-text; @state-warning-text; @state-warning-bg);\n}\n.has-error {\n .form-control-validation(@state-danger-text; @state-danger-text; @state-danger-bg);\n}\n\n// Reposition feedback icon if input has visible label above\n.has-feedback label {\n\n & ~ .form-control-feedback {\n top: (@line-height-computed + 5); // Height of the `label` and its margin\n }\n &.sr-only ~ .form-control-feedback {\n top: 0;\n }\n}\n\n\n// Help text\n//\n// Apply to any element you wish to create light text for placement immediately\n// below a form control. Use for general help, formatting, or instructional text.\n\n.help-block {\n display: block; // account for any element using help-block\n margin-top: 5px;\n margin-bottom: 10px;\n color: lighten(@text-color, 25%); // lighten the text some for contrast\n}\n\n\n// Inline forms\n//\n// Make forms appear inline(-block) by adding the `.form-inline` class. Inline\n// forms begin stacked on extra small (mobile) devices and then go inline when\n// viewports reach <768px.\n//\n// Requires wrapping inputs and labels with `.form-group` for proper display of\n// default HTML form controls and our custom form controls (e.g., input groups).\n//\n// Heads up! This is mixin-ed into `.navbar-form` in navbars.less.\n\n.form-inline {\n\n // Kick in the inline\n @media (min-width: @screen-sm-min) {\n // Inline-block all the things for \"inline\"\n .form-group {\n display: inline-block;\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // In navbar-form, allow folks to *not* use `.form-group`\n .form-control {\n display: inline-block;\n width: auto; // Prevent labels from stacking above inputs in `.form-group`\n vertical-align: middle;\n }\n\n // Make static controls behave like regular ones\n .form-control-static {\n display: inline-block;\n }\n\n .input-group {\n display: inline-table;\n vertical-align: middle;\n\n .input-group-addon,\n .input-group-btn,\n .form-control {\n width: auto;\n }\n }\n\n // Input groups need that 100% width though\n .input-group > .form-control {\n width: 100%;\n }\n\n .control-label {\n margin-bottom: 0;\n vertical-align: middle;\n }\n\n // Remove default margin on radios/checkboxes that were used for stacking, and\n // then undo the floating of radios and checkboxes to match.\n .radio,\n .checkbox {\n display: inline-block;\n margin-top: 0;\n margin-bottom: 0;\n vertical-align: middle;\n\n label {\n padding-left: 0;\n }\n }\n .radio input[type=\"radio\"],\n .checkbox input[type=\"checkbox\"] {\n position: relative;\n margin-left: 0;\n }\n\n // Re-override the feedback icon.\n .has-feedback .form-control-feedback {\n top: 0;\n }\n }\n}\n\n\n// Horizontal forms\n//\n// Horizontal forms are built on grid classes and allow you to create forms with\n// labels on the left and inputs on the right.\n\n.form-horizontal {\n\n // Consistent vertical alignment of radios and checkboxes\n //\n // Labels also get some reset styles, but that is scoped to a media query below.\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n margin-top: 0;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n // Account for padding we're adding to ensure the alignment and of help text\n // and other content below items\n .radio,\n .checkbox {\n min-height: (@line-height-computed + (@padding-base-vertical + 1));\n }\n\n // Make form groups behave like rows\n .form-group {\n .make-row();\n }\n\n // Reset spacing and right align labels, but scope to media queries so that\n // labels on narrow viewports stack the same as a default form example.\n @media (min-width: @screen-sm-min) {\n .control-label {\n text-align: right;\n margin-bottom: 0;\n padding-top: (@padding-base-vertical + 1); // Default padding plus a border\n }\n }\n\n // Validation states\n //\n // Reposition the icon because it's now within a grid column and columns have\n // `position: relative;` on them. Also accounts for the grid gutter padding.\n .has-feedback .form-control-feedback {\n right: floor((@grid-gutter-width / 2));\n }\n\n // Form group sizes\n //\n // Quick utility class for applying `.input-lg` and `.input-sm` styles to the\n // inputs and labels within a `.form-group`.\n .form-group-lg {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: ((@padding-large-vertical * @line-height-large) + 1);\n font-size: @font-size-large;\n }\n }\n }\n .form-group-sm {\n @media (min-width: @screen-sm-min) {\n .control-label {\n padding-top: (@padding-small-vertical + 1);\n font-size: @font-size-small;\n }\n }\n }\n}\n","// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline,\n &.radio label,\n &.checkbox label,\n &.radio-inline label,\n &.checkbox-inline label {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-border-focus` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `<select>`\n// element gets special love because it's special, and that's a fact!\n.input-size(@input-height; @padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n height: @input-height;\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n\n select& {\n height: @input-height;\n line-height: @input-height;\n }\n\n textarea&,\n select[multiple]& {\n height: auto;\n }\n}\n","//\n// Buttons\n// --------------------------------------------------\n\n\n// Base styles\n// --------------------------------------------------\n\n.btn {\n display: inline-block;\n margin-bottom: 0; // For input.btn\n font-weight: @btn-font-weight;\n text-align: center;\n vertical-align: middle;\n touch-action: manipulation;\n cursor: pointer;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n white-space: nowrap;\n .button-size(@padding-base-vertical; @padding-base-horizontal; @font-size-base; @line-height-base; @btn-border-radius-base);\n .user-select(none);\n\n &,\n &:active,\n &.active {\n &:focus,\n &.focus {\n .tab-focus();\n }\n }\n\n &:hover,\n &:focus,\n &.focus {\n color: @btn-default-color;\n text-decoration: none;\n }\n\n &:active,\n &.active {\n outline: 0;\n background-image: none;\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n cursor: @cursor-disabled;\n .opacity(.65);\n .box-shadow(none);\n }\n\n a& {\n &.disabled,\n fieldset[disabled] & {\n pointer-events: none; // Future-proof disabling of clicks on `<a>` elements\n }\n }\n}\n\n\n// Alternate buttons\n// --------------------------------------------------\n\n.btn-default {\n .button-variant(@btn-default-color; @btn-default-bg; @btn-default-border);\n}\n.btn-primary {\n .button-variant(@btn-primary-color; @btn-primary-bg; @btn-primary-border);\n}\n// Success appears as green\n.btn-success {\n .button-variant(@btn-success-color; @btn-success-bg; @btn-success-border);\n}\n// Info appears as blue-green\n.btn-info {\n .button-variant(@btn-info-color; @btn-info-bg; @btn-info-border);\n}\n// Warning appears as orange\n.btn-warning {\n .button-variant(@btn-warning-color; @btn-warning-bg; @btn-warning-border);\n}\n// Danger and error appear as red\n.btn-danger {\n .button-variant(@btn-danger-color; @btn-danger-bg; @btn-danger-border);\n}\n\n\n// Link buttons\n// -------------------------\n\n// Make a button look and behave like a link\n.btn-link {\n color: @link-color;\n font-weight: normal;\n border-radius: 0;\n\n &,\n &:active,\n &.active,\n &[disabled],\n fieldset[disabled] & {\n background-color: transparent;\n .box-shadow(none);\n }\n &,\n &:hover,\n &:focus,\n &:active {\n border-color: transparent;\n }\n &:hover,\n &:focus {\n color: @link-hover-color;\n text-decoration: @link-hover-decoration;\n background-color: transparent;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @btn-link-disabled-color;\n text-decoration: none;\n }\n }\n}\n\n\n// Button Sizes\n// --------------------------------------------------\n\n.btn-lg {\n // line-height: ensure even-numbered height of button next to large input\n .button-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @btn-border-radius-large);\n}\n.btn-sm {\n // line-height: ensure proper height of button next to small input\n .button-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n.btn-xs {\n .button-size(@padding-xs-vertical; @padding-xs-horizontal; @font-size-small; @line-height-small; @btn-border-radius-small);\n}\n\n\n// Block button\n// --------------------------------------------------\n\n.btn-block {\n display: block;\n width: 100%;\n}\n\n// Vertically space out multiple block buttons\n.btn-block + .btn-block {\n margin-top: 5px;\n}\n\n// Specificity overrides\ninput[type=\"submit\"],\ninput[type=\"reset\"],\ninput[type=\"button\"] {\n &.btn-block {\n width: 100%;\n }\n}\n","// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 25%);\n }\n &:hover {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 10%);\n border-color: darken(@border, 12%);\n\n &:hover,\n &:focus,\n &.focus {\n color: @color;\n background-color: darken(@background, 17%);\n border-color: darken(@border, 25%);\n }\n }\n &:active,\n &.active,\n .open > .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n","// Opacity\n\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n","//\n// Component animations\n// --------------------------------------------------\n\n// Heads up!\n//\n// We don't use the `.opacity()` mixin here since it causes a bug with text\n// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.\n\n.fade {\n opacity: 0;\n .transition(opacity .15s linear);\n &.in {\n opacity: 1;\n }\n}\n\n.collapse {\n display: none;\n\n &.in { display: block; }\n tr&.in { display: table-row; }\n tbody&.in { display: table-row-group; }\n}\n\n.collapsing {\n position: relative;\n height: 0;\n overflow: hidden;\n .transition-property(~\"height, visibility\");\n .transition-duration(.35s);\n .transition-timing-function(ease);\n}\n","//\n// Dropdown menus\n// --------------------------------------------------\n\n\n// Dropdown arrow/caret\n.caret {\n display: inline-block;\n width: 0;\n height: 0;\n margin-left: 2px;\n vertical-align: middle;\n border-top: @caret-width-base dashed;\n border-top: @caret-width-base solid ~\"\\9\"; // IE8\n border-right: @caret-width-base solid transparent;\n border-left: @caret-width-base solid transparent;\n}\n\n// The dropdown wrapper (div)\n.dropup,\n.dropdown {\n position: relative;\n}\n\n// Prevent the focus on the dropdown toggle when closing dropdowns\n.dropdown-toggle:focus {\n outline: 0;\n}\n\n// The dropdown menu (ul)\n.dropdown-menu {\n position: absolute;\n top: 100%;\n left: 0;\n z-index: @zindex-dropdown;\n display: none; // none by default, but block on \"open\" of the menu\n float: left;\n min-width: 160px;\n padding: 5px 0;\n margin: 2px 0 0; // override default ul\n list-style: none;\n font-size: @font-size-base;\n text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)\n background-color: @dropdown-bg;\n border: 1px solid @dropdown-fallback-border; // IE8 fallback\n border: 1px solid @dropdown-border;\n border-radius: @border-radius-base;\n .box-shadow(0 6px 12px rgba(0,0,0,.175));\n background-clip: padding-box;\n\n // Aligns the dropdown menu to right\n //\n // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`\n &.pull-right {\n right: 0;\n left: auto;\n }\n\n // Dividers (basically an hr) within the dropdown\n .divider {\n .nav-divider(@dropdown-divider-bg);\n }\n\n // Links within the dropdown menu\n > li > a {\n display: block;\n padding: 3px 20px;\n clear: both;\n font-weight: normal;\n line-height: @line-height-base;\n color: @dropdown-link-color;\n white-space: nowrap; // prevent links from randomly breaking onto new lines\n }\n}\n\n// Hover/Focus state\n.dropdown-menu > li > a {\n &:hover,\n &:focus {\n text-decoration: none;\n color: @dropdown-link-hover-color;\n background-color: @dropdown-link-hover-bg;\n }\n}\n\n// Active state\n.dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-active-color;\n text-decoration: none;\n outline: 0;\n background-color: @dropdown-link-active-bg;\n }\n}\n\n// Disabled state\n//\n// Gray out text and ensure the hover/focus state remains gray\n\n.dropdown-menu > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @dropdown-link-disabled-color;\n }\n\n // Nuke hover/focus effects\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: transparent;\n background-image: none; // Remove CSS gradient\n .reset-filter();\n cursor: @cursor-disabled;\n }\n}\n\n// Open state for the dropdown\n.open {\n // Show the menu\n > .dropdown-menu {\n display: block;\n }\n\n // Remove the outline when :focus is triggered\n > a {\n outline: 0;\n }\n}\n\n// Menu positioning\n//\n// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown\n// menu with the parent.\n.dropdown-menu-right {\n left: auto; // Reset the default from `.dropdown-menu`\n right: 0;\n}\n// With v3, we enabled auto-flipping if you have a dropdown within a right\n// aligned nav component. To enable the undoing of that, we provide an override\n// to restore the default dropdown menu alignment.\n//\n// This is only for left-aligning a dropdown menu within a `.navbar-right` or\n// `.pull-right` nav component.\n.dropdown-menu-left {\n left: 0;\n right: auto;\n}\n\n// Dropdown section headers\n.dropdown-header {\n display: block;\n padding: 3px 20px;\n font-size: @font-size-small;\n line-height: @line-height-base;\n color: @dropdown-header-color;\n white-space: nowrap; // as with > li > a\n}\n\n// Backdrop to catch body clicks on mobile, etc.\n.dropdown-backdrop {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n top: 0;\n z-index: (@zindex-dropdown - 10);\n}\n\n// Right aligned dropdowns\n.pull-right > .dropdown-menu {\n right: 0;\n left: auto;\n}\n\n// Allow for dropdowns to go bottom up (aka, dropup-menu)\n//\n// Just add .dropup after the standard .dropdown class and you're set, bro.\n// TODO: abstract this so that the navbar fixed styles are not placed here?\n\n.dropup,\n.navbar-fixed-bottom .dropdown {\n // Reverse the caret\n .caret {\n border-top: 0;\n border-bottom: @caret-width-base dashed;\n border-bottom: @caret-width-base solid ~\"\\9\"; // IE8\n content: \"\";\n }\n // Different positioning for bottom up menu\n .dropdown-menu {\n top: auto;\n bottom: 100%;\n margin-bottom: 2px;\n }\n}\n\n\n// Component alignment\n//\n// Reiterate per navbar.less and the modified component alignment there.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-right {\n .dropdown-menu {\n .dropdown-menu-right();\n }\n // Necessary for overrides of the default right aligned menu.\n // Will remove come v4 in all likelihood.\n .dropdown-menu-left {\n .dropdown-menu-left();\n }\n }\n}\n","// Horizontal dividers\n//\n// Dividers (basically an hr) within dropdowns and nav lists\n\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n","//\n// Button groups\n// --------------------------------------------------\n\n// Make the div behave like a button\n.btn-group,\n.btn-group-vertical {\n position: relative;\n display: inline-block;\n vertical-align: middle; // match .btn alignment given font-size hack above\n > .btn {\n position: relative;\n float: left;\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active,\n &.active {\n z-index: 2;\n }\n }\n}\n\n// Prevent double borders when buttons are next to each other\n.btn-group {\n .btn + .btn,\n .btn + .btn-group,\n .btn-group + .btn,\n .btn-group + .btn-group {\n margin-left: -1px;\n }\n}\n\n// Optional: Group multiple button groups together for a toolbar\n.btn-toolbar {\n margin-left: -5px; // Offset the first child's margin\n &:extend(.clearfix all);\n\n .btn,\n .btn-group,\n .input-group {\n float: left;\n }\n > .btn,\n > .btn-group,\n > .input-group {\n margin-left: 5px;\n }\n}\n\n.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {\n border-radius: 0;\n}\n\n// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match\n.btn-group > .btn:first-child {\n margin-left: 0;\n &:not(:last-child):not(.dropdown-toggle) {\n .border-right-radius(0);\n }\n}\n// Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it\n.btn-group > .btn:last-child:not(:first-child),\n.btn-group > .dropdown-toggle:not(:first-child) {\n .border-left-radius(0);\n}\n\n// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)\n.btn-group > .btn-group {\n float: left;\n}\n.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-right-radius(0);\n }\n}\n.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-left-radius(0);\n}\n\n// On active and open, don't show outline\n.btn-group .dropdown-toggle:active,\n.btn-group.open .dropdown-toggle {\n outline: 0;\n}\n\n\n// Sizing\n//\n// Remix the default button sizing classes into new ones for easier manipulation.\n\n.btn-group-xs > .btn { &:extend(.btn-xs); }\n.btn-group-sm > .btn { &:extend(.btn-sm); }\n.btn-group-lg > .btn { &:extend(.btn-lg); }\n\n\n// Split button dropdowns\n// ----------------------\n\n// Give the line between buttons some depth\n.btn-group > .btn + .dropdown-toggle {\n padding-left: 8px;\n padding-right: 8px;\n}\n.btn-group > .btn-lg + .dropdown-toggle {\n padding-left: 12px;\n padding-right: 12px;\n}\n\n// The clickable button for toggling the menu\n// Remove the gradient and set the same inset shadow as the :active state\n.btn-group.open .dropdown-toggle {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n\n // Show no shadow for `.btn-link` since it has no other button styles.\n &.btn-link {\n .box-shadow(none);\n }\n}\n\n\n// Reposition the caret\n.btn .caret {\n margin-left: 0;\n}\n// Carets in other button sizes\n.btn-lg .caret {\n border-width: @caret-width-large @caret-width-large 0;\n border-bottom-width: 0;\n}\n// Upside down carets for .dropup\n.dropup .btn-lg .caret {\n border-width: 0 @caret-width-large @caret-width-large;\n}\n\n\n// Vertical button groups\n// ----------------------\n\n.btn-group-vertical {\n > .btn,\n > .btn-group,\n > .btn-group > .btn {\n display: block;\n float: none;\n width: 100%;\n max-width: 100%;\n }\n\n // Clear floats so dropdown menus can be properly placed\n > .btn-group {\n &:extend(.clearfix all);\n > .btn {\n float: none;\n }\n }\n\n > .btn + .btn,\n > .btn + .btn-group,\n > .btn-group + .btn,\n > .btn-group + .btn-group {\n margin-top: -1px;\n margin-left: 0;\n }\n}\n\n.btn-group-vertical > .btn {\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n &:first-child:not(:last-child) {\n border-top-right-radius: @btn-border-radius-base;\n .border-bottom-radius(0);\n }\n &:last-child:not(:first-child) {\n border-bottom-left-radius: @btn-border-radius-base;\n .border-top-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {\n border-radius: 0;\n}\n.btn-group-vertical > .btn-group:first-child:not(:last-child) {\n > .btn:last-child,\n > .dropdown-toggle {\n .border-bottom-radius(0);\n }\n}\n.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {\n .border-top-radius(0);\n}\n\n\n// Justified button groups\n// ----------------------\n\n.btn-group-justified {\n display: table;\n width: 100%;\n table-layout: fixed;\n border-collapse: separate;\n > .btn,\n > .btn-group {\n float: none;\n display: table-cell;\n width: 1%;\n }\n > .btn-group .btn {\n width: 100%;\n }\n\n > .btn-group .dropdown-menu {\n left: auto;\n }\n}\n\n\n// Checkbox and radio options\n//\n// In order to support the browser's form validation feedback, powered by the\n// `required` attribute, we have to \"hide\" the inputs via `clip`. We cannot use\n// `display: none;` or `visibility: hidden;` as that also hides the popover.\n// Simply visually hiding the inputs via `opacity` would leave them clickable in\n// certain cases which is prevented by using `clip` and `pointer-events`.\n// This way, we ensure a DOM element is visible to position the popover from.\n//\n// See https://github.com/twbs/bootstrap/pull/12794 and\n// https://github.com/twbs/bootstrap/pull/14559 for more information.\n\n[data-toggle=\"buttons\"] {\n > .btn,\n > .btn-group > .btn {\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n position: absolute;\n clip: rect(0,0,0,0);\n pointer-events: none;\n }\n }\n}\n","// Single side border-radius\n\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n","//\n// Input groups\n// --------------------------------------------------\n\n// Base styles\n// -------------------------\n.input-group {\n position: relative; // For dropdowns\n display: table;\n border-collapse: separate; // prevent input groups from inheriting border styles from table cells when placed within a table\n\n // Undo padding and float of grid classes\n &[class*=\"col-\"] {\n float: none;\n padding-left: 0;\n padding-right: 0;\n }\n\n .form-control {\n // Ensure that the input is always above the *appended* addon button for\n // proper border colors.\n position: relative;\n z-index: 2;\n\n // IE9 fubars the placeholder attribute in text inputs and the arrows on\n // select elements in input groups. To fix it, we float the input. Details:\n // https://github.com/twbs/bootstrap/issues/11561#issuecomment-28936855\n float: left;\n\n width: 100%;\n margin-bottom: 0;\n }\n}\n\n// Sizing options\n//\n// Remix the default form control sizing classes into new ones for easier\n// manipulation.\n\n.input-group-lg > .form-control,\n.input-group-lg > .input-group-addon,\n.input-group-lg > .input-group-btn > .btn {\n .input-lg();\n}\n.input-group-sm > .form-control,\n.input-group-sm > .input-group-addon,\n.input-group-sm > .input-group-btn > .btn {\n .input-sm();\n}\n\n\n// Display as table-cell\n// -------------------------\n.input-group-addon,\n.input-group-btn,\n.input-group .form-control {\n display: table-cell;\n\n &:not(:first-child):not(:last-child) {\n border-radius: 0;\n }\n}\n// Addon and addon wrapper for buttons\n.input-group-addon,\n.input-group-btn {\n width: 1%;\n white-space: nowrap;\n vertical-align: middle; // Match the inputs\n}\n\n// Text input groups\n// -------------------------\n.input-group-addon {\n padding: @padding-base-vertical @padding-base-horizontal;\n font-size: @font-size-base;\n font-weight: normal;\n line-height: 1;\n color: @input-color;\n text-align: center;\n background-color: @input-group-addon-bg;\n border: 1px solid @input-group-addon-border-color;\n border-radius: @border-radius-base;\n\n // Sizing\n &.input-sm {\n padding: @padding-small-vertical @padding-small-horizontal;\n font-size: @font-size-small;\n border-radius: @border-radius-small;\n }\n &.input-lg {\n padding: @padding-large-vertical @padding-large-horizontal;\n font-size: @font-size-large;\n border-radius: @border-radius-large;\n }\n\n // Nuke default margins from checkboxes and radios to vertically center within.\n input[type=\"radio\"],\n input[type=\"checkbox\"] {\n margin-top: 0;\n }\n}\n\n// Reset rounded corners\n.input-group .form-control:first-child,\n.input-group-addon:first-child,\n.input-group-btn:first-child > .btn,\n.input-group-btn:first-child > .btn-group > .btn,\n.input-group-btn:first-child > .dropdown-toggle,\n.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle),\n.input-group-btn:last-child > .btn-group:not(:last-child) > .btn {\n .border-right-radius(0);\n}\n.input-group-addon:first-child {\n border-right: 0;\n}\n.input-group .form-control:last-child,\n.input-group-addon:last-child,\n.input-group-btn:last-child > .btn,\n.input-group-btn:last-child > .btn-group > .btn,\n.input-group-btn:last-child > .dropdown-toggle,\n.input-group-btn:first-child > .btn:not(:first-child),\n.input-group-btn:first-child > .btn-group:not(:first-child) > .btn {\n .border-left-radius(0);\n}\n.input-group-addon:last-child {\n border-left: 0;\n}\n\n// Button input groups\n// -------------------------\n.input-group-btn {\n position: relative;\n // Jankily prevent input button groups from wrapping with `white-space` and\n // `font-size` in combination with `inline-block` on buttons.\n font-size: 0;\n white-space: nowrap;\n\n // Negative margin for spacing, position for bringing hovered/focused/actived\n // element above the siblings.\n > .btn {\n position: relative;\n + .btn {\n margin-left: -1px;\n }\n // Bring the \"active\" button to the front\n &:hover,\n &:focus,\n &:active {\n z-index: 2;\n }\n }\n\n // Negative margin to only have a 1px border between the two\n &:first-child {\n > .btn,\n > .btn-group {\n margin-right: -1px;\n }\n }\n &:last-child {\n > .btn,\n > .btn-group {\n z-index: 2;\n margin-left: -1px;\n }\n }\n}\n","//\n// Navs\n// --------------------------------------------------\n\n\n// Base class\n// --------------------------------------------------\n\n.nav {\n margin-bottom: 0;\n padding-left: 0; // Override default ul/ol\n list-style: none;\n &:extend(.clearfix all);\n\n > li {\n position: relative;\n display: block;\n\n > a {\n position: relative;\n display: block;\n padding: @nav-link-padding;\n &:hover,\n &:focus {\n text-decoration: none;\n background-color: @nav-link-hover-bg;\n }\n }\n\n // Disabled state sets text to gray and nukes hover/tab effects\n &.disabled > a {\n color: @nav-disabled-link-color;\n\n &:hover,\n &:focus {\n color: @nav-disabled-link-hover-color;\n text-decoration: none;\n background-color: transparent;\n cursor: @cursor-disabled;\n }\n }\n }\n\n // Open dropdowns\n .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @nav-link-hover-bg;\n border-color: @link-color;\n }\n }\n\n // Nav dividers (deprecated with v3.0.1)\n //\n // This should have been removed in v3 with the dropping of `.nav-list`, but\n // we missed it. We don't currently support this anywhere, but in the interest\n // of maintaining backward compatibility in case you use it, it's deprecated.\n .nav-divider {\n .nav-divider();\n }\n\n // Prevent IE8 from misplacing imgs\n //\n // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989\n > li > a > img {\n max-width: none;\n }\n}\n\n\n// Tabs\n// -------------------------\n\n// Give the tabs something to sit on\n.nav-tabs {\n border-bottom: 1px solid @nav-tabs-border-color;\n > li {\n float: left;\n // Make the list-items overlay the bottom border\n margin-bottom: -1px;\n\n // Actual tabs (as links)\n > a {\n margin-right: 2px;\n line-height: @line-height-base;\n border: 1px solid transparent;\n border-radius: @border-radius-base @border-radius-base 0 0;\n &:hover {\n border-color: @nav-tabs-link-hover-border-color @nav-tabs-link-hover-border-color @nav-tabs-border-color;\n }\n }\n\n // Active state, and its :hover to override normal :hover\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-tabs-active-link-hover-color;\n background-color: @nav-tabs-active-link-hover-bg;\n border: 1px solid @nav-tabs-active-link-hover-border-color;\n border-bottom-color: transparent;\n cursor: default;\n }\n }\n }\n // pulling this in mainly for less shorthand\n &.nav-justified {\n .nav-justified();\n .nav-tabs-justified();\n }\n}\n\n\n// Pills\n// -------------------------\n.nav-pills {\n > li {\n float: left;\n\n // Links rendered as pills\n > a {\n border-radius: @nav-pills-border-radius;\n }\n + li {\n margin-left: 2px;\n }\n\n // Active state\n &.active > a {\n &,\n &:hover,\n &:focus {\n color: @nav-pills-active-link-hover-color;\n background-color: @nav-pills-active-link-hover-bg;\n }\n }\n }\n}\n\n\n// Stacked pills\n.nav-stacked {\n > li {\n float: none;\n + li {\n margin-top: 2px;\n margin-left: 0; // no need for this gap between nav items\n }\n }\n}\n\n\n// Nav variations\n// --------------------------------------------------\n\n// Justified nav links\n// -------------------------\n\n.nav-justified {\n width: 100%;\n\n > li {\n float: none;\n > a {\n text-align: center;\n margin-bottom: 5px;\n }\n }\n\n > .dropdown .dropdown-menu {\n top: auto;\n left: auto;\n }\n\n @media (min-width: @screen-sm-min) {\n > li {\n display: table-cell;\n width: 1%;\n > a {\n margin-bottom: 0;\n }\n }\n }\n}\n\n// Move borders to anchors instead of bottom of list\n//\n// Mixin for adding on top the shared `.nav-justified` styles for our tabs\n.nav-tabs-justified {\n border-bottom: 0;\n\n > li > a {\n // Override margin from .nav-tabs\n margin-right: 0;\n border-radius: @border-radius-base;\n }\n\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border: 1px solid @nav-tabs-justified-link-border-color;\n }\n\n @media (min-width: @screen-sm-min) {\n > li > a {\n border-bottom: 1px solid @nav-tabs-justified-link-border-color;\n border-radius: @border-radius-base @border-radius-base 0 0;\n }\n > .active > a,\n > .active > a:hover,\n > .active > a:focus {\n border-bottom-color: @nav-tabs-justified-active-link-border-color;\n }\n }\n}\n\n\n// Tabbable tabs\n// -------------------------\n\n// Hide tabbable panes to start, show them when `.active`\n.tab-content {\n > .tab-pane {\n display: none;\n }\n > .active {\n display: block;\n }\n}\n\n\n// Dropdowns\n// -------------------------\n\n// Specific dropdowns\n.nav-tabs .dropdown-menu {\n // make dropdown border overlap tab border\n margin-top: -1px;\n // Remove the top rounded corners here since there is a hard edge above the menu\n .border-top-radius(0);\n}\n","//\n// Navbars\n// --------------------------------------------------\n\n\n// Wrapper and base class\n//\n// Provide a static navbar from which we expand to create full-width, fixed, and\n// other navbar variations.\n\n.navbar {\n position: relative;\n min-height: @navbar-height; // Ensure a navbar always shows (e.g., without a .navbar-brand in collapsed mode)\n margin-bottom: @navbar-margin-bottom;\n border: 1px solid transparent;\n\n // Prevent floats from breaking the navbar\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: @navbar-border-radius;\n }\n}\n\n\n// Navbar heading\n//\n// Groups `.navbar-brand` and `.navbar-toggle` into a single component for easy\n// styling of responsive aspects.\n\n.navbar-header {\n &:extend(.clearfix all);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n }\n}\n\n\n// Navbar collapse (body)\n//\n// Group your navbar content into this for easy collapsing and expanding across\n// various device sizes. By default, this content is collapsed when <768px, but\n// will expand past that for a horizontal display.\n//\n// To start (on mobile devices) the navbar links, forms, and buttons are stacked\n// vertically and include a `max-height` to overflow in case you have too much\n// content for the user's viewport.\n\n.navbar-collapse {\n overflow-x: visible;\n padding-right: @navbar-padding-horizontal;\n padding-left: @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n box-shadow: inset 0 1px 0 rgba(255,255,255,.1);\n &:extend(.clearfix all);\n -webkit-overflow-scrolling: touch;\n\n &.in {\n overflow-y: auto;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border-top: 0;\n box-shadow: none;\n\n &.collapse {\n display: block !important;\n height: auto !important;\n padding-bottom: 0; // Override default setting\n overflow: visible !important;\n }\n\n &.in {\n overflow-y: visible;\n }\n\n // Undo the collapse side padding for navbars with containers to ensure\n // alignment of right-aligned contents.\n .navbar-fixed-top &,\n .navbar-static-top &,\n .navbar-fixed-bottom & {\n padding-left: 0;\n padding-right: 0;\n }\n }\n}\n\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n .navbar-collapse {\n max-height: @navbar-collapse-max-height;\n\n @media (max-device-width: @screen-xs-min) and (orientation: landscape) {\n max-height: 200px;\n }\n }\n}\n\n\n// Both navbar header and collapse\n//\n// When a container is present, change the behavior of the header and collapse.\n\n.container,\n.container-fluid {\n > .navbar-header,\n > .navbar-collapse {\n margin-right: -@navbar-padding-horizontal;\n margin-left: -@navbar-padding-horizontal;\n\n @media (min-width: @grid-float-breakpoint) {\n margin-right: 0;\n margin-left: 0;\n }\n }\n}\n\n\n//\n// Navbar alignment options\n//\n// Display the navbar across the entirety of the page or fixed it to the top or\n// bottom of the page.\n\n// Static top (unfixed, but 100% wide) navbar\n.navbar-static-top {\n z-index: @zindex-navbar;\n border-width: 0 0 1px;\n\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n\n// Fix the top/bottom navbars when screen real estate supports it\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n position: fixed;\n right: 0;\n left: 0;\n z-index: @zindex-navbar-fixed;\n\n // Undo the rounded corners\n @media (min-width: @grid-float-breakpoint) {\n border-radius: 0;\n }\n}\n.navbar-fixed-top {\n top: 0;\n border-width: 0 0 1px;\n}\n.navbar-fixed-bottom {\n bottom: 0;\n margin-bottom: 0; // override .navbar defaults\n border-width: 1px 0 0;\n}\n\n\n// Brand/project name\n\n.navbar-brand {\n float: left;\n padding: @navbar-padding-vertical @navbar-padding-horizontal;\n font-size: @font-size-large;\n line-height: @line-height-computed;\n height: @navbar-height;\n\n &:hover,\n &:focus {\n text-decoration: none;\n }\n\n > img {\n display: block;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n .navbar > .container &,\n .navbar > .container-fluid & {\n margin-left: -@navbar-padding-horizontal;\n }\n }\n}\n\n\n// Navbar toggle\n//\n// Custom button for toggling the `.navbar-collapse`, powered by the collapse\n// JavaScript plugin.\n\n.navbar-toggle {\n position: relative;\n float: right;\n margin-right: @navbar-padding-horizontal;\n padding: 9px 10px;\n .navbar-vertical-align(34px);\n background-color: transparent;\n background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214\n border: 1px solid transparent;\n border-radius: @border-radius-base;\n\n // We remove the `outline` here, but later compensate by attaching `:hover`\n // styles to `:focus`.\n &:focus {\n outline: 0;\n }\n\n // Bars\n .icon-bar {\n display: block;\n width: 22px;\n height: 2px;\n border-radius: 1px;\n }\n .icon-bar + .icon-bar {\n margin-top: 4px;\n }\n\n @media (min-width: @grid-float-breakpoint) {\n display: none;\n }\n}\n\n\n// Navbar nav links\n//\n// Builds on top of the `.nav` components with its own modifier class to make\n// the nav the full height of the horizontal nav (above 768px).\n\n.navbar-nav {\n margin: (@navbar-padding-vertical / 2) -@navbar-padding-horizontal;\n\n > li > a {\n padding-top: 10px;\n padding-bottom: 10px;\n line-height: @line-height-computed;\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n position: static;\n float: none;\n width: auto;\n margin-top: 0;\n background-color: transparent;\n border: 0;\n box-shadow: none;\n > li > a,\n .dropdown-header {\n padding: 5px 15px 5px 25px;\n }\n > li > a {\n line-height: @line-height-computed;\n &:hover,\n &:focus {\n background-image: none;\n }\n }\n }\n }\n\n // Uncollapse the nav\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin: 0;\n\n > li {\n float: left;\n > a {\n padding-top: @navbar-padding-vertical;\n padding-bottom: @navbar-padding-vertical;\n }\n }\n }\n}\n\n\n// Navbar form\n//\n// Extension of the `.form-inline` with some extra flavor for optimum display in\n// our navbars.\n\n.navbar-form {\n margin-left: -@navbar-padding-horizontal;\n margin-right: -@navbar-padding-horizontal;\n padding: 10px @navbar-padding-horizontal;\n border-top: 1px solid transparent;\n border-bottom: 1px solid transparent;\n @shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n\n // Mixin behavior for optimum display\n .form-inline();\n\n .form-group {\n @media (max-width: @grid-float-breakpoint-max) {\n margin-bottom: 5px;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n }\n\n // Vertically center in expanded, horizontal navbar\n .navbar-vertical-align(@input-height-base);\n\n // Undo 100% width for pull classes\n @media (min-width: @grid-float-breakpoint) {\n width: auto;\n border: 0;\n margin-left: 0;\n margin-right: 0;\n padding-top: 0;\n padding-bottom: 0;\n .box-shadow(none);\n }\n}\n\n\n// Dropdown menus\n\n// Menu position and menu carets\n.navbar-nav > li > .dropdown-menu {\n margin-top: 0;\n .border-top-radius(0);\n}\n// Menu position and menu caret support for dropups via extra dropup class\n.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu {\n margin-bottom: 0;\n .border-top-radius(@navbar-border-radius);\n .border-bottom-radius(0);\n}\n\n\n// Buttons in navbars\n//\n// Vertically center a button within a navbar (when *not* in a form).\n\n.navbar-btn {\n .navbar-vertical-align(@input-height-base);\n\n &.btn-sm {\n .navbar-vertical-align(@input-height-small);\n }\n &.btn-xs {\n .navbar-vertical-align(22);\n }\n}\n\n\n// Text in navbars\n//\n// Add a class to make any element properly align itself vertically within the navbars.\n\n.navbar-text {\n .navbar-vertical-align(@line-height-computed);\n\n @media (min-width: @grid-float-breakpoint) {\n float: left;\n margin-left: @navbar-padding-horizontal;\n margin-right: @navbar-padding-horizontal;\n }\n}\n\n\n// Component alignment\n//\n// Repurpose the pull utilities as their own navbar utilities to avoid specificity\n// issues with parents and chaining. Only do this when the navbar is uncollapsed\n// though so that navbar contents properly stack and align in mobile.\n//\n// Declared after the navbar components to ensure more specificity on the margins.\n\n@media (min-width: @grid-float-breakpoint) {\n .navbar-left { .pull-left(); }\n .navbar-right {\n .pull-right();\n margin-right: -@navbar-padding-horizontal;\n\n ~ .navbar-right {\n margin-right: 0;\n }\n }\n}\n\n\n// Alternate navbars\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n background-color: @navbar-default-bg;\n border-color: @navbar-default-border;\n\n .navbar-brand {\n color: @navbar-default-brand-color;\n &:hover,\n &:focus {\n color: @navbar-default-brand-hover-color;\n background-color: @navbar-default-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-default-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-default-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n\n .navbar-toggle {\n border-color: @navbar-default-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-default-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-default-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: @navbar-default-border;\n }\n\n // Dropdown menu items\n .navbar-nav {\n // Remove background color from open dropdown\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-default-link-active-bg;\n color: @navbar-default-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display when collapsed\n .open .dropdown-menu {\n > li > a {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n background-color: @navbar-default-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-active-color;\n background-color: @navbar-default-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n background-color: @navbar-default-link-disabled-bg;\n }\n }\n }\n }\n }\n\n\n // Links in navbars\n //\n // Add a class to ensure links outside the navbar nav are colored correctly.\n\n .navbar-link {\n color: @navbar-default-link-color;\n &:hover {\n color: @navbar-default-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-default-link-color;\n &:hover,\n &:focus {\n color: @navbar-default-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-default-link-disabled-color;\n }\n }\n }\n}\n\n// Inverse navbar\n\n.navbar-inverse {\n background-color: @navbar-inverse-bg;\n border-color: @navbar-inverse-border;\n\n .navbar-brand {\n color: @navbar-inverse-brand-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-brand-hover-color;\n background-color: @navbar-inverse-brand-hover-bg;\n }\n }\n\n .navbar-text {\n color: @navbar-inverse-color;\n }\n\n .navbar-nav {\n > li > a {\n color: @navbar-inverse-link-color;\n\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n\n // Darken the responsive nav toggle\n .navbar-toggle {\n border-color: @navbar-inverse-toggle-border-color;\n &:hover,\n &:focus {\n background-color: @navbar-inverse-toggle-hover-bg;\n }\n .icon-bar {\n background-color: @navbar-inverse-toggle-icon-bar-bg;\n }\n }\n\n .navbar-collapse,\n .navbar-form {\n border-color: darken(@navbar-inverse-bg, 7%);\n }\n\n // Dropdowns\n .navbar-nav {\n > .open > a {\n &,\n &:hover,\n &:focus {\n background-color: @navbar-inverse-link-active-bg;\n color: @navbar-inverse-link-active-color;\n }\n }\n\n @media (max-width: @grid-float-breakpoint-max) {\n // Dropdowns get custom display\n .open .dropdown-menu {\n > .dropdown-header {\n border-color: @navbar-inverse-border;\n }\n .divider {\n background-color: @navbar-inverse-border;\n }\n > li > a {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n background-color: @navbar-inverse-link-hover-bg;\n }\n }\n > .active > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-active-color;\n background-color: @navbar-inverse-link-active-bg;\n }\n }\n > .disabled > a {\n &,\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n background-color: @navbar-inverse-link-disabled-bg;\n }\n }\n }\n }\n }\n\n .navbar-link {\n color: @navbar-inverse-link-color;\n &:hover {\n color: @navbar-inverse-link-hover-color;\n }\n }\n\n .btn-link {\n color: @navbar-inverse-link-color;\n &:hover,\n &:focus {\n color: @navbar-inverse-link-hover-color;\n }\n &[disabled],\n fieldset[disabled] & {\n &:hover,\n &:focus {\n color: @navbar-inverse-link-disabled-color;\n }\n }\n }\n}\n","// Navbar vertical align\n//\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n","//\n// Utility classes\n// --------------------------------------------------\n\n\n// Floats\n// -------------------------\n\n.clearfix {\n .clearfix();\n}\n.center-block {\n .center-block();\n}\n.pull-right {\n float: right !important;\n}\n.pull-left {\n float: left !important;\n}\n\n\n// Toggling content\n// -------------------------\n\n// Note: Deprecated .hide in favor of .hidden or .sr-only (as appropriate) in v3.0.1\n.hide {\n display: none !important;\n}\n.show {\n display: block !important;\n}\n.invisible {\n visibility: hidden;\n}\n.text-hide {\n .text-hide();\n}\n\n\n// Hide from screenreaders and browsers\n//\n// Credit: HTML5 Boilerplate\n\n.hidden {\n display: none !important;\n}\n\n\n// For Affix plugin\n// -------------------------\n\n.affix {\n position: fixed;\n}\n","//\n// Breadcrumbs\n// --------------------------------------------------\n\n\n.breadcrumb {\n padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal;\n margin-bottom: @line-height-computed;\n list-style: none;\n background-color: @breadcrumb-bg;\n border-radius: @border-radius-base;\n\n > li {\n display: inline-block;\n\n + li:before {\n content: \"@{breadcrumb-separator}\\00a0\"; // Unicode space added since inline-block means non-collapsing white-space\n padding: 0 5px;\n color: @breadcrumb-color;\n }\n }\n\n > .active {\n color: @breadcrumb-active-color;\n }\n}\n","//\n// Pagination (multiple pages)\n// --------------------------------------------------\n.pagination {\n display: inline-block;\n padding-left: 0;\n margin: @line-height-computed 0;\n border-radius: @border-radius-base;\n\n > li {\n display: inline; // Remove list-style and block-level defaults\n > a,\n > span {\n position: relative;\n float: left; // Collapse white-space\n padding: @padding-base-vertical @padding-base-horizontal;\n line-height: @line-height-base;\n text-decoration: none;\n color: @pagination-color;\n background-color: @pagination-bg;\n border: 1px solid @pagination-border;\n margin-left: -1px;\n }\n &:first-child {\n > a,\n > span {\n margin-left: 0;\n .border-left-radius(@border-radius-base);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius-base);\n }\n }\n }\n\n > li > a,\n > li > span {\n &:hover,\n &:focus {\n z-index: 3;\n color: @pagination-hover-color;\n background-color: @pagination-hover-bg;\n border-color: @pagination-hover-border;\n }\n }\n\n > .active > a,\n > .active > span {\n &,\n &:hover,\n &:focus {\n z-index: 2;\n color: @pagination-active-color;\n background-color: @pagination-active-bg;\n border-color: @pagination-active-border;\n cursor: default;\n }\n }\n\n > .disabled {\n > span,\n > span:hover,\n > span:focus,\n > a,\n > a:hover,\n > a:focus {\n color: @pagination-disabled-color;\n background-color: @pagination-disabled-bg;\n border-color: @pagination-disabled-border;\n cursor: @cursor-disabled;\n }\n }\n}\n\n// Sizing\n// --------------------------------------------------\n\n// Large\n.pagination-lg {\n .pagination-size(@padding-large-vertical; @padding-large-horizontal; @font-size-large; @line-height-large; @border-radius-large);\n}\n\n// Small\n.pagination-sm {\n .pagination-size(@padding-small-vertical; @padding-small-horizontal; @font-size-small; @line-height-small; @border-radius-small);\n}\n","// Pagination\n\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n","//\n// Pager pagination\n// --------------------------------------------------\n\n\n.pager {\n padding-left: 0;\n margin: @line-height-computed 0;\n list-style: none;\n text-align: center;\n &:extend(.clearfix all);\n li {\n display: inline;\n > a,\n > span {\n display: inline-block;\n padding: 5px 14px;\n background-color: @pager-bg;\n border: 1px solid @pager-border;\n border-radius: @pager-border-radius;\n }\n\n > a:hover,\n > a:focus {\n text-decoration: none;\n background-color: @pager-hover-bg;\n }\n }\n\n .next {\n > a,\n > span {\n float: right;\n }\n }\n\n .previous {\n > a,\n > span {\n float: left;\n }\n }\n\n .disabled {\n > a,\n > a:hover,\n > a:focus,\n > span {\n color: @pager-disabled-color;\n background-color: @pager-bg;\n cursor: @cursor-disabled;\n }\n }\n}\n","//\n// Labels\n// --------------------------------------------------\n\n.label {\n display: inline;\n padding: .2em .6em .3em;\n font-size: 75%;\n font-weight: bold;\n line-height: 1;\n color: @label-color;\n text-align: center;\n white-space: nowrap;\n vertical-align: baseline;\n border-radius: .25em;\n\n // Add hover effects, but only for links\n a& {\n &:hover,\n &:focus {\n color: @label-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Empty labels collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for labels in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n}\n\n// Colors\n// Contextual variations (linked labels get darker on :hover)\n\n.label-default {\n .label-variant(@label-default-bg);\n}\n\n.label-primary {\n .label-variant(@label-primary-bg);\n}\n\n.label-success {\n .label-variant(@label-success-bg);\n}\n\n.label-info {\n .label-variant(@label-info-bg);\n}\n\n.label-warning {\n .label-variant(@label-warning-bg);\n}\n\n.label-danger {\n .label-variant(@label-danger-bg);\n}\n","// Labels\n\n.label-variant(@color) {\n background-color: @color;\n\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n","//\n// Badges\n// --------------------------------------------------\n\n\n// Base class\n.badge {\n display: inline-block;\n min-width: 10px;\n padding: 3px 7px;\n font-size: @font-size-small;\n font-weight: @badge-font-weight;\n color: @badge-color;\n line-height: @badge-line-height;\n vertical-align: middle;\n white-space: nowrap;\n text-align: center;\n background-color: @badge-bg;\n border-radius: @badge-border-radius;\n\n // Empty badges collapse automatically (not available in IE8)\n &:empty {\n display: none;\n }\n\n // Quick fix for badges in buttons\n .btn & {\n position: relative;\n top: -1px;\n }\n\n .btn-xs &,\n .btn-group-xs > .btn & {\n top: 0;\n padding: 1px 5px;\n }\n\n // Hover state, but only for links\n a& {\n &:hover,\n &:focus {\n color: @badge-link-hover-color;\n text-decoration: none;\n cursor: pointer;\n }\n }\n\n // Account for badges in navs\n .list-group-item.active > &,\n .nav-pills > .active > a > & {\n color: @badge-active-color;\n background-color: @badge-active-bg;\n }\n\n .list-group-item > & {\n float: right;\n }\n\n .list-group-item > & + & {\n margin-right: 5px;\n }\n\n .nav-pills > li > a > & {\n margin-left: 3px;\n }\n}\n","//\n// Jumbotron\n// --------------------------------------------------\n\n\n.jumbotron {\n padding-top: @jumbotron-padding;\n padding-bottom: @jumbotron-padding;\n margin-bottom: @jumbotron-padding;\n color: @jumbotron-color;\n background-color: @jumbotron-bg;\n\n h1,\n .h1 {\n color: @jumbotron-heading-color;\n }\n\n p {\n margin-bottom: (@jumbotron-padding / 2);\n font-size: @jumbotron-font-size;\n font-weight: 200;\n }\n\n > hr {\n border-top-color: darken(@jumbotron-bg, 10%);\n }\n\n .container &,\n .container-fluid & {\n border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container\n }\n\n .container {\n max-width: 100%;\n }\n\n @media screen and (min-width: @screen-sm-min) {\n padding-top: (@jumbotron-padding * 1.6);\n padding-bottom: (@jumbotron-padding * 1.6);\n\n .container &,\n .container-fluid & {\n padding-left: (@jumbotron-padding * 2);\n padding-right: (@jumbotron-padding * 2);\n }\n\n h1,\n .h1 {\n font-size: @jumbotron-heading-font-size;\n }\n }\n}\n","//\n// Thumbnails\n// --------------------------------------------------\n\n\n// Mixin and adjust the regular image class\n.thumbnail {\n display: block;\n padding: @thumbnail-padding;\n margin-bottom: @line-height-computed;\n line-height: @line-height-base;\n background-color: @thumbnail-bg;\n border: 1px solid @thumbnail-border;\n border-radius: @thumbnail-border-radius;\n .transition(border .2s ease-in-out);\n\n > img,\n a > img {\n &:extend(.img-responsive);\n margin-left: auto;\n margin-right: auto;\n }\n\n // Add a hover state for linked versions only\n a&:hover,\n a&:focus,\n a&.active {\n border-color: @link-color;\n }\n\n // Image captions\n .caption {\n padding: @thumbnail-caption-padding;\n color: @thumbnail-caption-color;\n }\n}\n","//\n// Alerts\n// --------------------------------------------------\n\n\n// Base styles\n// -------------------------\n\n.alert {\n padding: @alert-padding;\n margin-bottom: @line-height-computed;\n border: 1px solid transparent;\n border-radius: @alert-border-radius;\n\n // Headings for larger alerts\n h4 {\n margin-top: 0;\n // Specified for the h4 to prevent conflicts of changing @headings-color\n color: inherit;\n }\n\n // Provide class for links that match alerts\n .alert-link {\n font-weight: @alert-link-font-weight;\n }\n\n // Improve alignment and spacing of inner content\n > p,\n > ul {\n margin-bottom: 0;\n }\n\n > p + p {\n margin-top: 5px;\n }\n}\n\n// Dismissible alerts\n//\n// Expand the right padding and account for the close button's positioning.\n\n.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.\n.alert-dismissible {\n padding-right: (@alert-padding + 20);\n\n // Adjust close link position\n .close {\n position: relative;\n top: -2px;\n right: -21px;\n color: inherit;\n }\n}\n\n// Alternate styles\n//\n// Generate contextual modifier classes for colorizing the alert.\n\n.alert-success {\n .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);\n}\n\n.alert-info {\n .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);\n}\n\n.alert-warning {\n .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);\n}\n\n.alert-danger {\n .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);\n}\n","// Alerts\n\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n","//\n// Progress bars\n// --------------------------------------------------\n\n\n// Bar animations\n// -------------------------\n\n// WebKit\n@-webkit-keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n// Spec and IE10+\n@keyframes progress-bar-stripes {\n from { background-position: 40px 0; }\n to { background-position: 0 0; }\n}\n\n\n// Bar itself\n// -------------------------\n\n// Outer container\n.progress {\n overflow: hidden;\n height: @line-height-computed;\n margin-bottom: @line-height-computed;\n background-color: @progress-bg;\n border-radius: @progress-border-radius;\n .box-shadow(inset 0 1px 2px rgba(0,0,0,.1));\n}\n\n// Bar of progress\n.progress-bar {\n float: left;\n width: 0%;\n height: 100%;\n font-size: @font-size-small;\n line-height: @line-height-computed;\n color: @progress-bar-color;\n text-align: center;\n background-color: @progress-bar-bg;\n .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));\n .transition(width .6s ease);\n}\n\n// Striped bars\n//\n// `.progress-striped .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar-striped` class, which you just add to an existing\n// `.progress-bar`.\n.progress-striped .progress-bar,\n.progress-bar-striped {\n #gradient > .striped();\n background-size: 40px 40px;\n}\n\n// Call animation for the active one\n//\n// `.progress.active .progress-bar` is deprecated as of v3.2.0 in favor of the\n// `.progress-bar.active` approach.\n.progress.active .progress-bar,\n.progress-bar.active {\n .animation(progress-bar-stripes 2s linear infinite);\n}\n\n\n// Variations\n// -------------------------\n\n.progress-bar-success {\n .progress-bar-variant(@progress-bar-success-bg);\n}\n\n.progress-bar-info {\n .progress-bar-variant(@progress-bar-info-bg);\n}\n\n.progress-bar-warning {\n .progress-bar-variant(@progress-bar-warning-bg);\n}\n\n.progress-bar-danger {\n .progress-bar-variant(@progress-bar-danger-bg);\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Progress bars\n\n.progress-bar-variant(@color) {\n background-color: @color;\n\n // Deprecated parent class requirement as of v3.2.0\n .progress-striped & {\n #gradient > .striped();\n }\n}\n",".media {\n // Proper spacing between instances of .media\n margin-top: 15px;\n\n &:first-child {\n margin-top: 0;\n }\n}\n\n.media,\n.media-body {\n zoom: 1;\n overflow: hidden;\n}\n\n.media-body {\n width: 10000px;\n}\n\n.media-object {\n display: block;\n\n // Fix collapse in webkit from max-width: 100% and display: table-cell.\n &.img-thumbnail {\n max-width: none;\n }\n}\n\n.media-right,\n.media > .pull-right {\n padding-left: 10px;\n}\n\n.media-left,\n.media > .pull-left {\n padding-right: 10px;\n}\n\n.media-left,\n.media-right,\n.media-body {\n display: table-cell;\n vertical-align: top;\n}\n\n.media-middle {\n vertical-align: middle;\n}\n\n.media-bottom {\n vertical-align: bottom;\n}\n\n// Reset margins on headings for tighter default spacing\n.media-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n\n// Media list variation\n//\n// Undo default ul/ol styles\n.media-list {\n padding-left: 0;\n list-style: none;\n}\n","//\n// List groups\n// --------------------------------------------------\n\n\n// Base class\n//\n// Easily usable on <ul>, <ol>, or <div>.\n\n.list-group {\n // No need to set list-style: none; since .list-group-item is block level\n margin-bottom: 20px;\n padding-left: 0; // reset padding because ul and ol\n}\n\n\n// Individual list items\n//\n// Use on `li`s or `div`s within the `.list-group` parent.\n\n.list-group-item {\n position: relative;\n display: block;\n padding: 10px 15px;\n // Place the border on the list items and negative margin up for better styling\n margin-bottom: -1px;\n background-color: @list-group-bg;\n border: 1px solid @list-group-border;\n\n // Round the first and last items\n &:first-child {\n .border-top-radius(@list-group-border-radius);\n }\n &:last-child {\n margin-bottom: 0;\n .border-bottom-radius(@list-group-border-radius);\n }\n}\n\n\n// Interactive list items\n//\n// Use anchor or button elements instead of `li`s or `div`s to create interactive items.\n// Includes an extra `.active` modifier class for showing selected items.\n\na.list-group-item,\nbutton.list-group-item {\n color: @list-group-link-color;\n\n .list-group-item-heading {\n color: @list-group-link-heading-color;\n }\n\n // Hover state\n &:hover,\n &:focus {\n text-decoration: none;\n color: @list-group-link-hover-color;\n background-color: @list-group-hover-bg;\n }\n}\n\nbutton.list-group-item {\n width: 100%;\n text-align: left;\n}\n\n.list-group-item {\n // Disabled state\n &.disabled,\n &.disabled:hover,\n &.disabled:focus {\n background-color: @list-group-disabled-bg;\n color: @list-group-disabled-color;\n cursor: @cursor-disabled;\n\n // Force color to inherit for custom content\n .list-group-item-heading {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-disabled-text-color;\n }\n }\n\n // Active class on item itself, not parent\n &.active,\n &.active:hover,\n &.active:focus {\n z-index: 2; // Place active items above their siblings for proper border styling\n color: @list-group-active-color;\n background-color: @list-group-active-bg;\n border-color: @list-group-active-border;\n\n // Force color to inherit for custom content\n .list-group-item-heading,\n .list-group-item-heading > small,\n .list-group-item-heading > .small {\n color: inherit;\n }\n .list-group-item-text {\n color: @list-group-active-text-color;\n }\n }\n}\n\n\n// Contextual variants\n//\n// Add modifier classes to change text and background color on individual items.\n// Organizationally, this must come after the `:hover` states.\n\n.list-group-item-variant(success; @state-success-bg; @state-success-text);\n.list-group-item-variant(info; @state-info-bg; @state-info-text);\n.list-group-item-variant(warning; @state-warning-bg; @state-warning-text);\n.list-group-item-variant(danger; @state-danger-bg; @state-danger-text);\n\n\n// Custom content options\n//\n// Extra classes for creating well-formatted content within `.list-group-item`s.\n\n.list-group-item-heading {\n margin-top: 0;\n margin-bottom: 5px;\n}\n.list-group-item-text {\n margin-bottom: 0;\n line-height: 1.3;\n}\n","// List Groups\n\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a&,\n button& {\n color: @color;\n\n .list-group-item-heading {\n color: inherit;\n }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n","//\n// Panels\n// --------------------------------------------------\n\n\n// Base class\n.panel {\n margin-bottom: @line-height-computed;\n background-color: @panel-bg;\n border: 1px solid transparent;\n border-radius: @panel-border-radius;\n .box-shadow(0 1px 1px rgba(0,0,0,.05));\n}\n\n// Panel contents\n.panel-body {\n padding: @panel-body-padding;\n &:extend(.clearfix all);\n}\n\n// Optional heading\n.panel-heading {\n padding: @panel-heading-padding;\n border-bottom: 1px solid transparent;\n .border-top-radius((@panel-border-radius - 1));\n\n > .dropdown .dropdown-toggle {\n color: inherit;\n }\n}\n\n// Within heading, strip any `h*` tag of its default margins for spacing.\n.panel-title {\n margin-top: 0;\n margin-bottom: 0;\n font-size: ceil((@font-size-base * 1.125));\n color: inherit;\n\n > a,\n > small,\n > .small,\n > small > a,\n > .small > a {\n color: inherit;\n }\n}\n\n// Optional footer (stays gray in every modifier class)\n.panel-footer {\n padding: @panel-footer-padding;\n background-color: @panel-footer-bg;\n border-top: 1px solid @panel-inner-border;\n .border-bottom-radius((@panel-border-radius - 1));\n}\n\n\n// List groups in panels\n//\n// By default, space out list group content from panel headings to account for\n// any kind of custom content between the two.\n\n.panel {\n > .list-group,\n > .panel-collapse > .list-group {\n margin-bottom: 0;\n\n .list-group-item {\n border-width: 1px 0;\n border-radius: 0;\n }\n\n // Add border top radius for first one\n &:first-child {\n .list-group-item:first-child {\n border-top: 0;\n .border-top-radius((@panel-border-radius - 1));\n }\n }\n\n // Add border bottom radius for last one\n &:last-child {\n .list-group-item:last-child {\n border-bottom: 0;\n .border-bottom-radius((@panel-border-radius - 1));\n }\n }\n }\n > .panel-heading + .panel-collapse > .list-group {\n .list-group-item:first-child {\n .border-top-radius(0);\n }\n }\n}\n// Collapse space between when there's no additional content.\n.panel-heading + .list-group {\n .list-group-item:first-child {\n border-top-width: 0;\n }\n}\n.list-group + .panel-footer {\n border-top-width: 0;\n}\n\n// Tables in panels\n//\n// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and\n// watch it go full width.\n\n.panel {\n > .table,\n > .table-responsive > .table,\n > .panel-collapse > .table {\n margin-bottom: 0;\n\n caption {\n padding-left: @panel-body-padding;\n padding-right: @panel-body-padding;\n }\n }\n // Add border top radius for first one\n > .table:first-child,\n > .table-responsive:first-child > .table:first-child {\n .border-top-radius((@panel-border-radius - 1));\n\n > thead:first-child,\n > tbody:first-child {\n > tr:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n border-top-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-top-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-top-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n // Add border bottom radius for last one\n > .table:last-child,\n > .table-responsive:last-child > .table:last-child {\n .border-bottom-radius((@panel-border-radius - 1));\n\n > tbody:last-child,\n > tfoot:last-child {\n > tr:last-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n border-bottom-right-radius: (@panel-border-radius - 1);\n\n td:first-child,\n th:first-child {\n border-bottom-left-radius: (@panel-border-radius - 1);\n }\n td:last-child,\n th:last-child {\n border-bottom-right-radius: (@panel-border-radius - 1);\n }\n }\n }\n }\n > .panel-body + .table,\n > .panel-body + .table-responsive,\n > .table + .panel-body,\n > .table-responsive + .panel-body {\n border-top: 1px solid @table-border-color;\n }\n > .table > tbody:first-child > tr:first-child th,\n > .table > tbody:first-child > tr:first-child td {\n border-top: 0;\n }\n > .table-bordered,\n > .table-responsive > .table-bordered {\n border: 0;\n > thead,\n > tbody,\n > tfoot {\n > tr {\n > th:first-child,\n > td:first-child {\n border-left: 0;\n }\n > th:last-child,\n > td:last-child {\n border-right: 0;\n }\n }\n }\n > thead,\n > tbody {\n > tr:first-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n > tbody,\n > tfoot {\n > tr:last-child {\n > td,\n > th {\n border-bottom: 0;\n }\n }\n }\n }\n > .table-responsive {\n border: 0;\n margin-bottom: 0;\n }\n}\n\n\n// Collapsable panels (aka, accordion)\n//\n// Wrap a series of panels in `.panel-group` to turn them into an accordion with\n// the help of our collapse JavaScript plugin.\n\n.panel-group {\n margin-bottom: @line-height-computed;\n\n // Tighten up margin so it's only between panels\n .panel {\n margin-bottom: 0;\n border-radius: @panel-border-radius;\n\n + .panel {\n margin-top: 5px;\n }\n }\n\n .panel-heading {\n border-bottom: 0;\n\n + .panel-collapse > .panel-body,\n + .panel-collapse > .list-group {\n border-top: 1px solid @panel-inner-border;\n }\n }\n\n .panel-footer {\n border-top: 0;\n + .panel-collapse .panel-body {\n border-bottom: 1px solid @panel-inner-border;\n }\n }\n}\n\n\n// Contextual variations\n.panel-default {\n .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border);\n}\n.panel-primary {\n .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border);\n}\n.panel-success {\n .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border);\n}\n.panel-info {\n .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border);\n}\n.panel-warning {\n .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border);\n}\n.panel-danger {\n .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border);\n}\n","// Panels\n\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse > .panel-body {\n border-top-color: @border;\n }\n .badge {\n color: @heading-bg-color;\n background-color: @heading-text-color;\n }\n }\n & > .panel-footer {\n + .panel-collapse > .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n","// Embeds responsive\n//\n// Credit: Nicolas Gallagher and SUIT CSS.\n\n.embed-responsive {\n position: relative;\n display: block;\n height: 0;\n padding: 0;\n overflow: hidden;\n\n .embed-responsive-item,\n iframe,\n embed,\n object,\n video {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n height: 100%;\n width: 100%;\n border: 0;\n }\n}\n\n// Modifier class for 16:9 aspect ratio\n.embed-responsive-16by9 {\n padding-bottom: 56.25%;\n}\n\n// Modifier class for 4:3 aspect ratio\n.embed-responsive-4by3 {\n padding-bottom: 75%;\n}\n","//\n// Wells\n// --------------------------------------------------\n\n\n// Base class\n.well {\n min-height: 20px;\n padding: 19px;\n margin-bottom: 20px;\n background-color: @well-bg;\n border: 1px solid @well-border;\n border-radius: @border-radius-base;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.05));\n blockquote {\n border-color: #ddd;\n border-color: rgba(0,0,0,.15);\n }\n}\n\n// Sizes\n.well-lg {\n padding: 24px;\n border-radius: @border-radius-large;\n}\n.well-sm {\n padding: 9px;\n border-radius: @border-radius-small;\n}\n","//\n// Close icons\n// --------------------------------------------------\n\n\n.close {\n float: right;\n font-size: (@font-size-base * 1.5);\n font-weight: @close-font-weight;\n line-height: 1;\n color: @close-color;\n text-shadow: @close-text-shadow;\n .opacity(.2);\n\n &:hover,\n &:focus {\n color: @close-color;\n text-decoration: none;\n cursor: pointer;\n .opacity(.5);\n }\n\n // Additional properties for button version\n // iOS requires the button element instead of an anchor tag.\n // If you want the anchor version, it requires `href=\"#\"`.\n // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile\n button& {\n padding: 0;\n cursor: pointer;\n background: transparent;\n border: 0;\n -webkit-appearance: none;\n }\n}\n","//\n// Modals\n// --------------------------------------------------\n\n// .modal-open - body class for killing the scroll\n// .modal - container to scroll within\n// .modal-dialog - positioning shell for the actual modal\n// .modal-content - actual modal w/ bg and corners and shit\n\n// Kill the scroll on the body\n.modal-open {\n overflow: hidden;\n}\n\n// Container that the modal scrolls within\n.modal {\n display: none;\n overflow: hidden;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal;\n -webkit-overflow-scrolling: touch;\n\n // Prevent Chrome on Windows from adding a focus outline. For details, see\n // https://github.com/twbs/bootstrap/pull/10951.\n outline: 0;\n\n // When fading in the modal, animate it to slide down\n &.fade .modal-dialog {\n .translate(0, -25%);\n .transition-transform(~\"0.3s ease-out\");\n }\n &.in .modal-dialog { .translate(0, 0) }\n}\n.modal-open .modal {\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n// Shell div to position the modal with bottom padding\n.modal-dialog {\n position: relative;\n width: auto;\n margin: 10px;\n}\n\n// Actual modal\n.modal-content {\n position: relative;\n background-color: @modal-content-bg;\n border: 1px solid @modal-content-fallback-border-color; //old browsers fallback (ie8 etc)\n border: 1px solid @modal-content-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 3px 9px rgba(0,0,0,.5));\n background-clip: padding-box;\n // Remove focus outline from opened modal\n outline: 0;\n}\n\n// Modal background\n.modal-backdrop {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n z-index: @zindex-modal-background;\n background-color: @modal-backdrop-bg;\n // Fade for backdrop\n &.fade { .opacity(0); }\n &.in { .opacity(@modal-backdrop-opacity); }\n}\n\n// Modal header\n// Top section of the modal w/ title and dismiss\n.modal-header {\n padding: @modal-title-padding;\n border-bottom: 1px solid @modal-header-border-color;\n min-height: (@modal-title-padding + @modal-title-line-height);\n}\n// Close icon\n.modal-header .close {\n margin-top: -2px;\n}\n\n// Title text within header\n.modal-title {\n margin: 0;\n line-height: @modal-title-line-height;\n}\n\n// Modal body\n// Where all modal content resides (sibling of .modal-header and .modal-footer)\n.modal-body {\n position: relative;\n padding: @modal-inner-padding;\n}\n\n// Footer (for actions)\n.modal-footer {\n padding: @modal-inner-padding;\n text-align: right; // right align buttons\n border-top: 1px solid @modal-footer-border-color;\n &:extend(.clearfix all); // clear it in case folks use .pull-* classes on buttons\n\n // Properly space out buttons\n .btn + .btn {\n margin-left: 5px;\n margin-bottom: 0; // account for input[type=\"submit\"] which gets the bottom margin like all other inputs\n }\n // but override that for button groups\n .btn-group .btn + .btn {\n margin-left: -1px;\n }\n // and override it for block buttons as well\n .btn-block + .btn-block {\n margin-left: 0;\n }\n}\n\n// Measure scrollbar width for padding body during modal show/hide\n.modal-scrollbar-measure {\n position: absolute;\n top: -9999px;\n width: 50px;\n height: 50px;\n overflow: scroll;\n}\n\n// Scale up the modal\n@media (min-width: @screen-sm-min) {\n // Automatically set modal's width for larger viewports\n .modal-dialog {\n width: @modal-md;\n margin: 30px auto;\n }\n .modal-content {\n .box-shadow(0 5px 15px rgba(0,0,0,.5));\n }\n\n // Modal sizes\n .modal-sm { width: @modal-sm; }\n}\n\n@media (min-width: @screen-md-min) {\n .modal-lg { width: @modal-lg; }\n}\n","//\n// Tooltips\n// --------------------------------------------------\n\n\n// Base class\n.tooltip {\n position: absolute;\n z-index: @zindex-tooltip;\n display: block;\n // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n .reset-text();\n font-size: @font-size-small;\n\n .opacity(0);\n\n &.in { .opacity(@tooltip-opacity); }\n &.top { margin-top: -3px; padding: @tooltip-arrow-width 0; }\n &.right { margin-left: 3px; padding: 0 @tooltip-arrow-width; }\n &.bottom { margin-top: 3px; padding: @tooltip-arrow-width 0; }\n &.left { margin-left: -3px; padding: 0 @tooltip-arrow-width; }\n}\n\n// Wrapper for the tooltip content\n.tooltip-inner {\n max-width: @tooltip-max-width;\n padding: 3px 8px;\n color: @tooltip-color;\n text-align: center;\n background-color: @tooltip-bg;\n border-radius: @border-radius-base;\n}\n\n// Arrows\n.tooltip-arrow {\n position: absolute;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n}\n// Note: Deprecated .top-left, .top-right, .bottom-left, and .bottom-right as of v3.3.1\n.tooltip {\n &.top .tooltip-arrow {\n bottom: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-left .tooltip-arrow {\n bottom: 0;\n right: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.top-right .tooltip-arrow {\n bottom: 0;\n left: @tooltip-arrow-width;\n margin-bottom: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width 0;\n border-top-color: @tooltip-arrow-color;\n }\n &.right .tooltip-arrow {\n top: 50%;\n left: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width @tooltip-arrow-width @tooltip-arrow-width 0;\n border-right-color: @tooltip-arrow-color;\n }\n &.left .tooltip-arrow {\n top: 50%;\n right: 0;\n margin-top: -@tooltip-arrow-width;\n border-width: @tooltip-arrow-width 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-left-color: @tooltip-arrow-color;\n }\n &.bottom .tooltip-arrow {\n top: 0;\n left: 50%;\n margin-left: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-left .tooltip-arrow {\n top: 0;\n right: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n &.bottom-right .tooltip-arrow {\n top: 0;\n left: @tooltip-arrow-width;\n margin-top: -@tooltip-arrow-width;\n border-width: 0 @tooltip-arrow-width @tooltip-arrow-width;\n border-bottom-color: @tooltip-arrow-color;\n }\n}\n",".reset-text() {\n font-family: @font-family-base;\n // We deliberately do NOT reset font-size.\n font-style: normal;\n font-weight: normal;\n letter-spacing: normal;\n line-break: auto;\n line-height: @line-height-base;\n text-align: left; // Fallback for where `start` is not supported\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n white-space: normal;\n word-break: normal;\n word-spacing: normal;\n word-wrap: normal;\n}\n","//\n// Popovers\n// --------------------------------------------------\n\n\n.popover {\n position: absolute;\n top: 0;\n left: 0;\n z-index: @zindex-popover;\n display: none;\n max-width: @popover-max-width;\n padding: 1px;\n // Our parent element can be arbitrary since popovers are by default inserted as a sibling of their target element.\n // So reset our font and text properties to avoid inheriting weird values.\n .reset-text();\n font-size: @font-size-base;\n\n background-color: @popover-bg;\n background-clip: padding-box;\n border: 1px solid @popover-fallback-border-color;\n border: 1px solid @popover-border-color;\n border-radius: @border-radius-large;\n .box-shadow(0 5px 10px rgba(0,0,0,.2));\n\n // Offset the popover to account for the popover arrow\n &.top { margin-top: -@popover-arrow-width; }\n &.right { margin-left: @popover-arrow-width; }\n &.bottom { margin-top: @popover-arrow-width; }\n &.left { margin-left: -@popover-arrow-width; }\n}\n\n.popover-title {\n margin: 0; // reset heading margin\n padding: 8px 14px;\n font-size: @font-size-base;\n background-color: @popover-title-bg;\n border-bottom: 1px solid darken(@popover-title-bg, 5%);\n border-radius: (@border-radius-large - 1) (@border-radius-large - 1) 0 0;\n}\n\n.popover-content {\n padding: 9px 14px;\n}\n\n// Arrows\n//\n// .arrow is outer, .arrow:after is inner\n\n.popover > .arrow {\n &,\n &:after {\n position: absolute;\n display: block;\n width: 0;\n height: 0;\n border-color: transparent;\n border-style: solid;\n }\n}\n.popover > .arrow {\n border-width: @popover-arrow-outer-width;\n}\n.popover > .arrow:after {\n border-width: @popover-arrow-width;\n content: \"\";\n}\n\n.popover {\n &.top > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-top-color: @popover-arrow-outer-color;\n bottom: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n bottom: 1px;\n margin-left: -@popover-arrow-width;\n border-bottom-width: 0;\n border-top-color: @popover-arrow-color;\n }\n }\n &.right > .arrow {\n top: 50%;\n left: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-right-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n left: 1px;\n bottom: -@popover-arrow-width;\n border-left-width: 0;\n border-right-color: @popover-arrow-color;\n }\n }\n &.bottom > .arrow {\n left: 50%;\n margin-left: -@popover-arrow-outer-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-bottom-color: @popover-arrow-outer-color;\n top: -@popover-arrow-outer-width;\n &:after {\n content: \" \";\n top: 1px;\n margin-left: -@popover-arrow-width;\n border-top-width: 0;\n border-bottom-color: @popover-arrow-color;\n }\n }\n\n &.left > .arrow {\n top: 50%;\n right: -@popover-arrow-outer-width;\n margin-top: -@popover-arrow-outer-width;\n border-right-width: 0;\n border-left-color: @popover-arrow-outer-fallback-color; // IE8 fallback\n border-left-color: @popover-arrow-outer-color;\n &:after {\n content: \" \";\n right: 1px;\n border-right-width: 0;\n border-left-color: @popover-arrow-color;\n bottom: -@popover-arrow-width;\n }\n }\n}\n","//\n// Carousel\n// --------------------------------------------------\n\n\n// Wrapper for the slide container and indicators\n.carousel {\n position: relative;\n}\n\n.carousel-inner {\n position: relative;\n overflow: hidden;\n width: 100%;\n\n > .item {\n display: none;\n position: relative;\n .transition(.6s ease-in-out left);\n\n // Account for jankitude on images\n > img,\n > a > img {\n &:extend(.img-responsive);\n line-height: 1;\n }\n\n // WebKit CSS3 transforms for supported devices\n @media all and (transform-3d), (-webkit-transform-3d) {\n .transition-transform(~'0.6s ease-in-out');\n .backface-visibility(~'hidden');\n .perspective(1000px);\n\n &.next,\n &.active.right {\n .translate3d(100%, 0, 0);\n left: 0;\n }\n &.prev,\n &.active.left {\n .translate3d(-100%, 0, 0);\n left: 0;\n }\n &.next.left,\n &.prev.right,\n &.active {\n .translate3d(0, 0, 0);\n left: 0;\n }\n }\n }\n\n > .active,\n > .next,\n > .prev {\n display: block;\n }\n\n > .active {\n left: 0;\n }\n\n > .next,\n > .prev {\n position: absolute;\n top: 0;\n width: 100%;\n }\n\n > .next {\n left: 100%;\n }\n > .prev {\n left: -100%;\n }\n > .next.left,\n > .prev.right {\n left: 0;\n }\n\n > .active.left {\n left: -100%;\n }\n > .active.right {\n left: 100%;\n }\n\n}\n\n// Left/right controls for nav\n// ---------------------------\n\n.carousel-control {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n width: @carousel-control-width;\n .opacity(@carousel-control-opacity);\n font-size: @carousel-control-font-size;\n color: @carousel-control-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n // We can't have this transition here because WebKit cancels the carousel\n // animation if you trip this while in the middle of another animation.\n\n // Set gradients for backgrounds\n &.left {\n #gradient > .horizontal(@start-color: rgba(0,0,0,.5); @end-color: rgba(0,0,0,.0001));\n }\n &.right {\n left: auto;\n right: 0;\n #gradient > .horizontal(@start-color: rgba(0,0,0,.0001); @end-color: rgba(0,0,0,.5));\n }\n\n // Hover/focus state\n &:hover,\n &:focus {\n outline: 0;\n color: @carousel-control-color;\n text-decoration: none;\n .opacity(.9);\n }\n\n // Toggles\n .icon-prev,\n .icon-next,\n .glyphicon-chevron-left,\n .glyphicon-chevron-right {\n position: absolute;\n top: 50%;\n margin-top: -10px;\n z-index: 5;\n display: inline-block;\n }\n .icon-prev,\n .glyphicon-chevron-left {\n left: 50%;\n margin-left: -10px;\n }\n .icon-next,\n .glyphicon-chevron-right {\n right: 50%;\n margin-right: -10px;\n }\n .icon-prev,\n .icon-next {\n width: 20px;\n height: 20px;\n line-height: 1;\n font-family: serif;\n }\n\n\n .icon-prev {\n &:before {\n content: '\\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)\n }\n }\n .icon-next {\n &:before {\n content: '\\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)\n }\n }\n}\n\n// Optional indicator pips\n//\n// Add an unordered list with the following class and add a list item for each\n// slide your carousel holds.\n\n.carousel-indicators {\n position: absolute;\n bottom: 10px;\n left: 50%;\n z-index: 15;\n width: 60%;\n margin-left: -30%;\n padding-left: 0;\n list-style: none;\n text-align: center;\n\n li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 1px;\n text-indent: -999px;\n border: 1px solid @carousel-indicator-border-color;\n border-radius: 10px;\n cursor: pointer;\n\n // IE8-9 hack for event handling\n //\n // Internet Explorer 8-9 does not support clicks on elements without a set\n // `background-color`. We cannot use `filter` since that's not viewed as a\n // background color by the browser. Thus, a hack is needed.\n // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer\n //\n // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we\n // set alpha transparency for the best results possible.\n background-color: #000 \\9; // IE8\n background-color: rgba(0,0,0,0); // IE9\n }\n .active {\n margin: 0;\n width: 12px;\n height: 12px;\n background-color: @carousel-indicator-active-bg;\n }\n}\n\n// Optional captions\n// -----------------------------\n// Hidden by default for smaller viewports\n.carousel-caption {\n position: absolute;\n left: 15%;\n right: 15%;\n bottom: 20px;\n z-index: 10;\n padding-top: 20px;\n padding-bottom: 20px;\n color: @carousel-caption-color;\n text-align: center;\n text-shadow: @carousel-text-shadow;\n & .btn {\n text-shadow: none; // No shadow for button elements in carousel-caption\n }\n}\n\n\n// Scale up controls for tablets and up\n@media screen and (min-width: @screen-sm-min) {\n\n // Scale up the controls a smidge\n .carousel-control {\n .glyphicon-chevron-left,\n .glyphicon-chevron-right,\n .icon-prev,\n .icon-next {\n width: 30px;\n height: 30px;\n margin-top: -15px;\n font-size: 30px;\n }\n .glyphicon-chevron-left,\n .icon-prev {\n margin-left: -15px;\n }\n .glyphicon-chevron-right,\n .icon-next {\n margin-right: -15px;\n }\n }\n\n // Show and left align the captions\n .carousel-caption {\n left: 20%;\n right: 20%;\n padding-bottom: 30px;\n }\n\n // Move up the indicators\n .carousel-indicators {\n bottom: 20px;\n }\n}\n","// Clearfix\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n//\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n","// Center-align a block level element\n\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n","// CSS image replacement\n//\n// Heads up! v3 launched with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n","//\n// Responsive: Utility classes\n// --------------------------------------------------\n\n\n// IE10 in Windows (Phone) 8\n//\n// Support for responsive views via media queries is kind of borked in IE10, for\n// Surface/desktop in split view and for Windows Phone 8. This particular fix\n// must be accompanied by a snippet of JavaScript to sniff the user agent and\n// apply some conditional CSS to *only* the Surface/desktop Windows 8. Look at\n// our Getting Started page for more information on this bug.\n//\n// For more information, see the following:\n//\n// Issue: https://github.com/twbs/bootstrap/issues/10497\n// Docs: http://getbootstrap.com/getting-started/#support-ie10-width\n// Source: http://timkadlec.com/2013/01/windows-phone-8-and-device-width/\n// Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/\n\n@-ms-viewport {\n width: device-width;\n}\n\n\n// Visibility utilities\n// Note: Deprecated .visible-xs, .visible-sm, .visible-md, and .visible-lg as of v3.2.0\n.visible-xs,\n.visible-sm,\n.visible-md,\n.visible-lg {\n .responsive-invisibility();\n}\n\n.visible-xs-block,\n.visible-xs-inline,\n.visible-xs-inline-block,\n.visible-sm-block,\n.visible-sm-inline,\n.visible-sm-inline-block,\n.visible-md-block,\n.visible-md-inline,\n.visible-md-inline-block,\n.visible-lg-block,\n.visible-lg-inline,\n.visible-lg-inline-block {\n display: none !important;\n}\n\n.visible-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-visibility();\n }\n}\n.visible-xs-block {\n @media (max-width: @screen-xs-max) {\n display: block !important;\n }\n}\n.visible-xs-inline {\n @media (max-width: @screen-xs-max) {\n display: inline !important;\n }\n}\n.visible-xs-inline-block {\n @media (max-width: @screen-xs-max) {\n display: inline-block !important;\n }\n}\n\n.visible-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-visibility();\n }\n}\n.visible-sm-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: block !important;\n }\n}\n.visible-sm-inline {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline !important;\n }\n}\n.visible-sm-inline-block {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n display: inline-block !important;\n }\n}\n\n.visible-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-visibility();\n }\n}\n.visible-md-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: block !important;\n }\n}\n.visible-md-inline {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline !important;\n }\n}\n.visible-md-inline-block {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n display: inline-block !important;\n }\n}\n\n.visible-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-visibility();\n }\n}\n.visible-lg-block {\n @media (min-width: @screen-lg-min) {\n display: block !important;\n }\n}\n.visible-lg-inline {\n @media (min-width: @screen-lg-min) {\n display: inline !important;\n }\n}\n.visible-lg-inline-block {\n @media (min-width: @screen-lg-min) {\n display: inline-block !important;\n }\n}\n\n.hidden-xs {\n @media (max-width: @screen-xs-max) {\n .responsive-invisibility();\n }\n}\n.hidden-sm {\n @media (min-width: @screen-sm-min) and (max-width: @screen-sm-max) {\n .responsive-invisibility();\n }\n}\n.hidden-md {\n @media (min-width: @screen-md-min) and (max-width: @screen-md-max) {\n .responsive-invisibility();\n }\n}\n.hidden-lg {\n @media (min-width: @screen-lg-min) {\n .responsive-invisibility();\n }\n}\n\n\n// Print utilities\n//\n// Media queries are placed on the inside to be mixin-friendly.\n\n// Note: Deprecated .visible-print as of v3.2.0\n.visible-print {\n .responsive-invisibility();\n\n @media print {\n .responsive-visibility();\n }\n}\n.visible-print-block {\n display: none !important;\n\n @media print {\n display: block !important;\n }\n}\n.visible-print-inline {\n display: none !important;\n\n @media print {\n display: inline !important;\n }\n}\n.visible-print-inline-block {\n display: none !important;\n\n @media print {\n display: inline-block !important;\n }\n}\n\n.hidden-print {\n @media print {\n .responsive-invisibility();\n }\n}\n","// Responsive utilities\n\n//\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table !important; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n"]}
\ No newline at end of file
--- /dev/null
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */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{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!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^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.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 td,.table-bordered th{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.woff2) format('woff2'),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-eur:before,.glyphicon-euro: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"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-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}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;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}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>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}[role=button]{cursor:pointer}.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,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,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,.h5,.h6,h4,h5,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:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{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}dd,dt{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[data-original-title],abbr[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 ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer: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 .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer: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-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.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-md-1,.col-md-10,.col-md-11,.col-md-12,.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-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.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-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{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-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{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-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{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-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{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;font-size:14px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{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>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(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>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{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>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{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=checkbox],input[type=radio]{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=checkbox]:focus,input[type=radio]: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{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;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{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.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}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-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 .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-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 .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-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 .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{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.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.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.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{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{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{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.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{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.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{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.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;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:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{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=button].btn-block,input[type=reset].btn-block,input[type=submit].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}.collapse.in{display:block}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 dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{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:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{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 dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@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-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.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,.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:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-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=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{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.3333333;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}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.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}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn: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=checkbox],.input-group-addon input[type=radio]{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-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){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:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{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:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{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{z-index:2;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:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.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:focus,.nav-tabs>li.active>a:hover{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:focus,.nav-tabs.nav-justified>.active>a:hover{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:focus,.nav-tabs.nav-justified>.active>a:hover{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:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.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:focus,.nav-tabs-justified>.active>a:hover{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:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.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}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{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-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{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:focus,.navbar-brand:hover{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 .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{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 .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{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{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;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:focus,.navbar-default .navbar-brand:hover{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:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{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:focus,.navbar-default .navbar-nav>.open>a:hover{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:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{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:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{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:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{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:focus,.navbar-inverse .navbar-nav>.open>a:hover{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:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{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:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{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:#337ab7;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:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{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;line-height:1.3333333}.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;line-height:1.5}.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:focus,.pager li>a:hover{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:focus,.pager .disabled>a:hover,.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:focus,a.label:hover{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]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{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:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;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-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .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 a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.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:#337ab7;-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-bar-striped,.progress-striped .progress-bar{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-bar.active,.progress.active .progress-bar{-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,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{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}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{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>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>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>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody: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:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.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 th:first-child,.panel>.table-responsive:first-child>.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 th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.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 th:last-child,.panel>.table-responsive:first-child>.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 th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.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 th:first-child,.panel>.table-responsive:last-child>.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 th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.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 th:last-child,.panel>.table-responsive:last-child>.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 th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.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 td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.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>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{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:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.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 embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.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:focus,.close:hover{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:1050;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;z-index:1040;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-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.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;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{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;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;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-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-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;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);line-break:auto}.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>a>img,.carousel-inner>.item>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:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{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:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.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-next,.carousel-control .icon-prev{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}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row: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}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.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!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.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!important}tr.visible-md{display:table-row!important}td.visible-md,th.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!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.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!important}tr.visible-print{display:table-row!important}td.visible-print,th.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
--- /dev/null
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
+<font-face units-per-em="1200" ascent="960" descent="-240" />
+<missing-glyph horiz-adv-x="500" />
+<glyph horiz-adv-x="0" />
+<glyph horiz-adv-x="400" />
+<glyph unicode=" " />
+<glyph unicode="*" d="M600 1100q15 0 34 -1.5t30 -3.5l11 -1q10 -2 17.5 -10.5t7.5 -18.5v-224l158 158q7 7 18 8t19 -6l106 -106q7 -8 6 -19t-8 -18l-158 -158h224q10 0 18.5 -7.5t10.5 -17.5q6 -41 6 -75q0 -15 -1.5 -34t-3.5 -30l-1 -11q-2 -10 -10.5 -17.5t-18.5 -7.5h-224l158 -158 q7 -7 8 -18t-6 -19l-106 -106q-8 -7 -19 -6t-18 8l-158 158v-224q0 -10 -7.5 -18.5t-17.5 -10.5q-41 -6 -75 -6q-15 0 -34 1.5t-30 3.5l-11 1q-10 2 -17.5 10.5t-7.5 18.5v224l-158 -158q-7 -7 -18 -8t-19 6l-106 106q-7 8 -6 19t8 18l158 158h-224q-10 0 -18.5 7.5 t-10.5 17.5q-6 41 -6 75q0 15 1.5 34t3.5 30l1 11q2 10 10.5 17.5t18.5 7.5h224l-158 158q-7 7 -8 18t6 19l106 106q8 7 19 6t18 -8l158 -158v224q0 10 7.5 18.5t17.5 10.5q41 6 75 6z" />
+<glyph unicode="+" d="M450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-350h350q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-350v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v350h-350q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5 h350v350q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode=" " />
+<glyph unicode="¥" d="M825 1100h250q10 0 12.5 -5t-5.5 -13l-364 -364q-6 -6 -11 -18h268q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-100h275q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-125v-174q0 -11 -7.5 -18.5t-18.5 -7.5h-148q-11 0 -18.5 7.5t-7.5 18.5v174 h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h125v100h-275q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h118q-5 12 -11 18l-364 364q-8 8 -5.5 13t12.5 5h250q25 0 43 -18l164 -164q8 -8 18 -8t18 8l164 164q18 18 43 18z" />
+<glyph unicode=" " horiz-adv-x="650" />
+<glyph unicode=" " horiz-adv-x="1300" />
+<glyph unicode=" " horiz-adv-x="650" />
+<glyph unicode=" " horiz-adv-x="1300" />
+<glyph unicode=" " horiz-adv-x="433" />
+<glyph unicode=" " horiz-adv-x="325" />
+<glyph unicode=" " horiz-adv-x="216" />
+<glyph unicode=" " horiz-adv-x="216" />
+<glyph unicode=" " horiz-adv-x="162" />
+<glyph unicode=" " horiz-adv-x="260" />
+<glyph unicode=" " horiz-adv-x="72" />
+<glyph unicode=" " horiz-adv-x="260" />
+<glyph unicode=" " horiz-adv-x="325" />
+<glyph unicode="€" d="M744 1198q242 0 354 -189q60 -104 66 -209h-181q0 45 -17.5 82.5t-43.5 61.5t-58 40.5t-60.5 24t-51.5 7.5q-19 0 -40.5 -5.5t-49.5 -20.5t-53 -38t-49 -62.5t-39 -89.5h379l-100 -100h-300q-6 -50 -6 -100h406l-100 -100h-300q9 -74 33 -132t52.5 -91t61.5 -54.5t59 -29 t47 -7.5q22 0 50.5 7.5t60.5 24.5t58 41t43.5 61t17.5 80h174q-30 -171 -128 -278q-107 -117 -274 -117q-206 0 -324 158q-36 48 -69 133t-45 204h-217l100 100h112q1 47 6 100h-218l100 100h134q20 87 51 153.5t62 103.5q117 141 297 141z" />
+<glyph unicode="₽" d="M428 1200h350q67 0 120 -13t86 -31t57 -49.5t35 -56.5t17 -64.5t6.5 -60.5t0.5 -57v-16.5v-16.5q0 -36 -0.5 -57t-6.5 -61t-17 -65t-35 -57t-57 -50.5t-86 -31.5t-120 -13h-178l-2 -100h288q10 0 13 -6t-3 -14l-120 -160q-6 -8 -18 -14t-22 -6h-138v-175q0 -11 -5.5 -18 t-15.5 -7h-149q-10 0 -17.5 7.5t-7.5 17.5v175h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v100h-267q-10 0 -13 6t3 14l120 160q6 8 18 14t22 6h117v475q0 10 7.5 17.5t17.5 7.5zM600 1000v-300h203q64 0 86.5 33t22.5 119q0 84 -22.5 116t-86.5 32h-203z" />
+<glyph unicode="−" d="M250 700h800q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="⌛" d="M1000 1200v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-50v-100q0 -91 -49.5 -165.5t-130.5 -109.5q81 -35 130.5 -109.5t49.5 -165.5v-150h50q21 0 35.5 -14.5t14.5 -35.5v-150h-800v150q0 21 14.5 35.5t35.5 14.5h50v150q0 91 49.5 165.5t130.5 109.5q-81 35 -130.5 109.5 t-49.5 165.5v100h-50q-21 0 -35.5 14.5t-14.5 35.5v150h800zM400 1000v-100q0 -60 32.5 -109.5t87.5 -73.5q28 -12 44 -37t16 -55t-16 -55t-44 -37q-55 -24 -87.5 -73.5t-32.5 -109.5v-150h400v150q0 60 -32.5 109.5t-87.5 73.5q-28 12 -44 37t-16 55t16 55t44 37 q55 24 87.5 73.5t32.5 109.5v100h-400z" />
+<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" />
+<glyph unicode="☁" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -206.5q0 -121 -85 -207.5t-205 -86.5h-750q-79 0 -135.5 57t-56.5 137q0 69 42.5 122.5t108.5 67.5q-2 12 -2 37q0 153 108 260.5t260 107.5z" />
+<glyph unicode="⛺" d="M774 1193.5q16 -9.5 20.5 -27t-5.5 -33.5l-136 -187l467 -746h30q20 0 35 -18.5t15 -39.5v-42h-1200v42q0 21 15 39.5t35 18.5h30l468 746l-135 183q-10 16 -5.5 34t20.5 28t34 5.5t28 -20.5l111 -148l112 150q9 16 27 20.5t34 -5zM600 200h377l-182 112l-195 534v-646z " />
+<glyph unicode="✉" d="M25 1100h1150q10 0 12.5 -5t-5.5 -13l-564 -567q-8 -8 -18 -8t-18 8l-564 567q-8 8 -5.5 13t12.5 5zM18 882l264 -264q8 -8 8 -18t-8 -18l-264 -264q-8 -8 -13 -5.5t-5 12.5v550q0 10 5 12.5t13 -5.5zM918 618l264 264q8 8 13 5.5t5 -12.5v-550q0 -10 -5 -12.5t-13 5.5 l-264 264q-8 8 -8 18t8 18zM818 482l364 -364q8 -8 5.5 -13t-12.5 -5h-1150q-10 0 -12.5 5t5.5 13l364 364q8 8 18 8t18 -8l164 -164q8 -8 18 -8t18 8l164 164q8 8 18 8t18 -8z" />
+<glyph unicode="✏" d="M1011 1210q19 0 33 -13l153 -153q13 -14 13 -33t-13 -33l-99 -92l-214 214l95 96q13 14 32 14zM1013 800l-615 -614l-214 214l614 614zM317 96l-333 -112l110 335z" />
+<glyph unicode="" d="M700 650v-550h250q21 0 35.5 -14.5t14.5 -35.5v-50h-800v50q0 21 14.5 35.5t35.5 14.5h250v550l-500 550h1200z" />
+<glyph unicode="" d="M368 1017l645 163q39 15 63 0t24 -49v-831q0 -55 -41.5 -95.5t-111.5 -63.5q-79 -25 -147 -4.5t-86 75t25.5 111.5t122.5 82q72 24 138 8v521l-600 -155v-606q0 -42 -44 -90t-109 -69q-79 -26 -147 -5.5t-86 75.5t25.5 111.5t122.5 82.5q72 24 138 7v639q0 38 14.5 59 t53.5 34z" />
+<glyph unicode="" d="M500 1191q100 0 191 -39t156.5 -104.5t104.5 -156.5t39 -191l-1 -2l1 -5q0 -141 -78 -262l275 -274q23 -26 22.5 -44.5t-22.5 -42.5l-59 -58q-26 -20 -46.5 -20t-39.5 20l-275 274q-119 -77 -261 -77l-5 1l-2 -1q-100 0 -191 39t-156.5 104.5t-104.5 156.5t-39 191 t39 191t104.5 156.5t156.5 104.5t191 39zM500 1022q-88 0 -162 -43t-117 -117t-43 -162t43 -162t117 -117t162 -43t162 43t117 117t43 162t-43 162t-117 117t-162 43z" />
+<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104z" />
+<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429z" />
+<glyph unicode="" d="M407 800l131 353q7 19 17.5 19t17.5 -19l129 -353h421q21 0 24 -8.5t-14 -20.5l-342 -249l130 -401q7 -20 -0.5 -25.5t-24.5 6.5l-343 246l-342 -247q-17 -12 -24.5 -6.5t-0.5 25.5l130 400l-347 251q-17 12 -14 20.5t23 8.5h429zM477 700h-240l197 -142l-74 -226 l193 139l195 -140l-74 229l192 140h-234l-78 211z" />
+<glyph unicode="" d="M600 1200q124 0 212 -88t88 -212v-250q0 -46 -31 -98t-69 -52v-75q0 -10 6 -21.5t15 -17.5l358 -230q9 -5 15 -16.5t6 -21.5v-93q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v93q0 10 6 21.5t15 16.5l358 230q9 6 15 17.5t6 21.5v75q-38 0 -69 52 t-31 98v250q0 124 88 212t212 88z" />
+<glyph unicode="" d="M25 1100h1150q10 0 17.5 -7.5t7.5 -17.5v-1050q0 -10 -7.5 -17.5t-17.5 -7.5h-1150q-10 0 -17.5 7.5t-7.5 17.5v1050q0 10 7.5 17.5t17.5 7.5zM100 1000v-100h100v100h-100zM875 1000h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5t17.5 -7.5h550 q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM1000 1000v-100h100v100h-100zM100 800v-100h100v100h-100zM1000 800v-100h100v100h-100zM100 600v-100h100v100h-100zM1000 600v-100h100v100h-100zM875 500h-550q-10 0 -17.5 -7.5t-7.5 -17.5v-350q0 -10 7.5 -17.5 t17.5 -7.5h550q10 0 17.5 7.5t7.5 17.5v350q0 10 -7.5 17.5t-17.5 7.5zM100 400v-100h100v100h-100zM1000 400v-100h100v100h-100zM100 200v-100h100v100h-100zM1000 200v-100h100v100h-100z" />
+<glyph unicode="" d="M50 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM50 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM650 500h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM850 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 700h200q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM850 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5 t35.5 14.5z" />
+<glyph unicode="" d="M50 1100h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 1100h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200 q0 21 14.5 35.5t35.5 14.5zM50 700h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 700h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700 q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM50 300h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5zM450 300h700q21 0 35.5 -14.5t14.5 -35.5v-200 q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M465 477l571 571q8 8 18 8t17 -8l177 -177q8 -7 8 -17t-8 -18l-783 -784q-7 -8 -17.5 -8t-17.5 8l-384 384q-8 8 -8 18t8 17l177 177q7 8 17 8t18 -8l171 -171q7 -7 18 -7t18 7z" />
+<glyph unicode="" d="M904 1083l178 -179q8 -8 8 -18.5t-8 -17.5l-267 -268l267 -268q8 -7 8 -17.5t-8 -18.5l-178 -178q-8 -8 -18.5 -8t-17.5 8l-268 267l-268 -267q-7 -8 -17.5 -8t-18.5 8l-178 178q-8 8 -8 18.5t8 17.5l267 268l-267 268q-8 7 -8 17.5t8 18.5l178 178q8 8 18.5 8t17.5 -8 l268 -267l268 268q7 7 17.5 7t18.5 -7z" />
+<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM425 900h150q10 0 17.5 -7.5t7.5 -17.5v-75h75q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5 t-17.5 -7.5h-75v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-75q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v75q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M507 1177q98 0 187.5 -38.5t154.5 -103.5t103.5 -154.5t38.5 -187.5q0 -141 -78 -262l300 -299q8 -8 8 -18.5t-8 -18.5l-109 -108q-7 -8 -17.5 -8t-18.5 8l-300 299q-119 -77 -261 -77q-98 0 -188 38.5t-154.5 103t-103 154.5t-38.5 188t38.5 187.5t103 154.5 t154.5 103.5t188 38.5zM506.5 1023q-89.5 0 -165.5 -44t-120 -120.5t-44 -166t44 -165.5t120 -120t165.5 -44t166 44t120.5 120t44 165.5t-44 166t-120.5 120.5t-166 44zM325 800h350q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-350q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M550 1200h100q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM800 975v166q167 -62 272 -209.5t105 -331.5q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5 t-184.5 123t-123 184.5t-45.5 224q0 184 105 331.5t272 209.5v-166q-103 -55 -165 -155t-62 -220q0 -116 57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5q0 120 -62 220t-165 155z" />
+<glyph unicode="" d="M1025 1200h150q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM725 800h150q10 0 17.5 -7.5t7.5 -17.5v-750q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v750 q0 10 7.5 17.5t17.5 7.5zM425 500h150q10 0 17.5 -7.5t7.5 -17.5v-450q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v450q0 10 7.5 17.5t17.5 7.5zM125 300h150q10 0 17.5 -7.5t7.5 -17.5v-250q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5 v250q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M600 1174q33 0 74 -5l38 -152l5 -1q49 -14 94 -39l5 -2l134 80q61 -48 104 -105l-80 -134l3 -5q25 -44 39 -93l1 -6l152 -38q5 -43 5 -73q0 -34 -5 -74l-152 -38l-1 -6q-15 -49 -39 -93l-3 -5l80 -134q-48 -61 -104 -105l-134 81l-5 -3q-44 -25 -94 -39l-5 -2l-38 -151 q-43 -5 -74 -5q-33 0 -74 5l-38 151l-5 2q-49 14 -94 39l-5 3l-134 -81q-60 48 -104 105l80 134l-3 5q-25 45 -38 93l-2 6l-151 38q-6 42 -6 74q0 33 6 73l151 38l2 6q13 48 38 93l3 5l-80 134q47 61 105 105l133 -80l5 2q45 25 94 39l5 1l38 152q43 5 74 5zM600 815 q-89 0 -152 -63t-63 -151.5t63 -151.5t152 -63t152 63t63 151.5t-63 151.5t-152 63z" />
+<glyph unicode="" d="M500 1300h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-75h-1100v75q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5zM500 1200v-100h300v100h-300zM1100 900v-800q0 -41 -29.5 -70.5t-70.5 -29.5h-700q-41 0 -70.5 29.5t-29.5 70.5 v800h900zM300 800v-700h100v700h-100zM500 800v-700h100v700h-100zM700 800v-700h100v700h-100zM900 800v-700h100v700h-100z" />
+<glyph unicode="" d="M18 618l620 608q8 7 18.5 7t17.5 -7l608 -608q8 -8 5.5 -13t-12.5 -5h-175v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v375h-300v-375q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v575h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="" d="M600 1200v-400q0 -41 29.5 -70.5t70.5 -29.5h300v-650q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5h450zM1000 800h-250q-21 0 -35.5 14.5t-14.5 35.5v250z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h50q10 0 17.5 -7.5t7.5 -17.5v-275h175q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M1300 0h-538l-41 400h-242l-41 -400h-538l431 1200h209l-21 -300h162l-20 300h208zM515 800l-27 -300h224l-27 300h-170z" />
+<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-450h191q20 0 25.5 -11.5t-7.5 -27.5l-327 -400q-13 -16 -32 -16t-32 16l-327 400q-13 16 -7.5 27.5t25.5 11.5h191v450q0 21 14.5 35.5t35.5 14.5zM1125 400h50q10 0 17.5 -7.5t7.5 -17.5v-350q0 -10 -7.5 -17.5t-17.5 -7.5 h-1050q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h50q10 0 17.5 -7.5t7.5 -17.5v-175h900v175q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM525 900h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -275q-13 -16 -32 -16t-32 16l-223 275q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z " />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM632 914l223 -275q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5l223 275q13 16 32 16 t32 -16z" />
+<glyph unicode="" d="M225 1200h750q10 0 19.5 -7t12.5 -17l186 -652q7 -24 7 -49v-425q0 -12 -4 -27t-9 -17q-12 -6 -37 -6h-1100q-12 0 -27 4t-17 8q-6 13 -6 38l1 425q0 25 7 49l185 652q3 10 12.5 17t19.5 7zM878 1000h-556q-10 0 -19 -7t-11 -18l-87 -450q-2 -11 4 -18t16 -7h150 q10 0 19.5 -7t11.5 -17l38 -152q2 -10 11.5 -17t19.5 -7h250q10 0 19.5 7t11.5 17l38 152q2 10 11.5 17t19.5 7h150q10 0 16 7t4 18l-87 450q-2 11 -11 18t-19 7z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM540 820l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-362q0 -10 -7.5 -17.5t-17.5 -7.5h-362q-11 0 -13 5.5t5 12.5l133 133q-109 76 -238 76q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5h150q0 -117 -45.5 -224 t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117z" />
+<glyph unicode="" d="M947 1060l135 135q7 7 12.5 5t5.5 -13v-361q0 -11 -7.5 -18.5t-18.5 -7.5h-361q-11 0 -13 5.5t5 12.5l134 134q-110 75 -239 75q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5h-150q0 117 45.5 224t123 184.5t184.5 123t224 45.5q192 0 347 -117zM1027 600h150 q0 -117 -45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5q-192 0 -348 118l-134 -134q-7 -8 -12.5 -5.5t-5.5 12.5v360q0 11 7.5 18.5t18.5 7.5h360q10 0 12.5 -5.5t-5.5 -12.5l-133 -133q110 -76 240 -76q116 0 214.5 57t155.5 155.5t57 214.5z" />
+<glyph unicode="" d="M125 1200h1050q10 0 17.5 -7.5t7.5 -17.5v-1150q0 -10 -7.5 -17.5t-17.5 -7.5h-1050q-10 0 -17.5 7.5t-7.5 17.5v1150q0 10 7.5 17.5t17.5 7.5zM1075 1000h-850q-10 0 -17.5 -7.5t-7.5 -17.5v-850q0 -10 7.5 -17.5t17.5 -7.5h850q10 0 17.5 7.5t7.5 17.5v850 q0 10 -7.5 17.5t-17.5 7.5zM325 900h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 900h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 700h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 700h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 500h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 500h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5zM325 300h50q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM525 300h450q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-450q-10 0 -17.5 7.5t-7.5 17.5v50 q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M900 800v200q0 83 -58.5 141.5t-141.5 58.5h-300q-82 0 -141 -59t-59 -141v-200h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h900q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-100zM400 800v150q0 21 15 35.5t35 14.5h200 q20 0 35 -14.5t15 -35.5v-150h-300z" />
+<glyph unicode="" d="M125 1100h50q10 0 17.5 -7.5t7.5 -17.5v-1075h-100v1075q0 10 7.5 17.5t17.5 7.5zM1075 1052q4 0 9 -2q16 -6 16 -23v-421q0 -6 -3 -12q-33 -59 -66.5 -99t-65.5 -58t-56.5 -24.5t-52.5 -6.5q-26 0 -57.5 6.5t-52.5 13.5t-60 21q-41 15 -63 22.5t-57.5 15t-65.5 7.5 q-85 0 -160 -57q-7 -5 -15 -5q-6 0 -11 3q-14 7 -14 22v438q22 55 82 98.5t119 46.5q23 2 43 0.5t43 -7t32.5 -8.5t38 -13t32.5 -11q41 -14 63.5 -21t57 -14t63.5 -7q103 0 183 87q7 8 18 8z" />
+<glyph unicode="" d="M600 1175q116 0 227 -49.5t192.5 -131t131 -192.5t49.5 -227v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v300q0 127 -70.5 231.5t-184.5 161.5t-245 57t-245 -57t-184.5 -161.5t-70.5 -231.5v-300q0 -10 -7.5 -17.5t-17.5 -7.5h-50 q-10 0 -17.5 7.5t-7.5 17.5v300q0 116 49.5 227t131 192.5t192.5 131t227 49.5zM220 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460q0 8 6 14t14 6zM820 500h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14v460 q0 8 6 14t14 6z" />
+<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM900 668l120 120q7 7 17 7t17 -7l34 -34q7 -7 7 -17t-7 -17l-120 -120l120 -120q7 -7 7 -17 t-7 -17l-34 -34q-7 -7 -17 -7t-17 7l-120 119l-120 -119q-7 -7 -17 -7t-17 7l-34 34q-7 7 -7 17t7 17l119 120l-119 120q-7 7 -7 17t7 17l34 34q7 8 17 8t17 -8z" />
+<glyph unicode="" d="M321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6 l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238q-6 8 -4.5 18t9.5 17l29 22q7 5 15 5z" />
+<glyph unicode="" d="M967 1004h3q11 -1 17 -10q135 -179 135 -396q0 -105 -34 -206.5t-98 -185.5q-7 -9 -17 -10h-3q-9 0 -16 6l-42 34q-8 6 -9 16t5 18q111 150 111 328q0 90 -29.5 176t-84.5 157q-6 9 -5 19t10 16l42 33q7 5 15 5zM321 814l258 172q9 6 15 2.5t6 -13.5v-750q0 -10 -6 -13.5 t-15 2.5l-258 172q-21 14 -46 14h-250q-10 0 -17.5 7.5t-7.5 17.5v350q0 10 7.5 17.5t17.5 7.5h250q25 0 46 14zM766 900h4q10 -1 16 -10q96 -129 96 -290q0 -154 -90 -281q-6 -9 -17 -10l-3 -1q-9 0 -16 6l-29 23q-7 7 -8.5 16.5t4.5 17.5q72 103 72 229q0 132 -78 238 q-6 8 -4.5 18.5t9.5 16.5l29 22q7 5 15 5z" />
+<glyph unicode="" d="M500 900h100v-100h-100v-100h-400v-100h-100v600h500v-300zM1200 700h-200v-100h200v-200h-300v300h-200v300h-100v200h600v-500zM100 1100v-300h300v300h-300zM800 1100v-300h300v300h-300zM300 900h-100v100h100v-100zM1000 900h-100v100h100v-100zM300 500h200v-500 h-500v500h200v100h100v-100zM800 300h200v-100h-100v-100h-200v100h-100v100h100v200h-200v100h300v-300zM100 400v-300h300v300h-300zM300 200h-100v100h100v-100zM1200 200h-100v100h100v-100zM700 0h-100v100h100v-100zM1200 0h-300v100h300v-100z" />
+<glyph unicode="" d="M100 200h-100v1000h100v-1000zM300 200h-100v1000h100v-1000zM700 200h-200v1000h200v-1000zM900 200h-100v1000h100v-1000zM1200 200h-200v1000h200v-1000zM400 0h-300v100h300v-100zM600 0h-100v91h100v-91zM800 0h-100v91h100v-91zM1100 0h-200v91h200v-91z" />
+<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="" d="M500 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-682 682l1 475q0 10 7.5 17.5t17.5 7.5h474zM800 1200l682 -682q8 -8 8 -18t-8 -18l-464 -464q-8 -8 -18 -8t-18 8l-56 56l424 426l-700 700h150zM319.5 1024.5q-29.5 29.5 -71 29.5t-71 -29.5 t-29.5 -71.5t29.5 -71.5t71 -29.5t71 29.5t29.5 71.5t-29.5 71.5z" />
+<glyph unicode="" d="M300 1200h825q75 0 75 -75v-900q0 -25 -18 -43l-64 -64q-8 -8 -13 -5.5t-5 12.5v950q0 10 -7.5 17.5t-17.5 7.5h-700q-25 0 -43 -18l-64 -64q-8 -8 -5.5 -13t12.5 -5h700q10 0 17.5 -7.5t7.5 -17.5v-950q0 -10 -7.5 -17.5t-17.5 -7.5h-850q-10 0 -17.5 7.5t-7.5 17.5v975 q0 25 18 43l139 139q18 18 43 18z" />
+<glyph unicode="" d="M250 1200h800q21 0 35.5 -14.5t14.5 -35.5v-1150l-450 444l-450 -445v1151q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M822 1200h-444q-11 0 -19 -7.5t-9 -17.5l-78 -301q-7 -24 7 -45l57 -108q6 -9 17.5 -15t21.5 -6h450q10 0 21.5 6t17.5 15l62 108q14 21 7 45l-83 301q-1 10 -9 17.5t-19 7.5zM1175 800h-150q-10 0 -21 -6.5t-15 -15.5l-78 -156q-4 -9 -15 -15.5t-21 -6.5h-550 q-10 0 -21 6.5t-15 15.5l-78 156q-4 9 -15 15.5t-21 6.5h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-650q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h750q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5 t7.5 17.5v650q0 10 -7.5 17.5t-17.5 7.5zM850 200h-500q-10 0 -19.5 -7t-11.5 -17l-38 -152q-2 -10 3.5 -17t15.5 -7h600q10 0 15.5 7t3.5 17l-38 152q-2 10 -11.5 17t-19.5 7z" />
+<glyph unicode="" d="M500 1100h200q56 0 102.5 -20.5t72.5 -50t44 -59t25 -50.5l6 -20h150q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5h150q2 8 6.5 21.5t24 48t45 61t72 48t102.5 21.5zM900 800v-100 h100v100h-100zM600 730q-95 0 -162.5 -67.5t-67.5 -162.5t67.5 -162.5t162.5 -67.5t162.5 67.5t67.5 162.5t-67.5 162.5t-162.5 67.5zM600 603q43 0 73 -30t30 -73t-30 -73t-73 -30t-73 30t-30 73t30 73t73 30z" />
+<glyph unicode="" d="M681 1199l385 -998q20 -50 60 -92q18 -19 36.5 -29.5t27.5 -11.5l10 -2v-66h-417v66q53 0 75 43.5t5 88.5l-82 222h-391q-58 -145 -92 -234q-11 -34 -6.5 -57t25.5 -37t46 -20t55 -6v-66h-365v66q56 24 84 52q12 12 25 30.5t20 31.5l7 13l399 1006h93zM416 521h340 l-162 457z" />
+<glyph unicode="" d="M753 641q5 -1 14.5 -4.5t36 -15.5t50.5 -26.5t53.5 -40t50.5 -54.5t35.5 -70t14.5 -87q0 -67 -27.5 -125.5t-71.5 -97.5t-98.5 -66.5t-108.5 -40.5t-102 -13h-500v89q41 7 70.5 32.5t29.5 65.5v827q0 24 -0.5 34t-3.5 24t-8.5 19.5t-17 13.5t-28 12.5t-42.5 11.5v71 l471 -1q57 0 115.5 -20.5t108 -57t80.5 -94t31 -124.5q0 -51 -15.5 -96.5t-38 -74.5t-45 -50.5t-38.5 -30.5zM400 700h139q78 0 130.5 48.5t52.5 122.5q0 41 -8.5 70.5t-29.5 55.5t-62.5 39.5t-103.5 13.5h-118v-350zM400 200h216q80 0 121 50.5t41 130.5q0 90 -62.5 154.5 t-156.5 64.5h-159v-400z" />
+<glyph unicode="" d="M877 1200l2 -57q-83 -19 -116 -45.5t-40 -66.5l-132 -839q-9 -49 13 -69t96 -26v-97h-500v97q186 16 200 98l173 832q3 17 3 30t-1.5 22.5t-9 17.5t-13.5 12.5t-21.5 10t-26 8.5t-33.5 10q-13 3 -19 5v57h425z" />
+<glyph unicode="" d="M1300 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM175 1000h-75v-800h75l-125 -167l-125 167h75v800h-75l125 167z" />
+<glyph unicode="" d="M1100 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-650q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v650h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM1167 50l-167 -125v75h-800v-75l-167 125l167 125v-75h800v75z" />
+<glyph unicode="" d="M50 1100h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M250 1100h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM250 500h700q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000 q-21 0 -35.5 14.5t-14.5 35.5zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5zM0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5z" />
+<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 800h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 500h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 1100h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 800h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 500h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 500h800q21 0 35.5 -14.5t14.5 -35.5v-100 q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM350 200h800 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M400 0h-100v1100h100v-1100zM550 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM267 550l-167 -125v75h-200v100h200v75zM550 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM550 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM900 0h-100v1100h100v-1100zM50 800h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM1100 600h200v-100h-200v-75l-167 125l167 125v-75zM50 500h300q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5zM50 200h600 q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-600q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M75 1000h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53v650q0 31 22 53t53 22zM1200 300l-300 300l300 300v-600z" />
+<glyph unicode="" d="M44 1100h1112q18 0 31 -13t13 -31v-1012q0 -18 -13 -31t-31 -13h-1112q-18 0 -31 13t-13 31v1012q0 18 13 31t31 13zM100 1000v-737l247 182l298 -131l-74 156l293 318l236 -288v500h-1000zM342 884q56 0 95 -39t39 -94.5t-39 -95t-95 -39.5t-95 39.5t-39 95t39 94.5 t95 39z" />
+<glyph unicode="" d="M648 1169q117 0 216 -60t156.5 -161t57.5 -218q0 -115 -70 -258q-69 -109 -158 -225.5t-143 -179.5l-54 -62q-9 8 -25.5 24.5t-63.5 67.5t-91 103t-98.5 128t-95.5 148q-60 132 -60 249q0 88 34 169.5t91.5 142t137 96.5t166.5 36zM652.5 974q-91.5 0 -156.5 -65 t-65 -157t65 -156.5t156.5 -64.5t156.5 64.5t65 156.5t-65 157t-156.5 65z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 173v854q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57z" />
+<glyph unicode="" d="M554 1295q21 -72 57.5 -143.5t76 -130t83 -118t82.5 -117t70 -116t49.5 -126t18.5 -136.5q0 -71 -25.5 -135t-68.5 -111t-99 -82t-118.5 -54t-125.5 -23q-84 5 -161.5 34t-139.5 78.5t-99 125t-37 164.5q0 69 18 136.5t49.5 126.5t69.5 116.5t81.5 117.5t83.5 119 t76.5 131t58.5 143zM344 710q-23 -33 -43.5 -70.5t-40.5 -102.5t-17 -123q1 -37 14.5 -69.5t30 -52t41 -37t38.5 -24.5t33 -15q21 -7 32 -1t13 22l6 34q2 10 -2.5 22t-13.5 19q-5 4 -14 12t-29.5 40.5t-32.5 73.5q-26 89 6 271q2 11 -6 11q-8 1 -15 -10z" />
+<glyph unicode="" d="M1000 1013l108 115q2 1 5 2t13 2t20.5 -1t25 -9.5t28.5 -21.5q22 -22 27 -43t0 -32l-6 -10l-108 -115zM350 1100h400q50 0 105 -13l-187 -187h-368q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v182l200 200v-332 q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM1009 803l-362 -362l-161 -50l55 170l355 355z" />
+<glyph unicode="" d="M350 1100h361q-164 -146 -216 -200h-195q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-103q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M824 1073l339 -301q8 -7 8 -17.5t-8 -17.5l-340 -306q-7 -6 -12.5 -4t-6.5 11v203q-26 1 -54.5 0t-78.5 -7.5t-92 -17.5t-86 -35t-70 -57q10 59 33 108t51.5 81.5t65 58.5t68.5 40.5t67 24.5t56 13.5t40 4.5v210q1 10 6.5 12.5t13.5 -4.5z" />
+<glyph unicode="" d="M350 1100h350q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-219q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5z M643 639l395 395q7 7 17.5 7t17.5 -7l101 -101q7 -7 7 -17.5t-7 -17.5l-531 -532q-7 -7 -17.5 -7t-17.5 7l-248 248q-7 7 -7 17.5t7 17.5l101 101q7 7 17.5 7t17.5 -7l111 -111q8 -7 18 -7t18 7z" />
+<glyph unicode="" d="M318 918l264 264q8 8 18 8t18 -8l260 -264q7 -8 4.5 -13t-12.5 -5h-170v-200h200v173q0 10 5 12t13 -5l264 -260q8 -7 8 -17.5t-8 -17.5l-264 -265q-8 -7 -13 -5t-5 12v173h-200v-200h170q10 0 12.5 -5t-4.5 -13l-260 -264q-8 -8 -18 -8t-18 8l-264 264q-8 8 -5.5 13 t12.5 5h175v200h-200v-173q0 -10 -5 -12t-13 5l-264 265q-8 7 -8 17.5t8 17.5l264 260q8 7 13 5t5 -12v-173h200v200h-175q-10 0 -12.5 5t5.5 13z" />
+<glyph unicode="" d="M250 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M50 1100h100q21 0 35.5 -14.5t14.5 -35.5v-438l464 453q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5 t-14.5 35.5v1000q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M1200 1050v-1000q0 -21 -10.5 -25t-25.5 10l-464 453v-438q0 -21 -10.5 -25t-25.5 10l-492 480q-15 14 -15 35t15 35l492 480q15 14 25.5 10t10.5 -25v-438l464 453q15 14 25.5 10t10.5 -25z" />
+<glyph unicode="" d="M243 1074l814 -498q18 -11 18 -26t-18 -26l-814 -498q-18 -11 -30.5 -4t-12.5 28v1000q0 21 12.5 28t30.5 -4z" />
+<glyph unicode="" d="M250 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM650 1000h200q21 0 35.5 -14.5t14.5 -35.5v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v800 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M1100 950v-800q0 -21 -14.5 -35.5t-35.5 -14.5h-800q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="" d="M500 612v438q0 21 10.5 25t25.5 -10l492 -480q15 -14 15 -35t-15 -35l-492 -480q-15 -14 -25.5 -10t-10.5 25v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10z" />
+<glyph unicode="" d="M1048 1102l100 1q20 0 35 -14.5t15 -35.5l5 -1000q0 -21 -14.5 -35.5t-35.5 -14.5l-100 -1q-21 0 -35.5 14.5t-14.5 35.5l-2 437l-463 -454q-14 -15 -24.5 -10.5t-10.5 25.5l-2 437l-462 -455q-15 -14 -25.5 -9.5t-10.5 24.5l-5 1000q0 21 10.5 25.5t25.5 -10.5l466 -450 l-2 438q0 20 10.5 24.5t25.5 -9.5l466 -451l-2 438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M850 1100h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-464 -453q-15 -14 -25.5 -10t-10.5 25v1000q0 21 10.5 25t25.5 -10l464 -453v438q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M686 1081l501 -540q15 -15 10.5 -26t-26.5 -11h-1042q-22 0 -26.5 11t10.5 26l501 540q15 15 36 15t36 -15zM150 400h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M885 900l-352 -353l352 -353l-197 -198l-552 552l552 550z" />
+<glyph unicode="" d="M1064 547l-551 -551l-198 198l353 353l-353 353l198 198z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM650 900h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-150 q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5h150v-150q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v150h150q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-150v150q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM850 700h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5 t35.5 -14.5h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM741.5 913q-12.5 0 -21.5 -9l-120 -120l-120 120q-9 9 -21.5 9 t-21.5 -9l-141 -141q-9 -9 -9 -21.5t9 -21.5l120 -120l-120 -120q-9 -9 -9 -21.5t9 -21.5l141 -141q9 -9 21.5 -9t21.5 9l120 120l120 -120q9 -9 21.5 -9t21.5 9l141 141q9 9 9 21.5t-9 21.5l-120 120l120 120q9 9 9 21.5t-9 21.5l-141 141q-9 9 -21.5 9z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM546 623l-84 85q-7 7 -17.5 7t-18.5 -7l-139 -139q-7 -8 -7 -18t7 -18 l242 -241q7 -8 17.5 -8t17.5 8l375 375q7 7 7 17.5t-7 18.5l-139 139q-7 7 -17.5 7t-17.5 -7z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM588 941q-29 0 -59 -5.5t-63 -20.5t-58 -38.5t-41.5 -63t-16.5 -89.5 q0 -25 20 -25h131q30 -5 35 11q6 20 20.5 28t45.5 8q20 0 31.5 -10.5t11.5 -28.5q0 -23 -7 -34t-26 -18q-1 0 -13.5 -4t-19.5 -7.5t-20 -10.5t-22 -17t-18.5 -24t-15.5 -35t-8 -46q-1 -8 5.5 -16.5t20.5 -8.5h173q7 0 22 8t35 28t37.5 48t29.5 74t12 100q0 47 -17 83 t-42.5 57t-59.5 34.5t-64 18t-59 4.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM675 1000h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5 t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5zM675 700h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h75v-200h-75q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h350q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5 t-17.5 7.5h-75v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="" d="M525 1200h150q10 0 17.5 -7.5t7.5 -17.5v-194q103 -27 178.5 -102.5t102.5 -178.5h194q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-194q-27 -103 -102.5 -178.5t-178.5 -102.5v-194q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v194 q-103 27 -178.5 102.5t-102.5 178.5h-194q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h194q27 103 102.5 178.5t178.5 102.5v194q0 10 7.5 17.5t17.5 7.5zM700 893v-168q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v168q-68 -23 -119 -74 t-74 -119h168q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-168q23 -68 74 -119t119 -74v168q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-168q68 23 119 74t74 119h-168q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h168 q-23 68 -74 119t-119 74z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM759 823l64 -64q7 -7 7 -17.5t-7 -17.5l-124 -124l124 -124q7 -7 7 -17.5t-7 -17.5l-64 -64q-7 -7 -17.5 -7t-17.5 7l-124 124l-124 -124q-7 -7 -17.5 -7t-17.5 7l-64 64 q-7 7 -7 17.5t7 17.5l124 124l-124 124q-7 7 -7 17.5t7 17.5l64 64q7 7 17.5 7t17.5 -7l124 -124l124 124q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5t57 -214.5 t155.5 -155.5t214.5 -57t214.5 57t155.5 155.5t57 214.5t-57 214.5t-155.5 155.5t-214.5 57zM782 788l106 -106q7 -7 7 -17.5t-7 -17.5l-320 -321q-8 -7 -18 -7t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l197 197q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM600 1027q-116 0 -214.5 -57t-155.5 -155.5t-57 -214.5q0 -120 65 -225 l587 587q-105 65 -225 65zM965 819l-584 -584q104 -62 219 -62q116 0 214.5 57t155.5 155.5t57 214.5q0 115 -62 219z" />
+<glyph unicode="" d="M39 582l522 427q16 13 27.5 8t11.5 -26v-291h550q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-550v-291q0 -21 -11.5 -26t-27.5 8l-522 427q-16 13 -16 32t16 32z" />
+<glyph unicode="" d="M639 1009l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291h-550q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h550v291q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="" d="M682 1161l427 -522q13 -16 8 -27.5t-26 -11.5h-291v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v550h-291q-21 0 -26 11.5t8 27.5l427 522q13 16 32 16t32 -16z" />
+<glyph unicode="" d="M550 1200h200q21 0 35.5 -14.5t14.5 -35.5v-550h291q21 0 26 -11.5t-8 -27.5l-427 -522q-13 -16 -32 -16t-32 16l-427 522q-13 16 -8 27.5t26 11.5h291v550q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M639 1109l522 -427q16 -13 16 -32t-16 -32l-522 -427q-16 -13 -27.5 -8t-11.5 26v291q-94 -2 -182 -20t-170.5 -52t-147 -92.5t-100.5 -135.5q5 105 27 193.5t67.5 167t113 135t167 91.5t225.5 42v262q0 21 11.5 26t27.5 -8z" />
+<glyph unicode="" d="M850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5zM350 0h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249 q8 7 18 7t18 -7l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5z" />
+<glyph unicode="" d="M1014 1120l106 -106q7 -8 7 -18t-7 -18l-249 -249l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l249 249q8 7 18 7t18 -7zM250 600h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-249 -249q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l249 249l-94 94q-14 14 -10 24.5t25 10.5z" />
+<glyph unicode="" d="M600 1177q117 0 224 -45.5t184.5 -123t123 -184.5t45.5 -224t-45.5 -224t-123 -184.5t-184.5 -123t-224 -45.5t-224 45.5t-184.5 123t-123 184.5t-45.5 224t45.5 224t123 184.5t184.5 123t224 45.5zM704 900h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5 t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM675 400h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="" d="M260 1200q9 0 19 -2t15 -4l5 -2q22 -10 44 -23l196 -118q21 -13 36 -24q29 -21 37 -12q11 13 49 35l196 118q22 13 45 23q17 7 38 7q23 0 47 -16.5t37 -33.5l13 -16q14 -21 18 -45l25 -123l8 -44q1 -9 8.5 -14.5t17.5 -5.5h61q10 0 17.5 -7.5t7.5 -17.5v-50 q0 -10 -7.5 -17.5t-17.5 -7.5h-50q-10 0 -17.5 -7.5t-7.5 -17.5v-175h-400v300h-200v-300h-400v175q0 10 -7.5 17.5t-17.5 7.5h-50q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5h61q11 0 18 3t7 8q0 4 9 52l25 128q5 25 19 45q2 3 5 7t13.5 15t21.5 19.5t26.5 15.5 t29.5 7zM915 1079l-166 -162q-7 -7 -5 -12t12 -5h219q10 0 15 7t2 17l-51 149q-3 10 -11 12t-15 -6zM463 917l-177 157q-8 7 -16 5t-11 -12l-51 -143q-3 -10 2 -17t15 -7h231q11 0 12.5 5t-5.5 12zM500 0h-375q-10 0 -17.5 7.5t-7.5 17.5v375h400v-400zM1100 400v-375 q0 -10 -7.5 -17.5t-17.5 -7.5h-375v400h400z" />
+<glyph unicode="" d="M1165 1190q8 3 21 -6.5t13 -17.5q-2 -178 -24.5 -323.5t-55.5 -245.5t-87 -174.5t-102.5 -118.5t-118 -68.5t-118.5 -33t-120 -4.5t-105 9.5t-90 16.5q-61 12 -78 11q-4 1 -12.5 0t-34 -14.5t-52.5 -40.5l-153 -153q-26 -24 -37 -14.5t-11 43.5q0 64 42 102q8 8 50.5 45 t66.5 58q19 17 35 47t13 61q-9 55 -10 102.5t7 111t37 130t78 129.5q39 51 80 88t89.5 63.5t94.5 45t113.5 36t129 31t157.5 37t182 47.5zM1116 1098q-8 9 -22.5 -3t-45.5 -50q-38 -47 -119 -103.5t-142 -89.5l-62 -33q-56 -30 -102 -57t-104 -68t-102.5 -80.5t-85.5 -91 t-64 -104.5q-24 -56 -31 -86t2 -32t31.5 17.5t55.5 59.5q25 30 94 75.5t125.5 77.5t147.5 81q70 37 118.5 69t102 79.5t99 111t86.5 148.5q22 50 24 60t-6 19z" />
+<glyph unicode="" d="M653 1231q-39 -67 -54.5 -131t-10.5 -114.5t24.5 -96.5t47.5 -80t63.5 -62.5t68.5 -46.5t65 -30q-4 7 -17.5 35t-18.5 39.5t-17 39.5t-17 43t-13 42t-9.5 44.5t-2 42t4 43t13.5 39t23 38.5q96 -42 165 -107.5t105 -138t52 -156t13 -159t-19 -149.5q-13 -55 -44 -106.5 t-68 -87t-78.5 -64.5t-72.5 -45t-53 -22q-72 -22 -127 -11q-31 6 -13 19q6 3 17 7q13 5 32.5 21t41 44t38.5 63.5t21.5 81.5t-6.5 94.5t-50 107t-104 115.5q10 -104 -0.5 -189t-37 -140.5t-65 -93t-84 -52t-93.5 -11t-95 24.5q-80 36 -131.5 114t-53.5 171q-2 23 0 49.5 t4.5 52.5t13.5 56t27.5 60t46 64.5t69.5 68.5q-8 -53 -5 -102.5t17.5 -90t34 -68.5t44.5 -39t49 -2q31 13 38.5 36t-4.5 55t-29 64.5t-36 75t-26 75.5q-15 85 2 161.5t53.5 128.5t85.5 92.5t93.5 61t81.5 25.5z" />
+<glyph unicode="" d="M600 1094q82 0 160.5 -22.5t140 -59t116.5 -82.5t94.5 -95t68 -95t42.5 -82.5t14 -57.5t-14 -57.5t-43 -82.5t-68.5 -95t-94.5 -95t-116.5 -82.5t-140 -59t-159.5 -22.5t-159.5 22.5t-140 59t-116.5 82.5t-94.5 95t-68.5 95t-43 82.5t-14 57.5t14 57.5t42.5 82.5t68 95 t94.5 95t116.5 82.5t140 59t160.5 22.5zM888 829q-15 15 -18 12t5 -22q25 -57 25 -119q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 59 23 114q8 19 4.5 22t-17.5 -12q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q22 -36 47 -71t70 -82t92.5 -81t113 -58.5t133.5 -24.5 t133.5 24t113 58.5t92.5 81.5t70 81.5t47 70.5q11 18 9 42.5t-14 41.5q-90 117 -163 189zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l35 34q14 15 12.5 33.5t-16.5 33.5q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="" d="M592 0h-148l31 120q-91 20 -175.5 68.5t-143.5 106.5t-103.5 119t-66.5 110t-22 76q0 21 14 57.5t42.5 82.5t68 95t94.5 95t116.5 82.5t140 59t160.5 22.5q61 0 126 -15l32 121h148zM944 770l47 181q108 -85 176.5 -192t68.5 -159q0 -26 -19.5 -71t-59.5 -102t-93 -112 t-129 -104.5t-158 -75.5l46 173q77 49 136 117t97 131q11 18 9 42.5t-14 41.5q-54 70 -107 130zM310 824q-70 -69 -160 -184q-13 -16 -15 -40.5t9 -42.5q18 -30 39 -60t57 -70.5t74 -73t90 -61t105 -41.5l41 154q-107 18 -178.5 101.5t-71.5 193.5q0 59 23 114q8 19 4.5 22 t-17.5 -12zM448 727l-35 -36q-15 -15 -19.5 -38.5t4.5 -41.5q37 -68 93 -116q16 -13 38.5 -11t36.5 17l12 11l22 86l-3 4q-44 44 -89 117q-11 18 -28 20t-32 -12z" />
+<glyph unicode="" d="M-90 100l642 1066q20 31 48 28.5t48 -35.5l642 -1056q21 -32 7.5 -67.5t-50.5 -35.5h-1294q-37 0 -50.5 34t7.5 66zM155 200h345v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h345l-445 723zM496 700h208q20 0 32 -14.5t8 -34.5l-58 -252 q-4 -20 -21.5 -34.5t-37.5 -14.5h-54q-20 0 -37.5 14.5t-21.5 34.5l-58 252q-4 20 8 34.5t32 14.5z" />
+<glyph unicode="" d="M650 1200q62 0 106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -93 100 -113v-64q0 -21 -13 -29t-32 1l-205 128l-205 -128q-19 -9 -32 -1t-13 29v64q0 20 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5v41 q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44z" />
+<glyph unicode="" d="M850 1200h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-150h-1100v150q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-50h500v50q0 21 14.5 35.5t35.5 14.5zM1100 800v-750q0 -21 -14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v750h1100zM100 600v-100h100v100h-100zM300 600v-100h100v100h-100zM500 600v-100h100v100h-100zM700 600v-100h100v100h-100zM900 600v-100h100v100h-100zM100 400v-100h100v100h-100zM300 400v-100h100v100h-100zM500 400 v-100h100v100h-100zM700 400v-100h100v100h-100zM900 400v-100h100v100h-100zM100 200v-100h100v100h-100zM300 200v-100h100v100h-100zM500 200v-100h100v100h-100zM700 200v-100h100v100h-100zM900 200v-100h100v100h-100z" />
+<glyph unicode="" d="M1135 1165l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-159l-600 -600h-291q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h209l600 600h241v150q0 21 10.5 25t24.5 -10zM522 819l-141 -141l-122 122h-209q-21 0 -35.5 14.5 t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h291zM1135 565l249 -230q15 -14 15 -35t-15 -35l-249 -230q-14 -14 -24.5 -10t-10.5 25v150h-241l-181 181l141 141l122 -122h159v150q0 21 10.5 25t24.5 -10z" />
+<glyph unicode="" d="M100 1100h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5v600q0 41 29.5 70.5t70.5 29.5z" />
+<glyph unicode="" d="M150 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM850 1200h200q21 0 35.5 -14.5t14.5 -35.5v-250h-300v250q0 21 14.5 35.5t35.5 14.5zM1100 800v-300q0 -41 -3 -77.5t-15 -89.5t-32 -96t-58 -89t-89 -77t-129 -51t-174 -20t-174 20 t-129 51t-89 77t-58 89t-32 96t-15 89.5t-3 77.5v300h300v-250v-27v-42.5t1.5 -41t5 -38t10 -35t16.5 -30t25.5 -24.5t35 -19t46.5 -12t60 -4t60 4.5t46.5 12.5t35 19.5t25 25.5t17 30.5t10 35t5 38t2 40.5t-0.5 42v25v250h300z" />
+<glyph unicode="" d="M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z" />
+<glyph unicode="" d="M1101 789l-550 -551l-551 551l198 199l353 -353l353 353z" />
+<glyph unicode="" d="M404 1000h746q21 0 35.5 -14.5t14.5 -35.5v-551h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v401h-381zM135 984l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-400h385l215 -200h-750q-21 0 -35.5 14.5 t-14.5 35.5v550h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="" d="M56 1200h94q17 0 31 -11t18 -27l38 -162h896q24 0 39 -18.5t10 -42.5l-100 -475q-5 -21 -27 -42.5t-55 -21.5h-633l48 -200h535q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-50q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-300v-50 q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v50h-31q-18 0 -32.5 10t-20.5 19l-5 10l-201 961h-54q-20 0 -35 14.5t-15 35.5t15 35.5t35 14.5z" />
+<glyph unicode="" d="M1200 1000v-100h-1200v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500zM0 800h1200v-800h-1200v800z" />
+<glyph unicode="" d="M200 800l-200 -400v600h200q0 41 29.5 70.5t70.5 29.5h300q42 0 71 -29.5t29 -70.5h500v-200h-1000zM1500 700l-300 -700h-1200l300 700h1200z" />
+<glyph unicode="" d="M635 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-601h150q21 0 25 -10.5t-10 -24.5l-230 -249q-14 -15 -35 -15t-35 15l-230 249q-14 14 -10 24.5t25 10.5h150v601h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="" d="M936 864l249 -229q14 -15 14 -35.5t-14 -35.5l-249 -229q-15 -15 -25.5 -10.5t-10.5 24.5v151h-600v-151q0 -20 -10.5 -24.5t-25.5 10.5l-249 229q-14 15 -14 35.5t14 35.5l249 229q15 15 25.5 10.5t10.5 -25.5v-149h600v149q0 21 10.5 25.5t25.5 -10.5z" />
+<glyph unicode="" d="M1169 400l-172 732q-5 23 -23 45.5t-38 22.5h-672q-20 0 -38 -20t-23 -41l-172 -739h1138zM1100 300h-1000q-41 0 -70.5 -29.5t-29.5 -70.5v-100q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v100q0 41 -29.5 70.5t-70.5 29.5zM800 100v100h100v-100h-100 zM1000 100v100h100v-100h-100z" />
+<glyph unicode="" d="M1150 1100q21 0 35.5 -14.5t14.5 -35.5v-850q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v850q0 21 14.5 35.5t35.5 14.5zM1000 200l-675 200h-38l47 -276q3 -16 -5.5 -20t-29.5 -4h-7h-84q-20 0 -34.5 14t-18.5 35q-55 337 -55 351v250v6q0 16 1 23.5t6.5 14 t17.5 6.5h200l675 250v-850zM0 750v-250q-4 0 -11 0.5t-24 6t-30 15t-24 30t-11 48.5v50q0 26 10.5 46t25 30t29 16t25.5 7z" />
+<glyph unicode="" d="M553 1200h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q19 0 33 -14.5t14 -35t-13 -40.5t-31 -27q-8 -4 -23 -9.5t-65 -19.5t-103 -25t-132.5 -20t-158.5 -9q-57 0 -115 5t-104 12t-88.5 15.5t-73.5 17.5t-54.5 16t-35.5 12l-11 4 q-18 8 -31 28t-13 40.5t14 35t33 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3.5 32t28.5 13zM498 110q50 -6 102 -6q53 0 102 6q-12 -49 -39.5 -79.5t-62.5 -30.5t-63 30.5t-39 79.5z" />
+<glyph unicode="" d="M800 946l224 78l-78 -224l234 -45l-180 -155l180 -155l-234 -45l78 -224l-224 78l-45 -234l-155 180l-155 -180l-45 234l-224 -78l78 224l-234 45l180 155l-180 155l234 45l-78 224l224 -78l45 234l155 -180l155 180z" />
+<glyph unicode="" d="M650 1200h50q40 0 70 -40.5t30 -84.5v-150l-28 -125h328q40 0 70 -40.5t30 -84.5v-100q0 -45 -29 -74l-238 -344q-16 -24 -38 -40.5t-45 -16.5h-250q-7 0 -42 25t-66 50l-31 25h-61q-45 0 -72.5 18t-27.5 57v400q0 36 20 63l145 196l96 198q13 28 37.5 48t51.5 20z M650 1100l-100 -212l-150 -213v-375h100l136 -100h214l250 375v125h-450l50 225v175h-50zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M600 1100h250q23 0 45 -16.5t38 -40.5l238 -344q29 -29 29 -74v-100q0 -44 -30 -84.5t-70 -40.5h-328q28 -118 28 -125v-150q0 -44 -30 -84.5t-70 -40.5h-50q-27 0 -51.5 20t-37.5 48l-96 198l-145 196q-20 27 -20 63v400q0 39 27.5 57t72.5 18h61q124 100 139 100z M50 1000h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM636 1000l-136 -100h-100v-375l150 -213l100 -212h50v175l-50 225h450v125l-250 375h-214z" />
+<glyph unicode="" d="M356 873l363 230q31 16 53 -6l110 -112q13 -13 13.5 -32t-11.5 -34l-84 -121h302q84 0 138 -38t54 -110t-55 -111t-139 -39h-106l-131 -339q-6 -21 -19.5 -41t-28.5 -20h-342q-7 0 -90 81t-83 94v525q0 17 14 35.5t28 28.5zM400 792v-503l100 -89h293l131 339 q6 21 19.5 41t28.5 20h203q21 0 30.5 25t0.5 50t-31 25h-456h-7h-6h-5.5t-6 0.5t-5 1.5t-5 2t-4 2.5t-4 4t-2.5 4.5q-12 25 5 47l146 183l-86 83zM50 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v500 q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M475 1103l366 -230q2 -1 6 -3.5t14 -10.5t18 -16.5t14.5 -20t6.5 -22.5v-525q0 -13 -86 -94t-93 -81h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-85 0 -139.5 39t-54.5 111t54 110t138 38h302l-85 121q-11 15 -10.5 34t13.5 32l110 112q22 22 53 6zM370 945l146 -183 q17 -22 5 -47q-2 -2 -3.5 -4.5t-4 -4t-4 -2.5t-5 -2t-5 -1.5t-6 -0.5h-6h-6.5h-6h-475v-100h221q15 0 29 -20t20 -41l130 -339h294l106 89v503l-342 236zM1050 800h100q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5 v500q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M550 1294q72 0 111 -55t39 -139v-106l339 -131q21 -6 41 -19.5t20 -28.5v-342q0 -7 -81 -90t-94 -83h-525q-17 0 -35.5 14t-28.5 28l-9 14l-230 363q-16 31 6 53l112 110q13 13 32 13.5t34 -11.5l121 -84v302q0 84 38 138t110 54zM600 972v203q0 21 -25 30.5t-50 0.5 t-25 -31v-456v-7v-6v-5.5t-0.5 -6t-1.5 -5t-2 -5t-2.5 -4t-4 -4t-4.5 -2.5q-25 -12 -47 5l-183 146l-83 -86l236 -339h503l89 100v293l-339 131q-21 6 -41 19.5t-20 28.5zM450 200h500q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-500 q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M350 1100h500q21 0 35.5 14.5t14.5 35.5v100q0 21 -14.5 35.5t-35.5 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100q0 -21 14.5 -35.5t35.5 -14.5zM600 306v-106q0 -84 -39 -139t-111 -55t-110 54t-38 138v302l-121 -84q-15 -12 -34 -11.5t-32 13.5l-112 110 q-22 22 -6 53l230 363q1 2 3.5 6t10.5 13.5t16.5 17t20 13.5t22.5 6h525q13 0 94 -83t81 -90v-342q0 -15 -20 -28.5t-41 -19.5zM308 900l-236 -339l83 -86l183 146q22 17 47 5q2 -1 4.5 -2.5t4 -4t2.5 -4t2 -5t1.5 -5t0.5 -6v-5.5v-6v-7v-456q0 -22 25 -31t50 0.5t25 30.5 v203q0 15 20 28.5t41 19.5l339 131v293l-89 100h-503z" />
+<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM914 632l-275 223q-16 13 -27.5 8t-11.5 -26v-137h-275 q-10 0 -17.5 -7.5t-7.5 -17.5v-150q0 -10 7.5 -17.5t17.5 -7.5h275v-137q0 -21 11.5 -26t27.5 8l275 223q16 13 16 32t-16 32z" />
+<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM561 855l-275 -223q-16 -13 -16 -32t16 -32l275 -223q16 -13 27.5 -8 t11.5 26v137h275q10 0 17.5 7.5t7.5 17.5v150q0 10 -7.5 17.5t-17.5 7.5h-275v137q0 21 -11.5 26t-27.5 -8z" />
+<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM855 639l-223 275q-13 16 -32 16t-32 -16l-223 -275q-13 -16 -8 -27.5 t26 -11.5h137v-275q0 -10 7.5 -17.5t17.5 -7.5h150q10 0 17.5 7.5t7.5 17.5v275h137q21 0 26 11.5t-8 27.5z" />
+<glyph unicode="" d="M600 1178q118 0 225 -45.5t184.5 -123t123 -184.5t45.5 -225t-45.5 -225t-123 -184.5t-184.5 -123t-225 -45.5t-225 45.5t-184.5 123t-123 184.5t-45.5 225t45.5 225t123 184.5t184.5 123t225 45.5zM675 900h-150q-10 0 -17.5 -7.5t-7.5 -17.5v-275h-137q-21 0 -26 -11.5 t8 -27.5l223 -275q13 -16 32 -16t32 16l223 275q13 16 8 27.5t-26 11.5h-137v275q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="" d="M600 1176q116 0 222.5 -46t184 -123.5t123.5 -184t46 -222.5t-46 -222.5t-123.5 -184t-184 -123.5t-222.5 -46t-222.5 46t-184 123.5t-123.5 184t-46 222.5t46 222.5t123.5 184t184 123.5t222.5 46zM627 1101q-15 -12 -36.5 -20.5t-35.5 -12t-43 -8t-39 -6.5 q-15 -3 -45.5 0t-45.5 -2q-20 -7 -51.5 -26.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79q-9 -34 5 -93t8 -87q0 -9 17 -44.5t16 -59.5q12 0 23 -5t23.5 -15t19.5 -14q16 -8 33 -15t40.5 -15t34.5 -12q21 -9 52.5 -32t60 -38t57.5 -11 q7 -15 -3 -34t-22.5 -40t-9.5 -38q13 -21 23 -34.5t27.5 -27.5t36.5 -18q0 -7 -3.5 -16t-3.5 -14t5 -17q104 -2 221 112q30 29 46.5 47t34.5 49t21 63q-13 8 -37 8.5t-36 7.5q-15 7 -49.5 15t-51.5 19q-18 0 -41 -0.5t-43 -1.5t-42 -6.5t-38 -16.5q-51 -35 -66 -12 q-4 1 -3.5 25.5t0.5 25.5q-6 13 -26.5 17.5t-24.5 6.5q1 15 -0.5 30.5t-7 28t-18.5 11.5t-31 -21q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q7 -12 18 -24t21.5 -20.5t20 -15t15.5 -10.5l5 -3q2 12 7.5 30.5t8 34.5t-0.5 32q-3 18 3.5 29 t18 22.5t15.5 24.5q6 14 10.5 35t8 31t15.5 22.5t34 22.5q-6 18 10 36q8 0 24 -1.5t24.5 -1.5t20 4.5t20.5 15.5q-10 23 -31 42.5t-37.5 29.5t-49 27t-43.5 23q0 1 2 8t3 11.5t1.5 10.5t-1 9.5t-4.5 4.5q31 -13 58.5 -14.5t38.5 2.5l12 5q5 28 -9.5 46t-36.5 24t-50 15 t-41 20q-18 -4 -37 0zM613 994q0 -17 8 -42t17 -45t9 -23q-8 1 -39.5 5.5t-52.5 10t-37 16.5q3 11 16 29.5t16 25.5q10 -10 19 -10t14 6t13.5 14.5t16.5 12.5z" />
+<glyph unicode="" d="M756 1157q164 92 306 -9l-259 -138l145 -232l251 126q6 -89 -34 -156.5t-117 -110.5q-60 -34 -127 -39.5t-126 16.5l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5t15 37.5l600 599q-34 101 5.5 201.5t135.5 154.5z" />
+<glyph unicode="" horiz-adv-x="1220" d="M100 1196h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 1096h-200v-100h200v100zM100 796h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 696h-500v-100h500v100zM100 396h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5v100q0 41 29.5 70.5t70.5 29.5zM1100 296h-300v-100h300v100z " />
+<glyph unicode="" d="M150 1200h900q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM700 500v-300l-200 -200v500l-350 500h900z" />
+<glyph unicode="" d="M500 1200h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5zM500 1100v-100h200v100h-200zM1200 400v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5v200h1200z" />
+<glyph unicode="" d="M50 1200h300q21 0 25 -10.5t-10 -24.5l-94 -94l199 -199q7 -8 7 -18t-7 -18l-106 -106q-8 -7 -18 -7t-18 7l-199 199l-94 -94q-14 -14 -24.5 -10t-10.5 25v300q0 21 14.5 35.5t35.5 14.5zM850 1200h300q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -10.5 -25t-24.5 10l-94 94 l-199 -199q-8 -7 -18 -7t-18 7l-106 106q-7 8 -7 18t7 18l199 199l-94 94q-14 14 -10 24.5t25 10.5zM364 470l106 -106q7 -8 7 -18t-7 -18l-199 -199l94 -94q14 -14 10 -24.5t-25 -10.5h-300q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 10.5 25t24.5 -10l94 -94l199 199 q8 7 18 7t18 -7zM1071 271l94 94q14 14 24.5 10t10.5 -25v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -25 10.5t10 24.5l94 94l-199 199q-7 8 -7 18t7 18l106 106q8 7 18 7t18 -7z" />
+<glyph unicode="" d="M596 1192q121 0 231.5 -47.5t190 -127t127 -190t47.5 -231.5t-47.5 -231.5t-127 -190.5t-190 -127t-231.5 -47t-231.5 47t-190.5 127t-127 190.5t-47 231.5t47 231.5t127 190t190.5 127t231.5 47.5zM596 1010q-112 0 -207.5 -55.5t-151 -151t-55.5 -207.5t55.5 -207.5 t151 -151t207.5 -55.5t207.5 55.5t151 151t55.5 207.5t-55.5 207.5t-151 151t-207.5 55.5zM454.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38.5 -16.5t-38.5 16.5t-16 39t16 38.5t38.5 16zM754.5 905q22.5 0 38.5 -16t16 -38.5t-16 -39t-38 -16.5q-14 0 -29 10l-55 -145 q17 -23 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 23 16 39t38.5 16zM345.5 709q22.5 0 38.5 -16t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16zM854.5 709q22.5 0 38.5 -16 t16 -38.5t-16 -38.5t-38.5 -16t-38.5 16t-16 38.5t16 38.5t38.5 16z" />
+<glyph unicode="" d="M546 173l469 470q91 91 99 192q7 98 -52 175.5t-154 94.5q-22 4 -47 4q-34 0 -66.5 -10t-56.5 -23t-55.5 -38t-48 -41.5t-48.5 -47.5q-376 -375 -391 -390q-30 -27 -45 -41.5t-37.5 -41t-32 -46.5t-16 -47.5t-1.5 -56.5q9 -62 53.5 -95t99.5 -33q74 0 125 51l548 548 q36 36 20 75q-7 16 -21.5 26t-32.5 10q-26 0 -50 -23q-13 -12 -39 -38l-341 -338q-15 -15 -35.5 -15.5t-34.5 13.5t-14 34.5t14 34.5q327 333 361 367q35 35 67.5 51.5t78.5 16.5q14 0 29 -1q44 -8 74.5 -35.5t43.5 -68.5q14 -47 2 -96.5t-47 -84.5q-12 -11 -32 -32 t-79.5 -81t-114.5 -115t-124.5 -123.5t-123 -119.5t-96.5 -89t-57 -45q-56 -27 -120 -27q-70 0 -129 32t-93 89q-48 78 -35 173t81 163l511 511q71 72 111 96q91 55 198 55q80 0 152 -33q78 -36 129.5 -103t66.5 -154q17 -93 -11 -183.5t-94 -156.5l-482 -476 q-15 -15 -36 -16t-37 14t-17.5 34t14.5 35z" />
+<glyph unicode="" d="M649 949q48 68 109.5 104t121.5 38.5t118.5 -20t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-150 152.5t-126.5 127.5t-93.5 124.5t-33.5 117.5q0 64 28 123t73 100.5t104 64t119 20 t120.5 -38.5t104.5 -104zM896 972q-33 0 -64.5 -19t-56.5 -46t-47.5 -53.5t-43.5 -45.5t-37.5 -19t-36 19t-40 45.5t-43 53.5t-54 46t-65.5 19q-67 0 -122.5 -55.5t-55.5 -132.5q0 -23 13.5 -51t46 -65t57.5 -63t76 -75l22 -22q15 -14 44 -44t50.5 -51t46 -44t41 -35t23 -12 t23.5 12t42.5 36t46 44t52.5 52t44 43q4 4 12 13q43 41 63.5 62t52 55t46 55t26 46t11.5 44q0 79 -53 133.5t-120 54.5z" />
+<glyph unicode="" d="M776.5 1214q93.5 0 159.5 -66l141 -141q66 -66 66 -160q0 -42 -28 -95.5t-62 -87.5l-29 -29q-31 53 -77 99l-18 18l95 95l-247 248l-389 -389l212 -212l-105 -106l-19 18l-141 141q-66 66 -66 159t66 159l283 283q65 66 158.5 66zM600 706l105 105q10 -8 19 -17l141 -141 q66 -66 66 -159t-66 -159l-283 -283q-66 -66 -159 -66t-159 66l-141 141q-66 66 -66 159.5t66 159.5l55 55q29 -55 75 -102l18 -17l-95 -95l247 -248l389 389z" />
+<glyph unicode="" d="M603 1200q85 0 162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5v953q0 21 30 46.5t81 48t129 37.5t163 15zM300 1000v-700h600v700h-600zM600 254q-43 0 -73.5 -30.5t-30.5 -73.5t30.5 -73.5t73.5 -30.5t73.5 30.5 t30.5 73.5t-30.5 73.5t-73.5 30.5z" />
+<glyph unicode="" d="M902 1185l283 -282q15 -15 15 -36t-14.5 -35.5t-35.5 -14.5t-35 15l-36 35l-279 -267v-300l-212 210l-308 -307l-280 -203l203 280l307 308l-210 212h300l267 279l-35 36q-15 14 -15 35t14.5 35.5t35.5 14.5t35 -15z" />
+<glyph unicode="" d="M700 1248v-78q38 -5 72.5 -14.5t75.5 -31.5t71 -53.5t52 -84t24 -118.5h-159q-4 36 -10.5 59t-21 45t-40 35.5t-64.5 20.5v-307l64 -13q34 -7 64 -16.5t70 -32t67.5 -52.5t47.5 -80t20 -112q0 -139 -89 -224t-244 -97v-77h-100v79q-150 16 -237 103q-40 40 -52.5 93.5 t-15.5 139.5h139q5 -77 48.5 -126t117.5 -65v335l-27 8q-46 14 -79 26.5t-72 36t-63 52t-40 72.5t-16 98q0 70 25 126t67.5 92t94.5 57t110 27v77h100zM600 754v274q-29 -4 -50 -11t-42 -21.5t-31.5 -41.5t-10.5 -65q0 -29 7 -50.5t16.5 -34t28.5 -22.5t31.5 -14t37.5 -10 q9 -3 13 -4zM700 547v-310q22 2 42.5 6.5t45 15.5t41.5 27t29 42t12 59.5t-12.5 59.5t-38 44.5t-53 31t-66.5 24.5z" />
+<glyph unicode="" d="M561 1197q84 0 160.5 -40t123.5 -109.5t47 -147.5h-153q0 40 -19.5 71.5t-49.5 48.5t-59.5 26t-55.5 9q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -26 13.5 -63t26.5 -61t37 -66q6 -9 9 -14h241v-100h-197q8 -50 -2.5 -115t-31.5 -95q-45 -62 -99 -112 q34 10 83 17.5t71 7.5q32 1 102 -16t104 -17q83 0 136 30l50 -147q-31 -19 -58 -30.5t-55 -15.5t-42 -4.5t-46 -0.5q-23 0 -76 17t-111 32.5t-96 11.5q-39 -3 -82 -16t-67 -25l-23 -11l-55 145q4 3 16 11t15.5 10.5t13 9t15.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221v100h166q-23 47 -44 104q-7 20 -12 41.5t-6 55.5t6 66.5t29.5 70.5t58.5 71q97 88 263 88z" />
+<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM935 1184l230 -249q14 -14 10 -24.5t-25 -10.5h-150v-900h-200v900h-150q-21 0 -25 10.5t10 24.5l230 249q14 15 35 15t35 -15z" />
+<glyph unicode="" d="M1000 700h-100v100h-100v-100h-100v500h300v-500zM400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM801 1100v-200h100v200h-100zM1000 350l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150z " />
+<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 1050l-200 -250h200v-100h-300v150l200 250h-200v100h300v-150zM1000 0h-100v100h-100v-100h-100v500h300v-500zM801 400v-200h100v200h-100z " />
+<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1000 700h-100v400h-100v100h200v-500zM1100 0h-100v100h-200v400h300v-500zM901 400v-200h100v200h-100z" />
+<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1100 700h-100v100h-200v400h300v-500zM901 1100v-200h100v200h-100zM1000 0h-100v400h-100v100h200v-500z" />
+<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM900 1000h-200v200h200v-200zM1000 700h-300v200h300v-200zM1100 400h-400v200h400v-200zM1200 100h-500v200h500v-200z" />
+<glyph unicode="" d="M400 300h150q21 0 25 -11t-10 -25l-230 -250q-14 -15 -35 -15t-35 15l-230 250q-14 14 -10 25t25 11h150v900h200v-900zM1200 1000h-500v200h500v-200zM1100 700h-400v200h400v-200zM1000 400h-300v200h300v-200zM900 100h-200v200h200v-200z" />
+<glyph unicode="" d="M350 1100h400q162 0 256 -93.5t94 -256.5v-400q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5z" />
+<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-163 0 -256.5 92.5t-93.5 257.5v400q0 163 94 256.5t256 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM440 770l253 -190q17 -12 17 -30t-17 -30l-253 -190q-16 -12 -28 -6.5t-12 26.5v400q0 21 12 26.5t28 -6.5z" />
+<glyph unicode="" d="M350 1100h400q163 0 256.5 -94t93.5 -256v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 163 92.5 256.5t257.5 93.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM350 700h400q21 0 26.5 -12t-6.5 -28l-190 -253q-12 -17 -30 -17t-30 17l-190 253q-12 16 -6.5 28t26.5 12z" />
+<glyph unicode="" d="M350 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -163 -92.5 -256.5t-257.5 -93.5h-400q-163 0 -256.5 94t-93.5 256v400q0 165 92.5 257.5t257.5 92.5zM800 900h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5 v500q0 41 -29.5 70.5t-70.5 29.5zM580 693l190 -253q12 -16 6.5 -28t-26.5 -12h-400q-21 0 -26.5 12t6.5 28l190 253q12 17 30 17t30 -17z" />
+<glyph unicode="" d="M550 1100h400q165 0 257.5 -92.5t92.5 -257.5v-400q0 -165 -92.5 -257.5t-257.5 -92.5h-400q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h450q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-450q-21 0 -35.5 14.5t-14.5 35.5v100 q0 21 14.5 35.5t35.5 14.5zM338 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="" d="M793 1182l9 -9q8 -10 5 -27q-3 -11 -79 -225.5t-78 -221.5l300 1q24 0 32.5 -17.5t-5.5 -35.5q-1 0 -133.5 -155t-267 -312.5t-138.5 -162.5q-12 -15 -26 -15h-9l-9 8q-9 11 -4 32q2 9 42 123.5t79 224.5l39 110h-302q-23 0 -31 19q-10 21 6 41q75 86 209.5 237.5 t228 257t98.5 111.5q9 16 25 16h9z" />
+<glyph unicode="" d="M350 1100h400q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-450q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h450q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400 q0 165 92.5 257.5t257.5 92.5zM938 867l324 -284q16 -14 16 -33t-16 -33l-324 -284q-16 -14 -27 -9t-11 26v150h-250q-21 0 -35.5 14.5t-14.5 35.5v200q0 21 14.5 35.5t35.5 14.5h250v150q0 21 11 26t27 -9z" />
+<glyph unicode="" d="M750 1200h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -10.5 -25t-24.5 10l-109 109l-312 -312q-15 -15 -35.5 -15t-35.5 15l-141 141q-15 15 -15 35.5t15 35.5l312 312l-109 109q-14 14 -10 24.5t25 10.5zM456 900h-156q-41 0 -70.5 -29.5t-29.5 -70.5v-500 q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v148l200 200v-298q0 -165 -93.5 -257.5t-256.5 -92.5h-400q-165 0 -257.5 92.5t-92.5 257.5v400q0 165 92.5 257.5t257.5 92.5h300z" />
+<glyph unicode="" d="M600 1186q119 0 227.5 -46.5t187 -125t125 -187t46.5 -227.5t-46.5 -227.5t-125 -187t-187 -125t-227.5 -46.5t-227.5 46.5t-187 125t-125 187t-46.5 227.5t46.5 227.5t125 187t187 125t227.5 46.5zM600 1022q-115 0 -212 -56.5t-153.5 -153.5t-56.5 -212t56.5 -212 t153.5 -153.5t212 -56.5t212 56.5t153.5 153.5t56.5 212t-56.5 212t-153.5 153.5t-212 56.5zM600 794q80 0 137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137t57 137t137 57z" />
+<glyph unicode="" d="M450 1200h200q21 0 35.5 -14.5t14.5 -35.5v-350h245q20 0 25 -11t-9 -26l-383 -426q-14 -15 -33.5 -15t-32.5 15l-379 426q-13 15 -8.5 26t25.5 11h250v350q0 21 14.5 35.5t35.5 14.5zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="" d="M583 1182l378 -435q14 -15 9 -31t-26 -16h-244v-250q0 -20 -17 -35t-39 -15h-200q-20 0 -32 14.5t-12 35.5v250h-250q-20 0 -25.5 16.5t8.5 31.5l383 431q14 16 33.5 17t33.5 -14zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5z M900 200v-50h100v50h-100z" />
+<glyph unicode="" d="M396 723l369 369q7 7 17.5 7t17.5 -7l139 -139q7 -8 7 -18.5t-7 -17.5l-525 -525q-7 -8 -17.5 -8t-17.5 8l-292 291q-7 8 -7 18t7 18l139 139q8 7 18.5 7t17.5 -7zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50 h-100z" />
+<glyph unicode="" d="M135 1023l142 142q14 14 35 14t35 -14l77 -77l-212 -212l-77 76q-14 15 -14 36t14 35zM655 855l210 210q14 14 24.5 10t10.5 -25l-2 -599q-1 -20 -15.5 -35t-35.5 -15l-597 -1q-21 0 -25 10.5t10 24.5l208 208l-154 155l212 212zM50 300h1000q21 0 35.5 -14.5t14.5 -35.5 v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="" d="M350 1200l599 -2q20 -1 35 -15.5t15 -35.5l1 -597q0 -21 -10.5 -25t-24.5 10l-208 208l-155 -154l-212 212l155 154l-210 210q-14 14 -10 24.5t25 10.5zM524 512l-76 -77q-15 -14 -36 -14t-35 14l-142 142q-14 14 -14 35t14 35l77 77zM50 300h1000q21 0 35.5 -14.5 t14.5 -35.5v-250h-1100v250q0 21 14.5 35.5t35.5 14.5zM900 200v-50h100v50h-100z" />
+<glyph unicode="" d="M1200 103l-483 276l-314 -399v423h-399l1196 796v-1096zM483 424v-230l683 953z" />
+<glyph unicode="" d="M1100 1000v-850q0 -21 -14.5 -35.5t-35.5 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200z" />
+<glyph unicode="" d="M1100 1000l-2 -149l-299 -299l-95 95q-9 9 -21.5 9t-21.5 -9l-149 -147h-312v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1132 638l106 -106q7 -7 7 -17.5t-7 -17.5l-420 -421q-8 -7 -18 -7 t-18 7l-202 203q-8 7 -8 17.5t8 17.5l106 106q7 8 17.5 8t17.5 -8l79 -79l297 297q7 7 17.5 7t17.5 -7z" />
+<glyph unicode="" d="M1100 1000v-269l-103 -103l-134 134q-15 15 -33.5 16.5t-34.5 -12.5l-266 -266h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM1202 572l70 -70q15 -15 15 -35.5t-15 -35.5l-131 -131 l131 -131q15 -15 15 -35.5t-15 -35.5l-70 -70q-15 -15 -35.5 -15t-35.5 15l-131 131l-131 -131q-15 -15 -35.5 -15t-35.5 15l-70 70q-15 15 -15 35.5t15 35.5l131 131l-131 131q-15 15 -15 35.5t15 35.5l70 70q15 15 35.5 15t35.5 -15l131 -131l131 131q15 15 35.5 15 t35.5 -15z" />
+<glyph unicode="" d="M1100 1000v-300h-350q-21 0 -35.5 -14.5t-14.5 -35.5v-150h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM850 600h100q21 0 35.5 -14.5t14.5 -35.5v-250h150q21 0 25 -10.5t-10 -24.5 l-230 -230q-14 -14 -35 -14t-35 14l-230 230q-14 14 -10 24.5t25 10.5h150v250q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M1100 1000v-400l-165 165q-14 15 -35 15t-35 -15l-263 -265h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100zM700 1000h-100v200h100v-200zM935 565l230 -229q14 -15 10 -25.5t-25 -10.5h-150v-250q0 -20 -14.5 -35 t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35v250h-150q-21 0 -25 10.5t10 25.5l230 229q14 15 35 15t35 -15z" />
+<glyph unicode="" d="M50 1100h1100q21 0 35.5 -14.5t14.5 -35.5v-150h-1200v150q0 21 14.5 35.5t35.5 14.5zM1200 800v-550q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v550h1200zM100 500v-200h400v200h-400z" />
+<glyph unicode="" d="M935 1165l248 -230q14 -14 14 -35t-14 -35l-248 -230q-14 -14 -24.5 -10t-10.5 25v150h-400v200h400v150q0 21 10.5 25t24.5 -10zM200 800h-50q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v-200zM400 800h-100v200h100v-200zM18 435l247 230 q14 14 24.5 10t10.5 -25v-150h400v-200h-400v-150q0 -21 -10.5 -25t-24.5 10l-247 230q-15 14 -15 35t15 35zM900 300h-100v200h100v-200zM1000 500h51q20 0 34.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-34.5 -14.5h-51v200z" />
+<glyph unicode="" d="M862 1073l276 116q25 18 43.5 8t18.5 -41v-1106q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v397q-4 1 -11 5t-24 17.5t-30 29t-24 42t-11 56.5v359q0 31 18.5 65t43.5 52zM550 1200q22 0 34.5 -12.5t14.5 -24.5l1 -13v-450q0 -28 -10.5 -59.5 t-25 -56t-29 -45t-25.5 -31.5l-10 -11v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447q-4 4 -11 11.5t-24 30.5t-30 46t-24 55t-11 60v450q0 2 0.5 5.5t4 12t8.5 15t14.5 12t22.5 5.5q20 0 32.5 -12.5t14.5 -24.5l3 -13v-350h100v350v5.5t2.5 12 t7 15t15 12t25.5 5.5q23 0 35.5 -12.5t13.5 -24.5l1 -13v-350h100v350q0 2 0.5 5.5t3 12t7 15t15 12t24.5 5.5z" />
+<glyph unicode="" d="M1200 1100v-56q-4 0 -11 -0.5t-24 -3t-30 -7.5t-24 -15t-11 -24v-888q0 -22 25 -34.5t50 -13.5l25 -2v-56h-400v56q75 0 87.5 6.5t12.5 43.5v394h-500v-394q0 -37 12.5 -43.5t87.5 -6.5v-56h-400v56q4 0 11 0.5t24 3t30 7.5t24 15t11 24v888q0 22 -25 34.5t-50 13.5 l-25 2v56h400v-56q-75 0 -87.5 -6.5t-12.5 -43.5v-394h500v394q0 37 -12.5 43.5t-87.5 6.5v56h400z" />
+<glyph unicode="" d="M675 1000h375q21 0 35.5 -14.5t14.5 -35.5v-150h-105l-295 -98v98l-200 200h-400l100 100h375zM100 900h300q41 0 70.5 -29.5t29.5 -70.5v-500q0 -41 -29.5 -70.5t-70.5 -29.5h-300q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5zM100 800v-200h300v200 h-300zM1100 535l-400 -133v163l400 133v-163zM100 500v-200h300v200h-300zM1100 398v-248q0 -21 -14.5 -35.5t-35.5 -14.5h-375l-100 -100h-375l-100 100h400l200 200h105z" />
+<glyph unicode="" d="M17 1007l162 162q17 17 40 14t37 -22l139 -194q14 -20 11 -44.5t-20 -41.5l-119 -118q102 -142 228 -268t267 -227l119 118q17 17 42.5 19t44.5 -12l192 -136q19 -14 22.5 -37.5t-13.5 -40.5l-163 -162q-3 -1 -9.5 -1t-29.5 2t-47.5 6t-62.5 14.5t-77.5 26.5t-90 42.5 t-101.5 60t-111 83t-119 108.5q-74 74 -133.5 150.5t-94.5 138.5t-60 119.5t-34.5 100t-15 74.5t-4.5 48z" />
+<glyph unicode="" d="M600 1100q92 0 175 -10.5t141.5 -27t108.5 -36.5t81.5 -40t53.5 -37t31 -27l9 -10v-200q0 -21 -14.5 -33t-34.5 -9l-202 34q-20 3 -34.5 20t-14.5 38v146q-141 24 -300 24t-300 -24v-146q0 -21 -14.5 -38t-34.5 -20l-202 -34q-20 -3 -34.5 9t-14.5 33v200q3 4 9.5 10.5 t31 26t54 37.5t80.5 39.5t109 37.5t141 26.5t175 10.5zM600 795q56 0 97 -9.5t60 -23.5t30 -28t12 -24l1 -10v-50l365 -303q14 -15 24.5 -40t10.5 -45v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v212q0 20 10.5 45t24.5 40l365 303v50 q0 4 1 10.5t12 23t30 29t60 22.5t97 10z" />
+<glyph unicode="" d="M1100 700l-200 -200h-600l-200 200v500h200v-200h200v200h200v-200h200v200h200v-500zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5 t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M700 1100h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-1000h300v1000q0 41 -29.5 70.5t-70.5 29.5zM1100 800h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-700h300v700q0 41 -29.5 70.5t-70.5 29.5zM400 0h-300v400q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-400z " />
+<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 300h-100v200h-100v-200h-100v500h100v-200h100v200h100v-500zM900 700v-300l-100 -100h-200v500h200z M700 700v-300h100v300h-100z" />
+<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-300h200v-100h-300v500h300v-100zM900 700h-200v-300h200v-100h-300v500h300v-100z" />
+<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 400l-300 150l300 150v-300zM900 550l-300 -150v300z" />
+<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM900 300h-700v500h700v-500zM800 700h-130q-38 0 -66.5 -43t-28.5 -108t27 -107t68 -42h130v300zM300 700v-300 h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130z" />
+<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 700h-200v-100h200v-300h-300v100h200v100h-200v300h300v-100zM900 300h-100v400h-100v100h200v-500z M700 300h-100v100h100v-100z" />
+<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM300 700h200v-400h-300v500h100v-100zM900 300h-100v400h-100v100h200v-500zM300 600v-200h100v200h-100z M700 300h-100v100h100v-100z" />
+<glyph unicode="" d="M200 1100h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212v500q0 124 88 212t212 88zM100 900v-700h900v700h-900zM500 500l-199 -200h-100v50l199 200v150h-200v100h300v-300zM900 300h-100v400h-100v100h200v-500zM701 300h-100 v100h100v-100z" />
+<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700h-300v-200h300v-100h-300l-100 100v200l100 100h300v-100z" />
+<glyph unicode="" d="M600 1191q120 0 229.5 -47t188.5 -126t126 -188.5t47 -229.5t-47 -229.5t-126 -188.5t-188.5 -126t-229.5 -47t-229.5 47t-188.5 126t-126 188.5t-47 229.5t47 229.5t126 188.5t188.5 126t229.5 47zM600 1021q-114 0 -211 -56.5t-153.5 -153.5t-56.5 -211t56.5 -211 t153.5 -153.5t211 -56.5t211 56.5t153.5 153.5t56.5 211t-56.5 211t-153.5 153.5t-211 56.5zM800 700v-100l-50 -50l100 -100v-50h-100l-100 100h-150v-100h-100v400h300zM500 700v-100h200v100h-200z" />
+<glyph unicode="" d="M503 1089q110 0 200.5 -59.5t134.5 -156.5q44 14 90 14q120 0 205 -86.5t85 -207t-85 -207t-205 -86.5h-128v250q0 21 -14.5 35.5t-35.5 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-250h-222q-80 0 -136 57.5t-56 136.5q0 69 43 122.5t108 67.5q-2 19 -2 37q0 100 49 185 t134 134t185 49zM525 500h150q10 0 17.5 -7.5t7.5 -17.5v-275h137q21 0 26 -11.5t-8 -27.5l-223 -244q-13 -16 -32 -16t-32 16l-223 244q-13 16 -8 27.5t26 11.5h137v275q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M502 1089q110 0 201 -59.5t135 -156.5q43 15 89 15q121 0 206 -86.5t86 -206.5q0 -99 -60 -181t-150 -110l-378 360q-13 16 -31.5 16t-31.5 -16l-381 -365h-9q-79 0 -135.5 57.5t-56.5 136.5q0 69 43 122.5t108 67.5q-2 19 -2 38q0 100 49 184.5t133.5 134t184.5 49.5z M632 467l223 -228q13 -16 8 -27.5t-26 -11.5h-137v-275q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v275h-137q-21 0 -26 11.5t8 27.5q199 204 223 228q19 19 31.5 19t32.5 -19z" />
+<glyph unicode="" d="M700 100v100h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170l-270 -300h400v-100h-50q-21 0 -35.5 -14.5t-14.5 -35.5v-50h400v50q0 21 -14.5 35.5t-35.5 14.5h-50z" />
+<glyph unicode="" d="M600 1179q94 0 167.5 -56.5t99.5 -145.5q89 -6 150.5 -71.5t61.5 -155.5q0 -61 -29.5 -112.5t-79.5 -82.5q9 -29 9 -55q0 -74 -52.5 -126.5t-126.5 -52.5q-55 0 -100 30v-251q21 0 35.5 -14.5t14.5 -35.5v-50h-300v50q0 21 14.5 35.5t35.5 14.5v251q-45 -30 -100 -30 q-74 0 -126.5 52.5t-52.5 126.5q0 18 4 38q-47 21 -75.5 65t-28.5 97q0 74 52.5 126.5t126.5 52.5q5 0 23 -2q0 2 -1 10t-1 13q0 116 81.5 197.5t197.5 81.5z" />
+<glyph unicode="" d="M1010 1010q111 -111 150.5 -260.5t0 -299t-150.5 -260.5q-83 -83 -191.5 -126.5t-218.5 -43.5t-218.5 43.5t-191.5 126.5q-111 111 -150.5 260.5t0 299t150.5 260.5q83 83 191.5 126.5t218.5 43.5t218.5 -43.5t191.5 -126.5zM476 1065q-4 0 -8 -1q-121 -34 -209.5 -122.5 t-122.5 -209.5q-4 -12 2.5 -23t18.5 -14l36 -9q3 -1 7 -1q23 0 29 22q27 96 98 166q70 71 166 98q11 3 17.5 13.5t3.5 22.5l-9 35q-3 13 -14 19q-7 4 -15 4zM512 920q-4 0 -9 -2q-80 -24 -138.5 -82.5t-82.5 -138.5q-4 -13 2 -24t19 -14l34 -9q4 -1 8 -1q22 0 28 21 q18 58 58.5 98.5t97.5 58.5q12 3 18 13.5t3 21.5l-9 35q-3 12 -14 19q-7 4 -15 4zM719.5 719.5q-49.5 49.5 -119.5 49.5t-119.5 -49.5t-49.5 -119.5t49.5 -119.5t119.5 -49.5t119.5 49.5t49.5 119.5t-49.5 119.5zM855 551q-22 0 -28 -21q-18 -58 -58.5 -98.5t-98.5 -57.5 q-11 -4 -17 -14.5t-3 -21.5l9 -35q3 -12 14 -19q7 -4 15 -4q4 0 9 2q80 24 138.5 82.5t82.5 138.5q4 13 -2.5 24t-18.5 14l-34 9q-4 1 -8 1zM1000 515q-23 0 -29 -22q-27 -96 -98 -166q-70 -71 -166 -98q-11 -3 -17.5 -13.5t-3.5 -22.5l9 -35q3 -13 14 -19q7 -4 15 -4 q4 0 8 1q121 34 209.5 122.5t122.5 209.5q4 12 -2.5 23t-18.5 14l-36 9q-3 1 -7 1z" />
+<glyph unicode="" d="M700 800h300v-380h-180v200h-340v-200h-380v755q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM700 300h162l-212 -212l-212 212h162v200h100v-200zM520 0h-395q-10 0 -17.5 7.5t-7.5 17.5v395zM1000 220v-195q0 -10 -7.5 -17.5t-17.5 -7.5h-195z" />
+<glyph unicode="" d="M700 800h300v-520l-350 350l-550 -550v1095q0 10 7.5 17.5t17.5 7.5h575v-400zM1000 900h-200v200zM862 200h-162v-200h-100v200h-162l212 212zM480 0h-355q-10 0 -17.5 7.5t-7.5 17.5v55h380v-80zM1000 80v-55q0 -10 -7.5 -17.5t-17.5 -7.5h-155v80h180z" />
+<glyph unicode="" d="M1162 800h-162v-200h100l100 -100h-300v300h-162l212 212zM200 800h200q27 0 40 -2t29.5 -10.5t23.5 -30t7 -57.5h300v-100h-600l-200 -350v450h100q0 36 7 57.5t23.5 30t29.5 10.5t40 2zM800 400h240l-240 -400h-800l300 500h500v-100z" />
+<glyph unicode="" d="M650 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM1000 850v150q41 0 70.5 -29.5t29.5 -70.5v-800 q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-1 0 -20 4l246 246l-326 326v324q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM412 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="" d="M450 1100h100q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-300q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h50v50q0 21 14.5 35.5t35.5 14.5zM800 850v150q41 0 70.5 -29.5t29.5 -70.5v-500 h-200v-300h200q0 -36 -7 -57.5t-23.5 -30t-29.5 -10.5t-40 -2h-600q-41 0 -70.5 29.5t-29.5 70.5v800q0 41 29.5 70.5t70.5 29.5v-150q0 -62 44 -106t106 -44h300q62 0 106 44t44 106zM1212 250l-212 -212v162h-200v100h200v162z" />
+<glyph unicode="" d="M658 1197l637 -1104q23 -38 7 -65.5t-60 -27.5h-1276q-44 0 -60 27.5t7 65.5l637 1104q22 39 54 39t54 -39zM704 800h-208q-20 0 -32 -14.5t-8 -34.5l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5zM500 300v-100h200 v100h-200z" />
+<glyph unicode="" d="M425 1100h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM825 800h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM25 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5zM425 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 500h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5 v150q0 10 7.5 17.5t17.5 7.5zM25 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM425 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5 t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM825 200h250q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-250q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M700 1200h100v-200h-100v-100h350q62 0 86.5 -39.5t-3.5 -94.5l-66 -132q-41 -83 -81 -134h-772q-40 51 -81 134l-66 132q-28 55 -3.5 94.5t86.5 39.5h350v100h-100v200h100v100h200v-100zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-12l137 -100 h-950l138 100h-13q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M600 1300q40 0 68.5 -29.5t28.5 -70.5h-194q0 41 28.5 70.5t68.5 29.5zM443 1100h314q18 -37 18 -75q0 -8 -3 -25h328q41 0 44.5 -16.5t-30.5 -38.5l-175 -145h-678l-178 145q-34 22 -29 38.5t46 16.5h328q-3 17 -3 25q0 38 18 75zM250 700h700q21 0 35.5 -14.5 t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-150v-200l275 -200h-950l275 200v200h-150q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M600 1181q75 0 128 -53t53 -128t-53 -128t-128 -53t-128 53t-53 128t53 128t128 53zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13 l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M600 1300q47 0 92.5 -53.5t71 -123t25.5 -123.5q0 -78 -55.5 -133.5t-133.5 -55.5t-133.5 55.5t-55.5 133.5q0 62 34 143l144 -143l111 111l-163 163q34 26 63 26zM602 798h46q34 0 55.5 -28.5t21.5 -86.5q0 -76 39 -183h-324q39 107 39 183q0 58 21.5 86.5t56.5 28.5h45 zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M600 1200l300 -161v-139h-300q0 -57 18.5 -108t50 -91.5t63 -72t70 -67.5t57.5 -61h-530q-60 83 -90.5 177.5t-30.5 178.5t33 164.5t87.5 139.5t126 96.5t145.5 41.5v-98zM250 400h700q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-13l138 -100h-950l137 100 h-12q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5zM50 100h1100q21 0 35.5 -14.5t14.5 -35.5v-50h-1200v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M600 1300q41 0 70.5 -29.5t29.5 -70.5v-78q46 -26 73 -72t27 -100v-50h-400v50q0 54 27 100t73 72v78q0 41 29.5 70.5t70.5 29.5zM400 800h400q54 0 100 -27t72 -73h-172v-100h200v-100h-200v-100h200v-100h-200v-100h200q0 -83 -58.5 -141.5t-141.5 -58.5h-400 q-83 0 -141.5 58.5t-58.5 141.5v400q0 83 58.5 141.5t141.5 58.5z" />
+<glyph unicode="" d="M150 1100h900q21 0 35.5 -14.5t14.5 -35.5v-500q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v500q0 21 14.5 35.5t35.5 14.5zM125 400h950q10 0 17.5 -7.5t7.5 -17.5v-50q0 -10 -7.5 -17.5t-17.5 -7.5h-283l224 -224q13 -13 13 -31.5t-13 -32 t-31.5 -13.5t-31.5 13l-88 88h-524l-87 -88q-13 -13 -32 -13t-32 13.5t-13 32t13 31.5l224 224h-289q-10 0 -17.5 7.5t-7.5 17.5v50q0 10 7.5 17.5t17.5 7.5zM541 300l-100 -100h324l-100 100h-124z" />
+<glyph unicode="" d="M200 1100h800q83 0 141.5 -58.5t58.5 -141.5v-200h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100q0 41 -29.5 70.5t-70.5 29.5h-250q-41 0 -70.5 -29.5t-29.5 -70.5h-100v200q0 83 58.5 141.5t141.5 58.5zM100 600h1000q41 0 70.5 -29.5 t29.5 -70.5v-300h-1200v300q0 41 29.5 70.5t70.5 29.5zM300 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200zM1100 100v-50q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v50h200z" />
+<glyph unicode="" d="M480 1165l682 -683q31 -31 31 -75.5t-31 -75.5l-131 -131h-481l-517 518q-32 31 -32 75.5t32 75.5l295 296q31 31 75.5 31t76.5 -31zM108 794l342 -342l303 304l-341 341zM250 100h800q21 0 35.5 -14.5t14.5 -35.5v-50h-900v50q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M1057 647l-189 506q-8 19 -27.5 33t-40.5 14h-400q-21 0 -40.5 -14t-27.5 -33l-189 -506q-8 -19 1.5 -33t30.5 -14h625v-150q0 -21 14.5 -35.5t35.5 -14.5t35.5 14.5t14.5 35.5v150h125q21 0 30.5 14t1.5 33zM897 0h-595v50q0 21 14.5 35.5t35.5 14.5h50v50 q0 21 14.5 35.5t35.5 14.5h48v300h200v-300h47q21 0 35.5 -14.5t14.5 -35.5v-50h50q21 0 35.5 -14.5t14.5 -35.5v-50z" />
+<glyph unicode="" d="M900 800h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-375v591l-300 300v84q0 10 7.5 17.5t17.5 7.5h375v-400zM1200 900h-200v200zM400 600h300v-575q0 -10 -7.5 -17.5t-17.5 -7.5h-650q-10 0 -17.5 7.5t-7.5 17.5v950q0 10 7.5 17.5t17.5 7.5h375v-400zM700 700h-200v200z " />
+<glyph unicode="" d="M484 1095h195q75 0 146 -32.5t124 -86t89.5 -122.5t48.5 -142q18 -14 35 -20q31 -10 64.5 6.5t43.5 48.5q10 34 -15 71q-19 27 -9 43q5 8 12.5 11t19 -1t23.5 -16q41 -44 39 -105q-3 -63 -46 -106.5t-104 -43.5h-62q-7 -55 -35 -117t-56 -100l-39 -234q-3 -20 -20 -34.5 t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l12 70q-49 -14 -91 -14h-195q-24 0 -65 8l-11 -64q-3 -20 -20 -34.5t-38 -14.5h-100q-21 0 -33 14.5t-9 34.5l26 157q-84 74 -128 175l-159 53q-19 7 -33 26t-14 40v50q0 21 14.5 35.5t35.5 14.5h124q11 87 56 166l-111 95 q-16 14 -12.5 23.5t24.5 9.5h203q116 101 250 101zM675 1000h-250q-10 0 -17.5 -7.5t-7.5 -17.5v-50q0 -10 7.5 -17.5t17.5 -7.5h250q10 0 17.5 7.5t7.5 17.5v50q0 10 -7.5 17.5t-17.5 7.5z" />
+<glyph unicode="" d="M641 900l423 247q19 8 42 2.5t37 -21.5l32 -38q14 -15 12.5 -36t-17.5 -34l-139 -120h-390zM50 1100h106q67 0 103 -17t66 -71l102 -212h823q21 0 35.5 -14.5t14.5 -35.5v-50q0 -21 -14 -40t-33 -26l-737 -132q-23 -4 -40 6t-26 25q-42 67 -100 67h-300q-62 0 -106 44 t-44 106v200q0 62 44 106t106 44zM173 928h-80q-19 0 -28 -14t-9 -35v-56q0 -51 42 -51h134q16 0 21.5 8t5.5 24q0 11 -16 45t-27 51q-18 28 -43 28zM550 727q-32 0 -54.5 -22.5t-22.5 -54.5t22.5 -54.5t54.5 -22.5t54.5 22.5t22.5 54.5t-22.5 54.5t-54.5 22.5zM130 389 l152 130q18 19 34 24t31 -3.5t24.5 -17.5t25.5 -28q28 -35 50.5 -51t48.5 -13l63 5l48 -179q13 -61 -3.5 -97.5t-67.5 -79.5l-80 -69q-47 -40 -109 -35.5t-103 51.5l-130 151q-40 47 -35.5 109.5t51.5 102.5zM380 377l-102 -88q-31 -27 2 -65l37 -43q13 -15 27.5 -19.5 t31.5 6.5l61 53q19 16 14 49q-2 20 -12 56t-17 45q-11 12 -19 14t-23 -8z" />
+<glyph unicode="" d="M625 1200h150q10 0 17.5 -7.5t7.5 -17.5v-109q79 -33 131 -87.5t53 -128.5q1 -46 -15 -84.5t-39 -61t-46 -38t-39 -21.5l-17 -6q6 0 15 -1.5t35 -9t50 -17.5t53 -30t50 -45t35.5 -64t14.5 -84q0 -59 -11.5 -105.5t-28.5 -76.5t-44 -51t-49.5 -31.5t-54.5 -16t-49.5 -6.5 t-43.5 -1v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-100v-75q0 -10 -7.5 -17.5t-17.5 -7.5h-150q-10 0 -17.5 7.5t-7.5 17.5v75h-175q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5h75v600h-75q-10 0 -17.5 7.5t-7.5 17.5v150 q0 10 7.5 17.5t17.5 7.5h175v75q0 10 7.5 17.5t17.5 7.5h150q10 0 17.5 -7.5t7.5 -17.5v-75h100v75q0 10 7.5 17.5t17.5 7.5zM400 900v-200h263q28 0 48.5 10.5t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-263zM400 500v-200h363q28 0 48.5 10.5 t30 25t15 29t5.5 25.5l1 10q0 4 -0.5 11t-6 24t-15 30t-30 24t-48.5 11h-363z" />
+<glyph unicode="" d="M212 1198h780q86 0 147 -61t61 -147v-416q0 -51 -18 -142.5t-36 -157.5l-18 -66q-29 -87 -93.5 -146.5t-146.5 -59.5h-572q-82 0 -147 59t-93 147q-8 28 -20 73t-32 143.5t-20 149.5v416q0 86 61 147t147 61zM600 1045q-70 0 -132.5 -11.5t-105.5 -30.5t-78.5 -41.5 t-57 -45t-36 -41t-20.5 -30.5l-6 -12l156 -243h560l156 243q-2 5 -6 12.5t-20 29.5t-36.5 42t-57 44.5t-79 42t-105 29.5t-132.5 12zM762 703h-157l195 261z" />
+<glyph unicode="" d="M475 1300h150q103 0 189 -86t86 -189v-500q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="" d="M475 1300h96q0 -150 89.5 -239.5t239.5 -89.5v-446q0 -41 -42 -83t-83 -42h-450q-41 0 -83 42t-42 83v500q0 103 86 189t189 86zM700 300v-225q0 -21 -27 -48t-48 -27h-150q-21 0 -48 27t-27 48v225h300z" />
+<glyph unicode="" d="M1294 767l-638 -283l-378 170l-78 -60v-224l100 -150v-199l-150 148l-150 -149v200l100 150v250q0 4 -0.5 10.5t0 9.5t1 8t3 8t6.5 6l47 40l-147 65l642 283zM1000 380l-350 -166l-350 166v147l350 -165l350 165v-147z" />
+<glyph unicode="" d="M250 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM650 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM1050 800q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="" d="M550 1100q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 700q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44zM550 300q62 0 106 -44t44 -106t-44 -106t-106 -44t-106 44t-44 106t44 106t106 44z" />
+<glyph unicode="" d="M125 1100h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5zM125 700h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5 t17.5 7.5zM125 300h950q10 0 17.5 -7.5t7.5 -17.5v-150q0 -10 -7.5 -17.5t-17.5 -7.5h-950q-10 0 -17.5 7.5t-7.5 17.5v150q0 10 7.5 17.5t17.5 7.5z" />
+<glyph unicode="" d="M350 1200h500q162 0 256 -93.5t94 -256.5v-500q0 -165 -93.5 -257.5t-256.5 -92.5h-500q-165 0 -257.5 92.5t-92.5 257.5v500q0 165 92.5 257.5t257.5 92.5zM900 1000h-600q-41 0 -70.5 -29.5t-29.5 -70.5v-600q0 -41 29.5 -70.5t70.5 -29.5h600q41 0 70.5 29.5 t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5zM350 900h500q21 0 35.5 -14.5t14.5 -35.5v-300q0 -21 -14.5 -35.5t-35.5 -14.5h-500q-21 0 -35.5 14.5t-14.5 35.5v300q0 21 14.5 35.5t35.5 14.5zM400 800v-200h400v200h-400z" />
+<glyph unicode="" d="M150 1100h1000q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5t-35.5 -14.5h-50v-200h50q21 0 35.5 -14.5t14.5 -35.5t-14.5 -35.5 t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5h50v200h-50q-21 0 -35.5 14.5t-14.5 35.5t14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M650 1187q87 -67 118.5 -156t0 -178t-118.5 -155q-87 66 -118.5 155t0 178t118.5 156zM300 800q124 0 212 -88t88 -212q-124 0 -212 88t-88 212zM1000 800q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM300 500q124 0 212 -88t88 -212q-124 0 -212 88t-88 212z M1000 500q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM700 199v-144q0 -21 -14.5 -35.5t-35.5 -14.5t-35.5 14.5t-14.5 35.5v142q40 -4 43 -4q17 0 57 6z" />
+<glyph unicode="" d="M745 878l69 19q25 6 45 -12l298 -295q11 -11 15 -26.5t-2 -30.5q-5 -14 -18 -23.5t-28 -9.5h-8q1 0 1 -13q0 -29 -2 -56t-8.5 -62t-20 -63t-33 -53t-51 -39t-72.5 -14h-146q-184 0 -184 288q0 24 10 47q-20 4 -62 4t-63 -4q11 -24 11 -47q0 -288 -184 -288h-142 q-48 0 -84.5 21t-56 51t-32 71.5t-16 75t-3.5 68.5q0 13 2 13h-7q-15 0 -27.5 9.5t-18.5 23.5q-6 15 -2 30.5t15 25.5l298 296q20 18 46 11l76 -19q20 -5 30.5 -22.5t5.5 -37.5t-22.5 -31t-37.5 -5l-51 12l-182 -193h891l-182 193l-44 -12q-20 -5 -37.5 6t-22.5 31t6 37.5 t31 22.5z" />
+<glyph unicode="" d="M1200 900h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-200v-850q0 -22 25 -34.5t50 -13.5l25 -2v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v850h-200q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h1000v-300zM500 450h-25q0 15 -4 24.5t-9 14.5t-17 7.5t-20 3t-25 0.5h-100v-425q0 -11 12.5 -17.5t25.5 -7.5h12v-50h-200v50q50 0 50 25v425h-100q-17 0 -25 -0.5t-20 -3t-17 -7.5t-9 -14.5t-4 -24.5h-25v150h500v-150z" />
+<glyph unicode="" d="M1000 300v50q-25 0 -55 32q-14 14 -25 31t-16 27l-4 11l-289 747h-69l-300 -754q-18 -35 -39 -56q-9 -9 -24.5 -18.5t-26.5 -14.5l-11 -5v-50h273v50q-49 0 -78.5 21.5t-11.5 67.5l69 176h293l61 -166q13 -34 -3.5 -66.5t-55.5 -32.5v-50h312zM412 691l134 342l121 -342 h-255zM1100 150v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5z" />
+<glyph unicode="" d="M50 1200h1100q21 0 35.5 -14.5t14.5 -35.5v-1100q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5v1100q0 21 14.5 35.5t35.5 14.5zM611 1118h-70q-13 0 -18 -12l-299 -753q-17 -32 -35 -51q-18 -18 -56 -34q-12 -5 -12 -18v-50q0 -8 5.5 -14t14.5 -6 h273q8 0 14 6t6 14v50q0 8 -6 14t-14 6q-55 0 -71 23q-10 14 0 39l63 163h266l57 -153q11 -31 -6 -55q-12 -17 -36 -17q-8 0 -14 -6t-6 -14v-50q0 -8 6 -14t14 -6h313q8 0 14 6t6 14v50q0 7 -5.5 13t-13.5 7q-17 0 -42 25q-25 27 -40 63h-1l-288 748q-5 12 -19 12zM639 611 h-197l103 264z" />
+<glyph unicode="" d="M1200 1100h-1200v100h1200v-100zM50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 1000h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM700 900v-300h300v300h-300z" />
+<glyph unicode="" d="M50 1200h400q21 0 35.5 -14.5t14.5 -35.5v-900q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v900q0 21 14.5 35.5t35.5 14.5zM650 700h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400 q0 21 14.5 35.5t35.5 14.5zM700 600v-300h300v300h-300zM1200 0h-1200v100h1200v-100z" />
+<glyph unicode="" d="M50 1000h400q21 0 35.5 -14.5t14.5 -35.5v-350h100v150q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-150h100v-100h-100v-150q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v150h-100v-350q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5v800q0 21 14.5 35.5t35.5 14.5zM700 700v-300h300v300h-300z" />
+<glyph unicode="" d="M100 0h-100v1200h100v-1200zM250 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM300 1000v-300h300v300h-300zM250 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M600 1100h150q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-100h450q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h350v100h-150q-21 0 -35.5 14.5 t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5h150v100h100v-100zM400 1000v-300h300v300h-300z" />
+<glyph unicode="" d="M1200 0h-100v1200h100v-1200zM550 1100h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM600 1000v-300h300v300h-300zM50 500h900q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-900q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5z" />
+<glyph unicode="" d="M865 565l-494 -494q-23 -23 -41 -23q-14 0 -22 13.5t-8 38.5v1000q0 25 8 38.5t22 13.5q18 0 41 -23l494 -494q14 -14 14 -35t-14 -35z" />
+<glyph unicode="" d="M335 635l494 494q29 29 50 20.5t21 -49.5v-1000q0 -41 -21 -49.5t-50 20.5l-494 494q-14 14 -14 35t14 35z" />
+<glyph unicode="" d="M100 900h1000q41 0 49.5 -21t-20.5 -50l-494 -494q-14 -14 -35 -14t-35 14l-494 494q-29 29 -20.5 50t49.5 21z" />
+<glyph unicode="" d="M635 865l494 -494q29 -29 20.5 -50t-49.5 -21h-1000q-41 0 -49.5 21t20.5 50l494 494q14 14 35 14t35 -14z" />
+<glyph unicode="" d="M700 741v-182l-692 -323v221l413 193l-413 193v221zM1200 0h-800v200h800v-200z" />
+<glyph unicode="" d="M1200 900h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300zM0 700h50q0 21 4 37t9.5 26.5t18 17.5t22 11t28.5 5.5t31 2t37 0.5h100v-550q0 -22 -25 -34.5t-50 -13.5l-25 -2v-100h400v100q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v550h100q25 0 37 -0.5t31 -2 t28.5 -5.5t22 -11t18 -17.5t9.5 -26.5t4 -37h50v300h-800v-300z" />
+<glyph unicode="" d="M800 700h-50q0 21 -4 37t-9.5 26.5t-18 17.5t-22 11t-28.5 5.5t-31 2t-37 0.5h-100v-550q0 -22 25 -34.5t50 -14.5l25 -1v-100h-400v100q4 0 11 0.5t24 3t30 7t24 15t11 24.5v550h-100q-25 0 -37 -0.5t-31 -2t-28.5 -5.5t-22 -11t-18 -17.5t-9.5 -26.5t-4 -37h-50v300 h800v-300zM1100 200h-200v-100h200v-100h-300v300h200v100h-200v100h300v-300z" />
+<glyph unicode="" d="M701 1098h160q16 0 21 -11t-7 -23l-464 -464l464 -464q12 -12 7 -23t-21 -11h-160q-13 0 -23 9l-471 471q-7 8 -7 18t7 18l471 471q10 9 23 9z" />
+<glyph unicode="" d="M339 1098h160q13 0 23 -9l471 -471q7 -8 7 -18t-7 -18l-471 -471q-10 -9 -23 -9h-160q-16 0 -21 11t7 23l464 464l-464 464q-12 12 -7 23t21 11z" />
+<glyph unicode="" d="M1087 882q11 -5 11 -21v-160q0 -13 -9 -23l-471 -471q-8 -7 -18 -7t-18 7l-471 471q-9 10 -9 23v160q0 16 11 21t23 -7l464 -464l464 464q12 12 23 7z" />
+<glyph unicode="" d="M618 993l471 -471q9 -10 9 -23v-160q0 -16 -11 -21t-23 7l-464 464l-464 -464q-12 -12 -23 -7t-11 21v160q0 13 9 23l471 471q8 7 18 7t18 -7z" />
+<glyph unicode="" d="M1000 1200q0 -124 -88 -212t-212 -88q0 124 88 212t212 88zM450 1000h100q21 0 40 -14t26 -33l79 -194q5 1 16 3q34 6 54 9.5t60 7t65.5 1t61 -10t56.5 -23t42.5 -42t29 -64t5 -92t-19.5 -121.5q-1 -7 -3 -19.5t-11 -50t-20.5 -73t-32.5 -81.5t-46.5 -83t-64 -70 t-82.5 -50q-13 -5 -42 -5t-65.5 2.5t-47.5 2.5q-14 0 -49.5 -3.5t-63 -3.5t-43.5 7q-57 25 -104.5 78.5t-75 111.5t-46.5 112t-26 90l-7 35q-15 63 -18 115t4.5 88.5t26 64t39.5 43.5t52 25.5t58.5 13t62.5 2t59.5 -4.5t55.5 -8l-147 192q-12 18 -5.5 30t27.5 12z" />
+<glyph unicode="🔑" d="M250 1200h600q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-150v-500l-255 -178q-19 -9 -32 -1t-13 29v650h-150q-21 0 -35.5 14.5t-14.5 35.5v400q0 21 14.5 35.5t35.5 14.5zM400 1100v-100h300v100h-300z" />
+<glyph unicode="🚪" d="M250 1200h750q39 0 69.5 -40.5t30.5 -84.5v-933l-700 -117v950l600 125h-700v-1000h-100v1025q0 23 15.5 49t34.5 26zM500 525v-100l100 20v100z" />
+</font>
+</defs></svg>
\ No newline at end of file
--- /dev/null
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+
+if (typeof jQuery === 'undefined') {
+ throw new Error('Bootstrap\'s JavaScript requires jQuery')
+}
+
++function ($) {
+ 'use strict';
+ 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.5
+ * http://getbootstrap.com/javascript/#transitions
+ * ========================================================================
+ * Copyright 2011-2015 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.5
+ * http://getbootstrap.com/javascript/#alerts
+ * ========================================================================
+ * Copyright 2011-2015 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.5'
+
+ 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.5
+ * http://getbootstrap.com/javascript/#buttons
+ * ========================================================================
+ * Copyright 2011-2015 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.5'
+
+ 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 += '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')) changed = false
+ $parent.find('.active').removeClass('active')
+ this.$element.addClass('active')
+ } else if ($input.prop('type') == 'checkbox') {
+ if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
+ this.$element.toggleClass('active')
+ }
+ $input.prop('checked', this.$element.hasClass('active'))
+ if (changed) $input.trigger('change')
+ } else {
+ this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
+ 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')
+ if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
+ })
+ .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
+ $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: carousel.js v3.3.5
+ * http://getbootstrap.com/javascript/#carousel
+ * ========================================================================
+ * Copyright 2011-2015 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 = null
+ this.sliding = null
+ this.interval = null
+ this.$active = null
+ 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.5'
+
+ Carousel.TRANSITION_DURATION = 600
+
+ Carousel.DEFAULTS = {
+ interval: 5000,
+ pause: 'hover',
+ wrap: true,
+ keyboard: true
+ }
+
+ Carousel.prototype.keydown = function (e) {
+ if (/input|textarea/i.test(e.target.tagName)) return
+ 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 activeIndex = this.getItemIndex(active)
+ var willWrap = (direction == 'prev' && activeIndex === 0)
+ || (direction == 'next' && activeIndex == (this.$items.length - 1))
+ if (willWrap && !this.options.wrap) return active
+ var delta = direction == 'prev' ? -1 : 1
+ 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 that = this
+
+ 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.5
+ * http://getbootstrap.com/javascript/#collapse
+ * ========================================================================
+ * Copyright 2011-2015 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 = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
+ '[data-toggle="collapse"][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.5'
+
+ Collapse.TRANSITION_DURATION = 350
+
+ Collapse.DEFAULTS = {
+ toggle: true
+ }
+
+ 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.children('.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 && /show|hide/.test(option)) 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' : $this.data()
+
+ Plugin.call($target, option)
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.3.5
+ * http://getbootstrap.com/javascript/#dropdowns
+ * ========================================================================
+ * Copyright 2011-2015 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.5'
+
+ function getParent($this) {
+ var selector = $this.attr('data-target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ var $parent = selector && $(selector)
+
+ return $parent && $parent.length ? $parent : $this.parent()
+ }
+
+ function clearMenus(e) {
+ if (e && e.which === 3) return
+ $(backdrop).remove()
+ $(toggle).each(function () {
+ var $this = $(this)
+ var $parent = getParent($this)
+ var relatedTarget = { relatedTarget: this }
+
+ if (!$parent.hasClass('open')) return
+
+ if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
+
+ $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $this.attr('aria-expanded', 'false')
+ $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
+ })
+ }
+
+ 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
+ $(document.createElement('div'))
+ .addClass('dropdown-backdrop')
+ .insertAfter($(this))
+ .on('click', clearMenus)
+ }
+
+ var relatedTarget = { relatedTarget: this }
+ $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
+
+ if (e.isDefaultPrevented()) return
+
+ $this
+ .trigger('focus')
+ .attr('aria-expanded', 'true')
+
+ $parent
+ .toggleClass('open')
+ .trigger('shown.bs.dropdown', relatedTarget)
+ }
+
+ return false
+ }
+
+ Dropdown.prototype.keydown = function (e) {
+ if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
+
+ var $this = $(this)
+
+ e.preventDefault()
+ e.stopPropagation()
+
+ if ($this.is('.disabled, :disabled')) return
+
+ var $parent = getParent($this)
+ var isActive = $parent.hasClass('open')
+
+ if (!isActive && e.which != 27 || isActive && e.which == 27) {
+ if (e.which == 27) $parent.find(toggle).trigger('focus')
+ return $this.trigger('click')
+ }
+
+ var desc = ' li:not(.disabled):visible a'
+ var $items = $parent.find('.dropdown-menu' + desc)
+
+ if (!$items.length) return
+
+ var index = $items.index(e.target)
+
+ if (e.which == 38 && index > 0) index-- // up
+ if (e.which == 40 && index < $items.length - 1) index++ // down
+ if (!~index) index = 0
+
+ $items.eq(index).trigger('focus')
+ }
+
+
+ // DROPDOWN PLUGIN DEFINITION
+ // ==========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.dropdown')
+
+ if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ var old = $.fn.dropdown
+
+ $.fn.dropdown = Plugin
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ // DROPDOWN NO CONFLICT
+ // ====================
+
+ $.fn.dropdown.noConflict = function () {
+ $.fn.dropdown = old
+ return this
+ }
+
+
+ // APPLY TO STANDARD DROPDOWN ELEMENTS
+ // ===================================
+
+ $(document)
+ .on('click.bs.dropdown.data-api', clearMenus)
+ .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+ .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
+ .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: modal.js v3.3.5
+ * http://getbootstrap.com/javascript/#modals
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // MODAL CLASS DEFINITION
+ // ======================
+
+ var Modal = function (element, options) {
+ this.options = options
+ this.$body = $(document.body)
+ this.$element = $(element)
+ this.$dialog = this.$element.find('.modal-dialog')
+ this.$backdrop = null
+ this.isShown = null
+ this.originalBodyPad = null
+ this.scrollbarWidth = 0
+ this.ignoreBackdropClick = false
+
+ if (this.options.remote) {
+ this.$element
+ .find('.modal-content')
+ .load(this.options.remote, $.proxy(function () {
+ this.$element.trigger('loaded.bs.modal')
+ }, this))
+ }
+ }
+
+ Modal.VERSION = '3.3.5'
+
+ Modal.TRANSITION_DURATION = 300
+ Modal.BACKDROP_TRANSITION_DURATION = 150
+
+ Modal.DEFAULTS = {
+ backdrop: true,
+ keyboard: true,
+ show: true
+ }
+
+ Modal.prototype.toggle = function (_relatedTarget) {
+ return this.isShown ? this.hide() : this.show(_relatedTarget)
+ }
+
+ Modal.prototype.show = function (_relatedTarget) {
+ var that = this
+ var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+ this.$element.trigger(e)
+
+ if (this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = true
+
+ this.checkScrollbar()
+ this.setScrollbar()
+ this.$body.addClass('modal-open')
+
+ this.escape()
+ this.resize()
+
+ this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+ this.$dialog.on('mousedown.dismiss.bs.modal', function () {
+ that.$element.one('mouseup.dismiss.bs.modal', function (e) {
+ if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
+ })
+ })
+
+ this.backdrop(function () {
+ var transition = $.support.transition && that.$element.hasClass('fade')
+
+ if (!that.$element.parent().length) {
+ that.$element.appendTo(that.$body) // don't move modals dom position
+ }
+
+ that.$element
+ .show()
+ .scrollTop(0)
+
+ that.adjustDialog()
+
+ if (transition) {
+ that.$element[0].offsetWidth // force reflow
+ }
+
+ that.$element.addClass('in')
+
+ that.enforceFocus()
+
+ var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+ transition ?
+ that.$dialog // wait for modal to slide in
+ .one('bsTransitionEnd', function () {
+ that.$element.trigger('focus').trigger(e)
+ })
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+ that.$element.trigger('focus').trigger(e)
+ })
+ }
+
+ Modal.prototype.hide = function (e) {
+ if (e) e.preventDefault()
+
+ e = $.Event('hide.bs.modal')
+
+ this.$element.trigger(e)
+
+ if (!this.isShown || e.isDefaultPrevented()) return
+
+ this.isShown = false
+
+ this.escape()
+ this.resize()
+
+ $(document).off('focusin.bs.modal')
+
+ this.$element
+ .removeClass('in')
+ .off('click.dismiss.bs.modal')
+ .off('mouseup.dismiss.bs.modal')
+
+ this.$dialog.off('mousedown.dismiss.bs.modal')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$element
+ .one('bsTransitionEnd', $.proxy(this.hideModal, this))
+ .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
+ this.hideModal()
+ }
+
+ Modal.prototype.enforceFocus = function () {
+ $(document)
+ .off('focusin.bs.modal') // guard against infinite focus loop
+ .on('focusin.bs.modal', $.proxy(function (e) {
+ if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+ this.$element.trigger('focus')
+ }
+ }, this))
+ }
+
+ Modal.prototype.escape = function () {
+ if (this.isShown && this.options.keyboard) {
+ this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
+ e.which == 27 && this.hide()
+ }, this))
+ } else if (!this.isShown) {
+ this.$element.off('keydown.dismiss.bs.modal')
+ }
+ }
+
+ Modal.prototype.resize = function () {
+ if (this.isShown) {
+ $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
+ } else {
+ $(window).off('resize.bs.modal')
+ }
+ }
+
+ Modal.prototype.hideModal = function () {
+ var that = this
+ this.$element.hide()
+ this.backdrop(function () {
+ that.$body.removeClass('modal-open')
+ that.resetAdjustments()
+ that.resetScrollbar()
+ that.$element.trigger('hidden.bs.modal')
+ })
+ }
+
+ Modal.prototype.removeBackdrop = function () {
+ this.$backdrop && this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ Modal.prototype.backdrop = function (callback) {
+ var that = this
+ var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $(document.createElement('div'))
+ .addClass('modal-backdrop ' + animate)
+ .appendTo(this.$body)
+
+ this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
+ if (this.ignoreBackdropClick) {
+ this.ignoreBackdropClick = false
+ return
+ }
+ if (e.target !== e.currentTarget) return
+ this.options.backdrop == 'static'
+ ? this.$element[0].focus()
+ : this.hide()
+ }, this))
+
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+ this.$backdrop.addClass('in')
+
+ if (!callback) return
+
+ doAnimate ?
+ this.$backdrop
+ .one('bsTransitionEnd', callback)
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+ callback()
+
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
+
+ var callbackRemove = function () {
+ that.removeBackdrop()
+ callback && callback()
+ }
+ $.support.transition && this.$element.hasClass('fade') ?
+ this.$backdrop
+ .one('bsTransitionEnd', callbackRemove)
+ .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
+ callbackRemove()
+
+ } else if (callback) {
+ callback()
+ }
+ }
+
+ // these following methods are used to handle overflowing modals
+
+ Modal.prototype.handleUpdate = function () {
+ this.adjustDialog()
+ }
+
+ Modal.prototype.adjustDialog = function () {
+ var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
+
+ this.$element.css({
+ paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
+ paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
+ })
+ }
+
+ Modal.prototype.resetAdjustments = function () {
+ this.$element.css({
+ paddingLeft: '',
+ paddingRight: ''
+ })
+ }
+
+ Modal.prototype.checkScrollbar = function () {
+ var fullWindowWidth = window.innerWidth
+ if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
+ var documentElementRect = document.documentElement.getBoundingClientRect()
+ fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
+ }
+ this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
+ this.scrollbarWidth = this.measureScrollbar()
+ }
+
+ Modal.prototype.setScrollbar = function () {
+ var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
+ this.originalBodyPad = document.body.style.paddingRight || ''
+ if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
+ }
+
+ Modal.prototype.resetScrollbar = function () {
+ this.$body.css('padding-right', this.originalBodyPad)
+ }
+
+ Modal.prototype.measureScrollbar = function () { // thx walsh
+ var scrollDiv = document.createElement('div')
+ scrollDiv.className = 'modal-scrollbar-measure'
+ this.$body.append(scrollDiv)
+ var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
+ this.$body[0].removeChild(scrollDiv)
+ return scrollbarWidth
+ }
+
+
+ // MODAL PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option, _relatedTarget) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.modal')
+ var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+ if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+ if (typeof option == 'string') data[option](_relatedTarget)
+ else if (options.show) data.show(_relatedTarget)
+ })
+ }
+
+ var old = $.fn.modal
+
+ $.fn.modal = Plugin
+ $.fn.modal.Constructor = Modal
+
+
+ // MODAL NO CONFLICT
+ // =================
+
+ $.fn.modal.noConflict = function () {
+ $.fn.modal = old
+ return this
+ }
+
+
+ // MODAL DATA-API
+ // ==============
+
+ $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+ var $this = $(this)
+ var href = $this.attr('href')
+ var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
+ var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+ if ($this.is('a')) e.preventDefault()
+
+ $target.one('show.bs.modal', function (showEvent) {
+ if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
+ $target.one('hidden.bs.modal', function () {
+ $this.is(':visible') && $this.trigger('focus')
+ })
+ })
+ Plugin.call($target, option, this)
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.3.5
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Tooltip = function (element, options) {
+ this.type = null
+ this.options = null
+ this.enabled = null
+ this.timeout = null
+ this.hoverState = null
+ this.$element = null
+ this.inState = null
+
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.VERSION = '3.3.5'
+
+ Tooltip.TRANSITION_DURATION = 150
+
+ Tooltip.DEFAULTS = {
+ animation: true,
+ placement: 'top',
+ selector: false,
+ template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+ trigger: 'hover focus',
+ title: '',
+ delay: 0,
+ html: false,
+ container: false,
+ viewport: {
+ selector: 'body',
+ padding: 0
+ }
+ }
+
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+ this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
+ this.inState = { click: false, hover: false, focus: false }
+
+ if (this.$element[0] instanceof document.constructor && !this.options.selector) {
+ throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
+ }
+
+ var triggers = this.options.trigger.split(' ')
+
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ }
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
+
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay,
+ hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget).data('bs.' + this.type)
+
+ if (!self) {
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+ $(obj.currentTarget).data('bs.' + this.type, self)
+ }
+
+ if (obj instanceof $.Event) {
+ self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
+ }
+
+ if (self.tip().hasClass('in') || self.hoverState == 'in') {
+ self.hoverState = 'in'
+ return
+ }
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.isInStateTrue = function () {
+ for (var key in this.inState) {
+ if (this.inState[key]) return true
+ }
+
+ return false
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget).data('bs.' + this.type)
+
+ if (!self) {
+ self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
+ $(obj.currentTarget).data('bs.' + this.type, self)
+ }
+
+ if (obj instanceof $.Event) {
+ self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
+ }
+
+ if (self.isInStateTrue()) return
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.' + this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
+
+ var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
+ if (e.isDefaultPrevented() || !inDom) return
+ var that = this
+
+ var $tip = this.tip()
+
+ var tipId = this.getUID(this.type)
+
+ this.setContent()
+ $tip.attr('id', tipId)
+ this.$element.attr('aria-describedby', tipId)
+
+ if (this.options.animation) $tip.addClass('fade')
+
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
+ .data('bs.' + this.type, this)
+
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+ this.$element.trigger('inserted.bs.' + this.type)
+
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var orgPlacement = placement
+ var viewportDim = this.getPosition(this.$viewport)
+
+ placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
+ placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
+ placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
+ }
+
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+ this.applyPlacement(calculatedOffset, placement)
+
+ var complete = function () {
+ var prevHoverState = that.hoverState
+ that.$element.trigger('shown.bs.' + that.type)
+ that.hoverState = null
+
+ if (prevHoverState == 'out') that.leave(that)
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one('bsTransitionEnd', complete)
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+ complete()
+ }
+ }
+
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
+
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top += marginTop
+ offset.left += marginLeft
+
+ // $.fn.offset doesn't round pixel values
+ // so we use setOffset directly with our own function B-0
+ $.offset.setOffset($tip[0], $.extend({
+ using: function (props) {
+ $tip.css({
+ top: Math.round(props.top),
+ left: Math.round(props.left)
+ })
+ }
+ }, offset), 0)
+
+ $tip.addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ offset.top = offset.top + height - actualHeight
+ }
+
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
+
+ if (delta.left) offset.left += delta.left
+ else offset.top += delta.top
+
+ var isVertical = /top|bottom/.test(placement)
+ var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+ var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
+
+ $tip.offset(offset)
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
+ }
+
+ Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
+ this.arrow()
+ .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
+ .css(isVertical ? 'top' : 'left', '')
+ }
+
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ Tooltip.prototype.hide = function (callback) {
+ var that = this
+ var $tip = $(this.$tip)
+ var e = $.Event('hide.bs.' + this.type)
+
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
+ that.$element
+ .removeAttr('aria-describedby')
+ .trigger('hidden.bs.' + that.type)
+ callback && callback()
+ }
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ $tip.removeClass('in')
+
+ $.support.transition && $tip.hasClass('fade') ?
+ $tip
+ .one('bsTransitionEnd', complete)
+ .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
+ complete()
+
+ this.hoverState = null
+
+ return this
+ }
+
+ Tooltip.prototype.fixTitle = function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
+
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
+
+ Tooltip.prototype.getPosition = function ($element) {
+ $element = $element || this.$element
+
+ var el = $element[0]
+ var isBody = el.tagName == 'BODY'
+
+ var elRect = el.getBoundingClientRect()
+ if (elRect.width == null) {
+ // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
+ elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
+ }
+ var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()
+ var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
+ var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
+
+ return $.extend({}, elRect, scroll, outerDims, elOffset)
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+
+ }
+
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
+ var delta = { top: 0, left: 0 }
+ if (!this.$viewport) return delta
+
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
+ var viewportDimensions = this.getPosition(this.$viewport)
+
+ if (/right|left/.test(placement)) {
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
+ delta.top = viewportDimensions.top - topEdgeOffset
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+ }
+ } else {
+ var leftEdgeOffset = pos.left - viewportPadding
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+ delta.left = viewportDimensions.left - leftEdgeOffset
+ } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+ }
+ }
+
+ return delta
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.getUID = function (prefix) {
+ do prefix += ~~(Math.random() * 1000000)
+ while (document.getElementById(prefix))
+ return prefix
+ }
+
+ Tooltip.prototype.tip = function () {
+ if (!this.$tip) {
+ this.$tip = $(this.options.template)
+ if (this.$tip.length != 1) {
+ throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
+ }
+ }
+ return this.$tip
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = this
+ if (e) {
+ self = $(e.currentTarget).data('bs.' + this.type)
+ if (!self) {
+ self = new this.constructor(e.currentTarget, this.getDelegateOptions())
+ $(e.currentTarget).data('bs.' + this.type, self)
+ }
+ }
+
+ if (e) {
+ self.inState.click = !self.inState.click
+ if (self.isInStateTrue()) self.enter(self)
+ else self.leave(self)
+ } else {
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+ }
+
+ Tooltip.prototype.destroy = function () {
+ var that = this
+ clearTimeout(this.timeout)
+ this.hide(function () {
+ that.$element.off('.' + that.type).removeData('bs.' + that.type)
+ if (that.$tip) {
+ that.$tip.detach()
+ }
+ that.$tip = null
+ that.$arrow = null
+ that.$viewport = null
+ })
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+
+ if (!data && /destroy|hide/.test(option)) return
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = Plugin
+ $.fn.tooltip.Constructor = Tooltip
+
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.3.5
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // POPOVER PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Popover = function (element, options) {
+ this.init('popover', element, options)
+ }
+
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+ Popover.VERSION = '3.3.5'
+
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+ placement: 'right',
+ trigger: 'click',
+ content: '',
+ template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+ })
+
+
+ // NOTE: POPOVER EXTENDS tooltip.js
+ // ================================
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+ Popover.prototype.constructor = Popover
+
+ Popover.prototype.getDefaults = function () {
+ return Popover.DEFAULTS
+ }
+
+ Popover.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+ var content = this.getContent()
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+ ](content)
+
+ $tip.removeClass('fade top bottom left right in')
+
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+ // this manually by checking the contents.
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+ }
+
+ Popover.prototype.hasContent = function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ Popover.prototype.getContent = function () {
+ var $e = this.$element
+ var o = this.options
+
+ return $e.attr('data-content')
+ || (typeof o.content == 'function' ?
+ o.content.call($e[0]) :
+ o.content)
+ }
+
+ Popover.prototype.arrow = function () {
+ return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
+ }
+
+
+ // POPOVER PLUGIN DEFINITION
+ // =========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.popover')
+ var options = typeof option == 'object' && option
+
+ if (!data && /destroy|hide/.test(option)) return
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.popover
+
+ $.fn.popover = Plugin
+ $.fn.popover.Constructor = Popover
+
+
+ // POPOVER NO CONFLICT
+ // ===================
+
+ $.fn.popover.noConflict = function () {
+ $.fn.popover = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.3.5
+ * http://getbootstrap.com/javascript/#scrollspy
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // SCROLLSPY CLASS DEFINITION
+ // ==========================
+
+ function ScrollSpy(element, options) {
+ this.$body = $(document.body)
+ this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
+ this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
+ this.selector = (this.options.target || '') + ' .nav li > a'
+ this.offsets = []
+ this.targets = []
+ this.activeTarget = null
+ this.scrollHeight = 0
+
+ this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
+ this.refresh()
+ this.process()
+ }
+
+ ScrollSpy.VERSION = '3.3.5'
+
+ ScrollSpy.DEFAULTS = {
+ offset: 10
+ }
+
+ ScrollSpy.prototype.getScrollHeight = function () {
+ return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
+ }
+
+ ScrollSpy.prototype.refresh = function () {
+ var that = this
+ var offsetMethod = 'offset'
+ var offsetBase = 0
+
+ this.offsets = []
+ this.targets = []
+ this.scrollHeight = this.getScrollHeight()
+
+ if (!$.isWindow(this.$scrollElement[0])) {
+ offsetMethod = 'position'
+ offsetBase = this.$scrollElement.scrollTop()
+ }
+
+ this.$body
+ .find(this.selector)
+ .map(function () {
+ var $el = $(this)
+ var href = $el.data('target') || $el.attr('href')
+ var $href = /^#./.test(href) && $(href)
+
+ return ($href
+ && $href.length
+ && $href.is(':visible')
+ && [[$href[offsetMethod]().top + offsetBase, href]]) || null
+ })
+ .sort(function (a, b) { return a[0] - b[0] })
+ .each(function () {
+ that.offsets.push(this[0])
+ that.targets.push(this[1])
+ })
+ }
+
+ ScrollSpy.prototype.process = function () {
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+ var scrollHeight = this.getScrollHeight()
+ var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
+ var offsets = this.offsets
+ var targets = this.targets
+ var activeTarget = this.activeTarget
+ var i
+
+ if (this.scrollHeight != scrollHeight) {
+ this.refresh()
+ }
+
+ if (scrollTop >= maxScroll) {
+ return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
+ }
+
+ if (activeTarget && scrollTop < offsets[0]) {
+ this.activeTarget = null
+ return this.clear()
+ }
+
+ for (i = offsets.length; i--;) {
+ activeTarget != targets[i]
+ && scrollTop >= offsets[i]
+ && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
+ && this.activate(targets[i])
+ }
+ }
+
+ ScrollSpy.prototype.activate = function (target) {
+ this.activeTarget = target
+
+ this.clear()
+
+ var selector = this.selector +
+ '[data-target="' + target + '"],' +
+ this.selector + '[href="' + target + '"]'
+
+ var active = $(selector)
+ .parents('li')
+ .addClass('active')
+
+ if (active.parent('.dropdown-menu').length) {
+ active = active
+ .closest('li.dropdown')
+ .addClass('active')
+ }
+
+ active.trigger('activate.bs.scrollspy')
+ }
+
+ ScrollSpy.prototype.clear = function () {
+ $(this.selector)
+ .parentsUntil(this.options.target, '.active')
+ .removeClass('active')
+ }
+
+
+ // SCROLLSPY PLUGIN DEFINITION
+ // ===========================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.scrollspy')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.scrollspy
+
+ $.fn.scrollspy = Plugin
+ $.fn.scrollspy.Constructor = ScrollSpy
+
+
+ // SCROLLSPY NO CONFLICT
+ // =====================
+
+ $.fn.scrollspy.noConflict = function () {
+ $.fn.scrollspy = old
+ return this
+ }
+
+
+ // SCROLLSPY DATA-API
+ // ==================
+
+ $(window).on('load.bs.scrollspy.data-api', function () {
+ $('[data-spy="scroll"]').each(function () {
+ var $spy = $(this)
+ Plugin.call($spy, $spy.data())
+ })
+ })
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: tab.js v3.3.5
+ * http://getbootstrap.com/javascript/#tabs
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TAB CLASS DEFINITION
+ // ====================
+
+ var Tab = function (element) {
+ // jscs:disable requireDollarBeforejQueryAssignment
+ this.element = $(element)
+ // jscs:enable requireDollarBeforejQueryAssignment
+ }
+
+ Tab.VERSION = '3.3.5'
+
+ Tab.TRANSITION_DURATION = 150
+
+ Tab.prototype.show = function () {
+ var $this = this.element
+ var $ul = $this.closest('ul:not(.dropdown-menu)')
+ var selector = $this.data('target')
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+ }
+
+ if ($this.parent('li').hasClass('active')) return
+
+ var $previous = $ul.find('.active:last a')
+ var hideEvent = $.Event('hide.bs.tab', {
+ relatedTarget: $this[0]
+ })
+ var showEvent = $.Event('show.bs.tab', {
+ relatedTarget: $previous[0]
+ })
+
+ $previous.trigger(hideEvent)
+ $this.trigger(showEvent)
+
+ if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
+
+ var $target = $(selector)
+
+ this.activate($this.closest('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $previous.trigger({
+ type: 'hidden.bs.tab',
+ relatedTarget: $this[0]
+ })
+ $this.trigger({
+ type: 'shown.bs.tab',
+ relatedTarget: $previous[0]
+ })
+ })
+ }
+
+ Tab.prototype.activate = function (element, container, callback) {
+ var $active = container.find('> .active')
+ var transition = callback
+ && $.support.transition
+ && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', false)
+
+ element
+ .addClass('active')
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
+ }
+
+ if (element.parent('.dropdown-menu').length) {
+ element
+ .closest('li.dropdown')
+ .addClass('active')
+ .end()
+ .find('[data-toggle="tab"]')
+ .attr('aria-expanded', true)
+ }
+
+ callback && callback()
+ }
+
+ $active.length && transition ?
+ $active
+ .one('bsTransitionEnd', next)
+ .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
+ next()
+
+ $active.removeClass('in')
+ }
+
+
+ // TAB PLUGIN DEFINITION
+ // =====================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tab')
+
+ if (!data) $this.data('bs.tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.tab
+
+ $.fn.tab = Plugin
+ $.fn.tab.Constructor = Tab
+
+
+ // TAB NO CONFLICT
+ // ===============
+
+ $.fn.tab.noConflict = function () {
+ $.fn.tab = old
+ return this
+ }
+
+
+ // TAB DATA-API
+ // ============
+
+ var clickHandler = function (e) {
+ e.preventDefault()
+ Plugin.call($(this), 'show')
+ }
+
+ $(document)
+ .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
+ .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: affix.js v3.3.5
+ * http://getbootstrap.com/javascript/#affix
+ * ========================================================================
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // AFFIX CLASS DEFINITION
+ // ======================
+
+ var Affix = function (element, options) {
+ this.options = $.extend({}, Affix.DEFAULTS, options)
+
+ this.$target = $(this.options.target)
+ .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+ .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
+
+ this.$element = $(element)
+ this.affixed = null
+ this.unpin = null
+ this.pinnedOffset = null
+
+ this.checkPosition()
+ }
+
+ Affix.VERSION = '3.3.5'
+
+ Affix.RESET = 'affix affix-top affix-bottom'
+
+ Affix.DEFAULTS = {
+ offset: 0,
+ target: window
+ }
+
+ Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ var targetHeight = this.$target.height()
+
+ if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
+
+ if (this.affixed == 'bottom') {
+ if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
+ return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
+ }
+
+ var initializing = this.affixed == null
+ var colliderTop = initializing ? scrollTop : position.top
+ var colliderHeight = initializing ? targetHeight : height
+
+ if (offsetTop != null && scrollTop <= offsetTop) return 'top'
+ if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
+
+ return false
+ }
+
+ Affix.prototype.getPinnedOffset = function () {
+ if (this.pinnedOffset) return this.pinnedOffset
+ this.$element.removeClass(Affix.RESET).addClass('affix')
+ var scrollTop = this.$target.scrollTop()
+ var position = this.$element.offset()
+ return (this.pinnedOffset = position.top - scrollTop)
+ }
+
+ Affix.prototype.checkPositionWithEventLoop = function () {
+ setTimeout($.proxy(this.checkPosition, this), 1)
+ }
+
+ Affix.prototype.checkPosition = function () {
+ if (!this.$element.is(':visible')) return
+
+ var height = this.$element.height()
+ var offset = this.options.offset
+ var offsetTop = offset.top
+ var offsetBottom = offset.bottom
+ var scrollHeight = Math.max($(document).height(), $(document.body).height())
+
+ if (typeof offset != 'object') offsetBottom = offsetTop = offset
+ if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
+ if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
+
+ var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
+
+ if (this.affixed != affix) {
+ if (this.unpin != null) this.$element.css('top', '')
+
+ var affixType = 'affix' + (affix ? '-' + affix : '')
+ var e = $.Event(affixType + '.bs.affix')
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ this.affixed = affix
+ this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
+
+ this.$element
+ .removeClass(Affix.RESET)
+ .addClass(affixType)
+ .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
+ }
+
+ if (affix == 'bottom') {
+ this.$element.offset({
+ top: scrollHeight - height - offsetBottom
+ })
+ }
+ }
+
+
+ // AFFIX PLUGIN DEFINITION
+ // =======================
+
+ function Plugin(option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.affix')
+ var options = typeof option == 'object' && option
+
+ if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ var old = $.fn.affix
+
+ $.fn.affix = Plugin
+ $.fn.affix.Constructor = Affix
+
+
+ // AFFIX NO CONFLICT
+ // =================
+
+ $.fn.affix.noConflict = function () {
+ $.fn.affix = old
+ return this
+ }
+
+
+ // AFFIX DATA-API
+ // ==============
+
+ $(window).on('load', function () {
+ $('[data-spy="affix"]').each(function () {
+ var $spy = $(this)
+ var data = $spy.data()
+
+ data.offset = data.offset || {}
+
+ if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
+ if (data.offsetTop != null) data.offset.top = data.offsetTop
+
+ Plugin.call($spy, data)
+ })
+ })
+
+}(jQuery);
--- /dev/null
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under the MIT license
+ */
+if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.5",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a(f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.5",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),a(c.target).is('input[type="radio"]')||a(c.target).is('input[type="checkbox"]')||c.preventDefault()}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));return a>this.$items.length-1||0>a?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.5",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger("hidden.bs.dropdown",f))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.5",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.5",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.5",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),c.isInStateTrue()?void 0:(clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide())},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);return this.$element.trigger(g),g.isDefaultPrevented()?void 0:(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=d?{top:0,left:0}:b.offset(),g={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},h=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,g,h,f)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||!/destroy|hide/.test(b))&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.5",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.5",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),
+d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.5",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.5",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return c>e?"top":!1;if("bottom"==this.affixed)return null!=c?e+this.unpin<=f.top?!1:"bottom":a-d>=e+g?!1:"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&c>=e?"top":null!=d&&i+j>=a-d?"bottom":!1},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
\ No newline at end of file
--- /dev/null
+// This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment.
+require('../../js/transition.js')
+require('../../js/alert.js')
+require('../../js/button.js')
+require('../../js/carousel.js')
+require('../../js/collapse.js')
+require('../../js/dropdown.js')
+require('../../js/modal.js')
+require('../../js/tooltip.js')
+require('../../js/popover.js')
+require('../../js/scrollspy.js')
+require('../../js/tab.js')
+require('../../js/affix.js')
\ No newline at end of file
--- /dev/null
+/**@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic); **/
+/*!
+ * AdminLTE v2.3.0
+ * Author: Almsaeed Studio
+ * Website: Almsaeed Studio <http://almsaeedstudio.com>
+ * License: Open source - MIT
+ * Please visit http://opensource.org/licenses/MIT for more information
+!*/html,body{min-height:100%}.layout-boxed html,.layout-boxed body{height:100%}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:"Arial","Microsoft YaHei","黑体","宋体",sans-serif;font-weight:400;overflow-x:hidden;overflow-y:auto}.wrapper{min-height:100%;position:static;overflow:hidden}.wrapper:before,.wrapper:after{content:" ";display:table}.wrapper:after{clear:both}.layout-boxed .wrapper{max-width:1250px;margin:0 auto;min-height:100%;box-shadow:0 0 8px rgba(0,0,0,0.5);position:relative}.layout-boxed{background:url('../img/boxed-bg.jpg') repeat fixed}.content-wrapper,.right-side,.main-footer{-webkit-transition:-webkit-transform .3s ease-in-out,margin .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,margin .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,margin .3s ease-in-out;transition:transform .3s ease-in-out,margin .3s ease-in-out;margin-left:230px;z-index:820}.layout-top-nav .content-wrapper,.layout-top-nav .right-side,.layout-top-nav .main-footer{margin-left:0}@media (max-width:767px){.content-wrapper,.right-side,.main-footer{margin-left:0}}@media (min-width:768px){.sidebar-collapse .content-wrapper,.sidebar-collapse .right-side,.sidebar-collapse .main-footer{margin-left:0}}@media (max-width:767px){.sidebar-open .content-wrapper,.sidebar-open .right-side,.sidebar-open .main-footer{-webkit-transform:translate(230px, 0);-ms-transform:translate(230px, 0);-o-transform:translate(230px, 0);transform:translate(230px, 0)}}.content-wrapper,.right-side{min-height:100%;background-color:#ecf0f5;z-index:800}.main-footer{background:#fff;padding:15px;color:#444;border-top:1px solid #d2d6de}.fixed .main-header,.fixed .main-sidebar,.fixed .left-side{position:fixed}.fixed .main-header{top:0;right:0;left:0}.fixed .content-wrapper,.fixed .right-side{padding-top:50px}@media (max-width:767px){.fixed .content-wrapper,.fixed .right-side{padding-top:100px}}.fixed.layout-boxed .wrapper{max-width:100%}body.hold-transition .content-wrapper,body.hold-transition .right-side,body.hold-transition .main-footer,body.hold-transition .main-sidebar,body.hold-transition .left-side,body.hold-transition .main-header>.navbar,body.hold-transition .main-header .logo{-webkit-transition:none;-o-transition:none;transition:none}.content{min-height:250px;padding:15px;margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Arial","Microsoft YaHei","黑体","宋体",sans-serif}a{color:#3c8dbc}a:hover,a:active,a:focus{outline:none;text-decoration:none;color:#72afd2}.page-header{margin:10px 0 20px 0;font-size:22px}.page-header>small{color:#666;display:block;margin-top:5px}.main-header{position:relative;max-height:100px;z-index:1030}.main-header>.navbar{-webkit-transition:margin-left .3s ease-in-out;-o-transition:margin-left .3s ease-in-out;transition:margin-left .3s ease-in-out;margin-bottom:0;margin-left:230px;border:none;min-height:50px;border-radius:0}.layout-top-nav .main-header>.navbar{margin-left:0}.main-header #navbar-search-input.form-control{background:rgba(255,255,255,0.2);border-color:transparent}.main-header #navbar-search-input.form-control:focus,.main-header #navbar-search-input.form-control:active{border-color:rgba(0,0,0,0.1);background:rgba(255,255,255,0.9)}.main-header #navbar-search-input.form-control::-moz-placeholder{color:#ccc;opacity:1}.main-header #navbar-search-input.form-control:-ms-input-placeholder{color:#ccc}.main-header #navbar-search-input.form-control::-webkit-input-placeholder{color:#ccc}.main-header .navbar-custom-menu,.main-header .navbar-right{float:right}@media (max-width:991px){.main-header .navbar-custom-menu a,.main-header .navbar-right a{color:inherit;background:transparent}}@media (max-width:767px){.main-header .navbar-right{float:none}.navbar-collapse .main-header .navbar-right{margin:7.5px -15px}.main-header .navbar-right>li{color:inherit;border:0}}.main-header .sidebar-toggle{float:left;background-color:transparent;background-image:none;padding:15px 15px;font-family:"Arial","Microsoft YaHei","黑体","宋体",sans-serif}.main-header .sidebar-toggle:before{content:"\f0c9"}.main-header .sidebar-toggle:hover{color:#fff}.main-header .sidebar-toggle:focus,.main-header .sidebar-toggle:active{background:transparent}.main-header .sidebar-toggle .icon-bar{display:none}.main-header .navbar .nav>li.user>a>.fa,.main-header .navbar .nav>li.user>a>.glyphicon,.main-header .navbar .nav>li.user>a>.ion{margin-right:5px}.main-header .navbar .nav>li>a>.label{position:absolute;top:9px;right:7px;text-align:center;font-size:9px;padding:2px 3px;line-height:.9}.main-header .logo{-webkit-transition:width .3s ease-in-out;-o-transition:width .3s ease-in-out;transition:width .3s ease-in-out;display:block;float:left;height:50px;font-size:20px;line-height:50px;text-align:center;width:230px;font-family:"Arial","Microsoft YaHei","黑体","宋体",sans-serif;padding:0 15px;font-weight:300;overflow:hidden}.main-header .logo .logo-lg{display:block}.main-header .logo .logo-mini{display:none}.main-header .navbar-brand{color:#fff}.content-header{position:relative;padding:15px 15px 0 15px}.content-header>h1{margin:0;font-size:24px}.content-header>h1>small{font-size:15px;display:inline-block;padding-left:4px;font-weight:300}.content-header>.breadcrumb{float:right;background:transparent;margin-top:0;margin-bottom:0;font-size:12px;padding:7px 5px;position:absolute;top:15px;right:10px;border-radius:2px}.content-header>.breadcrumb>li>a{color:#444;text-decoration:none;display:inline-block}.content-header>.breadcrumb>li>a>.fa,.content-header>.breadcrumb>li>a>.glyphicon,.content-header>.breadcrumb>li>a>.ion{margin-right:5px}.content-header>.breadcrumb>li+li:before{content:'>\00a0'}@media (max-width:991px){.content-header>.breadcrumb{position:relative;margin-top:5px;top:0;right:0;float:none;background:#d2d6de;padding-left:10px}.content-header>.breadcrumb li:before{color:#97a0b3}}.navbar-toggle{color:#fff;border:0;margin:0;padding:15px 15px}@media (max-width:991px){.navbar-custom-menu .navbar-nav>li{float:left}.navbar-custom-menu .navbar-nav{margin:0;float:left}.navbar-custom-menu .navbar-nav>li>a{padding-top:15px;padding-bottom:15px;line-height:20px}}@media (max-width:767px){.main-header{position:relative}.main-header .logo,.main-header .navbar{width:100%;float:none}.main-header .navbar{margin:0}.main-header .navbar-custom-menu{float:right}}@media (max-width:991px){.navbar-collapse.pull-left{float:none!important}.navbar-collapse.pull-left+.navbar-custom-menu{display:block;position:absolute;top:0;right:40px}}.main-sidebar,.left-side{position:absolute;top:0;left:0;padding-top:50px;min-height:100%;width:230px;z-index:810;-webkit-transition:-webkit-transform .3s ease-in-out,width .3s ease-in-out;-moz-transition:-moz-transform .3s ease-in-out,width .3s ease-in-out;-o-transition:-o-transform .3s ease-in-out,width .3s ease-in-out;transition:transform .3s ease-in-out,width .3s ease-in-out}@media (max-width:767px){.main-sidebar,.left-side{padding-top:100px}}@media (max-width:767px){.main-sidebar,.left-side{-webkit-transform:translate(-230px, 0);-ms-transform:translate(-230px, 0);-o-transform:translate(-230px, 0);transform:translate(-230px, 0)}}@media (min-width:768px){.sidebar-collapse .main-sidebar,.sidebar-collapse .left-side{-webkit-transform:translate(-230px, 0);-ms-transform:translate(-230px, 0);-o-transform:translate(-230px, 0);transform:translate(-230px, 0)}}@media (max-width:767px){.sidebar-open .main-sidebar,.sidebar-open .left-side{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}}.sidebar{padding-bottom:10px}.sidebar-form input:focus{border-color:transparent}.user-panel{position:relative;width:100%;padding:10px;overflow:hidden}.user-panel:before,.user-panel:after{content:" ";display:table}.user-panel:after{clear:both}.user-panel>.image>img{width:100%;max-width:45px;height:auto}.user-panel>.info{padding:5px 5px 5px 15px;line-height:1;position:absolute;left:55px}.user-panel>.info>p{font-weight:600;margin-bottom:9px}.user-panel>.info>a{text-decoration:none;padding-right:5px;margin-top:3px;font-size:11px}.user-panel>.info>a>.fa,.user-panel>.info>a>.ion,.user-panel>.info>a>.glyphicon{margin-right:3px}.sidebar-menu{list-style:none;margin:0;padding:0}.sidebar-menu>li{position:relative;margin:0;padding:0}.sidebar-menu>li>a{padding:12px 5px 12px 15px;display:block}.sidebar-menu>li>a>.fa,.sidebar-menu>li>a>.glyphicon,.sidebar-menu>li>a>.ion{width:20px}.sidebar-menu>li .label,.sidebar-menu>li .badge{margin-top:3px;margin-right:5px}.sidebar-menu li.header{padding:10px 25px 10px 15px;font-size:12px}.sidebar-menu li>a>.fa-angle-left{width:auto;height:auto;padding:0;margin-right:10px;margin-top:3px}.sidebar-menu li.active>a>.fa-angle-left{-webkit-transform:rotate(-90deg);-ms-transform:rotate(-90deg);-o-transform:rotate(-90deg);transform:rotate(-90deg)}.sidebar-menu li.active>.treeview-menu{display:block}.sidebar-menu .treeview-menu{display:none;list-style:none;padding:0;margin:0;padding-left:5px}.sidebar-menu .treeview-menu .treeview-menu{padding-left:20px}.sidebar-menu .treeview-menu>li{margin:0}.sidebar-menu .treeview-menu>li>a{padding:5px 5px 5px 15px;display:block;font-size:14px}.sidebar-menu .treeview-menu>li>a>.fa,.sidebar-menu .treeview-menu>li>a>.glyphicon,.sidebar-menu .treeview-menu>li>a>.ion{width:20px}.sidebar-menu .treeview-menu>li>a>.fa-angle-left,.sidebar-menu .treeview-menu>li>a>.fa-angle-down{width:auto}@media (min-width:768px){.sidebar-mini.sidebar-collapse .content-wrapper,.sidebar-mini.sidebar-collapse .right-side,.sidebar-mini.sidebar-collapse .main-footer{margin-left:50px!important;z-index:840}.sidebar-mini.sidebar-collapse .main-sidebar{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0);width:50px!important;z-index:850}.sidebar-mini.sidebar-collapse .sidebar-menu>li{position:relative}.sidebar-mini.sidebar-collapse .sidebar-menu>li>a{margin-right:0}.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span{border-top-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:not(.treeview)>a>span{border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{padding-top:5px;padding-bottom:5px;border-bottom-right-radius:4px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>a>span:not(.pull-right),.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>.treeview-menu{display:block!important;position:absolute;width:180px;left:50px}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>a>span{top:0;margin-left:-3px;padding:12px 5px 12px 20px;background-color:inherit}.sidebar-mini.sidebar-collapse .sidebar-menu>li:hover>.treeview-menu{top:44px;margin-left:0}.sidebar-mini.sidebar-collapse .main-sidebar .user-panel>.info,.sidebar-mini.sidebar-collapse .sidebar-form,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>span,.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu,.sidebar-mini.sidebar-collapse .sidebar-menu>li>a>.pull-right,.sidebar-mini.sidebar-collapse .sidebar-menu li.header{display:none!important;-webkit-transform:translateZ(0)}.sidebar-mini.sidebar-collapse .main-header .logo{width:50px}.sidebar-mini.sidebar-collapse .main-header .logo>.logo-mini{display:block;margin-left:-15px;margin-right:-15px;font-size:18px}.sidebar-mini.sidebar-collapse .main-header .logo>.logo-lg{display:none}.sidebar-mini.sidebar-collapse .main-header .navbar{margin-left:50px}}.sidebar-menu,.main-sidebar .user-panel,.sidebar-menu>li.header{white-space:nowrap;overflow:hidden}.sidebar-menu:hover{overflow:visible}.sidebar-form,.sidebar-menu>li.header{overflow:hidden;text-overflow:clip}.sidebar-menu li>a{position:relative}.sidebar-menu li>a>.pull-right{position:absolute;top:50%;right:10px;margin-top:-7px}.control-sidebar-bg{position:fixed;z-index:1000;bottom:0}.control-sidebar-bg,.control-sidebar{top:0;right:-230px;width:230px;-webkit-transition:right .3s ease-in-out;-o-transition:right .3s ease-in-out;transition:right .3s ease-in-out}.control-sidebar{position:absolute;padding-top:50px;z-index:1010}@media (max-width:768px){.control-sidebar{padding-top:100px}}.control-sidebar>.tab-content{padding:10px 15px}.control-sidebar.control-sidebar-open,.control-sidebar.control-sidebar-open+.control-sidebar-bg{right:0}.control-sidebar-open .control-sidebar-bg,.control-sidebar-open .control-sidebar{right:0}@media (min-width:768px){.control-sidebar-open .content-wrapper,.control-sidebar-open .right-side,.control-sidebar-open .main-footer{margin-right:230px}}.nav-tabs.control-sidebar-tabs>li:first-of-type>a,.nav-tabs.control-sidebar-tabs>li:first-of-type>a:hover,.nav-tabs.control-sidebar-tabs>li:first-of-type>a:focus{border-left-width:0}.nav-tabs.control-sidebar-tabs>li>a{border-radius:0}.nav-tabs.control-sidebar-tabs>li>a,.nav-tabs.control-sidebar-tabs>li>a:hover{border-top:none;border-right:none;border-left:1px solid transparent;border-bottom:1px solid transparent}.nav-tabs.control-sidebar-tabs>li>a .icon{font-size:16px}.nav-tabs.control-sidebar-tabs>li.active>a,.nav-tabs.control-sidebar-tabs>li.active>a:hover,.nav-tabs.control-sidebar-tabs>li.active>a:focus,.nav-tabs.control-sidebar-tabs>li.active>a:active{border-top:none;border-right:none;border-bottom:none}@media (max-width:768px){.nav-tabs.control-sidebar-tabs{display:table}.nav-tabs.control-sidebar-tabs>li{display:table-cell}}.control-sidebar-heading{font-weight:400;font-size:16px;padding:10px 0;margin-bottom:10px}.control-sidebar-subheading{display:block;font-weight:400;font-size:14px}.control-sidebar-menu{list-style:none;padding:0;margin:0 -15px}.control-sidebar-menu>li>a{display:block;padding:10px 15px}.control-sidebar-menu>li>a:before,.control-sidebar-menu>li>a:after{content:" ";display:table}.control-sidebar-menu>li>a:after{clear:both}.control-sidebar-menu>li>a>.control-sidebar-subheading{margin-top:0}.control-sidebar-menu .menu-icon{float:left;width:35px;height:35px;border-radius:50%;text-align:center;line-height:35px}.control-sidebar-menu .menu-info{margin-left:45px;margin-top:3px}.control-sidebar-menu .menu-info>.control-sidebar-subheading{margin:0}.control-sidebar-menu .menu-info>p{margin:0;font-size:11px}.control-sidebar-menu .progress{margin:0}.control-sidebar-dark{color:#b8c7ce}.control-sidebar-dark,.control-sidebar-dark+.control-sidebar-bg{background:#222d32}.control-sidebar-dark .nav-tabs.control-sidebar-tabs{border-bottom:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a{background:#181f23;color:#b8c7ce}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:focus{border-left-color:#141a1d;border-bottom-color:#141a1d}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:active{background:#1c2529}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li>a:hover{color:#fff}.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:hover,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:focus,.control-sidebar-dark .nav-tabs.control-sidebar-tabs>li.active>a:active{background:#222d32;color:#fff}.control-sidebar-dark .control-sidebar-heading,.control-sidebar-dark .control-sidebar-subheading{color:#fff}.control-sidebar-dark .control-sidebar-menu>li>a:hover{background:#1e282c}.control-sidebar-dark .control-sidebar-menu>li>a .menu-info>p{color:#b8c7ce}.control-sidebar-light{color:#5e5e5e}.control-sidebar-light,.control-sidebar-light+.control-sidebar-bg{background:#f9fafc;border-left:1px solid #d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs{border-bottom:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a{background:#e8ecf4;color:#444}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:focus{border-left-color:#d2d6de;border-bottom-color:#d2d6de}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li>a:active{background:#eff1f7}.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:hover,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:focus,.control-sidebar-light .nav-tabs.control-sidebar-tabs>li.active>a:active{background:#f9fafc;color:#111}.control-sidebar-light .control-sidebar-heading,.control-sidebar-light .control-sidebar-subheading{color:#111}.control-sidebar-light .control-sidebar-menu{margin-left:-14px}.control-sidebar-light .control-sidebar-menu>li>a:hover{background:#f4f4f5}.control-sidebar-light .control-sidebar-menu>li>a .menu-info>p{color:#5e5e5e}.dropdown-menu{box-shadow:none;border-color:#eee}.dropdown-menu>li>a{color:#777}.dropdown-menu>li>a>.glyphicon,.dropdown-menu>li>a>.fa,.dropdown-menu>li>a>.ion{margin-right:10px}.dropdown-menu>li>a:hover{background-color:#e1e3e9;color:#333}.dropdown-menu>.divider{background-color:#eee}.navbar-nav>.notifications-menu>.dropdown-menu,.navbar-nav>.messages-menu>.dropdown-menu,.navbar-nav>.tasks-menu>.dropdown-menu{width:280px;padding:0 0 0 0;margin:0;top:100%}.navbar-nav>.notifications-menu>.dropdown-menu>li,.navbar-nav>.messages-menu>.dropdown-menu>li,.navbar-nav>.tasks-menu>.dropdown-menu>li{position:relative}.navbar-nav>.notifications-menu>.dropdown-menu>li.header,.navbar-nav>.messages-menu>.dropdown-menu>li.header,.navbar-nav>.tasks-menu>.dropdown-menu>li.header{border-top-left-radius:4px;border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:#ffffff;padding:7px 10px;border-bottom:1px solid #f4f4f4;color:#444444;font-size:14px}.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px;font-size:12px;background-color:#fff;padding:7px 10px;border-bottom:1px solid #eeeeee;color:#444!important;text-align:center}@media (max-width:991px){.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a{background:#fff!important;color:#444!important}}.navbar-nav>.notifications-menu>.dropdown-menu>li.footer>a:hover,.navbar-nav>.messages-menu>.dropdown-menu>li.footer>a:hover,.navbar-nav>.tasks-menu>.dropdown-menu>li.footer>a:hover{text-decoration:none;font-weight:normal}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu,.navbar-nav>.messages-menu>.dropdown-menu>li .menu,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu{max-height:200px;margin:0;padding:0;list-style:none;overflow-x:hidden}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a{display:block;white-space:nowrap;border-bottom:1px solid #f4f4f4}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a:hover,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:hover,.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a:hover{background:#f4f4f4;text-decoration:none}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a{color:#444444;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;padding:10px}.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.glyphicon,.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.fa,.navbar-nav>.notifications-menu>.dropdown-menu>li .menu>li>a>.ion{width:20px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a{margin:0;padding:10px 10px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>div>img{margin:auto 10px auto auto;width:40px;height:40px}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>h4{padding:0;margin:0 0 0 45px;color:#444444;font-size:15px;position:relative}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>h4>small{color:#999999;font-size:10px;position:absolute;top:0;right:0}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a>p{margin:0 0 0 45px;font-size:12px;color:#888888}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:before,.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:after{content:" ";display:table}.navbar-nav>.messages-menu>.dropdown-menu>li .menu>li>a:after{clear:both}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a{padding:10px}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a>h3{font-size:14px;padding:0;margin:0 0 10px 0;color:#666666}.navbar-nav>.tasks-menu>.dropdown-menu>li .menu>li>a>.progress{padding:0;margin:0}.navbar-nav>.user-menu>.dropdown-menu{border-top-right-radius:0;border-top-left-radius:0;padding:1px 0 0 0;border-top-width:0;width:280px}.navbar-nav>.user-menu>.dropdown-menu,.navbar-nav>.user-menu>.dropdown-menu>.user-body{border-bottom-right-radius:4px;border-bottom-left-radius:4px}.navbar-nav>.user-menu>.dropdown-menu>li.user-header{height:175px;padding:10px;text-align:center}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>img{z-index:5;height:90px;width:90px;border:3px solid;border-color:transparent;border-color:rgba(255,255,255,0.2)}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>p{z-index:5;color:#fff;color:rgba(255,255,255,0.8);font-size:17px;margin-top:10px}.navbar-nav>.user-menu>.dropdown-menu>li.user-header>p>small{display:block;font-size:12px}.navbar-nav>.user-menu>.dropdown-menu>.user-body{padding:15px;border-bottom:1px solid #f4f4f4;border-top:1px solid #dddddd}.navbar-nav>.user-menu>.dropdown-menu>.user-body:before,.navbar-nav>.user-menu>.dropdown-menu>.user-body:after{content:" ";display:table}.navbar-nav>.user-menu>.dropdown-menu>.user-body:after{clear:both}.navbar-nav>.user-menu>.dropdown-menu>.user-body a{color:#444 !important}@media (max-width:991px){.navbar-nav>.user-menu>.dropdown-menu>.user-body a{background:#fff !important;color:#444 !important}}.navbar-nav>.user-menu>.dropdown-menu>.user-footer{background-color:#f9f9f9;padding:10px}.navbar-nav>.user-menu>.dropdown-menu>.user-footer:before,.navbar-nav>.user-menu>.dropdown-menu>.user-footer:after{content:" ";display:table}.navbar-nav>.user-menu>.dropdown-menu>.user-footer:after{clear:both}.navbar-nav>.user-menu>.dropdown-menu>.user-footer .btn-default{color:#666666}@media (max-width:991px){.navbar-nav>.user-menu>.dropdown-menu>.user-footer .btn-default:hover{background-color:#f9f9f9}}.navbar-nav>.user-menu .user-image{float:left;width:25px;height:25px;border-radius:50%;margin-right:10px;margin-top:-2px}@media (max-width:767px){.navbar-nav>.user-menu .user-image{float:none;margin-right:0;margin-top:-8px;line-height:10px}}.open:not(.dropup)>.animated-dropdown-menu{backface-visibility:visible !important;-webkit-animation:flipInX .7s both;-o-animation:flipInX .7s both;animation:flipInX .7s both}@keyframes flipInX{0%{transform:perspective(400px) rotate3d(1, 0, 0, 90deg);transition-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotate3d(1, 0, 0, -20deg);transition-timing-function:ease-in}60%{transform:perspective(400px) rotate3d(1, 0, 0, 10deg);opacity:1}80%{transform:perspective(400px) rotate3d(1, 0, 0, -5deg)}100%{transform:perspective(400px)}}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, 90deg);-webkit-transition-timing-function:ease-in;opacity:0}40%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, -20deg);-webkit-transition-timing-function:ease-in}60%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, 10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotate3d(1, 0, 0, -5deg)}100%{-webkit-transform:perspective(400px)}}.navbar-custom-menu>.navbar-nav>li{position:relative}.navbar-custom-menu>.navbar-nav>li>.dropdown-menu{position:absolute;right:0;left:auto}@media (max-width:991px){.navbar-custom-menu>.navbar-nav{float:right}.navbar-custom-menu>.navbar-nav>li{position:static}.navbar-custom-menu>.navbar-nav>li>.dropdown-menu{position:absolute;right:5%;left:auto;border:1px solid #ddd;background:#fff}}.form-control{border-radius:0;box-shadow:none;border-color:#d2d6de}.form-control:focus{border-color:#3c8dbc;box-shadow:none}.form-control::-moz-placeholder,.form-control:-ms-input-placeholder,.form-control::-webkit-input-placeholder{color:#bbb;opacity:1}.form-control:not(select){-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-group.has-success label{color:#00a65a}.form-group.has-success .form-control{border-color:#00a65a;box-shadow:none}.form-group.has-warning label{color:#f39c12}.form-group.has-warning .form-control{border-color:#f39c12;box-shadow:none}.form-group.has-error label{color:#dd4b39}.form-group.has-error .form-control{border-color:#dd4b39;box-shadow:none}.input-group .input-group-addon{border-radius:0;border-color:#d2d6de;background-color:#fff}.btn-group-vertical .btn.btn-flat:first-of-type,.btn-group-vertical .btn.btn-flat:last-of-type{border-radius:0}.icheck>label{padding-left:0}.form-control-feedback.fa{line-height:34px}.input-lg+.form-control-feedback.fa,.input-group-lg+.form-control-feedback.fa,.form-group-lg .form-control+.form-control-feedback.fa{line-height:46px}.input-sm+.form-control-feedback.fa,.input-group-sm+.form-control-feedback.fa,.form-group-sm .form-control+.form-control-feedback.fa{line-height:30px}.progress,.progress>.progress-bar{-webkit-box-shadow:none;box-shadow:none}.progress,.progress>.progress-bar,.progress .progress-bar,.progress>.progress-bar .progress-bar{border-radius:1px}.progress.sm,.progress-sm{height:10px}.progress.sm,.progress-sm,.progress.sm .progress-bar,.progress-sm .progress-bar{border-radius:1px}.progress.xs,.progress-xs{height:7px}.progress.xs,.progress-xs,.progress.xs .progress-bar,.progress-xs .progress-bar{border-radius:1px}.progress.xxs,.progress-xxs{height:3px}.progress.xxs,.progress-xxs,.progress.xxs .progress-bar,.progress-xxs .progress-bar{border-radius:1px}.progress.vertical{position:relative;width:30px;height:200px;display:inline-block;margin-right:10px}.progress.vertical>.progress-bar{width:100%;position:absolute;bottom:0}.progress.vertical.sm,.progress.vertical.progress-sm{width:20px}.progress.vertical.xs,.progress.vertical.progress-xs{width:10px}.progress.vertical.xxs,.progress.vertical.progress-xxs{width:3px}.progress-group .progress-text{font-weight:600}.progress-group .progress-number{float:right}.table tr>td .progress{margin:0}.progress-bar-light-blue,.progress-bar-primary{background-color:#3c8dbc}.progress-striped .progress-bar-light-blue,.progress-striped .progress-bar-primary{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-green,.progress-bar-success{background-color:#00a65a}.progress-striped .progress-bar-green,.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-aqua,.progress-bar-info{background-color:#00c0ef}.progress-striped .progress-bar-aqua,.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-yellow,.progress-bar-warning{background-color:#f39c12}.progress-striped .progress-bar-yellow,.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.progress-bar-red,.progress-bar-danger{background-color:#dd4b39}.progress-striped .progress-bar-red,.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255,255,255,0.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.15) 50%, rgba(255,255,255,0.15) 75%, transparent 75%, transparent)}.small-box{border-radius:2px;position:relative;display:block;margin-bottom:20px;box-shadow:0 1px 1px rgba(0,0,0,0.1)}.small-box>.inner{padding:10px}.small-box>.small-box-footer{position:relative;text-align:center;padding:3px 0;color:#fff;color:rgba(255,255,255,0.8);display:block;z-index:10;background:rgba(0,0,0,0.1);text-decoration:none}.small-box>.small-box-footer:hover{color:#fff;background:rgba(0,0,0,0.15)}.small-box h3{font-size:38px;font-weight:bold;margin:0 0 10px 0;white-space:nowrap;padding:0}.small-box p{font-size:15px}.small-box p>small{display:block;color:#f9f9f9;font-size:13px;margin-top:5px}.small-box h3,.small-box p{z-index:5px}.small-box .icon{-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;position:absolute;top:-10px;right:10px;z-index:0;font-size:90px;color:rgba(0,0,0,0.15)}.small-box:hover{text-decoration:none;color:#f9f9f9}.small-box:hover .icon{font-size:95px}@media (max-width:767px){.small-box{text-align:center}.small-box .icon{display:none}.small-box p{font-size:12px}}.box{position:relative;border-radius:3px;background:#ffffff;border-top:3px solid #d2d6de;margin-bottom:20px;width:100%;box-shadow:0 1px 1px rgba(0,0,0,0.1)}.box.box-primary{border-top-color:#3c8dbc}.box.box-info{border-top-color:#00c0ef}.box.box-danger{border-top-color:#dd4b39}.box.box-warning{border-top-color:#f39c12}.box.box-success{border-top-color:#00a65a}.box.box-default{border-top-color:#d2d6de}.box.collapsed-box .box-body,.box.collapsed-box .box-footer{display:none}.box .nav-stacked>li{border-bottom:1px solid #f4f4f4;margin:0}.box .nav-stacked>li:last-of-type{border-bottom:none}.box.height-control .box-body{max-height:300px;overflow:auto}.box .border-right{border-right:1px solid #f4f4f4}.box .border-left{border-left:1px solid #f4f4f4}.box.box-solid{border-top:0}.box.box-solid>.box-header .btn.btn-default{background:transparent}.box.box-solid>.box-header .btn:hover,.box.box-solid>.box-header a:hover{background:rgba(0,0,0,0.1)}.box.box-solid.box-default{border:1px solid #d2d6de}.box.box-solid.box-default>.box-header{color:#444;background:#d2d6de;background-color:#d2d6de}.box.box-solid.box-default>.box-header a,.box.box-solid.box-default>.box-header .btn{color:#444}.box.box-solid.box-primary{border:1px solid #3c8dbc}.box.box-solid.box-primary>.box-header{color:#fff;background:#3c8dbc;background-color:#3c8dbc}.box.box-solid.box-primary>.box-header a,.box.box-solid.box-primary>.box-header .btn{color:#fff}.box.box-solid.box-info{border:1px solid #00c0ef}.box.box-solid.box-info>.box-header{color:#fff;background:#00c0ef;background-color:#00c0ef}.box.box-solid.box-info>.box-header a,.box.box-solid.box-info>.box-header .btn{color:#fff}.box.box-solid.box-danger{border:1px solid #dd4b39}.box.box-solid.box-danger>.box-header{color:#fff;background:#dd4b39;background-color:#dd4b39}.box.box-solid.box-danger>.box-header a,.box.box-solid.box-danger>.box-header .btn{color:#fff}.box.box-solid.box-warning{border:1px solid #f39c12}.box.box-solid.box-warning>.box-header{color:#fff;background:#f39c12;background-color:#f39c12}.box.box-solid.box-warning>.box-header a,.box.box-solid.box-warning>.box-header .btn{color:#fff}.box.box-solid.box-success{border:1px solid #00a65a}.box.box-solid.box-success>.box-header{color:#fff;background:#00a65a;background-color:#00a65a}.box.box-solid.box-success>.box-header a,.box.box-solid.box-success>.box-header .btn{color:#fff}.box.box-solid>.box-header>.box-tools .btn{border:0;box-shadow:none}.box.box-solid[class*='bg']>.box-header{color:#fff}.box .box-group>.box{margin-bottom:5px}.box .knob-label{text-align:center;color:#333;font-weight:100;font-size:12px;margin-bottom:0.3em}.box>.overlay,.overlay-wrapper>.overlay,.box>.loading-img,.overlay-wrapper>.loading-img{position:absolute;top:0;left:0;width:100%;height:100%}.box .overlay,.overlay-wrapper .overlay{z-index:50;background:rgba(255,255,255,0.7);border-radius:3px}.box .overlay>.fa,.overlay-wrapper .overlay>.fa{position:absolute;top:50%;left:50%;margin-left:-15px;margin-top:-15px;color:#000;font-size:30px}.box .overlay.dark,.overlay-wrapper .overlay.dark{background:rgba(0,0,0,0.5)}.box-header:before,.box-body:before,.box-footer:before,.box-header:after,.box-body:after,.box-footer:after{content:" ";display:table}.box-header:after,.box-body:after,.box-footer:after{clear:both}.box-header{color:#444;display:block;padding:10px;position:relative}.box-header.with-border{border-bottom:1px solid #f4f4f4}.collapsed-box .box-header.with-border{border-bottom:none}.box-header>.fa,.box-header>.glyphicon,.box-header>.ion,.box-header .box-title{display:inline-block;font-size:18px;margin:0;line-height:1}.box-header>.fa,.box-header>.glyphicon,.box-header>.ion{margin-right:5px}.box-header>.box-tools{position:absolute;right:10px;top:5px}.box-header>.box-tools [data-toggle="tooltip"]{position:relative}.box-header>.box-tools.pull-right .dropdown-menu{right:0;left:auto}.btn-box-tool{padding:5px;font-size:12px;background:transparent;color:#97a0b3}.open .btn-box-tool,.btn-box-tool:hover{color:#606c84}.btn-box-tool.btn:active{box-shadow:none}.box-body{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;padding:10px}.no-header .box-body{border-top-right-radius:3px;border-top-left-radius:3px}.box-body>.table{margin-bottom:0}.box-body .fc{margin-top:5px}.box-body .full-width-chart{margin:-19px}.box-body.no-padding .full-width-chart{margin:-9px}.box-body .box-pane{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:3px}.box-body .box-pane-right{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:0}.box-footer{border-top-left-radius:0;border-top-right-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px;border-top:1px solid #f4f4f4;padding:10px;background-color:#fff}.chart-legend{margin:10px 0}@media (max-width:991px){.chart-legend>li{float:left;margin-right:10px}}.box-comments{background:#f7f7f7}.box-comments .box-comment{padding:8px 0;border-bottom:1px solid #eee}.box-comments .box-comment:before,.box-comments .box-comment:after{content:" ";display:table}.box-comments .box-comment:after{clear:both}.box-comments .box-comment:last-of-type{border-bottom:0}.box-comments .box-comment:first-of-type{padding-top:0}.box-comments .box-comment img{float:left}.box-comments .comment-text{margin-left:40px;color:#555}.box-comments .username{color:#444;display:block;font-weight:600}.box-comments .text-muted{font-weight:400;font-size:12px}.todo-list{margin:0;padding:0;list-style:none;overflow:auto}.todo-list>li{border-radius:2px;padding:10px;background:#f4f4f4;margin-bottom:2px;border-left:2px solid #e6e7e8;color:#444}.todo-list>li:last-of-type{margin-bottom:0}.todo-list>li>input[type='checkbox']{margin:0 10px 0 5px}.todo-list>li .text{display:inline-block;margin-left:5px;font-weight:600}.todo-list>li .label{margin-left:10px;font-size:9px}.todo-list>li .tools{display:none;float:right;color:#dd4b39}.todo-list>li .tools>.fa,.todo-list>li .tools>.glyphicon,.todo-list>li .tools>.ion{margin-right:5px;cursor:pointer}.todo-list>li:hover .tools{display:inline-block}.todo-list>li.done{color:#999}.todo-list>li.done .text{text-decoration:line-through;font-weight:500}.todo-list>li.done .label{background:#d2d6de !important}.todo-list .danger{border-left-color:#dd4b39}.todo-list .warning{border-left-color:#f39c12}.todo-list .info{border-left-color:#00c0ef}.todo-list .success{border-left-color:#00a65a}.todo-list .primary{border-left-color:#3c8dbc}.todo-list .handle{display:inline-block;cursor:move;margin:0 5px}.chat{padding:5px 20px 5px 10px}.chat .item{margin-bottom:10px}.chat .item:before,.chat .item:after{content:" ";display:table}.chat .item:after{clear:both}.chat .item>img{width:40px;height:40px;border:2px solid transparent;border-radius:50%}.chat .item>.online{border:2px solid #00a65a}.chat .item>.offline{border:2px solid #dd4b39}.chat .item>.message{margin-left:55px;margin-top:-40px}.chat .item>.message>.name{display:block;font-weight:600}.chat .item>.attachment{border-radius:3px;background:#f4f4f4;margin-left:65px;margin-right:15px;padding:10px}.chat .item>.attachment>h4{margin:0 0 5px 0;font-weight:600;font-size:14px}.chat .item>.attachment>p,.chat .item>.attachment>.filename{font-weight:600;font-size:13px;font-style:italic;margin:0}.chat .item>.attachment:before,.chat .item>.attachment:after{content:" ";display:table}.chat .item>.attachment:after{clear:both}.box-input{max-width:200px}.modal .panel-body{color:#444}.info-box{display:block;min-height:90px;background:#fff;width:100%;box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:2px;margin-bottom:15px}.info-box small{font-size:14px}.info-box .progress{background:rgba(0,0,0,0.2);margin:5px -10px 5px -10px;height:2px}.info-box .progress,.info-box .progress .progress-bar{border-radius:0}.info-box .progress .progress-bar{background:#fff}.info-box-icon{border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px;display:block;float:left;height:90px;width:90px;text-align:center;font-size:45px;line-height:90px;background:rgba(0,0,0,0.2)}.info-box-icon>img{max-width:100%}.info-box-content{padding:5px 10px;margin-left:90px}.info-box-number{display:block;font-weight:bold;font-size:18px}.progress-description,.info-box-text{display:block;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.info-box-text{text-transform:uppercase}.info-box-more{display:block}.progress-description{margin:0}.timeline{position:relative;margin:0 0 30px 0;padding:0;list-style:none}.timeline:before{content:'';position:absolute;top:0;bottom:0;width:4px;background:#ddd;left:31px;margin:0;border-radius:2px}.timeline>li{position:relative;margin-right:10px;margin-bottom:15px}.timeline>li:before,.timeline>li:after{content:" ";display:table}.timeline>li:after{clear:both}.timeline>li>.timeline-item{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px;margin-top:0;background:#fff;color:#444;margin-left:60px;margin-right:15px;padding:0;position:relative}.timeline>li>.timeline-item>.time{color:#999;float:right;padding:10px;font-size:12px}.timeline>li>.timeline-item>.timeline-header{margin:0;color:#555;border-bottom:1px solid #f4f4f4;padding:10px;font-size:16px;line-height:1.1}.timeline>li>.timeline-item>.timeline-header>a{font-weight:600}.timeline>li>.timeline-item>.timeline-body,.timeline>li>.timeline-item>.timeline-footer{padding:10px}.timeline>li>.fa,.timeline>li>.glyphicon,.timeline>li>.ion{width:30px;height:30px;font-size:15px;line-height:30px;position:absolute;color:#666;background:#d2d6de;border-radius:50%;text-align:center;left:18px;top:0}.timeline>.time-label>span{font-weight:600;padding:5px;display:inline-block;background-color:#fff;border-radius:4px}.timeline-inverse>li>.timeline-item{background:#f0f0f0;border:1px solid #ddd;-webkit-box-shadow:none;box-shadow:none}.timeline-inverse>li>.timeline-item>.timeline-header{border-bottom-color:#ddd}.btn{border-radius:3px;-webkit-box-shadow:none;box-shadow:none;border:1px solid transparent}.btn.uppercase{text-transform:uppercase}.btn.btn-flat{border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;border-width:1px}.btn:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn:focus{outline:none}.btn.btn-file{position:relative;overflow:hidden}.btn.btn-file>input[type='file']{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;opacity:0;filter:alpha(opacity=0);outline:none;background:white;cursor:inherit;display:block}.btn-default{background-color:#f4f4f4;color:#444;border-color:#ddd}.btn-default:hover,.btn-default:active,.btn-default.hover{background-color:#e7e7e7}.btn-primary{background-color:#3c8dbc;border-color:#367fa9}.btn-primary:hover,.btn-primary:active,.btn-primary.hover{background-color:#367fa9}.btn-success{background-color:#00a65a;border-color:#008d4c}.btn-success:hover,.btn-success:active,.btn-success.hover{background-color:#008d4c}.btn-info{background-color:#00c0ef;border-color:#00acd6}.btn-info:hover,.btn-info:active,.btn-info.hover{background-color:#00acd6}.btn-danger{background-color:#dd4b39;border-color:#d73925}.btn-danger:hover,.btn-danger:active,.btn-danger.hover{background-color:#d73925}.btn-warning{background-color:#f39c12;border-color:#e08e0b}.btn-warning:hover,.btn-warning:active,.btn-warning.hover{background-color:#e08e0b}.btn-outline{border:1px solid #fff;background:transparent;color:#fff}.btn-outline:hover,.btn-outline:focus,.btn-outline:active{color:rgba(255,255,255,0.7);border-color:rgba(255,255,255,0.7)}.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn[class*='bg-']:hover{-webkit-box-shadow:inset 0 0 100px rgba(0,0,0,0.2);box-shadow:inset 0 0 100px rgba(0,0,0,0.2)}.btn-app{border-radius:3px;position:relative;padding:15px 5px;margin:0 0 10px 10px;min-width:80px;height:60px;text-align:center;color:#666;border:1px solid #ddd;background-color:#f4f4f4;font-size:12px}.btn-app>.fa,.btn-app>.glyphicon,.btn-app>.ion{font-size:20px;display:block}.btn-app:hover{background:#f4f4f4;color:#444;border-color:#aaa}.btn-app:active,.btn-app:focus{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-app>.badge{position:absolute;top:-3px;right:-10px;font-size:10px;font-weight:400}.callout{border-radius:3px;margin:0 0 20px 0;padding:15px 30px 15px 15px;border-left:5px solid #eee}.callout a{color:#fff;text-decoration:underline}.callout a:hover{color:#eee}.callout h4{margin-top:0;font-weight:600}.callout p:last-child{margin-bottom:0}.callout code,.callout .highlight{background-color:#fff}.callout.callout-danger{border-color:#c23321}.callout.callout-warning{border-color:#c87f0a}.callout.callout-info{border-color:#0097bc}.callout.callout-success{border-color:#00733e}.alert{border-radius:3px}.alert h4{font-weight:600}.alert .icon{margin-right:10px}.alert .close{color:#000;opacity:.2;filter:alpha(opacity=20)}.alert .close:hover{opacity:.5;filter:alpha(opacity=50)}.alert a{color:#fff;text-decoration:underline}.alert-success{border-color:#008d4c}.alert-danger,.alert-error{border-color:#d73925}.alert-warning{border-color:#e08e0b}.alert-info{border-color:#00acd6}.nav>li>a:hover,.nav>li>a:active,.nav>li>a:focus{color:#444;background:#f7f7f7}.nav-pills>li>a{border-radius:0;border-top:3px solid transparent;color:#444}.nav-pills>li>a>.fa,.nav-pills>li>a>.glyphicon,.nav-pills>li>a>.ion{margin-right:5px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{border-top-color:#3c8dbc}.nav-pills>li.active>a{font-weight:600}.nav-stacked>li>a{border-radius:0;border-top:0;border-left:3px solid transparent;color:#444}.nav-stacked>li.active>a,.nav-stacked>li.active>a:hover{background:transparent;color:#444;border-top:0;border-left-color:#3c8dbc}.nav-stacked>li.header{border-bottom:1px solid #ddd;color:#777;margin-bottom:10px;padding:5px 10px;text-transform:uppercase}.nav-tabs-custom{margin-bottom:20px;background:#fff;box-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px}.nav-tabs-custom>.nav-tabs{margin:0;border-bottom-color:#f4f4f4;border-top-right-radius:3px;border-top-left-radius:3px}.nav-tabs-custom>.nav-tabs>li{border-top:3px solid transparent;margin-bottom:-2px;margin-right:5px}.nav-tabs-custom>.nav-tabs>li>a{color:#444;border-radius:0}.nav-tabs-custom>.nav-tabs>li>a.text-muted{color:#999}.nav-tabs-custom>.nav-tabs>li>a,.nav-tabs-custom>.nav-tabs>li>a:hover{background:transparent;margin:0}.nav-tabs-custom>.nav-tabs>li>a:hover{color:#999}.nav-tabs-custom>.nav-tabs>li:not(.active)>a:hover,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:focus,.nav-tabs-custom>.nav-tabs>li:not(.active)>a:active{border-color:transparent}.nav-tabs-custom>.nav-tabs>li.active{border-top-color:#3c8dbc}.nav-tabs-custom>.nav-tabs>li.active>a,.nav-tabs-custom>.nav-tabs>li.active:hover>a{background-color:#fff;color:#444}.nav-tabs-custom>.nav-tabs>li.active>a{border-top-color:transparent;border-left-color:#f4f4f4;border-right-color:#f4f4f4}.nav-tabs-custom>.nav-tabs>li:first-of-type{margin-left:0}.nav-tabs-custom>.nav-tabs>li:first-of-type.active>a{border-left-color:transparent}.nav-tabs-custom>.nav-tabs.pull-right{float:none!important}.nav-tabs-custom>.nav-tabs.pull-right>li{float:right}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type{margin-right:0}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type>a{border-left-width:1px}.nav-tabs-custom>.nav-tabs.pull-right>li:first-of-type.active>a{border-left-color:#f4f4f4;border-right-color:transparent}.nav-tabs-custom>.nav-tabs>li.header{line-height:35px;padding:0 10px;font-size:20px;color:#444}.nav-tabs-custom>.nav-tabs>li.header>.fa,.nav-tabs-custom>.nav-tabs>li.header>.glyphicon,.nav-tabs-custom>.nav-tabs>li.header>.ion{margin-right:5px}.nav-tabs-custom>.tab-content{background:#fff;padding:10px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.nav-tabs-custom .dropdown.open>a:active,.nav-tabs-custom .dropdown.open>a:focus{background:transparent;color:#999}.pagination>li>a{background:#fafafa;color:#666}.pagination.pagination-flat>li>a{border-radius:0 !important}.products-list{list-style:none;margin:0;padding:0}.products-list>.item{border-radius:3px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.1);box-shadow:0 1px 1px rgba(0,0,0,0.1);padding:10px 0;background:#fff}.products-list>.item:before,.products-list>.item:after{content:" ";display:table}.products-list>.item:after{clear:both}.products-list .product-img{float:left}.products-list .product-img img{width:50px;height:50px}.products-list .product-info{margin-left:60px}.products-list .product-title{font-weight:600}.products-list .product-description{display:block;color:#999;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.product-list-in-box>.item{-webkit-box-shadow:none;box-shadow:none;border-radius:0;border-bottom:1px solid #f4f4f4}.product-list-in-box>.item:last-of-type{border-bottom-width:0}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{border-top:1px solid #f4f4f4}.table>thead>tr>th{border-bottom:2px solid #f4f4f4}.table tr td .progress{margin-top:5px}.table-bordered{border:1px solid #f4f4f4}.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 #f4f4f4}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table.no-border,.table.no-border td,.table.no-border th{border:0}table.text-center,table.text-center td,table.text-center th{text-align:center}.table.align th{text-align:left}.table.align td{text-align:right}.label-default{background-color:#d2d6de;color:#444}.direct-chat .box-body{border-bottom-right-radius:0;border-bottom-left-radius:0;position:relative;overflow-x:hidden;padding:0}.direct-chat.chat-pane-open .direct-chat-contacts{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.direct-chat-messages{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0);padding:10px;height:250px;overflow:auto}.direct-chat-msg,.direct-chat-text{display:block}.direct-chat-msg{margin-bottom:10px}.direct-chat-msg:before,.direct-chat-msg:after{content:" ";display:table}.direct-chat-msg:after{clear:both}.direct-chat-messages,.direct-chat-contacts{-webkit-transition:-webkit-transform .5s ease-in-out;-moz-transition:-moz-transform .5s ease-in-out;-o-transition:-o-transform .5s ease-in-out;transition:transform .5s ease-in-out}.direct-chat-text{border-radius:5px;position:relative;padding:5px 10px;background:#d2d6de;border:1px solid #d2d6de;margin:5px 0 0 50px;color:#444}.direct-chat-text:after,.direct-chat-text:before{position:absolute;right:100%;top:15px;border:solid transparent;border-right-color:#d2d6de;content:' ';height:0;width:0;pointer-events:none}.direct-chat-text:after{border-width:5px;margin-top:-5px}.direct-chat-text:before{border-width:6px;margin-top:-6px}.right .direct-chat-text{margin-right:50px;margin-left:0}.right .direct-chat-text:after,.right .direct-chat-text:before{right:auto;left:100%;border-right-color:transparent;border-left-color:#d2d6de}.direct-chat-img{border-radius:50%;float:left;width:40px;height:40px}.right .direct-chat-img{float:right}.direct-chat-info{display:block;margin-bottom:2px;font-size:12px}.direct-chat-name{font-weight:600}.direct-chat-timestamp{color:#999}.direct-chat-contacts-open .direct-chat-contacts{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}.direct-chat-contacts{-webkit-transform:translate(101%, 0);-ms-transform:translate(101%, 0);-o-transform:translate(101%, 0);transform:translate(101%, 0);position:absolute;top:0;bottom:0;height:250px;width:100%;background:#222d32;color:#fff;overflow:auto}.contacts-list>li{border-bottom:1px solid rgba(0,0,0,0.2);padding:10px;margin:0}.contacts-list>li:before,.contacts-list>li:after{content:" ";display:table}.contacts-list>li:after{clear:both}.contacts-list>li:last-of-type{border-bottom:none}.contacts-list-img{border-radius:50%;width:40px;float:left}.contacts-list-info{margin-left:45px;color:#fff}.contacts-list-name,.contacts-list-status{display:block}.contacts-list-name{font-weight:600}.contacts-list-status{font-size:12px}.contacts-list-date{color:#aaa;font-weight:normal}.contacts-list-msg{color:#999}.direct-chat-danger .right>.direct-chat-text{background:#dd4b39;border-color:#dd4b39;color:#fff}.direct-chat-danger .right>.direct-chat-text:after,.direct-chat-danger .right>.direct-chat-text:before{border-left-color:#dd4b39}.direct-chat-primary .right>.direct-chat-text{background:#3c8dbc;border-color:#3c8dbc;color:#fff}.direct-chat-primary .right>.direct-chat-text:after,.direct-chat-primary .right>.direct-chat-text:before{border-left-color:#3c8dbc}.direct-chat-warning .right>.direct-chat-text{background:#f39c12;border-color:#f39c12;color:#fff}.direct-chat-warning .right>.direct-chat-text:after,.direct-chat-warning .right>.direct-chat-text:before{border-left-color:#f39c12}.direct-chat-info .right>.direct-chat-text{background:#00c0ef;border-color:#00c0ef;color:#fff}.direct-chat-info .right>.direct-chat-text:after,.direct-chat-info .right>.direct-chat-text:before{border-left-color:#00c0ef}.direct-chat-success .right>.direct-chat-text{background:#00a65a;border-color:#00a65a;color:#fff}.direct-chat-success .right>.direct-chat-text:after,.direct-chat-success .right>.direct-chat-text:before{border-left-color:#00a65a}.users-list>li{width:25%;float:left;padding:10px;text-align:center}.users-list>li img{border-radius:50%;max-width:100%;height:auto}.users-list>li>a:hover,.users-list>li>a:hover .users-list-name{color:#999}.users-list-name,.users-list-date{display:block}.users-list-name{font-weight:600;color:#444;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.users-list-date{color:#999;font-size:12px}.carousel-control.left,.carousel-control.right{background-image:none}.carousel-control>.fa{font-size:40px;position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-20px}.modal{background:rgba(0,0,0,0.3)}.modal-content{border-radius:0;-webkit-box-shadow:0 2px 3px rgba(0,0,0,0.125);box-shadow:0 2px 3px rgba(0,0,0,0.125);border:0}@media (min-width:768px){.modal-content{-webkit-box-shadow:0 2px 3px rgba(0,0,0,0.125);box-shadow:0 2px 3px rgba(0,0,0,0.125)}}.modal-header{border-bottom-color:#f4f4f4}.modal-footer{border-top-color:#f4f4f4}.modal-primary .modal-header,.modal-primary .modal-footer{border-color:#307095}.modal-warning .modal-header,.modal-warning .modal-footer{border-color:#c87f0a}.modal-info .modal-header,.modal-info .modal-footer{border-color:#0097bc}.modal-success .modal-header,.modal-success .modal-footer{border-color:#00733e}.modal-danger .modal-header,.modal-danger .modal-footer{border-color:#c23321}.box-widget{border:none;position:relative}.widget-user .widget-user-header{padding:20px;height:120px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user .widget-user-username{margin-top:0;margin-bottom:5px;font-size:25px;font-weight:300;text-shadow:0 1px 1px rgba(0,0,0,0.2)}.widget-user .widget-user-desc{margin-top:0}.widget-user .widget-user-image{position:absolute;top:65px;left:50%;margin-left:-45px}.widget-user .widget-user-image>img{width:90px;height:auto;border:3px solid #fff}.widget-user .box-footer{padding-top:30px}.widget-user-2 .widget-user-header{padding:20px;border-top-right-radius:3px;border-top-left-radius:3px}.widget-user-2 .widget-user-username{margin-top:5px;margin-bottom:5px;font-size:25px;font-weight:300}.widget-user-2 .widget-user-desc{margin-top:0}.widget-user-2 .widget-user-username,.widget-user-2 .widget-user-desc{margin-left:75px}.widget-user-2 .widget-user-image>img{width:65px;height:auto;float:left}.mailbox-messages>.table{margin:0}.mailbox-controls{padding:5px}.mailbox-controls.with-border{border-bottom:1px solid #f4f4f4}.mailbox-read-info{border-bottom:1px solid #f4f4f4;padding:10px}.mailbox-read-info h3{font-size:20px;margin:0}.mailbox-read-info h5{margin:0;padding:5px 0 0 0}.mailbox-read-time{color:#999;font-size:13px}.mailbox-read-message{padding:10px}.mailbox-attachments li{float:left;width:200px;border:1px solid #eee;margin-bottom:10px;margin-right:10px}.mailbox-attachment-name{font-weight:bold;color:#666}.mailbox-attachment-icon,.mailbox-attachment-info,.mailbox-attachment-size{display:block}.mailbox-attachment-info{padding:10px;background:#f4f4f4}.mailbox-attachment-size{color:#999;font-size:12px}.mailbox-attachment-icon{text-align:center;font-size:65px;color:#666;padding:20px 10px}.mailbox-attachment-icon.has-img{padding:0}.mailbox-attachment-icon.has-img>img{max-width:100%;height:auto}.lockscreen{background:#d2d6de}.lockscreen-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.lockscreen-logo a{color:#444}.lockscreen-wrapper{max-width:400px;margin:0 auto;margin-top:10%}.lockscreen .lockscreen-name{text-align:center;font-weight:600}.lockscreen-item{border-radius:4px;padding:0;background:#fff;position:relative;margin:10px auto 30px auto;width:290px}.lockscreen-image{border-radius:50%;position:absolute;left:-10px;top:-25px;background:#fff;padding:5px;z-index:10}.lockscreen-image>img{border-radius:50%;width:70px;height:70px}.lockscreen-credentials{margin-left:70px}.lockscreen-credentials .form-control{border:0}.lockscreen-credentials .btn{background-color:#fff;border:0;padding:0 10px}.lockscreen-footer{margin-top:10px}.login-logo,.register-logo{font-size:35px;text-align:center;margin-bottom:25px;font-weight:300}.login-logo a,.register-logo a{color:#444}.login-page,.register-page{background:#d2d6de}.login-box,.register-box{width:360px;margin:7% auto}@media (max-width:768px){.login-box,.register-box{width:90%;margin-top:20px}}.login-box-body,.register-box-body{background:#fff;padding:20px;border-top:0;color:#666}.login-box-body .form-control-feedback,.register-box-body .form-control-feedback{color:#777}.login-box-msg,.register-box-msg{margin:0;text-align:center;padding:0 20px 20px 20px}.social-auth-links{margin:10px 0}.error-page{width:600px;margin:20px auto 0 auto}@media (max-width:991px){.error-page{width:100%}}.error-page>.headline{float:left;font-size:100px;font-weight:300}@media (max-width:991px){.error-page>.headline{float:none;text-align:center}}.error-page>.error-content{margin-left:190px;display:block}@media (max-width:991px){.error-page>.error-content{margin-left:0}}.error-page>.error-content>h3{font-weight:300;font-size:25px}@media (max-width:991px){.error-page>.error-content>h3{text-align:center}}.invoice{position:relative;background:#fff;border:1px solid #f4f4f4;padding:20px;margin:10px 25px}.invoice-title{margin-top:0}.profile-user-img{margin:0 auto;width:100px;padding:3px;border:3px solid #d2d6de}.profile-username{font-size:21px;margin-top:5px}.post{border-bottom:1px solid #d2d6de;margin-bottom:15px;padding-bottom:15px;color:#666}.post:last-of-type{border-bottom:0;margin-bottom:0;padding-bottom:0}.post .user-block{margin-bottom:15px}.btn-social{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.btn-social>:first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)}.btn-social.btn-lg{padding-left:61px}.btn-social.btn-lg>:first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social.btn-sm{padding-left:38px}.btn-social.btn-sm>:first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social.btn-xs{padding-left:30px}.btn-social.btn-xs>:first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:34px;width:34px;padding:0}.btn-social-icon>:first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)}.btn-social-icon.btn-lg{padding-left:61px}.btn-social-icon.btn-lg>:first-child{line-height:45px;width:45px;font-size:1.8em}.btn-social-icon.btn-sm{padding-left:38px}.btn-social-icon.btn-sm>:first-child{line-height:28px;width:28px;font-size:1.4em}.btn-social-icon.btn-xs{padding-left:30px}.btn-social-icon.btn-xs>:first-child{line-height:20px;width:20px;font-size:1.2em}.btn-social-icon>:first-child{border:none;text-align:center;width:100%}.btn-social-icon.btn-lg{height:45px;width:45px;padding-left:0;padding-right:0}.btn-social-icon.btn-sm{height:30px;width:30px;padding-left:0;padding-right:0}.btn-social-icon.btn-xs{height:22px;width:22px;padding-left:0;padding-right:0}.btn-adn{color:#fff;background-color:#d87a68;border-color:rgba(0,0,0,0.2)}.btn-adn:hover,.btn-adn:focus,.btn-adn.focus,.btn-adn:active,.btn-adn.active,.open>.dropdown-toggle.btn-adn{color:#fff;background-color:#ce563f;border-color:rgba(0,0,0,0.2)}.btn-adn:active,.btn-adn.active,.open>.dropdown-toggle.btn-adn{background-image:none}.btn-adn .badge{color:#d87a68;background-color:#fff}.btn-bitbucket{color:#fff;background-color:#205081;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:hover,.btn-bitbucket:focus,.btn-bitbucket.focus,.btn-bitbucket:active,.btn-bitbucket.active,.open>.dropdown-toggle.btn-bitbucket{color:#fff;background-color:#163758;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:active,.btn-bitbucket.active,.open>.dropdown-toggle.btn-bitbucket{background-image:none}.btn-bitbucket .badge{color:#205081;background-color:#fff}.btn-dropbox{color:#fff;background-color:#1087dd;border-color:rgba(0,0,0,0.2)}.btn-dropbox:hover,.btn-dropbox:focus,.btn-dropbox.focus,.btn-dropbox:active,.btn-dropbox.active,.open>.dropdown-toggle.btn-dropbox{color:#fff;background-color:#0d6aad;border-color:rgba(0,0,0,0.2)}.btn-dropbox:active,.btn-dropbox.active,.open>.dropdown-toggle.btn-dropbox{background-image:none}.btn-dropbox .badge{color:#1087dd;background-color:#fff}.btn-facebook{color:#fff;background-color:#3b5998;border-color:rgba(0,0,0,0.2)}.btn-facebook:hover,.btn-facebook:focus,.btn-facebook.focus,.btn-facebook:active,.btn-facebook.active,.open>.dropdown-toggle.btn-facebook{color:#fff;background-color:#2d4373;border-color:rgba(0,0,0,0.2)}.btn-facebook:active,.btn-facebook.active,.open>.dropdown-toggle.btn-facebook{background-image:none}.btn-facebook .badge{color:#3b5998;background-color:#fff}.btn-flickr{color:#fff;background-color:#ff0084;border-color:rgba(0,0,0,0.2)}.btn-flickr:hover,.btn-flickr:focus,.btn-flickr.focus,.btn-flickr:active,.btn-flickr.active,.open>.dropdown-toggle.btn-flickr{color:#fff;background-color:#cc006a;border-color:rgba(0,0,0,0.2)}.btn-flickr:active,.btn-flickr.active,.open>.dropdown-toggle.btn-flickr{background-image:none}.btn-flickr .badge{color:#ff0084;background-color:#fff}.btn-foursquare{color:#fff;background-color:#f94877;border-color:rgba(0,0,0,0.2)}.btn-foursquare:hover,.btn-foursquare:focus,.btn-foursquare.focus,.btn-foursquare:active,.btn-foursquare.active,.open>.dropdown-toggle.btn-foursquare{color:#fff;background-color:#f71752;border-color:rgba(0,0,0,0.2)}.btn-foursquare:active,.btn-foursquare.active,.open>.dropdown-toggle.btn-foursquare{background-image:none}.btn-foursquare .badge{color:#f94877;background-color:#fff}.btn-github{color:#fff;background-color:#444;border-color:rgba(0,0,0,0.2)}.btn-github:hover,.btn-github:focus,.btn-github.focus,.btn-github:active,.btn-github.active,.open>.dropdown-toggle.btn-github{color:#fff;background-color:#2b2b2b;border-color:rgba(0,0,0,0.2)}.btn-github:active,.btn-github.active,.open>.dropdown-toggle.btn-github{background-image:none}.btn-github .badge{color:#444;background-color:#fff}.btn-google{color:#fff;background-color:#dd4b39;border-color:rgba(0,0,0,0.2)}.btn-google:hover,.btn-google:focus,.btn-google.focus,.btn-google:active,.btn-google.active,.open>.dropdown-toggle.btn-google{color:#fff;background-color:#c23321;border-color:rgba(0,0,0,0.2)}.btn-google:active,.btn-google.active,.open>.dropdown-toggle.btn-google{background-image:none}.btn-google .badge{color:#dd4b39;background-color:#fff}.btn-instagram{color:#fff;background-color:#3f729b;border-color:rgba(0,0,0,0.2)}.btn-instagram:hover,.btn-instagram:focus,.btn-instagram.focus,.btn-instagram:active,.btn-instagram.active,.open>.dropdown-toggle.btn-instagram{color:#fff;background-color:#305777;border-color:rgba(0,0,0,0.2)}.btn-instagram:active,.btn-instagram.active,.open>.dropdown-toggle.btn-instagram{background-image:none}.btn-instagram .badge{color:#3f729b;background-color:#fff}.btn-linkedin{color:#fff;background-color:#007bb6;border-color:rgba(0,0,0,0.2)}.btn-linkedin:hover,.btn-linkedin:focus,.btn-linkedin.focus,.btn-linkedin:active,.btn-linkedin.active,.open>.dropdown-toggle.btn-linkedin{color:#fff;background-color:#005983;border-color:rgba(0,0,0,0.2)}.btn-linkedin:active,.btn-linkedin.active,.open>.dropdown-toggle.btn-linkedin{background-image:none}.btn-linkedin .badge{color:#007bb6;background-color:#fff}.btn-microsoft{color:#fff;background-color:#2672ec;border-color:rgba(0,0,0,0.2)}.btn-microsoft:hover,.btn-microsoft:focus,.btn-microsoft.focus,.btn-microsoft:active,.btn-microsoft.active,.open>.dropdown-toggle.btn-microsoft{color:#fff;background-color:#125acd;border-color:rgba(0,0,0,0.2)}.btn-microsoft:active,.btn-microsoft.active,.open>.dropdown-toggle.btn-microsoft{background-image:none}.btn-microsoft .badge{color:#2672ec;background-color:#fff}.btn-openid{color:#fff;background-color:#f7931e;border-color:rgba(0,0,0,0.2)}.btn-openid:hover,.btn-openid:focus,.btn-openid.focus,.btn-openid:active,.btn-openid.active,.open>.dropdown-toggle.btn-openid{color:#fff;background-color:#da7908;border-color:rgba(0,0,0,0.2)}.btn-openid:active,.btn-openid.active,.open>.dropdown-toggle.btn-openid{background-image:none}.btn-openid .badge{color:#f7931e;background-color:#fff}.btn-pinterest{color:#fff;background-color:#cb2027;border-color:rgba(0,0,0,0.2)}.btn-pinterest:hover,.btn-pinterest:focus,.btn-pinterest.focus,.btn-pinterest:active,.btn-pinterest.active,.open>.dropdown-toggle.btn-pinterest{color:#fff;background-color:#9f191f;border-color:rgba(0,0,0,0.2)}.btn-pinterest:active,.btn-pinterest.active,.open>.dropdown-toggle.btn-pinterest{background-image:none}.btn-pinterest .badge{color:#cb2027;background-color:#fff}.btn-reddit{color:#000;background-color:#eff7ff;border-color:rgba(0,0,0,0.2)}.btn-reddit:hover,.btn-reddit:focus,.btn-reddit.focus,.btn-reddit:active,.btn-reddit.active,.open>.dropdown-toggle.btn-reddit{color:#000;background-color:#bcddff;border-color:rgba(0,0,0,0.2)}.btn-reddit:active,.btn-reddit.active,.open>.dropdown-toggle.btn-reddit{background-image:none}.btn-reddit .badge{color:#eff7ff;background-color:#000}.btn-soundcloud{color:#fff;background-color:#f50;border-color:rgba(0,0,0,0.2)}.btn-soundcloud:hover,.btn-soundcloud:focus,.btn-soundcloud.focus,.btn-soundcloud:active,.btn-soundcloud.active,.open>.dropdown-toggle.btn-soundcloud{color:#fff;background-color:#c40;border-color:rgba(0,0,0,0.2)}.btn-soundcloud:active,.btn-soundcloud.active,.open>.dropdown-toggle.btn-soundcloud{background-image:none}.btn-soundcloud .badge{color:#f50;background-color:#fff}.btn-tumblr{color:#fff;background-color:#2c4762;border-color:rgba(0,0,0,0.2)}.btn-tumblr:hover,.btn-tumblr:focus,.btn-tumblr.focus,.btn-tumblr:active,.btn-tumblr.active,.open>.dropdown-toggle.btn-tumblr{color:#fff;background-color:#1c2d3f;border-color:rgba(0,0,0,0.2)}.btn-tumblr:active,.btn-tumblr.active,.open>.dropdown-toggle.btn-tumblr{background-image:none}.btn-tumblr .badge{color:#2c4762;background-color:#fff}.btn-twitter{color:#fff;background-color:#55acee;border-color:rgba(0,0,0,0.2)}.btn-twitter:hover,.btn-twitter:focus,.btn-twitter.focus,.btn-twitter:active,.btn-twitter.active,.open>.dropdown-toggle.btn-twitter{color:#fff;background-color:#2795e9;border-color:rgba(0,0,0,0.2)}.btn-twitter:active,.btn-twitter.active,.open>.dropdown-toggle.btn-twitter{background-image:none}.btn-twitter .badge{color:#55acee;background-color:#fff}.btn-vimeo{color:#fff;background-color:#1ab7ea;border-color:rgba(0,0,0,0.2)}.btn-vimeo:hover,.btn-vimeo:focus,.btn-vimeo.focus,.btn-vimeo:active,.btn-vimeo.active,.open>.dropdown-toggle.btn-vimeo{color:#fff;background-color:#1295bf;border-color:rgba(0,0,0,0.2)}.btn-vimeo:active,.btn-vimeo.active,.open>.dropdown-toggle.btn-vimeo{background-image:none}.btn-vimeo .badge{color:#1ab7ea;background-color:#fff}.btn-vk{color:#fff;background-color:#587ea3;border-color:rgba(0,0,0,0.2)}.btn-vk:hover,.btn-vk:focus,.btn-vk.focus,.btn-vk:active,.btn-vk.active,.open>.dropdown-toggle.btn-vk{color:#fff;background-color:#466482;border-color:rgba(0,0,0,0.2)}.btn-vk:active,.btn-vk.active,.open>.dropdown-toggle.btn-vk{background-image:none}.btn-vk .badge{color:#587ea3;background-color:#fff}.btn-yahoo{color:#fff;background-color:#720e9e;border-color:rgba(0,0,0,0.2)}.btn-yahoo:hover,.btn-yahoo:focus,.btn-yahoo.focus,.btn-yahoo:active,.btn-yahoo.active,.open>.dropdown-toggle.btn-yahoo{color:#fff;background-color:#500a6f;border-color:rgba(0,0,0,0.2)}.btn-yahoo:active,.btn-yahoo.active,.open>.dropdown-toggle.btn-yahoo{background-image:none}.btn-yahoo .badge{color:#720e9e;background-color:#fff}.fc-button{background:#f4f4f4;background-image:none;color:#444;border-color:#ddd;border-bottom-color:#ddd}.fc-button:hover,.fc-button:active,.fc-button.hover{background-color:#e9e9e9}.fc-header-title h2{font-size:15px;line-height:1.6em;color:#666;margin-left:10px}.fc-header-right{padding-right:10px}.fc-header-left{padding-left:10px}.fc-widget-header{background:#fafafa}.fc-grid{width:100%;border:0}.fc-widget-header:first-of-type,.fc-widget-content:first-of-type{border-left:0;border-right:0}.fc-widget-header:last-of-type,.fc-widget-content:last-of-type{border-right:0}.fc-toolbar{padding:10px;margin:0}.fc-day-number{font-size:20px;font-weight:300;padding-right:10px}.fc-color-picker{list-style:none;margin:0;padding:0}.fc-color-picker>li{float:left;font-size:30px;margin-right:5px;line-height:30px}.fc-color-picker>li .fa{-webkit-transition:-webkit-transform linear .3s;-moz-transition:-moz-transform linear .3s;-o-transition:-o-transform linear .3s;transition:transform linear .3s}.fc-color-picker>li .fa:hover{-webkit-transform:rotate(30deg);-ms-transform:rotate(30deg);-o-transform:rotate(30deg);transform:rotate(30deg)}#add-new-event{-webkit-transition:all linear .3s;-o-transition:all linear .3s;transition:all linear .3s}.external-event{padding:5px 10px;font-weight:bold;margin-bottom:4px;box-shadow:0 1px 1px rgba(0,0,0,0.1);text-shadow:0 1px 1px rgba(0,0,0,0.1);border-radius:3px;cursor:move}.external-event:hover{box-shadow:inset 0 0 90px rgba(0,0,0,0.2)}.select2-container--default.select2-container--focus,.select2-selection.select2-container--focus,.select2-container--default:focus,.select2-selection:focus,.select2-container--default:active,.select2-selection:active{outline:none}.select2-container--default .select2-selection--single,.select2-selection .select2-selection--single{border:1px solid #d2d6de;border-radius:0;padding:6px 12px;height:34px}.select2-container--default.select2-container--open{border-color:#3c8dbc}.select2-dropdown{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-results__option--highlighted[aria-selected]{background-color:#3c8dbc;color:white}.select2-results__option{padding:6px 12px;user-select:none;-webkit-user-select:none}.select2-container .select2-selection--single .select2-selection__rendered{padding-left:0;padding-right:0;height:auto;margin-top:-4px}.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered{padding-right:6px;padding-left:20px}.select2-container--default .select2-selection--single .select2-selection__arrow{height:28px;right:3px}.select2-container--default .select2-selection--single .select2-selection__arrow b{margin-top:0}.select2-dropdown .select2-search__field,.select2-search--inline .select2-search__field{border:1px solid #d2d6de}.select2-dropdown .select2-search__field:focus,.select2-search--inline .select2-search__field:focus{outline:none;border:1px solid #3c8dbc}.select2-container--default .select2-results__option[aria-disabled=true]{color:#999}.select2-container--default .select2-results__option[aria-selected=true]{background-color:#ddd}.select2-container--default .select2-results__option[aria-selected=true],.select2-container--default .select2-results__option[aria-selected=true]:hover{color:#444}.select2-container--default .select2-selection--multiple{border:1px solid #d2d6de;border-radius:0}.select2-container--default .select2-selection--multiple:focus{border-color:#3c8dbc}.select2-container--default.select2-container--focus .select2-selection--multiple{border-color:#d2d6de}.select2-container--default .select2-selection--multiple .select2-selection__choice{background-color:#3c8dbc;border-color:#367fa9;padding:1px 10px;color:#fff}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove{margin-right:5px;color:rgba(255,255,255,0.7)}.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover{color:#fff}.select2-container .select2-selection--single .select2-selection__rendered{padding-right:10px}.pad{padding:10px}.margin{margin:10px}.margin-bottom{margin-bottom:20px}.margin-bottom-none{margin-bottom:0}.margin-r-5{margin-right:5px}.inline{display:inline}.description-block{display:block;margin:10px 0;text-align:center}.description-block.margin-bottom{margin-bottom:25px}.description-block>.description-header{margin:0;padding:0;font-weight:600;font-size:16px}.description-block>.description-text{text-transform:uppercase}.bg-red,.bg-yellow,.bg-aqua,.bg-blue,.bg-light-blue,.bg-green,.bg-navy,.bg-teal,.bg-olive,.bg-lime,.bg-orange,.bg-fuchsia,.bg-purple,.bg-maroon,.bg-black,.bg-red-active,.bg-yellow-active,.bg-aqua-active,.bg-blue-active,.bg-light-blue-active,.bg-green-active,.bg-navy-active,.bg-teal-active,.bg-olive-active,.bg-lime-active,.bg-orange-active,.bg-fuchsia-active,.bg-purple-active,.bg-maroon-active,.bg-black-active,.callout.callout-danger,.callout.callout-warning,.callout.callout-info,.callout.callout-success,.alert-success,.alert-danger,.alert-error,.alert-warning,.alert-info,.label-danger,.label-info,.label-warning,.label-primary,.label-success,.modal-primary .modal-body,.modal-primary .modal-header,.modal-primary .modal-footer,.modal-warning .modal-body,.modal-warning .modal-header,.modal-warning .modal-footer,.modal-info .modal-body,.modal-info .modal-header,.modal-info .modal-footer,.modal-success .modal-body,.modal-success .modal-header,.modal-success .modal-footer,.modal-danger .modal-body,.modal-danger .modal-header,.modal-danger .modal-footer{color:#fff !important}.bg-gray{color:#000;background-color:#d2d6de !important}.bg-gray-light{background-color:#f7f7f7}.bg-black{background-color:#111 !important}.bg-red,.callout.callout-danger,.alert-danger,.alert-error,.label-danger,.modal-danger .modal-body{background-color:#dd4b39 !important}.bg-yellow,.callout.callout-warning,.alert-warning,.label-warning,.modal-warning .modal-body{background-color:#f39c12 !important}.bg-aqua,.callout.callout-info,.alert-info,.label-info,.modal-info .modal-body{background-color:#00c0ef !important}.bg-blue{background-color:#0073b7 !important}.bg-light-blue,.label-primary,.modal-primary .modal-body{background-color:#3c8dbc !important}.bg-green,.callout.callout-success,.alert-success,.label-success,.modal-success .modal-body{background-color:#00a65a !important}.bg-navy{background-color:#001f3f !important}.bg-teal{background-color:#39cccc !important}.bg-olive{background-color:#3d9970 !important}.bg-lime{background-color:#01ff70 !important}.bg-orange{background-color:#ff851b !important}.bg-fuchsia{background-color:#f012be !important}.bg-purple{background-color:#605ca8 !important}.bg-maroon{background-color:#d81b60 !important}.bg-gray-active{color:#000;background-color:#b5bbc8 !important}.bg-black-active{background-color:#000 !important}.bg-red-active,.modal-danger .modal-header,.modal-danger .modal-footer{background-color:#d33724 !important}.bg-yellow-active,.modal-warning .modal-header,.modal-warning .modal-footer{background-color:#db8b0b !important}.bg-aqua-active,.modal-info .modal-header,.modal-info .modal-footer{background-color:#00a7d0 !important}.bg-blue-active{background-color:#005384 !important}.bg-light-blue-active,.modal-primary .modal-header,.modal-primary .modal-footer{background-color:#357ca5 !important}.bg-green-active,.modal-success .modal-header,.modal-success .modal-footer{background-color:#008d4c !important}.bg-navy-active{background-color:#001a35 !important}.bg-teal-active{background-color:#30bbbb !important}.bg-olive-active{background-color:#368763 !important}.bg-lime-active{background-color:#00e765 !important}.bg-orange-active{background-color:#ff7701 !important}.bg-fuchsia-active{background-color:#db0ead !important}.bg-purple-active{background-color:#555299 !important}.bg-maroon-active{background-color:#ca195a !important}[class^="bg-"].disabled{opacity:.65;filter:alpha(opacity=65)}.text-red{color:#dd4b39 !important}.text-yellow{color:#f39c12 !important}.text-aqua{color:#00c0ef !important}.text-blue{color:#0073b7 !important}.text-black{color:#111 !important}.text-light-blue{color:#3c8dbc !important}.text-green{color:#00a65a !important}.text-gray{color:#d2d6de !important}.text-navy{color:#001f3f !important}.text-teal{color:#39cccc !important}.text-olive{color:#3d9970 !important}.text-lime{color:#01ff70 !important}.text-orange{color:#ff851b !important}.text-fuchsia{color:#f012be !important}.text-purple{color:#605ca8 !important}.text-maroon{color:#d81b60 !important}.link-muted{color:#7a869d}.link-muted:hover,.link-muted:focus{color:#606c84}.link-black{color:#666}.link-black:hover,.link-black:focus{color:#999}.hide{display:none !important}.no-border{border:0 !important}.no-padding{padding:0 !important}.no-margin{margin:0 !important}.no-shadow{box-shadow:none!important}.list-unstyled,.chart-legend,.contacts-list,.users-list,.mailbox-attachments{list-style:none;margin:0;padding:0}.list-group-unbordered>.list-group-item{border-left:0;border-right:0;border-radius:0;padding-left:0;padding-right:0}.flat{border-radius:0 !important}.text-bold,.text-bold.table td,.text-bold.table th{font-weight:700}.text-sm{font-size:12px}.jqstooltip{padding:5px!important;width:auto!important;height:auto!important}.bg-teal-gradient{background:#39cccc !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #39cccc), color-stop(1, #7adddd)) !important;background:-ms-linear-gradient(bottom, #39cccc, #7adddd) !important;background:-moz-linear-gradient(center bottom, #39cccc 0, #7adddd 100%) !important;background:-o-linear-gradient(#7adddd, #39cccc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#7adddd', endColorstr='#39cccc', GradientType=0) !important;color:#fff}.bg-light-blue-gradient{background:#3c8dbc !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #3c8dbc), color-stop(1, #67a8ce)) !important;background:-ms-linear-gradient(bottom, #3c8dbc, #67a8ce) !important;background:-moz-linear-gradient(center bottom, #3c8dbc 0, #67a8ce 100%) !important;background:-o-linear-gradient(#67a8ce, #3c8dbc) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#67a8ce', endColorstr='#3c8dbc', GradientType=0) !important;color:#fff}.bg-blue-gradient{background:#0073b7 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #0073b7), color-stop(1, #0089db)) !important;background:-ms-linear-gradient(bottom, #0073b7, #0089db) !important;background:-moz-linear-gradient(center bottom, #0073b7 0, #0089db 100%) !important;background:-o-linear-gradient(#0089db, #0073b7) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0089db', endColorstr='#0073b7', GradientType=0) !important;color:#fff}.bg-aqua-gradient{background:#00c0ef !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #00c0ef), color-stop(1, #14d1ff)) !important;background:-ms-linear-gradient(bottom, #00c0ef, #14d1ff) !important;background:-moz-linear-gradient(center bottom, #00c0ef 0, #14d1ff 100%) !important;background:-o-linear-gradient(#14d1ff, #00c0ef) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#14d1ff', endColorstr='#00c0ef', GradientType=0) !important;color:#fff}.bg-yellow-gradient{background:#f39c12 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #f39c12), color-stop(1, #f7bc60)) !important;background:-ms-linear-gradient(bottom, #f39c12, #f7bc60) !important;background:-moz-linear-gradient(center bottom, #f39c12 0, #f7bc60 100%) !important;background:-o-linear-gradient(#f7bc60, #f39c12) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f7bc60', endColorstr='#f39c12', GradientType=0) !important;color:#fff}.bg-purple-gradient{background:#605ca8 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #605ca8), color-stop(1, #9491c4)) !important;background:-ms-linear-gradient(bottom, #605ca8, #9491c4) !important;background:-moz-linear-gradient(center bottom, #605ca8 0, #9491c4 100%) !important;background:-o-linear-gradient(#9491c4, #605ca8) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#9491c4', endColorstr='#605ca8', GradientType=0) !important;color:#fff}.bg-green-gradient{background:#00a65a !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #00a65a), color-stop(1, #00ca6d)) !important;background:-ms-linear-gradient(bottom, #00a65a, #00ca6d) !important;background:-moz-linear-gradient(center bottom, #00a65a 0, #00ca6d 100%) !important;background:-o-linear-gradient(#00ca6d, #00a65a) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ca6d', endColorstr='#00a65a', GradientType=0) !important;color:#fff}.bg-red-gradient{background:#dd4b39 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #dd4b39), color-stop(1, #e47365)) !important;background:-ms-linear-gradient(bottom, #dd4b39, #e47365) !important;background:-moz-linear-gradient(center bottom, #dd4b39 0, #e47365 100%) !important;background:-o-linear-gradient(#e47365, #dd4b39) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e47365', endColorstr='#dd4b39', GradientType=0) !important;color:#fff}.bg-black-gradient{background:#111 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #111), color-stop(1, #2b2b2b)) !important;background:-ms-linear-gradient(bottom, #111, #2b2b2b) !important;background:-moz-linear-gradient(center bottom, #111 0, #2b2b2b 100%) !important;background:-o-linear-gradient(#2b2b2b, #111) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#2b2b2b', endColorstr='#111111', GradientType=0) !important;color:#fff}.bg-maroon-gradient{background:#d81b60 !important;background:-webkit-gradient(linear, left bottom, left top, color-stop(0, #d81b60), color-stop(1, #e73f7c)) !important;background:-ms-linear-gradient(bottom, #d81b60, #e73f7c) !important;background:-moz-linear-gradient(center bottom, #d81b60 0, #e73f7c 100%) !important;background:-o-linear-gradient(#e73f7c, #d81b60) !important;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#e73f7c', endColorstr='#d81b60', GradientType=0) !important;color:#fff}.description-block .description-icon{font-size:16px}.no-pad-top{padding-top:0}.position-static{position:static!important}.list-header{font-size:15px;padding:10px 4px;font-weight:bold;color:#666}.list-seperator{height:1px;background:#f4f4f4;margin:15px 0 9px 0}.list-link>a{padding:4px;color:#777}.list-link>a:hover{color:#222}.font-light{font-weight:300}.user-block:before,.user-block:after{content:" ";display:table}.user-block:after{clear:both}.user-block img{width:40px;height:40px;float:left}.user-block .username,.user-block .description,.user-block .comment{display:block;margin-left:50px}.user-block .username{font-size:16px;font-weight:600}.user-block .description{color:#999;font-size:13px}.user-block.user-block-sm .username,.user-block.user-block-sm .description,.user-block.user-block-sm .comment{margin-left:40px}.user-block.user-block-sm .username{font-size:14px}.img-sm,.img-md,.img-lg,.box-comments .box-comment img,.user-block.user-block-sm img{float:left}.img-sm,.box-comments .box-comment img,.user-block.user-block-sm img{width:30px!important;height:30px!important}.img-sm+.img-push{margin-left:40px}.img-md{width:60px;height:60px}.img-md+.img-push{margin-left:70px}.img-lg{width:100px;height:100px}.img-lg+.img-push{margin-left:110px}.img-bordered{border:3px solid #d2d6de;padding:3px}.img-bordered-sm{border:2px solid #d2d6de;padding:2px}.attachment-block{border:1px solid #f4f4f4;padding:5px;margin-bottom:10px;background:#f7f7f7}.attachment-block .attachment-img{max-width:100px;max-height:100px;height:auto;float:left}.attachment-block .attachment-pushed{margin-left:110px}.attachment-block .attachment-heading{margin:0}.attachment-block .attachment-text{color:#555}.connectedSortable{min-height:100px}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sort-highlight{background:#f4f4f4;border:1px dashed #ddd;margin-bottom:10px}.full-opacity-hover{opacity:.65;filter:alpha(opacity=65)}.full-opacity-hover:hover{opacity:1;filter:alpha(opacity=100)}.chart{position:relative;overflow:hidden;width:100%}.chart svg,.chart canvas{width:100%!important}@media print{.no-print,.main-sidebar,.left-side,.main-header,.content-header{display:none!important}.content-wrapper,.right-side,.main-footer{margin-left:0!important;min-height:0!important;-webkit-transform:translate(0, 0) !important;-ms-transform:translate(0, 0) !important;-o-transform:translate(0, 0) !important;transform:translate(0, 0) !important}.fixed .content-wrapper,.fixed .right-side{padding-top:0!important}.invoice{width:100%;border:0;margin:0;padding:0}.invoice-col{float:left;width:33.3333333%}.table-responsive{overflow:auto}.table-responsive>.table tr th,.table-responsive>.table tr td{white-space:normal!important}}
\ No newline at end of file
--- /dev/null
+.skin-blue .main-header .navbar{background-color:#3c8dbc}.skin-blue .main-header .navbar .nav>li>a{color:#fff}.skin-blue .main-header .navbar .nav>li>a:hover,.skin-blue .main-header .navbar .nav>li>a:active,.skin-blue .main-header .navbar .nav>li>a:focus,.skin-blue .main-header .navbar .nav .open>a,.skin-blue .main-header .navbar .nav .open>a:hover,.skin-blue .main-header .navbar .nav .open>a:focus,.skin-blue .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-blue .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-blue .main-header .navbar .dropdown-menu li a{color:#fff}.skin-blue .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue .main-header .logo{background-color:#367fa9;color:#fff;border-bottom:0 solid transparent}.skin-blue .main-header .logo:hover{background-color:#357ca5}.skin-blue .main-header li.user-header{background-color:#3c8dbc}.skin-blue .content-header{background:transparent}.skin-blue .wrapper,.skin-blue .main-sidebar,.skin-blue .left-side{background-color:#222d32}.skin-blue .user-panel>.info,.skin-blue .user-panel>.info>a{color:#fff}.skin-blue .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-blue .sidebar-menu>li>a{border-left:3px solid transparent}.skin-blue .sidebar-menu>li:hover>a,.skin-blue .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#3c8dbc}.skin-blue .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-blue .sidebar a{color:#b8c7ce}.skin-blue .sidebar a:hover{text-decoration:none}.skin-blue .treeview-menu>li>a{color:#8aa4af}.skin-blue .treeview-menu>li.active>a,.skin-blue .treeview-menu>li>a:hover{color:#fff}.skin-blue .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-blue .sidebar-form input[type="text"],.skin-blue .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-blue .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-blue .sidebar-form input[type="text"]:focus,.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-blue.layout-top-nav .main-header>.logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue.layout-top-nav .main-header>.logo:hover{background-color:#3b8ab8}.skin-blue-light .main-header .navbar{background-color:#3c8dbc}.skin-blue-light .main-header .navbar .nav>li>a{color:#fff}.skin-blue-light .main-header .navbar .nav>li>a:hover,.skin-blue-light .main-header .navbar .nav>li>a:active,.skin-blue-light .main-header .navbar .nav>li>a:focus,.skin-blue-light .main-header .navbar .nav .open>a,.skin-blue-light .main-header .navbar .nav .open>a:hover,.skin-blue-light .main-header .navbar .nav .open>a:focus,.skin-blue-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-blue-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-blue-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-blue-light .main-header .navbar .sidebar-toggle:hover{background-color:#367fa9}@media (max-width:767px){.skin-blue-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-blue-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-blue-light .main-header .navbar .dropdown-menu li a:hover{background:#367fa9}}.skin-blue-light .main-header .logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue-light .main-header .logo:hover{background-color:#3b8ab8}.skin-blue-light .main-header li.user-header{background-color:#3c8dbc}.skin-blue-light .content-header{background:transparent}.skin-blue-light .wrapper,.skin-blue-light .main-sidebar,.skin-blue-light .left-side{background-color:#f9fafc}.skin-blue-light .content-wrapper,.skin-blue-light .main-footer{border-left:1px solid #d2d6de}.skin-blue-light .user-panel>.info,.skin-blue-light .user-panel>.info>a{color:#444}.skin-blue-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-blue-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-blue-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-blue-light .sidebar-menu>li:hover>a,.skin-blue-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-blue-light .sidebar-menu>li.active{border-left-color:#3c8dbc}.skin-blue-light .sidebar-menu>li.active>a{font-weight:600}.skin-blue-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-blue-light .sidebar a{color:#444}.skin-blue-light .sidebar a:hover{text-decoration:none}.skin-blue-light .treeview-menu>li>a{color:#777}.skin-blue-light .treeview-menu>li.active>a,.skin-blue-light .treeview-menu>li>a:hover{color:#000}.skin-blue-light .treeview-menu>li.active>a{font-weight:600}.skin-blue-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-blue-light .sidebar-form input[type="text"],.skin-blue-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-blue-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-blue-light .sidebar-form input[type="text"]:focus,.skin-blue-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-blue-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-blue-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-blue-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}.skin-blue-light .main-footer{border-top-color:#d2d6de}.skin-blue.layout-top-nav .main-header>.logo{background-color:#3c8dbc;color:#fff;border-bottom:0 solid transparent}.skin-blue.layout-top-nav .main-header>.logo:hover{background-color:#3b8ab8}.skin-black .main-header{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.skin-black .main-header .navbar-toggle{color:#333}.skin-black .main-header .navbar-brand{color:#333;border-right:1px solid #eee}.skin-black .main-header>.navbar{background-color:#fff}.skin-black .main-header>.navbar .nav>li>a{color:#333}.skin-black .main-header>.navbar .nav>li>a:hover,.skin-black .main-header>.navbar .nav>li>a:active,.skin-black .main-header>.navbar .nav>li>a:focus,.skin-black .main-header>.navbar .nav .open>a,.skin-black .main-header>.navbar .nav .open>a:hover,.skin-black .main-header>.navbar .nav .open>a:focus,.skin-black .main-header>.navbar .nav>.active>a{background:#fff;color:#999}.skin-black .main-header>.navbar .sidebar-toggle{color:#333}.skin-black .main-header>.navbar .sidebar-toggle:hover{color:#999;background:#fff}.skin-black .main-header>.navbar>.sidebar-toggle{color:#333;border-right:1px solid #eee}.skin-black .main-header>.navbar .navbar-nav>li>a{border-right:1px solid #eee}.skin-black .main-header>.navbar .navbar-custom-menu .navbar-nav>li>a,.skin-black .main-header>.navbar .navbar-right>li>a{border-left:1px solid #eee;border-right-width:0}.skin-black .main-header>.logo{background-color:#fff;color:#333;border-bottom:0 solid transparent;border-right:1px solid #eee}.skin-black .main-header>.logo:hover{background-color:#fcfcfc}@media (max-width:767px){.skin-black .main-header>.logo{background-color:#222;color:#fff;border-bottom:0 solid transparent;border-right:none}.skin-black .main-header>.logo:hover{background-color:#1f1f1f}}.skin-black .main-header li.user-header{background-color:#222}.skin-black .content-header{background:transparent;box-shadow:none}.skin-black .wrapper,.skin-black .main-sidebar,.skin-black .left-side{background-color:#222d32}.skin-black .user-panel>.info,.skin-black .user-panel>.info>a{color:#fff}.skin-black .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-black .sidebar-menu>li>a{border-left:3px solid transparent}.skin-black .sidebar-menu>li:hover>a,.skin-black .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#fff}.skin-black .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-black .sidebar a{color:#b8c7ce}.skin-black .sidebar a:hover{text-decoration:none}.skin-black .treeview-menu>li>a{color:#8aa4af}.skin-black .treeview-menu>li.active>a,.skin-black .treeview-menu>li>a:hover{color:#fff}.skin-black .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-black .sidebar-form input[type="text"],.skin-black .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-black .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-black .sidebar-form input[type="text"]:focus,.skin-black .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-black .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-black .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-black-light .main-header{-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.skin-black-light .main-header .navbar-toggle{color:#333}.skin-black-light .main-header .navbar-brand{color:#333;border-right:1px solid #eee}.skin-black-light .main-header>.navbar{background-color:#fff}.skin-black-light .main-header>.navbar .nav>li>a{color:#333}.skin-black-light .main-header>.navbar .nav>li>a:hover,.skin-black-light .main-header>.navbar .nav>li>a:active,.skin-black-light .main-header>.navbar .nav>li>a:focus,.skin-black-light .main-header>.navbar .nav .open>a,.skin-black-light .main-header>.navbar .nav .open>a:hover,.skin-black-light .main-header>.navbar .nav .open>a:focus,.skin-black-light .main-header>.navbar .nav>.active>a{background:#fff;color:#999}.skin-black-light .main-header>.navbar .sidebar-toggle{color:#333}.skin-black-light .main-header>.navbar .sidebar-toggle:hover{color:#999;background:#fff}.skin-black-light .main-header>.navbar>.sidebar-toggle{color:#333;border-right:1px solid #eee}.skin-black-light .main-header>.navbar .navbar-nav>li>a{border-right:1px solid #eee}.skin-black-light .main-header>.navbar .navbar-custom-menu .navbar-nav>li>a,.skin-black-light .main-header>.navbar .navbar-right>li>a{border-left:1px solid #eee;border-right-width:0}.skin-black-light .main-header>.logo{background-color:#fff;color:#333;border-bottom:0 solid transparent;border-right:1px solid #eee}.skin-black-light .main-header>.logo:hover{background-color:#fcfcfc}@media (max-width:767px){.skin-black-light .main-header>.logo{background-color:#222;color:#fff;border-bottom:0 solid transparent;border-right:none}.skin-black-light .main-header>.logo:hover{background-color:#1f1f1f}}.skin-black-light .main-header li.user-header{background-color:#222}.skin-black-light .content-header{background:transparent;box-shadow:none}.skin-black-light .wrapper,.skin-black-light .main-sidebar,.skin-black-light .left-side{background-color:#f9fafc}.skin-black-light .content-wrapper,.skin-black-light .main-footer{border-left:1px solid #d2d6de}.skin-black-light .user-panel>.info,.skin-black-light .user-panel>.info>a{color:#444}.skin-black-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-black-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-black-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-black-light .sidebar-menu>li:hover>a,.skin-black-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-black-light .sidebar-menu>li.active{border-left-color:#fff}.skin-black-light .sidebar-menu>li.active>a{font-weight:600}.skin-black-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-black-light .sidebar a{color:#444}.skin-black-light .sidebar a:hover{text-decoration:none}.skin-black-light .treeview-menu>li>a{color:#777}.skin-black-light .treeview-menu>li.active>a,.skin-black-light .treeview-menu>li>a:hover{color:#000}.skin-black-light .treeview-menu>li.active>a{font-weight:600}.skin-black-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-black-light .sidebar-form input[type="text"],.skin-black-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-black-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-black-light .sidebar-form input[type="text"]:focus,.skin-black-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-black-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-black-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-black-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}.skin-green .main-header .navbar{background-color:#00a65a}.skin-green .main-header .navbar .nav>li>a{color:#fff}.skin-green .main-header .navbar .nav>li>a:hover,.skin-green .main-header .navbar .nav>li>a:active,.skin-green .main-header .navbar .nav>li>a:focus,.skin-green .main-header .navbar .nav .open>a,.skin-green .main-header .navbar .nav .open>a:hover,.skin-green .main-header .navbar .nav .open>a:focus,.skin-green .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-green .main-header .navbar .sidebar-toggle{color:#fff}.skin-green .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-green .main-header .navbar .sidebar-toggle{color:#fff}.skin-green .main-header .navbar .sidebar-toggle:hover{background-color:#008d4c}@media (max-width:767px){.skin-green .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-green .main-header .navbar .dropdown-menu li a{color:#fff}.skin-green .main-header .navbar .dropdown-menu li a:hover{background:#008d4c}}.skin-green .main-header .logo{background-color:#008d4c;color:#fff;border-bottom:0 solid transparent}.skin-green .main-header .logo:hover{background-color:#008749}.skin-green .main-header li.user-header{background-color:#00a65a}.skin-green .content-header{background:transparent}.skin-green .wrapper,.skin-green .main-sidebar,.skin-green .left-side{background-color:#222d32}.skin-green .user-panel>.info,.skin-green .user-panel>.info>a{color:#fff}.skin-green .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-green .sidebar-menu>li>a{border-left:3px solid transparent}.skin-green .sidebar-menu>li:hover>a,.skin-green .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#00a65a}.skin-green .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-green .sidebar a{color:#b8c7ce}.skin-green .sidebar a:hover{text-decoration:none}.skin-green .treeview-menu>li>a{color:#8aa4af}.skin-green .treeview-menu>li.active>a,.skin-green .treeview-menu>li>a:hover{color:#fff}.skin-green .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-green .sidebar-form input[type="text"],.skin-green .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-green .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-green .sidebar-form input[type="text"]:focus,.skin-green .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-green .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-green .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-green-light .main-header .navbar{background-color:#00a65a}.skin-green-light .main-header .navbar .nav>li>a{color:#fff}.skin-green-light .main-header .navbar .nav>li>a:hover,.skin-green-light .main-header .navbar .nav>li>a:active,.skin-green-light .main-header .navbar .nav>li>a:focus,.skin-green-light .main-header .navbar .nav .open>a,.skin-green-light .main-header .navbar .nav .open>a:hover,.skin-green-light .main-header .navbar .nav .open>a:focus,.skin-green-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-green-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-green-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-green-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-green-light .main-header .navbar .sidebar-toggle:hover{background-color:#008d4c}@media (max-width:767px){.skin-green-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-green-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-green-light .main-header .navbar .dropdown-menu li a:hover{background:#008d4c}}.skin-green-light .main-header .logo{background-color:#00a65a;color:#fff;border-bottom:0 solid transparent}.skin-green-light .main-header .logo:hover{background-color:#00a157}.skin-green-light .main-header li.user-header{background-color:#00a65a}.skin-green-light .content-header{background:transparent}.skin-green-light .wrapper,.skin-green-light .main-sidebar,.skin-green-light .left-side{background-color:#f9fafc}.skin-green-light .content-wrapper,.skin-green-light .main-footer{border-left:1px solid #d2d6de}.skin-green-light .user-panel>.info,.skin-green-light .user-panel>.info>a{color:#444}.skin-green-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-green-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-green-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-green-light .sidebar-menu>li:hover>a,.skin-green-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-green-light .sidebar-menu>li.active{border-left-color:#00a65a}.skin-green-light .sidebar-menu>li.active>a{font-weight:600}.skin-green-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-green-light .sidebar a{color:#444}.skin-green-light .sidebar a:hover{text-decoration:none}.skin-green-light .treeview-menu>li>a{color:#777}.skin-green-light .treeview-menu>li.active>a,.skin-green-light .treeview-menu>li>a:hover{color:#000}.skin-green-light .treeview-menu>li.active>a{font-weight:600}.skin-green-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-green-light .sidebar-form input[type="text"],.skin-green-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-green-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-green-light .sidebar-form input[type="text"]:focus,.skin-green-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-green-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-green-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-green-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}.skin-red .main-header .navbar{background-color:#dd4b39}.skin-red .main-header .navbar .nav>li>a{color:#fff}.skin-red .main-header .navbar .nav>li>a:hover,.skin-red .main-header .navbar .nav>li>a:active,.skin-red .main-header .navbar .nav>li>a:focus,.skin-red .main-header .navbar .nav .open>a,.skin-red .main-header .navbar .nav .open>a:hover,.skin-red .main-header .navbar .nav .open>a:focus,.skin-red .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-red .main-header .navbar .sidebar-toggle{color:#fff}.skin-red .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-red .main-header .navbar .sidebar-toggle{color:#fff}.skin-red .main-header .navbar .sidebar-toggle:hover{background-color:#d73925}@media (max-width:767px){.skin-red .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-red .main-header .navbar .dropdown-menu li a{color:#fff}.skin-red .main-header .navbar .dropdown-menu li a:hover{background:#d73925}}.skin-red .main-header .logo{background-color:#d73925;color:#fff;border-bottom:0 solid transparent}.skin-red .main-header .logo:hover{background-color:#d33724}.skin-red .main-header li.user-header{background-color:#dd4b39}.skin-red .content-header{background:transparent}.skin-red .wrapper,.skin-red .main-sidebar,.skin-red .left-side{background-color:#222d32}.skin-red .user-panel>.info,.skin-red .user-panel>.info>a{color:#fff}.skin-red .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-red .sidebar-menu>li>a{border-left:3px solid transparent}.skin-red .sidebar-menu>li:hover>a,.skin-red .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#dd4b39}.skin-red .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-red .sidebar a{color:#b8c7ce}.skin-red .sidebar a:hover{text-decoration:none}.skin-red .treeview-menu>li>a{color:#8aa4af}.skin-red .treeview-menu>li.active>a,.skin-red .treeview-menu>li>a:hover{color:#fff}.skin-red .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-red .sidebar-form input[type="text"],.skin-red .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-red .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-red .sidebar-form input[type="text"]:focus,.skin-red .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-red .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-red .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-red-light .main-header .navbar{background-color:#dd4b39}.skin-red-light .main-header .navbar .nav>li>a{color:#fff}.skin-red-light .main-header .navbar .nav>li>a:hover,.skin-red-light .main-header .navbar .nav>li>a:active,.skin-red-light .main-header .navbar .nav>li>a:focus,.skin-red-light .main-header .navbar .nav .open>a,.skin-red-light .main-header .navbar .nav .open>a:hover,.skin-red-light .main-header .navbar .nav .open>a:focus,.skin-red-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-red-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-red-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-red-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-red-light .main-header .navbar .sidebar-toggle:hover{background-color:#d73925}@media (max-width:767px){.skin-red-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-red-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-red-light .main-header .navbar .dropdown-menu li a:hover{background:#d73925}}.skin-red-light .main-header .logo{background-color:#dd4b39;color:#fff;border-bottom:0 solid transparent}.skin-red-light .main-header .logo:hover{background-color:#dc4735}.skin-red-light .main-header li.user-header{background-color:#dd4b39}.skin-red-light .content-header{background:transparent}.skin-red-light .wrapper,.skin-red-light .main-sidebar,.skin-red-light .left-side{background-color:#f9fafc}.skin-red-light .content-wrapper,.skin-red-light .main-footer{border-left:1px solid #d2d6de}.skin-red-light .user-panel>.info,.skin-red-light .user-panel>.info>a{color:#444}.skin-red-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-red-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-red-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-red-light .sidebar-menu>li:hover>a,.skin-red-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-red-light .sidebar-menu>li.active{border-left-color:#dd4b39}.skin-red-light .sidebar-menu>li.active>a{font-weight:600}.skin-red-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-red-light .sidebar a{color:#444}.skin-red-light .sidebar a:hover{text-decoration:none}.skin-red-light .treeview-menu>li>a{color:#777}.skin-red-light .treeview-menu>li.active>a,.skin-red-light .treeview-menu>li>a:hover{color:#000}.skin-red-light .treeview-menu>li.active>a{font-weight:600}.skin-red-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-red-light .sidebar-form input[type="text"],.skin-red-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-red-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-red-light .sidebar-form input[type="text"]:focus,.skin-red-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-red-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-red-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-red-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}.skin-yellow .main-header .navbar{background-color:#f39c12}.skin-yellow .main-header .navbar .nav>li>a{color:#fff}.skin-yellow .main-header .navbar .nav>li>a:hover,.skin-yellow .main-header .navbar .nav>li>a:active,.skin-yellow .main-header .navbar .nav>li>a:focus,.skin-yellow .main-header .navbar .nav .open>a,.skin-yellow .main-header .navbar .nav .open>a:hover,.skin-yellow .main-header .navbar .nav .open>a:focus,.skin-yellow .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-yellow .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-yellow .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow .main-header .navbar .sidebar-toggle:hover{background-color:#e08e0b}@media (max-width:767px){.skin-yellow .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-yellow .main-header .navbar .dropdown-menu li a{color:#fff}.skin-yellow .main-header .navbar .dropdown-menu li a:hover{background:#e08e0b}}.skin-yellow .main-header .logo{background-color:#e08e0b;color:#fff;border-bottom:0 solid transparent}.skin-yellow .main-header .logo:hover{background-color:#db8b0b}.skin-yellow .main-header li.user-header{background-color:#f39c12}.skin-yellow .content-header{background:transparent}.skin-yellow .wrapper,.skin-yellow .main-sidebar,.skin-yellow .left-side{background-color:#222d32}.skin-yellow .user-panel>.info,.skin-yellow .user-panel>.info>a{color:#fff}.skin-yellow .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-yellow .sidebar-menu>li>a{border-left:3px solid transparent}.skin-yellow .sidebar-menu>li:hover>a,.skin-yellow .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#f39c12}.skin-yellow .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-yellow .sidebar a{color:#b8c7ce}.skin-yellow .sidebar a:hover{text-decoration:none}.skin-yellow .treeview-menu>li>a{color:#8aa4af}.skin-yellow .treeview-menu>li.active>a,.skin-yellow .treeview-menu>li>a:hover{color:#fff}.skin-yellow .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-yellow .sidebar-form input[type="text"],.skin-yellow .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-yellow .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-yellow .sidebar-form input[type="text"]:focus,.skin-yellow .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-yellow .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-yellow .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-yellow-light .main-header .navbar{background-color:#f39c12}.skin-yellow-light .main-header .navbar .nav>li>a{color:#fff}.skin-yellow-light .main-header .navbar .nav>li>a:hover,.skin-yellow-light .main-header .navbar .nav>li>a:active,.skin-yellow-light .main-header .navbar .nav>li>a:focus,.skin-yellow-light .main-header .navbar .nav .open>a,.skin-yellow-light .main-header .navbar .nav .open>a:hover,.skin-yellow-light .main-header .navbar .nav .open>a:focus,.skin-yellow-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-yellow-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-yellow-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-yellow-light .main-header .navbar .sidebar-toggle:hover{background-color:#e08e0b}@media (max-width:767px){.skin-yellow-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-yellow-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-yellow-light .main-header .navbar .dropdown-menu li a:hover{background:#e08e0b}}.skin-yellow-light .main-header .logo{background-color:#f39c12;color:#fff;border-bottom:0 solid transparent}.skin-yellow-light .main-header .logo:hover{background-color:#f39a0d}.skin-yellow-light .main-header li.user-header{background-color:#f39c12}.skin-yellow-light .content-header{background:transparent}.skin-yellow-light .wrapper,.skin-yellow-light .main-sidebar,.skin-yellow-light .left-side{background-color:#f9fafc}.skin-yellow-light .content-wrapper,.skin-yellow-light .main-footer{border-left:1px solid #d2d6de}.skin-yellow-light .user-panel>.info,.skin-yellow-light .user-panel>.info>a{color:#444}.skin-yellow-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-yellow-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-yellow-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-yellow-light .sidebar-menu>li:hover>a,.skin-yellow-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-yellow-light .sidebar-menu>li.active{border-left-color:#f39c12}.skin-yellow-light .sidebar-menu>li.active>a{font-weight:600}.skin-yellow-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-yellow-light .sidebar a{color:#444}.skin-yellow-light .sidebar a:hover{text-decoration:none}.skin-yellow-light .treeview-menu>li>a{color:#777}.skin-yellow-light .treeview-menu>li.active>a,.skin-yellow-light .treeview-menu>li>a:hover{color:#000}.skin-yellow-light .treeview-menu>li.active>a{font-weight:600}.skin-yellow-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-yellow-light .sidebar-form input[type="text"],.skin-yellow-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-yellow-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-yellow-light .sidebar-form input[type="text"]:focus,.skin-yellow-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-yellow-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-yellow-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-yellow-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}.skin-purple .main-header .navbar{background-color:#605ca8}.skin-purple .main-header .navbar .nav>li>a{color:#fff}.skin-purple .main-header .navbar .nav>li>a:hover,.skin-purple .main-header .navbar .nav>li>a:active,.skin-purple .main-header .navbar .nav>li>a:focus,.skin-purple .main-header .navbar .nav .open>a,.skin-purple .main-header .navbar .nav .open>a:hover,.skin-purple .main-header .navbar .nav .open>a:focus,.skin-purple .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-purple .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-purple .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple .main-header .navbar .sidebar-toggle:hover{background-color:#555299}@media (max-width:767px){.skin-purple .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-purple .main-header .navbar .dropdown-menu li a{color:#fff}.skin-purple .main-header .navbar .dropdown-menu li a:hover{background:#555299}}.skin-purple .main-header .logo{background-color:#555299;color:#fff;border-bottom:0 solid transparent}.skin-purple .main-header .logo:hover{background-color:#545096}.skin-purple .main-header li.user-header{background-color:#605ca8}.skin-purple .content-header{background:transparent}.skin-purple .wrapper,.skin-purple .main-sidebar,.skin-purple .left-side{background-color:#222d32}.skin-purple .user-panel>.info,.skin-purple .user-panel>.info>a{color:#fff}.skin-purple .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-purple .sidebar-menu>li>a{border-left:3px solid transparent}.skin-purple .sidebar-menu>li:hover>a,.skin-purple .sidebar-menu>li.active>a{color:#fff;background:#1e282c;border-left-color:#605ca8}.skin-purple .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-purple .sidebar a{color:#b8c7ce}.skin-purple .sidebar a:hover{text-decoration:none}.skin-purple .treeview-menu>li>a{color:#8aa4af}.skin-purple .treeview-menu>li.active>a,.skin-purple .treeview-menu>li>a:hover{color:#fff}.skin-purple .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px 10px}.skin-purple .sidebar-form input[type="text"],.skin-purple .sidebar-form .btn{box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-purple .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-purple .sidebar-form input[type="text"]:focus,.skin-purple .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-purple .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-purple .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-purple-light .main-header .navbar{background-color:#605ca8}.skin-purple-light .main-header .navbar .nav>li>a{color:#fff}.skin-purple-light .main-header .navbar .nav>li>a:hover,.skin-purple-light .main-header .navbar .nav>li>a:active,.skin-purple-light .main-header .navbar .nav>li>a:focus,.skin-purple-light .main-header .navbar .nav .open>a,.skin-purple-light .main-header .navbar .nav .open>a:hover,.skin-purple-light .main-header .navbar .nav .open>a:focus,.skin-purple-light .main-header .navbar .nav>.active>a{background:rgba(0,0,0,0.1);color:#f6f6f6}.skin-purple-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple-light .main-header .navbar .sidebar-toggle:hover{color:#f6f6f6;background:rgba(0,0,0,0.1)}.skin-purple-light .main-header .navbar .sidebar-toggle{color:#fff}.skin-purple-light .main-header .navbar .sidebar-toggle:hover{background-color:#555299}@media (max-width:767px){.skin-purple-light .main-header .navbar .dropdown-menu li.divider{background-color:rgba(255,255,255,0.1)}.skin-purple-light .main-header .navbar .dropdown-menu li a{color:#fff}.skin-purple-light .main-header .navbar .dropdown-menu li a:hover{background:#555299}}.skin-purple-light .main-header .logo{background-color:#605ca8;color:#fff;border-bottom:0 solid transparent}.skin-purple-light .main-header .logo:hover{background-color:#5d59a6}.skin-purple-light .main-header li.user-header{background-color:#605ca8}.skin-purple-light .content-header{background:transparent}.skin-purple-light .wrapper,.skin-purple-light .main-sidebar,.skin-purple-light .left-side{background-color:#f9fafc}.skin-purple-light .content-wrapper,.skin-purple-light .main-footer{border-left:1px solid #d2d6de}.skin-purple-light .user-panel>.info,.skin-purple-light .user-panel>.info>a{color:#444}.skin-purple-light .sidebar-menu>li{-webkit-transition:border-left-color .3s ease;-o-transition:border-left-color .3s ease;transition:border-left-color .3s ease}.skin-purple-light .sidebar-menu>li.header{color:#848484;background:#f9fafc}.skin-purple-light .sidebar-menu>li>a{border-left:3px solid transparent;font-weight:600}.skin-purple-light .sidebar-menu>li:hover>a,.skin-purple-light .sidebar-menu>li.active>a{color:#000;background:#f4f4f5}.skin-purple-light .sidebar-menu>li.active{border-left-color:#605ca8}.skin-purple-light .sidebar-menu>li.active>a{font-weight:600}.skin-purple-light .sidebar-menu>li>.treeview-menu{background:#f4f4f5}.skin-purple-light .sidebar a{color:#444}.skin-purple-light .sidebar a:hover{text-decoration:none}.skin-purple-light .treeview-menu>li>a{color:#777}.skin-purple-light .treeview-menu>li.active>a,.skin-purple-light .treeview-menu>li>a:hover{color:#000}.skin-purple-light .treeview-menu>li.active>a{font-weight:600}.skin-purple-light .sidebar-form{border-radius:3px;border:1px solid #d2d6de;margin:10px 10px}.skin-purple-light .sidebar-form input[type="text"],.skin-purple-light .sidebar-form .btn{box-shadow:none;background-color:#fff;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-purple-light .sidebar-form input[type="text"]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-purple-light .sidebar-form input[type="text"]:focus,.skin-purple-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-purple-light .sidebar-form input[type="text"]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-purple-light .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}@media (min-width:768px){.skin-purple-light.sidebar-mini.sidebar-collapse .sidebar-menu>li>.treeview-menu{border-left:1px solid #d2d6de}}
\ No newline at end of file
--- /dev/null
+/*!
+ * Bootstrap v3.3.5 (http://getbootstrap.com)
+ * Copyright 2011-2015 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ *//*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */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{*,:after,:before{color:#000!important;text-shadow:none!important;background:0 0!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^="javascript:"]:after,a[href^="#"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.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 td,.table-bordered th{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.woff2) format('woff2'),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-eur:before,.glyphicon-euro: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"}.glyphicon-cd:before{content:"\e201"}.glyphicon-save-file:before{content:"\e202"}.glyphicon-open-file:before{content:"\e203"}.glyphicon-level-up:before{content:"\e204"}.glyphicon-copy:before{content:"\e205"}.glyphicon-paste:before{content:"\e206"}.glyphicon-alert:before{content:"\e209"}.glyphicon-equalizer:before{content:"\e210"}.glyphicon-king:before{content:"\e211"}.glyphicon-queen:before{content:"\e212"}.glyphicon-pawn:before{content:"\e213"}.glyphicon-bishop:before{content:"\e214"}.glyphicon-knight:before{content:"\e215"}.glyphicon-baby-formula:before{content:"\e216"}.glyphicon-tent:before{content:"\26fa"}.glyphicon-blackboard:before{content:"\e218"}.glyphicon-bed:before{content:"\e219"}.glyphicon-apple:before{content:"\f8ff"}.glyphicon-erase:before{content:"\e221"}.glyphicon-hourglass:before{content:"\231b"}.glyphicon-lamp:before{content:"\e223"}.glyphicon-duplicate:before{content:"\e224"}.glyphicon-piggy-bank:before{content:"\e225"}.glyphicon-scissors:before{content:"\e226"}.glyphicon-bitcoin:before{content:"\e227"}.glyphicon-btc:before{content:"\e227"}.glyphicon-xbt:before{content:"\e227"}.glyphicon-yen:before{content:"\00a5"}.glyphicon-jpy:before{content:"\00a5"}.glyphicon-ruble:before{content:"\20bd"}.glyphicon-rub:before{content:"\20bd"}.glyphicon-scale:before{content:"\e230"}.glyphicon-ice-lolly:before{content:"\e231"}.glyphicon-ice-lolly-tasted:before{content:"\e232"}.glyphicon-education:before{content:"\e233"}.glyphicon-option-horizontal:before{content:"\e234"}.glyphicon-option-vertical:before{content:"\e235"}.glyphicon-menu-hamburger:before{content:"\e236"}.glyphicon-modal-window:before{content:"\e237"}.glyphicon-oil:before{content:"\e238"}.glyphicon-grain:before{content:"\e239"}.glyphicon-sunglasses:before{content:"\e240"}.glyphicon-text-size:before{content:"\e241"}.glyphicon-text-color:before{content:"\e242"}.glyphicon-text-background:before{content:"\e243"}.glyphicon-object-align-top:before{content:"\e244"}.glyphicon-object-align-bottom:before{content:"\e245"}.glyphicon-object-align-horizontal:before{content:"\e246"}.glyphicon-object-align-left:before{content:"\e247"}.glyphicon-object-align-vertical:before{content:"\e248"}.glyphicon-object-align-right:before{content:"\e249"}.glyphicon-triangle-right:before{content:"\e250"}.glyphicon-triangle-left:before{content:"\e251"}.glyphicon-triangle-bottom:before{content:"\e252"}.glyphicon-triangle-top:before{content:"\e253"}.glyphicon-console:before{content:"\e254"}.glyphicon-superscript:before{content:"\e255"}.glyphicon-subscript:before{content:"\e256"}.glyphicon-menu-left:before{content:"\e257"}.glyphicon-menu-right:before{content:"\e258"}.glyphicon-menu-down:before{content:"\e259"}.glyphicon-menu-up:before{content:"\e260"}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:after,:before{-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}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#337ab7;text-decoration:none}a:focus,a:hover{color:#23527c;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}.carousel-inner>.item>a>img,.carousel-inner>.item>img,.img-responsive,.thumbnail a>img,.thumbnail>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}[role=button]{cursor:pointer}.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,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,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,.h5,.h6,h4,h5,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:#337ab7}a.text-primary:focus,a.text-primary:hover{color:#286090}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#337ab7}a.bg-primary:focus,a.bg-primary:hover{background-color:#286090}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{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}dd,dt{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[data-original-title],abbr[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 ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.42857143;color:#777}blockquote .small:before,blockquote footer: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 .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer: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-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.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-md-1,.col-md-10,.col-md-11,.col-md-12,.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-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.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-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-10,.col-xs-11,.col-xs-12,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9{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-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9{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-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9{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-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9{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>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{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>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(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>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{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>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{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=checkbox],input[type=radio]{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=checkbox]:focus,input[type=radio]: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{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=time].form-control,input[type=datetime-local].form-control,input[type=month].form-control{line-height:34px}.input-group-sm input[type=date],.input-group-sm input[type=time],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],input[type=date].input-sm,input[type=time].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm{line-height:30px}.input-group-lg input[type=date],.input-group-lg input[type=time],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],input[type=date].input-lg,input[type=time].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox],.radio input[type=radio],.radio-inline input[type=radio]{position:absolute;margin-top:4px\9;margin-left:-20px}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;font-weight:400;vertical-align:middle;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.checkbox-inline.disabled,.radio-inline.disabled,fieldset[disabled] .checkbox-inline,fieldset[disabled] .radio-inline{cursor:not-allowed}.checkbox.disabled label,.radio.disabled label,fieldset[disabled] .checkbox label,fieldset[disabled] .radio label{cursor:not-allowed}.form-control-static{min-height:34px;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{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}select.input-lg{height:46px;line-height:46px}select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.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}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.checkbox label,.has-success.checkbox-inline label,.has-success.radio label,.has-success.radio-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 .checkbox,.has-warning .checkbox-inline,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.checkbox label,.has-warning.checkbox-inline label,.has-warning.radio label,.has-warning.radio-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 .checkbox,.has-error .checkbox-inline,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.checkbox label,.has-error.checkbox-inline label,.has-error.radio label,.has-error.radio-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 .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{padding-top:7px;margin-top:0;margin-bottom:0}.form-horizontal .checkbox,.form-horizontal .radio{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.33px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.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.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{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{cursor:not-allowed;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none;opacity:.65}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default:hover{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.dropdown-toggle.btn-default.focus,.open>.dropdown-toggle.btn-default:focus,.open>.dropdown-toggle.btn-default:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.dropdown-toggle.btn-primary.focus,.open>.dropdown-toggle.btn-primary:focus,.open>.dropdown-toggle.btn-primary:hover{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary.active,.btn-primary:active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.dropdown-toggle.btn-success.focus,.open>.dropdown-toggle.btn-success:focus,.open>.dropdown-toggle.btn-success:hover{color:#fff;background-color:#398439;border-color:#255625}.btn-success.active,.btn-success:active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{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.focus,.btn-info:focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.dropdown-toggle.btn-info.focus,.open>.dropdown-toggle.btn-info:focus,.open>.dropdown-toggle.btn-info:hover{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info.active,.btn-info:active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{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.focus,.btn-warning:focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.dropdown-toggle.btn-warning.focus,.open>.dropdown-toggle.btn-warning:focus,.open>.dropdown-toggle.btn-warning:hover{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning.active,.btn-warning:active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{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.focus,.btn-danger:focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.dropdown-toggle.btn-danger.focus,.open>.dropdown-toggle.btn-danger:focus,.open>.dropdown-toggle.btn-danger:hover{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger.active,.btn-danger:active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{font-weight:400;color:#337ab7;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:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-xs>.btn,.btn-xs{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=button].btn-block,input[type=reset].btn-block,input[type=submit].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}.collapse.in{display:block}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 dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{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:focus,.dropdown-menu>li>a:hover{color:#262626;text-decoration:none;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;background-color:#337ab7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{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 dashed;border-bottom:4px solid\9}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@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-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.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,.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:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child:not(:first-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=checkbox],[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio]{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.3333333;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}select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn,textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.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}select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn,textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group .form-control,.input-group-addon,.input-group-btn{display:table-cell}.input-group .form-control:not(:first-child):not(:last-child),.input-group-addon:not(:first-child):not(:last-child),.input-group-btn: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=checkbox],.input-group-addon input[type=radio]{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-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){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:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle{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:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{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{z-index:2;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:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#337ab7}.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:focus,.nav-tabs>li.active>a:hover{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:focus,.nav-tabs.nav-justified>.active>a:hover{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:focus,.nav-tabs.nav-justified>.active>a:hover{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:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#337ab7}.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:focus,.nav-tabs-justified>.active>a:hover{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:focus,.nav-tabs-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.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}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-right:0;padding-left:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{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-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{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:focus,.navbar-brand:hover{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 .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{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 .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{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{margin-bottom:0;border-top-left-radius:4px;border-top-right-radius:4px;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:focus,.navbar-default .navbar-brand:hover{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:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{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:focus,.navbar-default .navbar-nav>.open>a:hover{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:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{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:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{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:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{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:focus,.navbar-inverse .navbar-nav>.open>a:hover{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:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{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:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{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:#337ab7;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:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:3;color:#23527c;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:2;color:#fff;cursor:default;background-color:#337ab7;border-color:#337ab7}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{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;line-height:1.3333333}.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;line-height:1.5}.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:focus,.pager li>a:hover{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:focus,.pager .disabled>a:hover,.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:focus,a.label:hover{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]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#337ab7}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#286090}.label-success{background-color:#5cb85c}.label-success[href]:focus,.label-success[href]:hover{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:focus,.label-info[href]:hover{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:focus,.label-danger[href]:hover{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:middle;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#337ab7;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding-top:30px;padding-bottom:30px;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-top:48px;padding-bottom:48px}.container .jumbotron,.container-fluid .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 a>img,.thumbnail>img{margin-right:auto;margin-left:auto}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#337ab7}.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:#337ab7;-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-bar-striped,.progress-striped .progress-bar{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-bar.active,.progress.active .progress-bar{-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,.media-body{overflow:hidden;zoom:1}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{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}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{color:#555;text-decoration:none;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{color:#777;cursor:not-allowed;background-color:#eee}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#337ab7;border-color:#337ab7}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#c7ddef}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{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>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>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>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-left-radius:0;border-top-right-radius:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.list-group+.panel-footer{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table caption,.panel>.table-responsive>.table caption{padding-right:15px;padding-left:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.table:first-child>tbody: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:first-child>thead:first-child>tr:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.panel>.table-responsive:first-child>.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 th:first-child,.panel>.table-responsive:first-child>.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 th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table-responsive:first-child>.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 th:last-child,.panel>.table-responsive:first-child>.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 th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:3px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.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 th:first-child,.panel>.table-responsive:last-child>.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 th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table-responsive:last-child>.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 th:last-child,.panel>.table-responsive:last-child>.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 th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.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 td,.panel>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.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>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{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:#337ab7}.panel-primary>.panel-heading{color:#fff;background-color:#337ab7;border-color:#337ab7}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#337ab7}.panel-primary>.panel-heading .badge{color:#337ab7;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#337ab7}.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 embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.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:focus,.close:hover{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:1050;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;z-index:1040;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-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;white-space:normal;filter:alpha(opacity=0);opacity:0;line-break:auto}.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;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{right:5px;bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;left:5px;margin-bottom:-5px;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;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-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-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;font-style:normal;font-weight:400;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;word-wrap:normal;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);line-break:auto}.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>a>img,.carousel-inner>.item>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:1000px;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{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:focus,.carousel-control:hover{color:#fff;text-decoration:none;filter:alpha(opacity=90);outline:0;opacity:.9}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;z-index:5;display:inline-block;margin-top:-10px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;font-family:serif;line-height:1}.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-next,.carousel-control .icon-prev{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}}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before,.btn-toolbar:after,.btn-toolbar:before,.clearfix:after,.clearfix:before,.container-fluid:after,.container-fluid:before,.container:after,.container:before,.dl-horizontal dd:after,.dl-horizontal dd:before,.form-horizontal .form-group:after,.form-horizontal .form-group:before,.modal-footer:after,.modal-footer:before,.nav:after,.nav:before,.navbar-collapse:after,.navbar-collapse:before,.navbar-header:after,.navbar-header:before,.navbar:after,.navbar:before,.pager:after,.pager:before,.panel-body:after,.panel-body:before,.row:after,.row:before{display:table;content:" "}.btn-group-vertical>.btn-group:after,.btn-toolbar:after,.clearfix:after,.container-fluid:after,.container:after,.dl-horizontal dd:after,.form-horizontal .form-group:after,.modal-footer:after,.nav:after,.navbar-collapse:after,.navbar-header:after,.navbar:after,.pager:after,.panel-body:after,.row: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}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-md,.visible-sm,.visible-xs{display:none!important}.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.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!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.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!important}tr.visible-md{display:table-row!important}td.visible-md,th.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!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.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!important}tr.visible-print{display:table-row!important}td.visible-print,th.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
--- /dev/null
+/*!\r
+ * Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome\r
+ * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)\r
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.4.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.4.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.4.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.4.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.4.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.4.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}\r
--- /dev/null
+@charset "UTF-8";/*!\r
+ Ionicons, v2.0.1\r
+ Created by Ben Sperry for the Ionic Framework, http://ionicons.com/\r
+ https://twitter.com/benjsperry https://twitter.com/ionicframework\r
+ MIT License: https://github.com/driftyco/ionicons\r
+\r
+ Android-style icons originally built by Google’s\r
+ Material Design Icons: https://github.com/google/material-design-icons\r
+ used under CC BY http://creativecommons.org/licenses/by/4.0/\r
+ Modified icons to fit ionicon’s grid from original.\r
+*/@font-face{font-family:"Ionicons";src:url("../fonts/ionicons.eot?v=2.0.1");src:url("../fonts/ionicons.eot?v=2.0.1#iefix") format("embedded-opentype"),url("../fonts/ionicons.ttf?v=2.0.1") format("truetype"),url("../fonts/ionicons.woff?v=2.0.1") format("woff"),url("../fonts/ionicons.svg?v=2.0.1#Ionicons") format("svg");font-weight:normal;font-style:normal}.ion,.ionicons,.ion-alert:before,.ion-alert-circled:before,.ion-android-add:before,.ion-android-add-circle:before,.ion-android-alarm-clock:before,.ion-android-alert:before,.ion-android-apps:before,.ion-android-archive:before,.ion-android-arrow-back:before,.ion-android-arrow-down:before,.ion-android-arrow-dropdown:before,.ion-android-arrow-dropdown-circle:before,.ion-android-arrow-dropleft:before,.ion-android-arrow-dropleft-circle:before,.ion-android-arrow-dropright:before,.ion-android-arrow-dropright-circle:before,.ion-android-arrow-dropup:before,.ion-android-arrow-dropup-circle:before,.ion-android-arrow-forward:before,.ion-android-arrow-up:before,.ion-android-attach:before,.ion-android-bar:before,.ion-android-bicycle:before,.ion-android-boat:before,.ion-android-bookmark:before,.ion-android-bulb:before,.ion-android-bus:before,.ion-android-calendar:before,.ion-android-call:before,.ion-android-camera:before,.ion-android-cancel:before,.ion-android-car:before,.ion-android-cart:before,.ion-android-chat:before,.ion-android-checkbox:before,.ion-android-checkbox-blank:before,.ion-android-checkbox-outline:before,.ion-android-checkbox-outline-blank:before,.ion-android-checkmark-circle:before,.ion-android-clipboard:before,.ion-android-close:before,.ion-android-cloud:before,.ion-android-cloud-circle:before,.ion-android-cloud-done:before,.ion-android-cloud-outline:before,.ion-android-color-palette:before,.ion-android-compass:before,.ion-android-contact:before,.ion-android-contacts:before,.ion-android-contract:before,.ion-android-create:before,.ion-android-delete:before,.ion-android-desktop:before,.ion-android-document:before,.ion-android-done:before,.ion-android-done-all:before,.ion-android-download:before,.ion-android-drafts:before,.ion-android-exit:before,.ion-android-expand:before,.ion-android-favorite:before,.ion-android-favorite-outline:before,.ion-android-film:before,.ion-android-folder:before,.ion-android-folder-open:before,.ion-android-funnel:before,.ion-android-globe:before,.ion-android-hand:before,.ion-android-hangout:before,.ion-android-happy:before,.ion-android-home:before,.ion-android-image:before,.ion-android-laptop:before,.ion-android-list:before,.ion-android-locate:before,.ion-android-lock:before,.ion-android-mail:before,.ion-android-map:before,.ion-android-menu:before,.ion-android-microphone:before,.ion-android-microphone-off:before,.ion-android-more-horizontal:before,.ion-android-more-vertical:before,.ion-android-navigate:before,.ion-android-notifications:before,.ion-android-notifications-none:before,.ion-android-notifications-off:before,.ion-android-open:before,.ion-android-options:before,.ion-android-people:before,.ion-android-person:before,.ion-android-person-add:before,.ion-android-phone-landscape:before,.ion-android-phone-portrait:before,.ion-android-pin:before,.ion-android-plane:before,.ion-android-playstore:before,.ion-android-print:before,.ion-android-radio-button-off:before,.ion-android-radio-button-on:before,.ion-android-refresh:before,.ion-android-remove:before,.ion-android-remove-circle:before,.ion-android-restaurant:before,.ion-android-sad:before,.ion-android-search:before,.ion-android-send:before,.ion-android-settings:before,.ion-android-share:before,.ion-android-share-alt:before,.ion-android-star:before,.ion-android-star-half:before,.ion-android-star-outline:before,.ion-android-stopwatch:before,.ion-android-subway:before,.ion-android-sunny:before,.ion-android-sync:before,.ion-android-textsms:before,.ion-android-time:before,.ion-android-train:before,.ion-android-unlock:before,.ion-android-upload:before,.ion-android-volume-down:before,.ion-android-volume-mute:before,.ion-android-volume-off:before,.ion-android-volume-up:before,.ion-android-walk:before,.ion-android-warning:before,.ion-android-watch:before,.ion-android-wifi:before,.ion-aperture:before,.ion-archive:before,.ion-arrow-down-a:before,.ion-arrow-down-b:before,.ion-arrow-down-c:before,.ion-arrow-expand:before,.ion-arrow-graph-down-left:before,.ion-arrow-graph-down-right:before,.ion-arrow-graph-up-left:before,.ion-arrow-graph-up-right:before,.ion-arrow-left-a:before,.ion-arrow-left-b:before,.ion-arrow-left-c:before,.ion-arrow-move:before,.ion-arrow-resize:before,.ion-arrow-return-left:before,.ion-arrow-return-right:before,.ion-arrow-right-a:before,.ion-arrow-right-b:before,.ion-arrow-right-c:before,.ion-arrow-shrink:before,.ion-arrow-swap:before,.ion-arrow-up-a:before,.ion-arrow-up-b:before,.ion-arrow-up-c:before,.ion-asterisk:before,.ion-at:before,.ion-backspace:before,.ion-backspace-outline:before,.ion-bag:before,.ion-battery-charging:before,.ion-battery-empty:before,.ion-battery-full:before,.ion-battery-half:before,.ion-battery-low:before,.ion-beaker:before,.ion-beer:before,.ion-bluetooth:before,.ion-bonfire:before,.ion-bookmark:before,.ion-bowtie:before,.ion-briefcase:before,.ion-bug:before,.ion-calculator:before,.ion-calendar:before,.ion-camera:before,.ion-card:before,.ion-cash:before,.ion-chatbox:before,.ion-chatbox-working:before,.ion-chatboxes:before,.ion-chatbubble:before,.ion-chatbubble-working:before,.ion-chatbubbles:before,.ion-checkmark:before,.ion-checkmark-circled:before,.ion-checkmark-round:before,.ion-chevron-down:before,.ion-chevron-left:before,.ion-chevron-right:before,.ion-chevron-up:before,.ion-clipboard:before,.ion-clock:before,.ion-close:before,.ion-close-circled:before,.ion-close-round:before,.ion-closed-captioning:before,.ion-cloud:before,.ion-code:before,.ion-code-download:before,.ion-code-working:before,.ion-coffee:before,.ion-compass:before,.ion-compose:before,.ion-connection-bars:before,.ion-contrast:before,.ion-crop:before,.ion-cube:before,.ion-disc:before,.ion-document:before,.ion-document-text:before,.ion-drag:before,.ion-earth:before,.ion-easel:before,.ion-edit:before,.ion-egg:before,.ion-eject:before,.ion-email:before,.ion-email-unread:before,.ion-erlenmeyer-flask:before,.ion-erlenmeyer-flask-bubbles:before,.ion-eye:before,.ion-eye-disabled:before,.ion-female:before,.ion-filing:before,.ion-film-marker:before,.ion-fireball:before,.ion-flag:before,.ion-flame:before,.ion-flash:before,.ion-flash-off:before,.ion-folder:before,.ion-fork:before,.ion-fork-repo:before,.ion-forward:before,.ion-funnel:before,.ion-gear-a:before,.ion-gear-b:before,.ion-grid:before,.ion-hammer:before,.ion-happy:before,.ion-happy-outline:before,.ion-headphone:before,.ion-heart:before,.ion-heart-broken:before,.ion-help:before,.ion-help-buoy:before,.ion-help-circled:before,.ion-home:before,.ion-icecream:before,.ion-image:before,.ion-images:before,.ion-information:before,.ion-information-circled:before,.ion-ionic:before,.ion-ios-alarm:before,.ion-ios-alarm-outline:before,.ion-ios-albums:before,.ion-ios-albums-outline:before,.ion-ios-americanfootball:before,.ion-ios-americanfootball-outline:before,.ion-ios-analytics:before,.ion-ios-analytics-outline:before,.ion-ios-arrow-back:before,.ion-ios-arrow-down:before,.ion-ios-arrow-forward:before,.ion-ios-arrow-left:before,.ion-ios-arrow-right:before,.ion-ios-arrow-thin-down:before,.ion-ios-arrow-thin-left:before,.ion-ios-arrow-thin-right:before,.ion-ios-arrow-thin-up:before,.ion-ios-arrow-up:before,.ion-ios-at:before,.ion-ios-at-outline:before,.ion-ios-barcode:before,.ion-ios-barcode-outline:before,.ion-ios-baseball:before,.ion-ios-baseball-outline:before,.ion-ios-basketball:before,.ion-ios-basketball-outline:before,.ion-ios-bell:before,.ion-ios-bell-outline:before,.ion-ios-body:before,.ion-ios-body-outline:before,.ion-ios-bolt:before,.ion-ios-bolt-outline:before,.ion-ios-book:before,.ion-ios-book-outline:before,.ion-ios-bookmarks:before,.ion-ios-bookmarks-outline:before,.ion-ios-box:before,.ion-ios-box-outline:before,.ion-ios-briefcase:before,.ion-ios-briefcase-outline:before,.ion-ios-browsers:before,.ion-ios-browsers-outline:before,.ion-ios-calculator:before,.ion-ios-calculator-outline:before,.ion-ios-calendar:before,.ion-ios-calendar-outline:before,.ion-ios-camera:before,.ion-ios-camera-outline:before,.ion-ios-cart:before,.ion-ios-cart-outline:before,.ion-ios-chatboxes:before,.ion-ios-chatboxes-outline:before,.ion-ios-chatbubble:before,.ion-ios-chatbubble-outline:before,.ion-ios-checkmark:before,.ion-ios-checkmark-empty:before,.ion-ios-checkmark-outline:before,.ion-ios-circle-filled:before,.ion-ios-circle-outline:before,.ion-ios-clock:before,.ion-ios-clock-outline:before,.ion-ios-close:before,.ion-ios-close-empty:before,.ion-ios-close-outline:before,.ion-ios-cloud:before,.ion-ios-cloud-download:before,.ion-ios-cloud-download-outline:before,.ion-ios-cloud-outline:before,.ion-ios-cloud-upload:before,.ion-ios-cloud-upload-outline:before,.ion-ios-cloudy:before,.ion-ios-cloudy-night:before,.ion-ios-cloudy-night-outline:before,.ion-ios-cloudy-outline:before,.ion-ios-cog:before,.ion-ios-cog-outline:before,.ion-ios-color-filter:before,.ion-ios-color-filter-outline:before,.ion-ios-color-wand:before,.ion-ios-color-wand-outline:before,.ion-ios-compose:before,.ion-ios-compose-outline:before,.ion-ios-contact:before,.ion-ios-contact-outline:before,.ion-ios-copy:before,.ion-ios-copy-outline:before,.ion-ios-crop:before,.ion-ios-crop-strong:before,.ion-ios-download:before,.ion-ios-download-outline:before,.ion-ios-drag:before,.ion-ios-email:before,.ion-ios-email-outline:before,.ion-ios-eye:before,.ion-ios-eye-outline:before,.ion-ios-fastforward:before,.ion-ios-fastforward-outline:before,.ion-ios-filing:before,.ion-ios-filing-outline:before,.ion-ios-film:before,.ion-ios-film-outline:before,.ion-ios-flag:before,.ion-ios-flag-outline:before,.ion-ios-flame:before,.ion-ios-flame-outline:before,.ion-ios-flask:before,.ion-ios-flask-outline:before,.ion-ios-flower:before,.ion-ios-flower-outline:before,.ion-ios-folder:before,.ion-ios-folder-outline:before,.ion-ios-football:before,.ion-ios-football-outline:before,.ion-ios-game-controller-a:before,.ion-ios-game-controller-a-outline:before,.ion-ios-game-controller-b:before,.ion-ios-game-controller-b-outline:before,.ion-ios-gear:before,.ion-ios-gear-outline:before,.ion-ios-glasses:before,.ion-ios-glasses-outline:before,.ion-ios-grid-view:before,.ion-ios-grid-view-outline:before,.ion-ios-heart:before,.ion-ios-heart-outline:before,.ion-ios-help:before,.ion-ios-help-empty:before,.ion-ios-help-outline:before,.ion-ios-home:before,.ion-ios-home-outline:before,.ion-ios-infinite:before,.ion-ios-infinite-outline:before,.ion-ios-information:before,.ion-ios-information-empty:before,.ion-ios-information-outline:before,.ion-ios-ionic-outline:before,.ion-ios-keypad:before,.ion-ios-keypad-outline:before,.ion-ios-lightbulb:before,.ion-ios-lightbulb-outline:before,.ion-ios-list:before,.ion-ios-list-outline:before,.ion-ios-location:before,.ion-ios-location-outline:before,.ion-ios-locked:before,.ion-ios-locked-outline:before,.ion-ios-loop:before,.ion-ios-loop-strong:before,.ion-ios-medical:before,.ion-ios-medical-outline:before,.ion-ios-medkit:before,.ion-ios-medkit-outline:before,.ion-ios-mic:before,.ion-ios-mic-off:before,.ion-ios-mic-outline:before,.ion-ios-minus:before,.ion-ios-minus-empty:before,.ion-ios-minus-outline:before,.ion-ios-monitor:before,.ion-ios-monitor-outline:before,.ion-ios-moon:before,.ion-ios-moon-outline:before,.ion-ios-more:before,.ion-ios-more-outline:before,.ion-ios-musical-note:before,.ion-ios-musical-notes:before,.ion-ios-navigate:before,.ion-ios-navigate-outline:before,.ion-ios-nutrition:before,.ion-ios-nutrition-outline:before,.ion-ios-paper:before,.ion-ios-paper-outline:before,.ion-ios-paperplane:before,.ion-ios-paperplane-outline:before,.ion-ios-partlysunny:before,.ion-ios-partlysunny-outline:before,.ion-ios-pause:before,.ion-ios-pause-outline:before,.ion-ios-paw:before,.ion-ios-paw-outline:before,.ion-ios-people:before,.ion-ios-people-outline:before,.ion-ios-person:before,.ion-ios-person-outline:before,.ion-ios-personadd:before,.ion-ios-personadd-outline:before,.ion-ios-photos:before,.ion-ios-photos-outline:before,.ion-ios-pie:before,.ion-ios-pie-outline:before,.ion-ios-pint:before,.ion-ios-pint-outline:before,.ion-ios-play:before,.ion-ios-play-outline:before,.ion-ios-plus:before,.ion-ios-plus-empty:before,.ion-ios-plus-outline:before,.ion-ios-pricetag:before,.ion-ios-pricetag-outline:before,.ion-ios-pricetags:before,.ion-ios-pricetags-outline:before,.ion-ios-printer:before,.ion-ios-printer-outline:before,.ion-ios-pulse:before,.ion-ios-pulse-strong:before,.ion-ios-rainy:before,.ion-ios-rainy-outline:before,.ion-ios-recording:before,.ion-ios-recording-outline:before,.ion-ios-redo:before,.ion-ios-redo-outline:before,.ion-ios-refresh:before,.ion-ios-refresh-empty:before,.ion-ios-refresh-outline:before,.ion-ios-reload:before,.ion-ios-reverse-camera:before,.ion-ios-reverse-camera-outline:before,.ion-ios-rewind:before,.ion-ios-rewind-outline:before,.ion-ios-rose:before,.ion-ios-rose-outline:before,.ion-ios-search:before,.ion-ios-search-strong:before,.ion-ios-settings:before,.ion-ios-settings-strong:before,.ion-ios-shuffle:before,.ion-ios-shuffle-strong:before,.ion-ios-skipbackward:before,.ion-ios-skipbackward-outline:before,.ion-ios-skipforward:before,.ion-ios-skipforward-outline:before,.ion-ios-snowy:before,.ion-ios-speedometer:before,.ion-ios-speedometer-outline:before,.ion-ios-star:before,.ion-ios-star-half:before,.ion-ios-star-outline:before,.ion-ios-stopwatch:before,.ion-ios-stopwatch-outline:before,.ion-ios-sunny:before,.ion-ios-sunny-outline:before,.ion-ios-telephone:before,.ion-ios-telephone-outline:before,.ion-ios-tennisball:before,.ion-ios-tennisball-outline:before,.ion-ios-thunderstorm:before,.ion-ios-thunderstorm-outline:before,.ion-ios-time:before,.ion-ios-time-outline:before,.ion-ios-timer:before,.ion-ios-timer-outline:before,.ion-ios-toggle:before,.ion-ios-toggle-outline:before,.ion-ios-trash:before,.ion-ios-trash-outline:before,.ion-ios-undo:before,.ion-ios-undo-outline:before,.ion-ios-unlocked:before,.ion-ios-unlocked-outline:before,.ion-ios-upload:before,.ion-ios-upload-outline:before,.ion-ios-videocam:before,.ion-ios-videocam-outline:before,.ion-ios-volume-high:before,.ion-ios-volume-low:before,.ion-ios-wineglass:before,.ion-ios-wineglass-outline:before,.ion-ios-world:before,.ion-ios-world-outline:before,.ion-ipad:before,.ion-iphone:before,.ion-ipod:before,.ion-jet:before,.ion-key:before,.ion-knife:before,.ion-laptop:before,.ion-leaf:before,.ion-levels:before,.ion-lightbulb:before,.ion-link:before,.ion-load-a:before,.ion-load-b:before,.ion-load-c:before,.ion-load-d:before,.ion-location:before,.ion-lock-combination:before,.ion-locked:before,.ion-log-in:before,.ion-log-out:before,.ion-loop:before,.ion-magnet:before,.ion-male:before,.ion-man:before,.ion-map:before,.ion-medkit:before,.ion-merge:before,.ion-mic-a:before,.ion-mic-b:before,.ion-mic-c:before,.ion-minus:before,.ion-minus-circled:before,.ion-minus-round:before,.ion-model-s:before,.ion-monitor:before,.ion-more:before,.ion-mouse:before,.ion-music-note:before,.ion-navicon:before,.ion-navicon-round:before,.ion-navigate:before,.ion-network:before,.ion-no-smoking:before,.ion-nuclear:before,.ion-outlet:before,.ion-paintbrush:before,.ion-paintbucket:before,.ion-paper-airplane:before,.ion-paperclip:before,.ion-pause:before,.ion-person:before,.ion-person-add:before,.ion-person-stalker:before,.ion-pie-graph:before,.ion-pin:before,.ion-pinpoint:before,.ion-pizza:before,.ion-plane:before,.ion-planet:before,.ion-play:before,.ion-playstation:before,.ion-plus:before,.ion-plus-circled:before,.ion-plus-round:before,.ion-podium:before,.ion-pound:before,.ion-power:before,.ion-pricetag:before,.ion-pricetags:before,.ion-printer:before,.ion-pull-request:before,.ion-qr-scanner:before,.ion-quote:before,.ion-radio-waves:before,.ion-record:before,.ion-refresh:before,.ion-reply:before,.ion-reply-all:before,.ion-ribbon-a:before,.ion-ribbon-b:before,.ion-sad:before,.ion-sad-outline:before,.ion-scissors:before,.ion-search:before,.ion-settings:before,.ion-share:before,.ion-shuffle:before,.ion-skip-backward:before,.ion-skip-forward:before,.ion-social-android:before,.ion-social-android-outline:before,.ion-social-angular:before,.ion-social-angular-outline:before,.ion-social-apple:before,.ion-social-apple-outline:before,.ion-social-bitcoin:before,.ion-social-bitcoin-outline:before,.ion-social-buffer:before,.ion-social-buffer-outline:before,.ion-social-chrome:before,.ion-social-chrome-outline:before,.ion-social-codepen:before,.ion-social-codepen-outline:before,.ion-social-css3:before,.ion-social-css3-outline:before,.ion-social-designernews:before,.ion-social-designernews-outline:before,.ion-social-dribbble:before,.ion-social-dribbble-outline:before,.ion-social-dropbox:before,.ion-social-dropbox-outline:before,.ion-social-euro:before,.ion-social-euro-outline:before,.ion-social-facebook:before,.ion-social-facebook-outline:before,.ion-social-foursquare:before,.ion-social-foursquare-outline:before,.ion-social-freebsd-devil:before,.ion-social-github:before,.ion-social-github-outline:before,.ion-social-google:before,.ion-social-google-outline:before,.ion-social-googleplus:before,.ion-social-googleplus-outline:before,.ion-social-hackernews:before,.ion-social-hackernews-outline:before,.ion-social-html5:before,.ion-social-html5-outline:before,.ion-social-instagram:before,.ion-social-instagram-outline:before,.ion-social-javascript:before,.ion-social-javascript-outline:before,.ion-social-linkedin:before,.ion-social-linkedin-outline:before,.ion-social-markdown:before,.ion-social-nodejs:before,.ion-social-octocat:before,.ion-social-pinterest:before,.ion-social-pinterest-outline:before,.ion-social-python:before,.ion-social-reddit:before,.ion-social-reddit-outline:before,.ion-social-rss:before,.ion-social-rss-outline:before,.ion-social-sass:before,.ion-social-skype:before,.ion-social-skype-outline:before,.ion-social-snapchat:before,.ion-social-snapchat-outline:before,.ion-social-tumblr:before,.ion-social-tumblr-outline:before,.ion-social-tux:before,.ion-social-twitch:before,.ion-social-twitch-outline:before,.ion-social-twitter:before,.ion-social-twitter-outline:before,.ion-social-usd:before,.ion-social-usd-outline:before,.ion-social-vimeo:before,.ion-social-vimeo-outline:before,.ion-social-whatsapp:before,.ion-social-whatsapp-outline:before,.ion-social-windows:before,.ion-social-windows-outline:before,.ion-social-wordpress:before,.ion-social-wordpress-outline:before,.ion-social-yahoo:before,.ion-social-yahoo-outline:before,.ion-social-yen:before,.ion-social-yen-outline:before,.ion-social-youtube:before,.ion-social-youtube-outline:before,.ion-soup-can:before,.ion-soup-can-outline:before,.ion-speakerphone:before,.ion-speedometer:before,.ion-spoon:before,.ion-star:before,.ion-stats-bars:before,.ion-steam:before,.ion-stop:before,.ion-thermometer:before,.ion-thumbsdown:before,.ion-thumbsup:before,.ion-toggle:before,.ion-toggle-filled:before,.ion-transgender:before,.ion-trash-a:before,.ion-trash-b:before,.ion-trophy:before,.ion-tshirt:before,.ion-tshirt-outline:before,.ion-umbrella:before,.ion-university:before,.ion-unlocked:before,.ion-upload:before,.ion-usb:before,.ion-videocamera:before,.ion-volume-high:before,.ion-volume-low:before,.ion-volume-medium:before,.ion-volume-mute:before,.ion-wand:before,.ion-waterdrop:before,.ion-wifi:before,.ion-wineglass:before,.ion-woman:before,.ion-wrench:before,.ion-xbox:before{display:inline-block;font-family:"Ionicons";speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ion-alert:before{content:"\f101"}.ion-alert-circled:before{content:"\f100"}.ion-android-add:before{content:"\f2c7"}.ion-android-add-circle:before{content:"\f359"}.ion-android-alarm-clock:before{content:"\f35a"}.ion-android-alert:before{content:"\f35b"}.ion-android-apps:before{content:"\f35c"}.ion-android-archive:before{content:"\f2c9"}.ion-android-arrow-back:before{content:"\f2ca"}.ion-android-arrow-down:before{content:"\f35d"}.ion-android-arrow-dropdown:before{content:"\f35f"}.ion-android-arrow-dropdown-circle:before{content:"\f35e"}.ion-android-arrow-dropleft:before{content:"\f361"}.ion-android-arrow-dropleft-circle:before{content:"\f360"}.ion-android-arrow-dropright:before{content:"\f363"}.ion-android-arrow-dropright-circle:before{content:"\f362"}.ion-android-arrow-dropup:before{content:"\f365"}.ion-android-arrow-dropup-circle:before{content:"\f364"}.ion-android-arrow-forward:before{content:"\f30f"}.ion-android-arrow-up:before{content:"\f366"}.ion-android-attach:before{content:"\f367"}.ion-android-bar:before{content:"\f368"}.ion-android-bicycle:before{content:"\f369"}.ion-android-boat:before{content:"\f36a"}.ion-android-bookmark:before{content:"\f36b"}.ion-android-bulb:before{content:"\f36c"}.ion-android-bus:before{content:"\f36d"}.ion-android-calendar:before{content:"\f2d1"}.ion-android-call:before{content:"\f2d2"}.ion-android-camera:before{content:"\f2d3"}.ion-android-cancel:before{content:"\f36e"}.ion-android-car:before{content:"\f36f"}.ion-android-cart:before{content:"\f370"}.ion-android-chat:before{content:"\f2d4"}.ion-android-checkbox:before{content:"\f374"}.ion-android-checkbox-blank:before{content:"\f371"}.ion-android-checkbox-outline:before{content:"\f373"}.ion-android-checkbox-outline-blank:before{content:"\f372"}.ion-android-checkmark-circle:before{content:"\f375"}.ion-android-clipboard:before{content:"\f376"}.ion-android-close:before{content:"\f2d7"}.ion-android-cloud:before{content:"\f37a"}.ion-android-cloud-circle:before{content:"\f377"}.ion-android-cloud-done:before{content:"\f378"}.ion-android-cloud-outline:before{content:"\f379"}.ion-android-color-palette:before{content:"\f37b"}.ion-android-compass:before{content:"\f37c"}.ion-android-contact:before{content:"\f2d8"}.ion-android-contacts:before{content:"\f2d9"}.ion-android-contract:before{content:"\f37d"}.ion-android-create:before{content:"\f37e"}.ion-android-delete:before{content:"\f37f"}.ion-android-desktop:before{content:"\f380"}.ion-android-document:before{content:"\f381"}.ion-android-done:before{content:"\f383"}.ion-android-done-all:before{content:"\f382"}.ion-android-download:before{content:"\f2dd"}.ion-android-drafts:before{content:"\f384"}.ion-android-exit:before{content:"\f385"}.ion-android-expand:before{content:"\f386"}.ion-android-favorite:before{content:"\f388"}.ion-android-favorite-outline:before{content:"\f387"}.ion-android-film:before{content:"\f389"}.ion-android-folder:before{content:"\f2e0"}.ion-android-folder-open:before{content:"\f38a"}.ion-android-funnel:before{content:"\f38b"}.ion-android-globe:before{content:"\f38c"}.ion-android-hand:before{content:"\f2e3"}.ion-android-hangout:before{content:"\f38d"}.ion-android-happy:before{content:"\f38e"}.ion-android-home:before{content:"\f38f"}.ion-android-image:before{content:"\f2e4"}.ion-android-laptop:before{content:"\f390"}.ion-android-list:before{content:"\f391"}.ion-android-locate:before{content:"\f2e9"}.ion-android-lock:before{content:"\f392"}.ion-android-mail:before{content:"\f2eb"}.ion-android-map:before{content:"\f393"}.ion-android-menu:before{content:"\f394"}.ion-android-microphone:before{content:"\f2ec"}.ion-android-microphone-off:before{content:"\f395"}.ion-android-more-horizontal:before{content:"\f396"}.ion-android-more-vertical:before{content:"\f397"}.ion-android-navigate:before{content:"\f398"}.ion-android-notifications:before{content:"\f39b"}.ion-android-notifications-none:before{content:"\f399"}.ion-android-notifications-off:before{content:"\f39a"}.ion-android-open:before{content:"\f39c"}.ion-android-options:before{content:"\f39d"}.ion-android-people:before{content:"\f39e"}.ion-android-person:before{content:"\f3a0"}.ion-android-person-add:before{content:"\f39f"}.ion-android-phone-landscape:before{content:"\f3a1"}.ion-android-phone-portrait:before{content:"\f3a2"}.ion-android-pin:before{content:"\f3a3"}.ion-android-plane:before{content:"\f3a4"}.ion-android-playstore:before{content:"\f2f0"}.ion-android-print:before{content:"\f3a5"}.ion-android-radio-button-off:before{content:"\f3a6"}.ion-android-radio-button-on:before{content:"\f3a7"}.ion-android-refresh:before{content:"\f3a8"}.ion-android-remove:before{content:"\f2f4"}.ion-android-remove-circle:before{content:"\f3a9"}.ion-android-restaurant:before{content:"\f3aa"}.ion-android-sad:before{content:"\f3ab"}.ion-android-search:before{content:"\f2f5"}.ion-android-send:before{content:"\f2f6"}.ion-android-settings:before{content:"\f2f7"}.ion-android-share:before{content:"\f2f8"}.ion-android-share-alt:before{content:"\f3ac"}.ion-android-star:before{content:"\f2fc"}.ion-android-star-half:before{content:"\f3ad"}.ion-android-star-outline:before{content:"\f3ae"}.ion-android-stopwatch:before{content:"\f2fd"}.ion-android-subway:before{content:"\f3af"}.ion-android-sunny:before{content:"\f3b0"}.ion-android-sync:before{content:"\f3b1"}.ion-android-textsms:before{content:"\f3b2"}.ion-android-time:before{content:"\f3b3"}.ion-android-train:before{content:"\f3b4"}.ion-android-unlock:before{content:"\f3b5"}.ion-android-upload:before{content:"\f3b6"}.ion-android-volume-down:before{content:"\f3b7"}.ion-android-volume-mute:before{content:"\f3b8"}.ion-android-volume-off:before{content:"\f3b9"}.ion-android-volume-up:before{content:"\f3ba"}.ion-android-walk:before{content:"\f3bb"}.ion-android-warning:before{content:"\f3bc"}.ion-android-watch:before{content:"\f3bd"}.ion-android-wifi:before{content:"\f305"}.ion-aperture:before{content:"\f313"}.ion-archive:before{content:"\f102"}.ion-arrow-down-a:before{content:"\f103"}.ion-arrow-down-b:before{content:"\f104"}.ion-arrow-down-c:before{content:"\f105"}.ion-arrow-expand:before{content:"\f25e"}.ion-arrow-graph-down-left:before{content:"\f25f"}.ion-arrow-graph-down-right:before{content:"\f260"}.ion-arrow-graph-up-left:before{content:"\f261"}.ion-arrow-graph-up-right:before{content:"\f262"}.ion-arrow-left-a:before{content:"\f106"}.ion-arrow-left-b:before{content:"\f107"}.ion-arrow-left-c:before{content:"\f108"}.ion-arrow-move:before{content:"\f263"}.ion-arrow-resize:before{content:"\f264"}.ion-arrow-return-left:before{content:"\f265"}.ion-arrow-return-right:before{content:"\f266"}.ion-arrow-right-a:before{content:"\f109"}.ion-arrow-right-b:before{content:"\f10a"}.ion-arrow-right-c:before{content:"\f10b"}.ion-arrow-shrink:before{content:"\f267"}.ion-arrow-swap:before{content:"\f268"}.ion-arrow-up-a:before{content:"\f10c"}.ion-arrow-up-b:before{content:"\f10d"}.ion-arrow-up-c:before{content:"\f10e"}.ion-asterisk:before{content:"\f314"}.ion-at:before{content:"\f10f"}.ion-backspace:before{content:"\f3bf"}.ion-backspace-outline:before{content:"\f3be"}.ion-bag:before{content:"\f110"}.ion-battery-charging:before{content:"\f111"}.ion-battery-empty:before{content:"\f112"}.ion-battery-full:before{content:"\f113"}.ion-battery-half:before{content:"\f114"}.ion-battery-low:before{content:"\f115"}.ion-beaker:before{content:"\f269"}.ion-beer:before{content:"\f26a"}.ion-bluetooth:before{content:"\f116"}.ion-bonfire:before{content:"\f315"}.ion-bookmark:before{content:"\f26b"}.ion-bowtie:before{content:"\f3c0"}.ion-briefcase:before{content:"\f26c"}.ion-bug:before{content:"\f2be"}.ion-calculator:before{content:"\f26d"}.ion-calendar:before{content:"\f117"}.ion-camera:before{content:"\f118"}.ion-card:before{content:"\f119"}.ion-cash:before{content:"\f316"}.ion-chatbox:before{content:"\f11b"}.ion-chatbox-working:before{content:"\f11a"}.ion-chatboxes:before{content:"\f11c"}.ion-chatbubble:before{content:"\f11e"}.ion-chatbubble-working:before{content:"\f11d"}.ion-chatbubbles:before{content:"\f11f"}.ion-checkmark:before{content:"\f122"}.ion-checkmark-circled:before{content:"\f120"}.ion-checkmark-round:before{content:"\f121"}.ion-chevron-down:before{content:"\f123"}.ion-chevron-left:before{content:"\f124"}.ion-chevron-right:before{content:"\f125"}.ion-chevron-up:before{content:"\f126"}.ion-clipboard:before{content:"\f127"}.ion-clock:before{content:"\f26e"}.ion-close:before{content:"\f12a"}.ion-close-circled:before{content:"\f128"}.ion-close-round:before{content:"\f129"}.ion-closed-captioning:before{content:"\f317"}.ion-cloud:before{content:"\f12b"}.ion-code:before{content:"\f271"}.ion-code-download:before{content:"\f26f"}.ion-code-working:before{content:"\f270"}.ion-coffee:before{content:"\f272"}.ion-compass:before{content:"\f273"}.ion-compose:before{content:"\f12c"}.ion-connection-bars:before{content:"\f274"}.ion-contrast:before{content:"\f275"}.ion-crop:before{content:"\f3c1"}.ion-cube:before{content:"\f318"}.ion-disc:before{content:"\f12d"}.ion-document:before{content:"\f12f"}.ion-document-text:before{content:"\f12e"}.ion-drag:before{content:"\f130"}.ion-earth:before{content:"\f276"}.ion-easel:before{content:"\f3c2"}.ion-edit:before{content:"\f2bf"}.ion-egg:before{content:"\f277"}.ion-eject:before{content:"\f131"}.ion-email:before{content:"\f132"}.ion-email-unread:before{content:"\f3c3"}.ion-erlenmeyer-flask:before{content:"\f3c5"}.ion-erlenmeyer-flask-bubbles:before{content:"\f3c4"}.ion-eye:before{content:"\f133"}.ion-eye-disabled:before{content:"\f306"}.ion-female:before{content:"\f278"}.ion-filing:before{content:"\f134"}.ion-film-marker:before{content:"\f135"}.ion-fireball:before{content:"\f319"}.ion-flag:before{content:"\f279"}.ion-flame:before{content:"\f31a"}.ion-flash:before{content:"\f137"}.ion-flash-off:before{content:"\f136"}.ion-folder:before{content:"\f139"}.ion-fork:before{content:"\f27a"}.ion-fork-repo:before{content:"\f2c0"}.ion-forward:before{content:"\f13a"}.ion-funnel:before{content:"\f31b"}.ion-gear-a:before{content:"\f13d"}.ion-gear-b:before{content:"\f13e"}.ion-grid:before{content:"\f13f"}.ion-hammer:before{content:"\f27b"}.ion-happy:before{content:"\f31c"}.ion-happy-outline:before{content:"\f3c6"}.ion-headphone:before{content:"\f140"}.ion-heart:before{content:"\f141"}.ion-heart-broken:before{content:"\f31d"}.ion-help:before{content:"\f143"}.ion-help-buoy:before{content:"\f27c"}.ion-help-circled:before{content:"\f142"}.ion-home:before{content:"\f144"}.ion-icecream:before{content:"\f27d"}.ion-image:before{content:"\f147"}.ion-images:before{content:"\f148"}.ion-information:before{content:"\f14a"}.ion-information-circled:before{content:"\f149"}.ion-ionic:before{content:"\f14b"}.ion-ios-alarm:before{content:"\f3c8"}.ion-ios-alarm-outline:before{content:"\f3c7"}.ion-ios-albums:before{content:"\f3ca"}.ion-ios-albums-outline:before{content:"\f3c9"}.ion-ios-americanfootball:before{content:"\f3cc"}.ion-ios-americanfootball-outline:before{content:"\f3cb"}.ion-ios-analytics:before{content:"\f3ce"}.ion-ios-analytics-outline:before{content:"\f3cd"}.ion-ios-arrow-back:before{content:"\f3cf"}.ion-ios-arrow-down:before{content:"\f3d0"}.ion-ios-arrow-forward:before{content:"\f3d1"}.ion-ios-arrow-left:before{content:"\f3d2"}.ion-ios-arrow-right:before{content:"\f3d3"}.ion-ios-arrow-thin-down:before{content:"\f3d4"}.ion-ios-arrow-thin-left:before{content:"\f3d5"}.ion-ios-arrow-thin-right:before{content:"\f3d6"}.ion-ios-arrow-thin-up:before{content:"\f3d7"}.ion-ios-arrow-up:before{content:"\f3d8"}.ion-ios-at:before{content:"\f3da"}.ion-ios-at-outline:before{content:"\f3d9"}.ion-ios-barcode:before{content:"\f3dc"}.ion-ios-barcode-outline:before{content:"\f3db"}.ion-ios-baseball:before{content:"\f3de"}.ion-ios-baseball-outline:before{content:"\f3dd"}.ion-ios-basketball:before{content:"\f3e0"}.ion-ios-basketball-outline:before{content:"\f3df"}.ion-ios-bell:before{content:"\f3e2"}.ion-ios-bell-outline:before{content:"\f3e1"}.ion-ios-body:before{content:"\f3e4"}.ion-ios-body-outline:before{content:"\f3e3"}.ion-ios-bolt:before{content:"\f3e6"}.ion-ios-bolt-outline:before{content:"\f3e5"}.ion-ios-book:before{content:"\f3e8"}.ion-ios-book-outline:before{content:"\f3e7"}.ion-ios-bookmarks:before{content:"\f3ea"}.ion-ios-bookmarks-outline:before{content:"\f3e9"}.ion-ios-box:before{content:"\f3ec"}.ion-ios-box-outline:before{content:"\f3eb"}.ion-ios-briefcase:before{content:"\f3ee"}.ion-ios-briefcase-outline:before{content:"\f3ed"}.ion-ios-browsers:before{content:"\f3f0"}.ion-ios-browsers-outline:before{content:"\f3ef"}.ion-ios-calculator:before{content:"\f3f2"}.ion-ios-calculator-outline:before{content:"\f3f1"}.ion-ios-calendar:before{content:"\f3f4"}.ion-ios-calendar-outline:before{content:"\f3f3"}.ion-ios-camera:before{content:"\f3f6"}.ion-ios-camera-outline:before{content:"\f3f5"}.ion-ios-cart:before{content:"\f3f8"}.ion-ios-cart-outline:before{content:"\f3f7"}.ion-ios-chatboxes:before{content:"\f3fa"}.ion-ios-chatboxes-outline:before{content:"\f3f9"}.ion-ios-chatbubble:before{content:"\f3fc"}.ion-ios-chatbubble-outline:before{content:"\f3fb"}.ion-ios-checkmark:before{content:"\f3ff"}.ion-ios-checkmark-empty:before{content:"\f3fd"}.ion-ios-checkmark-outline:before{content:"\f3fe"}.ion-ios-circle-filled:before{content:"\f400"}.ion-ios-circle-outline:before{content:"\f401"}.ion-ios-clock:before{content:"\f403"}.ion-ios-clock-outline:before{content:"\f402"}.ion-ios-close:before{content:"\f406"}.ion-ios-close-empty:before{content:"\f404"}.ion-ios-close-outline:before{content:"\f405"}.ion-ios-cloud:before{content:"\f40c"}.ion-ios-cloud-download:before{content:"\f408"}.ion-ios-cloud-download-outline:before{content:"\f407"}.ion-ios-cloud-outline:before{content:"\f409"}.ion-ios-cloud-upload:before{content:"\f40b"}.ion-ios-cloud-upload-outline:before{content:"\f40a"}.ion-ios-cloudy:before{content:"\f410"}.ion-ios-cloudy-night:before{content:"\f40e"}.ion-ios-cloudy-night-outline:before{content:"\f40d"}.ion-ios-cloudy-outline:before{content:"\f40f"}.ion-ios-cog:before{content:"\f412"}.ion-ios-cog-outline:before{content:"\f411"}.ion-ios-color-filter:before{content:"\f414"}.ion-ios-color-filter-outline:before{content:"\f413"}.ion-ios-color-wand:before{content:"\f416"}.ion-ios-color-wand-outline:before{content:"\f415"}.ion-ios-compose:before{content:"\f418"}.ion-ios-compose-outline:before{content:"\f417"}.ion-ios-contact:before{content:"\f41a"}.ion-ios-contact-outline:before{content:"\f419"}.ion-ios-copy:before{content:"\f41c"}.ion-ios-copy-outline:before{content:"\f41b"}.ion-ios-crop:before{content:"\f41e"}.ion-ios-crop-strong:before{content:"\f41d"}.ion-ios-download:before{content:"\f420"}.ion-ios-download-outline:before{content:"\f41f"}.ion-ios-drag:before{content:"\f421"}.ion-ios-email:before{content:"\f423"}.ion-ios-email-outline:before{content:"\f422"}.ion-ios-eye:before{content:"\f425"}.ion-ios-eye-outline:before{content:"\f424"}.ion-ios-fastforward:before{content:"\f427"}.ion-ios-fastforward-outline:before{content:"\f426"}.ion-ios-filing:before{content:"\f429"}.ion-ios-filing-outline:before{content:"\f428"}.ion-ios-film:before{content:"\f42b"}.ion-ios-film-outline:before{content:"\f42a"}.ion-ios-flag:before{content:"\f42d"}.ion-ios-flag-outline:before{content:"\f42c"}.ion-ios-flame:before{content:"\f42f"}.ion-ios-flame-outline:before{content:"\f42e"}.ion-ios-flask:before{content:"\f431"}.ion-ios-flask-outline:before{content:"\f430"}.ion-ios-flower:before{content:"\f433"}.ion-ios-flower-outline:before{content:"\f432"}.ion-ios-folder:before{content:"\f435"}.ion-ios-folder-outline:before{content:"\f434"}.ion-ios-football:before{content:"\f437"}.ion-ios-football-outline:before{content:"\f436"}.ion-ios-game-controller-a:before{content:"\f439"}.ion-ios-game-controller-a-outline:before{content:"\f438"}.ion-ios-game-controller-b:before{content:"\f43b"}.ion-ios-game-controller-b-outline:before{content:"\f43a"}.ion-ios-gear:before{content:"\f43d"}.ion-ios-gear-outline:before{content:"\f43c"}.ion-ios-glasses:before{content:"\f43f"}.ion-ios-glasses-outline:before{content:"\f43e"}.ion-ios-grid-view:before{content:"\f441"}.ion-ios-grid-view-outline:before{content:"\f440"}.ion-ios-heart:before{content:"\f443"}.ion-ios-heart-outline:before{content:"\f442"}.ion-ios-help:before{content:"\f446"}.ion-ios-help-empty:before{content:"\f444"}.ion-ios-help-outline:before{content:"\f445"}.ion-ios-home:before{content:"\f448"}.ion-ios-home-outline:before{content:"\f447"}.ion-ios-infinite:before{content:"\f44a"}.ion-ios-infinite-outline:before{content:"\f449"}.ion-ios-information:before{content:"\f44d"}.ion-ios-information-empty:before{content:"\f44b"}.ion-ios-information-outline:before{content:"\f44c"}.ion-ios-ionic-outline:before{content:"\f44e"}.ion-ios-keypad:before{content:"\f450"}.ion-ios-keypad-outline:before{content:"\f44f"}.ion-ios-lightbulb:before{content:"\f452"}.ion-ios-lightbulb-outline:before{content:"\f451"}.ion-ios-list:before{content:"\f454"}.ion-ios-list-outline:before{content:"\f453"}.ion-ios-location:before{content:"\f456"}.ion-ios-location-outline:before{content:"\f455"}.ion-ios-locked:before{content:"\f458"}.ion-ios-locked-outline:before{content:"\f457"}.ion-ios-loop:before{content:"\f45a"}.ion-ios-loop-strong:before{content:"\f459"}.ion-ios-medical:before{content:"\f45c"}.ion-ios-medical-outline:before{content:"\f45b"}.ion-ios-medkit:before{content:"\f45e"}.ion-ios-medkit-outline:before{content:"\f45d"}.ion-ios-mic:before{content:"\f461"}.ion-ios-mic-off:before{content:"\f45f"}.ion-ios-mic-outline:before{content:"\f460"}.ion-ios-minus:before{content:"\f464"}.ion-ios-minus-empty:before{content:"\f462"}.ion-ios-minus-outline:before{content:"\f463"}.ion-ios-monitor:before{content:"\f466"}.ion-ios-monitor-outline:before{content:"\f465"}.ion-ios-moon:before{content:"\f468"}.ion-ios-moon-outline:before{content:"\f467"}.ion-ios-more:before{content:"\f46a"}.ion-ios-more-outline:before{content:"\f469"}.ion-ios-musical-note:before{content:"\f46b"}.ion-ios-musical-notes:before{content:"\f46c"}.ion-ios-navigate:before{content:"\f46e"}.ion-ios-navigate-outline:before{content:"\f46d"}.ion-ios-nutrition:before{content:"\f470"}.ion-ios-nutrition-outline:before{content:"\f46f"}.ion-ios-paper:before{content:"\f472"}.ion-ios-paper-outline:before{content:"\f471"}.ion-ios-paperplane:before{content:"\f474"}.ion-ios-paperplane-outline:before{content:"\f473"}.ion-ios-partlysunny:before{content:"\f476"}.ion-ios-partlysunny-outline:before{content:"\f475"}.ion-ios-pause:before{content:"\f478"}.ion-ios-pause-outline:before{content:"\f477"}.ion-ios-paw:before{content:"\f47a"}.ion-ios-paw-outline:before{content:"\f479"}.ion-ios-people:before{content:"\f47c"}.ion-ios-people-outline:before{content:"\f47b"}.ion-ios-person:before{content:"\f47e"}.ion-ios-person-outline:before{content:"\f47d"}.ion-ios-personadd:before{content:"\f480"}.ion-ios-personadd-outline:before{content:"\f47f"}.ion-ios-photos:before{content:"\f482"}.ion-ios-photos-outline:before{content:"\f481"}.ion-ios-pie:before{content:"\f484"}.ion-ios-pie-outline:before{content:"\f483"}.ion-ios-pint:before{content:"\f486"}.ion-ios-pint-outline:before{content:"\f485"}.ion-ios-play:before{content:"\f488"}.ion-ios-play-outline:before{content:"\f487"}.ion-ios-plus:before{content:"\f48b"}.ion-ios-plus-empty:before{content:"\f489"}.ion-ios-plus-outline:before{content:"\f48a"}.ion-ios-pricetag:before{content:"\f48d"}.ion-ios-pricetag-outline:before{content:"\f48c"}.ion-ios-pricetags:before{content:"\f48f"}.ion-ios-pricetags-outline:before{content:"\f48e"}.ion-ios-printer:before{content:"\f491"}.ion-ios-printer-outline:before{content:"\f490"}.ion-ios-pulse:before{content:"\f493"}.ion-ios-pulse-strong:before{content:"\f492"}.ion-ios-rainy:before{content:"\f495"}.ion-ios-rainy-outline:before{content:"\f494"}.ion-ios-recording:before{content:"\f497"}.ion-ios-recording-outline:before{content:"\f496"}.ion-ios-redo:before{content:"\f499"}.ion-ios-redo-outline:before{content:"\f498"}.ion-ios-refresh:before{content:"\f49c"}.ion-ios-refresh-empty:before{content:"\f49a"}.ion-ios-refresh-outline:before{content:"\f49b"}.ion-ios-reload:before{content:"\f49d"}.ion-ios-reverse-camera:before{content:"\f49f"}.ion-ios-reverse-camera-outline:before{content:"\f49e"}.ion-ios-rewind:before{content:"\f4a1"}.ion-ios-rewind-outline:before{content:"\f4a0"}.ion-ios-rose:before{content:"\f4a3"}.ion-ios-rose-outline:before{content:"\f4a2"}.ion-ios-search:before{content:"\f4a5"}.ion-ios-search-strong:before{content:"\f4a4"}.ion-ios-settings:before{content:"\f4a7"}.ion-ios-settings-strong:before{content:"\f4a6"}.ion-ios-shuffle:before{content:"\f4a9"}.ion-ios-shuffle-strong:before{content:"\f4a8"}.ion-ios-skipbackward:before{content:"\f4ab"}.ion-ios-skipbackward-outline:before{content:"\f4aa"}.ion-ios-skipforward:before{content:"\f4ad"}.ion-ios-skipforward-outline:before{content:"\f4ac"}.ion-ios-snowy:before{content:"\f4ae"}.ion-ios-speedometer:before{content:"\f4b0"}.ion-ios-speedometer-outline:before{content:"\f4af"}.ion-ios-star:before{content:"\f4b3"}.ion-ios-star-half:before{content:"\f4b1"}.ion-ios-star-outline:before{content:"\f4b2"}.ion-ios-stopwatch:before{content:"\f4b5"}.ion-ios-stopwatch-outline:before{content:"\f4b4"}.ion-ios-sunny:before{content:"\f4b7"}.ion-ios-sunny-outline:before{content:"\f4b6"}.ion-ios-telephone:before{content:"\f4b9"}.ion-ios-telephone-outline:before{content:"\f4b8"}.ion-ios-tennisball:before{content:"\f4bb"}.ion-ios-tennisball-outline:before{content:"\f4ba"}.ion-ios-thunderstorm:before{content:"\f4bd"}.ion-ios-thunderstorm-outline:before{content:"\f4bc"}.ion-ios-time:before{content:"\f4bf"}.ion-ios-time-outline:before{content:"\f4be"}.ion-ios-timer:before{content:"\f4c1"}.ion-ios-timer-outline:before{content:"\f4c0"}.ion-ios-toggle:before{content:"\f4c3"}.ion-ios-toggle-outline:before{content:"\f4c2"}.ion-ios-trash:before{content:"\f4c5"}.ion-ios-trash-outline:before{content:"\f4c4"}.ion-ios-undo:before{content:"\f4c7"}.ion-ios-undo-outline:before{content:"\f4c6"}.ion-ios-unlocked:before{content:"\f4c9"}.ion-ios-unlocked-outline:before{content:"\f4c8"}.ion-ios-upload:before{content:"\f4cb"}.ion-ios-upload-outline:before{content:"\f4ca"}.ion-ios-videocam:before{content:"\f4cd"}.ion-ios-videocam-outline:before{content:"\f4cc"}.ion-ios-volume-high:before{content:"\f4ce"}.ion-ios-volume-low:before{content:"\f4cf"}.ion-ios-wineglass:before{content:"\f4d1"}.ion-ios-wineglass-outline:before{content:"\f4d0"}.ion-ios-world:before{content:"\f4d3"}.ion-ios-world-outline:before{content:"\f4d2"}.ion-ipad:before{content:"\f1f9"}.ion-iphone:before{content:"\f1fa"}.ion-ipod:before{content:"\f1fb"}.ion-jet:before{content:"\f295"}.ion-key:before{content:"\f296"}.ion-knife:before{content:"\f297"}.ion-laptop:before{content:"\f1fc"}.ion-leaf:before{content:"\f1fd"}.ion-levels:before{content:"\f298"}.ion-lightbulb:before{content:"\f299"}.ion-link:before{content:"\f1fe"}.ion-load-a:before{content:"\f29a"}.ion-load-b:before{content:"\f29b"}.ion-load-c:before{content:"\f29c"}.ion-load-d:before{content:"\f29d"}.ion-location:before{content:"\f1ff"}.ion-lock-combination:before{content:"\f4d4"}.ion-locked:before{content:"\f200"}.ion-log-in:before{content:"\f29e"}.ion-log-out:before{content:"\f29f"}.ion-loop:before{content:"\f201"}.ion-magnet:before{content:"\f2a0"}.ion-male:before{content:"\f2a1"}.ion-man:before{content:"\f202"}.ion-map:before{content:"\f203"}.ion-medkit:before{content:"\f2a2"}.ion-merge:before{content:"\f33f"}.ion-mic-a:before{content:"\f204"}.ion-mic-b:before{content:"\f205"}.ion-mic-c:before{content:"\f206"}.ion-minus:before{content:"\f209"}.ion-minus-circled:before{content:"\f207"}.ion-minus-round:before{content:"\f208"}.ion-model-s:before{content:"\f2c1"}.ion-monitor:before{content:"\f20a"}.ion-more:before{content:"\f20b"}.ion-mouse:before{content:"\f340"}.ion-music-note:before{content:"\f20c"}.ion-navicon:before{content:"\f20e"}.ion-navicon-round:before{content:"\f20d"}.ion-navigate:before{content:"\f2a3"}.ion-network:before{content:"\f341"}.ion-no-smoking:before{content:"\f2c2"}.ion-nuclear:before{content:"\f2a4"}.ion-outlet:before{content:"\f342"}.ion-paintbrush:before{content:"\f4d5"}.ion-paintbucket:before{content:"\f4d6"}.ion-paper-airplane:before{content:"\f2c3"}.ion-paperclip:before{content:"\f20f"}.ion-pause:before{content:"\f210"}.ion-person:before{content:"\f213"}.ion-person-add:before{content:"\f211"}.ion-person-stalker:before{content:"\f212"}.ion-pie-graph:before{content:"\f2a5"}.ion-pin:before{content:"\f2a6"}.ion-pinpoint:before{content:"\f2a7"}.ion-pizza:before{content:"\f2a8"}.ion-plane:before{content:"\f214"}.ion-planet:before{content:"\f343"}.ion-play:before{content:"\f215"}.ion-playstation:before{content:"\f30a"}.ion-plus:before{content:"\f218"}.ion-plus-circled:before{content:"\f216"}.ion-plus-round:before{content:"\f217"}.ion-podium:before{content:"\f344"}.ion-pound:before{content:"\f219"}.ion-power:before{content:"\f2a9"}.ion-pricetag:before{content:"\f2aa"}.ion-pricetags:before{content:"\f2ab"}.ion-printer:before{content:"\f21a"}.ion-pull-request:before{content:"\f345"}.ion-qr-scanner:before{content:"\f346"}.ion-quote:before{content:"\f347"}.ion-radio-waves:before{content:"\f2ac"}.ion-record:before{content:"\f21b"}.ion-refresh:before{content:"\f21c"}.ion-reply:before{content:"\f21e"}.ion-reply-all:before{content:"\f21d"}.ion-ribbon-a:before{content:"\f348"}.ion-ribbon-b:before{content:"\f349"}.ion-sad:before{content:"\f34a"}.ion-sad-outline:before{content:"\f4d7"}.ion-scissors:before{content:"\f34b"}.ion-search:before{content:"\f21f"}.ion-settings:before{content:"\f2ad"}.ion-share:before{content:"\f220"}.ion-shuffle:before{content:"\f221"}.ion-skip-backward:before{content:"\f222"}.ion-skip-forward:before{content:"\f223"}.ion-social-android:before{content:"\f225"}.ion-social-android-outline:before{content:"\f224"}.ion-social-angular:before{content:"\f4d9"}.ion-social-angular-outline:before{content:"\f4d8"}.ion-social-apple:before{content:"\f227"}.ion-social-apple-outline:before{content:"\f226"}.ion-social-bitcoin:before{content:"\f2af"}.ion-social-bitcoin-outline:before{content:"\f2ae"}.ion-social-buffer:before{content:"\f229"}.ion-social-buffer-outline:before{content:"\f228"}.ion-social-chrome:before{content:"\f4db"}.ion-social-chrome-outline:before{content:"\f4da"}.ion-social-codepen:before{content:"\f4dd"}.ion-social-codepen-outline:before{content:"\f4dc"}.ion-social-css3:before{content:"\f4df"}.ion-social-css3-outline:before{content:"\f4de"}.ion-social-designernews:before{content:"\f22b"}.ion-social-designernews-outline:before{content:"\f22a"}.ion-social-dribbble:before{content:"\f22d"}.ion-social-dribbble-outline:before{content:"\f22c"}.ion-social-dropbox:before{content:"\f22f"}.ion-social-dropbox-outline:before{content:"\f22e"}.ion-social-euro:before{content:"\f4e1"}.ion-social-euro-outline:before{content:"\f4e0"}.ion-social-facebook:before{content:"\f231"}.ion-social-facebook-outline:before{content:"\f230"}.ion-social-foursquare:before{content:"\f34d"}.ion-social-foursquare-outline:before{content:"\f34c"}.ion-social-freebsd-devil:before{content:"\f2c4"}.ion-social-github:before{content:"\f233"}.ion-social-github-outline:before{content:"\f232"}.ion-social-google:before{content:"\f34f"}.ion-social-google-outline:before{content:"\f34e"}.ion-social-googleplus:before{content:"\f235"}.ion-social-googleplus-outline:before{content:"\f234"}.ion-social-hackernews:before{content:"\f237"}.ion-social-hackernews-outline:before{content:"\f236"}.ion-social-html5:before{content:"\f4e3"}.ion-social-html5-outline:before{content:"\f4e2"}.ion-social-instagram:before{content:"\f351"}.ion-social-instagram-outline:before{content:"\f350"}.ion-social-javascript:before{content:"\f4e5"}.ion-social-javascript-outline:before{content:"\f4e4"}.ion-social-linkedin:before{content:"\f239"}.ion-social-linkedin-outline:before{content:"\f238"}.ion-social-markdown:before{content:"\f4e6"}.ion-social-nodejs:before{content:"\f4e7"}.ion-social-octocat:before{content:"\f4e8"}.ion-social-pinterest:before{content:"\f2b1"}.ion-social-pinterest-outline:before{content:"\f2b0"}.ion-social-python:before{content:"\f4e9"}.ion-social-reddit:before{content:"\f23b"}.ion-social-reddit-outline:before{content:"\f23a"}.ion-social-rss:before{content:"\f23d"}.ion-social-rss-outline:before{content:"\f23c"}.ion-social-sass:before{content:"\f4ea"}.ion-social-skype:before{content:"\f23f"}.ion-social-skype-outline:before{content:"\f23e"}.ion-social-snapchat:before{content:"\f4ec"}.ion-social-snapchat-outline:before{content:"\f4eb"}.ion-social-tumblr:before{content:"\f241"}.ion-social-tumblr-outline:before{content:"\f240"}.ion-social-tux:before{content:"\f2c5"}.ion-social-twitch:before{content:"\f4ee"}.ion-social-twitch-outline:before{content:"\f4ed"}.ion-social-twitter:before{content:"\f243"}.ion-social-twitter-outline:before{content:"\f242"}.ion-social-usd:before{content:"\f353"}.ion-social-usd-outline:before{content:"\f352"}.ion-social-vimeo:before{content:"\f245"}.ion-social-vimeo-outline:before{content:"\f244"}.ion-social-whatsapp:before{content:"\f4f0"}.ion-social-whatsapp-outline:before{content:"\f4ef"}.ion-social-windows:before{content:"\f247"}.ion-social-windows-outline:before{content:"\f246"}.ion-social-wordpress:before{content:"\f249"}.ion-social-wordpress-outline:before{content:"\f248"}.ion-social-yahoo:before{content:"\f24b"}.ion-social-yahoo-outline:before{content:"\f24a"}.ion-social-yen:before{content:"\f4f2"}.ion-social-yen-outline:before{content:"\f4f1"}.ion-social-youtube:before{content:"\f24d"}.ion-social-youtube-outline:before{content:"\f24c"}.ion-soup-can:before{content:"\f4f4"}.ion-soup-can-outline:before{content:"\f4f3"}.ion-speakerphone:before{content:"\f2b2"}.ion-speedometer:before{content:"\f2b3"}.ion-spoon:before{content:"\f2b4"}.ion-star:before{content:"\f24e"}.ion-stats-bars:before{content:"\f2b5"}.ion-steam:before{content:"\f30b"}.ion-stop:before{content:"\f24f"}.ion-thermometer:before{content:"\f2b6"}.ion-thumbsdown:before{content:"\f250"}.ion-thumbsup:before{content:"\f251"}.ion-toggle:before{content:"\f355"}.ion-toggle-filled:before{content:"\f354"}.ion-transgender:before{content:"\f4f5"}.ion-trash-a:before{content:"\f252"}.ion-trash-b:before{content:"\f253"}.ion-trophy:before{content:"\f356"}.ion-tshirt:before{content:"\f4f7"}.ion-tshirt-outline:before{content:"\f4f6"}.ion-umbrella:before{content:"\f2b7"}.ion-university:before{content:"\f357"}.ion-unlocked:before{content:"\f254"}.ion-upload:before{content:"\f255"}.ion-usb:before{content:"\f2b8"}.ion-videocamera:before{content:"\f256"}.ion-volume-high:before{content:"\f257"}.ion-volume-low:before{content:"\f258"}.ion-volume-medium:before{content:"\f259"}.ion-volume-mute:before{content:"\f25a"}.ion-wand:before{content:"\f358"}.ion-waterdrop:before{content:"\f25b"}.ion-wifi:before{content:"\f25c"}.ion-wineglass:before{content:"\f2b9"}.ion-woman:before{content:"\f25d"}.ion-wrench:before{content:"\f2ba"}.ion-xbox:before{content:"\f30c"}\r
--- /dev/null
+/*loading ¶¯»*/\r
+.loading {\r
+ width: 100%;\r
+ height: 100%;\r
+ position: fixed;\r
+ top:0;\r
+ left:0;\r
+ z-index: 999999;\r
+ background-color: rgba(0, 0, 0, 0);\r
+}\r
+.loading .title {\r
+ width: 300px;\r
+ text-align: center;\r
+ margin: 250px auto 0px;\r
+ color: #2F7095;\r
+ font-weight: 900;\r
+ font-size: 24px;\r
+}\r
+.loading .rectbox {\r
+ width: 150px;\r
+ height: 40px;\r
+ margin: 10px auto;\r
+}\r
+.loading .rectbox .title {\r
+ font-size: 14px;\r
+ font-family: 'Microsoft YaHei';\r
+ font-weight: 900;\r
+ text-align: center;\r
+ color: rgba(68, 149, 57, 1);\r
+}\r
+.loading .rectbox .rect {\r
+ width: 25px;\r
+ height: 25px;\r
+ background-color: rgba(68, 149, 57, 1);\r
+ margin: 0 2px auto 3px;\r
+ float: left;\r
+ -webkit-animation: loading 0.48s infinite ease-in-out;\r
+ -o-animation: loading 0.48s infinite ease-in-out;\r
+ animation: loading 0.48s infinite ease-in-out;\r
+}\r
+.loading .rectbox .rect1 {\r
+ -webkit-animation-delay: 0s;\r
+ -moz-animation-delay: 0s;\r
+ -o-animation-delay: 0s;\r
+ animation-delay: 0s;\r
+}\r
+.loading .rectbox .rect2 {\r
+ -webkit-animation-delay: 0.12s;\r
+ -moz-animation-delay: 0.12s;\r
+ -o-animation-delay: 0.12s;\r
+ animation-delay: 0.12s;\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+}\r
+.loading .rectbox .rect3 {\r
+ -webkit-animation-delay: 0.24s;\r
+ -moz-animation-delay: 0.24s;\r
+ -o-animation-delay: 0.24s;\r
+ animation-delay: 0.24s;\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+}\r
+.loading .rectbox .rect4 {\r
+ -webkit-animation-delay: 0.36s;\r
+ -moz-animation-delay: 0.36s;\r
+ -o-animation-delay: 0.36s;\r
+ animation-delay: 0.36s;\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+}\r
+.loading .rectbox .rect5 {\r
+ -webkit-animation-delay: 0.48s;\r
+ -moz-animation-delay: 0.48s;\r
+ -o-animation-delay: 0.48s;\r
+ animation-delay: 0.48s;\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+}\r
+@keyframes loading {\r
+ 0% {\r
+ background-color: rgba(68, 149, 57, 1);\r
+ }\r
+ 25% {\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+ }\r
+ 50% {\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+ }\r
+ 75% {\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+ }\r
+ 100% {\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+ }\r
+}\r
+@-moz-keyframes loading {\r
+ 0% {\r
+ background-color: rgba(68, 149, 57, 1);\r
+ }\r
+ 25% {\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+ }\r
+ 50% {\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+ }\r
+ 75% {\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+ }\r
+ 100% {\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+ }\r
+}\r
+@-ms-keyframes loading {\r
+ 0% {\r
+ background-color: rgba(68, 149, 57, 1);\r
+ }\r
+ 25% {\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+ }\r
+ 50% {\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+ }\r
+ 75% {\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+ }\r
+ 100% {\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+ }\r
+}\r
+@-webkit-keyframes loading {\r
+ 0% {\r
+ background-color: rgba(68, 149, 57, 1);\r
+ }\r
+ 25% {\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+ }\r
+ 50% {\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+ }\r
+ 75% {\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+ }\r
+ 100% {\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+ }\r
+}\r
+\r
+/*vtoy server is running*/\r
+#vtoy-main .loading {\r
+ width: 100%;\r
+ position: relative;\r
+ top:0;\r
+ left:0;\r
+ background-color: rgba(0, 0, 0, 0);\r
+}\r
+#vtoy-main .loading .title {\r
+ width: 300px;\r
+ text-align: center;\r
+ margin: 250px auto 0px;\r
+ color: #449539;\r
+ font-weight: 900;\r
+ font-size: 24px;\r
+}\r
+#vtoy-main .loading .rectbox {\r
+ width: 120px;\r
+ height: 40px;\r
+ margin: 10px auto;\r
+}\r
+#vtoy-main .loading .rectbox .title {\r
+ font-size: 14px;\r
+ font-family: 'Microsoft YaHei';\r
+ font-weight: 900;\r
+ text-align: center;\r
+ color: rgba(68, 149, 57, 1);\r
+}\r
+#vtoy-main .loading .rectbox .rect {\r
+ width: 25px;\r
+ height: 25px;\r
+ background-color: rgba(68, 149, 57, 1);\r
+ margin: 0 2px auto 3px;\r
+ float: left;\r
+ -webkit-animation: loading 1.44s infinite ease-in-out;\r
+ -o-animation: loading 0.48s infinite ease-in-out;\r
+ animation: loading 0.48s infinite ease-in-out;\r
+}\r
+#vtoy-main .loading .rectbox .rect1 {\r
+ -webkit-animation-delay: 0s;\r
+ -moz-animation-delay: 0s;\r
+ -o-animation-delay: 0s;\r
+ animation-delay: 0s;\r
+}\r
+#vtoy-main .loading .rectbox .rect2 {\r
+ -webkit-animation-delay: 0.36s;\r
+ -moz-animation-delay: 0.12s;\r
+ -o-animation-delay: 0.12s;\r
+ animation-delay: 0.12s;\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+}\r
+#vtoy-main .loading .rectbox .rect3 {\r
+ -webkit-animation-delay: 0.72s;\r
+ -moz-animation-delay: 0.24s;\r
+ -o-animation-delay: 0.24s;\r
+ animation-delay: 0.24s;\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+}\r
+#vtoy-main .loading .rectbox .rect4 {\r
+ -webkit-animation-delay: 1.08s;\r
+ -moz-animation-delay: 0.36s;\r
+ -o-animation-delay: 0.36s;\r
+ animation-delay: 0.36s;\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+}\r
+#vtoy-main .loading .rectbox .rect5 {\r
+ -webkit-animation-delay: 1.44s;\r
+ -moz-animation-delay: 0.48s;\r
+ -o-animation-delay: 0.48s;\r
+ animation-delay: 0.48s;\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+}\r
+@keyframes running {\r
+ 0% {\r
+ background-color: rgba(68, 149, 57, 1);\r
+ }\r
+ 25% {\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+ }\r
+ 50% {\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+ }\r
+ 75% {\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+ }\r
+ 100% {\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+ }\r
+}\r
+@-moz-keyframes running {\r
+ 0% {\r
+ background-color: rgba(68, 149, 57, 1);\r
+ }\r
+ 25% {\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+ }\r
+ 50% {\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+ }\r
+ 75% {\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+ }\r
+ 100% {\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+ }\r
+}\r
+@-ms-keyframes running {\r
+ 0% {\r
+ background-color: rgba(68, 149, 57, 1);\r
+ }\r
+ 25% {\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+ }\r
+ 50% {\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+ }\r
+ 75% {\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+ }\r
+ 100% {\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+ }\r
+}\r
+@-webkit-keyframes running {\r
+ 0% {\r
+ background-color: rgba(68, 149, 57, 1);\r
+ }\r
+ 25% {\r
+ background-color: rgba(68, 149, 57, 0.8);\r
+ }\r
+ 50% {\r
+ background-color: rgba(68, 149, 57, 0.6);\r
+ }\r
+ 75% {\r
+ background-color: rgba(68, 149, 57, 0.4);\r
+ }\r
+ 100% {\r
+ background-color: rgba(68, 149, 57, 0.2);\r
+ }\r
+}\r
+\r
+\r
+\r
+.loadEffect{\r
+ width: 110px;\r
+ height: 110px;\r
+ position: relative;\r
+ margin: 0 auto;\r
+ margin-top:0 auto;\r
+}\r
+.loadEffect span{\r
+ display: inline-block;\r
+ width: 20px;\r
+ height: 20px;\r
+ border-radius: 50%;\r
+ background: lightgreen;\r
+ position: absolute;\r
+ -webkit-animation: load 1.04s ease infinite;\r
+}\r
+@-webkit-keyframes load{\r
+ 0%{\r
+ opacity: 1;\r
+ }\r
+ 100%{\r
+ opacity: 0.2;\r
+ }\r
+}\r
+\r
+\r
+.td_ctrl_col{\r
+ width: 15%;\r
+ font-weight:bold;\r
+}\r
+\r
+.loadEffect span:nth-child(1){\r
+ left: 40%;\r
+ top: -130%;\r
+ -webkit-animation-delay:0.13s;\r
+}\r
+.loadEffect span:nth-child(2){\r
+ left: 90%;\r
+ top: 8%;\r
+ margin-top:-120%;\r
+ -webkit-animation-delay:0.26s;\r
+}\r
+.loadEffect span:nth-child(3){\r
+ left: 110%;\r
+ top: -80%;\r
+ margin-left: %-100;\r
+ -webkit-animation-delay:0.39s;\r
+}\r
+.loadEffect span:nth-child(4){\r
+ top: -40%;\r
+ left:110%;\r
+ -webkit-animation-delay:0.52s;\r
+}\r
+.loadEffect span:nth-child(5){\r
+ left: 40%;\r
+ top: 0;\r
+ margin-top:10%;\r
+ -webkit-animation-delay:0.65s;\r
+}\r
+.loadEffect span:nth-child(6){\r
+ left: -20%;\r
+ bottom:120%;\r
+ -webkit-animation-delay:0.78s;\r
+}\r
+.loadEffect span:nth-child(7){\r
+ bottom: 160%;\r
+ left: -20%;\r
+ -webkit-animation-delay:0.91s;\r
+}\r
+.loadEffect span:nth-child(8){\r
+ bottom: 200%;\r
+ left: -10%;\r
+ -webkit-animation-delay:1.04s;\r
+}\r
--- /dev/null
+div.dataTables_length label {
+ font-weight: normal;
+ text-align: left;
+ white-space: nowrap;
+}
+
+div.dataTables_length select {
+ width: 75px;
+ display: inline-block;
+}
+
+div.dataTables_filter {
+ text-align: right;
+}
+
+div.dataTables_filter label {
+ font-weight: normal;
+ white-space: nowrap;
+ text-align: left;
+}
+
+div.dataTables_filter input {
+ margin-left: 0.5em;
+ display: inline-block;
+ width: auto;
+}
+
+div.dataTables_info {
+ padding-top: 8px;
+ white-space: nowrap;
+}
+
+div.dataTables_paginate {
+ margin: 0;
+ white-space: nowrap;
+ text-align: right;
+}
+
+div.dataTables_paginate ul.pagination {
+ margin: 2px 0;
+ white-space: nowrap;
+}
+
+@media screen and (max-width: 767px) {
+ div.dataTables_wrapper > div.row > div,
+ div.dataTables_length,
+ div.dataTables_filter,
+ div.dataTables_info,
+ div.dataTables_paginate {
+ text-align: center;
+ }
+
+ div.DTTT {
+ margin-bottom: 0.5em;
+ }
+}
+
+
+table.dataTable td,
+table.dataTable th {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+
+table.dataTable {
+ clear: both;
+ margin-top: 6px !important;
+ margin-bottom: 6px !important;
+ max-width: none !important;
+}
+
+table.dataTable thead .sorting,
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc,
+table.dataTable thead .sorting_asc_disabled,
+table.dataTable thead .sorting_desc_disabled {
+ cursor: pointer;
+ position: relative;
+}
+
+table.dataTable thead .sorting:after,
+table.dataTable thead .sorting_asc:after,
+table.dataTable thead .sorting_desc:after {
+ position: absolute;
+ top: 8px;
+ right: 8px;
+ display: block;
+ font-family: 'Glyphicons Halflings';
+ opacity: 0.5;
+}
+table.dataTable thead .sorting:after {
+ opacity: 0.2;
+ content: "\e150"; /* sort */
+}
+table.dataTable thead .sorting_asc:after {
+ content: "\e155"; /* sort-by-attributes */
+}
+table.dataTable thead .sorting_desc:after {
+ content: "\e156"; /* sort-by-attributes-alt */
+}
+div.dataTables_scrollBody table.dataTable thead .sorting:after,
+div.dataTables_scrollBody table.dataTable thead .sorting_asc:after,
+div.dataTables_scrollBody table.dataTable thead .sorting_desc:after {
+ display: none;
+}
+
+table.dataTable thead .sorting_asc_disabled:after,
+table.dataTable thead .sorting_desc_disabled:after {
+ color: #eee;
+}
+
+table.dataTable thead > tr > th {
+ padding-right: 30px;
+}
+
+table.dataTable th:active {
+ outline: none;
+}
+
+
+/* Condensed */
+table.dataTable.table-condensed thead > tr > th {
+ padding-right: 20px;
+}
+
+table.dataTable.table-condensed thead .sorting:after,
+table.dataTable.table-condensed thead .sorting_asc:after,
+table.dataTable.table-condensed thead .sorting_desc:after {
+ top: 6px;
+ right: 6px;
+}
+
+/* Scrolling */
+div.dataTables_scrollHead table {
+ margin-bottom: 0 !important;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+div.dataTables_scrollHead table thead tr:last-child th:first-child,
+div.dataTables_scrollHead table thead tr:last-child td:first-child {
+ border-bottom-left-radius: 0 !important;
+ border-bottom-right-radius: 0 !important;
+}
+
+div.dataTables_scrollBody table {
+ border-top: none;
+ margin-top: 0 !important;
+ margin-bottom: 0 !important;
+}
+
+div.dataTables_scrollBody tbody tr:first-child th,
+div.dataTables_scrollBody tbody tr:first-child td {
+ border-top: none;
+}
+
+div.dataTables_scrollFoot table {
+ margin-top: 0 !important;
+ border-top: none;
+}
+
+/* Frustratingly the border-collapse:collapse used by Bootstrap makes the column
+ width calculations when using scrolling impossible to align columns. We have
+ to use separate
+ */
+table.table-bordered.dataTable {
+ border-collapse: separate !important;
+}
+table.table-bordered thead th,
+table.table-bordered thead td {
+ border-left-width: 0;
+ border-top-width: 0;
+}
+table.table-bordered tbody th,
+table.table-bordered tbody td {
+ border-left-width: 0;
+ border-bottom-width: 0;
+}
+table.table-bordered tfoot th,
+table.table-bordered tfoot td {
+ border-left-width: 0;
+ border-bottom-width: 0;
+}
+table.table-bordered th:last-child,
+table.table-bordered td:last-child {
+ border-right-width: 0;
+}
+div.dataTables_scrollHead table.table-bordered {
+ border-bottom-width: 0;
+}
+
+
+
+
+/*
+ * TableTools styles
+ */
+.table.dataTable tbody tr.active td,
+.table.dataTable tbody tr.active th {
+ background-color: #08C;
+ color: white;
+}
+
+.table.dataTable tbody tr.active:hover td,
+.table.dataTable tbody tr.active:hover th {
+ background-color: #0075b0 !important;
+}
+
+.table.dataTable tbody tr.active th > a,
+.table.dataTable tbody tr.active td > a {
+ color: white;
+}
+
+.table-striped.dataTable tbody tr.active:nth-child(odd) td,
+.table-striped.dataTable tbody tr.active:nth-child(odd) th {
+ background-color: #017ebc;
+}
+
+table.DTTT_selectable tbody tr {
+ cursor: pointer;
+}
+
+div.DTTT .btn:hover {
+ text-decoration: none !important;
+}
+
+ul.DTTT_dropdown.dropdown-menu {
+ z-index: 2003;
+}
+
+ul.DTTT_dropdown.dropdown-menu a {
+ color: #333 !important; /* needed only when demo_page.css is included */
+}
+
+ul.DTTT_dropdown.dropdown-menu li {
+ position: relative;
+}
+
+ul.DTTT_dropdown.dropdown-menu li:hover a {
+ background-color: #0088cc;
+ color: white !important;
+}
+
+div.DTTT_collection_background {
+ z-index: 2002;
+}
+
+/* TableTools information display */
+div.DTTT_print_info {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: 400px;
+ height: 150px;
+ margin-left: -200px;
+ margin-top: -75px;
+ text-align: center;
+ color: #333;
+ padding: 10px 30px;
+ opacity: 0.95;
+
+ background-color: white;
+ border: 1px solid rgba(0, 0, 0, 0.2);
+ border-radius: 6px;
+
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.5);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.5);
+}
+
+div.DTTT_print_info h6 {
+ font-weight: normal;
+ font-size: 28px;
+ line-height: 28px;
+ margin: 1em;
+}
+
+div.DTTT_print_info p {
+ font-size: 14px;
+ line-height: 20px;
+}
+
+div.dataTables_processing {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 100%;
+ height: 60px;
+ margin-left: -50%;
+ margin-top: -25px;
+ padding-top: 20px;
+ padding-bottom: 20px;
+ text-align: center;
+ font-size: 1.2em;
+ background-color: white;
+ background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));
+ background: -webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+ background: -moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+ background: -ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+ background: -o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+ background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
+}
+
+
+
+/*
+ * FixedColumns styles
+ */
+div.DTFC_LeftHeadWrapper table,
+div.DTFC_LeftFootWrapper table,
+div.DTFC_RightHeadWrapper table,
+div.DTFC_RightFootWrapper table,
+table.DTFC_Cloned tr.even {
+ background-color: white;
+ margin-bottom: 0;
+}
+
+div.DTFC_RightHeadWrapper table ,
+div.DTFC_LeftHeadWrapper table {
+ border-bottom: none !important;
+ margin-bottom: 0 !important;
+ border-top-right-radius: 0 !important;
+ border-bottom-left-radius: 0 !important;
+ border-bottom-right-radius: 0 !important;
+}
+
+div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,
+div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,
+div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,
+div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {
+ border-bottom-left-radius: 0 !important;
+ border-bottom-right-radius: 0 !important;
+}
+
+div.DTFC_RightBodyWrapper table,
+div.DTFC_LeftBodyWrapper table {
+ border-top: none;
+ margin: 0 !important;
+}
+
+div.DTFC_RightBodyWrapper tbody tr:first-child th,
+div.DTFC_RightBodyWrapper tbody tr:first-child td,
+div.DTFC_LeftBodyWrapper tbody tr:first-child th,
+div.DTFC_LeftBodyWrapper tbody tr:first-child td {
+ border-top: none;
+}
+
+div.DTFC_RightFootWrapper table,
+div.DTFC_LeftFootWrapper table {
+ border-top: none;
+ margin-top: 0 !important;
+}
+
+
+div.DTFC_LeftBodyWrapper table.dataTable thead .sorting:after,
+div.DTFC_LeftBodyWrapper table.dataTable thead .sorting_asc:after,
+div.DTFC_LeftBodyWrapper table.dataTable thead .sorting_desc:after,
+div.DTFC_RightBodyWrapper table.dataTable thead .sorting:after,
+div.DTFC_RightBodyWrapper table.dataTable thead .sorting_asc:after,
+div.DTFC_RightBodyWrapper table.dataTable thead .sorting_desc:after {
+ display: none;
+}
+
+
+/*
+ * FixedHeader styles
+ */
+div.FixedHeader_Cloned table {
+ margin: 0 !important
+}
+
--- /dev/null
+/*!
+ DataTables Bootstrap 3 integration
+ ©2011-2014 SpryMedia Ltd - datatables.net/license
+*/
+(function(l,q){var e=function(b,c){b.extend(!0,c.defaults,{dom:"<'row'<'col-sm-6'l><'col-sm-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-5'i><'col-sm-7'p>>",renderer:"bootstrap"});b.extend(c.ext.classes,{sWrapper:"dataTables_wrapper form-inline dt-bootstrap",sFilterInput:"form-control input-sm",sLengthSelect:"form-control input-sm"});c.ext.renderer.pageButton.bootstrap=function(g,e,r,s,i,m){var t=new c.Api(g),u=g.oClasses,j=g.oLanguage.oPaginate,d,f,n=0,p=function(c,e){var k,h,o,a,l=function(a){a.preventDefault();
+b(a.currentTarget).hasClass("disabled")||t.page(a.data.action).draw(!1)};k=0;for(h=e.length;k<h;k++)if(a=e[k],b.isArray(a))p(c,a);else{f=d="";switch(a){case "ellipsis":d="…";f="disabled";break;case "first":d=j.sFirst;f=a+(0<i?"":" disabled");break;case "previous":d=j.sPrevious;f=a+(0<i?"":" disabled");break;case "next":d=j.sNext;f=a+(i<m-1?"":" disabled");break;case "last":d=j.sLast;f=a+(i<m-1?"":" disabled");break;default:d=a+1,f=i===a?"active":""}d&&(o=b("<li>",{"class":u.sPageButton+" "+
+f,id:0===r&&"string"===typeof a?g.sTableId+"_"+a:null}).append(b("<a>",{href:"#","aria-controls":g.sTableId,"data-dt-idx":n,tabindex:g.iTabIndex}).html(d)).appendTo(c),g.oApi._fnBindAction(o,{action:a},l),n++)}},h;try{h=b(q.activeElement).data("dt-idx")}catch(l){}p(b(e).empty().html('<ul class="pagination"/>').children("ul"),s);h&&b(e).find("[data-dt-idx="+h+"]").focus()};c.TableTools&&(b.extend(!0,c.TableTools.classes,{container:"DTTT btn-group",buttons:{normal:"btn btn-default",disabled:"disabled"},
+collection:{container:"DTTT_dropdown dropdown-menu",buttons:{normal:"",disabled:"disabled"}},print:{info:"DTTT_print_info"},select:{row:"active"}}),b.extend(!0,c.TableTools.DEFAULTS.oTags,{collection:{container:"ul",button:"li",liner:"a"}}))};"function"===typeof define&&define.amd?define(["jquery","datatables"],e):"object"===typeof exports?e(require("jquery"),require("datatables")):jQuery&&e(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+div.AutoFill_filler{display:none;position:absolute;height:14px;width:14px;background:url(../images/filler.png) no-repeat center center;z-index:1002}div.AutoFill_border{display:none;position:absolute;background-color:#0063dc;z-index:1001;box-shadow:0px 0px 5px #76b4ff;-moz-box-shadow:0px 0px 5px #76b4ff;-webkit-box-shadow:0px 0px 5px #76b4ff}
--- /dev/null
+/*!
+ AutoFill 1.2.1
+ ©2008-2014 SpryMedia Ltd - datatables.net/license
+*/
+(function(o,j,m){var l=function(c,k){var h=function(d,b){if(!(this instanceof h))throw"Warning: AutoFill must be initialised with the keyword 'new'";if(!c.fn.dataTableExt.fnVersionCheck("1.7.0"))throw"Warning: AutoFill requires DataTables 1.7 or greater";this.c={};this.s={filler:{height:0,width:0},border:{width:2},drag:{startX:-1,startY:-1,startTd:null,endTd:null,dragging:!1},screen:{interval:null,y:0,height:0,scrollTop:0},scroller:{top:0,bottom:0},columns:[]};this.dom={table:null,filler:null,borderTop:null,
+borderRight:null,borderBottom:null,borderLeft:null,currentTarget:null};this.fnSettings=function(){return this.s};this._fnInit(d,b);return this};h.prototype={_fnInit:function(d,b){var a=this;this.s.dt=k.Api?(new k.Api(d)).settings()[0]:d.fnSettings();this.s.init=b||{};this.dom.table=this.s.dt.nTable;c.extend(!0,this.c,h.defaults,b);this._initColumns();var e=c("<div/>",{"class":"AutoFill_filler"}).appendTo("body");this.dom.filler=e[0];this.s.filler.height=e.height();this.s.filler.width=e.width();e[0].style.display=
+"none";var g,f=j.body;""!==a.s.dt.oScroll.sY&&(a.s.dt.nTable.parentNode.style.position="relative",f=a.s.dt.nTable.parentNode);g=c("<div/>",{"class":"AutoFill_border"});this.dom.borderTop=g.clone().appendTo(f)[0];this.dom.borderRight=g.clone().appendTo(f)[0];this.dom.borderBottom=g.clone().appendTo(f)[0];this.dom.borderLeft=g.clone().appendTo(f)[0];e.on("mousedown.DTAF",function(b){this.onselectstart=function(){return false};a._fnFillerDragStart.call(a,b);return false});c("tbody",this.dom.table).on("mouseover.DTAF mouseout.DTAF",
+">tr>td, >tr>th",function(b){a._fnFillerDisplay.call(a,b)});c(this.dom.table).on("destroy.dt.DTAF",function(){e.off("mousedown.DTAF").remove();c("tbody",this.dom.table).off("mouseover.DTAF mouseout.DTAF")})},_initColumns:function(){var d=this,b,a,e=this.s.dt,g=this.s.init;b=0;for(a=e.aoColumns.length;b<a;b++)this.s.columns[b]=c.extend(!0,{},h.defaults.column);e.oApi._fnApplyColumnDefs(e,g.aoColumnDefs||g.columnDefs,g.aoColumns||g.columns,function(a,b){d._fnColumnOptions(a,b)});b=0;for(a=e.aoColumns.length;b<
+a;b++)if(e=this.s.columns[b],e.read||(e.read=this._fnReadCell),e.write||(e.read=this._fnWriteCell),!e.step)e.read=this._fnStep},_fnColumnOptions:function(d,b){var a=this.s.columns[d],c=function(c,d){b[d[0]]!==m&&(a[c]=b[d[0]]);b[d[1]]!==m&&(a[c]=b[d[1]])};c("enable",["bEnable","enable"]);c("read",["fnRead","read"]);c("write",["fnWrite","write"]);c("step",["fnStep","step"]);c("increment",["bIncrement","increment"])},_fnTargetCoords:function(d){var b=c(d).parents("tr")[0],a=this.s.dt.oInstance.fnGetPosition(d);
+return{x:c("td",b).index(d),y:c("tr",b.parentNode).index(b),row:a[0],column:a[2]}},_fnUpdateBorder:function(d,b){var a=this.s.border.width,e=c(d).offset(),g=c(b).offset(),f=e.left-a,i=g.left+c(b).outerWidth(),n=e.top-a,h=g.top+c(b).outerHeight(),j=g.left+c(b).outerWidth()-e.left+2*a,k=g.top+c(b).outerHeight()-e.top+2*a;e.left>g.left&&(f=g.left-a,i=e.left+c(d).outerWidth(),j=e.left+c(d).outerWidth()-g.left+2*a);""!==this.s.dt.oScroll.sY&&(a=c(this.s.dt.nTable.parentNode).offset(),e=c(this.s.dt.nTable.parentNode).scrollTop(),
+g=c(this.s.dt.nTable.parentNode).scrollLeft(),f-=a.left-g,i-=a.left-g,n-=a.top-e,h-=a.top-e);a=this.dom.borderTop.style;a.top=n+"px";a.left=f+"px";a.height=this.s.border.width+"px";a.width=j+"px";a=this.dom.borderBottom.style;a.top=h+"px";a.left=f+"px";a.height=this.s.border.width+"px";a.width=j+"px";a=this.dom.borderLeft.style;a.top=n+"px";a.left=f+"px";a.height=k+"px";a.width=this.s.border.width+"px";a=this.dom.borderRight.style;a.top=n+"px";a.left=i+"px";a.height=k+"px";a.width=this.s.border.width+
+"px"},_fnFillerDragStart:function(d){var b=this,a=this.dom.currentTarget;this.s.drag.dragging=!0;b.dom.borderTop.style.display="block";b.dom.borderRight.style.display="block";b.dom.borderBottom.style.display="block";b.dom.borderLeft.style.display="block";var e=this._fnTargetCoords(a);this.s.drag.startX=e.x;this.s.drag.startY=e.y;this.s.drag.startTd=a;this.s.drag.endTd=a;this._fnUpdateBorder(a,a);c(j).bind("mousemove.AutoFill",function(a){b._fnFillerDragMove.call(b,a)});c(j).bind("mouseup.AutoFill",
+function(a){b._fnFillerFinish.call(b,a)});this.s.screen.y=d.pageY;this.s.screen.height=c(o).height();this.s.screen.scrollTop=c(j).scrollTop();""!==this.s.dt.oScroll.sY&&(this.s.scroller.top=c(this.s.dt.nTable.parentNode).offset().top,this.s.scroller.bottom=this.s.scroller.top+c(this.s.dt.nTable.parentNode).height());this.s.screen.interval=setInterval(function(){var a=c(j).scrollTop();b.s.screen.y=b.s.screen.y+(a-b.s.screen.scrollTop);b.s.screen.height-b.s.screen.y+a<50?c("html, body").animate({scrollTop:a+
+50},240,"linear"):b.s.screen.y-a<50&&c("html, body").animate({scrollTop:a-50},240,"linear");b.s.dt.oScroll.sY!==""&&(b.s.screen.y>b.s.scroller.bottom-50?c(b.s.dt.nTable.parentNode).animate({scrollTop:c(b.s.dt.nTable.parentNode).scrollTop()+50},240,"linear"):b.s.screen.y<b.s.scroller.top+50&&c(b.s.dt.nTable.parentNode).animate({scrollTop:c(b.s.dt.nTable.parentNode).scrollTop()-50},240,"linear"))},250)},_fnFillerDragMove:function(d){if(d.target&&"TD"==d.target.nodeName.toUpperCase()&&d.target!=this.s.drag.endTd){var b=
+this._fnTargetCoords(d.target);"y"==this.c.mode&&b.x!=this.s.drag.startX&&(d.target=c("tbody>tr:eq("+b.y+")>td:eq("+this.s.drag.startX+")",this.dom.table)[0]);"x"==this.c.mode&&b.y!=this.s.drag.startY&&(d.target=c("tbody>tr:eq("+this.s.drag.startY+")>td:eq("+b.x+")",this.dom.table)[0]);"either"==this.c.mode&&(b.x!=this.s.drag.startX?d.target=c("tbody>tr:eq("+this.s.drag.startY+")>td:eq("+b.x+")",this.dom.table)[0]:b.y!=this.s.drag.startY&&(d.target=c("tbody>tr:eq("+b.y+")>td:eq("+this.s.drag.startX+
+")",this.dom.table)[0]));"both"!==this.c.mode&&(b=this._fnTargetCoords(d.target));var a=this.s.drag;a.endTd=d.target;b.y>=this.s.drag.startY?this._fnUpdateBorder(a.startTd,a.endTd):this._fnUpdateBorder(a.endTd,a.startTd);this._fnFillerPosition(d.target)}this.s.screen.y=d.pageY;this.s.screen.scrollTop=c(j).scrollTop();""!==this.s.dt.oScroll.sY&&(this.s.scroller.scrollTop=c(this.s.dt.nTable.parentNode).scrollTop(),this.s.scroller.top=c(this.s.dt.nTable.parentNode).offset().top,this.s.scroller.bottom=
+this.s.scroller.top+c(this.s.dt.nTable.parentNode).height())},_fnFillerFinish:function(){var d=this,b,a;c(j).unbind("mousemove.AutoFill mouseup.AutoFill");this.dom.borderTop.style.display="none";this.dom.borderRight.style.display="none";this.dom.borderBottom.style.display="none";this.dom.borderLeft.style.display="none";this.s.drag.dragging=!1;clearInterval(this.s.screen.interval);var e=[],g=this.dom.table,f=this._fnTargetCoords(this.s.drag.startTd),i=this._fnTargetCoords(this.s.drag.endTd),h=function(a){return d.s.dt.oApi._fnVisibleToColumnIndex(d.s.dt,
+a)};if(f.y<=i.y)for(b=f.y;b<=i.y;b++)if(f.x<=i.x)for(a=f.x;a<=i.x;a++)e.push({node:c("tbody>tr:eq("+b+")>td:eq("+a+")",g)[0],x:a-f.x,y:b-f.y,colIdx:h(a)});else for(a=f.x;a>=i.x;a--)e.push({node:c("tbody>tr:eq("+b+")>td:eq("+a+")",g)[0],x:a-f.x,y:b-f.y,colIdx:h(a)});else for(b=f.y;b>=i.y;b--)if(f.x<=i.x)for(a=f.x;a<=i.x;a++)e.push({node:c("tbody>tr:eq("+b+")>td:eq("+a+")",g)[0],x:a-f.x,y:b-f.y,colIdx:h(a)});else for(a=f.x;a>=i.x;a--)e.push({node:c("tbody>tr:eq("+b+")>td:eq("+a+")",g)[0],x:f.x-a,y:f.y-
+b,colIdx:h(a)});if(!(1>=e.length)){var g=[],m;b=0;for(a=e.length;b<a;b++){var f=e[b],i=this.s.columns[f.colIdx],h=i.read.call(i,f.node),l=i.step.call(i,f.node,h,m,b,f.x,f.y);i.write.call(i,f.node,l);m=l;g.push({cell:f,colIdx:f.colIdx,newValue:l,oldValue:h})}null!==this.c.complete&&this.c.complete.call(this,g);k.Api?(new k.Api(this.s.dt)).draw(!1):this.s.dt.oInstance.fnDraw()}},_fnFillerDisplay:function(d){var b=this.dom.filler;if(!this.s.drag.dragging){var a="td"==d.target.nodeName.toLowerCase()?
+d.target:c(d.target).parents("td")[0],e=this._fnTargetCoords(a).column;if(this.s.columns[e].enable)if("mouseover"==d.type)this.dom.currentTarget=a,this._fnFillerPosition(a),b.style.display="block";else{if(!d.relatedTarget||!d.relatedTarget.className.match(/AutoFill/))b.style.display="none"}else b.style.display="none"}},_fnFillerPosition:function(d){var b=c(d).offset(),a=this.dom.filler;a.style.top=b.top-this.s.filler.height/2-1+c(d).outerHeight()+"px";a.style.left=b.left-this.s.filler.width/2-1+c(d).outerWidth()+
+"px"}};k.AutoFill=h;k.AutoFill=h;h.version="1.2.1";h.defaults={mode:"y",complete:null,column:{enable:!0,increment:!0,read:function(d){return c(d).html()},write:function(d,b){var a=c(d).parents("table");if(k.Api)a.DataTable().cell(d).data(b);else{var a=a.dataTable(),e=a.fnGetPosition(d);a.fnUpdate(b,e[0],e[2],!1)}},step:function(c,b,a,e,g,f){c=/(\-?\d+)/;return(e=this.increment&&a?a.match(c):null)?a.replace(c,parseInt(e[1],10)+(0>g||0>f?-1:1)):a===m?b:a}}};return h};"function"===typeof define&&define.amd?
+define(["jquery","datatables"],l):"object"===typeof exports?l(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.AutoFill&&l(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+Copyright (c) 2010-2015 SpryMedia Limited
+http://datatables.net
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+# ColReorder
+
+ColReorder adds the ability for the end user to click and drag column headers to reorder a table as they see fit, to DataTables. Key features include:
+
+* Very easy integration with DataTables
+* Tight integration with all other DataTables plug-ins
+* The ability to exclude the first (or more) column from being movable
+* Predefine a column order
+* Save staving integration with DataTables
+
+
+# Installation
+
+To use ColReorder, first download DataTables ( http://datatables.net/download ) and place the unzipped ColReorder package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser.
+
+
+# Basic usage
+
+ColReorder is initialised using the `$.fn.dataTable.ColReorder` constructor. For example:
+
+```js
+$(document).ready( function () {
+ $('#example').DataTable();
+
+ new $.fn.dataTable.ColReorder( table );
+} );
+```
+
+
+# Documentation / support
+
+* Documentation: http://datatables.net/extensions/colreorder/
+* DataTables support forums: http://datatables.net/forums
+
+
+# GitHub
+
+If you fancy getting involved with the development of ColReorder and help make it better, please refer to its GitHub repo: https://github.com/DataTables/ColReorder
+
--- /dev/null
+table.DTCR_clonedTable{background-color:rgba(255,255,255,0.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#0259C4;z-index:201}
--- /dev/null
+/*!
+ ColReorder 1.1.3
+ ©2010-2014 SpryMedia Ltd - datatables.net/license
+*/
+(function(o,r,s){function p(d){for(var f=[],a=0,b=d.length;a<b;a++)f[d[a]]=a;return f}function l(d,f,a){f=d.splice(f,1)[0];d.splice(a,0,f)}function q(d,f,a){for(var b=[],e=0,h=d.childNodes.length;e<h;e++)1==d.childNodes[e].nodeType&&b.push(d.childNodes[e]);f=b[f];null!==a?d.insertBefore(f,b[a]):d.appendChild(f)}o=function(d){d.fn.dataTableExt.oApi.fnColReorder=function(a,b,e){var h=d.fn.dataTable.Api?!0:!1,c,g,f,m,n=a.aoColumns.length,i,j;i=function(a,b,c){if(a[b]){var e=a[b].split("."),d=e.shift();
+isNaN(1*d)||(a[b]=c[1*d]+"."+e.join("."))}};if(b!=e)if(0>b||b>=n)this.oApi._fnLog(a,1,"ColReorder 'from' index is out of bounds: "+b);else if(0>e||e>=n)this.oApi._fnLog(a,1,"ColReorder 'to' index is out of bounds: "+e);else{f=[];c=0;for(g=n;c<g;c++)f[c]=c;l(f,b,e);var k=p(f);c=0;for(g=a.aaSorting.length;c<g;c++)a.aaSorting[c][0]=k[a.aaSorting[c][0]];if(null!==a.aaSortingFixed){c=0;for(g=a.aaSortingFixed.length;c<g;c++)a.aaSortingFixed[c][0]=k[a.aaSortingFixed[c][0]]}c=0;for(g=n;c<g;c++){j=a.aoColumns[c];
+f=0;for(m=j.aDataSort.length;f<m;f++)j.aDataSort[f]=k[j.aDataSort[f]];h&&(j.idx=k[j.idx])}h&&d.each(a.aLastSort,function(b,c){a.aLastSort[b].src=k[c.src]});c=0;for(g=n;c<g;c++)j=a.aoColumns[c],"number"==typeof j.mData?(j.mData=k[j.mData],a.oApi._fnColumnOptions(a,c,{})):d.isPlainObject(j.mData)&&(i(j.mData,"_",k),i(j.mData,"filter",k),i(j.mData,"sort",k),i(j.mData,"type",k),a.oApi._fnColumnOptions(a,c,{}));if(a.aoColumns[b].bVisible){f=this.oApi._fnColumnIndexToVisible(a,b);m=null;for(c=e<b?e:e+1;null===
+m&&c<n;)m=this.oApi._fnColumnIndexToVisible(a,c),c++;i=a.nTHead.getElementsByTagName("tr");c=0;for(g=i.length;c<g;c++)q(i[c],f,m);if(null!==a.nTFoot){i=a.nTFoot.getElementsByTagName("tr");c=0;for(g=i.length;c<g;c++)q(i[c],f,m)}c=0;for(g=a.aoData.length;c<g;c++)null!==a.aoData[c].nTr&&q(a.aoData[c].nTr,f,m)}l(a.aoColumns,b,e);l(a.aoPreSearchCols,b,e);c=0;for(g=a.aoData.length;c<g;c++)i=a.aoData[c],h?(i.anCells&&l(i.anCells,b,e),"dom"!==i.src&&d.isArray(i._aData)&&l(i._aData,b,e)):(d.isArray(i._aData)&&
+l(i._aData,b,e),l(i._anHidden,b,e));c=0;for(g=a.aoHeader.length;c<g;c++)l(a.aoHeader[c],b,e);if(null!==a.aoFooter){c=0;for(g=a.aoFooter.length;c<g;c++)l(a.aoFooter[c],b,e)}h&&(new d.fn.dataTable.Api(a)).rows().invalidate();c=0;for(g=n;c<g;c++)d(a.aoColumns[c].nTh).off("click.DT"),this.oApi._fnSortAttachListener(a,a.aoColumns[c].nTh,c);d(a.oInstance).trigger("column-reorder",[a,{iFrom:b,iTo:e,aiInvertMapping:k}])}};var f=function(a,b){var e;d.fn.dataTable.Api?e=(new d.fn.dataTable.Api(a)).settings()[0]:
+a.fnSettings?e=a.fnSettings():"string"===typeof a?d.fn.dataTable.fnIsDataTable(d(a)[0])&&(e=d(a).eq(0).dataTable().fnSettings()):a.nodeName&&"table"===a.nodeName.toLowerCase()?d.fn.dataTable.fnIsDataTable(a.nodeName)&&(e=d(a.nodeName).dataTable().fnSettings()):a instanceof jQuery?d.fn.dataTable.fnIsDataTable(a[0])&&(e=a.eq(0).dataTable().fnSettings()):e=a;if(e._colReorder)throw"ColReorder already initialised on table #"+e.nTable.id;var h=d.fn.dataTable.camelToHungarian;h&&(h(f.defaults,f.defaults,
+!0),h(f.defaults,b||{}));this.s={dt:null,init:d.extend(!0,{},f.defaults,b),fixed:0,fixedRight:0,reorderCallback:null,mouse:{startX:-1,startY:-1,offsetX:-1,offsetY:-1,target:-1,targetIndex:-1,fromIndex:-1},aoTargets:[]};this.dom={drag:null,pointer:null};this.s.dt=e;this.s.dt._colReorder=this;this._fnConstruct();e.oApi._fnCallbackReg(e,"aoDestroyCallback",d.proxy(this._fnDestroy,this),"ColReorder");return this};f.prototype={fnReset:function(){for(var a=[],b=0,e=this.s.dt.aoColumns.length;b<e;b++)a.push(this.s.dt.aoColumns[b]._ColReorder_iOrigCol);
+this._fnOrderColumns(a);return this},fnGetCurrentOrder:function(){return this.fnOrder()},fnOrder:function(a){if(a===s){for(var a=[],b=0,e=this.s.dt.aoColumns.length;b<e;b++)a.push(this.s.dt.aoColumns[b]._ColReorder_iOrigCol);return a}this._fnOrderColumns(p(a));return this},_fnConstruct:function(){var a=this,b=this.s.dt.aoColumns.length,e;this.s.init.iFixedColumns&&(this.s.fixed=this.s.init.iFixedColumns);this.s.fixedRight=this.s.init.iFixedColumnsRight?this.s.init.iFixedColumnsRight:0;this.s.init.fnReorderCallback&&
+(this.s.reorderCallback=this.s.init.fnReorderCallback);for(e=0;e<b;e++)e>this.s.fixed-1&&e<b-this.s.fixedRight&&this._fnMouseListener(e,this.s.dt.aoColumns[e].nTh),this.s.dt.aoColumns[e]._ColReorder_iOrigCol=e;this.s.dt.oApi._fnCallbackReg(this.s.dt,"aoStateSaveParams",function(b,c){a._fnStateSave.call(a,c)},"ColReorder_State");var d=null;this.s.init.aiOrder&&(d=this.s.init.aiOrder.slice());this.s.dt.oLoadedState&&("undefined"!=typeof this.s.dt.oLoadedState.ColReorder&&this.s.dt.oLoadedState.ColReorder.length==
+this.s.dt.aoColumns.length)&&(d=this.s.dt.oLoadedState.ColReorder);if(d)if(a.s.dt._bInitComplete)b=p(d),a._fnOrderColumns.call(a,b);else{var c=!1;this.s.dt.aoDrawCallback.push({fn:function(){if(!a.s.dt._bInitComplete&&!c){c=true;var b=p(d);a._fnOrderColumns.call(a,b)}},sName:"ColReorder_Pre"})}else this._fnSetColumnIndexes()},_fnOrderColumns:function(a){if(a.length!=this.s.dt.aoColumns.length)this.s.dt.oInstance.oApi._fnLog(this.s.dt,1,"ColReorder - array reorder does not match known number of columns. Skipping.");
+else{for(var b=0,e=a.length;b<e;b++){var h=d.inArray(b,a);b!=h&&(l(a,h,b),this.s.dt.oInstance.fnColReorder(h,b))}(""!==this.s.dt.oScroll.sX||""!==this.s.dt.oScroll.sY)&&this.s.dt.oInstance.fnAdjustColumnSizing(!1);this.s.dt.oInstance.oApi._fnSaveState(this.s.dt);this._fnSetColumnIndexes();null!==this.s.reorderCallback&&this.s.reorderCallback.call(this)}},_fnStateSave:function(a){var b,e,h,c=this.s.dt.aoColumns;a.ColReorder=[];if(a.aaSorting){for(b=0;b<a.aaSorting.length;b++)a.aaSorting[b][0]=c[a.aaSorting[b][0]]._ColReorder_iOrigCol;
+var f=d.extend(!0,[],a.aoSearchCols);b=0;for(e=c.length;b<e;b++)h=c[b]._ColReorder_iOrigCol,a.aoSearchCols[h]=f[b],a.abVisCols[h]=c[b].bVisible,a.ColReorder.push(h)}else if(a.order){for(b=0;b<a.order.length;b++)a.order[b][0]=c[a.order[b][0]]._ColReorder_iOrigCol;f=d.extend(!0,[],a.columns);b=0;for(e=c.length;b<e;b++)h=c[b]._ColReorder_iOrigCol,a.columns[h]=f[b],a.ColReorder.push(h)}},_fnMouseListener:function(a,b){var e=this;d(b).on("mousedown.ColReorder",function(a){a.preventDefault();e._fnMouseDown.call(e,
+a,b)})},_fnMouseDown:function(a,b){var e=this,f=d(a.target).closest("th, td").offset(),c=parseInt(d(b).attr("data-column-index"),10);c!==s&&(this.s.mouse.startX=a.pageX,this.s.mouse.startY=a.pageY,this.s.mouse.offsetX=a.pageX-f.left,this.s.mouse.offsetY=a.pageY-f.top,this.s.mouse.target=this.s.dt.aoColumns[c].nTh,this.s.mouse.targetIndex=c,this.s.mouse.fromIndex=c,this._fnRegions(),d(r).on("mousemove.ColReorder",function(a){e._fnMouseMove.call(e,a)}).on("mouseup.ColReorder",function(a){e._fnMouseUp.call(e,
+a)}))},_fnMouseMove:function(a){if(null===this.dom.drag){if(5>Math.pow(Math.pow(a.pageX-this.s.mouse.startX,2)+Math.pow(a.pageY-this.s.mouse.startY,2),0.5))return;this._fnCreateDragNode()}this.dom.drag.css({left:a.pageX-this.s.mouse.offsetX,top:a.pageY-this.s.mouse.offsetY});for(var b=!1,e=this.s.mouse.toIndex,d=1,c=this.s.aoTargets.length;d<c;d++)if(a.pageX<this.s.aoTargets[d-1].x+(this.s.aoTargets[d].x-this.s.aoTargets[d-1].x)/2){this.dom.pointer.css("left",this.s.aoTargets[d-1].x);this.s.mouse.toIndex=
+this.s.aoTargets[d-1].to;b=!0;break}b||(this.dom.pointer.css("left",this.s.aoTargets[this.s.aoTargets.length-1].x),this.s.mouse.toIndex=this.s.aoTargets[this.s.aoTargets.length-1].to);this.s.init.bRealtime&&e!==this.s.mouse.toIndex&&(this.s.dt.oInstance.fnColReorder(this.s.mouse.fromIndex,this.s.mouse.toIndex),this.s.mouse.fromIndex=this.s.mouse.toIndex,this._fnRegions())},_fnMouseUp:function(){d(r).off("mousemove.ColReorder mouseup.ColReorder");null!==this.dom.drag&&(this.dom.drag.remove(),this.dom.pointer.remove(),
+this.dom.drag=null,this.dom.pointer=null,this.s.dt.oInstance.fnColReorder(this.s.mouse.fromIndex,this.s.mouse.toIndex),this._fnSetColumnIndexes(),(""!==this.s.dt.oScroll.sX||""!==this.s.dt.oScroll.sY)&&this.s.dt.oInstance.fnAdjustColumnSizing(!1),this.s.dt.oInstance.oApi._fnSaveState(this.s.dt),null!==this.s.reorderCallback&&this.s.reorderCallback.call(this))},_fnRegions:function(){var a=this.s.dt.aoColumns;this.s.aoTargets.splice(0,this.s.aoTargets.length);this.s.aoTargets.push({x:d(this.s.dt.nTable).offset().left,
+to:0});for(var b=0,e=0,f=a.length;e<f;e++)e!=this.s.mouse.fromIndex&&b++,a[e].bVisible&&this.s.aoTargets.push({x:d(a[e].nTh).offset().left+d(a[e].nTh).outerWidth(),to:b});0!==this.s.fixedRight&&this.s.aoTargets.splice(this.s.aoTargets.length-this.s.fixedRight);0!==this.s.fixed&&this.s.aoTargets.splice(0,this.s.fixed)},_fnCreateDragNode:function(){var a=""!==this.s.dt.oScroll.sX||""!==this.s.dt.oScroll.sY,b=this.s.dt.aoColumns[this.s.mouse.targetIndex].nTh,e=b.parentNode,f=e.parentNode,c=f.parentNode,
+g=d(b).clone();this.dom.drag=d(c.cloneNode(!1)).addClass("DTCR_clonedTable").append(d(f.cloneNode(!1)).append(d(e.cloneNode(!1)).append(g[0]))).css({position:"absolute",top:0,left:0,width:d(b).outerWidth(),height:d(b).outerHeight()}).appendTo("body");this.dom.pointer=d("<div></div>").addClass("DTCR_pointer").css({position:"absolute",top:a?d("div.dataTables_scroll",this.s.dt.nTableWrapper).offset().top:d(this.s.dt.nTable).offset().top,height:a?d("div.dataTables_scroll",this.s.dt.nTableWrapper).height():
+d(this.s.dt.nTable).height()}).appendTo("body")},_fnDestroy:function(){var a,b;a=0;for(b=this.s.dt.aoDrawCallback.length;a<b;a++)if("ColReorder_Pre"===this.s.dt.aoDrawCallback[a].sName){this.s.dt.aoDrawCallback.splice(a,1);break}d(this.s.dt.nTHead).find("*").off(".ColReorder");d.each(this.s.dt.aoColumns,function(a,b){d(b.nTh).removeAttr("data-column-index")});this.s=this.s.dt._colReorder=null},_fnSetColumnIndexes:function(){d.each(this.s.dt.aoColumns,function(a,b){d(b.nTh).attr("data-column-index",
+a)})}};f.defaults={aiOrder:null,bRealtime:!1,iFixedColumns:0,iFixedColumnsRight:0,fnReorderCallback:null};f.version="1.1.3";d.fn.dataTable.ColReorder=f;d.fn.DataTable.ColReorder=f;"function"==typeof d.fn.dataTable&&"function"==typeof d.fn.dataTableExt.fnVersionCheck&&d.fn.dataTableExt.fnVersionCheck("1.9.3")?d.fn.dataTableExt.aoFeatures.push({fnInit:function(a){var b=a.oInstance;a._colReorder?b.oApi._fnLog(a,1,"ColReorder attempted to initialise twice. Ignoring second"):(b=a.oInit,new f(a,b.colReorder||
+b.oColReorder||{}));return null},cFeature:"R",sFeature:"ColReorder"}):alert("Warning: ColReorder requires DataTables 1.9.3 or greater - www.datatables.net/download");d.fn.dataTable.Api&&(d.fn.dataTable.Api.register("colReorder.reset()",function(){return this.iterator("table",function(a){a._colReorder.fnReset()})}),d.fn.dataTable.Api.register("colReorder.order()",function(a){return a?this.iterator("table",function(b){b._colReorder.fnOrder(a)}):this.context.length?this.context[0]._colReorder.fnOrder():
+null}));return f};"function"===typeof define&&define.amd?define(["jquery","datatables"],o):"object"===typeof exports?o(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.ColReorder&&o(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+Copyright (c) 2010-2015 SpryMedia Limited
+http://datatables.net
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+# ColVis
+
+ColVis adds a button to the toolbars around DataTables which gives the end user of the table the ability to dynamically change the visibility of the columns in the table:
+
+* Dynamically show and hide columns in a table
+* Very easy integration with DataTables
+* Ability to exclude columns from being either hidden or shown
+* Save saving integration with DataTables
+
+
+# Installation
+
+To use ColVis, first download DataTables ( http://datatables.net/download ) and place the unzipped ColVis package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser.
+
+
+# Basic usage
+
+ColVis is initialised using the `C` option that it adds to DataTables' `dom` option. For example:
+
+```js
+$(document).ready( function () {
+ $('#example').dataTable( {
+ "dom": 'C<"clear">lfrtip'
+ } );
+} );
+```
+
+
+# Documentation / support
+
+* Documentation: http://datatables.net/extensions/colvis/
+* DataTables support forums: http://datatables.net/forums
+
+
+# GitHub
+
+If you fancy getting involved with the development of ColVis and help make it better, please refer to its GitHub repo: https://github.com/DataTables/ColVis
+
--- /dev/null
+div.ColVis{float:right;margin-bottom:1em}button.ColVis_Button,ul.ColVis_collection li{position:relative;float:left;margin-right:3px;padding:5px 8px;border:1px solid #999;cursor:pointer;*cursor:hand;font-size:0.88em;color:black !important;white-space:nowrap;-webkit-border-radius:2px;-moz-border-radius:2px;-ms-border-radius:2px;-o-border-radius:2px;border-radius:2px;-webkit-box-shadow:1px 1px 3px #ccc;-moz-box-shadow:1px 1px 3px #ccc;-ms-box-shadow:1px 1px 3px #ccc;-o-box-shadow:1px 1px 3px #ccc;box-shadow:1px 1px 3px #ccc;background:#ffffff;background:-webkit-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-moz-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-ms-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-o-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f9f9f9',GradientType=0 )}.ColVis_Button:hover,ul.ColVis_collection li:hover{border:1px solid #666;text-decoration:none !important;-webkit-box-shadow:1px 1px 3px #999;-moz-box-shadow:1px 1px 3px #999;-ms-box-shadow:1px 1px 3px #999;-o-box-shadow:1px 1px 3px #999;box-shadow:1px 1px 3px #999;background:#f3f3f3;background:-webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);background:-moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);background:-ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);background:-o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);background:linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3f3f3', endColorstr='#f4f4f4',GradientType=0 )}button.ColVis_Button{height:30px;padding:3px 8px}button.ColVis_Button::-moz-focus-inner{border:none !important;padding:0}button.ColVis_Button:active{outline:none}div.ColVis_collectionBackground{position:fixed;top:0;left:0;height:100%;width:100%;background-color:black;z-index:1100}ul.ColVis_collection{list-style:none;width:150px;padding:8px 8px 4px 8px;margin:0;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.4);background-color:#f3f3f3;background-color:rgba(255,255,255,0.3);overflow:hidden;z-index:2002;-webkit-border-radius:5px;-moz-border-radius:5px;-ms-border-radius:5px;-o-border-radius:5px;border-radius:5px;-webkit-box-shadow:3px 3px 5px rgba(0,0,0,0.3);-moz-box-shadow:3px 3px 5px rgba(0,0,0,0.3);-ms-box-shadow:3px 3px 5px rgba(0,0,0,0.3);-o-box-shadow:3px 3px 5px rgba(0,0,0,0.3);box-shadow:3px 3px 5px rgba(0,0,0,0.3)}ul.ColVis_collection li{position:relative;height:auto;left:0;right:0;padding:0.5em;display:block;float:none;margin-bottom:4px;-webkit-box-shadow:1px 1px 3px #999;-moz-box-shadow:1px 1px 3px #999;-ms-box-shadow:1px 1px 3px #999;-o-box-shadow:1px 1px 3px #999;box-shadow:1px 1px 3px #999}ul.ColVis_collection li{text-align:left}ul.ColVis_collection li.ColVis_Button:hover{border:1px solid #999;background-color:#f0f0f0}ul.ColVis_collection li span{display:inline-block;padding-left:0.5em;cursor:pointer}ul.ColVis_collection li.ColVis_Special{border-color:#555;background:#ededed;background:-webkit-linear-gradient(top, #ededed 0%, #d6d6d6 77%, #e8e8e8 100%);background:-moz-linear-gradient(top, #ededed 0%, #d6d6d6 77%, #e8e8e8 100%);background:-ms-linear-gradient(top, #ededed 0%, #d6d6d6 77%, #e8e8e8 100%);background:-o-linear-gradient(top, #ededed 0%, #d6d6d6 77%, #e8e8e8 100%);background:linear-gradient(to bottom, #ededed 0%, #d6d6d6 77%, #e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#e8e8e8',GradientType=0 )}ul.ColVis_collection li.ColVis_Special:hover{background:#e2e2e2;background:-webkit-linear-gradient(top, #d0d0d0 0%, #d5d5d5 89%, #e2e2e2 100%);background:-moz-linear-gradient(top, #d0d0d0 0%, #d5d5d5 89%, #e2e2e2 100%);background:-ms-linear-gradient(top, #d0d0d0 0%, #d5d5d5 89%, #e2e2e2 100%);background:-o-linear-gradient(top, #d0d0d0 0%, #d5d5d5 89%, #e2e2e2 100%);background:linear-gradient(top, #d0d0d0 0%, #d5d5d5 89%, #e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3f3f3', endColorstr='#e2e2e2',GradientType=0 )}span.ColVis_radio{display:inline-block;width:20px}div.ColVis_catcher{position:absolute;z-index:1101}.disabled{color:#999}
--- /dev/null
+
+button.ColVis_Button,
+ul.ColVis_collection li {
+ padding: 0.5em;
+}
+
+ul.ColVis_collection {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ z-index: 2002;
+}
+
+ul.ColVis_collection li {
+ clear: both;
+ display: block;
+ text-align: left;
+ margin: -1px 0 0 0;
+}
+
+ul.ColVis_collection li span {
+ display: inline-block;
+ padding-left: 0.5em;
+ cursor: pointer;
+}
+
+div.ColVis_collectionBackground {
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ background-color: black;
+ z-index: 1100;
+}
+
+
+div.ColVis_catcher {
+ position: absolute;
+ z-index: 1101;
+}
\ No newline at end of file
--- /dev/null
+/*!
+ ColVis 1.1.2
+ ©2010-2015 SpryMedia Ltd - datatables.net/license
+*/
+(function(j,i,k){j=function(d){var e=function(a,b){(!this.CLASS||"ColVis"!=this.CLASS)&&alert("Warning: ColVis must be initialised with the keyword 'new'");"undefined"==typeof b&&(b={});var c=d.fn.dataTable.camelToHungarian;c&&(c(e.defaults,e.defaults,!0),c(e.defaults,b));this.s={dt:null,oInit:b,hidden:!0,abOriginal:[]};this.dom={wrapper:null,button:null,collection:null,background:null,catcher:null,buttons:[],groupButtons:[],restore:null};e.aInstances.push(this);this.s.dt=d.fn.dataTable.Api?(new d.fn.dataTable.Api(a)).settings()[0]:
+a;this._fnConstruct(b);return this};e.prototype={button:function(){return this.dom.wrapper},fnRebuild:function(){this.rebuild()},rebuild:function(){for(var a=this.dom.buttons.length-1;0<=a;a--)this.dom.collection.removeChild(this.dom.buttons[a]);this.dom.buttons.splice(0,this.dom.buttons.length);this.dom.groupButtons.splice(0,this.dom.groupButtons.length);this.dom.restore&&this.dom.restore.parentNode(this.dom.restore);this._fnAddGroups();this._fnAddButtons();this._fnDrawCallback()},_fnConstruct:function(a){this._fnApplyCustomisation(a);
+var b=this,c,f;this.dom.wrapper=i.createElement("div");this.dom.wrapper.className="ColVis";this.dom.button=d("<button />",{"class":!this.s.dt.bJUI?"ColVis_Button ColVis_MasterButton":"ColVis_Button ColVis_MasterButton ui-button ui-state-default"}).append("<span>"+this.s.buttonText+"</span>").bind("mouseover"==this.s.activate?"mouseover":"click",function(a){a.preventDefault();b._fnCollectionShow()}).appendTo(this.dom.wrapper)[0];this.dom.catcher=this._fnDomCatcher();this.dom.collection=this._fnDomCollection();
+this.dom.background=this._fnDomBackground();this._fnAddGroups();this._fnAddButtons();c=0;for(f=this.s.dt.aoColumns.length;c<f;c++)this.s.abOriginal.push(this.s.dt.aoColumns[c].bVisible);this.s.dt.aoDrawCallback.push({fn:function(){b._fnDrawCallback.call(b)},sName:"ColVis"});d(this.s.dt.oInstance).bind("column-reorder.dt",function(a,d,e){c=0;for(f=b.s.aiExclude.length;c<f;c++)b.s.aiExclude[c]=e.aiInvertMapping[b.s.aiExclude[c]];a=b.s.abOriginal.splice(e.iFrom,1)[0];b.s.abOriginal.splice(e.iTo,0,a);
+b.fnRebuild()});d(this.s.dt.oInstance).bind("destroy.dt",function(){d(b.dom.wrapper).remove()});this._fnDrawCallback()},_fnApplyCustomisation:function(a){d.extend(!0,this.s,e.defaults,a);!this.s.showAll&&this.s.bShowAll&&(this.s.showAll=this.s.sShowAll);!this.s.restore&&this.s.bRestore&&(this.s.restore=this.s.sRestore);var a=this.s.groups,b=this.s.aoGroups;if(a)for(var c=0,f=a.length;c<f;c++)if(a[c].title&&(b[c].sTitle=a[c].title),a[c].columns)b[c].aiColumns=a[c].columns},_fnDrawCallback:function(){for(var a=
+this.s.dt.aoColumns,b=this.dom.buttons,c=this.s.aoGroups,f,g=0,h=b.length;g<h;g++)f=b[g],f.__columnIdx!==k&&d("input",f).prop("checked",a[f.__columnIdx].bVisible);b=0;for(f=c.length;b<f;b++){a:{for(var g=c[b].aiColumns,h=0,e=g.length;h<e;h++)if(!1===a[g[h]].bVisible){g=!1;break a}g=!0}if(g)d("input",this.dom.groupButtons[b]).prop("checked",!0),d("input",this.dom.groupButtons[b]).prop("indeterminate",!1);else{a:{g=c[b].aiColumns;h=0;for(e=g.length;h<e;h++)if(!0===a[g[h]].bVisible){g=!1;break a}g=!0}g?
+(d("input",this.dom.groupButtons[b]).prop("checked",!1),d("input",this.dom.groupButtons[b]).prop("indeterminate",!1)):d("input",this.dom.groupButtons[b]).prop("indeterminate",!0)}}},_fnAddGroups:function(){var a;if("undefined"!=typeof this.s.aoGroups)for(var b=0,c=this.s.aoGroups.length;b<c;b++)a=this._fnDomGroupButton(b),this.dom.groupButtons.push(a),this.dom.buttons.push(a),this.dom.collection.appendChild(a)},_fnAddButtons:function(){var a,b=this.s.dt.aoColumns;if(-1===d.inArray("all",this.s.aiExclude))for(var c=
+0,f=b.length;c<f;c++)-1===d.inArray(c,this.s.aiExclude)&&(a=this._fnDomColumnButton(c),a.__columnIdx=c,this.dom.buttons.push(a));"alpha"===this.s.order&&this.dom.buttons.sort(function(a,c){var d=b[a.__columnIdx].sTitle,f=b[c.__columnIdx].sTitle;return d===f?0:d<f?-1:1});this.s.restore&&(a=this._fnDomRestoreButton(),a.className+=" ColVis_Restore",this.dom.buttons.push(a));this.s.showAll&&(a=this._fnDomShowXButton(this.s.showAll,!0),a.className+=" ColVis_ShowAll",this.dom.buttons.push(a));this.s.showNone&&
+(a=this._fnDomShowXButton(this.s.showNone,!1),a.className+=" ColVis_ShowNone",this.dom.buttons.push(a));d(this.dom.collection).append(this.dom.buttons)},_fnDomRestoreButton:function(){var a=this;return d('<li class="ColVis_Special '+(this.s.dt.bJUI?"ui-button ui-state-default":"")+'">'+this.s.restore+"</li>").click(function(){for(var b=0,c=a.s.abOriginal.length;b<c;b++)a.s.dt.oInstance.fnSetColumnVis(b,a.s.abOriginal[b],!1);a._fnAdjustOpenRows();a.s.dt.oInstance.fnAdjustColumnSizing(!1);a.s.dt.oInstance.fnDraw(!1)})[0]},
+_fnDomShowXButton:function(a,b){var c=this;return d('<li class="ColVis_Special '+(this.s.dt.bJUI?"ui-button ui-state-default":"")+'">'+a+"</li>").click(function(){for(var a=0,d=c.s.abOriginal.length;a<d;a++)-1===c.s.aiExclude.indexOf(a)&&c.s.dt.oInstance.fnSetColumnVis(a,b,!1);c._fnAdjustOpenRows();c.s.dt.oInstance.fnAdjustColumnSizing(!1);c.s.dt.oInstance.fnDraw(!1)})[0]},_fnDomGroupButton:function(a){var b=this,c=this.s.aoGroups[a];return d('<li class="ColVis_Special '+(this.s.dt.bJUI?"ui-button ui-state-default":
+"")+'"><label><input type="checkbox" /><span>'+c.sTitle+"</span></label></li>").click(function(a){var g=!d("input",this).is(":checked");"li"!==a.target.nodeName.toLowerCase()&&(g=!g);for(a=0;a<c.aiColumns.length;a++)b.s.dt.oInstance.fnSetColumnVis(c.aiColumns[a],g)})[0]},_fnDomColumnButton:function(a){var b=this,c=this.s.dt.aoColumns[a],f=this.s.dt,c=null===this.s.fnLabel?c.sTitle:this.s.fnLabel(a,c.sTitle,c.nTh);return d("<li "+(f.bJUI?'class="ui-button ui-state-default"':"")+'><label><input type="checkbox" /><span>'+
+c+"</span></label></li>").click(function(c){var e=!d("input",this).is(":checked");if("li"!==c.target.nodeName.toLowerCase()&&("input"==c.target.nodeName.toLowerCase()||null===b.s.fnStateChange))e=!e;var i=d.fn.dataTableExt.iApiIndex;d.fn.dataTableExt.iApiIndex=b._fnDataTablesApiIndex.call(b);f.oFeatures.bServerSide?(b.s.dt.oInstance.fnSetColumnVis(a,e,!1),b.s.dt.oInstance.fnAdjustColumnSizing(!1),(""!==f.oScroll.sX||""!==f.oScroll.sY)&&b.s.dt.oInstance.oApi._fnScrollDraw(b.s.dt),b._fnDrawCallback()):
+b.s.dt.oInstance.fnSetColumnVis(a,e);d.fn.dataTableExt.iApiIndex=i;null!==b.s.fnStateChange&&("span"==c.target.nodeName.toLowerCase()&&c.preventDefault(),b.s.fnStateChange.call(b,a,e))})[0]},_fnDataTablesApiIndex:function(){for(var a=0,b=this.s.dt.oInstance.length;a<b;a++)if(this.s.dt.oInstance[a]==this.s.dt.nTable)return a;return 0},_fnDomCollection:function(){return d("<ul />",{"class":!this.s.dt.bJUI?"ColVis_collection":"ColVis_collection ui-buttonset ui-buttonset-multi"}).css({display:"none",
+opacity:0,position:!this.s.bCssPosition?"absolute":""})[0]},_fnDomCatcher:function(){var a=this,b=i.createElement("div");b.className="ColVis_catcher";d(b).click(function(){a._fnCollectionHide.call(a,null,null)});return b},_fnDomBackground:function(){var a=this,b=d("<div></div>").addClass("ColVis_collectionBackground").css("opacity",0).click(function(){a._fnCollectionHide.call(a,null,null)});"mouseover"==this.s.activate&&b.mouseover(function(){a.s.overcollection=!1;a._fnCollectionHide.call(a,null,
+null)});return b[0]},_fnCollectionShow:function(){var a=this,b;b=d(this.dom.button).offset();var c=this.dom.collection,f=this.dom.background,e=parseInt(b.left,10),h=parseInt(b.top+d(this.dom.button).outerHeight(),10);this.s.bCssPosition||(c.style.top=h+"px",c.style.left=e+"px");d(c).css({display:"block",opacity:0});f.style.bottom="0px";f.style.right="0px";h=this.dom.catcher.style;h.height=d(this.dom.button).outerHeight()+"px";h.width=d(this.dom.button).outerWidth()+"px";h.top=b.top+"px";h.left=e+
+"px";i.body.appendChild(f);i.body.appendChild(c);i.body.appendChild(this.dom.catcher);d(c).animate({opacity:1},a.s.iOverlayFade);d(f).animate({opacity:0.1},a.s.iOverlayFade,"linear",function(){d.browser&&(d.browser.msie&&d.browser.version=="6.0")&&a._fnDrawCallback()});this.s.bCssPosition||(b="left"==this.s.sAlign?e:e-d(c).outerWidth()+d(this.dom.button).outerWidth(),c.style.left=b+"px",f=d(c).outerWidth(),d(c).outerHeight(),e=d(i).width(),b+f>e&&(c.style.left=e-f+"px"));this.s.hidden=!1},_fnCollectionHide:function(){var a=
+this;!this.s.hidden&&null!==this.dom.collection&&(this.s.hidden=!0,d(this.dom.collection).animate({opacity:0},a.s.iOverlayFade,function(){this.style.display="none"}),d(this.dom.background).animate({opacity:0},a.s.iOverlayFade,function(){i.body.removeChild(a.dom.background);i.body.removeChild(a.dom.catcher)}))},_fnAdjustOpenRows:function(){for(var a=this.s.dt.aoOpenRows,b=this.s.dt.oApi._fnVisbleColumns(this.s.dt),c=0,d=a.length;c<d;c++)a[c].nTr.getElementsByTagName("td")[0].colSpan=b}};e.fnRebuild=
+function(a){var b=null;"undefined"!=typeof a&&(b=d.fn.dataTable.Api?(new d.fn.dataTable.Api(a)).table().node():a.fnSettings().nTable);for(var c=0,f=e.aInstances.length;c<f;c++)("undefined"==typeof a||b==e.aInstances[c].s.dt.nTable)&&e.aInstances[c].fnRebuild()};e.defaults={active:"click",buttonText:"Show / hide columns",aiExclude:[],bRestore:!1,sRestore:"Restore original",bShowAll:!1,sShowAll:"Show All",sAlign:"left",fnStateChange:null,iOverlayFade:500,fnLabel:null,bCssPosition:!1,aoGroups:[],order:"column"};
+e.aInstances=[];e.prototype.CLASS="ColVis";e.VERSION="1.1.2";e.prototype.VERSION=e.VERSION;"function"==typeof d.fn.dataTable&&"function"==typeof d.fn.dataTableExt.fnVersionCheck&&d.fn.dataTableExt.fnVersionCheck("1.7.0")?d.fn.dataTableExt.aoFeatures.push({fnInit:function(a){var b=a.oInit;return(new e(a,b.colVis||b.oColVis||{})).button()},cFeature:"C",sFeature:"ColVis"}):alert("Warning: ColVis requires DataTables 1.7 or greater - www.datatables.net/download");d.fn.dataTable.ColVis=e;return d.fn.DataTable.ColVis=
+e};"function"===typeof define&&define.amd?define(["jquery","datatables"],j):"object"===typeof exports?j(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.ColVis&&j(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+Copyright (c) 2010-2015 SpryMedia Limited
+http://datatables.net
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+# FixedColumns
+
+When making use of DataTables' x-axis scrolling feature (`scrollX`), you may wish to fix the left or right most columns in place. This plug-in for DataTables provides exactly this option (for non-scrolling tables, please use the FixedHeader plug-in, which can fix headers, footers and columns). Key features include:
+
+* Freezes the left most column to the side of the table
+* Option to freeze two or more columns
+* Full integration with DataTables' scrolling options
+
+
+# Installation
+
+To use FixedColumns, first download DataTables ( http://datatables.net/download ) and place the unzipped FixedColumns package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser.
+
+
+# Basic usage
+
+FixedColumns is initialised using the `$.fn.dataTable.FixedColumns()` constructor. For example:
+
+```js
+$(document).ready(function() {
+ var table = $('#example').DataTable( {
+ scrollY: "300px",
+ scrollX: true,
+ scrollCollapse: true,
+ paging: false
+ } );
+
+ new $.fn.dataTable.FixedColumns( table );
+} );
+```
+
+
+# Documentation / support
+
+* Documentation: http://datatables.net/extensions/FixedColumns/
+* DataTables support forums: http://datatables.net/forums
+
+
+# GitHub
+
+If you fancy getting involved with the development of FixedColumns and help make it better, please refer to its GitHub repo: https://github.com/DataTables/FixedColumns
+
--- /dev/null
+table.DTFC_Cloned thead,table.DTFC_Cloned tfoot{background-color:white}div.DTFC_Blocker{background-color:white}div.DTFC_LeftWrapper table.dataTable,div.DTFC_RightWrapper table.dataTable{margin-bottom:0;z-index:2}div.DTFC_LeftWrapper table.dataTable.no-footer,div.DTFC_RightWrapper table.dataTable.no-footer{border-bottom:none}
--- /dev/null
+/*!
+ FixedColumns 3.0.4
+ ©2010-2014 SpryMedia Ltd - datatables.net/license
+*/
+(function(r,s,t){var p=function(d){var j=function(a,b){var c=this;if(this instanceof j){"undefined"==typeof b&&(b={});var g=d.fn.dataTable.camelToHungarian;g&&(g(j.defaults,j.defaults,!0),g(j.defaults,b));g=d.fn.dataTable.Api?(new d.fn.dataTable.Api(a)).settings()[0]:a.fnSettings();this.s={dt:g,iTableColumns:g.aoColumns.length,aiOuterWidths:[],aiInnerWidths:[]};this.dom={scroller:null,header:null,body:null,footer:null,grid:{wrapper:null,dt:null,left:{wrapper:null,head:null,body:null,foot:null},right:{wrapper:null,
+head:null,body:null,foot:null}},clone:{left:{header:null,body:null,footer:null},right:{header:null,body:null,footer:null}}};g._oFixedColumns=this;g._bInitComplete?this._fnConstruct(b):g.oApi._fnCallbackReg(g,"aoInitComplete",function(){c._fnConstruct(b)},"FixedColumns")}else alert("FixedColumns warning: FixedColumns must be initialised with the 'new' keyword.")};j.prototype={fnUpdate:function(){this._fnDraw(!0)},fnRedrawLayout:function(){this._fnColCalc();this._fnGridLayout();this.fnUpdate()},fnRecalculateHeight:function(a){delete a._DTTC_iHeight;
+a.style.height="auto"},fnSetRowHeight:function(a,b){a.style.height=b+"px"},fnGetPosition:function(a){var b=this.s.dt.oInstance;if(d(a).parents(".DTFC_Cloned").length){if("tr"===a.nodeName.toLowerCase())return a=d(a).index(),b.fnGetPosition(d("tr",this.s.dt.nTBody)[a]);var c=d(a).index(),a=d(a.parentNode).index();return[b.fnGetPosition(d("tr",this.s.dt.nTBody)[a]),c,b.oApi._fnVisibleToColumnIndex(this.s.dt,c)]}return b.fnGetPosition(a)},_fnConstruct:function(a){var b=this;if("function"!=typeof this.s.dt.oInstance.fnVersionCheck||
+!0!==this.s.dt.oInstance.fnVersionCheck("1.8.0"))alert("FixedColumns "+j.VERSION+" required DataTables 1.8.0 or later. Please upgrade your DataTables installation");else if(""===this.s.dt.oScroll.sX)this.s.dt.oInstance.oApi._fnLog(this.s.dt,1,"FixedColumns is not needed (no x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for column fixing when scrolling is not enabled");else{this.s=d.extend(!0,this.s,j.defaults,a);a=this.s.dt.oClasses;this.dom.grid.dt=d(this.s.dt.nTable).parents("div."+
+a.sScrollWrapper)[0];this.dom.scroller=d("div."+a.sScrollBody,this.dom.grid.dt)[0];this._fnColCalc();this._fnGridSetup();var c;d(this.dom.scroller).on("mouseover.DTFC touchstart.DTFC",function(){c="main"}).on("scroll.DTFC",function(){if("main"===c&&(0<b.s.iLeftColumns&&(b.dom.grid.left.liner.scrollTop=b.dom.scroller.scrollTop),0<b.s.iRightColumns))b.dom.grid.right.liner.scrollTop=b.dom.scroller.scrollTop});var g="onwheel"in s.createElement("div")?"wheel.DTFC":"mousewheel.DTFC";if(0<b.s.iLeftColumns)d(b.dom.grid.left.liner).on("mouseover.DTFC touchstart.DTFC",
+function(){c="left"}).on("scroll.DTFC",function(){"left"===c&&(b.dom.scroller.scrollTop=b.dom.grid.left.liner.scrollTop,0<b.s.iRightColumns&&(b.dom.grid.right.liner.scrollTop=b.dom.grid.left.liner.scrollTop))}).on(g,function(a){b.dom.scroller.scrollLeft-="wheel"===a.type?-a.originalEvent.deltaX:a.originalEvent.wheelDeltaX});if(0<b.s.iRightColumns)d(b.dom.grid.right.liner).on("mouseover.DTFC touchstart.DTFC",function(){c="right"}).on("scroll.DTFC",function(){"right"===c&&(b.dom.scroller.scrollTop=
+b.dom.grid.right.liner.scrollTop,0<b.s.iLeftColumns&&(b.dom.grid.left.liner.scrollTop=b.dom.grid.right.liner.scrollTop))}).on(g,function(a){b.dom.scroller.scrollLeft-="wheel"===a.type?-a.originalEvent.deltaX:a.originalEvent.wheelDeltaX});d(r).on("resize.DTFC",function(){b._fnGridLayout.call(b)});var f=!0,e=d(this.s.dt.nTable);e.on("draw.dt.DTFC",function(){b._fnDraw.call(b,f);f=!1}).on("column-sizing.dt.DTFC",function(){b._fnColCalc();b._fnGridLayout(b)}).on("column-visibility.dt.DTFC",function(){b._fnColCalc();
+b._fnGridLayout(b);b._fnDraw(!0)}).on("destroy.dt.DTFC",function(){e.off("column-sizing.dt.DTFC destroy.dt.DTFC draw.dt.DTFC");d(b.dom.scroller).off("scroll.DTFC mouseover.DTFC");d(r).off("resize.DTFC");d(b.dom.grid.left.liner).off("scroll.DTFC mouseover.DTFC "+g);d(b.dom.grid.left.wrapper).remove();d(b.dom.grid.right.liner).off("scroll.DTFC mouseover.DTFC "+g);d(b.dom.grid.right.wrapper).remove()});this._fnGridLayout();this.s.dt.oInstance.fnDraw(!1)}},_fnColCalc:function(){var a=this,b=0,c=0;this.s.aiInnerWidths=
+[];this.s.aiOuterWidths=[];d.each(this.s.dt.aoColumns,function(g,f){var e=d(f.nTh),h;if(e.filter(":visible").length){var i=e.outerWidth();0===a.s.aiOuterWidths.length&&(h=d(a.s.dt.nTable).css("border-left-width"),i+="string"===typeof h?1:parseInt(h,10));a.s.aiOuterWidths.length===a.s.dt.aoColumns.length-1&&(h=d(a.s.dt.nTable).css("border-right-width"),i+="string"===typeof h?1:parseInt(h,10));a.s.aiOuterWidths.push(i);a.s.aiInnerWidths.push(e.width());g<a.s.iLeftColumns&&(b+=i);a.s.iTableColumns-a.s.iRightColumns<=
+g&&(c+=i)}else a.s.aiInnerWidths.push(0),a.s.aiOuterWidths.push(0)});this.s.iLeftWidth=b;this.s.iRightWidth=c},_fnGridSetup:function(){var a=this._fnDTOverflow(),b;this.dom.body=this.s.dt.nTable;this.dom.header=this.s.dt.nTHead.parentNode;this.dom.header.parentNode.parentNode.style.position="relative";var c=d('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;"><div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;"><div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div><div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;"><div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div></div><div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div></div><div class="DTFC_RightWrapper" style="position:absolute; top:0; left:0;"><div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;"><div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div></div><div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;"><div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div></div><div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;"><div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div></div></div></div>')[0],
+g=c.childNodes[0],f=c.childNodes[1];this.dom.grid.dt.parentNode.insertBefore(c,this.dom.grid.dt);c.appendChild(this.dom.grid.dt);this.dom.grid.wrapper=c;0<this.s.iLeftColumns&&(this.dom.grid.left.wrapper=g,this.dom.grid.left.head=g.childNodes[0],this.dom.grid.left.body=g.childNodes[1],this.dom.grid.left.liner=d("div.DTFC_LeftBodyLiner",c)[0],c.appendChild(g));0<this.s.iRightColumns&&(this.dom.grid.right.wrapper=f,this.dom.grid.right.head=f.childNodes[0],this.dom.grid.right.body=f.childNodes[1],this.dom.grid.right.liner=
+d("div.DTFC_RightBodyLiner",c)[0],b=d("div.DTFC_RightHeadBlocker",c)[0],b.style.width=a.bar+"px",b.style.right=-a.bar+"px",this.dom.grid.right.headBlock=b,b=d("div.DTFC_RightFootBlocker",c)[0],b.style.width=a.bar+"px",b.style.right=-a.bar+"px",this.dom.grid.right.footBlock=b,c.appendChild(f));if(this.s.dt.nTFoot&&(this.dom.footer=this.s.dt.nTFoot.parentNode,0<this.s.iLeftColumns&&(this.dom.grid.left.foot=g.childNodes[2]),0<this.s.iRightColumns))this.dom.grid.right.foot=f.childNodes[2]},_fnGridLayout:function(){var a=
+this.dom.grid,b=d(a.wrapper).width(),c=d(this.s.dt.nTable.parentNode).outerHeight(),g=d(this.s.dt.nTable.parentNode.parentNode).outerHeight(),f=this._fnDTOverflow(),e=this.s.iLeftWidth,h=this.s.iRightWidth,i=function(a,b){f.bar?a.style.width=b+f.bar+"px":(a.style.width=b+20+"px",a.style.paddingRight="20px",a.style.boxSizing="border-box")};f.x&&(c-=f.bar);a.wrapper.style.height=g+"px";0<this.s.iLeftColumns&&(a.left.wrapper.style.width=e+"px",a.left.wrapper.style.height="1px",a.left.body.style.height=
+c+"px",a.left.foot&&(a.left.foot.style.top=(f.x?f.bar:0)+"px"),i(a.left.liner,e),a.left.liner.style.height=c+"px");0<this.s.iRightColumns&&(b-=h,f.y&&(b-=f.bar),a.right.wrapper.style.width=h+"px",a.right.wrapper.style.left=b+"px",a.right.wrapper.style.height="1px",a.right.body.style.height=c+"px",a.right.foot&&(a.right.foot.style.top=(f.x?f.bar:0)+"px"),i(a.right.liner,h),a.right.liner.style.height=c+"px",a.right.headBlock.style.display=f.y?"block":"none",a.right.footBlock.style.display=f.y?"block":
+"none")},_fnDTOverflow:function(){var a=this.s.dt.nTable,b=a.parentNode,c={x:!1,y:!1,bar:this.s.dt.oScroll.iBarWidth};a.offsetWidth>b.clientWidth&&(c.x=!0);a.offsetHeight>b.clientHeight&&(c.y=!0);return c},_fnDraw:function(a){this._fnGridLayout();this._fnCloneLeft(a);this._fnCloneRight(a);null!==this.s.fnDrawCallback&&this.s.fnDrawCallback.call(this,this.dom.clone.left,this.dom.clone.right);d(this).trigger("draw.dtfc",{leftClone:this.dom.clone.left,rightClone:this.dom.clone.right})},_fnCloneRight:function(a){if(!(0>=
+this.s.iRightColumns)){var b,c=[];for(b=this.s.iTableColumns-this.s.iRightColumns;b<this.s.iTableColumns;b++)this.s.dt.aoColumns[b].bVisible&&c.push(b);this._fnClone(this.dom.clone.right,this.dom.grid.right,c,a)}},_fnCloneLeft:function(a){if(!(0>=this.s.iLeftColumns)){var b,c=[];for(b=0;b<this.s.iLeftColumns;b++)this.s.dt.aoColumns[b].bVisible&&c.push(b);this._fnClone(this.dom.clone.left,this.dom.grid.left,c,a)}},_fnCopyLayout:function(a,b){for(var c=[],g=[],f=[],e=0,h=a.length;e<h;e++){var i=[];
+i.nTr=d(a[e].nTr).clone(!0,!0)[0];for(var k=0,j=this.s.iTableColumns;k<j;k++)if(-1!==d.inArray(k,b)){var m=d.inArray(a[e][k].cell,f);-1===m?(m=d(a[e][k].cell).clone(!0,!0)[0],g.push(m),f.push(a[e][k].cell),i.push({cell:m,unique:a[e][k].unique})):i.push({cell:g[m],unique:a[e][k].unique})}c.push(i)}return c},_fnClone:function(a,b,c,g){var f=this,e,h,i,k,j,m,o,n,q,l=this.s.dt;if(g){null!==a.header&&a.header.parentNode.removeChild(a.header);a.header=d(this.dom.header).clone(!0,!0)[0];a.header.className+=
+" DTFC_Cloned";a.header.style.width="100%";b.head.appendChild(a.header);n=this._fnCopyLayout(l.aoHeader,c);k=d(">thead",a.header);k.empty();e=0;for(h=n.length;e<h;e++)k[0].appendChild(n[e].nTr);l.oApi._fnDrawHead(l,n,!0)}else{n=this._fnCopyLayout(l.aoHeader,c);q=[];l.oApi._fnDetectHeader(q,d(">thead",a.header)[0]);e=0;for(h=n.length;e<h;e++){i=0;for(k=n[e].length;i<k;i++)q[e][i].cell.className=n[e][i].cell.className,d("span.DataTables_sort_icon",q[e][i].cell).each(function(){this.className=d("span.DataTables_sort_icon",
+n[e][i].cell)[0].className})}}this._fnEqualiseHeights("thead",this.dom.header,a.header);"auto"==this.s.sHeightMatch&&d(">tbody>tr",f.dom.body).css("height","auto");null!==a.body&&(a.body.parentNode.removeChild(a.body),a.body=null);a.body=d(this.dom.body).clone(!0)[0];a.body.className+=" DTFC_Cloned";a.body.style.paddingBottom=l.oScroll.iBarWidth+"px";a.body.style.marginBottom=2*l.oScroll.iBarWidth+"px";null!==a.body.getAttribute("id")&&a.body.removeAttribute("id");d(">thead>tr",a.body).empty();d(">tfoot",
+a.body).remove();var p=d("tbody",a.body)[0];d(p).empty();if(0<l.aiDisplay.length){h=d(">thead>tr",a.body)[0];for(o=0;o<c.length;o++)j=c[o],m=d(l.aoColumns[j].nTh).clone(!0)[0],m.innerHTML="",k=m.style,k.paddingTop="0",k.paddingBottom="0",k.borderTopWidth="0",k.borderBottomWidth="0",k.height=0,k.width=f.s.aiInnerWidths[j]+"px",h.appendChild(m);d(">tbody>tr",f.dom.body).each(function(a){var b=this.cloneNode(false);b.removeAttribute("id");a=f.s.dt.aoData[f.s.dt.oFeatures.bServerSide===false?f.s.dt.aiDisplay[f.s.dt._iDisplayStart+
+a]:a].anCells||d(this).children("td, th");for(o=0;o<c.length;o++){j=c[o];if(a.length>0){m=d(a[j]).clone(true,true)[0];b.appendChild(m)}}p.appendChild(b)})}else d(">tbody>tr",f.dom.body).each(function(){m=this.cloneNode(true);m.className=m.className+" DTFC_NoData";d("td",m).html("");p.appendChild(m)});a.body.style.width="100%";a.body.style.margin="0";a.body.style.padding="0";l.oScroller!==t&&(h=l.oScroller.dom.force,b.forcer?b.forcer.style.height=h.style.height:(b.forcer=h.cloneNode(!0),b.liner.appendChild(b.forcer)));
+b.liner.appendChild(a.body);this._fnEqualiseHeights("tbody",f.dom.body,a.body);if(null!==l.nTFoot){if(g){null!==a.footer&&a.footer.parentNode.removeChild(a.footer);a.footer=d(this.dom.footer).clone(!0,!0)[0];a.footer.className+=" DTFC_Cloned";a.footer.style.width="100%";b.foot.appendChild(a.footer);n=this._fnCopyLayout(l.aoFooter,c);b=d(">tfoot",a.footer);b.empty();e=0;for(h=n.length;e<h;e++)b[0].appendChild(n[e].nTr);l.oApi._fnDrawHead(l,n,!0)}else{n=this._fnCopyLayout(l.aoFooter,c);b=[];l.oApi._fnDetectHeader(b,
+d(">tfoot",a.footer)[0]);e=0;for(h=n.length;e<h;e++){i=0;for(k=n[e].length;i<k;i++)b[e][i].cell.className=n[e][i].cell.className}}this._fnEqualiseHeights("tfoot",this.dom.footer,a.footer)}b=l.oApi._fnGetUniqueThs(l,d(">thead",a.header)[0]);d(b).each(function(a){j=c[a];this.style.width=f.s.aiInnerWidths[j]+"px"});null!==f.s.dt.nTFoot&&(b=l.oApi._fnGetUniqueThs(l,d(">tfoot",a.footer)[0]),d(b).each(function(a){j=c[a];this.style.width=f.s.aiInnerWidths[j]+"px"}))},_fnGetTrNodes:function(a){for(var b=
+[],c=0,d=a.childNodes.length;c<d;c++)"TR"==a.childNodes[c].nodeName.toUpperCase()&&b.push(a.childNodes[c]);return b},_fnEqualiseHeights:function(a,b,c){if(!("none"==this.s.sHeightMatch&&"thead"!==a&&"tfoot"!==a)){var g,f,e=b.getElementsByTagName(a)[0],c=c.getElementsByTagName(a)[0],a=d(">"+a+">tr:eq(0)",b).children(":first");a.outerHeight();a.height();for(var e=this._fnGetTrNodes(e),b=this._fnGetTrNodes(c),h=[],c=0,a=b.length;c<a;c++)g=e[c].offsetHeight,f=b[c].offsetHeight,g=f>g?f:g,"semiauto"==this.s.sHeightMatch&&
+(e[c]._DTTC_iHeight=g),h.push(g);c=0;for(a=b.length;c<a;c++)b[c].style.height=h[c]+"px",e[c].style.height=h[c]+"px"}}};j.defaults={iLeftColumns:1,iRightColumns:0,fnDrawCallback:null,sHeightMatch:"semiauto"};j.version="3.0.4";d.fn.dataTable.FixedColumns=j;return d.fn.DataTable.FixedColumns=j};"function"===typeof define&&define.amd?define(["jquery","datatables"],p):"object"===typeof exports?p(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.FixedColumns&&p(jQuery,jQuery.fn.dataTable)})(window,
+document);
--- /dev/null
+# FixedHeader
+
+At times it can be useful to ensure that column titles will remain always visible on a table, even when a user scrolls down a table. The FixedHeader plug-in for DataTables will float the 'thead' element above the table at all times to help address this issue. The column titles also remain click-able to perform sorting. Key features include:
+
+* Fix the header to the top of the window
+* Ability to fix the footer and left / right columns as well
+* z-Index ordering options
+
+
+# Installation
+
+To use FixedHeader, first download DataTables ( http://datatables.net/download ) and place the unzipped FixedHeader package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser.
+
+
+# Basic usage
+
+FixedHeader is initialised using the `$.fn.dataTable.FixedHeader()` object. For example:
+
+```js
+$(document).ready( function () {
+ var table = $('#example').dataTable();
+ new $.fn.dataTable.FixedHeader( table );
+} );
+```
+
+
+# Documentation / support
+
+* Documentation: http://datatables.net/extensions/FixedHeader/
+* DataTables support forums: http://datatables.net/forums
+
+
+# GitHub
+
+If you fancy getting involved with the development of FixedHeader and help make it better, please refer to its GitHub repo: https://github.com/DataTables/FixedHeader
+
--- /dev/null
+div.FixedHeader_Cloned th,div.FixedHeader_Cloned td{background-color:white !important}
--- /dev/null
+/*!
+ FixedHeader 2.1.2
+ ©2010-2014 SpryMedia Ltd - datatables.net/license
+*/
+var FixedHeader;
+(function(j,k,h){var l=function(e){FixedHeader=function(a,b){if(!this instanceof FixedHeader)alert("FixedHeader warning: FixedHeader must be initialised with the 'new' keyword.");else{var c={aoCache:[],oSides:{top:!0,bottom:!1,left:0,right:0},oZIndexes:{top:104,bottom:103,left:102,right:101},oCloneOnDraw:{top:!1,bottom:!1,left:!0,right:!0},oMes:{iTableWidth:0,iTableHeight:0,iTableLeft:0,iTableRight:0,iTableTop:0,iTableBottom:0},oOffset:{top:0},nTable:null,bFooter:!1,bInitComplete:!1};this.fnGetSettings=
+function(){return c};this.fnUpdate=function(){this._fnUpdateClones();this._fnUpdatePositions()};this.fnPosition=function(){this._fnUpdatePositions()};var d=e.fn.dataTable.Api?(new e.fn.dataTable.Api(a)).settings()[0]:a.fnSettings();d._oPluginFixedHeader=this;this.fnInit(d,b)}};FixedHeader.prototype={fnInit:function(a,b){var c=this.fnGetSettings(),d=this;this.fnInitSettings(c,b);""!==a.oScroll.sX||""!==a.oScroll.sY?alert("FixedHeader 2 is not supported with DataTables' scrolling mode at this time"):
+(c.nTable=a.nTable,a.aoDrawCallback.unshift({fn:function(){FixedHeader.fnMeasure();d._fnUpdateClones.call(d);d._fnUpdatePositions.call(d)},sName:"FixedHeader"}),c.bFooter=0<e(">tfoot",c.nTable).length?!0:!1,c.oSides.top&&c.aoCache.push(d._fnCloneTable("fixedHeader","FixedHeader_Header",d._fnCloneThead)),c.oSides.bottom&&c.aoCache.push(d._fnCloneTable("fixedFooter","FixedHeader_Footer",d._fnCloneTfoot)),c.oSides.left&&c.aoCache.push(d._fnCloneTable("fixedLeft","FixedHeader_Left",d._fnCloneTLeft,c.oSides.left)),
+c.oSides.right&&c.aoCache.push(d._fnCloneTable("fixedRight","FixedHeader_Right",d._fnCloneTRight,c.oSides.right)),FixedHeader.afnScroll.push(function(){d._fnUpdatePositions.call(d)}),e(j).resize(function(){FixedHeader.fnMeasure();d._fnUpdateClones.call(d);d._fnUpdatePositions.call(d)}),e(c.nTable).on("column-reorder.dt",function(){FixedHeader.fnMeasure();d._fnUpdateClones(!0);d._fnUpdatePositions()}).on("column-visibility.dt",function(){FixedHeader.fnMeasure();d._fnUpdateClones(!0);d._fnUpdatePositions()}),
+FixedHeader.fnMeasure(),d._fnUpdateClones(),d._fnUpdatePositions(),c.bInitComplete=!0)},fnInitSettings:function(a,b){if(b!==h&&(b.top!==h&&(a.oSides.top=b.top),b.bottom!==h&&(a.oSides.bottom=b.bottom),"boolean"==typeof b.left?a.oSides.left=b.left?1:0:b.left!==h&&(a.oSides.left=b.left),"boolean"==typeof b.right?a.oSides.right=b.right?1:0:b.right!==h&&(a.oSides.right=b.right),b.zTop!==h&&(a.oZIndexes.top=b.zTop),b.zBottom!==h&&(a.oZIndexes.bottom=b.zBottom),b.zLeft!==h&&(a.oZIndexes.left=b.zLeft),b.zRight!==
+h&&(a.oZIndexes.right=b.zRight),b.offsetTop!==h&&(a.oOffset.top=b.offsetTop),b.alwaysCloneTop!==h&&(a.oCloneOnDraw.top=b.alwaysCloneTop),b.alwaysCloneBottom!==h&&(a.oCloneOnDraw.bottom=b.alwaysCloneBottom),b.alwaysCloneLeft!==h&&(a.oCloneOnDraw.left=b.alwaysCloneLeft),b.alwaysCloneRight!==h))a.oCloneOnDraw.right=b.alwaysCloneRight},_fnCloneTable:function(a,b,c,d){var f=this.fnGetSettings(),g;"absolute"!=e(f.nTable.parentNode).css("position")&&(f.nTable.parentNode.style.position="relative");g=f.nTable.cloneNode(!1);
+g.removeAttribute("id");var i=k.createElement("div");i.style.position="absolute";i.style.top="0px";i.style.left="0px";i.className+=" FixedHeader_Cloned "+a+" "+b;"fixedHeader"==a&&(i.style.zIndex=f.oZIndexes.top);"fixedFooter"==a&&(i.style.zIndex=f.oZIndexes.bottom);"fixedLeft"==a?i.style.zIndex=f.oZIndexes.left:"fixedRight"==a&&(i.style.zIndex=f.oZIndexes.right);g.style.margin="0";i.appendChild(g);k.body.appendChild(i);return{nNode:g,nWrapper:i,sType:a,sPosition:"",sTop:"",sLeft:"",fnClone:c,iCells:d}},
+_fnMeasure:function(){var a=this.fnGetSettings(),b=a.oMes,c=e(a.nTable),d=c.offset(),f=this._fnSumScroll(a.nTable.parentNode,"scrollTop");this._fnSumScroll(a.nTable.parentNode,"scrollLeft");b.iTableWidth=c.outerWidth();b.iTableHeight=c.outerHeight();b.iTableLeft=d.left+a.nTable.parentNode.scrollLeft;b.iTableTop=d.top+f;b.iTableRight=b.iTableLeft+b.iTableWidth;b.iTableRight=FixedHeader.oDoc.iWidth-b.iTableLeft-b.iTableWidth;b.iTableBottom=FixedHeader.oDoc.iHeight-b.iTableTop-b.iTableHeight},_fnSumScroll:function(a,
+b){for(var c=a[b];(a=a.parentNode)&&!("HTML"==a.nodeName||"BODY"==a.nodeName);)c=a[b];return c},_fnUpdatePositions:function(){var a=this.fnGetSettings();this._fnMeasure();for(var b=0,c=a.aoCache.length;b<c;b++)"fixedHeader"==a.aoCache[b].sType?this._fnScrollFixedHeader(a.aoCache[b]):"fixedFooter"==a.aoCache[b].sType?this._fnScrollFixedFooter(a.aoCache[b]):"fixedLeft"==a.aoCache[b].sType?this._fnScrollHorizontalLeft(a.aoCache[b]):this._fnScrollHorizontalRight(a.aoCache[b])},_fnUpdateClones:function(a){var b=
+this.fnGetSettings();a&&(b.bInitComplete=!1);for(var c=0,d=b.aoCache.length;c<d;c++)b.aoCache[c].fnClone.call(this,b.aoCache[c]);a&&(b.bInitComplete=!0)},_fnScrollHorizontalRight:function(a){var b=this.fnGetSettings().oMes,c=FixedHeader.oWin,d=FixedHeader.oDoc,f=a.nWrapper,g=e(f).outerWidth();c.iScrollRight<b.iTableRight?(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",f.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+b.iTableWidth-
+g+"px","left",f.style)):b.iTableLeft<d.iWidth-c.iScrollRight-g?(this._fnUpdateCache(a,"sPosition","fixed","position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop-c.iScrollTop+"px","top",f.style),this._fnUpdateCache(a,"sLeft",c.iWidth-g+"px","left",f.style)):(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",f.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",f.style))},_fnScrollHorizontalLeft:function(a){var b=this.fnGetSettings().oMes,
+c=FixedHeader.oWin,d=a.nWrapper,f=e(d).outerWidth();c.iScrollLeft<b.iTableLeft?(this._fnUpdateCache(a,"sPosition","absolute","position",d.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",d.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",d.style)):c.iScrollLeft<b.iTableLeft+b.iTableWidth-f?(this._fnUpdateCache(a,"sPosition","fixed","position",d.style),this._fnUpdateCache(a,"sTop",b.iTableTop-c.iScrollTop+"px","top",d.style),this._fnUpdateCache(a,"sLeft","0px","left",d.style)):
+(this._fnUpdateCache(a,"sPosition","absolute","position",d.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",d.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+b.iTableWidth-f+"px","left",d.style))},_fnScrollFixedFooter:function(a){var b=this.fnGetSettings(),c=b.oMes,d=FixedHeader.oWin,f=a.nWrapper,b=e("thead",b.nTable).outerHeight(),g=e(f).outerHeight();d.iScrollBottom<c.iTableBottom?(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",c.iTableTop+
+c.iTableHeight-g+"px","top",f.style),this._fnUpdateCache(a,"sLeft",c.iTableLeft+"px","left",f.style)):d.iScrollBottom<c.iTableBottom+c.iTableHeight-g-b?(this._fnUpdateCache(a,"sPosition","fixed","position",f.style),this._fnUpdateCache(a,"sTop",d.iHeight-g+"px","top",f.style),this._fnUpdateCache(a,"sLeft",c.iTableLeft-d.iScrollLeft+"px","left",f.style)):(this._fnUpdateCache(a,"sPosition","absolute","position",f.style),this._fnUpdateCache(a,"sTop",c.iTableTop+g+"px","top",f.style),this._fnUpdateCache(a,
+"sLeft",c.iTableLeft+"px","left",f.style))},_fnScrollFixedHeader:function(a){for(var b=this.fnGetSettings(),c=b.oMes,d=FixedHeader.oWin,e=a.nWrapper,g=0,i=b.nTable.getElementsByTagName("tbody"),h=0;h<i.length;++h)g+=i[h].offsetHeight;c.iTableTop>d.iScrollTop+b.oOffset.top?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",c.iTableTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",c.iTableLeft+"px","left",e.style)):d.iScrollTop+b.oOffset.top>c.iTableTop+
+g?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",c.iTableTop+g+"px","top",e.style),this._fnUpdateCache(a,"sLeft",c.iTableLeft+"px","left",e.style)):(this._fnUpdateCache(a,"sPosition","fixed","position",e.style),this._fnUpdateCache(a,"sTop",b.oOffset.top+"px","top",e.style),this._fnUpdateCache(a,"sLeft",c.iTableLeft-d.iScrollLeft+"px","left",e.style))},_fnUpdateCache:function(a,b,c,d,e){a[b]!=c&&(e[d]=c,a[b]=c)},_fnClassUpdate:function(a,b){var c=this;
+if("TR"===a.nodeName.toUpperCase()||"TH"===a.nodeName.toUpperCase()||"TD"===a.nodeName.toUpperCase()||"SPAN"===a.nodeName.toUpperCase())b.className=a.className;e(a).children().each(function(d){c._fnClassUpdate(e(a).children()[d],e(b).children()[d])})},_fnCloneThead:function(a){var b=this.fnGetSettings(),c=a.nNode;if(b.bInitComplete&&!b.oCloneOnDraw.top)this._fnClassUpdate(e("thead",b.nTable)[0],e("thead",c)[0]);else{var d=e(b.nTable).outerWidth();a.nWrapper.style.width=d+"px";for(c.style.width=d+
+"px";0<c.childNodes.length;)e("thead th",c).unbind("click"),c.removeChild(c.childNodes[0]);a=e("thead",b.nTable).clone(!0)[0];c.appendChild(a);var f=[],g=[];e("thead>tr th",b.nTable).each(function(){f.push(e(this).width())});e("thead>tr td",b.nTable).each(function(){g.push(e(this).width())});e("thead>tr th",b.nTable).each(function(a){e("thead>tr th:eq("+a+")",c).width(f[a]);e(this).width(f[a])});e("thead>tr td",b.nTable).each(function(a){e("thead>tr td:eq("+a+")",c).width(g[a]);e(this).width(g[a])});
+e("th.sorting, th.sorting_desc, th.sorting_asc",c).bind("click",function(){this.blur()})}},_fnCloneTfoot:function(a){var b=this.fnGetSettings(),c=a.nNode;for(a.nWrapper.style.width=e(b.nTable).outerWidth()+"px";0<c.childNodes.length;)c.removeChild(c.childNodes[0]);a=e("tfoot",b.nTable).clone(!0)[0];c.appendChild(a);e("tfoot:eq(0)>tr th",b.nTable).each(function(a){e("tfoot:eq(0)>tr th:eq("+a+")",c).width(e(this).width())});e("tfoot:eq(0)>tr td",b.nTable).each(function(a){e("tfoot:eq(0)>tr td:eq("+
+a+")",c).width(e(this).width())})},_fnCloneTLeft:function(a){for(var b=this.fnGetSettings(),c=a.nNode,d=e("tbody",b.nTable)[0];0<c.childNodes.length;)c.removeChild(c.childNodes[0]);c.appendChild(e("thead",b.nTable).clone(!0)[0]);c.appendChild(e("tbody",b.nTable).clone(!0)[0]);b.bFooter&&c.appendChild(e("tfoot",b.nTable).clone(!0)[0]);var f="gt("+(a.iCells-1)+")";e("thead tr",c).each(function(){e("th:"+f,this).remove()});e("tfoot tr",c).each(function(){e("th:"+f,this).remove()});e("tbody tr",c).each(function(){e("td:"+
+f,this).remove()});this.fnEqualiseHeights("thead",d.parentNode,c);this.fnEqualiseHeights("tbody",d.parentNode,c);this.fnEqualiseHeights("tfoot",d.parentNode,c);for(var g=d=0;g<a.iCells;g++)d+=e("thead tr th:eq("+g+")",b.nTable).outerWidth();c.style.width=d+"px";a.nWrapper.style.width=d+"px"},_fnCloneTRight:function(a){for(var b=this.fnGetSettings(),c=e("tbody",b.nTable)[0],d=a.nNode,f=e("tbody tr:eq(0) td",b.nTable).length;0<d.childNodes.length;)d.removeChild(d.childNodes[0]);d.appendChild(e("thead",
+b.nTable).clone(!0)[0]);d.appendChild(e("tbody",b.nTable).clone(!0)[0]);b.bFooter&&d.appendChild(e("tfoot",b.nTable).clone(!0)[0]);e("thead tr th:lt("+(f-a.iCells)+")",d).remove();e("tfoot tr th:lt("+(f-a.iCells)+")",d).remove();e("tbody tr",d).each(function(){e("td:lt("+(f-a.iCells)+")",this).remove()});this.fnEqualiseHeights("thead",c.parentNode,d);this.fnEqualiseHeights("tbody",c.parentNode,d);this.fnEqualiseHeights("tfoot",c.parentNode,d);for(var g=c=0;g<a.iCells;g++)c+=e("thead tr th:eq("+(f-
+1-g)+")",b.nTable).outerWidth();d.style.width=c+"px";a.nWrapper.style.width=c+"px"},fnEqualiseHeights:function(a,b,c){var d=e(a+" tr",b),f;e(a+" tr",c).each(function(a){f=d.eq(a).css("height");"Microsoft Internet Explorer"==navigator.appName&&(f=parseInt(f,10)+1);e(this).css("height",f);d.eq(a).css("height",f)})}};FixedHeader.oWin={iScrollTop:0,iScrollRight:0,iScrollBottom:0,iScrollLeft:0,iHeight:0,iWidth:0};FixedHeader.oDoc={iHeight:0,iWidth:0};FixedHeader.afnScroll=[];FixedHeader.fnMeasure=function(){var a=
+e(j),b=e(k),c=FixedHeader.oWin,d=FixedHeader.oDoc;d.iHeight=b.height();d.iWidth=b.width();c.iHeight=a.height();c.iWidth=a.width();c.iScrollTop=a.scrollTop();c.iScrollLeft=a.scrollLeft();c.iScrollRight=d.iWidth-c.iScrollLeft-c.iWidth;c.iScrollBottom=d.iHeight-c.iScrollTop-c.iHeight};FixedHeader.version="2.1.2";e(j).scroll(function(){FixedHeader.fnMeasure();for(var a=0,b=FixedHeader.afnScroll.length;a<b;a++)FixedHeader.afnScroll[a]()});e.fn.dataTable.FixedHeader=FixedHeader;return e.fn.DataTable.FixedHeader=
+FixedHeader};"function"===typeof define&&define.amd?define(["jquery","datatables"],l):"object"===typeof exports?l(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.FixedHeader&&l(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+# KeyTable
+
+KeyTable provides enhanced accessibility and navigation options for DataTables enhanced tables, by allowing Excel like cell navigation on any table. Events (focus, blur, action etc) can be assigned to individual cells, columns, rows or all cells to allow advanced interaction options.. Key features include:
+
+* Easy to use spreadsheet like interaction
+* Fully integrated with DataTables
+* Wide range of supported events
+
+
+# Installation
+
+To use KeyTable, first download DataTables ( http://datatables.net/download ) and place the unzipped KeyTable package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser.
+
+
+# Basic usage
+
+KeyTable is initialised using the `C` option that it adds to DataTables' `dom` option. For example:
+
+```js
+$(document).ready( function () {
+ var table = $('#example').DataTable();
+ new $.fn.dataTable.KeyTable( table );
+} );
+```
+
+
+# Documentation / support
+
+* Documentation: http://datatables.net/extensions/keytable/
+* DataTables support forums: http://datatables.net/forums
+
+
+# GitHub
+
+If you fancy getting involved with the development of KeyTable and help make it better, please refer to its GitHub repo: https://github.com/DataTables/KeyTable
+
--- /dev/null
+table.KeyTable th.focus,table.KeyTable td.focus{outline:3px solid #3366FF;outline-offset:-3px}
--- /dev/null
+/*!
+ KeyTable 1.2.1
+ ©2010-2014 SpryMedia Ltd - datatables.net/license
+*/
+var KeyTable;
+(function(F,n,K){var A=function(d){KeyTable=function(j){function A(a){return function(e,c,p){(null===e||"number"==typeof e)&&(null===c||"number"==typeof c)&&"function"==typeof p?k[a].push({x:e,y:c,fn:p}):"object"==typeof e&&"function"==typeof c?(e=E(e),k[a].push({x:e[0],y:e[1],fn:c})):alert("Unhandable event type was added: x"+e+" y:"+c+" z:"+p)}}function L(a){return function(e,c,p){(null===e||"number"==typeof e)&&(null===c||"number"==typeof c)?"function"==typeof p?B(a,e,c,p):B(a,e,c):"object"==
+typeof e?(e=E(e),"function"==typeof c?B(a,e[0],e[1],c):B(a,e[0],e[1])):alert("Unhandable event type was removed: x"+e+" y:"+c+" z:"+p)}}function B(a,e,c,p){for(var h=0,b=0,d=k[a].length;b<d-h;b++)if("undefined"!=typeof p)k[a][b-h].x==e&&(k[a][b-h].y==c&&k[a][b-h].fn==p)&&(k[a].splice(b-h,1),h++);else if(k[a][b-h].x==e&&k[a][b-h].y==c)return k[a].splice(b,1),1;return h}function C(a,e,c){for(var p=0,a=k[a],b=0;b<a.length;b++)if(a[b].x==e&&a[b].y==c||null===a[b].x&&a[b].y==c||a[b].x==e&&null===a[b].y||
+null===a[b].x&&null===a[b].y)a[b].fn(w(e,c),e,c),p++;return p}function q(a,e){if(t!=a){"undefined"==typeof e&&(e=!0);null!==t&&G(t);d(a).addClass(x);d(a).parent().addClass(x);var c;if(i){c=i;for(var b=H(a)[1],h=o;b>=c.fnDisplayEnd();)0<=c._iDisplayLength?c._iDisplayStart+c._iDisplayLength<c.fnRecordsDisplay()&&(c._iDisplayStart+=c._iDisplayLength):c._iDisplayStart=0,i.oApi._fnCalculateEnd(c);for(;b<c._iDisplayStart;)c._iDisplayStart=0<=c._iDisplayLength?c._iDisplayStart-c._iDisplayLength:0,0>c._iDisplayStart&&
+(c._iDisplayStart=0),i.oApi._fnCalculateEnd(c);i.oApi._fnDraw(c);o=h}b=E(a);t=a;l=b[0];g=b[1];var r,j,k,m,f;if(e){r=d(F).height();b=d(F).width();j=d(n).scrollTop();h=d(n).scrollLeft();k=a.offsetHeight;m=a.offsetWidth;f=a;var q=0,s=0;if(f.offsetParent){q=f.offsetLeft;s=f.offsetTop;for(f=f.offsetParent;f;)q+=f.offsetLeft,s+=f.offsetTop,f=f.offsetParent}f=[q,s];if(i&&"undefined"!=typeof c.oScroll&&(""!==c.oScroll.sX||""!==c.oScroll.sY))f[1]-=d(c.nTable.parentNode).scrollTop(),f[0]-=d(c.nTable.parentNode).scrollLeft();
+f[1]+k>j+r?(r=f[1]+k-r,n.documentElement.scrollTop=r,n.body.scrollTop=r):f[1]<j&&(r=f[1],n.documentElement.scrollTop=r,n.body.scrollTop=r);f[0]+m>h+b?(b=f[0]+m-b,n.documentElement.scrollLeft=b,n.body.scrollLeft=b):f[0]<h&&(b=f[0],n.documentElement.scrollLeft=b,n.body.scrollLeft=b)}if(i&&"undefined"!=typeof c.oScroll&&(""!==c.oScroll.sX||""!==c.oScroll.sY))(c=c.nTable.parentNode,r=c.clientHeight,b=c.clientWidth,j=c.scrollTop,h=c.scrollLeft,k=a.offsetHeight,m=a.offsetWidth,a.offsetTop+k>r+j?c.scrollTop=
+a.offsetTop+k-r:a.offsetTop<j&&(c.scrollTop=a.offsetTop),a.offsetLeft+m>b+h)?c.scrollLeft=a.offsetLeft+m-b:a.offsetLeft<h&&(c.scrollLeft=a.offsetLeft);o||(o=!0);C("focus",l,g)}}function y(){G(t);t=g=l=null;o=!1}function G(a){d(a).removeClass(x);d(a).parent().removeClass(x);C("blur",l,g)}function I(){for(var a=this;"TD"!=a.nodeName;)a=a.parentNode;q(a);o||(o=!0)}function w(a,b){return i?"undefined"!=typeof i.aoData[i.aiDisplay[b]]?i.aoData[i.aiDisplay[b]].nTr.getElementsByTagName("td")[a]:null:d("tr:eq("+
+b+")>td:eq("+a+")",z)[0]}function E(a){return i?[d("td",a.parentNode).index(a),d("tr",a.parentNode.parentNode).index(a.parentNode)+i._iDisplayStart]:[d("td",a.parentNode).index(a),d("tr",a.parentNode.parentNode).index(a.parentNode)]}function H(a){for(var b=0,c=i.aiDisplay.length;b<c;b++)for(var d=i.aoData[i.aiDisplay[b]].nTr.getElementsByTagName("td"),h=0,g=d.length;h<g;h++)if(d[h]==a)return[h,b];return null}this.block=!1;this.event={remove:{}};this.fnGetCurrentPosition=function(){return[l,g]};this.fnGetCurrentData=
+function(){return t.innerHTML};this.fnGetCurrentTD=function(){return t};this.fnSetPosition=function(a,b){"object"==typeof a&&a.nodeName?q(a):q(w(a,b))};this.fnBlur=function(){y()};var z=null,t=null,l=null,g=null,J=null,x="focus",o=!1,k={action:[],esc:[],focus:[],blur:[]},i=null,D,s,u=!1,m;for(m in k)m&&(this.event[m]=A(m),this.event.remove[m]=L(m));var v;j===K?(m=d("table.KeyTable")[0],v=null):d.isPlainObject(j)?(m=j.table,v=j.datatable):(v=(new d.fn.dataTable.Api(j)).settings()[0],m=v.nTable);var b=
+j,J=this;"undefined"==typeof b&&(b={});"undefined"==typeof b.focus&&(b.focus=[0,0]);b.table=m;d(b.table).addClass("KeyTable");"undefined"!=typeof b.focusClass&&(x=b.focusClass);"undefined"!=typeof v&&(i=v);"undefined"==typeof b.initScroll&&(b.initScroll=!0);"undefined"==typeof b.form&&(b.form=!1);D=b.form;z=b.table.getElementsByTagName("tbody")[0];D?(j=n.createElement("div"),s=n.createElement("input"),j.style.height="1px",j.style.width="0px",j.style.overflow="hidden","undefined"!=typeof b.tabIndex&&
+(s.tabIndex=b.tabIndex),j.appendChild(s),b.table.parentNode.insertBefore(j,b.table.nextSibling),d(s).focus(function(){if(!u){o=true;u=false;typeof b.focus.nodeName!="undefined"?q(b.focus,b.initScroll):q(w(b.focus[0],b.focus[1]),b.initScroll);setTimeout(function(){s.blur()},0)}}),o=!1):("undefined"!=typeof b.focus.nodeName?q(b.focus,b.initScroll):q(w(b.focus[0],b.focus[1]),b.initScroll),o||(o=!0));d(n).bind("keydown",function(a){if(J.block||!o||a.metaKey||a.altKey||a.ctrlKey)return true;var b;b=z.getElementsByTagName("tr")[0].getElementsByTagName("td").length;
+var c;if(i){c=i.aiDisplay.length;var d=H(t);if(d===null)return;l=d[0];g=d[1]}else c=z.getElementsByTagName("tr").length;d=a.keyCode==9&&a.shiftKey?-1:a.keyCode;switch(d){case 13:a.preventDefault();a.stopPropagation();C("action",l,g);return true;case 27:if(!C("esc",l,g)){y();return}a=l;b=g;break;case -1:case 37:if(l>0){a=l-1;b=g}else if(g>0){a=b-1;b=g-1}else{if(d==-1&&D){u=true;s.focus();setTimeout(function(){u=false},0);o=false;y();return true}return false}break;case 38:if(g>0){a=l;b=g-1}else return false;
+break;case 36:a=l;b=0;break;case 33:a=l;b=g-10;b<0&&(b=0);break;case 9:case 39:if(l<b-1){a=l+1;b=g}else if(g<c-1){a=0;b=g+1}else{if(d==9&&D){u=true;s.focus();setTimeout(function(){u=false},0);o=false;y();return true}return false}break;case 40:if(g<c-1){a=l;b=g+1}else return false;break;case 35:a=l;b=c-1;break;case 34:a=l;b=g+10;b>c-1&&(b=c-1);break;default:return true}q(w(a,b));return false});if(i)d(i.nTable).on("click","td",I);else d(z).on("click","td",I);d(n).click(function(a){for(var a=a.target,
+d=false;a;){if(a==b.table){d=true;break}a=a.parentNode}d||y()})};KeyTable.version="1.2.1";d.fn.dataTable.KeyTable=KeyTable;return d.fn.DataTable.KeyTable=KeyTable};"function"===typeof define&&define.amd?define(["jquery","datatables"],A):"object"===typeof exports?A(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.KeyTable&&A(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+Copyright (c) 2014-2015 SpryMedia Limited
+http://datatables.net
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child,
+table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child {
+ position: relative;
+ padding-left: 30px;
+ cursor: pointer;
+}
+table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child:before,
+table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child:before {
+ top: 8px;
+ left: 4px;
+ height: 16px;
+ width: 16px;
+ display: block;
+ position: absolute;
+ color: white;
+ border: 2px solid white;
+ border-radius: 16px;
+ text-align: center;
+ line-height: 14px;
+ box-shadow: 0 0 3px #444;
+ box-sizing: content-box;
+ content: '+';
+ background-color: #31b131;
+}
+table.dataTable.dtr-inline.collapsed > tbody > tr > td:first-child.dataTables_empty:before,
+table.dataTable.dtr-inline.collapsed > tbody > tr > th:first-child.dataTables_empty:before {
+ display: none;
+}
+table.dataTable.dtr-inline.collapsed > tbody > tr.parent > td:first-child:before,
+table.dataTable.dtr-inline.collapsed > tbody > tr.parent > th:first-child:before {
+ content: '-';
+ background-color: #d33333;
+}
+table.dataTable.dtr-inline.collapsed > tbody > tr.child td:before {
+ display: none;
+}
+table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child,
+table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child {
+ padding-left: 27px;
+}
+table.dataTable.dtr-inline.collapsed.compact > tbody > tr > td:first-child:before,
+table.dataTable.dtr-inline.collapsed.compact > tbody > tr > th:first-child:before {
+ top: 5px;
+ left: 4px;
+ height: 14px;
+ width: 14px;
+ border-radius: 14px;
+ line-height: 12px;
+}
+table.dataTable.dtr-column > tbody > tr > td.control,
+table.dataTable.dtr-column > tbody > tr > th.control {
+ position: relative;
+ cursor: pointer;
+}
+table.dataTable.dtr-column > tbody > tr > td.control:before,
+table.dataTable.dtr-column > tbody > tr > th.control:before {
+ top: 50%;
+ left: 50%;
+ height: 16px;
+ width: 16px;
+ margin-top: -10px;
+ margin-left: -10px;
+ display: block;
+ position: absolute;
+ color: white;
+ border: 2px solid white;
+ border-radius: 16px;
+ text-align: center;
+ line-height: 14px;
+ box-shadow: 0 0 3px #444;
+ box-sizing: content-box;
+ content: '+';
+ background-color: #31b131;
+}
+table.dataTable.dtr-column > tbody > tr.parent td.control:before,
+table.dataTable.dtr-column > tbody > tr.parent th.control:before {
+ content: '-';
+ background-color: #d33333;
+}
+table.dataTable > tbody > tr.child {
+ padding: 0.5em 1em;
+}
+table.dataTable > tbody > tr.child:hover {
+ background: transparent !important;
+}
+table.dataTable > tbody > tr.child ul {
+ display: inline-block;
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+}
+table.dataTable > tbody > tr.child ul li {
+ border-bottom: 1px solid #efefef;
+ padding: 0.5em 0;
+}
+table.dataTable > tbody > tr.child ul li:first-child {
+ padding-top: 0;
+}
+table.dataTable > tbody > tr.child ul li:last-child {
+ border-bottom: none;
+}
+table.dataTable > tbody > tr.child span.dtr-title {
+ display: inline-block;
+ min-width: 75px;
+ font-weight: bold;
+}
--- /dev/null
+
+//
+// Mixins
+//
+@mixin control() {
+ display: block;
+ position: absolute;
+ color: white;
+ border: 2px solid white;
+ border-radius: 16px;
+ text-align: center;
+ line-height: 14px;
+ box-shadow: 0 0 3px #444;
+ box-sizing: content-box;
+}
+
+@mixin control-open() {
+ content: '+';
+ background-color: #31b131;
+}
+
+@mixin control-close() {
+ content: '-';
+ background-color: #d33333;
+}
+
+
+//
+// Table styles
+//
+table.dataTable {
+ // Styling for the `inline` type
+ &.dtr-inline.collapsed > tbody {
+ > tr > td:first-child,
+ > tr > th:first-child {
+ position: relative;
+ padding-left: 30px;
+ cursor: pointer;
+
+ &:before {
+ top: 8px;
+ left: 4px;
+ height: 16px;
+ width: 16px;
+ @include control;
+ @include control-open;
+ }
+
+ &.dataTables_empty:before {
+ display: none;
+ }
+ }
+
+ > tr.parent {
+ > td:first-child:before,
+ > th:first-child:before {
+ @include control-close;
+ }
+ }
+
+ > tr.child td:before {
+ display: none;
+ }
+ }
+
+ // DataTables' `compact` styling
+ &.dtr-inline.collapsed.compact > tbody {
+ > tr > td:first-child,
+ > tr > th:first-child {
+ padding-left: 27px;
+
+ &:before {
+ top: 5px;
+ left: 4px;
+ height: 14px;
+ width: 14px;
+ border-radius: 14px;
+ line-height: 12px;
+ }
+ }
+ }
+
+
+ // Styling for the `column` type
+ &.dtr-column > tbody {
+ > tr > td.control,
+ > tr > th.control {
+ position: relative;
+ cursor: pointer;
+
+ &:before {
+ top: 50%;
+ left: 50%;
+ height: 16px;
+ width: 16px;
+ margin-top: -10px;
+ margin-left: -10px;
+ @include control;
+ @include control-open;
+ }
+ }
+
+ > tr.parent {
+ td.control:before,
+ th.control:before {
+ @include control-close;
+ }
+ }
+ }
+
+
+ // Child row styling
+ > tbody > tr.child {
+ padding: 0.5em 1em;
+
+ &:hover {
+ background: transparent !important;
+ }
+
+ ul {
+ display: inline-block;
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+
+ li {
+ border-bottom: 1px solid #efefef;
+ padding: 0.5em 0;
+
+ &:first-child {
+ padding-top: 0;
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+ }
+
+ span.dtr-title {
+ display: inline-block;
+ min-width: 75px;
+ font-weight: bold;
+ }
+
+ span.dtr-data {}
+ }
+}
+
--- /dev/null
+/*!
+ Responsive 1.0.6
+ 2014-2015 SpryMedia Ltd - datatables.net/license
+*/
+(function(n,p){var o=function(e,k){var h=function(d,a){if(!k.versionCheck||!k.versionCheck("1.10.1"))throw"DataTables Responsive requires DataTables 1.10.1 or newer";this.s={dt:new k.Api(d),columns:[]};this.s.dt.settings()[0].responsive||(a&&"string"===typeof a.details&&(a.details={type:a.details}),this.c=e.extend(!0,{},h.defaults,k.defaults.responsive,a),d.responsive=this,this._constructor())};h.prototype={_constructor:function(){var d=this,a=this.s.dt;a.settings()[0]._responsive=this;e(n).on("resize.dtr orientationchange.dtr",
+a.settings()[0].oApi._fnThrottle(function(){d._resize()}));a.on("destroy.dtr",function(){e(n).off("resize.dtr orientationchange.dtr draw.dtr")});this.c.breakpoints.sort(function(a,c){return a.width<c.width?1:a.width>c.width?-1:0});this._classLogic();this._resizeAuto();var c=this.c.details;c.type&&(d._detailsInit(),this._detailsVis(),a.on("column-visibility.dtr",function(){d._detailsVis()}),a.on("draw.dtr",function(){a.rows({page:"current"}).iterator("row",function(b,c){var f=a.row(c);if(f.child.isShown()){var i=
+d.c.details.renderer(a,c);f.child(i,"child").show()}})}),e(a.table().node()).addClass("dtr-"+c.type));this._resize()},_columnsVisiblity:function(d){var a=this.s.dt,c=this.s.columns,b,g,f=e.map(c,function(a){return a.auto&&null===a.minWidth?!1:!0===a.auto?"-":-1!==e.inArray(d,a.includeIn)}),i=0;b=0;for(g=f.length;b<g;b++)!0===f[b]&&(i+=c[b].minWidth);b=a.settings()[0].oScroll;b=b.sY||b.sX?b.iBarWidth:0;a=a.table().container().offsetWidth-b-i;b=0;for(g=f.length;b<g;b++)c[b].control&&(a-=c[b].minWidth);
+i=!1;b=0;for(g=f.length;b<g;b++)"-"===f[b]&&!c[b].control&&(i||0>a-c[b].minWidth?(i=!0,f[b]=!1):f[b]=!0,a-=c[b].minWidth);a=!1;b=0;for(g=c.length;b<g;b++)if(!c[b].control&&!c[b].never&&!f[b]){a=!0;break}b=0;for(g=c.length;b<g;b++)c[b].control&&(f[b]=a);-1===e.inArray(!0,f)&&(f[0]=!0);return f},_classLogic:function(){var d=this,a=this.c.breakpoints,c=this.s.dt.columns().eq(0).map(function(a){a=this.column(a).header().className;return{className:a,includeIn:[],auto:!1,control:!1,never:a.match(/\bnever\b/)?
+!0:!1}}),b=function(a,b){var d=c[a].includeIn;-1===e.inArray(b,d)&&d.push(b)},g=function(f,g,e,j){if(e)if("max-"===e){j=d._find(g).width;g=0;for(e=a.length;g<e;g++)a[g].width<=j&&b(f,a[g].name)}else if("min-"===e){j=d._find(g).width;g=0;for(e=a.length;g<e;g++)a[g].width>=j&&b(f,a[g].name)}else{if("not-"===e){g=0;for(e=a.length;g<e;g++)-1===a[g].name.indexOf(j)&&b(f,a[g].name)}}else c[f].includeIn.push(g)};c.each(function(b,c){for(var d=b.className.split(" "),j=!1,h=0,k=d.length;h<k;h++){var l=e.trim(d[h]);
+if("all"===l){j=!0;b.includeIn=e.map(a,function(a){return a.name});return}if("none"===l||"never"===l){j=!0;return}if("control"===l){j=!0;b.control=!0;return}e.each(a,function(a,b){var d=b.name.split("-"),e=l.match(RegExp("(min\\-|max\\-|not\\-)?("+d[0]+")(\\-[_a-zA-Z0-9])?"));e&&(j=!0,e[2]===d[0]&&e[3]==="-"+d[1]?g(c,b.name,e[1],e[2]+e[3]):e[2]===d[0]&&!e[3]&&g(c,b.name,e[1],e[2]))})}j||(b.auto=!0)});this.s.columns=c},_detailsInit:function(){var d=this,a=this.s.dt,c=this.c.details;"inline"===c.type&&
+(c.target="td:first-child");var b=c.target;e(a.table().body()).on("click","string"===typeof b?b:"td",function(){if(e(a.table().node()).hasClass("collapsed")&&a.row(e(this).closest("tr")).length){if(typeof b==="number"){var c=b<0?a.columns().eq(0).length+b:b;if(a.cell(this).index().column!==c)return}c=a.row(e(this).closest("tr"));if(c.child.isShown()){c.child(false);e(c.node()).removeClass("parent")}else{var f=d.c.details.renderer(a,c[0]);c.child(f,"child").show();e(c.node()).addClass("parent")}}})},
+_detailsVis:function(){var d=this,a=this.s.dt,c=a.columns().indexes().filter(function(b){var c=a.column(b);return c.visible()?null:e(c.header()).hasClass("never")?null:b}),b=!0;if(0===c.length||1===c.length&&this.s.columns[c[0]].control)b=!1;b?a.rows({page:"current"}).eq(0).each(function(b){b=a.row(b);if(b.child()){var c=d.c.details.renderer(a,b[0]);!1===c?b.child.hide():b.child(c,"child").show()}}):a.rows({page:"current"}).eq(0).each(function(b){a.row(b).child.hide()})},_find:function(d){for(var a=
+this.c.breakpoints,c=0,b=a.length;c<b;c++)if(a[c].name===d)return a[c]},_resize:function(){var d=this.s.dt,a=e(n).width(),c=this.c.breakpoints,b=c[0].name,g=this.s.columns,f;for(f=c.length-1;0<=f;f--)if(a<=c[f].width){b=c[f].name;break}var i=this._columnsVisiblity(b),c=!1;f=0;for(a=g.length;f<a;f++)if(!1===i[f]&&!g[f].never){c=!0;break}e(d.table().node()).toggleClass("collapsed",c);d.columns().eq(0).each(function(a,b){d.column(a).visible(i[b])})},_resizeAuto:function(){var d=this.s.dt,a=this.s.columns;
+if(this.c.auto&&-1!==e.inArray(!0,e.map(a,function(a){return a.auto}))){d.table().node();var c=d.table().node().cloneNode(!1),b=e(d.table().header().cloneNode(!1)).appendTo(c),g=e(d.table().body().cloneNode(!1)).appendTo(c);e(d.table().footer()).clone(!1).appendTo(c);d.rows({page:"current"}).indexes().flatten().each(function(a){var b=d.row(a).node().cloneNode(!0);d.columns(":hidden").flatten().length&&e(b).append(d.cells(a,":hidden").nodes().to$().clone());e(b).appendTo(g)});var f=d.columns().header().to$().clone(!1);
+e("<tr/>").append(f).appendTo(b);"inline"===this.c.details.type&&e(c).addClass("dtr-inline collapsed");c=e("<div/>").css({width:1,height:1,overflow:"hidden"}).append(c);c.find("th.never, td.never").remove();c.insertBefore(d.table().node());d.columns().eq(0).each(function(b){a[b].minWidth=f[b].offsetWidth||0});c.remove()}}};h.breakpoints=[{name:"desktop",width:Infinity},{name:"tablet-l",width:1024},{name:"tablet-p",width:768},{name:"mobile-l",width:480},{name:"mobile-p",width:320}];h.defaults={breakpoints:h.breakpoints,
+auto:!0,details:{renderer:function(d,a){var c=d.cells(a,":hidden").eq(0).map(function(a){var c=e(d.column(a.column).header()),a=d.cell(a).index();if(c.hasClass("control")||c.hasClass("never"))return"";var f=d.settings()[0],f=f.oApi._fnGetCellData(f,a.row,a.column,"display");(c=c.text())&&(c+=":");return'<li data-dtr-index="'+a.column+'"><span class="dtr-title">'+c+'</span> <span class="dtr-data">'+f+"</span></li>"}).toArray().join("");return c?e('<ul data-dtr-index="'+a+'"/>').append(c):!1},target:0,
+type:"inline"}};var m=e.fn.dataTable.Api;m.register("responsive()",function(){return this});m.register("responsive.index()",function(d){d=e(d);return{column:d.data("dtr-index"),row:d.parent().data("dtr-index")}});m.register("responsive.rebuild()",function(){return this.iterator("table",function(d){d._responsive&&d._responsive._classLogic()})});m.register("responsive.recalc()",function(){return this.iterator("table",function(d){d._responsive&&(d._responsive._resizeAuto(),d._responsive._resize())})});
+h.version="1.0.6";e.fn.dataTable.Responsive=h;e.fn.DataTable.Responsive=h;e(p).on("init.dt.dtr",function(d,a){if("dt"===d.namespace&&(e(a.nTable).hasClass("responsive")||e(a.nTable).hasClass("dt-responsive")||a.oInit.responsive||k.defaults.responsive)){var c=a.oInit.responsive;!1!==c&&new h(a,e.isPlainObject(c)?c:{})}});return h};"function"===typeof define&&define.amd?define(["jquery","datatables"],o):"object"===typeof exports?o(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.Responsive&&
+o(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+# Scroller
+
+Scroller is a virtual rendering plug-in for DataTables which allows large datasets to be drawn on screen every quickly. What the virtual rendering means is that only the visible portion of the table (and a bit to either side to make the scrolling smooth) is drawn, while the scrolling container gives the visual impression that the whole table is visible. This is done by making use of the pagination abilities of DataTables and moving the table around in the scrolling container DataTables adds to the page. The scrolling container is forced to the height it would be for the full table display using an extra element.
+
+Key features include:
+
+* Speed! The aim of Scroller for DataTables is to make rendering large data sets fast
+* Full compatibility with DataTables' deferred rendering for maximum speed
+* Integration with state saving in DataTables (scrolling position is saved)
+* Support for scrolling with millions of rows
+* Easy to use
+
+
+# Installation
+
+To use Scroller, first download DataTables ( http://datatables.net/download ) and place the unzipped Scroller package into a `extensions` directory in the DataTables package. This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser.
+
+
+# Basic usage
+
+Scroller is initialised by simply including the letter `dt-string S` in the `dt-init dom` for the table you want to have this feature enabled on. Note that the `dt-string S` must come after the `dt-string t` parameter in `dom`. For example:
+
+```js
+$(document).ready( function () {
+ $('#example').DataTable( {
+ dom: 'lfrtipS'
+ } );
+} );
+```
+
+Note that rows in the table must all be the same height. Information in a cell which expands on to multiple lines will cause some odd behaviour in the scrolling. Additionally, the table's `cellspacing` parameter must be set to 0, again to ensure the information display is correct.
+
+
+# Documentation / support
+
+* Documentation: http://datatables.net/extensions/scroller/
+* DataTables support forums: http://datatables.net/forums
+
+
+# GitHub
+
+If you fancy getting involved with the development of Scroller and help make it better, please refer to its GitHub repo: https://github.com/DataTables/Scroller
+
--- /dev/null
+div.DTS tbody th,div.DTS tbody td{white-space:nowrap}div.DTS tbody tr.even{background-color:white}div.DTS div.DTS_Loading{position:absolute;top:50%;left:50%;width:200px;height:20px;margin-top:-20px;margin-left:-100px;z-index:1;border:1px solid #999;padding:20px 0;text-align:center;background-color:white;background-color:rgba(255,255,255,0.5)}div.DTS div.dataTables_scrollHead,div.DTS div.dataTables_scrollFoot{background-color:white}div.DTS div.dataTables_scrollBody{z-index:2}div.DTS div.dataTables_scroll{background:url("../images/loading-background.png") repeat 0 0}
--- /dev/null
+/*!
+ Scroller 1.2.2
+ ©2011-2014 SpryMedia Ltd - datatables.net/license
+*/
+(function(m,n,k){var l=function(e){var g=function(a,b){!this instanceof g?alert("Scroller warning: Scroller must be initialised with the 'new' keyword."):("undefined"==typeof b&&(b={}),this.s={dt:a,tableTop:0,tableBottom:0,redrawTop:0,redrawBottom:0,autoHeight:!0,viewportRows:0,stateTO:null,drawTO:null,heights:{jump:null,page:null,virtual:null,scroll:null,row:null,viewport:null},topRowFloat:0,scrollDrawDiff:null,loaderVisible:!1},this.s=e.extend(this.s,g.oDefaults,b),this.s.heights.row=this.s.rowHeight,
+this.dom={force:n.createElement("div"),scroller:null,table:null,loader:null},this.s.dt.oScroller=this,this._fnConstruct())};g.prototype={fnRowToPixels:function(a,b,c){a=c?this._domain("virtualToPhysical",a*this.s.heights.row):this.s.baseScrollTop+(a-this.s.baseRowTop)*this.s.heights.row;return b||b===k?parseInt(a,10):a},fnPixelsToRow:function(a,b,c){var d=a-this.s.baseScrollTop,a=c?this._domain("physicalToVirtual",a)/this.s.heights.row:d/this.s.heights.row+this.s.baseRowTop;return b||b===k?parseInt(a,
+10):a},fnScrollToRow:function(a,b){var c=this,d=!1,f=this.fnRowToPixels(a),h=a-(this.s.displayBuffer-1)/2*this.s.viewportRows;0>h&&(h=0);if((f>this.s.redrawBottom||f<this.s.redrawTop)&&this.s.dt._iDisplayStart!==h)d=!0,f=this.fnRowToPixels(a,!1,!0);"undefined"==typeof b||b?(this.s.ani=d,e(this.dom.scroller).animate({scrollTop:f},function(){setTimeout(function(){c.s.ani=!1},25)})):e(this.dom.scroller).scrollTop(f)},fnMeasure:function(a){this.s.autoHeight&&this._fnCalcRowHeight();var b=this.s.heights;
+b.viewport=e(this.dom.scroller).height();this.s.viewportRows=parseInt(b.viewport/b.row,10)+1;this.s.dt._iDisplayLength=this.s.viewportRows*this.s.displayBuffer;(a===k||a)&&this.s.dt.oInstance.fnDraw()},_fnConstruct:function(){var a=this;if(this.s.dt.oFeatures.bPaginate){this.dom.force.style.position="absolute";this.dom.force.style.top="0px";this.dom.force.style.left="0px";this.dom.force.style.width="1px";this.dom.scroller=e("div."+this.s.dt.oClasses.sScrollBody,this.s.dt.nTableWrapper)[0];this.dom.scroller.appendChild(this.dom.force);
+this.dom.scroller.style.position="relative";this.dom.table=e(">table",this.dom.scroller)[0];this.dom.table.style.position="absolute";this.dom.table.style.top="0px";this.dom.table.style.left="0px";e(this.s.dt.nTableWrapper).addClass("DTS");this.s.loadingIndicator&&(this.dom.loader=e('<div class="DTS_Loading">'+this.s.dt.oLanguage.sLoadingRecords+"</div>").css("display","none"),e(this.dom.scroller.parentNode).css("position","relative").append(this.dom.loader));this.s.heights.row&&"auto"!=this.s.heights.row&&
+(this.s.autoHeight=!1);this.fnMeasure(!1);this.s.ingnoreScroll=!0;this.s.stateSaveThrottle=this.s.dt.oApi._fnThrottle(function(){a.s.dt.oApi._fnSaveState(a.s.dt)},500);e(this.dom.scroller).on("scroll.DTS",function(){a._fnScroll.call(a)});e(this.dom.scroller).on("touchstart.DTS",function(){a._fnScroll.call(a)});this.s.dt.aoDrawCallback.push({fn:function(){a.s.dt.bInitialised&&a._fnDrawCallback.call(a)},sName:"Scroller"});e(m).on("resize.DTS",function(){a.fnMeasure(false);a._fnInfo()});var b=!0;this.s.dt.oApi._fnCallbackReg(this.s.dt,
+"aoStateSaveParams",function(c,d){if(b&&a.s.dt.oLoadedState){d.iScroller=a.s.dt.oLoadedState.iScroller;d.iScrollerTopRow=a.s.dt.oLoadedState.iScrollerTopRow;b=false}else{d.iScroller=a.dom.scroller.scrollTop;d.iScrollerTopRow=a.s.topRowFloat}},"Scroller_State");this.s.dt.oLoadedState&&(this.s.topRowFloat=this.s.dt.oLoadedState.iScrollerTopRow||0);this.s.dt.aoDestroyCallback.push({sName:"Scroller",fn:function(){e(m).off("resize.DTS");e(a.dom.scroller).off("touchstart.DTS scroll.DTS");e(a.s.dt.nTableWrapper).removeClass("DTS");
+e("div.DTS_Loading",a.dom.scroller.parentNode).remove();a.dom.table.style.position="";a.dom.table.style.top="";a.dom.table.style.left=""}})}else this.s.dt.oApi._fnLog(this.s.dt,0,"Pagination must be enabled for Scroller")},_fnScroll:function(){var a=this,b=this.s.heights,c=this.dom.scroller.scrollTop,d;if(!this.s.skip&&!this.s.ingnoreScroll)if(this.s.dt.bFiltered||this.s.dt.bSorted)this.s.lastScrollTop=0;else{this._fnInfo();clearTimeout(this.s.stateTO);this.s.stateTO=setTimeout(function(){a.s.dt.oApi._fnSaveState(a.s.dt)},
+250);if(c<this.s.redrawTop||c>this.s.redrawBottom){var f=Math.ceil((this.s.displayBuffer-1)/2*this.s.viewportRows);Math.abs(c-this.s.lastScrollTop)>b.viewport||this.s.ani?(d=parseInt(this._domain("physicalToVirtual",c)/b.row,10)-f,this.s.topRowFloat=this._domain("physicalToVirtual",c)/b.row):(d=this.fnPixelsToRow(c)-f,this.s.topRowFloat=this.fnPixelsToRow(c,!1));0>=d?d=0:d+this.s.dt._iDisplayLength>this.s.dt.fnRecordsDisplay()?(d=this.s.dt.fnRecordsDisplay()-this.s.dt._iDisplayLength,0>d&&(d=0)):
+0!==d%2&&d++;if(d!=this.s.dt._iDisplayStart&&(this.s.tableTop=e(this.s.dt.nTable).offset().top,this.s.tableBottom=e(this.s.dt.nTable).height()+this.s.tableTop,b=function(){if(a.s.scrollDrawReq===null)a.s.scrollDrawReq=c;a.s.dt._iDisplayStart=d;a.s.dt.oApi._fnCalculateEnd&&a.s.dt.oApi._fnCalculateEnd(a.s.dt);a.s.dt.oApi._fnDraw(a.s.dt)},this.s.dt.oFeatures.bServerSide?(clearTimeout(this.s.drawTO),this.s.drawTO=setTimeout(b,this.s.serverWait)):b(),this.dom.loader&&!this.s.loaderVisible))this.dom.loader.css("display",
+"block"),this.s.loaderVisible=!0}this.s.lastScrollTop=c;this.s.stateSaveThrottle()}},_domain:function(a,b){var c=this.s.heights,d;if(c.virtual===c.scroll){d=(c.virtual-c.viewport)/(c.scroll-c.viewport);if("virtualToPhysical"===a)return b/d;if("physicalToVirtual"===a)return b*d}var e=(c.scroll-c.viewport)/2,h=(c.virtual-c.viewport)/2;d=h/(e*e);if("virtualToPhysical"===a){if(b<h)return Math.pow(b/d,0.5);b=2*h-b;return 0>b?c.scroll:2*e-Math.pow(b/d,0.5)}if("physicalToVirtual"===a){if(b<e)return b*b*
+d;b=2*e-b;return 0>b?c.virtual:2*h-b*b*d}},_fnDrawCallback:function(){var a=this,b=this.s.heights,c=this.dom.scroller.scrollTop,d=e(this.s.dt.nTable).height(),f=this.s.dt._iDisplayStart,h=this.s.dt._iDisplayLength,g=this.s.dt.fnRecordsDisplay();this.s.skip=!0;this._fnScrollForce();c=0===f?this.s.topRowFloat*b.row:f+h>=g?b.scroll-(g-this.s.topRowFloat)*b.row:this._domain("virtualToPhysical",this.s.topRowFloat*b.row);this.dom.scroller.scrollTop=c;this.s.baseScrollTop=c;this.s.baseRowTop=this.s.topRowFloat;
+var j=c-(this.s.topRowFloat-f)*b.row;0===f?j=0:f+h>=g&&(j=b.scroll-d);this.dom.table.style.top=j+"px";this.s.tableTop=j;this.s.tableBottom=d+this.s.tableTop;d=(c-this.s.tableTop)*this.s.boundaryScale;this.s.redrawTop=c-d;this.s.redrawBottom=c+d;this.s.skip=!1;this.s.dt.oFeatures.bStateSave&&null!==this.s.dt.oLoadedState&&"undefined"!=typeof this.s.dt.oLoadedState.iScroller?((c=(this.s.dt.sAjaxSource||a.s.dt.ajax)&&!this.s.dt.oFeatures.bServerSide?!0:!1)&&2==this.s.dt.iDraw||!c&&1==this.s.dt.iDraw)&&
+setTimeout(function(){e(a.dom.scroller).scrollTop(a.s.dt.oLoadedState.iScroller);a.s.redrawTop=a.s.dt.oLoadedState.iScroller-b.viewport/2;setTimeout(function(){a.s.ingnoreScroll=!1},0)},0):a.s.ingnoreScroll=!1;setTimeout(function(){a._fnInfo.call(a)},0);this.dom.loader&&this.s.loaderVisible&&(this.dom.loader.css("display","none"),this.s.loaderVisible=!1)},_fnScrollForce:function(){var a=this.s.heights;a.virtual=a.row*this.s.dt.fnRecordsDisplay();a.scroll=a.virtual;1E6<a.scroll&&(a.scroll=1E6);this.dom.force.style.height=
+a.scroll+"px"},_fnCalcRowHeight:function(){var a=this.s.dt,b=a.nTable,c=b.cloneNode(!1),d=e("<tbody/>").appendTo(c),f=e('<div class="'+a.oClasses.sWrapper+' DTS"><div class="'+a.oClasses.sScrollWrapper+'"><div class="'+a.oClasses.sScrollBody+'"></div></div></div>');for(e("tbody tr:lt(4)",b).clone().appendTo(d);3>e("tr",d).length;)d.append("<tr><td> </td></tr>");e("div."+a.oClasses.sScrollBody,f).append(c);a._bInitComplete?a=b.parentNode:(this.s.dt.nHolding||(this.s.dt.nHolding=e("<div></div>").insertBefore(this.s.dt.nTable)),
+a=this.s.dt.nHolding);f.appendTo(a);this.s.heights.row=e("tr",d).eq(1).outerHeight();f.remove()},_fnInfo:function(){if(this.s.dt.oFeatures.bInfo){var a=this.s.dt,b=a.oLanguage,c=this.dom.scroller.scrollTop,d=Math.floor(this.fnPixelsToRow(c,!1,this.s.ani)+1),f=a.fnRecordsTotal(),h=a.fnRecordsDisplay(),c=Math.ceil(this.fnPixelsToRow(c+this.s.heights.viewport,!1,this.s.ani)),c=h<c?h:c,g=a.fnFormatNumber(d),j=a.fnFormatNumber(c),i=a.fnFormatNumber(f),k=a.fnFormatNumber(h),g=0===a.fnRecordsDisplay()&&
+a.fnRecordsDisplay()==a.fnRecordsTotal()?b.sInfoEmpty+b.sInfoPostFix:0===a.fnRecordsDisplay()?b.sInfoEmpty+" "+b.sInfoFiltered.replace("_MAX_",i)+b.sInfoPostFix:a.fnRecordsDisplay()==a.fnRecordsTotal()?b.sInfo.replace("_START_",g).replace("_END_",j).replace("_MAX_",i).replace("_TOTAL_",k)+b.sInfoPostFix:b.sInfo.replace("_START_",g).replace("_END_",j).replace("_MAX_",i).replace("_TOTAL_",k)+" "+b.sInfoFiltered.replace("_MAX_",a.fnFormatNumber(a.fnRecordsTotal()))+b.sInfoPostFix;(b=b.fnInfoCallback)&&
+(g=b.call(a.oInstance,a,d,c,f,h,g));a=a.aanFeatures.i;if("undefined"!=typeof a){d=0;for(f=a.length;d<f;d++)e(a[d]).html(g)}}}};g.defaults={trace:!1,rowHeight:"auto",serverWait:200,displayBuffer:9,boundaryScale:0.5,loadingIndicator:!1};g.oDefaults=g.defaults;g.version="1.2.2";"function"==typeof e.fn.dataTable&&"function"==typeof e.fn.dataTableExt.fnVersionCheck&&e.fn.dataTableExt.fnVersionCheck("1.9.0")?e.fn.dataTableExt.aoFeatures.push({fnInit:function(a){var b=a.oInit;return(new g(a,b.scroller||
+b.oScroller||{})).dom.wrapper},cFeature:"S",sFeature:"Scroller"}):alert("Warning: Scroller requires DataTables 1.9.0 or greater - www.datatables.net/download");e.fn.dataTable.Scroller=g;e.fn.DataTable.Scroller=g;if(e.fn.dataTable.Api){var i=e.fn.dataTable.Api;i.register("scroller()",function(){return this});i.register("scroller().rowToPixels()",function(a,b,c){var d=this.context;if(d.length&&d[0].oScroller)return d[0].oScroller.fnRowToPixels(a,b,c)});i.register("scroller().pixelsToRow()",function(a,
+b,c){var d=this.context;if(d.length&&d[0].oScroller)return d[0].oScroller.fnPixelsToRow(a,b,c)});i.register("scroller().scrollToRow()",function(a,b){this.iterator("table",function(c){c.oScroller&&c.oScroller.fnScrollToRow(a,b)});return this});i.register("scroller().measure()",function(a){this.iterator("table",function(b){b.oScroller&&b.oScroller.fnMeasure(a)});return this})}return g};"function"===typeof define&&define.amd?define(["jquery","datatables"],l):"object"===typeof exports?l(require("jquery"),
+require("datatables")):jQuery&&!jQuery.fn.dataTable.Scroller&&l(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+# TableTools
+
+TableTools is a plug-in for the DataTables HTML table enhancer, which adds a highly customisable button toolbar to a DataTable. Key features include:
+
+* Copy to clipboard
+* Save table data as CSV, XLS or PDF files
+* Print view for clean printing
+* Row selection options
+* Easy use predefined buttons
+* Simple customisation of buttons
+* Well defined API for advanced control
+
+
+# Installation
+
+To use TableTools, first download DataTables ( http://datatables.net/download ) and place the unzipped TableTools package into a `extensions` directory in the DataTables package (in DataTables 1.9- use the `extras` directory). This will allow the pages in the examples to operate correctly. To see the examples running, open the `examples` directory in your web-browser.
+
+
+# Basic usage
+
+TableTools is initialised using the `T` option that it adds to DataTables' `dom` option. For example:
+
+```js
+$(document).ready( function () {
+ $('#example').DataTable( {
+ dom: 'T<"clear">lfrtip'
+ } );
+} );
+```
+
+
+# Documentation / support
+
+* Documentation: http://datatables.net/extensions/tabletools/
+* DataTables support forums: http://datatables.net/forums
+
+
+# GitHub
+
+If you fancy getting involved with the development of TableTools and help make it better, please refer to its GitHub repo: https://github.com/DataTables/TableTools
+
--- /dev/null
+div.DTTT_container{position:relative;float:right;margin-bottom:1em}@media screen and (max-width: 640px){div.DTTT_container{float:none !important;text-align:center}div.DTTT_container:after{visibility:hidden;display:block;content:"";clear:both;height:0}}button.DTTT_button,div.DTTT_button,a.DTTT_button{position:relative;display:inline-block;margin-right:3px;padding:5px 8px;border:1px solid #999;cursor:pointer;*cursor:hand;font-size:0.88em;color:black !important;-webkit-border-radius:2px;-moz-border-radius:2px;-ms-border-radius:2px;-o-border-radius:2px;border-radius:2px;-webkit-box-shadow:1px 1px 3px #ccc;-moz-box-shadow:1px 1px 3px #ccc;-ms-box-shadow:1px 1px 3px #ccc;-o-box-shadow:1px 1px 3px #ccc;box-shadow:1px 1px 3px #ccc;background:#ffffff;background:-webkit-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-moz-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-ms-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-o-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f9f9f9',GradientType=0 )}button.DTTT_button{height:30px;padding:3px 8px}.DTTT_button embed{outline:none}button.DTTT_button:hover:not(.DTTT_disabled),div.DTTT_button:hover:not(.DTTT_disabled),a.DTTT_button:hover:not(.DTTT_disabled){border:1px solid #666;text-decoration:none !important;-webkit-box-shadow:1px 1px 3px #999;-moz-box-shadow:1px 1px 3px #999;-ms-box-shadow:1px 1px 3px #999;-o-box-shadow:1px 1px 3px #999;box-shadow:1px 1px 3px #999;background:#f3f3f3;background:-webkit-linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);background:-moz-linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);background:-ms-linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);background:-o-linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);background:linear-gradient(top, #f3f3f3 0%, #e2e2e2 89%, #f4f4f4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3f3f3', endColorstr='#f4f4f4',GradientType=0 )}button.DTTT_button:focus,div.DTTT_button:focus,a.DTTT_button:focus{border:1px solid #426c9e;text-shadow:0 1px 0 #c4def1;outline:none;background-color:#a3d0ef 100%;background-image:-webkit-linear-gradient(top, #a3d0ef 0%, #79ace9 65%, #a3d0ef 100%);background-image:-moz-linear-gradient(top, #a3d0ef 0%, #79ace9 65%, #a3d0ef 100%);background-image:-ms-linear-gradient(top, #a3d0ef 0%, #79ace9 65%, #a3d0ef 100%);background-image:-o-linear-gradient(top, #a3d0ef 0%, #79ace9 65%, #a3d0ef 100%);background-image:linear-gradient(top, #a3d0ef 0%, #79ace9 65%, #a3d0ef 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#a3d0ef', EndColorStr='#a3d0ef')}button.DTTT_button:active:not(.DTTT_disabled),div.DTTT_button:active:not(.DTTT_disabled),a.DTTT_button:active:not(.DTTT_disabled){-webkit-box-shadow:inset 1px 1px 3px #999999;-moz-box-shadow:inset 1px 1px 3px #999999;box-shadow:inset 1px 1px 3px #999999}button.DTTT_disabled,div.DTTT_disabled,a.DTTT_disabled{color:#999 !important;border:1px solid #d0d0d0;cursor:default;background:#ffffff;background:-webkit-linear-gradient(top, #fff 0%, #f9f9f9 89%, #fafafa 100%);background:-moz-linear-gradient(top, #fff 0%, #f9f9f9 89%, #fafafa 100%);background:-ms-linear-gradient(top, #fff 0%, #f9f9f9 89%, #fafafa 100%);background:-o-linear-gradient(top, #fff 0%, #f9f9f9 89%, #fafafa 100%);background:linear-gradient(top, #fff 0%, #f9f9f9 89%, #fafafa 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#fafafa',GradientType=0 )}button.DTTT_button_collection span{padding-right:17px;background:url(../images/collection.png) no-repeat center right}button.DTTT_button_collection:hover span{padding-right:17px;background:#f0f0f0 url(../images/collection_hover.png) no-repeat center right}table.DTTT_selectable tbody tr{cursor:pointer;*cursor:hand}table.dataTable tr.DTTT_selected.odd{background-color:#9FAFD1}table.dataTable tr.DTTT_selected.odd td.sorting_1{background-color:#9FAFD1}table.dataTable tr.DTTT_selected.odd td.sorting_2{background-color:#9FAFD1}table.dataTable tr.DTTT_selected.odd td.sorting_3{background-color:#9FAFD1}table.dataTable tr.DTTT_selected.even{background-color:#B0BED9}table.dataTable tr.DTTT_selected.even td.sorting_1{background-color:#B0BED9}table.dataTable tr.DTTT_selected.even td.sorting_2{background-color:#B0BED9}table.dataTable tr.DTTT_selected.even td.sorting_3{background-color:#B0BED9}div.DTTT_collection{width:150px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.4);background-color:#f3f3f3;background-color:rgba(255,255,255,0.3);overflow:hidden;z-index:2002;-webkit-border-radius:5px;-moz-border-radius:5px;-ms-border-radius:5px;-o-border-radius:5px;border-radius:5px;-webkit-box-shadow:3px 3px 5px rgba(0,0,0,0.3);-moz-box-shadow:3px 3px 5px rgba(0,0,0,0.3);-ms-box-shadow:3px 3px 5px rgba(0,0,0,0.3);-o-box-shadow:3px 3px 5px rgba(0,0,0,0.3);box-shadow:3px 3px 5px rgba(0,0,0,0.3)}div.DTTT_collection_background{background:black;z-index:2001}div.DTTT_collection button.DTTT_button,div.DTTT_collection div.DTTT_button,div.DTTT_collection a.DTTT_button{position:relative;left:0;right:0;display:block;float:none;margin-bottom:4px;-webkit-box-shadow:1px 1px 3px #999;-moz-box-shadow:1px 1px 3px #999;-ms-box-shadow:1px 1px 3px #999;-o-box-shadow:1px 1px 3px #999;box-shadow:1px 1px 3px #999}.DTTT_print_info{position:fixed;top:50%;left:50%;width:400px;height:150px;margin-left:-200px;margin-top:-75px;text-align:center;color:#333;padding:10px 30px;background:#ffffff;background:-webkit-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-moz-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-ms-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:-o-linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);background:linear-gradient(top, #fff 0%, #f3f3f3 89%, #f9f9f9 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f9f9f9',GradientType=0 );opacity:0.95;border:1px solid black;border:1px solid rgba(0,0,0,0.5);-webkit-border-radius:6px;-moz-border-radius:6px;-ms-border-radius:6px;-o-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.5);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.5);-ms-box-shadow:0 3px 7px rgba(0,0,0,0.5);-o-box-shadow:0 3px 7px rgba(0,0,0,0.5);box-shadow:0 3px 7px rgba(0,0,0,0.5)}.DTTT_print_info h6{font-weight:normal;font-size:28px;line-height:28px;margin:1em}.DTTT_print_info p{font-size:14px;line-height:20px}
--- /dev/null
+/*!
+ TableTools 2.2.4
+ 2009-2015 SpryMedia Ltd - datatables.net/license
+
+ ZeroClipboard 1.0.4
+ Author: Joseph Huckaby - MIT licensed
+*/
+var TableTools;
+(function(n,k,q){var p=function(m,p){var g={version:"1.0.4-TableTools2",clients:{},moviePath:"",nextId:1,$:function(a){"string"==typeof a&&(a=k.getElementById(a));a.addClass||(a.hide=function(){this.style.display="none"},a.show=function(){this.style.display=""},a.addClass=function(a){this.removeClass(a);this.className+=" "+a},a.removeClass=function(a){this.className=this.className.replace(RegExp("\\s*"+a+"\\s*")," ").replace(/^\s+/,"").replace(/\s+$/,"")},a.hasClass=function(a){return!!this.className.match(RegExp("\\s*"+a+
+"\\s*"))});return a},setMoviePath:function(a){this.moviePath=a},dispatch:function(a,b,c){(a=this.clients[a])&&a.receiveEvent(b,c)},register:function(a,b){this.clients[a]=b},getDOMObjectPosition:function(a){var b={left:0,top:0,width:a.width?a.width:a.offsetWidth,height:a.height?a.height:a.offsetHeight};""!==a.style.width&&(b.width=a.style.width.replace("px",""));""!==a.style.height&&(b.height=a.style.height.replace("px",""));for(;a;)b.left+=a.offsetLeft,b.top+=a.offsetTop,a=a.offsetParent;return b},
+Client:function(a){this.handlers={};this.id=g.nextId++;this.movieId="ZeroClipboard_TableToolsMovie_"+this.id;g.register(this.id,this);a&&this.glue(a)}};g.Client.prototype={id:0,ready:!1,movie:null,clipText:"",fileName:"",action:"copy",handCursorEnabled:!0,cssEffects:!0,handlers:null,sized:!1,glue:function(a,b){this.domElement=g.$(a);var c=99;this.domElement.style.zIndex&&(c=parseInt(this.domElement.style.zIndex,10)+1);var d=g.getDOMObjectPosition(this.domElement);this.div=k.createElement("div");var f=
+this.div.style;f.position="absolute";f.left="0px";f.top="0px";f.width=d.width+"px";f.height=d.height+"px";f.zIndex=c;"undefined"!=typeof b&&""!==b&&(this.div.title=b);0!==d.width&&0!==d.height&&(this.sized=!0);this.domElement&&(this.domElement.appendChild(this.div),this.div.innerHTML=this.getHTML(d.width,d.height).replace(/&/g,"&"))},positionElement:function(){var a=g.getDOMObjectPosition(this.domElement),b=this.div.style;b.position="absolute";b.width=a.width+"px";b.height=a.height+"px";0!==a.width&&
+0!==a.height&&(this.sized=!0,b=this.div.childNodes[0],b.width=a.width,b.height=a.height)},getHTML:function(a,b){var c="",d="id="+this.id+"&width="+a+"&height="+b;if(navigator.userAgent.match(/MSIE/))var f=location.href.match(/^https/i)?"https://":"http://",c=c+('<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+f+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0" width="'+a+'" height="'+b+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+
+g.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+d+'"/><param name="wmode" value="transparent"/></object>');else c+='<embed id="'+this.movieId+'" src="'+g.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+a+'" height="'+b+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+
+d+'" wmode="transparent" />';return c},hide:function(){this.div&&(this.div.style.left="-2000px")},show:function(){this.reposition()},destroy:function(){if(this.domElement&&this.div){this.hide();this.div.innerHTML="";var a=k.getElementsByTagName("body")[0];try{a.removeChild(this.div)}catch(b){}this.div=this.domElement=null}},reposition:function(a){a&&((this.domElement=g.$(a))||this.hide());if(this.domElement&&this.div){var a=g.getDOMObjectPosition(this.domElement),b=this.div.style;b.left=""+a.left+
+"px";b.top=""+a.top+"px"}},clearText:function(){this.clipText="";this.ready&&this.movie.clearText()},appendText:function(a){this.clipText+=a;this.ready&&this.movie.appendText(a)},setText:function(a){this.clipText=a;this.ready&&this.movie.setText(a)},setCharSet:function(a){this.charSet=a;this.ready&&this.movie.setCharSet(a)},setBomInc:function(a){this.incBom=a;this.ready&&this.movie.setBomInc(a)},setFileName:function(a){this.fileName=a;this.ready&&this.movie.setFileName(a)},setAction:function(a){this.action=
+a;this.ready&&this.movie.setAction(a)},addEventListener:function(a,b){a=a.toString().toLowerCase().replace(/^on/,"");this.handlers[a]||(this.handlers[a]=[]);this.handlers[a].push(b)},setHandCursor:function(a){this.handCursorEnabled=a;this.ready&&this.movie.setHandCursor(a)},setCSSEffects:function(a){this.cssEffects=!!a},receiveEvent:function(a,b){var c,a=a.toString().toLowerCase().replace(/^on/,"");switch(a){case "load":this.movie=k.getElementById(this.movieId);if(!this.movie){c=this;setTimeout(function(){c.receiveEvent("load",
+null)},1);return}if(!this.ready&&navigator.userAgent.match(/Firefox/)&&navigator.userAgent.match(/Windows/)){c=this;setTimeout(function(){c.receiveEvent("load",null)},100);this.ready=!0;return}this.ready=!0;this.movie.clearText();this.movie.appendText(this.clipText);this.movie.setFileName(this.fileName);this.movie.setAction(this.action);this.movie.setCharSet(this.charSet);this.movie.setBomInc(this.incBom);this.movie.setHandCursor(this.handCursorEnabled);break;case "mouseover":this.domElement&&this.cssEffects&&
+this.recoverActive&&this.domElement.addClass("active");break;case "mouseout":this.domElement&&this.cssEffects&&(this.recoverActive=!1,this.domElement.hasClass("active")&&(this.domElement.removeClass("active"),this.recoverActive=!0));break;case "mousedown":this.domElement&&this.cssEffects&&this.domElement.addClass("active");break;case "mouseup":this.domElement&&this.cssEffects&&(this.domElement.removeClass("active"),this.recoverActive=!1)}if(this.handlers[a])for(var d=0,f=this.handlers[a].length;d<
+f;d++){var e=this.handlers[a][d];if("function"==typeof e)e(this,b);else if("object"==typeof e&&2==e.length)e[0][e[1]](this,b);else if("string"==typeof e)n[e](this,b)}}};n.ZeroClipboard_TableTools=g;var e=jQuery;TableTools=function(a,b){!this instanceof TableTools&&alert("Warning: TableTools must be initialised with the keyword 'new'");this.s={that:this,dt:e.fn.dataTable.Api?(new e.fn.dataTable.Api(a)).settings()[0]:a.fnSettings(),print:{saveStart:-1,saveLength:-1,saveScroll:-1,funcEnd:function(){}},
+buttonCounter:0,select:{type:"",selected:[],preRowSelect:null,postSelected:null,postDeselected:null,all:!1,selectedClass:""},custom:{},swfPath:"",buttonSet:[],master:!1,tags:{}};this.dom={container:null,table:null,print:{hidden:[],message:null},collection:{collection:null,background:null}};this.classes=e.extend(!0,{},TableTools.classes);this.s.dt.bJUI&&e.extend(!0,this.classes,TableTools.classes_themeroller);this.fnSettings=function(){return this.s};"undefined"==typeof b&&(b={});TableTools._aInstances.push(this);
+this._fnConstruct(b);return this};TableTools.prototype={fnGetSelected:function(a){var b=[],c=this.s.dt.aoData,d=this.s.dt.aiDisplay,f;if(a){a=0;for(f=d.length;a<f;a++)c[d[a]]._DTTT_selected&&b.push(c[d[a]].nTr)}else{a=0;for(f=c.length;a<f;a++)c[a]._DTTT_selected&&b.push(c[a].nTr)}return b},fnGetSelectedData:function(){var a=[],b=this.s.dt.aoData,c,d;c=0;for(d=b.length;c<d;c++)b[c]._DTTT_selected&&a.push(this.s.dt.oInstance.fnGetData(c));return a},fnGetSelectedIndexes:function(a){var b=[],c=this.s.dt.aoData,
+d=this.s.dt.aiDisplay,f;if(a){a=0;for(f=d.length;a<f;a++)c[d[a]]._DTTT_selected&&b.push(d[a])}else{a=0;for(f=c.length;a<f;a++)c[a]._DTTT_selected&&b.push(a)}return b},fnIsSelected:function(a){a=this.s.dt.oInstance.fnGetPosition(a);return!0===this.s.dt.aoData[a]._DTTT_selected?!0:!1},fnSelectAll:function(a){this._fnRowSelect(a?this.s.dt.aiDisplay:this.s.dt.aoData)},fnSelectNone:function(a){this._fnRowDeselect(this.fnGetSelectedIndexes(a))},fnSelect:function(a){"single"==this.s.select.type&&this.fnSelectNone();
+this._fnRowSelect(a)},fnDeselect:function(a){this._fnRowDeselect(a)},fnGetTitle:function(a){var b="";"undefined"!=typeof a.sTitle&&""!==a.sTitle?b=a.sTitle:(a=k.getElementsByTagName("title"),0<a.length&&(b=a[0].innerHTML));return 4>"¡".toString().length?b.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g,""):b.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g,"")},fnCalcColRatios:function(a){var b=this.s.dt.aoColumns,a=this._fnColumnTargets(a.mColumns),c=[],d=0,f=0,e,i;e=0;for(i=a.length;e<i;e++)a[e]&&(d=b[e].nTh.offsetWidth,
+f+=d,c.push(d));e=0;for(i=c.length;e<i;e++)c[e]/=f;return c.join("\t")},fnGetTableData:function(a){if(this.s.dt)return this._fnGetDataTablesData(a)},fnSetText:function(a,b){this._fnFlashSetText(a,b)},fnResizeButtons:function(){for(var a in g.clients)if(a){var b=g.clients[a];"undefined"!=typeof b.domElement&&b.domElement.parentNode&&b.positionElement()}},fnResizeRequired:function(){for(var a in g.clients)if(a){var b=g.clients[a];if("undefined"!=typeof b.domElement&&b.domElement.parentNode==this.dom.container&&
+!1===b.sized)return!0}return!1},fnPrint:function(a,b){b===q&&(b={});a===q||a?this._fnPrintStart(b):this._fnPrintEnd()},fnInfo:function(a,b){var c=e("<div/>").addClass(this.classes.print.info).html(a).appendTo("body");setTimeout(function(){c.fadeOut("normal",function(){c.remove()})},b)},fnContainer:function(){return this.dom.container},_fnConstruct:function(a){var b=this;this._fnCustomiseSettings(a);this.dom.container=k.createElement(this.s.tags.container);this.dom.container.className=this.classes.container;
+"none"!=this.s.select.type&&this._fnRowSelectConfig();this._fnButtonDefinations(this.s.buttonSet,this.dom.container);this.s.dt.aoDestroyCallback.push({sName:"TableTools",fn:function(){e(b.s.dt.nTBody).off("click.DTTT_Select",b.s.custom.sRowSelector).off("mousedown.DTTT_Select","tr").off("mouseup.DTTT_Select","tr");e(b.dom.container).empty();var a=e.inArray(b,TableTools._aInstances);-1!==a&&TableTools._aInstances.splice(a,1)}})},_fnCustomiseSettings:function(a){"undefined"==typeof this.s.dt._TableToolsInit&&
+(this.s.master=!0,this.s.dt._TableToolsInit=!0);this.dom.table=this.s.dt.nTable;this.s.custom=e.extend({},TableTools.DEFAULTS,a);this.s.swfPath=this.s.custom.sSwfPath;"undefined"!=typeof g&&(g.moviePath=this.s.swfPath);this.s.select.type=this.s.custom.sRowSelect;this.s.select.preRowSelect=this.s.custom.fnPreRowSelect;this.s.select.postSelected=this.s.custom.fnRowSelected;this.s.select.postDeselected=this.s.custom.fnRowDeselected;this.s.custom.sSelectedClass&&(this.classes.select.row=this.s.custom.sSelectedClass);
+this.s.tags=this.s.custom.oTags;this.s.buttonSet=this.s.custom.aButtons},_fnButtonDefinations:function(a,b){for(var c,d=0,f=a.length;d<f;d++){if("string"==typeof a[d]){if("undefined"==typeof TableTools.BUTTONS[a[d]]){alert("TableTools: Warning - unknown button type: "+a[d]);continue}c=e.extend({},TableTools.BUTTONS[a[d]],!0)}else{if("undefined"==typeof TableTools.BUTTONS[a[d].sExtends]){alert("TableTools: Warning - unknown button type: "+a[d].sExtends);continue}c=e.extend({},TableTools.BUTTONS[a[d].sExtends],
+!0);c=e.extend(c,a[d],!0)}(c=this._fnCreateButton(c,e(b).hasClass(this.classes.collection.container)))&&b.appendChild(c)}},_fnCreateButton:function(a,b){var c=this._fnButtonBase(a,b);if(a.sAction.match(/flash/)){if(!this._fnHasFlash())return!1;this._fnFlashConfig(c,a)}else"text"==a.sAction?this._fnTextConfig(c,a):"div"==a.sAction?this._fnTextConfig(c,a):"collection"==a.sAction&&(this._fnTextConfig(c,a),this._fnCollectionConfig(c,a));if(-1!==this.s.dt.iTabIndex)e(c).attr("tabindex",this.s.dt.iTabIndex).attr("aria-controls",
+this.s.dt.sTableId).on("keyup.DTTT",function(a){13===a.keyCode&&(a.stopPropagation(),e(this).trigger("click"))}).on("mousedown.DTTT",function(b){a.sAction.match(/flash/)||b.preventDefault()});return c},_fnButtonBase:function(a,b){var c,d,f;b?(c=a.sTag&&"default"!==a.sTag?a.sTag:this.s.tags.collection.button,d=a.sLinerTag&&"default"!==a.sLinerTag?a.sLiner:this.s.tags.collection.liner,f=this.classes.collection.buttons.normal):(c=a.sTag&&"default"!==a.sTag?a.sTag:this.s.tags.button,d=a.sLinerTag&&"default"!==
+a.sLinerTag?a.sLiner:this.s.tags.liner,f=this.classes.buttons.normal);c=k.createElement(c);d=k.createElement(d);var e=this._fnGetMasterSettings();c.className=f+" "+a.sButtonClass;c.setAttribute("id","ToolTables_"+this.s.dt.sInstance+"_"+e.buttonCounter);c.appendChild(d);d.innerHTML=a.sButtonText;e.buttonCounter++;return c},_fnGetMasterSettings:function(){if(this.s.master)return this.s;for(var a=TableTools._aInstances,b=0,c=a.length;b<c;b++)if(this.dom.table==a[b].s.dt.nTable)return a[b].s},_fnCollectionConfig:function(a,
+b){var c=k.createElement(this.s.tags.collection.container);c.style.display="none";c.className=this.classes.collection.container;b._collection=c;k.body.appendChild(c);this._fnButtonDefinations(b.aButtons,c)},_fnCollectionShow:function(a,b){var c=this,d=e(a).offset(),f=b._collection,j=d.left,d=d.top+e(a).outerHeight(),i=e(n).height(),h=e(k).height(),o=e(n).width(),g=e(k).width();f.style.position="absolute";f.style.left=j+"px";f.style.top=d+"px";f.style.display="block";e(f).css("opacity",0);var l=k.createElement("div");
+l.style.position="absolute";l.style.left="0px";l.style.top="0px";l.style.height=(i>h?i:h)+"px";l.style.width=(o>g?o:g)+"px";l.className=this.classes.collection.background;e(l).css("opacity",0);k.body.appendChild(l);k.body.appendChild(f);i=e(f).outerWidth();o=e(f).outerHeight();j+i>g&&(f.style.left=g-i+"px");d+o>h&&(f.style.top=d-o-e(a).outerHeight()+"px");this.dom.collection.collection=f;this.dom.collection.background=l;setTimeout(function(){e(f).animate({opacity:1},500);e(l).animate({opacity:0.25},
+500)},10);this.fnResizeButtons();e(l).click(function(){c._fnCollectionHide.call(c,null,null)})},_fnCollectionHide:function(a,b){!(null!==b&&"collection"==b.sExtends)&&null!==this.dom.collection.collection&&(e(this.dom.collection.collection).animate({opacity:0},500,function(){this.style.display="none"}),e(this.dom.collection.background).animate({opacity:0},500,function(){this.parentNode.removeChild(this)}),this.dom.collection.collection=null,this.dom.collection.background=null)},_fnRowSelectConfig:function(){if(this.s.master){var a=
+this,b=this.s.dt;e(b.nTable).addClass(this.classes.select.table);"os"===this.s.select.type&&(e(b.nTBody).on("mousedown.DTTT_Select","tr",function(a){if(a.shiftKey)e(b.nTBody).css("-moz-user-select","none").one("selectstart.DTTT_Select","tr",function(){return!1})}),e(b.nTBody).on("mouseup.DTTT_Select","tr",function(){e(b.nTBody).css("-moz-user-select","")}));e(b.nTBody).on("click.DTTT_Select",this.s.custom.sRowSelector,function(c){var d=this.nodeName.toLowerCase()==="tr"?this:e(this).parents("tr")[0],
+f=a.s.select,j=a.s.dt.oInstance.fnGetPosition(d);if(d.parentNode==b.nTBody&&b.oInstance.fnGetData(d)!==null){if(f.type=="os")if(c.ctrlKey||c.metaKey)a.fnIsSelected(d)?a._fnRowDeselect(d,c):a._fnRowSelect(d,c);else if(c.shiftKey){var i=a.s.dt.aiDisplay.slice(),h=e.inArray(f.lastRow,i),o=e.inArray(j,i);if(a.fnGetSelected().length===0||h===-1)i.splice(e.inArray(j,i)+1,i.length);else{if(h>o)var g=o,o=h,h=g;i.splice(o+1,i.length);i.splice(0,h)}if(a.fnIsSelected(d)){i.splice(e.inArray(j,i),1);a._fnRowDeselect(i,
+c)}else a._fnRowSelect(i,c)}else if(a.fnIsSelected(d)&&a.fnGetSelected().length===1)a._fnRowDeselect(d,c);else{a.fnSelectNone();a._fnRowSelect(d,c)}else if(a.fnIsSelected(d))a._fnRowDeselect(d,c);else if(f.type=="single"){a.fnSelectNone();a._fnRowSelect(d,c)}else f.type=="multi"&&a._fnRowSelect(d,c);f.lastRow=j}});b.oApi._fnCallbackReg(b,"aoRowCreatedCallback",function(c,d,f){b.aoData[f]._DTTT_selected&&e(c).addClass(a.classes.select.row)},"TableTools-SelectAll")}},_fnRowSelect:function(a,b){var c=
+this._fnSelectData(a),d=[],f,j;f=0;for(j=c.length;f<j;f++)c[f].nTr&&d.push(c[f].nTr);if(null===this.s.select.preRowSelect||this.s.select.preRowSelect.call(this,b,d,!0)){f=0;for(j=c.length;f<j;f++)c[f]._DTTT_selected=!0,c[f].nTr&&e(c[f].nTr).addClass(this.classes.select.row);null!==this.s.select.postSelected&&this.s.select.postSelected.call(this,d);TableTools._fnEventDispatch(this,"select",d,!0)}},_fnRowDeselect:function(a,b){var c=this._fnSelectData(a),d=[],f,j;f=0;for(j=c.length;f<j;f++)c[f].nTr&&
+d.push(c[f].nTr);if(null===this.s.select.preRowSelect||this.s.select.preRowSelect.call(this,b,d,!1)){f=0;for(j=c.length;f<j;f++)c[f]._DTTT_selected=!1,c[f].nTr&&e(c[f].nTr).removeClass(this.classes.select.row);null!==this.s.select.postDeselected&&this.s.select.postDeselected.call(this,d);TableTools._fnEventDispatch(this,"select",d,!1)}},_fnSelectData:function(a){var b=[],c,d,f;if(a.nodeName)c=this.s.dt.oInstance.fnGetPosition(a),b.push(this.s.dt.aoData[c]);else if("undefined"!==typeof a.length){d=
+0;for(f=a.length;d<f;d++)a[d].nodeName?(c=this.s.dt.oInstance.fnGetPosition(a[d]),b.push(this.s.dt.aoData[c])):"number"===typeof a[d]?b.push(this.s.dt.aoData[a[d]]):b.push(a[d])}else"number"===typeof a?b.push(this.s.dt.aoData[a]):b.push(a);return b},_fnTextConfig:function(a,b){var c=this;null!==b.fnInit&&b.fnInit.call(this,a,b);""!==b.sToolTip&&(a.title=b.sToolTip);e(a).hover(function(){b.fnMouseover!==null&&b.fnMouseover.call(this,a,b,null)},function(){b.fnMouseout!==null&&b.fnMouseout.call(this,
+a,b,null)});null!==b.fnSelect&&TableTools._fnEventListen(this,"select",function(d){b.fnSelect.call(c,a,b,d)});e(a).click(function(d){b.fnClick!==null&&b.fnClick.call(c,a,b,null,d);b.fnComplete!==null&&b.fnComplete.call(c,a,b,null,null);c._fnCollectionHide(a,b)})},_fnHasFlash:function(){try{if(new ActiveXObject("ShockwaveFlash.ShockwaveFlash"))return!0}catch(a){if(navigator.mimeTypes&&navigator.mimeTypes["application/x-shockwave-flash"]!==q&&navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin)return!0}return!1},
+_fnFlashConfig:function(a,b){var c=this,d=new g.Client;null!==b.fnInit&&b.fnInit.call(this,a,b);d.setHandCursor(!0);"flash_save"==b.sAction?(d.setAction("save"),d.setCharSet("utf16le"==b.sCharSet?"UTF16LE":"UTF8"),d.setBomInc(b.bBomInc),d.setFileName(b.sFileName.replace("*",this.fnGetTitle(b)))):"flash_pdf"==b.sAction?(d.setAction("pdf"),d.setFileName(b.sFileName.replace("*",this.fnGetTitle(b)))):d.setAction("copy");d.addEventListener("mouseOver",function(){b.fnMouseover!==null&&b.fnMouseover.call(c,
+a,b,d)});d.addEventListener("mouseOut",function(){b.fnMouseout!==null&&b.fnMouseout.call(c,a,b,d)});d.addEventListener("mouseDown",function(){b.fnClick!==null&&b.fnClick.call(c,a,b,d)});d.addEventListener("complete",function(f,e){b.fnComplete!==null&&b.fnComplete.call(c,a,b,d,e);c._fnCollectionHide(a,b)});null!==b.fnSelect&&TableTools._fnEventListen(this,"select",function(d){b.fnSelect.call(c,a,b,d)});this._fnFlashGlue(d,a,b.sToolTip)},_fnFlashGlue:function(a,b,c){var d=this,f=b.getAttribute("id");
+k.getElementById(f)?a.glue(b,c):setTimeout(function(){d._fnFlashGlue(a,b,c)},100)},_fnFlashSetText:function(a,b){var c=this._fnChunkData(b,8192);a.clearText();for(var d=0,f=c.length;d<f;d++)a.appendText(c[d])},_fnColumnTargets:function(a){var b=[],c=this.s.dt,d,f=c.aoColumns;d=f.length;if("function"==typeof a){a=a.call(this,c);for(c=0;c<d;c++)b.push(-1!==e.inArray(c,a)?!0:!1)}else if("object"==typeof a){for(c=0;c<d;c++)b.push(!1);c=0;for(d=a.length;c<d;c++)b[a[c]]=!0}else if("visible"==a)for(c=0;c<
+d;c++)b.push(f[c].bVisible?!0:!1);else if("hidden"==a)for(c=0;c<d;c++)b.push(f[c].bVisible?!1:!0);else if("sortable"==a)for(c=0;c<d;c++)b.push(f[c].bSortable?!0:!1);else for(c=0;c<d;c++)b.push(!0);return b},_fnNewline:function(a){return"auto"==a.sNewLine?navigator.userAgent.match(/Windows/)?"\r\n":"\n":a.sNewLine},_fnGetDataTablesData:function(a){var b,c,d,f,j,i=[],h="",g=this.s.dt,k,l=RegExp(a.sFieldBoundary,"g"),n=this._fnColumnTargets(a.mColumns);d="undefined"!=typeof a.bSelectedOnly?a.bSelectedOnly:
+!1;if(a.bHeader){j=[];b=0;for(c=g.aoColumns.length;b<c;b++)n[b]&&(h=g.aoColumns[b].sTitle.replace(/\n/g," ").replace(/<.*?>/g,"").replace(/^\s+|\s+$/g,""),h=this._fnHtmlDecode(h),j.push(this._fnBoundData(h,a.sFieldBoundary,l)));i.push(j.join(a.sFieldSeperator))}d=!0;var m;f=this.fnGetSelectedIndexes();m=(d="none"!==this.s.select.type&&d&&0!==f.length)?f:p.Api?(new p.Api(g)).rows(a.oSelectorOpts).indexes().flatten().toArray():g.oInstance.$("tr",a.oSelectorOpts).map(function(a,b){return g.oInstance.fnGetPosition(b)}).get();
+d=0;for(f=m.length;d<f;d++){k=g.aoData[m[d]].nTr;j=[];b=0;for(c=g.aoColumns.length;b<c;b++)n[b]&&(h=g.oApi._fnGetCellData(g,m[d],b,"display"),a.fnCellRender?h=a.fnCellRender(h,b,k,m[d])+"":"string"==typeof h?(h=h.replace(/\n/g," "),h=h.replace(/<img.*?\s+alt\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+)).*?>/gi,"$1$2$3"),h=h.replace(/<.*?>/g,"")):h+="",h=h.replace(/^\s+/,"").replace(/\s+$/,""),h=this._fnHtmlDecode(h),j.push(this._fnBoundData(h,a.sFieldBoundary,l)));i.push(j.join(a.sFieldSeperator));a.bOpenRows&&
+(b=e.grep(g.aoOpenRows,function(a){return a.nParent===k}),1===b.length&&(h=this._fnBoundData(e("td",b[0].nTr).html(),a.sFieldBoundary,l),i.push(h)))}if(a.bFooter&&null!==g.nTFoot){j=[];b=0;for(c=g.aoColumns.length;b<c;b++)n[b]&&null!==g.aoColumns[b].nTf&&(h=g.aoColumns[b].nTf.innerHTML.replace(/\n/g," ").replace(/<.*?>/g,""),h=this._fnHtmlDecode(h),j.push(this._fnBoundData(h,a.sFieldBoundary,l)));i.push(j.join(a.sFieldSeperator))}return i.join(this._fnNewline(a))},_fnBoundData:function(a,b,c){return""===
+b?a:b+a.replace(c,b+b)+b},_fnChunkData:function(a,b){for(var c=[],d=a.length,f=0;f<d;f+=b)f+b<d?c.push(a.substring(f,f+b)):c.push(a.substring(f,d));return c},_fnHtmlDecode:function(a){if(-1===a.indexOf("&"))return a;var b=k.createElement("div");return a.replace(/&([^\s]*?);/g,function(a,d){if("#"===a.substr(1,1))return String.fromCharCode(Number(d.substr(1)));b.innerHTML=a;return b.childNodes[0].nodeValue})},_fnPrintStart:function(a){var b=this,c=this.s.dt;this._fnPrintHideNodes(c.nTable);this.s.print.saveStart=
+c._iDisplayStart;this.s.print.saveLength=c._iDisplayLength;a.bShowAll&&(c._iDisplayStart=0,c._iDisplayLength=-1,c.oApi._fnCalculateEnd&&c.oApi._fnCalculateEnd(c),c.oApi._fnDraw(c));if(""!==c.oScroll.sX||""!==c.oScroll.sY)this._fnPrintScrollStart(c),e(this.s.dt.nTable).bind("draw.DTTT_Print",function(){b._fnPrintScrollStart(c)});var d=c.aanFeatures,f;for(f in d)if("i"!=f&&"t"!=f&&1==f.length)for(var g=0,i=d[f].length;g<i;g++)this.dom.print.hidden.push({node:d[f][g],display:"block"}),d[f][g].style.display=
+"none";e(k.body).addClass(this.classes.print.body);""!==a.sInfo&&this.fnInfo(a.sInfo,3E3);a.sMessage&&e("<div/>").addClass(this.classes.print.message).html(a.sMessage).prependTo("body");this.s.print.saveScroll=e(n).scrollTop();n.scrollTo(0,0);e(k).bind("keydown.DTTT",function(a){if(a.keyCode==27){a.preventDefault();b._fnPrintEnd.call(b,a)}})},_fnPrintEnd:function(){var a=this.s.dt,b=this.s.print;this._fnPrintShowNodes();if(""!==a.oScroll.sX||""!==a.oScroll.sY)e(this.s.dt.nTable).unbind("draw.DTTT_Print"),
+this._fnPrintScrollEnd();n.scrollTo(0,b.saveScroll);e("div."+this.classes.print.message).remove();e(k.body).removeClass("DTTT_Print");a._iDisplayStart=b.saveStart;a._iDisplayLength=b.saveLength;a.oApi._fnCalculateEnd&&a.oApi._fnCalculateEnd(a);a.oApi._fnDraw(a);e(k).unbind("keydown.DTTT")},_fnPrintScrollStart:function(){var a=this.s.dt;a.nScrollHead.getElementsByTagName("div")[0].getElementsByTagName("table");var b=a.nTable.parentNode,c;c=a.nTable.getElementsByTagName("thead");0<c.length&&a.nTable.removeChild(c[0]);
+null!==a.nTFoot&&(c=a.nTable.getElementsByTagName("tfoot"),0<c.length&&a.nTable.removeChild(c[0]));c=a.nTHead.cloneNode(!0);a.nTable.insertBefore(c,a.nTable.childNodes[0]);null!==a.nTFoot&&(c=a.nTFoot.cloneNode(!0),a.nTable.insertBefore(c,a.nTable.childNodes[1]));""!==a.oScroll.sX&&(a.nTable.style.width=e(a.nTable).outerWidth()+"px",b.style.width=e(a.nTable).outerWidth()+"px",b.style.overflow="visible");""!==a.oScroll.sY&&(b.style.height=e(a.nTable).outerHeight()+"px",b.style.overflow="visible")},
+_fnPrintScrollEnd:function(){var a=this.s.dt,b=a.nTable.parentNode;""!==a.oScroll.sX&&(b.style.width=a.oApi._fnStringToCss(a.oScroll.sX),b.style.overflow="auto");""!==a.oScroll.sY&&(b.style.height=a.oApi._fnStringToCss(a.oScroll.sY),b.style.overflow="auto")},_fnPrintShowNodes:function(){for(var a=this.dom.print.hidden,b=0,c=a.length;b<c;b++)a[b].node.style.display=a[b].display;a.splice(0,a.length)},_fnPrintHideNodes:function(a){for(var b=this.dom.print.hidden,c=a.parentNode,d=c.childNodes,f=0,g=d.length;f<
+g;f++)if(d[f]!=a&&1==d[f].nodeType){var i=e(d[f]).css("display");"none"!=i&&(b.push({node:d[f],display:i}),d[f].style.display="none")}"BODY"!=c.nodeName.toUpperCase()&&this._fnPrintHideNodes(c)}};TableTools._aInstances=[];TableTools._aListeners=[];TableTools.fnGetMasters=function(){for(var a=[],b=0,c=TableTools._aInstances.length;b<c;b++)TableTools._aInstances[b].s.master&&a.push(TableTools._aInstances[b]);return a};TableTools.fnGetInstance=function(a){"object"!=typeof a&&(a=k.getElementById(a));
+for(var b=0,c=TableTools._aInstances.length;b<c;b++)if(TableTools._aInstances[b].s.master&&TableTools._aInstances[b].dom.table==a)return TableTools._aInstances[b];return null};TableTools._fnEventListen=function(a,b,c){TableTools._aListeners.push({that:a,type:b,fn:c})};TableTools._fnEventDispatch=function(a,b,c,d){for(var f=TableTools._aListeners,e=0,g=f.length;e<g;e++)a.dom.table==f[e].that.dom.table&&f[e].type==b&&f[e].fn(c,d)};TableTools.buttonBase={sAction:"text",sTag:"default",sLinerTag:"default",
+sButtonClass:"DTTT_button_text",sButtonText:"Button text",sTitle:"",sToolTip:"",sCharSet:"utf8",bBomInc:!1,sFileName:"*.csv",sFieldBoundary:"",sFieldSeperator:"\t",sNewLine:"auto",mColumns:"all",bHeader:!0,bFooter:!0,bOpenRows:!1,bSelectedOnly:!1,oSelectorOpts:q,fnMouseover:null,fnMouseout:null,fnClick:null,fnSelect:null,fnComplete:null,fnInit:null,fnCellRender:null};TableTools.BUTTONS={csv:e.extend({},TableTools.buttonBase,{sAction:"flash_save",sButtonClass:"DTTT_button_csv",sButtonText:"CSV",sFieldBoundary:'"',
+sFieldSeperator:",",fnClick:function(a,b,c){this.fnSetText(c,this.fnGetTableData(b))}}),xls:e.extend({},TableTools.buttonBase,{sAction:"flash_save",sCharSet:"utf16le",bBomInc:!0,sButtonClass:"DTTT_button_xls",sButtonText:"Excel",fnClick:function(a,b,c){this.fnSetText(c,this.fnGetTableData(b))}}),copy:e.extend({},TableTools.buttonBase,{sAction:"flash_copy",sButtonClass:"DTTT_button_copy",sButtonText:"Copy",fnClick:function(a,b,c){this.fnSetText(c,this.fnGetTableData(b))},fnComplete:function(a,b,c,
+d){a=d.split("\n").length;b.bHeader&&a--;null!==this.s.dt.nTFoot&&b.bFooter&&a--;this.fnInfo("<h6>Table copied</h6><p>Copied "+a+" row"+(1==a?"":"s")+" to the clipboard.</p>",1500)}}),pdf:e.extend({},TableTools.buttonBase,{sAction:"flash_pdf",sNewLine:"\n",sFileName:"*.pdf",sButtonClass:"DTTT_button_pdf",sButtonText:"PDF",sPdfOrientation:"portrait",sPdfSize:"A4",sPdfMessage:"",fnClick:function(a,b,c){this.fnSetText(c,"title:"+this.fnGetTitle(b)+"\nmessage:"+b.sPdfMessage+"\ncolWidth:"+this.fnCalcColRatios(b)+
+"\norientation:"+b.sPdfOrientation+"\nsize:"+b.sPdfSize+"\n--/TableToolsOpts--\n"+this.fnGetTableData(b))}}),print:e.extend({},TableTools.buttonBase,{sInfo:"<h6>Print view</h6><p>Please use your browser's print function to print this table. Press escape when finished.</p>",sMessage:null,bShowAll:!0,sToolTip:"View print view",sButtonClass:"DTTT_button_print",sButtonText:"Print",fnClick:function(a,b){this.fnPrint(!0,b)}}),text:e.extend({},TableTools.buttonBase),select:e.extend({},TableTools.buttonBase,
+{sButtonText:"Select button",fnSelect:function(a){0!==this.fnGetSelected().length?e(a).removeClass(this.classes.buttons.disabled):e(a).addClass(this.classes.buttons.disabled)},fnInit:function(a){e(a).addClass(this.classes.buttons.disabled)}}),select_single:e.extend({},TableTools.buttonBase,{sButtonText:"Select button",fnSelect:function(a){1==this.fnGetSelected().length?e(a).removeClass(this.classes.buttons.disabled):e(a).addClass(this.classes.buttons.disabled)},fnInit:function(a){e(a).addClass(this.classes.buttons.disabled)}}),
+select_all:e.extend({},TableTools.buttonBase,{sButtonText:"Select all",fnClick:function(){this.fnSelectAll()},fnSelect:function(a){this.fnGetSelected().length==this.s.dt.fnRecordsDisplay()?e(a).addClass(this.classes.buttons.disabled):e(a).removeClass(this.classes.buttons.disabled)}}),select_none:e.extend({},TableTools.buttonBase,{sButtonText:"Deselect all",fnClick:function(){this.fnSelectNone()},fnSelect:function(a){0!==this.fnGetSelected().length?e(a).removeClass(this.classes.buttons.disabled):e(a).addClass(this.classes.buttons.disabled)},
+fnInit:function(a){e(a).addClass(this.classes.buttons.disabled)}}),ajax:e.extend({},TableTools.buttonBase,{sAjaxUrl:"/xhr.php",sButtonText:"Ajax button",fnClick:function(a,b){var c=this.fnGetTableData(b);e.ajax({url:b.sAjaxUrl,data:[{name:"tableData",value:c}],success:b.fnAjaxComplete,dataType:"json",type:"POST",cache:!1,error:function(){alert("Error detected when sending table data to server")}})},fnAjaxComplete:function(){alert("Ajax complete")}}),div:e.extend({},TableTools.buttonBase,{sAction:"div",
+sTag:"div",sButtonClass:"DTTT_nonbutton",sButtonText:"Text button"}),collection:e.extend({},TableTools.buttonBase,{sAction:"collection",sButtonClass:"DTTT_button_collection",sButtonText:"Collection",fnClick:function(a,b){this._fnCollectionShow(a,b)}})};TableTools.buttons=TableTools.BUTTONS;TableTools.classes={container:"DTTT_container",buttons:{normal:"DTTT_button",disabled:"DTTT_disabled"},collection:{container:"DTTT_collection",background:"DTTT_collection_background",buttons:{normal:"DTTT_button",
+disabled:"DTTT_disabled"}},select:{table:"DTTT_selectable",row:"DTTT_selected selected"},print:{body:"DTTT_Print",info:"DTTT_print_info",message:"DTTT_PrintMessage"}};TableTools.classes_themeroller={container:"DTTT_container ui-buttonset ui-buttonset-multi",buttons:{normal:"DTTT_button ui-button ui-state-default"},collection:{container:"DTTT_collection ui-buttonset ui-buttonset-multi"}};TableTools.DEFAULTS={sSwfPath:"../swf/copy_csv_xls_pdf.swf",sRowSelect:"none",sRowSelector:"tr",sSelectedClass:null,
+fnPreRowSelect:null,fnRowSelected:null,fnRowDeselected:null,aButtons:["copy","csv","xls","pdf","print"],oTags:{container:"div",button:"a",liner:"span",collection:{container:"div",button:"a",liner:"span"}}};TableTools.defaults=TableTools.DEFAULTS;TableTools.prototype.CLASS="TableTools";TableTools.version="2.2.4";e.fn.dataTable.Api&&e.fn.dataTable.Api.register("tabletools()",function(){var a=null;0<this.context.length&&(a=TableTools.fnGetInstance(this.context[0].nTable));return a});"function"==typeof e.fn.dataTable&&
+"function"==typeof e.fn.dataTableExt.fnVersionCheck&&e.fn.dataTableExt.fnVersionCheck("1.9.0")?e.fn.dataTableExt.aoFeatures.push({fnInit:function(a){var b=a.oInit;return(new TableTools(a.oInstance,b?b.tableTools||b.oTableTools||{}:{})).dom.container},cFeature:"T",sFeature:"TableTools"}):alert("Warning: TableTools requires DataTables 1.9.0 or newer - www.datatables.net/download");e.fn.DataTable.TableTools=TableTools;"function"==typeof m.fn.dataTable&&"function"==typeof m.fn.dataTableExt.fnVersionCheck&&
+m.fn.dataTableExt.fnVersionCheck("1.9.0")?m.fn.dataTableExt.aoFeatures.push({fnInit:function(a){a=new TableTools(a.oInstance,"undefined"!=typeof a.oInit.oTableTools?a.oInit.oTableTools:{});TableTools._aInstances.push(a);return a.dom.container},cFeature:"T",sFeature:"TableTools"}):alert("Warning: TableTools 2 requires DataTables 1.9.0 or newer - www.datatables.net/download");m.fn.dataTable.TableTools=TableTools;return m.fn.DataTable.TableTools=TableTools};"function"===typeof define&&define.amd?define(["jquery",
+"datatables"],p):"object"===typeof exports?p(require("jquery"),require("datatables")):jQuery&&!jQuery.fn.dataTable.TableTools&&p(jQuery,jQuery.fn.dataTable)})(window,document);
--- /dev/null
+table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc{cursor:pointer;*cursor:hand}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc_disabled{background-repeat:no-repeat;background-position:center right}table.dataTable thead .sorting{background-image:url("../images/sort_both.png")}table.dataTable thead .sorting_asc{background-image:url("../images/sort_asc.png")}table.dataTable thead .sorting_desc{background-image:url("../images/sort_desc.png")}table.dataTable thead .sorting_asc_disabled{background-image:url("../images/sort_asc_disabled.png")}table.dataTable thead .sorting_desc_disabled{background-image:url("../images/sort_desc_disabled.png")}table.dataTable tbody tr{background-color:#fff}table.dataTable tbody tr.selected{background-color:#B0BED9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#abb9d3}table.dataTable.hover tbody tr:hover,table.dataTable.display tbody tr:hover{background-color:#f5f5f5}table.dataTable.hover tbody tr:hover.selected,table.dataTable.display tbody tr:hover.selected{background-color:#a9b7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#f9f9f9}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad4}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:#f5f5f5}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b3cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a7b5ce}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b6d0}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#f9f9f9}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fbfbfb}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fdfdfd}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad4}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#adbbd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2{background-color:#ebebeb}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3{background-color:#eee}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1{background-color:#a1aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2{background-color:#a2afc8}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3{background-color:#a4b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:4px 17px 4px 4px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:4px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #cacaca;background-color:#fff;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_paginate .ellipsis{padding:0 1em}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table,.dataTables_wrapper.no-footer div.dataTables_scrollBody table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}}
--- /dev/null
+/*! DataTables 1.10.7
+ * ©2008-2015 SpryMedia Ltd - datatables.net/license
+ */
+(function(Ea,Q,k){var P=function(h){function W(a){var b,c,e={};h.each(a,function(d){if((b=d.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=d.replace(b[0],b[2].toLowerCase()),e[c]=d,"o"===b[1]&&W(a[d])});a._hungarianMap=e}function H(a,b,c){a._hungarianMap||W(a);var e;h.each(b,function(d){e=a._hungarianMap[d];if(e!==k&&(c||b[e]===k))"o"===e.charAt(0)?(b[e]||(b[e]={}),h.extend(!0,b[e],b[d]),H(a[e],b[e],c)):b[e]=b[d]})}function P(a){var b=m.defaults.oLanguage,c=a.sZeroRecords;
+!a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&E(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&E(a,a,"sZeroRecords","sLoadingRecords");a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&db(a)}function eb(a){A(a,"ordering","bSort");A(a,"orderMulti","bSortMulti");A(a,"orderClasses","bSortClasses");A(a,"orderCellsTop","bSortCellsTop");A(a,"order","aaSorting");A(a,"orderFixed","aaSortingFixed");A(a,"paging","bPaginate");
+A(a,"pagingType","sPaginationType");A(a,"pageLength","iDisplayLength");A(a,"searching","bFilter");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&H(m.models.oSearch,a[b])}function fb(a){A(a,"orderable","bSortable");A(a,"orderData","aDataSort");A(a,"orderSequence","asSorting");A(a,"orderDataType","sortDataType");var b=a.aDataSort;b&&!h.isArray(b)&&(a.aDataSort=[b])}function gb(a){var a=a.oBrowser,b=h("<div/>").css({position:"absolute",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(h("<div/>").css({position:"absolute",
+top:1,left:1,width:100,overflow:"scroll"}).append(h('<div class="test"/>').css({width:"100%",height:10}))).appendTo("body"),c=b.find(".test");a.bScrollOversize=100===c[0].offsetWidth;a.bScrollbarLeft=1!==Math.round(c.offset().left);b.remove()}function hb(a,b,c,e,d,f){var g,j=!1;c!==k&&(g=c,j=!0);for(;e!==d;)a.hasOwnProperty(e)&&(g=j?b(g,a[e],e,a):a[e],j=!0,e+=f);return g}function Fa(a,b){var c=m.defaults.column,e=a.aoColumns.length,c=h.extend({},m.models.oColumn,c,{nTh:b?b:Q.createElement("th"),sTitle:c.sTitle?
+c.sTitle:b?b.innerHTML:"",aDataSort:c.aDataSort?c.aDataSort:[e],mData:c.mData?c.mData:e,idx:e});a.aoColumns.push(c);c=a.aoPreSearchCols;c[e]=h.extend({},m.models.oSearch,c[e]);ka(a,e,h(b).data())}function ka(a,b,c){var b=a.aoColumns[b],e=a.oClasses,d=h(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=d.attr("width")||null;var f=(d.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==k&&null!==c&&(fb(c),H(m.defaults.column,c),c.mDataProp!==k&&!c.mData&&(c.mData=c.mDataProp),c.sType&&
+(b._sManualType=c.sType),c.className&&!c.sClass&&(c.sClass=c.className),h.extend(b,c),E(b,c,"sWidth","sWidthOrig"),c.iDataSort!==k&&(b.aDataSort=[c.iDataSort]),E(b,c,"aDataSort"));var g=b.mData,j=R(g),i=b.mRender?R(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=h.isPlainObject(g)&&(c(g.sort)||c(g.type)||c(g.filter));b.fnGetData=function(a,b,c){var e=j(a,b,k,c);return i&&b?i(e,b,a,c):e};b.fnSetData=function(a,b,c){return S(g)(a,b,c)};"number"!==typeof g&&
+(a._rowReadObject=!0);a.oFeatures.bSort||(b.bSortable=!1,d.addClass(e.sSortableNone));a=-1!==h.inArray("asc",b.asSorting);c=-1!==h.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=e.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=e.sSortableAsc,b.sSortingClassJUI=e.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=e.sSortableDesc,b.sSortingClassJUI=e.sSortJUIDescAllowed):(b.sSortingClass=e.sSortable,b.sSortingClassJUI=e.sSortJUI)}function X(a){if(!1!==a.oFeatures.bAutoWidth){var b=
+a.aoColumns;Ga(a);for(var c=0,e=b.length;c<e;c++)b[c].nTh.style.width=b[c].sWidth}b=a.oScroll;(""!==b.sY||""!==b.sX)&&Y(a);w(a,null,"column-sizing",[a])}function la(a,b){var c=Z(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function $(a,b){var c=Z(a,"bVisible"),c=h.inArray(b,c);return-1!==c?c:null}function aa(a){return Z(a,"bVisible").length}function Z(a,b){var c=[];h.map(a.aoColumns,function(a,d){a[b]&&c.push(d)});return c}function Ha(a){var b=a.aoColumns,c=a.aoData,e=m.ext.type.detect,d,
+f,g,j,i,h,l,q,n;d=0;for(f=b.length;d<f;d++)if(l=b[d],n=[],!l.sType&&l._sManualType)l.sType=l._sManualType;else if(!l.sType){g=0;for(j=e.length;g<j;g++){i=0;for(h=c.length;i<h;i++){n[i]===k&&(n[i]=x(a,i,d,"type"));q=e[g](n[i],a);if(!q&&g!==e.length-1)break;if("html"===q)break}if(q){l.sType=q;break}}l.sType||(l.sType="string")}}function ib(a,b,c,e){var d,f,g,j,i,o,l=a.aoColumns;if(b)for(d=b.length-1;0<=d;d--){o=b[d];var q=o.targets!==k?o.targets:o.aTargets;h.isArray(q)||(q=[q]);f=0;for(g=q.length;f<
+g;f++)if("number"===typeof q[f]&&0<=q[f]){for(;l.length<=q[f];)Fa(a);e(q[f],o)}else if("number"===typeof q[f]&&0>q[f])e(l.length+q[f],o);else if("string"===typeof q[f]){j=0;for(i=l.length;j<i;j++)("_all"==q[f]||h(l[j].nTh).hasClass(q[f]))&&e(j,o)}}if(c){d=0;for(a=c.length;d<a;d++)e(d,c[d])}}function K(a,b,c,e){var d=a.aoData.length,f=h.extend(!0,{},m.models.oRow,{src:c?"dom":"data"});f._aData=b;a.aoData.push(f);for(var b=a.aoColumns,f=0,g=b.length;f<g;f++)c&&Ia(a,d,f,x(a,d,f)),b[f].sType=null;a.aiDisplayMaster.push(d);
+(c||!a.oFeatures.bDeferRender)&&Ja(a,d,c,e);return d}function ma(a,b){var c;b instanceof h||(b=h(b));return b.map(function(b,d){c=na(a,d);return K(a,c.data,d,c.cells)})}function x(a,b,c,e){var d=a.iDraw,f=a.aoColumns[c],g=a.aoData[b]._aData,j=f.sDefaultContent,c=f.fnGetData(g,e,{settings:a,row:b,col:c});if(c===k)return a.iDrawError!=d&&null===j&&(I(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b,4),a.iDrawError=d),j;if((c===g||null===c)&&
+null!==j)c=j;else if("function"===typeof c)return c.call(g);return null===c&&"display"==e?"":c}function Ia(a,b,c,e){a.aoColumns[c].fnSetData(a.aoData[b]._aData,e,{settings:a,row:b,col:c})}function Ka(a){return h.map(a.match(/(\\.|[^\.])+/g),function(a){return a.replace(/\\./g,".")})}function R(a){if(h.isPlainObject(a)){var b={};h.each(a,function(a,c){c&&(b[a]=R(c))});return function(a,c,f,g){var j=b[c]||b._;return j!==k?j(a,c,f,g):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,
+c,f,g){return a(b,c,f,g)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,b,f){var g,j;if(""!==f){j=Ka(f);for(var i=0,h=j.length;i<h;i++){f=j[i].match(ba);g=j[i].match(T);if(f){j[i]=j[i].replace(ba,"");""!==j[i]&&(a=a[j[i]]);g=[];j.splice(0,i+1);j=j.join(".");i=0;for(h=a.length;i<h;i++)g.push(c(a[i],b,j));a=f[0].substring(1,f[0].length-1);a=""===a?g:g.join(a);break}else if(g){j[i]=j[i].replace(T,"");a=a[j[i]]();continue}if(null===a||a[j[i]]===
+k)return k;a=a[j[i]]}}return a};return function(b,d){return c(b,d,a)}}return function(b){return b[a]}}function S(a){if(h.isPlainObject(a))return S(a._);if(null===a)return function(){};if("function"===typeof a)return function(b,e,d){a(b,"set",e,d)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,e,d){var d=Ka(d),f;f=d[d.length-1];for(var g,j,i=0,h=d.length-1;i<h;i++){g=d[i].match(ba);j=d[i].match(T);if(g){d[i]=d[i].replace(ba,"");a[d[i]]=[];
+f=d.slice();f.splice(0,i+1);g=f.join(".");j=0;for(h=e.length;j<h;j++)f={},b(f,e[j],g),a[d[i]].push(f);return}j&&(d[i]=d[i].replace(T,""),a=a[d[i]](e));if(null===a[d[i]]||a[d[i]]===k)a[d[i]]={};a=a[d[i]]}if(f.match(T))a[f.replace(T,"")](e);else a[f.replace(ba,"")]=e};return function(c,e){return b(c,e,a)}}return function(b,e){b[a]=e}}function La(a){return D(a.aoData,"_aData")}function oa(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0}function pa(a,b,c){for(var e=-1,d=0,f=a.length;d<
+f;d++)a[d]==b?e=d:a[d]>b&&a[d]--; -1!=e&&c===k&&a.splice(e,1)}function ca(a,b,c,e){var d=a.aoData[b],f,g=function(c,f){for(;c.childNodes.length;)c.removeChild(c.firstChild);c.innerHTML=x(a,b,f,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===d.src)d._aData=na(a,d,e,e===k?k:d._aData).data;else{var j=d.anCells;if(j)if(e!==k)g(j[e],e);else{c=0;for(f=j.length;c<f;c++)g(j[c],c)}}d._aSortData=null;d._aFilterData=null;g=a.aoColumns;if(e!==k)g[e].sType=null;else{c=0;for(f=g.length;c<f;c++)g[c].sType=null;
+Ma(d)}}function na(a,b,c,e){var d=[],f=b.firstChild,g,j=0,i,o=a.aoColumns,l=a._rowReadObject,e=e||l?{}:[],q=function(a,b){if("string"===typeof a){var c=a.indexOf("@");-1!==c&&(c=a.substring(c+1),S(a)(e,b.getAttribute(c)))}},a=function(a){if(c===k||c===j)g=o[j],i=h.trim(a.innerHTML),g&&g._bAttrSrc?(S(g.mData._)(e,i),q(g.mData.sort,a),q(g.mData.type,a),q(g.mData.filter,a)):l?(g._setter||(g._setter=S(g.mData)),g._setter(e,i)):e[j]=i;j++};if(f)for(;f;){b=f.nodeName.toUpperCase();if("TD"==b||"TH"==b)a(f),
+d.push(f);f=f.nextSibling}else{d=b.anCells;f=0;for(b=d.length;f<b;f++)a(d[f])}return{data:e,cells:d}}function Ja(a,b,c,e){var d=a.aoData[b],f=d._aData,g=[],j,i,h,l,q;if(null===d.nTr){j=c||Q.createElement("tr");d.nTr=j;d.anCells=g;j._DT_RowIndex=b;Ma(d);l=0;for(q=a.aoColumns.length;l<q;l++){h=a.aoColumns[l];i=c?e[l]:Q.createElement(h.sCellType);g.push(i);if(!c||h.mRender||h.mData!==l)i.innerHTML=x(a,b,l,"display");h.sClass&&(i.className+=" "+h.sClass);h.bVisible&&!c?j.appendChild(i):!h.bVisible&&c&&
+i.parentNode.removeChild(i);h.fnCreatedCell&&h.fnCreatedCell.call(a.oInstance,i,x(a,b,l),f,b,l)}w(a,"aoRowCreatedCallback",null,[j,f,b])}d.nTr.setAttribute("role","row")}function Ma(a){var b=a.nTr,c=a._aData;if(b){c.DT_RowId&&(b.id=c.DT_RowId);if(c.DT_RowClass){var e=c.DT_RowClass.split(" ");a.__rowc=a.__rowc?Na(a.__rowc.concat(e)):e;h(b).removeClass(a.__rowc.join(" ")).addClass(c.DT_RowClass)}c.DT_RowAttr&&h(b).attr(c.DT_RowAttr);c.DT_RowData&&h(b).data(c.DT_RowData)}}function jb(a){var b,c,e,d,
+f,g=a.nTHead,j=a.nTFoot,i=0===h("th, td",g).length,o=a.oClasses,l=a.aoColumns;i&&(d=h("<tr/>").appendTo(g));b=0;for(c=l.length;b<c;b++)f=l[b],e=h(f.nTh).addClass(f.sClass),i&&e.appendTo(d),a.oFeatures.bSort&&(e.addClass(f.sSortingClass),!1!==f.bSortable&&(e.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),Oa(a,f.nTh,b))),f.sTitle!=e.html()&&e.html(f.sTitle),Pa(a,"header")(a,e,f,o);i&&da(a.aoHeader,g);h(g).find(">tr").attr("role","row");h(g).find(">tr>th, >tr>td").addClass(o.sHeaderTH);
+h(j).find(">tr>th, >tr>td").addClass(o.sFooterTH);if(null!==j){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=l[b],f.nTf=a[b].cell,f.sClass&&h(f.nTf).addClass(f.sClass)}}function ea(a,b,c){var e,d,f,g=[],j=[],i=a.aoColumns.length,o;if(b){c===k&&(c=!1);e=0;for(d=b.length;e<d;e++){g[e]=b[e].slice();g[e].nTr=b[e].nTr;for(f=i-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&g[e].splice(f,1);j.push([])}e=0;for(d=g.length;e<d;e++){if(a=g[e].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=g[e].length;f<b;f++)if(o=
+i=1,j[e][f]===k){a.appendChild(g[e][f].cell);for(j[e][f]=1;g[e+i]!==k&&g[e][f].cell==g[e+i][f].cell;)j[e+i][f]=1,i++;for(;g[e][f+o]!==k&&g[e][f].cell==g[e][f+o].cell;){for(c=0;c<i;c++)j[e+c][f+o]=1;o++}h(g[e][f].cell).attr("rowspan",i).attr("colspan",o)}}}}function M(a){var b=w(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==h.inArray(!1,b))C(a,!1);else{var b=[],c=0,e=a.asStripeClasses,d=e.length,f=a.oLanguage,g=a.iInitDisplayStart,j="ssp"==B(a),i=a.aiDisplay;a.bDrawing=!0;g!==k&&-1!==g&&(a._iDisplayStart=
+j?g:g>=a.fnRecordsDisplay()?0:g,a.iInitDisplayStart=-1);var g=a._iDisplayStart,o=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++,C(a,!1);else if(j){if(!a.bDestroying&&!kb(a))return}else a.iDraw++;if(0!==i.length){f=j?a.aoData.length:o;for(j=j?0:g;j<f;j++){var l=i[j],q=a.aoData[l];null===q.nTr&&Ja(a,l);l=q.nTr;if(0!==d){var n=e[c%d];q._sRowStripe!=n&&(h(l).removeClass(q._sRowStripe).addClass(n),q._sRowStripe=n)}w(a,"aoRowCallback",null,[l,q._aData,c,j]);b.push(l);c++}}else c=f.sZeroRecords,
+1==a.iDraw&&"ajax"==B(a)?c=f.sLoadingRecords:f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=h("<tr/>",{"class":d?e[0]:""}).append(h("<td />",{valign:"top",colSpan:aa(a),"class":a.oClasses.sRowEmpty}).html(c))[0];w(a,"aoHeaderCallback","header",[h(a.nTHead).children("tr")[0],La(a),g,o,i]);w(a,"aoFooterCallback","footer",[h(a.nTFoot).children("tr")[0],La(a),g,o,i]);e=h(a.nTBody);e.children().detach();e.append(h(b));w(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=
+!1}}function N(a,b){var c=a.oFeatures,e=c.bFilter;c.bSort&&lb(a);e?fa(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();!0!==b&&(a._iDisplayStart=0);a._drawHold=b;M(a);a._drawHold=!1}function mb(a){var b=a.oClasses,c=h(a.nTable),c=h("<div/>").insertBefore(c),e=a.oFeatures,d=h("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=d[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),g,j,i,o,l,q,n=0;n<f.length;n++){g=
+null;j=f[n];if("<"==j){i=h("<div/>")[0];o=f[n+1];if("'"==o||'"'==o){l="";for(q=2;f[n+q]!=o;)l+=f[n+q],q++;"H"==l?l=b.sJUIHeader:"F"==l&&(l=b.sJUIFooter);-1!=l.indexOf(".")?(o=l.split("."),i.id=o[0].substr(1,o[0].length-1),i.className=o[1]):"#"==l.charAt(0)?i.id=l.substr(1,l.length-1):i.className=l;n+=q}d.append(i);d=h(i)}else if(">"==j)d=d.parent();else if("l"==j&&e.bPaginate&&e.bLengthChange)g=nb(a);else if("f"==j&&e.bFilter)g=ob(a);else if("r"==j&&e.bProcessing)g=pb(a);else if("t"==j)g=qb(a);else if("i"==
+j&&e.bInfo)g=rb(a);else if("p"==j&&e.bPaginate)g=sb(a);else if(0!==m.ext.feature.length){i=m.ext.feature;q=0;for(o=i.length;q<o;q++)if(j==i[q].cFeature){g=i[q].fnInit(a);break}}g&&(i=a.aanFeatures,i[j]||(i[j]=[]),i[j].push(g),d.append(g))}c.replaceWith(d)}function da(a,b){var c=h(b).children("tr"),e,d,f,g,j,i,o,l,q,n;a.splice(0,a.length);f=0;for(i=c.length;f<i;f++)a.push([]);f=0;for(i=c.length;f<i;f++){e=c[f];for(d=e.firstChild;d;){if("TD"==d.nodeName.toUpperCase()||"TH"==d.nodeName.toUpperCase()){l=
+1*d.getAttribute("colspan");q=1*d.getAttribute("rowspan");l=!l||0===l||1===l?1:l;q=!q||0===q||1===q?1:q;g=0;for(j=a[f];j[g];)g++;o=g;n=1===l?!0:!1;for(j=0;j<l;j++)for(g=0;g<q;g++)a[f+g][o+j]={cell:d,unique:n},a[f+g].nTr=e}d=d.nextSibling}}}function qa(a,b,c){var e=[];c||(c=a.aoHeader,b&&(c=[],da(c,b)));for(var b=0,d=c.length;b<d;b++)for(var f=0,g=c[b].length;f<g;f++)if(c[b][f].unique&&(!e[f]||!a.bSortCellsTop))e[f]=c[b][f].cell;return e}function ra(a,b,c){w(a,"aoServerParams","serverParams",[b]);
+if(b&&h.isArray(b)){var e={},d=/(.*?)\[\]$/;h.each(b,function(a,b){var c=b.name.match(d);c?(c=c[0],e[c]||(e[c]=[]),e[c].push(b.value)):e[b.name]=b.value});b=e}var f,g=a.ajax,j=a.oInstance,i=function(b){w(a,null,"xhr",[a,b,a.jqXHR]);c(b)};if(h.isPlainObject(g)&&g.data){f=g.data;var o=h.isFunction(f)?f(b,a):f,b=h.isFunction(f)&&o?o:h.extend(!0,b,o);delete g.data}o={data:b,success:function(b){var c=b.error||b.sError;c&&I(a,0,c);a.json=b;i(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,
+c){var f=w(a,null,"xhr",[a,null,a.jqXHR]);-1===h.inArray(!0,f)&&("parsererror"==c?I(a,0,"Invalid JSON response",1):4===b.readyState&&I(a,0,"Ajax error",7));C(a,!1)}};a.oAjaxData=b;w(a,null,"preXhr",[a,b]);a.fnServerData?a.fnServerData.call(j,a.sAjaxSource,h.map(b,function(a,b){return{name:b,value:a}}),i,a):a.sAjaxSource||"string"===typeof g?a.jqXHR=h.ajax(h.extend(o,{url:g||a.sAjaxSource})):h.isFunction(g)?a.jqXHR=g.call(j,b,i,a):(a.jqXHR=h.ajax(h.extend(o,g)),g.data=f)}function kb(a){return a.bAjaxDataGet?
+(a.iDraw++,C(a,!0),ra(a,tb(a),function(b){ub(a,b)}),!1):!0}function tb(a){var b=a.aoColumns,c=b.length,e=a.oFeatures,d=a.oPreviousSearch,f=a.aoPreSearchCols,g,j=[],i,o,l,q=U(a);g=a._iDisplayStart;i=!1!==e.bPaginate?a._iDisplayLength:-1;var n=function(a,b){j.push({name:a,value:b})};n("sEcho",a.iDraw);n("iColumns",c);n("sColumns",D(b,"sName").join(","));n("iDisplayStart",g);n("iDisplayLength",i);var k={draw:a.iDraw,columns:[],order:[],start:g,length:i,search:{value:d.sSearch,regex:d.bRegex}};for(g=
+0;g<c;g++)o=b[g],l=f[g],i="function"==typeof o.mData?"function":o.mData,k.columns.push({data:i,name:o.sName,searchable:o.bSearchable,orderable:o.bSortable,search:{value:l.sSearch,regex:l.bRegex}}),n("mDataProp_"+g,i),e.bFilter&&(n("sSearch_"+g,l.sSearch),n("bRegex_"+g,l.bRegex),n("bSearchable_"+g,o.bSearchable)),e.bSort&&n("bSortable_"+g,o.bSortable);e.bFilter&&(n("sSearch",d.sSearch),n("bRegex",d.bRegex));e.bSort&&(h.each(q,function(a,b){k.order.push({column:b.col,dir:b.dir});n("iSortCol_"+a,b.col);
+n("sSortDir_"+a,b.dir)}),n("iSortingCols",q.length));b=m.ext.legacy.ajax;return null===b?a.sAjaxSource?j:k:b?j:k}function ub(a,b){var c=sa(a,b),e=b.sEcho!==k?b.sEcho:b.draw,d=b.iTotalRecords!==k?b.iTotalRecords:b.recordsTotal,f=b.iTotalDisplayRecords!==k?b.iTotalDisplayRecords:b.recordsFiltered;if(e){if(1*e<a.iDraw)return;a.iDraw=1*e}oa(a);a._iRecordsTotal=parseInt(d,10);a._iRecordsDisplay=parseInt(f,10);e=0;for(d=c.length;e<d;e++)K(a,c[e]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;
+M(a);a._bInitComplete||ta(a,b);a.bAjaxDataGet=!0;C(a,!1)}function sa(a,b){var c=h.isPlainObject(a.ajax)&&a.ajax.dataSrc!==k?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?R(c)(b):b}function ob(a){var b=a.oClasses,c=a.sTableId,e=a.oLanguage,d=a.oPreviousSearch,f=a.aanFeatures,g='<input type="search" class="'+b.sFilterInput+'"/>',j=e.sSearch,j=j.match(/_INPUT_/)?j.replace("_INPUT_",g):j+g,b=h("<div/>",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(h("<label/>").append(j)),
+f=function(){var b=!this.value?"":this.value;b!=d.sSearch&&(fa(a,{sSearch:b,bRegex:d.bRegex,bSmart:d.bSmart,bCaseInsensitive:d.bCaseInsensitive}),a._iDisplayStart=0,M(a))},g=null!==a.searchDelay?a.searchDelay:"ssp"===B(a)?400:0,i=h("input",b).val(d.sSearch).attr("placeholder",e.sSearchPlaceholder).bind("keyup.DT search.DT input.DT paste.DT cut.DT",g?ua(f,g):f).bind("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);h(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{i[0]!==
+Q.activeElement&&i.val(d.sSearch)}catch(f){}});return b[0]}function fa(a,b,c){var e=a.oPreviousSearch,d=a.aoPreSearchCols,f=function(a){e.sSearch=a.sSearch;e.bRegex=a.bRegex;e.bSmart=a.bSmart;e.bCaseInsensitive=a.bCaseInsensitive};Ha(a);if("ssp"!=B(a)){vb(a,b.sSearch,c,b.bEscapeRegex!==k?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<d.length;b++)wb(a,d[b].sSearch,b,d[b].bEscapeRegex!==k?!d[b].bEscapeRegex:d[b].bRegex,d[b].bSmart,d[b].bCaseInsensitive);xb(a)}else f(b);a.bFiltered=
+!0;w(a,null,"search",[a])}function xb(a){for(var b=m.ext.search,c=a.aiDisplay,e,d,f=0,g=b.length;f<g;f++){for(var j=[],i=0,h=c.length;i<h;i++)d=c[i],e=a.aoData[d],b[f](a,e._aFilterData,d,e._aData,i)&&j.push(d);c.length=0;c.push.apply(c,j)}}function wb(a,b,c,e,d,f){if(""!==b)for(var g=a.aiDisplay,e=Qa(b,e,d,f),d=g.length-1;0<=d;d--)b=a.aoData[g[d]]._aFilterData[c],e.test(b)||g.splice(d,1)}function vb(a,b,c,e,d,f){var e=Qa(b,e,d,f),d=a.oPreviousSearch.sSearch,f=a.aiDisplayMaster,g;0!==m.ext.search.length&&
+(c=!0);g=yb(a);if(0>=b.length)a.aiDisplay=f.slice();else{if(g||c||d.length>b.length||0!==b.indexOf(d)||a.bSorted)a.aiDisplay=f.slice();b=a.aiDisplay;for(c=b.length-1;0<=c;c--)e.test(a.aoData[b[c]]._sFilterRow)||b.splice(c,1)}}function Qa(a,b,c,e){a=b?a:va(a);c&&(a="^(?=.*?"+h.map(a.match(/"[^"]+"|[^ ]+/g)||[""],function(a){if('"'===a.charAt(0))var b=a.match(/^"(.*)"$/),a=b?b[1]:a;return a.replace('"',"")}).join(")(?=.*?")+").*$");return RegExp(a,e?"i":"")}function va(a){return a.replace(Yb,"\\$1")}
+function yb(a){var b=a.aoColumns,c,e,d,f,g,j,i,h,l=m.ext.type.search;c=!1;e=0;for(f=a.aoData.length;e<f;e++)if(h=a.aoData[e],!h._aFilterData){j=[];d=0;for(g=b.length;d<g;d++)c=b[d],c.bSearchable?(i=x(a,e,d,"filter"),l[c.sType]&&(i=l[c.sType](i)),null===i&&(i=""),"string"!==typeof i&&i.toString&&(i=i.toString())):i="",i.indexOf&&-1!==i.indexOf("&")&&(wa.innerHTML=i,i=Zb?wa.textContent:wa.innerText),i.replace&&(i=i.replace(/[\r\n]/g,"")),j.push(i);h._aFilterData=j;h._sFilterRow=j.join(" ");c=!0}return c}
+function zb(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,caseInsensitive:a.bCaseInsensitive}}function Ab(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}function rb(a){var b=a.sTableId,c=a.aanFeatures.i,e=h("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Bb,sName:"information"}),e.attr("role","status").attr("aria-live","polite"),h(a.nTable).attr("aria-describedby",b+"_info"));return e[0]}function Bb(a){var b=
+a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,e=a._iDisplayStart+1,d=a.fnDisplayEnd(),f=a.fnRecordsTotal(),g=a.fnRecordsDisplay(),j=g?c.sInfo:c.sInfoEmpty;g!==f&&(j+=" "+c.sInfoFiltered);j+=c.sInfoPostFix;j=Cb(a,j);c=c.fnInfoCallback;null!==c&&(j=c.call(a.oInstance,a,e,d,f,g,j));h(b).html(j)}}function Cb(a,b){var c=a.fnFormatNumber,e=a._iDisplayStart+1,d=a._iDisplayLength,f=a.fnRecordsDisplay(),g=-1===d;return b.replace(/_START_/g,c.call(a,e)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,
+c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,f)).replace(/_PAGE_/g,c.call(a,g?1:Math.ceil(e/d))).replace(/_PAGES_/g,c.call(a,g?1:Math.ceil(f/d)))}function ga(a){var b,c,e=a.iInitDisplayStart,d=a.aoColumns,f;c=a.oFeatures;if(a.bInitialised){mb(a);jb(a);ea(a,a.aoHeader);ea(a,a.aoFooter);C(a,!0);c.bAutoWidth&&Ga(a);b=0;for(c=d.length;b<c;b++)f=d[b],f.sWidth&&(f.nTh.style.width=s(f.sWidth));N(a);d=B(a);"ssp"!=d&&("ajax"==d?ra(a,[],function(c){var f=sa(a,c);for(b=0;b<f.length;b++)K(a,f[b]);
+a.iInitDisplayStart=e;N(a);C(a,!1);ta(a,c)},a):(C(a,!1),ta(a)))}else setTimeout(function(){ga(a)},200)}function ta(a,b){a._bInitComplete=!0;b&&X(a);w(a,"aoInitComplete","init",[a,b])}function Ra(a,b){var c=parseInt(b,10);a._iDisplayLength=c;Sa(a);w(a,null,"length",[a,c])}function nb(a){for(var b=a.oClasses,c=a.sTableId,e=a.aLengthMenu,d=h.isArray(e[0]),f=d?e[0]:e,e=d?e[1]:e,d=h("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),g=0,j=f.length;g<j;g++)d[0][g]=new Option(e[g],
+f[g]);var i=h("<div><label/></div>").addClass(b.sLength);a.aanFeatures.l||(i[0].id=c+"_length");i.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",d[0].outerHTML));h("select",i).val(a._iDisplayLength).bind("change.DT",function(){Ra(a,h(this).val());M(a)});h(a.nTable).bind("length.dt.DT",function(b,c,f){a===c&&h("select",i).val(f)});return i[0]}function sb(a){var b=a.sPaginationType,c=m.ext.pager[b],e="function"===typeof c,d=function(a){M(a)},b=h("<div/>").addClass(a.oClasses.sPaging+b)[0],
+f=a.aanFeatures;e||c.fnInit(a,b,d);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(e){var b=a._iDisplayStart,i=a._iDisplayLength,h=a.fnRecordsDisplay(),l=-1===i,b=l?0:Math.ceil(b/i),i=l?1:Math.ceil(h/i),h=c(b,i),q,l=0;for(q=f.p.length;l<q;l++)Pa(a,"pageButton")(a,f.p[l],l,h,b,i)}else c.fnUpdate(a,d)},sName:"pagination"}));return b}function Ta(a,b,c){var e=a._iDisplayStart,d=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===d?e=0:"number"===typeof b?(e=b*d,e>f&&(e=0)):
+"first"==b?e=0:"previous"==b?(e=0<=d?e-d:0,0>e&&(e=0)):"next"==b?e+d<f&&(e+=d):"last"==b?e=Math.floor((f-1)/d)*d:I(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==e;a._iDisplayStart=e;b&&(w(a,null,"page",[a]),c&&M(a));return b}function pb(a){return h("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function C(a,b){a.oFeatures.bProcessing&&h(a.aanFeatures.r).css("display",b?"block":"none");w(a,
+null,"processing",[a,b])}function qb(a){var b=h(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var e=c.sX,d=c.sY,f=a.oClasses,g=b.children("caption"),j=g.length?g[0]._captionSide:null,i=h(b[0].cloneNode(!1)),o=h(b[0].cloneNode(!1)),l=b.children("tfoot");c.sX&&"100%"===b.attr("width")&&b.removeAttr("width");l.length||(l=null);c=h("<div/>",{"class":f.sScrollWrapper}).append(h("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,
+width:e?!e?null:s(e):"100%"}).append(h("<div/>",{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(i.removeAttr("id").css("margin-left",0).append("top"===j?g:null).append(b.children("thead"))))).append(h("<div/>",{"class":f.sScrollBody}).css({overflow:"auto",height:!d?null:s(d),width:!e?null:s(e)}).append(b));l&&c.append(h("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:e?!e?null:s(e):"100%"}).append(h("<div/>",{"class":f.sScrollFootInner}).append(o.removeAttr("id").css("margin-left",
+0).append("bottom"===j?g:null).append(b.children("tfoot")))));var b=c.children(),q=b[0],f=b[1],n=l?b[2]:null;if(e)h(f).on("scroll.DT",function(){var a=this.scrollLeft;q.scrollLeft=a;l&&(n.scrollLeft=a)});a.nScrollHead=q;a.nScrollBody=f;a.nScrollFoot=n;a.aoDrawCallback.push({fn:Y,sName:"scrolling"});return c[0]}function Y(a){var b=a.oScroll,c=b.sX,e=b.sXInner,d=b.sY,f=b.iBarWidth,g=h(a.nScrollHead),j=g[0].style,i=g.children("div"),o=i[0].style,l=i.children("table"),i=a.nScrollBody,q=h(i),n=i.style,
+k=h(a.nScrollFoot).children("div"),p=k.children("table"),m=h(a.nTHead),r=h(a.nTable),t=r[0],O=t.style,L=a.nTFoot?h(a.nTFoot):null,ha=a.oBrowser,w=ha.bScrollOversize,v,u,y,x,z,A=[],B=[],C=[],D,E=function(a){a=a.style;a.paddingTop="0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};r.children("thead, tfoot").remove();z=m.clone().prependTo(r);v=m.find("tr");y=z.find("tr");z.find("th, td").removeAttr("tabindex");L&&(x=L.clone().prependTo(r),u=L.find("tr"),x=x.find("tr"));
+c||(n.width="100%",g[0].style.width="100%");h.each(qa(a,z),function(b,c){D=la(a,b);c.style.width=a.aoColumns[D].sWidth});L&&G(function(a){a.style.width=""},x);b.bCollapse&&""!==d&&(n.height=q[0].offsetHeight+m[0].offsetHeight+"px");g=r.outerWidth();if(""===c){if(O.width="100%",w&&(r.find("tbody").height()>i.offsetHeight||"scroll"==q.css("overflow-y")))O.width=s(r.outerWidth()-f)}else""!==e?O.width=s(e):g==q.width()&&q.height()<r.height()?(O.width=s(g-f),r.outerWidth()>g-f&&(O.width=s(g))):O.width=
+s(g);g=r.outerWidth();G(E,y);G(function(a){C.push(a.innerHTML);A.push(s(h(a).css("width")))},y);G(function(a,b){a.style.width=A[b]},v);h(y).height(0);L&&(G(E,x),G(function(a){B.push(s(h(a).css("width")))},x),G(function(a,b){a.style.width=B[b]},u),h(x).height(0));G(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+C[b]+"</div>";a.style.width=A[b]},y);L&&G(function(a,b){a.innerHTML="";a.style.width=B[b]},x);if(r.outerWidth()<g){u=i.scrollHeight>i.offsetHeight||
+"scroll"==q.css("overflow-y")?g+f:g;if(w&&(i.scrollHeight>i.offsetHeight||"scroll"==q.css("overflow-y")))O.width=s(u-f);(""===c||""!==e)&&I(a,1,"Possible column misalignment",6)}else u="100%";n.width=s(u);j.width=s(u);L&&(a.nScrollFoot.style.width=s(u));!d&&w&&(n.height=s(t.offsetHeight+f));d&&b.bCollapse&&(n.height=s(d),b=c&&t.offsetWidth>i.offsetWidth?f:0,t.offsetHeight<i.offsetHeight&&(n.height=s(t.offsetHeight+b)));b=r.outerWidth();l[0].style.width=s(b);o.width=s(b);l=r.height()>i.clientHeight||
+"scroll"==q.css("overflow-y");ha="padding"+(ha.bScrollbarLeft?"Left":"Right");o[ha]=l?f+"px":"0px";L&&(p[0].style.width=s(b),k[0].style.width=s(b),k[0].style[ha]=l?f+"px":"0px");q.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)i.scrollTop=0}function G(a,b,c){for(var e=0,d=0,f=b.length,g,j;d<f;){g=b[d].firstChild;for(j=c?c[d].firstChild:null;g;)1===g.nodeType&&(c?a(g,j,e):a(g,e),e++),g=g.nextSibling,j=c?j.nextSibling:null;d++}}function Ga(a){var b=a.nTable,c=a.aoColumns,e=a.oScroll,d=e.sY,f=e.sX,
+g=e.sXInner,j=c.length,e=Z(a,"bVisible"),i=h("th",a.nTHead),o=b.getAttribute("width"),l=b.parentNode,k=!1,n,m;(n=b.style.width)&&-1!==n.indexOf("%")&&(o=n);for(n=0;n<e.length;n++)m=c[e[n]],null!==m.sWidth&&(m.sWidth=Db(m.sWidthOrig,l),k=!0);if(!k&&!f&&!d&&j==aa(a)&&j==i.length)for(n=0;n<j;n++)c[n].sWidth=s(i.eq(n).width());else{j=h(b).clone().css("visibility","hidden").removeAttr("id");j.find("tbody tr").remove();var p=h("<tr/>").appendTo(j.find("tbody"));j.find("tfoot th, tfoot td").css("width",
+"");i=qa(a,j.find("thead")[0]);for(n=0;n<e.length;n++)m=c[e[n]],i[n].style.width=null!==m.sWidthOrig&&""!==m.sWidthOrig?s(m.sWidthOrig):"";if(a.aoData.length)for(n=0;n<e.length;n++)k=e[n],m=c[k],h(Eb(a,k)).clone(!1).append(m.sContentPadding).appendTo(p);j.appendTo(l);f&&g?j.width(g):f?(j.css("width","auto"),j.width()<l.offsetWidth&&j.width(l.offsetWidth)):d?j.width(l.offsetWidth):o&&j.width(o);Fb(a,j[0]);if(f){for(n=g=0;n<e.length;n++)m=c[e[n]],d=h(i[n]).outerWidth(),g+=null===m.sWidthOrig?d:parseInt(m.sWidth,
+10)+d-h(i[n]).width();j.width(s(g));b.style.width=s(g)}for(n=0;n<e.length;n++)if(m=c[e[n]],d=h(i[n]).width())m.sWidth=s(d);b.style.width=s(j.css("width"));j.remove()}o&&(b.style.width=s(o));if((o||f)&&!a._reszEvt)b=function(){h(Ea).bind("resize.DT-"+a.sInstance,ua(function(){X(a)}))},a.oBrowser.bScrollOversize?setTimeout(b,1E3):b(),a._reszEvt=!0}function ua(a,b){var c=b!==k?b:200,e,d;return function(){var b=this,g=+new Date,j=arguments;e&&g<e+c?(clearTimeout(d),d=setTimeout(function(){e=k;a.apply(b,
+j)},c)):(e=g,a.apply(b,j))}}function Db(a,b){if(!a)return 0;var c=h("<div/>").css("width",s(a)).appendTo(b||Q.body),e=c[0].offsetWidth;c.remove();return e}function Fb(a,b){var c=a.oScroll;if(c.sX||c.sY)c=!c.sX?c.iBarWidth:0,b.style.width=s(h(b).outerWidth()-c)}function Eb(a,b){var c=Gb(a,b);if(0>c)return null;var e=a.aoData[c];return!e.nTr?h("<td/>").html(x(a,c,b,"display"))[0]:e.anCells[b]}function Gb(a,b){for(var c,e=-1,d=-1,f=0,g=a.aoData.length;f<g;f++)c=x(a,f,b,"display")+"",c=c.replace($b,""),
+c.length>e&&(e=c.length,d=f);return d}function s(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function Hb(){var a=m.__scrollbarWidth;if(a===k){var b=h("<p/>").css({position:"absolute",top:0,left:0,width:"100%",height:150,padding:0,overflow:"scroll",visibility:"hidden"}).appendTo("body"),a=b[0].offsetWidth-b[0].clientWidth;m.__scrollbarWidth=a;b.remove()}return a}function U(a){var b,c,e=[],d=a.aoColumns,f,g,j,i;b=a.aaSortingFixed;c=h.isPlainObject(b);var o=[];
+f=function(a){a.length&&!h.isArray(a[0])?o.push(a):o.push.apply(o,a)};h.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<o.length;a++){i=o[a][0];f=d[i].aDataSort;b=0;for(c=f.length;b<c;b++)g=f[b],j=d[g].sType||"string",o[a]._idx===k&&(o[a]._idx=h.inArray(o[a][1],d[g].asSorting)),e.push({src:i,col:g,dir:o[a][1],index:o[a]._idx,type:j,formatter:m.ext.type.order[j+"-pre"]})}return e}function lb(a){var b,c,e=[],d=m.ext.type.order,f=a.aoData,g=0,j,i=a.aiDisplayMaster,h;
+Ha(a);h=U(a);b=0;for(c=h.length;b<c;b++)j=h[b],j.formatter&&g++,Ib(a,j.col);if("ssp"!=B(a)&&0!==h.length){b=0;for(c=i.length;b<c;b++)e[i[b]]=b;g===h.length?i.sort(function(a,b){var c,d,g,j,i=h.length,k=f[a]._aSortData,m=f[b]._aSortData;for(g=0;g<i;g++)if(j=h[g],c=k[j.col],d=m[j.col],c=c<d?-1:c>d?1:0,0!==c)return"asc"===j.dir?c:-c;c=e[a];d=e[b];return c<d?-1:c>d?1:0}):i.sort(function(a,b){var c,g,j,i,k=h.length,m=f[a]._aSortData,r=f[b]._aSortData;for(j=0;j<k;j++)if(i=h[j],c=m[i.col],g=r[i.col],i=d[i.type+
+"-"+i.dir]||d["string-"+i.dir],c=i(c,g),0!==c)return c;c=e[a];g=e[b];return c<g?-1:c>g?1:0})}a.bSorted=!0}function Jb(a){for(var b,c,e=a.aoColumns,d=U(a),a=a.oLanguage.oAria,f=0,g=e.length;f<g;f++){c=e[f];var j=c.asSorting;b=c.sTitle.replace(/<.*?>/g,"");var i=c.nTh;i.removeAttribute("aria-sort");c.bSortable&&(0<d.length&&d[0].col==f?(i.setAttribute("aria-sort","asc"==d[0].dir?"ascending":"descending"),c=j[d[0].index+1]||j[0]):c=j[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);i.setAttribute("aria-label",
+b)}}function Ua(a,b,c,e){var d=a.aaSorting,f=a.aoColumns[b].asSorting,g=function(a,b){var c=a._idx;c===k&&(c=h.inArray(a[1],f));return c+1<f.length?c+1:b?null:0};"number"===typeof d[0]&&(d=a.aaSorting=[d]);c&&a.oFeatures.bSortMulti?(c=h.inArray(b,D(d,"0")),-1!==c?(b=g(d[c],!0),null===b&&1===d.length&&(b=0),null===b?d.splice(c,1):(d[c][1]=f[b],d[c]._idx=b)):(d.push([b,f[0],0]),d[d.length-1]._idx=0)):d.length&&d[0][0]==b?(b=g(d[0]),d.length=1,d[0][1]=f[b],d[0]._idx=b):(d.length=0,d.push([b,f[0]]),d[0]._idx=
+0);N(a);"function"==typeof e&&e(a)}function Oa(a,b,c,e){var d=a.aoColumns[c];Va(b,{},function(b){!1!==d.bSortable&&(a.oFeatures.bProcessing?(C(a,!0),setTimeout(function(){Ua(a,c,b.shiftKey,e);"ssp"!==B(a)&&C(a,!1)},0)):Ua(a,c,b.shiftKey,e))})}function xa(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,e=U(a),d=a.oFeatures,f,g;if(d.bSort&&d.bSortClasses){d=0;for(f=b.length;d<f;d++)g=b[d].src,h(D(a.aoData,"anCells",g)).removeClass(c+(2>d?d+1:3));d=0;for(f=e.length;d<f;d++)g=e[d].src,h(D(a.aoData,"anCells",
+g)).addClass(c+(2>d?d+1:3))}a.aLastSort=e}function Ib(a,b){var c=a.aoColumns[b],e=m.ext.order[c.sSortDataType],d;e&&(d=e.call(a.oInstance,a,b,$(a,b)));for(var f,g=m.ext.type.order[c.sType+"-pre"],j=0,i=a.aoData.length;j<i;j++)if(c=a.aoData[j],c._aSortData||(c._aSortData=[]),!c._aSortData[b]||e)f=e?d[j]:x(a,j,b,"sort"),c._aSortData[b]=g?g(f):f}function ya(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:h.extend(!0,[],a.aaSorting),
+search:zb(a.oPreviousSearch),columns:h.map(a.aoColumns,function(b,e){return{visible:b.bVisible,search:zb(a.aoPreSearchCols[e])}})};w(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=b;a.fnStateSaveCallback.call(a.oInstance,a,b)}}function Kb(a){var b,c,e=a.aoColumns;if(a.oFeatures.bStateSave){var d=a.fnStateLoadCallback.call(a.oInstance,a);if(d&&d.time&&(b=w(a,"aoStateLoadParams","stateLoadParams",[a,d]),-1===h.inArray(!1,b)&&(b=a.iStateDuration,!(0<b&&d.time<+new Date-1E3*b)&&e.length===
+d.columns.length))){a.oLoadedState=h.extend(!0,{},d);d.start!==k&&(a._iDisplayStart=d.start,a.iInitDisplayStart=d.start);d.length!==k&&(a._iDisplayLength=d.length);d.order!==k&&(a.aaSorting=[],h.each(d.order,function(b,c){a.aaSorting.push(c[0]>=e.length?[0,c[1]]:c)}));d.search!==k&&h.extend(a.oPreviousSearch,Ab(d.search));b=0;for(c=d.columns.length;b<c;b++){var f=d.columns[b];f.visible!==k&&(e[b].bVisible=f.visible);f.search!==k&&h.extend(a.aoPreSearchCols[b],Ab(f.search))}w(a,"aoStateLoaded","stateLoaded",
+[a,d])}}}function za(a){var b=m.settings,a=h.inArray(a,D(b,"nTable"));return-1!==a?b[a]:null}function I(a,b,c,e){c="DataTables warning: "+(null!==a?"table id="+a.sTableId+" - ":"")+c;e&&(c+=". For more information about this error, please see http://datatables.net/tn/"+e);if(b)Ea.console&&console.log&&console.log(c);else if(b=m.ext,b=b.sErrMode||b.errMode,w(a,null,"error",[a,e,c]),"alert"==b)alert(c);else{if("throw"==b)throw Error(c);"function"==typeof b&&b(a,e,c)}}function E(a,b,c,e){h.isArray(c)?
+h.each(c,function(c,f){h.isArray(f)?E(a,b,f[0],f[1]):E(a,b,f)}):(e===k&&(e=c),b[c]!==k&&(a[e]=b[c]))}function Lb(a,b,c){var e,d;for(d in b)b.hasOwnProperty(d)&&(e=b[d],h.isPlainObject(e)?(h.isPlainObject(a[d])||(a[d]={}),h.extend(!0,a[d],e)):a[d]=c&&"data"!==d&&"aaData"!==d&&h.isArray(e)?e.slice():e);return a}function Va(a,b,c){h(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===a.which&&(a.preventDefault(),c(a))}).bind("selectstart.DT",function(){return!1})}function z(a,
+b,c,e){c&&a[b].push({fn:c,sName:e})}function w(a,b,c,e){var d=[];b&&(d=h.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,e)}));null!==c&&(b=h.Event(c+".dt"),h(a.nTable).trigger(b,e),d.push(b.result));return d}function Sa(a){var b=a._iDisplayStart,c=a.fnDisplayEnd(),e=a._iDisplayLength;b>=c&&(b=c-e);b-=b%e;if(-1===e||0>b)b=0;a._iDisplayStart=b}function Pa(a,b){var c=a.renderer,e=m.ext.renderer[b];return h.isPlainObject(c)&&c[b]?e[c[b]]||e._:"string"===typeof c?e[c]||e._:e._}function B(a){return a.oFeatures.bServerSide?
+"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Wa(a,b){var c=[],c=Mb.numbers_length,e=Math.floor(c/2);b<=c?c=V(0,b):a<=e?(c=V(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-e?c=V(b-(c-2),b):(c=V(a-e+2,a+e-1),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function db(a){h.each({num:function(b){return Aa(b,a)},"num-fmt":function(b){return Aa(b,a,Xa)},"html-num":function(b){return Aa(b,a,Ba)},"html-num-fmt":function(b){return Aa(b,a,Ba,Xa)}},function(b,
+c){u.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(u.type.search[b+a]=u.type.search.html)})}function Nb(a){return function(){var b=[za(this[m.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return m.ext.internal[a].apply(this,b)}}var m,u,t,r,v,Ya={},Ob=/[\r\n]/g,Ba=/<.*?>/g,ac=/^[\w\+\-]/,bc=/[\w\+\-]$/,Yb=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Xa=/[',$\u00a3\u20ac\u00a5%\u2009\u202F\u20BD\u20a9\u20BArfk]/gi,J=function(a){return!a||!0===a||
+"-"===a?!0:!1},Pb=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Qb=function(a,b){Ya[b]||(Ya[b]=RegExp(va(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(Ya[b],"."):a},Za=function(a,b,c){var e="string"===typeof a;if(J(a))return!0;b&&e&&(a=Qb(a,b));c&&e&&(a=a.replace(Xa,""));return!isNaN(parseFloat(a))&&isFinite(a)},Rb=function(a,b,c){return J(a)?!0:!(J(a)||"string"===typeof a)?null:Za(a.replace(Ba,""),b,c)?!0:null},D=function(a,b,c){var e=[],d=0,f=a.length;
+if(c!==k)for(;d<f;d++)a[d]&&a[d][b]&&e.push(a[d][b][c]);else for(;d<f;d++)a[d]&&e.push(a[d][b]);return e},ia=function(a,b,c,e){var d=[],f=0,g=b.length;if(e!==k)for(;f<g;f++)a[b[f]][c]&&d.push(a[b[f]][c][e]);else for(;f<g;f++)d.push(a[b[f]][c]);return d},V=function(a,b){var c=[],e;b===k?(b=0,e=a):(e=b,b=a);for(var d=b;d<e;d++)c.push(d);return c},Sb=function(a){for(var b=[],c=0,e=a.length;c<e;c++)a[c]&&b.push(a[c]);return b},Na=function(a){var b=[],c,e,d=a.length,f,g=0;e=0;a:for(;e<d;e++){c=a[e];for(f=
+0;f<g;f++)if(b[f]===c)continue a;b.push(c);g++}return b},A=function(a,b,c){a[b]!==k&&(a[c]=a[b])},ba=/\[.*?\]$/,T=/\(\)$/,wa=h("<div>")[0],Zb=wa.textContent!==k,$b=/<.*?>/g;m=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new t(za(this[u.iApiIndex])):new t(this)};this.fnAddData=function(a,b){var c=this.api(!0),e=h.isArray(a)&&(h.isArray(a[0])||h.isPlainObject(a[0]))?c.rows.add(a):c.row.add(a);(b===
+k||b)&&c.draw();return e.flatten().toArray()};this.fnAdjustColumnSizing=function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],e=c.oScroll;a===k||a?b.draw(!1):(""!==e.sX||""!==e.sY)&&Y(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===k||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var e=this.api(!0),a=e.rows(a),d=a.settings()[0],h=d.aoData[a[0][0]];a.remove();b&&b.call(this,d,h);(c===k||c)&&e.draw();return h};
+this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(a)};this.fnFilter=function(a,b,c,e,d,h){d=this.api(!0);null===b||b===k?d.search(a,c,e,h):d.column(b).search(a,c,e,h);d.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==k){var e=a.nodeName?a.nodeName.toLowerCase():"";return b!==k||"td"==e||"th"==e?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);return a!==k?b.row(a).node():b.rows().nodes().flatten().toArray()};
+this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===k||b)&&c.draw(!1)};this.fnSetColumnVis=function(a,b,c){a=this.api(!0).column(a).visible(b);(c===
+k||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return za(this[u.iApiIndex])};this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,e,d){var h=this.api(!0);c===k||null===c?h.row(b).data(a):h.cell(b,c).data(a);(d===k||d)&&h.columns.adjust();(e===k||e)&&h.draw();return 0};this.fnVersionCheck=u.fnVersionCheck;var b=this,c=a===k,e=this.length;c&&(a={});this.oApi=this.internal=u.internal;for(var d in m.ext.internal)d&&
+(this[d]=Nb(d));this.each(function(){var d={},d=1<e?Lb(d,a,!0):a,g=0,j,i=this.getAttribute("id"),o=!1,l=m.defaults,q=h(this);if("table"!=this.nodeName.toLowerCase())I(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{eb(l);fb(l.column);H(l,l,!0);H(l.column,l.column,!0);H(l,h.extend(d,q.data()));var n=m.settings,g=0;for(j=n.length;g<j;g++){var r=n[g];if(r.nTable==this||r.nTHead.parentNode==this||r.nTFoot&&r.nTFoot.parentNode==this){g=d.bRetrieve!==k?d.bRetrieve:l.bRetrieve;if(c||g)return r.oInstance;
+if(d.bDestroy!==k?d.bDestroy:l.bDestroy){r.oInstance.fnDestroy();break}else{I(r,0,"Cannot reinitialise DataTable",3);return}}if(r.sTableId==this.id){n.splice(g,1);break}}if(null===i||""===i)this.id=i="DataTables_Table_"+m.ext._unique++;var p=h.extend(!0,{},m.models.oSettings,{sDestroyWidth:q[0].style.width,sInstance:i,sTableId:i});p.nTable=this;p.oApi=b.internal;p.oInit=d;n.push(p);p.oInstance=1===b.length?b:q.dataTable();eb(d);d.oLanguage&&P(d.oLanguage);d.aLengthMenu&&!d.iDisplayLength&&(d.iDisplayLength=
+h.isArray(d.aLengthMenu[0])?d.aLengthMenu[0][0]:d.aLengthMenu[0]);d=Lb(h.extend(!0,{},l),d);E(p.oFeatures,d,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));E(p,d,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback",
+"renderer","searchDelay",["iCookieDuration","iStateDuration"],["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"],["bJQueryUI","bJUI"]]);E(p.oScroll,d,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);E(p.oLanguage,d,"fnInfoCallback");z(p,"aoDrawCallback",d.fnDrawCallback,"user");z(p,"aoServerParams",d.fnServerParams,"user");z(p,"aoStateSaveParams",d.fnStateSaveParams,"user");z(p,"aoStateLoadParams",
+d.fnStateLoadParams,"user");z(p,"aoStateLoaded",d.fnStateLoaded,"user");z(p,"aoRowCallback",d.fnRowCallback,"user");z(p,"aoRowCreatedCallback",d.fnCreatedRow,"user");z(p,"aoHeaderCallback",d.fnHeaderCallback,"user");z(p,"aoFooterCallback",d.fnFooterCallback,"user");z(p,"aoInitComplete",d.fnInitComplete,"user");z(p,"aoPreDrawCallback",d.fnPreDrawCallback,"user");i=p.oClasses;d.bJQueryUI?(h.extend(i,m.ext.oJUIClasses,d.oClasses),d.sDom===l.sDom&&"lfrtip"===l.sDom&&(p.sDom='<"H"lfr>t<"F"ip>'),p.renderer)?
+h.isPlainObject(p.renderer)&&!p.renderer.header&&(p.renderer.header="jqueryui"):p.renderer="jqueryui":h.extend(i,m.ext.classes,d.oClasses);q.addClass(i.sTable);if(""!==p.oScroll.sX||""!==p.oScroll.sY)p.oScroll.iBarWidth=Hb();!0===p.oScroll.sX&&(p.oScroll.sX="100%");p.iInitDisplayStart===k&&(p.iInitDisplayStart=d.iDisplayStart,p._iDisplayStart=d.iDisplayStart);null!==d.iDeferLoading&&(p.bDeferLoading=!0,g=h.isArray(d.iDeferLoading),p._iRecordsDisplay=g?d.iDeferLoading[0]:d.iDeferLoading,p._iRecordsTotal=
+g?d.iDeferLoading[1]:d.iDeferLoading);var t=p.oLanguage;h.extend(!0,t,d.oLanguage);""!==t.sUrl&&(h.ajax({dataType:"json",url:t.sUrl,success:function(a){P(a);H(l.oLanguage,a);h.extend(true,t,a);ga(p)},error:function(){ga(p)}}),o=!0);null===d.asStripeClasses&&(p.asStripeClasses=[i.sStripeOdd,i.sStripeEven]);var g=p.asStripeClasses,s=q.children("tbody").find("tr").eq(0);-1!==h.inArray(!0,h.map(g,function(a){return s.hasClass(a)}))&&(h("tbody tr",this).removeClass(g.join(" ")),p.asDestroyStripes=g.slice());
+n=[];g=this.getElementsByTagName("thead");0!==g.length&&(da(p.aoHeader,g[0]),n=qa(p));if(null===d.aoColumns){r=[];g=0;for(j=n.length;g<j;g++)r.push(null)}else r=d.aoColumns;g=0;for(j=r.length;g<j;g++)Fa(p,n?n[g]:null);ib(p,d.aoColumnDefs,r,function(a,b){ka(p,a,b)});if(s.length){var u=function(a,b){return a.getAttribute("data-"+b)!==null?b:null};h.each(na(p,s[0]).cells,function(a,b){var c=p.aoColumns[a];if(c.mData===a){var d=u(b,"sort")||u(b,"order"),e=u(b,"filter")||u(b,"search");if(d!==null||e!==
+null){c.mData={_:a+".display",sort:d!==null?a+".@data-"+d:k,type:d!==null?a+".@data-"+d:k,filter:e!==null?a+".@data-"+e:k};ka(p,a)}}})}var v=p.oFeatures;d.bStateSave&&(v.bStateSave=!0,Kb(p,d),z(p,"aoDrawCallback",ya,"state_save"));if(d.aaSorting===k){n=p.aaSorting;g=0;for(j=n.length;g<j;g++)n[g][1]=p.aoColumns[g].asSorting[0]}xa(p);v.bSort&&z(p,"aoDrawCallback",function(){if(p.bSorted){var a=U(p),b={};h.each(a,function(a,c){b[c.src]=c.dir});w(p,null,"order",[p,a,b]);Jb(p)}});z(p,"aoDrawCallback",
+function(){(p.bSorted||B(p)==="ssp"||v.bDeferRender)&&xa(p)},"sc");gb(p);g=q.children("caption").each(function(){this._captionSide=q.css("caption-side")});j=q.children("thead");0===j.length&&(j=h("<thead/>").appendTo(this));p.nTHead=j[0];j=q.children("tbody");0===j.length&&(j=h("<tbody/>").appendTo(this));p.nTBody=j[0];j=q.children("tfoot");if(0===j.length&&0<g.length&&(""!==p.oScroll.sX||""!==p.oScroll.sY))j=h("<tfoot/>").appendTo(this);0===j.length||0===j.children().length?q.addClass(i.sNoFooter):
+0<j.length&&(p.nTFoot=j[0],da(p.aoFooter,p.nTFoot));if(d.aaData)for(g=0;g<d.aaData.length;g++)K(p,d.aaData[g]);else(p.bDeferLoading||"dom"==B(p))&&ma(p,h(p.nTBody).children("tr"));p.aiDisplay=p.aiDisplayMaster.slice();p.bInitialised=!0;!1===o&&ga(p)}});b=null;return this};var Tb=[],y=Array.prototype,cc=function(a){var b,c,e=m.settings,d=h.map(e,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=h.inArray(a,d),-1!==b?[e[b]]:
+null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=h(a):a instanceof h&&(c=a)}else return[];if(c)return c.map(function(){b=h.inArray(this,d);return-1!==b?e[b]:null}).toArray()};t=function(a,b){if(!(this instanceof t))return new t(a,b);var c=[],e=function(a){(a=cc(a))&&c.push.apply(c,a)};if(h.isArray(a))for(var d=0,f=a.length;d<f;d++)e(a[d]);else e(a);this.context=Na(c);b&&this.push.apply(this,b.toArray?b.toArray():b);this.selector={rows:null,cols:null,opts:null};
+t.extend(this,this,Tb)};m.Api=t;t.prototype={any:function(){return 0!==this.flatten().length},concat:y.concat,context:[],each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=this.context;return b.length>a?new t(b[a],this[a]):null},filter:function(a){var b=[];if(y.filter)b=y.filter.call(this,a,this);else for(var c=0,e=this.length;c<e;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new t(this.context,b)},flatten:function(){var a=[];
+return new t(this.context,a.concat.apply(a,this.toArray()))},join:y.join,indexOf:y.indexOf||function(a,b){for(var c=b||0,e=this.length;c<e;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c,e){var d=[],f,g,h,i,o,l=this.context,q,n,m=this.selector;"string"===typeof a&&(e=c,c=b,b=a,a=!1);g=0;for(h=l.length;g<h;g++){var p=new t(l[g]);if("table"===b)f=c.call(p,l[g],g),f!==k&&d.push(f);else if("columns"===b||"rows"===b)f=c.call(p,l[g],this[g],g),f!==k&&d.push(f);else if("column"===b||"column-rows"===
+b||"row"===b||"cell"===b){n=this[g];"column-rows"===b&&(q=Ca(l[g],m.opts));i=0;for(o=n.length;i<o;i++)f=n[i],f="cell"===b?c.call(p,l[g],f.row,f.column,g,i):c.call(p,l[g],f,g,i,q),f!==k&&d.push(f)}}return d.length||e?(a=new t(l,a?d.concat.apply([],d):d),b=a.selector,b.rows=m.rows,b.cols=m.cols,b.opts=m.opts,a):this},lastIndexOf:y.lastIndexOf||function(a,b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(y.map)b=y.map.call(this,a,this);else for(var c=
+0,e=this.length;c<e;c++)b.push(a.call(this,this[c],c));return new t(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},pop:y.pop,push:y.push,reduce:y.reduce||function(a,b){return hb(this,a,b,0,this.length,1)},reduceRight:y.reduceRight||function(a,b){return hb(this,a,b,this.length-1,-1,-1)},reverse:y.reverse,selector:null,shift:y.shift,sort:y.sort,splice:y.splice,toArray:function(){return y.slice.call(this)},to$:function(){return h(this)},toJQuery:function(){return h(this)},
+unique:function(){return new t(this.context,Na(this))},unshift:y.unshift};t.extend=function(a,b,c){if(c.length&&b&&(b instanceof t||b.__dt_wrapper)){var e,d,f,g=function(a,b,c){return function(){var d=b.apply(a,arguments);t.extend(d,d,c.methodExt);return d}};e=0;for(d=c.length;e<d;e++)f=c[e],b[f.name]="function"===typeof f.val?g(a,f.val,f):h.isPlainObject(f.val)?{}:f.val,b[f.name].__dt_wrapper=!0,t.extend(a,b[f.name],f.propExt)}};t.register=r=function(a,b){if(h.isArray(a))for(var c=0,e=a.length;c<
+e;c++)t.register(a[c],b);else for(var d=a.split("."),f=Tb,g,j,c=0,e=d.length;c<e;c++){g=(j=-1!==d[c].indexOf("()"))?d[c].replace("()",""):d[c];var i;a:{i=0;for(var o=f.length;i<o;i++)if(f[i].name===g){i=f[i];break a}i=null}i||(i={name:g,val:{},methodExt:[],propExt:[]},f.push(i));c===e-1?i.val=b:f=j?i.methodExt:i.propExt}};t.registerPlural=v=function(a,b,c){t.register(a,c);t.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof t?a.length?h.isArray(a[0])?new t(a.context,
+a[0]):a[0]:k:a})};r("tables()",function(a){var b;if(a){b=t;var c=this.context;if("number"===typeof a)a=[c[a]];else var e=h.map(c,function(a){return a.nTable}),a=h(e).filter(a).map(function(){var a=h.inArray(this,e);return c[a]}).toArray();b=new b(a)}else b=this;return b});r("table()",function(a){var a=this.tables(a),b=a.context;return b.length?new t(b[0]):a});v("tables().nodes()","table().node()",function(){return this.iterator("table",function(a){return a.nTable},1)});v("tables().body()","table().body()",
+function(){return this.iterator("table",function(a){return a.nTBody},1)});v("tables().header()","table().header()",function(){return this.iterator("table",function(a){return a.nTHead},1)});v("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot},1)});v("tables().containers()","table().container()",function(){return this.iterator("table",function(a){return a.nTableWrapper},1)});r("draw()",function(a){return this.iterator("table",function(b){N(b,
+!1===a)})});r("page()",function(a){return a===k?this.page.info().page:this.iterator("table",function(b){Ta(b,a)})});r("page.info()",function(){if(0===this.context.length)return k;var a=this.context[0],b=a._iDisplayStart,c=a._iDisplayLength,e=a.fnRecordsDisplay(),d=-1===c;return{page:d?0:Math.floor(b/c),pages:d?1:Math.ceil(e/c),start:b,end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:e}});r("page.len()",function(a){return a===k?0!==this.context.length?this.context[0]._iDisplayLength:
+k:this.iterator("table",function(b){Ra(b,a)})});var Ub=function(a,b,c){if(c){var e=new t(a);e.one("draw",function(){c(e.ajax.json())})}"ssp"==B(a)?N(a,b):(C(a,!0),ra(a,[],function(c){oa(a);for(var c=sa(a,c),e=0,g=c.length;e<g;e++)K(a,c[e]);N(a,b);C(a,!1)}))};r("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});r("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});r("ajax.reload()",function(a,b){return this.iterator("table",function(c){Ub(c,
+!1===b,a)})});r("ajax.url()",function(a){var b=this.context;if(a===k){if(0===b.length)return k;b=b[0];return b.ajax?h.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){h.isPlainObject(b.ajax)?b.ajax.url=a:b.ajax=a})});r("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Ub(c,!1===b,a)})});var $a=function(a,b,c,e,d){var f=[],g,j,i,o,l,q;i=typeof b;if(!b||"string"===i||"function"===i||b.length===k)b=[b];i=0;for(o=b.length;i<o;i++){j=
+b[i]&&b[i].split?b[i].split(","):[b[i]];l=0;for(q=j.length;l<q;l++)(g=c("string"===typeof j[l]?h.trim(j[l]):j[l]))&&g.length&&f.push.apply(f,g)}a=u.selector[a];if(a.length){i=0;for(o=a.length;i<o;i++)f=a[i](e,d,f)}return f},ab=function(a){a||(a={});a.filter&&a.search===k&&(a.search=a.filter);return h.extend({search:"none",order:"current",page:"all"},a)},bb=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=a[b],a[0].length=1,a.length=1,a.context=[a.context[b]],a;a.length=0;return a},
+Ca=function(a,b){var c,e,d,f=[],g=a.aiDisplay;c=a.aiDisplayMaster;var j=b.search;e=b.order;d=b.page;if("ssp"==B(a))return"removed"===j?[]:V(0,c.length);if("current"==d){c=a._iDisplayStart;for(e=a.fnDisplayEnd();c<e;c++)f.push(g[c])}else if("current"==e||"applied"==e)f="none"==j?c.slice():"applied"==j?g.slice():h.map(c,function(a){return-1===h.inArray(a,g)?a:null});else if("index"==e||"original"==e){c=0;for(e=a.aoData.length;c<e;c++)"none"==j?f.push(c):(d=h.inArray(c,g),(-1===d&&"removed"==j||0<=d&&
+"applied"==j)&&f.push(c))}return f};r("rows()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=ab(b),c=this.iterator("table",function(c){var d=b;return $a("row",a,function(a){var b=Pb(a);if(b!==null&&!d)return[b];var j=Ca(c,d);if(b!==null&&h.inArray(b,j)!==-1)return[b];if(!a)return j;if(typeof a==="function")return h.map(j,function(b){var d=c.aoData[b];return a(b,d._aData,d.nTr)?b:null});b=Sb(ia(c.aoData,j,"nTr"));return a.nodeName&&h.inArray(a,b)!==-1?[a._DT_RowIndex]:h(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()},
+c,d)},1);c.selector.rows=a;c.selector.opts=b;return c});r("rows().nodes()",function(){return this.iterator("row",function(a,b){return a.aoData[b].nTr||k},1)});r("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return ia(a.aoData,b,"_aData")},1)});v("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var e=b.aoData[c];return"search"===a?e._aFilterData:e._aSortData},1)});v("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",
+function(b,c){ca(b,c,a)})});v("rows().indexes()","row().index()",function(){return this.iterator("row",function(a,b){return b},1)});v("rows().remove()","row().remove()",function(){var a=this;return this.iterator("row",function(b,c,e){var d=b.aoData;d.splice(c,1);for(var f=0,g=d.length;f<g;f++)null!==d[f].nTr&&(d[f].nTr._DT_RowIndex=f);h.inArray(c,b.aiDisplay);pa(b.aiDisplayMaster,c);pa(b.aiDisplay,c);pa(a[e],c,!1);Sa(b)})});r("rows.add()",function(a){var b=this.iterator("table",function(b){var c,
+f,g,h=[];f=0;for(g=a.length;f<g;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?h.push(ma(b,c)[0]):h.push(K(b,c));return h},1),c=this.rows(-1);c.pop();c.push.apply(c,b.toArray());return c});r("row()",function(a,b){return bb(this.rows(a,b))});r("row().data()",function(a){var b=this.context;if(a===k)return b.length&&this.length?b[0].aoData[this[0]]._aData:k;b[0].aoData[this[0]]._aData=a;ca(b[0],this[0],"data");return this});r("row().node()",function(){var a=this.context;return a.length&&this.length?
+a[0].aoData[this[0]].nTr||null:null});r("row.add()",function(a){a instanceof h&&a.length&&(a=a[0]);var b=this.iterator("table",function(b){return a.nodeName&&"TR"===a.nodeName.toUpperCase()?ma(b,a)[0]:K(b,a)});return this.row(b[0])});var cb=function(a,b){var c=a.context;c.length&&(c=c[0].aoData[b!==k?b:a[0]],c._details&&(c._details.remove(),c._detailsShow=k,c._details=k))},Vb=function(a,b){var c=a.context;if(c.length&&a.length){var e=c[0].aoData[a[0]];if(e._details){(e._detailsShow=b)?e._details.insertAfter(e.nTr):
+e._details.detach();var d=c[0],f=new t(d),g=d.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");0<D(g,"_details").length&&(f.on("draw.dt.DT_details",function(a,b){d===b&&f.rows({page:"current"}).eq(0).each(function(a){a=g[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(d===b)for(var c,e=aa(b),f=0,h=g.length;f<h;f++)c=g[f],c._details&&c._details.children("td[colspan]").attr("colspan",e)}),f.on("destroy.dt.DT_details",
+function(a,b){if(d===b)for(var c=0,e=g.length;c<e;c++)g[c]._details&&cb(f,c)}))}}};r("row().child()",function(a,b){var c=this.context;if(a===k)return c.length&&this.length?c[0].aoData[this[0]]._details:k;if(!0===a)this.child.show();else if(!1===a)cb(this);else if(c.length&&this.length){var e=c[0],c=c[0].aoData[this[0]],d=[],f=function(a,b){if(h.isArray(a)||a instanceof h)for(var c=0,k=a.length;c<k;c++)f(a[c],b);else a.nodeName&&"tr"===a.nodeName.toLowerCase()?d.push(a):(c=h("<tr><td/></tr>").addClass(b),
+h("td",c).addClass(b).html(a)[0].colSpan=aa(e),d.push(c[0]))};f(a,b);c._details&&c._details.remove();c._details=h(d);c._detailsShow&&c._details.insertAfter(c.nTr)}return this});r(["row().child.show()","row().child().show()"],function(){Vb(this,!0);return this});r(["row().child.hide()","row().child().hide()"],function(){Vb(this,!1);return this});r(["row().child.remove()","row().child().remove()"],function(){cb(this);return this});r("row().child.isShown()",function(){var a=this.context;return a.length&&
+this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var dc=/^(.+):(name|visIdx|visible)$/,Wb=function(a,b,c,e,d){for(var c=[],e=0,f=d.length;e<f;e++)c.push(x(a,d[e],b));return c};r("columns()",function(a,b){a===k?a="":h.isPlainObject(a)&&(b=a,a="");var b=ab(b),c=this.iterator("table",function(c){var d=a,f=b,g=c.aoColumns,j=D(g,"sName"),i=D(g,"nTh");return $a("column",d,function(a){var b=Pb(a);if(a==="")return V(g.length);if(b!==null)return[b>=0?b:g.length+b];if(typeof a==="function"){var d=Ca(c,
+f);return h.map(g,function(b,f){return a(f,Wb(c,f,0,0,d),i[f])?f:null})}var k=typeof a==="string"?a.match(dc):"";if(k)switch(k[2]){case "visIdx":case "visible":b=parseInt(k[1],10);if(b<0){var m=h.map(g,function(a,b){return a.bVisible?b:null});return[m[m.length+b]]}return[la(c,b)];case "name":return h.map(j,function(a,b){return a===k[1]?b:null})}else return h(i).filter(a).map(function(){return h.inArray(this,i)}).toArray()},c,f)},1);c.selector.cols=a;c.selector.opts=b;return c});v("columns().header()",
+"column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});v("columns().footer()","column().footer()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTf},1)});v("columns().data()","column().data()",function(){return this.iterator("column-rows",Wb,1)});v("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});v("columns().cache()","column().cache()",
+function(a){return this.iterator("column-rows",function(b,c,e,d,f){return ia(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});v("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",function(a,b,c,e,d){return ia(a.aoData,d,"anCells",b)},1)});v("columns().visible()","column().visible()",function(a,b){return this.iterator("column",function(c,e){if(a===k)return c.aoColumns[e].bVisible;var d=c.aoColumns,f=d[e],g=c.aoData,j,i,m;if(a!==k&&f.bVisible!==a){if(a){var l=
+h.inArray(!0,D(d,"bVisible"),e+1);j=0;for(i=g.length;j<i;j++)m=g[j].nTr,d=g[j].anCells,m&&m.insertBefore(d[e],d[l]||null)}else h(D(c.aoData,"anCells",e)).detach();f.bVisible=a;ea(c,c.aoHeader);ea(c,c.aoFooter);if(b===k||b)X(c),(c.oScroll.sX||c.oScroll.sY)&&Y(c);w(c,null,"column-visibility",[c,e,a]);ya(c)}})});v("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===a?$(b,c):c},1)});r("columns.adjust()",function(){return this.iterator("table",
+function(a){X(a)},1)});r("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return la(c,b);if("fromData"===a||"toVisible"===a)return $(c,b)}});r("column()",function(a,b){return bb(this.columns(a,b))});r("cells()",function(a,b,c){h.isPlainObject(a)&&(a.row===k?(c=a,a=null):(c=b,b=null));h.isPlainObject(b)&&(c=b,b=null);if(null===b||b===k)return this.iterator("table",function(b){var d=a,e=ab(c),f=b.aoData,g=Ca(b,e),i=Sb(ia(f,g,"anCells")),
+j=h([].concat.apply([],i)),l,m=b.aoColumns.length,o,r,t,s,u,v;return $a("cell",d,function(a){var c=typeof a==="function";if(a===null||a===k||c){o=[];r=0;for(t=g.length;r<t;r++){l=g[r];for(s=0;s<m;s++){u={row:l,column:s};if(c){v=b.aoData[l];a(u,x(b,l,s),v.anCells?v.anCells[s]:null)&&o.push(u)}else o.push(u)}}return o}return h.isPlainObject(a)?[a]:j.filter(a).map(function(a,b){l=b.parentNode._DT_RowIndex;return{row:l,column:h.inArray(b,f[l].anCells)}}).toArray()},b,e)});var e=this.columns(b,c),d=this.rows(a,
+c),f,g,j,i,m,l=this.iterator("table",function(a,b){f=[];g=0;for(j=d[b].length;g<j;g++){i=0;for(m=e[b].length;i<m;i++)f.push({row:d[b][g],column:e[b][i]})}return f},1);h.extend(l.selector,{cols:b,rows:a,opts:c});return l});v("cells().nodes()","cell().node()",function(){return this.iterator("cell",function(a,b,c){return(a=a.aoData[b].anCells)?a[c]:k},1)});r("cells().data()",function(){return this.iterator("cell",function(a,b,c){return x(a,b,c)},1)});v("cells().cache()","cell().cache()",function(a){a=
+"search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,e){return b.aoData[c][a][e]},1)});v("cells().render()","cell().render()",function(a){return this.iterator("cell",function(b,c,e){return x(b,c,e,a)},1)});v("cells().indexes()","cell().index()",function(){return this.iterator("cell",function(a,b,c){return{row:b,column:c,columnVisible:$(a,c)}},1)});v("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(b,c,e){ca(b,c,a,e)})});r("cell()",
+function(a,b,c){return bb(this.cells(a,b,c))});r("cell().data()",function(a){var b=this.context,c=this[0];if(a===k)return b.length&&c.length?x(b[0],c[0].row,c[0].column):k;Ia(b[0],c[0].row,c[0].column,a);ca(b[0],c[0].row,"data",c[0].column);return this});r("order()",function(a,b){var c=this.context;if(a===k)return 0!==c.length?c[0].aaSorting:k;"number"===typeof a?a=[[a,b]]:h.isArray(a[0])||(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});
+r("order.listener()",function(a,b,c){return this.iterator("table",function(e){Oa(e,a,b,c)})});r(["columns().order()","column().order()"],function(a){var b=this;return this.iterator("table",function(c,e){var d=[];h.each(b[e],function(b,c){d.push([c,a])});c.aaSorting=d})});r("search()",function(a,b,c,e){var d=this.context;return a===k?0!==d.length?d[0].oPreviousSearch.sSearch:k:this.iterator("table",function(d){d.oFeatures.bFilter&&fa(d,h.extend({},d.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:
+b,bSmart:null===c?!0:c,bCaseInsensitive:null===e?!0:e}),1)})});v("columns().search()","column().search()",function(a,b,c,e){return this.iterator("column",function(d,f){var g=d.aoPreSearchCols;if(a===k)return g[f].sSearch;d.oFeatures.bFilter&&(h.extend(g[f],{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===e?!0:e}),fa(d,d.oPreviousSearch,1))})});r("state()",function(){return this.context.length?this.context[0].oSavedState:null});r("state.clear()",function(){return this.iterator("table",
+function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});r("state.loaded()",function(){return this.context.length?this.context[0].oLoadedState:null});r("state.save()",function(){return this.iterator("table",function(a){ya(a)})});m.versionCheck=m.fnVersionCheck=function(a){for(var b=m.version.split("."),a=a.split("."),c,e,d=0,f=a.length;d<f;d++)if(c=parseInt(b[d],10)||0,e=parseInt(a[d],10)||0,c!==e)return c>e;return!0};m.isDataTable=m.fnIsDataTable=function(a){var b=h(a).get(0),c=!1;h.each(m.settings,
+function(a,d){var f=d.nScrollHead?h("table",d.nScrollHead)[0]:null,g=d.nScrollFoot?h("table",d.nScrollFoot)[0]:null;if(d.nTable===b||f===b||g===b)c=!0});return c};m.tables=m.fnTables=function(a){return h.map(m.settings,function(b){if(!a||a&&h(b.nTable).is(":visible"))return b.nTable})};m.util={throttle:ua,escapeRegex:va};m.camelToHungarian=H;r("$()",function(a,b){var c=this.rows(b).nodes(),c=h(c);return h([].concat(c.filter(a).toArray(),c.find(a).toArray()))});h.each(["on","one","off"],function(a,
+b){r(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0].match(/\.dt\b/)||(a[0]+=".dt");var e=h(this.tables().nodes());e[b].apply(e,a);return this})});r("clear()",function(){return this.iterator("table",function(a){oa(a)})});r("settings()",function(){return new t(this.context,this.context)});r("init()",function(){var a=this.context;return a.length?a[0].oInit:null});r("data()",function(){return this.iterator("table",function(a){return D(a.aoData,"_aData")}).flatten()});r("destroy()",
+function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,e=b.oClasses,d=b.nTable,f=b.nTBody,g=b.nTHead,j=b.nTFoot,i=h(d),f=h(f),k=h(b.nTableWrapper),l=h.map(b.aoData,function(a){return a.nTr}),q;b.bDestroying=!0;w(b,"aoDestroyCallback","destroy",[b]);a||(new t(b)).columns().visible(!0);k.unbind(".DT").find(":not(tbody *)").unbind(".DT");h(Ea).unbind(".DT-"+b.sInstance);d!=g.parentNode&&(i.children("thead").detach(),i.append(g));j&&d!=j.parentNode&&(i.children("tfoot").detach(),
+i.append(j));i.detach();k.detach();b.aaSorting=[];b.aaSortingFixed=[];xa(b);h(l).removeClass(b.asStripeClasses.join(" "));h("th, td",g).removeClass(e.sSortable+" "+e.sSortableAsc+" "+e.sSortableDesc+" "+e.sSortableNone);b.bJUI&&(h("th span."+e.sSortIcon+", td span."+e.sSortIcon,g).detach(),h("th, td",g).each(function(){var a=h("div."+e.sSortJUIWrapper,this);h(this).append(a.contents());a.detach()}));!a&&c&&c.insertBefore(d,b.nTableReinsertBefore);f.children().detach();f.append(l);i.css("width",b.sDestroyWidth).removeClass(e.sTable);
+(q=b.asDestroyStripes.length)&&f.children().each(function(a){h(this).addClass(b.asDestroyStripes[a%q])});c=h.inArray(b,m.settings);-1!==c&&m.settings.splice(c,1)})});h.each(["column","row","cell"],function(a,b){r(b+"s().every()",function(a){return this.iterator(b,function(e,d,f){a.call((new t(e))[b](d,f))})})});r("i18n()",function(a,b,c){var e=this.context[0],a=R(a)(e.oLanguage);a===k&&(a=b);c!==k&&h.isPlainObject(a)&&(a=a[c]!==k?a[c]:a._);return a.replace("%d",c)});m.version="1.10.7";m.settings=
+[];m.models={};m.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};m.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null};m.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",
+sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};m.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,
+fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,
+fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},
+sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:h.extend({},m.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,
+sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null};W(m.defaults);m.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};W(m.defaults.column);m.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,
+bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],
+sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,
+bAjaxDataGet:!0,jqXHR:null,json:k,oAjaxData:k,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==B(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==B(this)?1*this._iRecordsDisplay:
+this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,e=this.aiDisplay.length,d=this.oFeatures,f=d.bPaginate;return d.bServerSide?!1===f||-1===a?b+e:Math.min(b+a,this._iRecordsDisplay):!f||c>e||-1===a?e:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{}};m.ext=u={buttons:{},classes:{},errMode:"alert",feature:[],search:[],selector:{cell:[],column:[],row:[]},internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},
+header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:m.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:m.version};h.extend(u,{afnFiltering:u.search,aTypes:u.type.detect,ofnSearch:u.type.search,oSort:u.type.order,afnSortData:u.order,aoFeatures:u.feature,oApi:u.internal,oStdClasses:u.classes,oPagination:u.pager});h.extend(m.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",
+sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",
+sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Da="",Da="",F=Da+"ui-state-default",ja=Da+"css_right ui-icon ui-icon-",Xb=Da+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";h.extend(m.ext.oJUIClasses,
+m.ext.classes,{sPageButton:"fg-button ui-button "+F,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:F+" sorting_asc",sSortDesc:F+" sorting_desc",sSortable:F+" sorting",sSortableAsc:F+" sorting_asc_disabled",sSortableDesc:F+" sorting_desc_disabled",sSortableNone:F+" sorting_disabled",sSortJUIAsc:ja+"triangle-1-n",sSortJUIDesc:ja+"triangle-1-s",sSortJUI:ja+"carat-2-n-s",
+sSortJUIAscAllowed:ja+"carat-1-n",sSortJUIDescAllowed:ja+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+F,sScrollFoot:"dataTables_scrollFoot "+F,sHeaderTH:F,sFooterTH:F,sJUIHeader:Xb+" ui-corner-tl ui-corner-tr",sJUIFooter:Xb+" ui-corner-bl ui-corner-br"});var Mb=m.ext.pager;h.extend(Mb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},simple_numbers:function(a,b){return["previous",
+Wa(a,b),"next"]},full_numbers:function(a,b){return["first","previous",Wa(a,b),"next","last"]},_numbers:Wa,numbers_length:7});h.extend(!0,m.ext.renderer,{pageButton:{_:function(a,b,c,e,d,f){var g=a.oClasses,j=a.oLanguage.oPaginate,i,k,l=0,m=function(b,e){var n,r,t,s,u=function(b){Ta(a,b.data.action,true)};n=0;for(r=e.length;n<r;n++){s=e[n];if(h.isArray(s)){t=h("<"+(s.DT_el||"div")+"/>").appendTo(b);m(t,s)}else{k=i="";switch(s){case "ellipsis":b.append('<span class="ellipsis">…</span>');break;
+case "first":i=j.sFirst;k=s+(d>0?"":" "+g.sPageButtonDisabled);break;case "previous":i=j.sPrevious;k=s+(d>0?"":" "+g.sPageButtonDisabled);break;case "next":i=j.sNext;k=s+(d<f-1?"":" "+g.sPageButtonDisabled);break;case "last":i=j.sLast;k=s+(d<f-1?"":" "+g.sPageButtonDisabled);break;default:i=s+1;k=d===s?g.sPageButtonActive:""}if(i){t=h("<a>",{"class":g.sPageButton+" "+k,"aria-controls":a.sTableId,"data-dt-idx":l,tabindex:a.iTabIndex,id:c===0&&typeof s==="string"?a.sTableId+"_"+s:null}).html(i).appendTo(b);
+Va(t,{action:s},u);l++}}}},n;try{n=h(Q.activeElement).data("dt-idx")}catch(r){}m(h(b).empty(),e);n&&h(b).find("[data-dt-idx="+n+"]").focus()}}});h.extend(m.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;return Za(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&(!ac.test(a)||!bc.test(a)))return null;var b=Date.parse(a);return null!==b&&!isNaN(b)||J(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return Za(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;
+return Rb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Rb(a,c,!0)?"html-num-fmt"+c:null},function(a){return J(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);h.extend(m.ext.type.search,{html:function(a){return J(a)?a:"string"===typeof a?a.replace(Ob," ").replace(Ba,""):""},string:function(a){return J(a)?a:"string"===typeof a?a.replace(Ob," "):a}});var Aa=function(a,b,c,e){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Qb(a,b));a.replace&&(c&&(a=a.replace(c,"")),
+e&&(a=a.replace(e,"")));return 1*a};h.extend(u.type.order,{"date-pre":function(a){return Date.parse(a)||0},"html-pre":function(a){return J(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return J(a)?"":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a<b?-1:a>b?1:0},"string-desc":function(a,b){return a<b?1:a>b?-1:0}});db("");h.extend(!0,m.ext.renderer,{header:{_:function(a,b,c,e){h(a.nTable).on("order.dt.DT",function(d,
+f,g,h){if(a===f){d=c.idx;b.removeClass(c.sSortingClass+" "+e.sSortAsc+" "+e.sSortDesc).addClass(h[d]=="asc"?e.sSortAsc:h[d]=="desc"?e.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,e){h("<div/>").addClass(e.sSortJUIWrapper).append(b.contents()).append(h("<span/>").addClass(e.sSortIcon+" "+c.sSortingClassJUI)).appendTo(b);h(a.nTable).on("order.dt.DT",function(d,f,g,h){if(a===f){d=c.idx;b.removeClass(e.sSortAsc+" "+e.sSortDesc).addClass(h[d]=="asc"?e.sSortAsc:h[d]=="desc"?e.sSortDesc:c.sSortingClass);
+b.find("span."+e.sSortIcon).removeClass(e.sSortJUIAsc+" "+e.sSortJUIDesc+" "+e.sSortJUI+" "+e.sSortJUIAscAllowed+" "+e.sSortJUIDescAllowed).addClass(h[d]=="asc"?e.sSortJUIAsc:h[d]=="desc"?e.sSortJUIDesc:c.sSortingClassJUI)}})}}});m.render={number:function(a,b,c,e){return{display:function(d){if("number"!==typeof d&&"string"!==typeof d)return d;var f=0>d?"-":"",d=Math.abs(parseFloat(d)),g=parseInt(d,10),d=c?b+(d-g).toFixed(c).substring(2):"";return f+(e||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,
+a)+d}}}};h.extend(m.ext.internal,{_fnExternApiFunc:Nb,_fnBuildAjax:ra,_fnAjaxUpdate:kb,_fnAjaxParameters:tb,_fnAjaxUpdateDraw:ub,_fnAjaxDataSrc:sa,_fnAddColumn:Fa,_fnColumnOptions:ka,_fnAdjustColumnSizing:X,_fnVisibleToColumnIndex:la,_fnColumnIndexToVisible:$,_fnVisbleColumns:aa,_fnGetColumns:Z,_fnColumnTypes:Ha,_fnApplyColumnDefs:ib,_fnHungarianMap:W,_fnCamelToHungarian:H,_fnLanguageCompat:P,_fnBrowserDetect:gb,_fnAddData:K,_fnAddTr:ma,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==k?b._DT_RowIndex:
+null},_fnNodeToColumnIndex:function(a,b,c){return h.inArray(c,a.aoData[b].anCells)},_fnGetCellData:x,_fnSetCellData:Ia,_fnSplitObjNotation:Ka,_fnGetObjectDataFn:R,_fnSetObjectDataFn:S,_fnGetDataMaster:La,_fnClearTable:oa,_fnDeleteIndex:pa,_fnInvalidate:ca,_fnGetRowElements:na,_fnCreateTr:Ja,_fnBuildHead:jb,_fnDrawHead:ea,_fnDraw:M,_fnReDraw:N,_fnAddOptionsHtml:mb,_fnDetectHeader:da,_fnGetUniqueThs:qa,_fnFeatureHtmlFilter:ob,_fnFilterComplete:fa,_fnFilterCustom:xb,_fnFilterColumn:wb,_fnFilter:vb,_fnFilterCreateSearch:Qa,
+_fnEscapeRegex:va,_fnFilterData:yb,_fnFeatureHtmlInfo:rb,_fnUpdateInfo:Bb,_fnInfoMacros:Cb,_fnInitialise:ga,_fnInitComplete:ta,_fnLengthChange:Ra,_fnFeatureHtmlLength:nb,_fnFeatureHtmlPaginate:sb,_fnPageChange:Ta,_fnFeatureHtmlProcessing:pb,_fnProcessingDisplay:C,_fnFeatureHtmlTable:qb,_fnScrollDraw:Y,_fnApplyToChildren:G,_fnCalculateColumnWidths:Ga,_fnThrottle:ua,_fnConvertToWidth:Db,_fnScrollingWidthAdjust:Fb,_fnGetWidestNode:Eb,_fnGetMaxLenString:Gb,_fnStringToCss:s,_fnScrollBarWidth:Hb,_fnSortFlatten:U,
+_fnSort:lb,_fnSortAria:Jb,_fnSortListener:Ua,_fnSortAttachListener:Oa,_fnSortingClasses:xa,_fnSortData:Ib,_fnSaveState:ya,_fnLoadState:Kb,_fnSettingsFromNode:za,_fnLog:I,_fnMap:E,_fnBindAction:Va,_fnCallbackReg:z,_fnCallbackFire:w,_fnLengthOverflow:Sa,_fnRenderer:Pa,_fnDataSource:B,_fnRowAttributes:Ma,_fnCalculateEnd:function(){}});h.fn.dataTable=m;h.fn.dataTableSettings=m.settings;h.fn.dataTableExt=m.ext;h.fn.DataTable=function(a){return h(this).dataTable(a).api()};h.each(m,function(a,b){h.fn.DataTable[a]=
+b});return h.fn.dataTable};"function"===typeof define&&define.amd?define("datatables",["jquery"],P):"object"===typeof exports?module.exports=P(require("jquery")):jQuery&&!jQuery.fn.dataTable&&P(jQuery)})(window,document);
--- /dev/null
+/*
+ * Table styles
+ */
+table.dataTable {
+ width: 100%;
+ margin: 0 auto;
+ clear: both;
+ border-collapse: separate;
+ border-spacing: 0;
+ /*
+ * Header and footer styles
+ */
+ /*
+ * Body styles
+ */
+}
+table.dataTable thead th,
+table.dataTable thead td,
+table.dataTable tfoot th,
+table.dataTable tfoot td {
+ padding: 4px 10px;
+}
+table.dataTable thead th,
+table.dataTable tfoot th {
+ font-weight: bold;
+}
+table.dataTable thead th:active,
+table.dataTable thead td:active {
+ outline: none;
+}
+table.dataTable thead .sorting_asc,
+table.dataTable thead .sorting_desc,
+table.dataTable thead .sorting {
+ cursor: pointer;
+ *cursor: hand;
+}
+table.dataTable thead th div.DataTables_sort_wrapper {
+ position: relative;
+ padding-right: 10px;
+}
+table.dataTable thead th div.DataTables_sort_wrapper span {
+ position: absolute;
+ top: 50%;
+ margin-top: -8px;
+ right: -5px;
+}
+table.dataTable thead th.ui-state-default {
+ border-right-width: 0;
+}
+table.dataTable thead th.ui-state-default:last-child {
+ border-right-width: 1px;
+}
+table.dataTable tbody tr {
+ background-color: #ffffff;
+}
+table.dataTable tbody tr.selected {
+ background-color: #B0BED9;
+}
+table.dataTable tbody th,
+table.dataTable tbody td {
+ padding: 8px 10px;
+}
+table.dataTable th.center,
+table.dataTable td.center,
+table.dataTable td.dataTables_empty {
+ text-align: center;
+}
+table.dataTable th.right,
+table.dataTable td.right {
+ text-align: right;
+}
+table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
+ border-top: 1px solid #ddd;
+}
+table.dataTable.row-border tbody tr:first-child th,
+table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
+table.dataTable.display tbody tr:first-child td {
+ border-top: none;
+}
+table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
+ border-top: 1px solid #ddd;
+ border-right: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr th:first-child,
+table.dataTable.cell-border tbody tr td:first-child {
+ border-left: 1px solid #ddd;
+}
+table.dataTable.cell-border tbody tr:first-child th,
+table.dataTable.cell-border tbody tr:first-child td {
+ border-top: none;
+}
+table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
+ background-color: #f9f9f9;
+}
+table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
+ background-color: #abb9d3;
+}
+table.dataTable.hover tbody tr:hover,
+table.dataTable.hover tbody tr.odd:hover,
+table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,
+table.dataTable.display tbody tr.odd:hover,
+table.dataTable.display tbody tr.even:hover {
+ background-color: whitesmoke;
+}
+table.dataTable.hover tbody tr:hover.selected,
+table.dataTable.hover tbody tr.odd:hover.selected,
+table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,
+table.dataTable.display tbody tr.odd:hover.selected,
+table.dataTable.display tbody tr.even:hover.selected {
+ background-color: #a9b7d1;
+}
+table.dataTable.order-column tbody tr > .sorting_1,
+table.dataTable.order-column tbody tr > .sorting_2,
+table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
+table.dataTable.display tbody tr > .sorting_2,
+table.dataTable.display tbody tr > .sorting_3 {
+ background-color: #f9f9f9;
+}
+table.dataTable.order-column tbody tr.selected > .sorting_1,
+table.dataTable.order-column tbody tr.selected > .sorting_2,
+table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
+table.dataTable.display tbody tr.selected > .sorting_2,
+table.dataTable.display tbody tr.selected > .sorting_3 {
+ background-color: #acbad4;
+}
+table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
+ background-color: #f1f1f1;
+}
+table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
+ background-color: #f3f3f3;
+}
+table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
+ background-color: whitesmoke;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
+ background-color: #a6b3cd;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
+ background-color: #a7b5ce;
+}
+table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
+ background-color: #a9b6d0;
+}
+table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
+ background-color: #f9f9f9;
+}
+table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
+ background-color: #fbfbfb;
+}
+table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
+ background-color: #fdfdfd;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
+ background-color: #acbad4;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
+ background-color: #adbbd6;
+}
+table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
+ background-color: #afbdd8;
+}
+table.dataTable.display tbody tr:hover > .sorting_1,
+table.dataTable.display tbody tr.odd:hover > .sorting_1,
+table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {
+ background-color: #eaeaea;
+}
+table.dataTable.display tbody tr:hover > .sorting_2,
+table.dataTable.display tbody tr.odd:hover > .sorting_2,
+table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {
+ background-color: #ebebeb;
+}
+table.dataTable.display tbody tr:hover > .sorting_3,
+table.dataTable.display tbody tr.odd:hover > .sorting_3,
+table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,
+table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,
+table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {
+ background-color: #eeeeee;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_1,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_1,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {
+ background-color: #a1aec7;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_2,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_2,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {
+ background-color: #a2afc8;
+}
+table.dataTable.display tbody tr:hover.selected > .sorting_3,
+table.dataTable.display tbody tr.odd:hover.selected > .sorting_3,
+table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,
+table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,
+table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {
+ background-color: #a4b2cb;
+}
+table.dataTable.nowrap th, table.dataTable.nowrap td {
+ white-space: nowrap;
+}
+table.dataTable.compact thead th,
+table.dataTable.compact thead td {
+ padding: 5px 9px;
+}
+table.dataTable.compact tfoot th,
+table.dataTable.compact tfoot td {
+ padding: 5px 9px 3px 9px;
+}
+table.dataTable.compact tbody th,
+table.dataTable.compact tbody td {
+ padding: 4px 5px;
+}
+table.dataTable th.dt-left,
+table.dataTable td.dt-left {
+ text-align: left;
+}
+table.dataTable th.dt-center,
+table.dataTable td.dt-center,
+table.dataTable td.dataTables_empty {
+ text-align: center;
+}
+table.dataTable th.dt-right,
+table.dataTable td.dt-right {
+ text-align: right;
+}
+table.dataTable th.dt-justify,
+table.dataTable td.dt-justify {
+ text-align: justify;
+}
+table.dataTable th.dt-nowrap,
+table.dataTable td.dt-nowrap {
+ white-space: nowrap;
+}
+table.dataTable thead th.dt-head-left,
+table.dataTable thead td.dt-head-left,
+table.dataTable tfoot th.dt-head-left,
+table.dataTable tfoot td.dt-head-left {
+ text-align: left;
+}
+table.dataTable thead th.dt-head-center,
+table.dataTable thead td.dt-head-center,
+table.dataTable tfoot th.dt-head-center,
+table.dataTable tfoot td.dt-head-center {
+ text-align: center;
+}
+table.dataTable thead th.dt-head-right,
+table.dataTable thead td.dt-head-right,
+table.dataTable tfoot th.dt-head-right,
+table.dataTable tfoot td.dt-head-right {
+ text-align: right;
+}
+table.dataTable thead th.dt-head-justify,
+table.dataTable thead td.dt-head-justify,
+table.dataTable tfoot th.dt-head-justify,
+table.dataTable tfoot td.dt-head-justify {
+ text-align: justify;
+}
+table.dataTable thead th.dt-head-nowrap,
+table.dataTable thead td.dt-head-nowrap,
+table.dataTable tfoot th.dt-head-nowrap,
+table.dataTable tfoot td.dt-head-nowrap {
+ white-space: nowrap;
+}
+table.dataTable tbody th.dt-body-left,
+table.dataTable tbody td.dt-body-left {
+ text-align: left;
+}
+table.dataTable tbody th.dt-body-center,
+table.dataTable tbody td.dt-body-center {
+ text-align: center;
+}
+table.dataTable tbody th.dt-body-right,
+table.dataTable tbody td.dt-body-right {
+ text-align: right;
+}
+table.dataTable tbody th.dt-body-justify,
+table.dataTable tbody td.dt-body-justify {
+ text-align: justify;
+}
+table.dataTable tbody th.dt-body-nowrap,
+table.dataTable tbody td.dt-body-nowrap {
+ white-space: nowrap;
+}
+
+table.dataTable,
+table.dataTable th,
+table.dataTable td {
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+
+/*
+ * Control feature layout
+ */
+.dataTables_wrapper {
+ position: relative;
+ clear: both;
+ *zoom: 1;
+ zoom: 1;
+}
+.dataTables_wrapper .dataTables_length {
+ float: left;
+}
+.dataTables_wrapper .dataTables_filter {
+ float: right;
+ text-align: right;
+}
+.dataTables_wrapper .dataTables_filter input {
+ margin-left: 0.5em;
+}
+.dataTables_wrapper .dataTables_info {
+ clear: both;
+ float: left;
+ padding-top: 0.55em;
+}
+.dataTables_wrapper .dataTables_paginate {
+ float: right;
+ text-align: right;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button {
+ box-sizing: border-box;
+ display: inline-block;
+ min-width: 1.5em;
+ padding: 0.5em;
+ margin-left: 2px;
+ text-align: center;
+ text-decoration: none !important;
+ cursor: pointer;
+ *cursor: hand;
+ color: #333 !important;
+ border: 1px solid transparent;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:active {
+ outline: none;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:first-child {
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+.dataTables_wrapper .dataTables_paginate .fg-button:last-child {
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+.dataTables_wrapper .dataTables_processing {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 100%;
+ height: 40px;
+ margin-left: -50%;
+ margin-top: -25px;
+ padding-top: 20px;
+ text-align: center;
+ font-size: 1.2em;
+ background-color: white;
+ background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
+ /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+ /* Chrome10+,Safari5.1+ */
+ background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+ /* FF3.6+ */
+ background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+ /* IE10+ */
+ background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+ /* Opera 11.10+ */
+ background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
+ /* W3C */
+}
+.dataTables_wrapper .dataTables_length,
+.dataTables_wrapper .dataTables_filter,
+.dataTables_wrapper .dataTables_info,
+.dataTables_wrapper .dataTables_processing,
+.dataTables_wrapper .dataTables_paginate {
+ color: #333;
+}
+.dataTables_wrapper .dataTables_scroll {
+ clear: both;
+}
+.dataTables_wrapper .dataTables_scrollBody {
+ *margin-top: -1px;
+ -webkit-overflow-scrolling: touch;
+}
+.dataTables_wrapper .ui-widget-header {
+ font-weight: normal;
+}
+.dataTables_wrapper .ui-toolbar {
+ padding: 8px;
+}
+.dataTables_wrapper:after {
+ visibility: hidden;
+ display: block;
+ content: "";
+ clear: both;
+ height: 0;
+}
+
+@media screen and (max-width: 767px) {
+ .dataTables_wrapper .dataTables_length,
+ .dataTables_wrapper .dataTables_filter,
+ .dataTables_wrapper .dataTables_info,
+ .dataTables_wrapper .dataTables_paginate {
+ float: none;
+ text-align: center;
+ }
+ .dataTables_wrapper .dataTables_filter,
+ .dataTables_wrapper .dataTables_paginate {
+ margin-top: 0.5em;
+ }
+}
--- /dev/null
+/*! jQuery v2.1.4 | (c) 2005, 2015 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b="length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,aa=/[+~]/,ba=/'|\\/g,ca=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),da=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ea=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fa){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(ba,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+ra(o[l]);w=aa.test(a)&&pa(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",ea,!1):e.attachEvent&&e.attachEvent("onunload",ea)),p=!f(g),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ca,da);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\f]' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?la(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ca,da),a[3]=(a[3]||a[4]||a[5]||"").replace(ca,da),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ca,da).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(ca,da),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return W.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(ca,da).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:oa(function(){return[0]}),last:oa(function(a,b){return[b-1]}),eq:oa(function(a,b,c){return[0>c?c+b:c]}),even:oa(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:oa(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:oa(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:oa(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function qa(){}qa.prototype=d.filters=d.pseudos,d.setFilters=new qa,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function ra(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function sa(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function ta(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ua(a,b,c){for(var d=0,e=b.length;e>d;d++)ga(a,b[d],c);return c}function va(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wa(a,b,c,d,e,f){return d&&!d[u]&&(d=wa(d)),e&&!e[u]&&(e=wa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ua(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:va(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=va(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=va(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sa(function(a){return a===b},h,!0),l=sa(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sa(ta(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wa(i>1&&ta(m),i>1&&ra(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xa(a.slice(i,e)),f>e&&xa(a=a.slice(e)),f>e&&ra(a))}m.push(c)}return ta(m)}function ya(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=va(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&ga.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,ya(e,d)),f.selector=a}return f},i=ga.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ca,da),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ca,da),aa.test(j[0].type)&&pa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&ra(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,aa.test(a)&&pa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){
+return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,ba=/<([\w:]+)/,ca=/<|&#?\w+;/,da=/<(?:script|style|link)/i,ea=/checked\s*(?:[^=]|=\s*.checked.)/i,fa=/^$|\/(?:java|ecma)script/i,ga=/^true\/(.*)/,ha=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ia={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ia.optgroup=ia.option,ia.tbody=ia.tfoot=ia.colgroup=ia.caption=ia.thead,ia.th=ia.td;function ja(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function ka(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function la(a){var b=ga.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function ma(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function na(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function oa(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pa(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=oa(h),f=oa(a),d=0,e=f.length;e>d;d++)pa(f[d],g[d]);if(b)if(c)for(f=f||oa(a),g=g||oa(h),d=0,e=f.length;e>d;d++)na(f[d],g[d]);else na(a,h);return g=oa(h,"script"),g.length>0&&ma(g,!i&&oa(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(ca.test(e)){f=f||k.appendChild(b.createElement("div")),g=(ba.exec(e)||["",""])[1].toLowerCase(),h=ia[g]||ia._default,f.innerHTML=h[1]+e.replace(aa,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=oa(k.appendChild(e),"script"),i&&ma(f),c)){j=0;while(e=f[j++])fa.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=ja(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(oa(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&ma(oa(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(oa(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!da.test(a)&&!ia[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(aa,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(oa(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(oa(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&ea.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(oa(c,"script"),ka),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,oa(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,la),j=0;g>j;j++)h=f[j],fa.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(ha,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qa,ra={};function sa(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function ta(a){var b=l,c=ra[a];return c||(c=sa(a,b),"none"!==c&&c||(qa=(qa||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qa[0].contentDocument,b.write(),b.close(),c=sa(a,b),qa.detach()),ra[a]=c),c}var ua=/^margin/,va=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wa=function(b){return b.ownerDocument.defaultView.opener?b.ownerDocument.defaultView.getComputedStyle(b,null):a.getComputedStyle(b,null)};function xa(a,b,c){var d,e,f,g,h=a.style;return c=c||wa(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),va.test(g)&&ua.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function ya(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),f.removeChild(c),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var za=/^(none|table(?!-c[ea]).+)/,Aa=new RegExp("^("+Q+")(.*)$","i"),Ba=new RegExp("^([+-])=("+Q+")","i"),Ca={position:"absolute",visibility:"hidden",display:"block"},Da={letterSpacing:"0",fontWeight:"400"},Ea=["Webkit","O","Moz","ms"];function Fa(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Ea.length;while(e--)if(b=Ea[e]+c,b in a)return b;return d}function Ga(a,b,c){var d=Aa.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Ha(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ia(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wa(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xa(a,b,f),(0>e||null==e)&&(e=a.style[b]),va.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Ha(a,b,c||(g?"border":"content"),d,f)+"px"}function Ja(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",ta(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xa(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fa(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Ba.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fa(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xa(a,b,d)),"normal"===e&&b in Da&&(e=Da[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?za.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Ca,function(){return Ia(a,b,d)}):Ia(a,b,d):void 0},set:function(a,c,d){var e=d&&wa(a);return Ga(a,c,d?Ha(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=ya(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xa,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ua.test(a)||(n.cssHooks[a+b].set=Ga)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wa(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Ja(this,!0)},hide:function(){return Ja(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Ka(a,b,c,d,e){return new Ka.prototype.init(a,b,c,d,e)}n.Tween=Ka,Ka.prototype={constructor:Ka,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Ka.propHooks[this.prop];return a&&a.get?a.get(this):Ka.propHooks._default.get(this)},run:function(a){var b,c=Ka.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Ka.propHooks._default.set(this),this}},Ka.prototype.init.prototype=Ka.prototype,Ka.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Ka.propHooks.scrollTop=Ka.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Ka.prototype.init,n.fx.step={};var La,Ma,Na=/^(?:toggle|show|hide)$/,Oa=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pa=/queueHooks$/,Qa=[Va],Ra={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Oa.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Oa.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sa(){return setTimeout(function(){La=void 0}),La=n.now()}function Ta(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ua(a,b,c){for(var d,e=(Ra[b]||[]).concat(Ra["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Va(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||ta(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Na.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?ta(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ua(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wa(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xa(a,b,c){var d,e,f=0,g=Qa.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=La||Sa(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:La||Sa(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wa(k,j.opts.specialEasing);g>f;f++)if(d=Qa[f].call(j,a,k,j.opts))return d;return n.map(k,Ua,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xa,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Ra[c]=Ra[c]||[],Ra[c].unshift(b)},prefilter:function(a,b){b?Qa.unshift(a):Qa.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xa(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pa.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Ta(b,!0),a,d,e)}}),n.each({slideDown:Ta("show"),slideUp:Ta("hide"),slideToggle:Ta("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(La=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),La=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Ma||(Ma=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Ma),Ma=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Ya,Za,$a=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Za:Ya)),
+void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Za={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$a[b]||n.find.attr;$a[b]=function(a,b,d){var e,f;return d||(f=$a[b],$a[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$a[b]=f),e}});var _a=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_a.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ab=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ab," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ab," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ab," ").indexOf(b)>=0)return!0;return!1}});var bb=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cb=n.now(),db=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var eb=/#.*$/,fb=/([?&])_=[^&]*/,gb=/^(.*?):[ \t]*([^\r\n]*)$/gm,hb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ib=/^(?:GET|HEAD)$/,jb=/^\/\//,kb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,lb={},mb={},nb="*/".concat("*"),ob=a.location.href,pb=kb.exec(ob.toLowerCase())||[];function qb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function rb(a,b,c,d){var e={},f=a===mb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function sb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function tb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function ub(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:ob,type:"GET",isLocal:hb.test(pb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":nb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?sb(sb(a,n.ajaxSettings),b):sb(n.ajaxSettings,a)},ajaxPrefilter:qb(lb),ajaxTransport:qb(mb),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=gb.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||ob)+"").replace(eb,"").replace(jb,pb[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=kb.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===pb[1]&&h[2]===pb[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(pb[3]||("http:"===pb[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),rb(lb,k,b,v),2===t)return v;i=n.event&&k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!ib.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(db.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=fb.test(d)?d.replace(fb,"$1_="+cb++):d+(db.test(d)?"&":"?")+"_="+cb++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+nb+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=rb(mb,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=tb(k,v,f)),u=ub(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var vb=/%20/g,wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&").replace(vb,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Bb=0,Cb={},Db={0:200,1223:204},Eb=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in Cb)Cb[a]()}),k.cors=!!Eb&&"withCredentials"in Eb,k.ajax=Eb=!!Eb,n.ajaxTransport(function(a){var b;return k.cors||Eb&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Bb;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Cb[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Db[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Cb[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Fb=[],Gb=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Fb.pop()||n.expando+"_"+cb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Gb.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Gb.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Gb,"$1"+e):b.jsonp!==!1&&(b.url+=(db.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Fb.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Hb=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Hb)return Hb.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Ib=a.document.documentElement;function Jb(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Jb(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Ib;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Ib})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Jb(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=ya(k.pixelPosition,function(a,c){return c?(c=xa(a,b),va.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Kb=a.jQuery,Lb=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Lb),b&&a.jQuery===n&&(a.jQuery=Kb),n},typeof b===U&&(a.jQuery=a.$=n),n});
--- /dev/null
+/*! jQuery Validation Plugin - v1.14.0 - 6/30/2015
+ * http://jqueryvalidation.org/
+ * Copyright (c) 2015 Jörn Zaefferer; Licensed MIT */
+!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.on("click.validate",":submit",function(b){c.settings.submitHandler&&(c.submitButton=b.target),a(this).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(this).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.on("submit.validate",function(b){function d(){var d,e;return c.settings.submitHandler?(c.submitButton&&(d=a("<input type='hidden'/>").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),e=c.settings.submitHandler.call(c,c.currentForm,b),c.submitButton&&d.remove(),void 0!==e?e:!1):!0}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c,d;return a(this[0]).is("form")?b=this.validate().form():(d=[],b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b,d=d.concat(c.errorList)}),c.errorList=d),b},rules:function(b,c){var d,e,f,g,h,i,j=this[0];if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(b,c){i[c]=f[c],delete f[c],"required"===c&&a(j).removeAttr("aria-required")}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g),a(j).attr("aria-required","true")),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}),a.extend(a.expr[":"],{blank:function(b){return!a.trim(""+a(b).val())},filled:function(b){return!!a.trim(""+a(b).val())},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(b,c){var d=[16,17,18,20,35,36,37,38,39,40,45,144,225];9===c.which&&""===this.elementValue(b)||-1!==a.inArray(c.keyCode,d)||(b.name in this.submitted||b===this.lastElement)&&this.element(b)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date ( ISO ).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){var c=a.data(this.form,"validator"),d="on"+b.type.replace(/^validate/,""),e=c.settings;e[d]&&!a(this).is(e.ignore)&&e[d].call(c,this,b)}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){d[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).on("focusin.validate focusout.validate keyup.validate",":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], [type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox']",b).on("click.validate","select, option, [type='radio'], [type='checkbox']",b),this.settings.invalidHandler&&a(this.currentForm).on("invalid-form.validate",this.settings.invalidHandler),a(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required","true")},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c=this.clean(b),d=this.validationTargetFor(c),e=!0;return this.lastElement=d,void 0===d?delete this.invalid[c.name]:(this.prepareElement(d),this.currentElements=a(d),e=this.check(d)!==!1,e?delete this.invalid[d.name]:this.invalid[d.name]=!0),a(b).attr("aria-invalid",!e),this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),e},showErrors:function(b){if(b){a.extend(this.errorMap,b),this.errorList=[];for(var c in b)this.errorList.push({message:b[c],element:this.findByName(c)[0]});this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors();var b,c=this.elements().removeData("previousValue").removeAttr("aria-invalid");if(this.settings.unhighlight)for(b=0;c[b];b++)this.settings.unhighlight.call(this,c[b],this.settings.errorClass,"");else c.removeClass(this.settings.errorClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, :disabled").not(this.settings.ignore).filter(function(){return!this.name&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in c||!b.objectLength(a(this).rules())?!1:(c[this.name]=!0,!0)})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([]),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d=a(b),e=b.type;return"radio"===e||"checkbox"===e?this.findByName(b.name).filter(":checked").val():"number"===e&&"undefined"!=typeof b.validity?b.validity.badInput?!1:d.val():(c=d.val(),"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f=a(b).rules(),g=a.map(f,function(a,b){return b}).length,h=!1,i=this.elementValue(b);for(d in f){e={method:d,parameters:f[d]};try{if(c=a.validator.methods[d].call(this,i,b,e.parameters),"dependency-mismatch"===c&&1===g){h=!0;continue}if(h=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(j){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",j),j instanceof TypeError&&(j.message+=". Exception occurred when checking element "+b.id+", check the '"+e.method+"' method."),j}}if(!h)return this.objectLength(f)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;a<arguments.length;a++)if(void 0!==arguments[a])return arguments[a];return void 0},defaultMessage:function(b,c){return this.findDefined(this.customMessage(b.name,c),this.customDataMessage(b,c),!this.settings.ignoreTitle&&b.title||void 0,a.validator.messages[c],"<strong>Warning: No message defined for "+b.name+"</strong>")},formatAndAdd:function(b,c){var d=this.defaultMessage(b,c.method),e=/\$?\{(\d+)\}/g;"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),this.errorList.push({message:d,element:b,method:c.method}),this.errorMap[b.name]=d,this.submitted[b.name]=d},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g=this.errorsFor(b),h=this.idOrName(b),i=a(b).attr("aria-describedby");g.length?(g.removeClass(this.settings.validClass).addClass(this.settings.errorClass),g.html(c)):(g=a("<"+this.settings.errorElement+">").attr("id",h+"-error").addClass(this.settings.errorClass).html(c||""),d=g,this.settings.wrapper&&(d=g.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement(d,a(b)):d.insertAfter(b),g.is("label")?g.attr("for",h):0===g.parents("label[for='"+h+"']").length&&(f=g.attr("id").replace(/(:|\.|\[|\]|\$)/g,"\\$1"),i?i.match(new RegExp("\\b"+f+"\\b"))||(i+=" "+f):i=f,a(b).attr("aria-describedby",i),e=this.groups[b.name],e&&a.each(this.groups,function(b,c){c===e&&a("[name='"+b+"']",this.currentForm).attr("aria-describedby",g.attr("id"))}))),!c&&this.settings.success&&(g.text(""),"string"==typeof this.settings.success?g.addClass(this.settings.success):this.settings.success(g,b)),this.toShow=this.toShow.add(g)},errorsFor:function(b){var c=this.idOrName(b),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+d.replace(/\s+/g,", #")),this.errors().filter(e)},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+b+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return this.dependTypes[typeof a]?this.dependTypes[typeof a](a,b):!0},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(a){this.pending[a.name]||(this.pendingRequest++,this.pending[a.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b){return a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,"remote")})},destroy:function(){this.resetForm(),a(this.currentForm).off(".validate").removeData("validator")}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},normalizeAttributeRule:function(a,b,c,d){/min|max/.test(c)&&(null===b||/number|range|text/.test(b))&&(d=Number(d),isNaN(d)&&(d=void 0)),d||0===d?a[c]=d:b===c&&"range"!==b&&(a[c]=!0)},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),this.normalizeAttributeRule(e,g,c,d);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),this.normalizeAttributeRule(e,g,c,d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0!==e.param?e.param:!0:delete b[d]}}),a.each(b,function(d,e){b[d]=a.isFunction(e)?e(c):e}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var c;b[this]&&(a.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(c=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(c[0]),Number(c[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:b.length>0},email:function(a,b){return this.optional(b)||/^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(a)},date:function(a,b){return this.optional(b)||!/Invalid|NaN/.test(new Date(a).toString())},dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},creditcard:function(a,b){if(this.optional(b))return"dependency-mismatch";if(/[^0-9 \-]+/.test(a))return!1;var c,d,e=0,f=0,g=!1;if(a=a.replace(/\D/g,""),a.length<13||a.length>19)return!1;for(c=a.length-1;c>=0;c--)d=a.charAt(c),f=parseInt(d,10),g&&(f*=2)>9&&(f-=9),e+=f,g=!g;return e%10===0},minlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d},maxlength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||d>=e},rangelength:function(b,c,d){var e=a.isArray(b)?b.length:this.getLength(b,c);return this.optional(c)||e>=d[0]&&e<=d[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||c>=a},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.off(".validate-equalTo").on("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d){if(this.optional(c))return"dependency-mismatch";var e,f,g=this.previousValue(c);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),g.originalMessage=this.settings.messages[c.name].remote,this.settings.messages[c.name].remote=g.message,d="string"==typeof d&&{url:d}||d,g.old===b?g.valid:(g.old=b,e=this,this.startRequest(c),f={},f[c.name]=b,a.ajax(a.extend(!0,{mode:"abort",port:"validate"+c.name,dataType:"json",data:f,context:e.currentForm,success:function(d){var f,h,i,j=d===!0||"true"===d;e.settings.messages[c.name].remote=g.originalMessage,j?(i=e.formSubmitted,e.prepareElement(c),e.formSubmitted=i,e.successList.push(c),delete e.invalid[c.name],e.showErrors()):(f={},h=d||e.defaultMessage(c,"remote"),f[c.name]=g.message=a.isFunction(h)?h(b):h,e.invalid[c.name]=!0,e.showErrors(f)),g.valid=j,e.stopRequest(c,j)}},d)),"pending")}}});var b,c={};a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,d){var e=a.port;"abort"===a.mode&&(c[e]&&c[e].abort(),c[e]=d)}):(b=a.ajax,a.ajax=function(d){var e=("mode"in d?d:a.ajaxSettings).mode,f=("port"in d?d:a.ajaxSettings).port;return"abort"===e?(c[f]&&c[f].abort(),c[f]=b.apply(this,arguments),c[f]):b.apply(this,arguments)})});
\ No newline at end of file
--- /dev/null
+(function(factory) {\r
+ if (typeof define === "function" && define.amd) {\r
+ define(["jquery", "../jquery.validate"], factory);\r
+ } else {\r
+ factory(jQuery);\r
+ }\r
+} (function($) {\r
+\r
+ // 设置validator插件默认校验格式\r
+ $.validator.setDefaults({\r
+ highlight: function(element) {\r
+ $(element).closest('.form-group').addClass('has-error');\r
+ },\r
+ success: function(label) {\r
+ label.closest('.form-group').removeClass('has-error');\r
+ label.remove();\r
+ }\r
+ });\r
+\r
+\r
+ //密码\r
+ $.validator.addMethod('password', function(value, element, params) {\r
+ if (this.optional(element)) {\r
+ return true;\r
+ }\r
+ var re = /^[^\u4e00-\u9fa5]{1,64}$/;\r
+ return re.test(value);\r
+ }, '密码不合法');\r
+\r
+ $.validator.addMethod('utfmaxlen', function(value, element, params) {\r
+ if (this.optional(element)) {\r
+ return true;\r
+ }\r
+\r
+ if (ventoy_get_ulen(value) > 250) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }, 'Input too long');\r
+\r
+ $.validator.addMethod('start_slash', function(value, element, params) {\r
+ if (this.optional(element)) {\r
+ return true;\r
+ }\r
+\r
+ if (value.length > 0 && value.charCodeAt(0) != 47) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }, 'Must start with /');\r
+\r
+ $.validator.addMethod('noquotes', function(value, element, params) {\r
+ if (this.optional(element)) {\r
+ return true;\r
+ }\r
+\r
+ if (value.length > 0 && value.indexOf('"') >= 0) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }, 'Can not contain double quotes');\r
+ \r
+\r
+ $.validator.addMethod('printascii', function(value, element, params) {\r
+ if (this.optional(element)) {\r
+ return true;\r
+ }\r
+\r
+ for (var i = 0; i < value.length; i++) {\r
+ if (value.charCodeAt(i) > 127) {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ if (value.length > 0 && value.indexOf('"') >= 0) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+ }, 'Can only use printable ascii code');\r
+ \r
+}));\r
--- /dev/null
+\r
+/**\r
+ * 用于bootstap框架下提示信息框\r
+ * demo: \r
+ * \r
+ * 模态框\r
+ * Modal.confirm({msg: "是否确定提交?"}).on( function (e) {alert("返回结果:" + e);});\r
+ * Modal.alert({msg:"该记录已删除!"})\r
+ * Modal.process('show'/'hide') 隐藏或显示全屏、进度条\r
+ * \r
+ * 非模态框\r
+ * Message.show({ type : 'S|W|E|I', msg: '提示信息' })\r
+ * Message.success('成功信息')\r
+ * Message.error('错误信息')\r
+ * Message.warn('警告信息')\r
+ * Message.info('提示信息')\r
+ * Message.warn('警告信息',10000) //10000为显示时长\r
+ */\r
+;$(function() {\r
+ \r
+ window.Modal = function() {\r
+ var reg = new RegExp("\\[([^\\[\\]]*?)\\]", 'igm');\r
+ var alr = $("#msgAlertDiv");\r
+ \r
+ if (alr.length == 0) {\r
+ alr = $('<div id="msgAlertDiv" class="modal fade"></div>')\r
+ $("body").append(alr);\r
+ }\r
+ \r
+ var ahtml = ' <div class="modal-dialog">'\r
+ + '<div class="modal-content">'\r
+ + '<div class="modal-header">'\r
+ + '<h3 class="modal-title"><B style="font-weight: 400;"> [Title]</B></h3>'\r
+ + '</div>'\r
+ + '<div class="modal-body " style="word-break: break-all;display: block;">'\r
+ + '[Message]'\r
+ + '</div>'\r
+ + '<div class="modal-footer" >'\r
+ + '<button type="button" class="btn btn-success ok" data-dismiss="modal">[BtnOk]</button>'\r
+ + '[UserDefined]'\r
+ + '<button type="button" class="btn cancel" data-dismiss="modal">[BtnCancel]</button>'\r
+ + '</div>' + '</div>' + '</div>';\r
+\r
+ var _alert = function(options) {\r
+ alr.html(ahtml); // 复原\r
+ alr.find('.ok').removeClass('btn-success').addClass('btn-primary');\r
+ \r
+ if (document.body.clientHeight > 400) {\r
+ alr.find('.modal-dialog').css("top",((document.body.clientHeight - 400) / 2)); \r
+ }\r
+ \r
+ alr.find('.cancel').hide();\r
+ _dialog(options);\r
+\r
+ return {\r
+ on : function(callback) {\r
+ if (callback && callback instanceof Function) {\r
+ alr.find('.ok').click(function() {\r
+ callback(true)\r
+ });\r
+ }\r
+ }\r
+ };\r
+ };\r
+\r
+ var _confirm = function(options) {\r
+ alr.html(ahtml);\r
+ alr.find('.ok').removeClass('btn-primary').addClass('btn-success');\r
+ alr.find('.cancel').show();\r
+ if (document.body.clientHeight > 400) {\r
+ alr.find('.modal-dialog').css("top",((document.body.clientHeight - 400) / 2)); \r
+ }\r
+ \r
+ _dialog(options);\r
+\r
+ return {\r
+ on : function(callback) {\r
+ if (callback && callback instanceof Function) {\r
+ alr.find('.ok').click(function() {\r
+ callback(true);\r
+ });\r
+ alr.find('.cancel').click(function() {\r
+ callback(false);\r
+ });\r
+ alr.find('.userDefiend').click(function() {\r
+ callback("userDefiend");\r
+ });\r
+ }\r
+ }\r
+ };\r
+ };\r
+\r
+ var _dialog = function(options) {\r
+ var ops = {\r
+ msg : '',\r
+ title : g_vtoy_cur_language.STR_INFO,\r
+ btnok : g_vtoy_cur_language.STR_BTN_OK,\r
+ btncl : g_vtoy_cur_language.STR_BTN_CANCEL,\r
+ userDefined : ""\r
+ };\r
+\r
+ $.extend(ops, options);\r
+\r
+ var html = alr.html().replace(reg, function(node, key) {\r
+ return {\r
+ Title : ops.title,\r
+ Message : ops.msg,\r
+ BtnOk : ops.btnok,\r
+ BtnCancel : ops.btncl,\r
+ UserDefined : ops.userDefined\r
+ }[key];\r
+ });\r
+\r
+ alr.html(html);\r
+ alr.modal({\r
+ width : 500,\r
+ backdrop : 'static'\r
+ });\r
+ }\r
+\r
+ var _process = function(showOrHide,time) {\r
+ var defaultTime = 100;\r
+ if($.isNumeric(time)) {\r
+ defaultTime = time;\r
+ }\r
+ var $proc;\r
+ $proc = $("#vtoy_proc");\r
+ if('hide' === showOrHide) {\r
+ $proc.remove();\r
+ } else if ('show' === showOrHide) {\r
+ if($proc.length == 1) {\r
+ return;\r
+ }\r
+ $(document).find(":focus").blur();\r
+ $proc = $('<div id="vtoy_proc" class="loading"></div>');\r
+ $("body").append($proc);\r
+ setTimeout(function() {\r
+ $proc.replaceWith('<div id="vtoy_proc" class="loading" style="background-color: rgba(0, 0, 0, 0.2);"><div class="rectbox"><div class="title">DATA</div><div class="rect rect1"></div><div class="rect rect2"></div><div class="rect rect3"></div><div class="rect rect4"></div><div class="rect rect5"></div></div></div>');\r
+ }, $.isNumeric(time) ? time : 100);\r
+ } else {\r
+ alert("Modal.process参数必须为show/hide");\r
+ }\r
+ }\r
+ \r
+ return {\r
+ alert : _alert,\r
+ confirm : _confirm,\r
+ process : _process\r
+ }\r
+\r
+ }();\r
+ \r
+ window.Message = function() {\r
+ var _showMsg = function(type, msg, time) {\r
+ var o = {type : type, msg : msg };\r
+ if(time) {\r
+ o.time = time;\r
+ }\r
+ _show(o);\r
+ }\r
+ \r
+ var _show = function(options) {\r
+ var ops = {\r
+ msg : "提示内容",\r
+ type: 'S',\r
+ time: 3000\r
+ };\r
+ $.extend(ops, options);\r
+\r
+ var msg_class = 'alert-success';\r
+ if('S' === ops.type || 's' === ops.type) {\r
+ msg_class = 'alert-success';\r
+ } else if ('E' === ops.type || 'e' === ops.type) {\r
+ msg_class = 'alert-danger';\r
+ } else if ('W' === ops.type || 'w' === ops.type) {\r
+ msg_class = 'alert-warning';\r
+ } else if ('I' === ops.type || 'i' === ops.type) {\r
+ msg_class = 'alert-info';\r
+ } else {\r
+ alert("未知的类型,请使用: w-警告;s-成功;e-失败;i-提示");\r
+ return;\r
+ }\r
+ var $messageContainer = $("#fcss_message");\r
+ if($messageContainer.length === 0) {\r
+ $messageContainer = $('<div id="fcss_message" style="position:fixed; left: 20%; right: 20%; top:0px; z-index:99999999"></div>');\r
+ $messageContainer.appendTo($('body'));\r
+ }\r
+ var $div = $('<div class="alert ' + msg_class + ' alert-dismissible fade in" role="alert" style="margin-bottom: 0; padding-top:10px; padding-bottom: 10px;"></div>');\r
+ var $btn = $('<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>');\r
+ $div.append($btn).append(ops.msg).appendTo($messageContainer);\r
+ setTimeout(function() {\r
+ $div.remove();\r
+ }, ops.time);\r
+ }\r
+ \r
+ var _success = function(msg, time) {\r
+ _showMsg('s', msg, time);\r
+ }\r
+ var _error = function(msg, time) {\r
+ _showMsg('e', msg, time || 6000);\r
+ }\r
+ var _warn = function(msg, time) {\r
+ _showMsg('w', msg, time);\r
+ }\r
+ var _info = function(msg, time) {\r
+ _showMsg('i', msg, time);\r
+ }\r
+ \r
+ return {\r
+ success : _success,\r
+ error : _error,\r
+ warn : _warn,\r
+ info : _info,\r
+ show : _show\r
+ }\r
+ }();\r
+ \r
+});
\ No newline at end of file
--- /dev/null
+!function(n){"use strict";function d(n,t){var r=(65535&n)+(65535&t);return(n>>16)+(t>>16)+(r>>16)<<16|65535&r}function f(n,t,r,e,o,u){return d((u=d(d(t,n),d(e,u)))<<o|u>>>32-o,r)}function l(n,t,r,e,o,u,c){return f(t&r|~t&e,n,t,o,u,c)}function g(n,t,r,e,o,u,c){return f(t&e|r&~e,n,t,o,u,c)}function v(n,t,r,e,o,u,c){return f(t^r^e,n,t,o,u,c)}function m(n,t,r,e,o,u,c){return f(r^(t|~e),n,t,o,u,c)}function c(n,t){var r,e,o,u;n[t>>5]|=128<<t%32,n[14+(t+64>>>9<<4)]=t;for(var c=1732584193,f=-271733879,i=-1732584194,a=271733878,h=0;h<n.length;h+=16)c=l(r=c,e=f,o=i,u=a,n[h],7,-680876936),a=l(a,c,f,i,n[h+1],12,-389564586),i=l(i,a,c,f,n[h+2],17,606105819),f=l(f,i,a,c,n[h+3],22,-1044525330),c=l(c,f,i,a,n[h+4],7,-176418897),a=l(a,c,f,i,n[h+5],12,1200080426),i=l(i,a,c,f,n[h+6],17,-1473231341),f=l(f,i,a,c,n[h+7],22,-45705983),c=l(c,f,i,a,n[h+8],7,1770035416),a=l(a,c,f,i,n[h+9],12,-1958414417),i=l(i,a,c,f,n[h+10],17,-42063),f=l(f,i,a,c,n[h+11],22,-1990404162),c=l(c,f,i,a,n[h+12],7,1804603682),a=l(a,c,f,i,n[h+13],12,-40341101),i=l(i,a,c,f,n[h+14],17,-1502002290),c=g(c,f=l(f,i,a,c,n[h+15],22,1236535329),i,a,n[h+1],5,-165796510),a=g(a,c,f,i,n[h+6],9,-1069501632),i=g(i,a,c,f,n[h+11],14,643717713),f=g(f,i,a,c,n[h],20,-373897302),c=g(c,f,i,a,n[h+5],5,-701558691),a=g(a,c,f,i,n[h+10],9,38016083),i=g(i,a,c,f,n[h+15],14,-660478335),f=g(f,i,a,c,n[h+4],20,-405537848),c=g(c,f,i,a,n[h+9],5,568446438),a=g(a,c,f,i,n[h+14],9,-1019803690),i=g(i,a,c,f,n[h+3],14,-187363961),f=g(f,i,a,c,n[h+8],20,1163531501),c=g(c,f,i,a,n[h+13],5,-1444681467),a=g(a,c,f,i,n[h+2],9,-51403784),i=g(i,a,c,f,n[h+7],14,1735328473),c=v(c,f=g(f,i,a,c,n[h+12],20,-1926607734),i,a,n[h+5],4,-378558),a=v(a,c,f,i,n[h+8],11,-2022574463),i=v(i,a,c,f,n[h+11],16,1839030562),f=v(f,i,a,c,n[h+14],23,-35309556),c=v(c,f,i,a,n[h+1],4,-1530992060),a=v(a,c,f,i,n[h+4],11,1272893353),i=v(i,a,c,f,n[h+7],16,-155497632),f=v(f,i,a,c,n[h+10],23,-1094730640),c=v(c,f,i,a,n[h+13],4,681279174),a=v(a,c,f,i,n[h],11,-358537222),i=v(i,a,c,f,n[h+3],16,-722521979),f=v(f,i,a,c,n[h+6],23,76029189),c=v(c,f,i,a,n[h+9],4,-640364487),a=v(a,c,f,i,n[h+12],11,-421815835),i=v(i,a,c,f,n[h+15],16,530742520),c=m(c,f=v(f,i,a,c,n[h+2],23,-995338651),i,a,n[h],6,-198630844),a=m(a,c,f,i,n[h+7],10,1126891415),i=m(i,a,c,f,n[h+14],15,-1416354905),f=m(f,i,a,c,n[h+5],21,-57434055),c=m(c,f,i,a,n[h+12],6,1700485571),a=m(a,c,f,i,n[h+3],10,-1894986606),i=m(i,a,c,f,n[h+10],15,-1051523),f=m(f,i,a,c,n[h+1],21,-2054922799),c=m(c,f,i,a,n[h+8],6,1873313359),a=m(a,c,f,i,n[h+15],10,-30611744),i=m(i,a,c,f,n[h+6],15,-1560198380),f=m(f,i,a,c,n[h+13],21,1309151649),c=m(c,f,i,a,n[h+4],6,-145523070),a=m(a,c,f,i,n[h+11],10,-1120210379),i=m(i,a,c,f,n[h+2],15,718787259),f=m(f,i,a,c,n[h+9],21,-343485551),c=d(c,r),f=d(f,e),i=d(i,o),a=d(a,u);return[c,f,i,a]}function i(n){for(var t="",r=32*n.length,e=0;e<r;e+=8)t+=String.fromCharCode(n[e>>5]>>>e%32&255);return t}function a(n){var t=[];for(t[(n.length>>2)-1]=void 0,e=0;e<t.length;e+=1)t[e]=0;for(var r=8*n.length,e=0;e<r;e+=8)t[e>>5]|=(255&n.charCodeAt(e/8))<<e%32;return t}function e(n){for(var t,r="0123456789abcdef",e="",o=0;o<n.length;o+=1)t=n.charCodeAt(o),e+=r.charAt(t>>>4&15)+r.charAt(15&t);return e}function r(n){return unescape(encodeURIComponent(n))}function o(n){return i(c(a(n=r(n)),8*n.length))}function u(n,t){return function(n,t){var r,e=a(n),o=[],u=[];for(o[15]=u[15]=void 0,16<e.length&&(e=c(e,8*n.length)),r=0;r<16;r+=1)o[r]=909522486^e[r],u[r]=1549556828^e[r];return t=c(o.concat(a(t)),512+8*t.length),i(c(u.concat(t),640))}(r(n),r(t))}function t(n,t,r){return t?r?u(t,n):e(u(t,n)):r?o(n):e(o(n))}"function"==typeof define&&define.amd?define(function(){return t}):"object"==typeof module&&module.exports?module.exports=t:n.md5=t}(this);
+//# sourceMappingURL=md5.min.js.map
\ No newline at end of file
--- /dev/null
+\r
+function ventoy_replace_slash(str) {\r
+ var str1 = str.replace(/\\/g, '/');\r
+ var str2 = str1.replace(/\/\//g, '/');\r
+ return str2;\r
+}\r
+\r
+\r
+function ventoy_get_ulen(str) { \r
+ var c, b = 0, l = str.length; \r
+ while(l) { \r
+ c = str.charCodeAt(--l); \r
+ b += (c < 128) ? 1 : ((c < 2048) ? 2 : ((c < 65536) ? 3 : 4)); \r
+ }; \r
+ return b; \r
+}\r
+\r
+\r
+function ventoy_common_check_path(path) {\r
+ if (path.indexOf('//') >= 0) {\r
+ return false;\r
+ }\r
+\r
+ if (path.length <= g_current_dir.length) {\r
+ return false;\r
+ }\r
+\r
+ if (path.substr(0, g_current_dir.length) != g_current_dir) {\r
+ return false;\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+\r
+// 加载子页面内容\r
+function loadContent(page) {\r
+ $("#plugson-content").load(page + ".html?_=" + (new Date().getTime()), function() {\r
+ $("body").scrollTop(0);\r
+ });\r
+}\r
+\r
+// 包装ajax请求\r
+function callVtoyCatchErr(p1, p2, p3) {\r
+ var url = '/vtoy/json';\r
+ var data = {};\r
+ var func = function(data) {};\r
+ var errfunc = function(xmlHttpRequest, textStatus, errorThrown) {};\r
+\r
+ if (typeof(p1) === 'string') {\r
+ url = p1;\r
+ } else if (typeof(p1) === 'object') {\r
+ data = p1;\r
+ }\r
+ if (typeof(p2) === 'object') {\r
+ data = p2;\r
+ } else if (typeof(p2) === 'function') {\r
+ func = p2;\r
+ }\r
+ if (typeof(p3) === 'function') {\r
+ errfunc = p3;\r
+ }\r
+\r
+ //vtoy.debug('callVtoy:\t\t\t\t' + JSON.stringify(data));\r
+ $.ajax({\r
+ url: url,\r
+ type: 'post',\r
+ cache: false,\r
+ dataType: 'json',\r
+ data: JSON.stringify(data),\r
+ success: func,\r
+ error: errfunc,\r
+ complete: function(data) {\r
+ //vtoy.debug('callVtoy\'s resp:\t\t' + data.responseText);\r
+ }\r
+ });\r
+}\r
+\r
+// 包装ajax请求\r
+function callVtoy(p1, p2, p3) {\r
+ var url = '/vtoy/json';\r
+ var data = {};\r
+ var func = function(data) {};\r
+\r
+ if (typeof(p1) === 'string') {\r
+ url = p1;\r
+ } else if (typeof(p1) === 'object') {\r
+ data = p1;\r
+ }\r
+ if (typeof(p2) === 'object') {\r
+ data = p2;\r
+ } else if (typeof(p2) === 'function') {\r
+ func = p2;\r
+ }\r
+ if (typeof(p3) === 'function') {\r
+ func = p3;\r
+ }\r
+\r
+ //vtoy.debug('callVtoy:\t\t\t\t' + JSON.stringify(data));\r
+ $.ajax({\r
+ url: url,\r
+ type: 'post',\r
+ cache: false,\r
+ dataType: 'json',\r
+ data: JSON.stringify(data),\r
+ success: func,\r
+ error: function(xmlHttpRequest, textStatus, errorThrown) {\r
+\r
+ if(undefined === errorThrown)\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_REMOTE_ABNORMAL);\r
+ }\r
+ else if(undefined === errorThrown.length)\r
+ {\r
+ \r
+ }\r
+ else if('' == errorThrown.trim())\r
+ {\r
+ }\r
+ else\r
+ {\r
+ switch(errorThrown)\r
+ {\r
+ case 'timeout':\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_REQUEST_TIMEOUT);\r
+ break;\r
+ }\r
+ case 'Service Unavailable':\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_SERVICE_UNAVAILABLE);\r
+ break;\r
+ }\r
+ case 'abort':\r
+ {\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_COMMUNICATION_ERR + errorThrown);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ },\r
+ complete: function(data) {\r
+ //vtoy.debug('callVtoy\'s resp:\t\t' + data.responseText);\r
+ }\r
+ });\r
+}\r
+\r
+function callVtoyASyncTimeout(time, data, func) {\r
+ $.ajax({\r
+ url: '/vtoy/json',\r
+ type: 'post',\r
+ cache: false,\r
+ dataType: 'json',\r
+ async: true,\r
+ timeout: time,\r
+ data: JSON.stringify(data),\r
+ success: func,\r
+ error: function(xmlHttpRequest, textStatus, errorThrown) {\r
+ if(undefined === errorThrown)\r
+ { \r
+ }\r
+ else if(undefined === errorThrown.length)\r
+ {\r
+ \r
+ }\r
+ else if('' == errorThrown.trim())\r
+ {\r
+ }\r
+ else\r
+ {\r
+ switch(errorThrown)\r
+ {\r
+ case 'timeout':\r
+ {\r
+ callVtoyASyncTimeout(time, data, func);\r
+ break;\r
+ }\r
+ case 'Service Unavailable':\r
+ {\r
+ break;\r
+ }\r
+ case 'abort':\r
+ {\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ },\r
+ complete: function(data) {\r
+ //vtoy.debug('callVtoyASyncTimeout\'s resp:\t' + JSON.stringify(data));\r
+ }\r
+ });\r
+}\r
+\r
+function callVtoySync(data, func) {\r
+ //vtoy.debug('callVtoySync:\t\t\t' + JSON.stringify(data));\r
+ $.ajax({\r
+ url: '/vtoy/json',\r
+ type: 'post',\r
+ cache: false,\r
+ dataType: 'json',\r
+ async: false,\r
+ data: JSON.stringify(data),\r
+ success: function VtoyCallFuncWrapper(data) { \r
+ if (data.result === 'busy') {\r
+ var titlestr = '<span class="fa fa-check-circle" style="color:green; font-weight:bold;"> ' + g_vtoy_cur_language.STR_INFO + '</span>';\r
+ var msgstr = '<span style="font-size:14px; font-weight:bold;"> ' + g_vtoy_cur_language.STR_WEB_SERVICE_BUSY + '</span>';\r
+ Modal.alert({title:titlestr, msg:msgstr, btnok:g_vtoy_cur_language.STR_BTN_OK }); \r
+ }else {\r
+ func(data);\r
+ }\r
+ },\r
+ error: function(xmlHttpRequest, textStatus, errorThrown) {\r
+ if(undefined === errorThrown)\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_REMOTE_ABNORMAL);\r
+ }\r
+ else if(undefined === errorThrown.length)\r
+ {\r
+ \r
+ }\r
+ else if('' == errorThrown.trim())\r
+ {\r
+ }\r
+ else\r
+ {\r
+ switch(errorThrown)\r
+ {\r
+ case 'timeout':\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_REQUEST_TIMEOUT);\r
+ break;\r
+ }\r
+ case 'Service Unavailable':\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_SERVICE_UNAVAILABLE);\r
+ break;\r
+ }\r
+ case 'abort':\r
+ {\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ Message.error(g_vtoy_cur_language.STR_WEB_COMMUNICATION_ERR + errorThrown);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ },\r
+ complete: function(data) {\r
+ //vtoy.debug('callVtoySync\'s resp:\t' + JSON.stringify(data));\r
+ }\r
+ });\r
+}\r
+\r
+var vtoy = { \r
+ baseurl : '',\r
+ status: '', \r
+ scan: {\r
+ time: 3,\r
+ ret: []\r
+ }\r
+}\r
+\r
+// \r
+String.prototype.endsWith = function(str) {\r
+ if (str == null || str == "" || this.length == 0 || str.length > this.length)\r
+ return false;\r
+ if (this.substring(this.length - str.length) == str)\r
+ return true;\r
+ else\r
+ return false;\r
+}\r
+\r
+window.Message = function() {\r
+ var _showMsg = function(type, msg, time) {\r
+ var o = {type : type, msg : msg };\r
+ if(time) {\r
+ o.time = time;\r
+ }\r
+ _show(o);\r
+ }\r
+ \r
+ var _show = function(options) {\r
+ var ops = {\r
+ msg : "提示内容",\r
+ type: 'S',\r
+ time: 3000\r
+ };\r
+ $.extend(ops, options);\r
+\r
+ var msg_class = 'alert-success';\r
+ if('S' === ops.type || 's' === ops.type) {\r
+ msg_class = 'alert-success';\r
+ } else if ('E' === ops.type || 'e' === ops.type) {\r
+ msg_class = 'alert-danger';\r
+ } else if ('W' === ops.type || 'w' === ops.type) {\r
+ msg_class = 'alert-warning';\r
+ } else if ('I' === ops.type || 'i' === ops.type) {\r
+ msg_class = 'alert-info';\r
+ } else {\r
+ alert("未知的类型,请使用: w-警告;s-成功;e-失败;i-提示");\r
+ return;\r
+ }\r
+ var $messageContainer = $("#fcss_message");\r
+ if($messageContainer.length === 0) {\r
+ $messageContainer = $('<div id="fcss_message" style="position:fixed; left: 20%; right: 20%; top:0px; z-index:99999999"></div>');\r
+ $messageContainer.appendTo($('body'));\r
+ }\r
+ var $div = $('<div class="alert ' + msg_class + ' alert-dismissible fade in" role="alert" style="margin-bottom: 0; padding-top:10px; padding-bottom: 10px;"></div>');\r
+ var $btn = $('<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>');\r
+ $div.append($btn).append(ops.msg).appendTo($messageContainer);\r
+ setTimeout(function() {\r
+ $div.remove();\r
+ }, ops.time);\r
+ }\r
+ \r
+ var _success = function(msg, time) {\r
+ _showMsg('s', msg, time);\r
+ }\r
+ var _error = function(msg, time) { \r
+ _showMsg('e', msg, time || 5000);\r
+ }\r
+ var _warn = function(msg, time) {\r
+ _showMsg('w', msg, time);\r
+ }\r
+ var _info = function(msg, time) {\r
+ _showMsg('i', msg, time);\r
+ }\r
+ \r
+ return {\r
+ success : _success,\r
+ error : _error,\r
+ warn : _warn,\r
+ info : _info,\r
+ show : _show\r
+ }\r
+}();\r
+\r
+\r
+var g_vtoy_cur_language_en = \r
+{\r
+ "STR_INFO": "Info",\r
+ "STR_BTN_OK": "OK",\r
+ "STR_BTN_CANCEL": "Cancel",\r
+ "STR_SAVE": " Save",\r
+ "STR_RESET": " Reset",\r
+ "STR_DISCARD": " Discard",\r
+ "STR_ENABLE": " Enable",\r
+ "STR_ADD": "Add",\r
+ "STR_DEL": "Delete",\r
+ "STR_CLEAR": "Clear",\r
+ "STR_STATUS": "Status",\r
+ "STR_DEFAULT": "Default",\r
+ "STR_DEFAULT_SEL": "Default",\r
+ "STR_RANDOM_SEL": "Random",\r
+ "STR_OPERATION": "Operation",\r
+ "STR_VALID": "Valid",\r
+ "STR_INVALID": "Invalid",\r
+ "STR_OPT_SETTING": "Option Setting",\r
+ "STR_OPT_DESC": "Option Description",\r
+ "STR_EDIT": "Edit",\r
+ "STR_FILE": "File",\r
+ "STR_DIR": "Dir",\r
+ "STR_SAVE_TIP": "Data in current page has been modified. Do you want to save it?",\r
+ "STR_SAVE_SUCCESS": "Configuration successfully saved!",\r
+ "STR_FILE_EXIST": "OK",\r
+ "STR_FILE_NONEXIST": "Invalid",\r
+ "STR_FILE_FUZZY": "Fuzzy",\r
+ "STR_DIR_EXIST": "OK",\r
+ "STR_DIR_NONEXIST": "Invalid",\r
+ "STR_DUPLICATE_PATH": "Duplicate path",\r
+ "STR_DELETE_CONFIRM": "Delete this item, Continue?",\r
+ "STR_FILE_PATH": "File Path",\r
+ "STR_DIR_PATH": "Directory Path",\r
+\r
+ "STR_SET_ALIAS": "Set Menu Alias",\r
+ "STR_ALIAS": "Alias",\r
+ "STR_SET_TIP": "Set Menu Tip",\r
+ "STR_TIP": "Tip",\r
+ "STR_SET_CLASS": "Set Menu Class",\r
+ "STR_CLASS": "Class",\r
+ "STR_SET_INJECTION": "Set Injection",\r
+ "STR_SET_AUTO_INS": "Set Auto Install",\r
+ "STR_SET_AUTO_TEMPLATE": "Template",\r
+\r
+ "STR_SET_PERSISTENCE": "Set Persistence",\r
+ "STR_SET_PERSISTENCE_DAT": "Dat File",\r
+\r
+ "STR_SET_DUD": "Set DUD",\r
+ "STR_SET_DUD_FILE": "DUD File",\r
+\r
+ "STR_PASSWORD": "Password",\r
+ "STR_SET_PASSWORD": "Set Password",\r
+ "STR_PASSWORD_TYPE": "Password Type",\r
+ "STR_PASSWORD_VALUE": "Password Value",\r
+\r
+\r
+ "STR_WEB_COMMUNICATION_ERR":"Communication error:",\r
+ "STR_WEB_REMOTE_ABNORMAL":"Communication error: remote abnormal",\r
+ "STR_WEB_REQUEST_TIMEOUT":"Communication error: Request timed out",\r
+ "STR_WEB_SERVICE_UNAVAILABLE":"Communication error: Service Unavailable",\r
+ "STR_WEB_SERVICE_BUSY":"Service is busy, please retry later.",\r
+\r
+ "STR_PLUG_DEVICE": "Device Information",\r
+ "STR_PLUG_CONTROL": "Global Control Plugin",\r
+ "STR_PLUG_THEME": "Theme Plugin",\r
+ "STR_PLUG_ALIAS": "Menu Alias Plugin",\r
+ "STR_PLUG_CLASS": "Menu Class Plugin",\r
+ "STR_PLUG_TIP": "Menu Tip Plugin",\r
+ "STR_PLUG_AUTO_INSTALL": "Auto Install Plugin",\r
+ "STR_PLUG_PERSISTENCE": "Persistence Plugin",\r
+ "STR_PLUG_INJECTION": "Injection Plugin",\r
+ "STR_PLUG_CONF_REPLACE": "Boot Conf Replace Plugin",\r
+ "STR_PLUG_PASSWORD": "Password Plugin",\r
+ "STR_PLUG_IMAGELIST": "Image List Plugin",\r
+ "STR_PLUG_AUTO_MEMDISK": "Auto Memdisk Plugin",\r
+ "STR_PLUG_DUD": "DUD Plugin",\r
+ "STR_PLUG_DONATION": "Donation",\r
+\r
+ "STR_PATH_TOO_LONG": "The path exceeds the maximum supported length, please check!",\r
+ "STR_INPUT_TOO_LONG": "The string exceeds the maximum supported length, please check!",\r
+ "STR_INVALID_FILE_PATH": "Invalid full file path, please check!",\r
+ "STR_INVALID_FILE_PATH1": "The 1st file path is invalid!", \r
+ "STR_INVALID_FILE_PATH2": "The 2nd file path is invalid!", \r
+ "STR_INVALID_NEW_FILE_PATH": "The full file path of new is invalid, please check!",\r
+ "STR_INVALID_DIR_PATH": "Invalid directory path, please check!",\r
+ "STR_INVALID_NUMBER": "Please input valid non-negative integer!",\r
+ "STR_INVALID_AUTOSEL": "autosel exceeds the length of the list!",\r
+ "STR_INVALID_TIMEOUT": "Please input valid timeout integer!",\r
+ "STR_INVALID_PERCENT": "Please input integer between 0-100 !",\r
+ "STR_INVALID_COLOR": "Please input valid color!",\r
+ "STR_SELECT": "Please Select",\r
+ "STR_SET_ALIAS_FOR_FILE": "Set Menu Alias For File",\r
+ "STR_SET_ALIAS_FOR_DIR": "Set Menu Alias For Directory",\r
+ "STR_SET_TIP_FOR_FILE": "Set Menu Tip For File",\r
+ "STR_SET_TIP_FOR_DIR": "Set Menu Tip For Directory",\r
+ "STR_SET_INJECTION_FOR_FILE": "[image] Set injection for a file",\r
+ "STR_SET_INJECTION_FOR_DIR": "[parent] Set the same injection for all the files under a directory.",\r
+ "STR_INVALID_ARCHIVE_PATH": "Invalid archive file path, please check!",\r
+ "STR_SET_PWD_FOR_FILE": "[file] Set password for a file.",\r
+ "STR_SET_PWD_FOR_DIR": "[parent] Set the same password for all the files under a directory.",\r
+ "STR_SET_AUTO_INSTALL_FOR_FILE": "[image] Set auto install template for a file",\r
+ "STR_SET_AUTO_INSTALL_FOR_DIR": "[parent] Set the same auto install template for all the files under a directory.",\r
+\r
+ "STR_SET_CLASS_BY_KEY": "[key] Set menu class by filename keyword.",\r
+ "STR_SET_CLASS_BY_DIR": "[dir] Set menu class for a directory.",\r
+ "STR_SET_CLASS_BY_PARENT": "[parent] Set menu class for all the files under a directory.",\r
+ "STR_SET_IMAGE_PWD": "[file] Set Password For A File",\r
+ "STR_SET_PARENT_PWD": "[parent] Set the same password for all the files under a directory.",\r
+\r
+ "STR_SET_SEARCH_ROOT": "Set Search Root", \r
+ "STR_SET_DEFAULT_IMAGE": "Set Default Image",\r
+ "STR_ADD_THEME": "Add Theme",\r
+ "STR_ADD_FONT": "Set Font",\r
+ "STR_ADD_FILE_TO_LIST": "Add File To List",\r
+ "STR_DEFAULT_SELECT": " Default",\r
+ "STR_AUTO_TEMPLATE": "Auto Install Template",\r
+ "STR_ADD_AUTO_TEMPLATE": "Add Auto Install Template",\r
+ \r
+ "STR_PERSISTENCE_DAT": "Persistence Dat File",\r
+ "STR_ADD_PERSISTENCE_DAT": "Add Persistence Dat File",\r
+\r
+ "STR_DUD_FILE": "DUD File",\r
+ "STR_ADD_DUD_FILE": "Add DUD File",\r
+\r
+ "STR_DEL_LAST": "The entry will be deleted if you delete the this last item. Continue?",\r
+\r
+ "STR_CLOSE_TIP": "Service unavailable, the page will close!",\r
+ "STR_SECURE_BOOT_ENABLE": "Enable",\r
+ "STR_SECURE_BOOT_DISABLE": "Disable",\r
+ "STR_SYNTAX_ERROR_TIP": "Syntax error detected in ventoy.json, so the configuration is not loaded!",\r
+\r
+ "STR_XXX": "xxx"\r
+};\r
+\r
+var g_vtoy_cur_language_cn = \r
+{\r
+ "STR_INFO": "提醒",\r
+ "STR_BTN_OK": "确定",\r
+ "STR_BTN_CANCEL": "取消",\r
+ "STR_SAVE": " 保存",\r
+ "STR_RESET": " 重置",\r
+ "STR_DISCARD": " 丢弃",\r
+ "STR_ENABLE": " 使能",\r
+ "STR_ADD": "新增",\r
+ "STR_DEL": "删除",\r
+ "STR_CLEAR": "清除",\r
+ "STR_STATUS": "状态",\r
+ "STR_DEFAULT": "默认",\r
+ "STR_DEFAULT_SEL": "默认选择",\r
+ "STR_RANDOM_SEL": "随机选择",\r
+ "STR_OPERATION": "操作",\r
+ "STR_VALID": "有效",\r
+ "STR_INVALID": "无效",\r
+ "STR_OPT_SETTING": "选项设置",\r
+ "STR_OPT_DESC": "选项说明",\r
+ "STR_EDIT": "设置",\r
+ "STR_FILE": "文件",\r
+ "STR_DIR": "目录",\r
+ "STR_SAVE_TIP": "当前页面数据已经修改,是否保存?",\r
+ "STR_SAVE_SUCCESS": "配置保存成功!",\r
+ "STR_FILE_EXIST": "文件存在",\r
+ "STR_FILE_NONEXIST": "文件无效",\r
+ "STR_FILE_FUZZY": "模糊匹配",\r
+ "STR_DIR_EXIST": "目录存在",\r
+ "STR_DIR_NONEXIST": "目录无效",\r
+ "STR_DUPLICATE_PATH": "路径不允许重复",\r
+ "STR_DELETE_CONFIRM": "确定要删除吗?",\r
+ "STR_FILE_PATH": "文件路径",\r
+ "STR_DIR_PATH": "目录路径",\r
+ \r
+ "STR_SET_ALIAS": "设置菜单别名",\r
+ "STR_ALIAS": "别名",\r
+ "STR_SET_TIP": "设置菜单提示",\r
+ "STR_TIP": "提示",\r
+ "STR_SET_CLASS": "设置菜单类型",\r
+ "STR_CLASS": "类型",\r
+ "STR_SET_INJECTION": "设置文件注入",\r
+ "STR_SET_AUTO_INS": "设置自动安装",\r
+ "STR_SET_AUTO_TEMPLATE": "自动安装脚本",\r
+ "STR_SET_PERSISTENCE": "设置持久化文件",\r
+ "STR_SET_PERSISTENCE_DAT": "持久化文件",\r
+\r
+ "STR_SET_DUD": "设置 DUD",\r
+ "STR_SET_DUD_FILE": "DUD 文件",\r
+\r
+ "STR_PASSWORD": "密码",\r
+ "STR_SET_PASSWORD": "设置密码",\r
+ "STR_PASSWORD_TYPE": "密码类型",\r
+ "STR_PASSWORD_VALUE": "密码内容",\r
+\r
+ "STR_WEB_COMMUNICATION_ERR":"通信失败:",\r
+ "STR_WEB_REMOTE_ABNORMAL":"通信失败:服务端异常",\r
+ "STR_WEB_REQUEST_TIMEOUT":"通信失败:请求超时",\r
+ "STR_WEB_SERVICE_UNAVAILABLE":"通信失败:服务不可用",\r
+ "STR_WEB_SERVICE_BUSY":"后台服务正忙,请稍后重试",\r
+\r
+ "STR_PLUG_DEVICE": "设备信息",\r
+ "STR_PLUG_CONTROL": "全局控制插件",\r
+ "STR_PLUG_THEME": "主题插件",\r
+ "STR_PLUG_ALIAS": "菜单别名插件",\r
+ "STR_PLUG_CLASS": "菜单类型插件",\r
+ "STR_PLUG_TIP": "菜单提示插件",\r
+ "STR_PLUG_AUTO_INSTALL": "自动安装插件",\r
+ "STR_PLUG_PERSISTENCE": "数据持久化插件",\r
+ "STR_PLUG_INJECTION": "文件注入插件",\r
+ "STR_PLUG_CONF_REPLACE": "启动配置替换插件",\r
+ "STR_PLUG_PASSWORD": "密码插件",\r
+ "STR_PLUG_IMAGELIST": "文件列表插件",\r
+ "STR_PLUG_AUTO_MEMDISK": "自动Memdisk插件",\r
+ "STR_PLUG_DUD": "Driver Update Disk插件",\r
+ "STR_PLUG_DONATION": "捐助",\r
+\r
+ "STR_PATH_TOO_LONG": "路径超过最大支持长度,请检查!",\r
+ "STR_INPUT_TOO_LONG": "字符串超过最大支持长度,请检查!",\r
+ "STR_INVALID_FILE_PATH": "文件路径不合法,请检查!", \r
+ "STR_INVALID_FILE_PATH1": "第1个文件路径不合法,请检查!", \r
+ "STR_INVALID_FILE_PATH2": "第2个文件路径不合法,请检查!", \r
+ "STR_INVALID_NEW_FILE_PATH": "new 文件路径不合法,请检查!", \r
+ "STR_INVALID_DIR_PATH": "文件夹路径不合法,请检查!",\r
+ "STR_INVALID_NUMBER": "请输入合法的非负整数!",\r
+ "STR_INVALID_AUTOSEL": "autosel 的值超过了列表实际长度!",\r
+ "STR_INVALID_TIMEOUT": "请输入合法的超时秒数!",\r
+ "STR_INVALID_PERCENT": "请输入 0-100 以内的整数!",\r
+ "STR_INVALID_COLOR": "请输入合法的颜色!",\r
+ "STR_SELECT": "请选择",\r
+ "STR_SET_ALIAS_FOR_FILE": "为文件设置别名",\r
+ "STR_SET_ALIAS_FOR_DIR": "为目录设置别名",\r
+ "STR_SET_TIP_FOR_FILE": "为文件设置菜单提示信息",\r
+ "STR_SET_TIP_FOR_DIR": "为目录设置菜单提示信息",\r
+ "STR_SET_INJECTION_FOR_FILE": "[image] 为某一个文件设置注入",\r
+ "STR_SET_INJECTION_FOR_DIR": "[parent] 为某个目录下的所有文件设置相同的注入",\r
+ "STR_INVALID_ARCHIVE_PATH": "Archive 文件路径非法,请检查!",\r
+ "STR_SET_PWD_FOR_FILE": "[file] 为指定文件设置密码",\r
+ "STR_SET_PWD_FOR_DIR": "[parent] 为某个目录下的所有文件设置相同的密码",\r
+ "STR_SET_AUTO_INSTALL_FOR_FILE": "[image] 为某个镜像文件设置自动安装脚本",\r
+ "STR_SET_AUTO_INSTALL_FOR_DIR": "[parent] 为某个目录下的所有文件设置相同的自动安装脚本",\r
+\r
+ "STR_SET_CLASS_BY_KEY": "[key] 通过文件名关键字设置类型",\r
+ "STR_SET_CLASS_BY_DIR": "[dir] 为某个目录设置类型(只针对该目录本身,不包含里面的文件及子目录)",\r
+ "STR_SET_CLASS_BY_PARENT": "[parent] 为某个目录下的所有子文件设置类型(只针对文件,不包含目录)",\r
+\r
+ "STR_SET_IMAGE_PWD": "[file] 为某个镜像文件设置密码",\r
+ "STR_SET_PARENT_PWD": "[parent] 为某个目录下的所有文件设置相同的密码",\r
+\r
+\r
+ \r
+ "STR_SET_SEARCH_ROOT": "设置搜索目录",\r
+ "STR_SET_DEFAULT_IMAGE": "设置默认镜像文件",\r
+ "STR_ADD_THEME": "添加主题",\r
+ "STR_ADD_FONT": "添加字体",\r
+ "STR_ADD_FILE_TO_LIST": "添加文件",\r
+ "STR_DEFAULT_SELECT": " 默认选择",\r
+ "STR_AUTO_TEMPLATE": "自动安装脚本",\r
+ "STR_ADD_AUTO_TEMPLATE": "添加自动安装脚本",\r
+ "STR_PERSISTENCE_DAT": "持久化数据文件",\r
+ "STR_ADD_PERSISTENCE_DAT": "添加持久化数据文件",\r
+ "STR_DUD_FILE": "DUD 文件",\r
+ "STR_ADD_DUD_FILE": "添加 DUD 文件",\r
+\r
+ "STR_DEL_LAST": "这是本条目中的最后一项,删除此项将会删除整个条目。是否继续?",\r
+ "STR_CLOSE_TIP": "后台服务不可用,页面即将关闭!",\r
+ "STR_SECURE_BOOT_ENABLE": "开启",\r
+ "STR_SECURE_BOOT_DISABLE": "未开启",\r
+ "STR_SYNTAX_ERROR_TIP": "ventoy.json 文件中存在语法错误,配置未加载!",\r
+\r
+\r
+\r
+ "STR_XXX": "xxx"\r
+};\r
+\r
+var g_current_dir;\r
+var g_current_os;\r
+var g_current_language = 'cn';\r
+var g_vtoy_cur_language = g_vtoy_cur_language_cn;\r
+var g_vtoy_data_default_index = 6;\r
+\r
+var g_file_with_extra = false;\r
+var g_dir_with_extra = false;\r
+var g_file_fuzzy_match = 0;\r
+var g_file_modal_callback;\r
+var g_dir_modal_callback;\r
+\r
+function ventoy_file_submit(form, extra) {\r
+ var filepath = $("#FilePath").val();\r
+ var fileextra = $("#FileExtra").val();\r
+\r
+ if (!filepath) {\r
+ return;\r
+ }\r
+\r
+ if (extra) {\r
+ if (!fileextra) {\r
+ return;\r
+ }\r
+ }\r
+\r
+ filepath = ventoy_replace_slash(filepath);\r
+\r
+ if (!ventoy_common_check_path(filepath)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ return;\r
+ }\r
+\r
+ if (g_file_fuzzy_match && filepath.indexOf("*") >= 0) {\r
+ callVtoySync({\r
+ method : 'check_fuzzy',\r
+ path: filepath\r
+ }, function(data) { \r
+ if (data.exist != 0) {\r
+ if (typeof(g_file_modal_callback) === 'function') {\r
+ g_file_modal_callback(filepath, -1, fileextra);\r
+ }\r
+ $("#SetFileModal").modal('hide');\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ }\r
+ });\r
+ } else {\r
+ callVtoySync({\r
+ method : 'check_path',\r
+ dir: 0,\r
+ path: filepath\r
+ }, function(data) { \r
+ if (data.exist === 1) {\r
+ if (typeof(g_file_modal_callback) === 'function') {\r
+ g_file_modal_callback(filepath, 1, fileextra);\r
+ }\r
+ $("#SetFileModal").modal('hide');\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ }\r
+ });\r
+ }\r
+}\r
+\r
+\r
+var g_filepath_validator = $("#SetFileForm").validate({\r
+ rules: { \r
+ FilePath : {\r
+ required: true,\r
+ utfmaxlen: true,\r
+ noquotes: true\r
+ },\r
+ FileExtra : {\r
+ required: false,\r
+ utfmaxlen: true\r
+ }\r
+ },\r
+ submitHandler: function(form) {\r
+ ventoy_file_submit(form, g_file_with_extra);\r
+ }\r
+});\r
+\r
+var g_dirpath_validator = $("#SetDirForm").validate({\r
+ rules: { \r
+ DirPath : {\r
+ required: true,\r
+ utfmaxlen: true,\r
+ noquotes: true\r
+ },\r
+ DirExtra : {\r
+ required: false,\r
+ utfmaxlen: true\r
+ }\r
+ },\r
+ submitHandler: function(form) {\r
+ var dirpath = $("#DirPath").val();\r
+ var dirextra = $("#DirExtra").val();\r
+ \r
+ if (!dirpath) {\r
+ return;\r
+ }\r
+\r
+ if (g_dir_with_extra) {\r
+ if (!dirextra) {\r
+ return;\r
+ }\r
+ }\r
+\r
+ dirpath = ventoy_replace_slash(dirpath);\r
+\r
+ if (dirpath.length > 0 && dirpath.charCodeAt(dirpath.length - 1) === 47) {\r
+ dirpath = dirpath.substring(0, dirpath.length - 1);\r
+ }\r
+\r
+ if (!ventoy_common_check_path(dirpath)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_DIR_PATH);\r
+ return;\r
+ }\r
+\r
+ callVtoySync({\r
+ method : 'check_path',\r
+ dir: 1,\r
+ path: dirpath \r
+ }, function(data) { \r
+ if (data.exist === 1) {\r
+ if (typeof(g_dir_modal_callback) === 'function') {\r
+ g_dir_modal_callback(dirpath, dirextra);\r
+ }\r
+ $("#SetDirModal").modal('hide');\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_DIR_PATH);\r
+ }\r
+ });\r
+ }\r
+});\r
+\r
+function VtoySelectFilePath(cb, para) {\r
+ g_file_fuzzy_match = para.fuzzy;\r
+ \r
+ if (para.extra) {\r
+ $('div[id=id_div_file_extra]').show();\r
+ $('#SetFileForm_extra').text(para.extra_title);\r
+ } else {\r
+ $('div[id=id_div_file_extra]').hide();\r
+ }\r
+\r
+ $('span[id=id_span_filepath_tip1]').each(function(){\r
+ $(this).text(para.tip1);\r
+ });\r
+ $('span[id=id_span_filepath_tip2]').each(function(){\r
+ $(this).text(para.tip2);\r
+ });\r
+ $('span[id=id_span_filepath_tip3]').each(function(){\r
+ $(this).text(para.tip3);\r
+ });\r
+\r
+ if (g_current_language === 'en') {\r
+ if (para.title.length === 0) {\r
+ $('#SetFileForm #SetFileForm_lang_1').text("Set File Path");\r
+ } else {\r
+ $('#SetFileForm #SetFileForm_lang_1').text(para.title);\r
+ }\r
+ \r
+ $('#SetFileForm #SetFileForm_lang_2').text("File Path");\r
+ $('#SetFileForm #SetFileForm_lang_3').text(" OK");\r
+ $('#SetFileForm #SetFileForm_lang_4').text("Cancel");\r
+ $('#SetFileForm #id_note_setfile_cn').hide();\r
+ $('#SetFileForm #id_note_setfile_en').show();\r
+ } else {\r
+ if (para.title.length === 0) {\r
+ $('#SetFileForm #SetFileForm_lang_1').text("设置文件路径");\r
+ } else {\r
+ $('#SetFileForm #SetFileForm_lang_1').text(para.title);\r
+ }\r
+ $('#SetFileForm #SetFileForm_lang_2').text("文件路径");\r
+ $('#SetFileForm #SetFileForm_lang_3').text("确定");\r
+ $('#SetFileForm #SetFileForm_lang_4').text("取消");\r
+ $('#SetFileForm #id_note_setfile_cn').show();\r
+ $('#SetFileForm #id_note_setfile_en').hide();\r
+ }\r
+\r
+ if (para.tip3.length > 0) {\r
+ if (g_current_language === 'en') {\r
+ $('#SetFileForm #id_note_tip3_en').show();\r
+ $('#SetFileForm #id_note_tip3_cn').hide();\r
+ } else {\r
+ $('#SetFileForm #id_note_tip3_cn').show();\r
+ $('#SetFileForm #id_note_tip3_en').hide();\r
+ }\r
+ } else {\r
+ $('#SetFileForm #id_note_tip3_en').hide();\r
+ $('#SetFileForm #id_note_tip3_cn').hide();\r
+ }\r
+\r
+ g_file_modal_callback = cb;\r
+ g_file_with_extra = para.extra;\r
+ g_filepath_validator.settings.rules.FileExtra.required = g_file_with_extra;\r
+ g_filepath_validator.resetForm();\r
+ $("#SetFileModal").modal(); \r
+}\r
+\r
+\r
+function VtoySelectDirPath(cb, para) {\r
+ $('span[id=id_span_dirpath_tip]').each(function(){\r
+ $(this).text(para.tip);\r
+ });\r
+ $('span[id=id_span_dirpath_tip3]').each(function(){\r
+ $(this).text(para.tip3);\r
+ });\r
+\r
+ if (para.extra) {\r
+ $('div[id=id_div_dir_extra]').show();\r
+ $('label[id=SetDirForm_extra]').text(para.extra_title);\r
+ } else {\r
+ $('div[id=id_div_dir_extra]').hide();\r
+ }\r
+\r
+ if (g_current_language === 'en') {\r
+ if (para.title.length === 0) {\r
+ $('#SetDirForm #SetDirForm_lang_1').text("Set Directory Path");\r
+ } else {\r
+ $('#SetDirForm #SetDirForm_lang_1').text(para.title);\r
+ }\r
+ $('#SetDirForm #SetDirForm_lang_2').text("Directory Path");\r
+ $('#SetDirForm #SetDirForm_lang_3').text(" OK");\r
+ $('#SetDirForm #SetDirForm_lang_4').text("Cancel");\r
+ $('#SetDirForm #id_note_setfile_cn').hide();\r
+ $('#SetDirForm #id_note_setfile_en').show();\r
+ } else {\r
+ if (para.title.length === 0) {\r
+ $('#SetDirForm #SetDirForm_lang_1').text("设置文件夹路径");\r
+ } else {\r
+ $('#SetDirForm #SetDirForm_lang_1').text(para.title);\r
+ }\r
+ $('#SetDirForm #SetDirForm_lang_2').text("文件夹路径");\r
+ $('#SetDirForm #SetDirForm_lang_3').text("确定");\r
+ $('#SetDirForm #SetDirForm_lang_4').text("取消");\r
+ $('#SetDirForm #id_note_setfile_cn').show();\r
+ $('#SetDirForm #id_note_setfile_en').hide();\r
+ }\r
+\r
+ if (para.tip3.length > 0) {\r
+ if (g_current_language === 'en') {\r
+ $('#SetDirForm #id_note_tip3_en').show();\r
+ $('#SetDirForm #id_note_tip3_cn').hide();\r
+ } else {\r
+ $('#SetDirForm #id_note_tip3_cn').show();\r
+ $('#SetDirForm #id_note_tip3_en').hide();\r
+ }\r
+ } else {\r
+ $('#SetDirForm #id_note_tip3_en').hide();\r
+ $('#SetDirForm #id_note_tip3_cn').hide();\r
+ }\r
+\r
+ g_dir_modal_callback = cb;\r
+ g_dir_with_extra = para.extra;\r
+ g_dirpath_validator.settings.rules.DirExtra.required = g_dir_with_extra;\r
+ g_dirpath_validator.resetForm(); \r
+ $("#SetDirModal").modal(); \r
+}\r
+\r
+function VtoyCommonChangeLanguage(newlang) {\r
+ if (newlang === 'en') {\r
+ g_vtoy_cur_language = g_vtoy_cur_language_en;\r
+ ;$.extend($.validator.messages, {\r
+ required: "This field is required",\r
+ remote: "Please modify this field", \r
+ maxlength: $.validator.format("You can enter up to {0} characters"),\r
+ minlength: $.validator.format("Must enter at least {0} characters"),\r
+ rangelength: $.validator.format("Please input {0} to {1} characters"),\r
+ range: $.validator.format("The input range is from {0} to {1}"),\r
+ max: $.validator.format("Please input a number less than or equal to {0}"),\r
+ min: $.validator.format("Please input a number bigger than or equal to {0}"),\r
+ utfmaxlen: $.validator.format("The string exceeds the maximum supported length"),\r
+ start_slash: $.validator.format("Must start with /"),\r
+ noquotes: $.validator.format("Can not include double quotes"),\r
+ printascii: $.validator.format("Can not include non-ascii characters.")\r
+ });\r
+\r
+ $("a[id=id_a_official_doc]").each(function(){\r
+ var oldlink = $(this).attr('href');\r
+ var newlink = oldlink.replace("/cn/", "/en/");\r
+ $(this).attr('href', newlink);\r
+ });\r
+ \r
+ $("span[id=id_span_official_doc]").each(function(){\r
+ $(this).text(" Plugin Official Document");\r
+ });\r
+ \r
+ $('#id_span_language').text("中文");\r
+ \r
+ $("tr[id=tr_title_desc_cn]").each(function(){\r
+ $(this).hide();\r
+ });\r
+ \r
+ $("tr[id=tr_title_desc_en]").each(function(){\r
+ $(this).show();\r
+ });\r
+ \r
+ $("th[id=id_th_file_path]").each(function(){\r
+ $(this).text("Full File Path");\r
+ });\r
+\r
+ $("span[id=id_span_desc_cn]").each(function(){\r
+ $(this).hide();\r
+ });\r
+\r
+ } else {\r
+ g_vtoy_cur_language = g_vtoy_cur_language_cn;\r
+ ;$.extend($.validator.messages, {\r
+ required: "这是必填字段",\r
+ remote: "请修正此字段", \r
+ maxlength: $.validator.format("最多可以输入 {0} 个字符"),\r
+ minlength: $.validator.format("最少要输入 {0} 个字符"),\r
+ rangelength: $.validator.format("请输入长度在 {0} 到 {1} 之间的字符串"),\r
+ range: $.validator.format("取值范围{0}到{1}"),\r
+ max: $.validator.format("请输入不大于 {0} 的数值"),\r
+ min: $.validator.format("请输入不小于 {0} 的数值"),\r
+ utfmaxlen: $.validator.format("超过最大长度"),\r
+ start_slash: $.validator.format("必须以反斜杠 / 开头"),\r
+ noquotes: $.validator.format("不能包含双引号"),\r
+ printascii: $.validator.format("不能包含中文或其他非 ascii 字符。")\r
+ });\r
+ \r
+ $("a[id=id_a_official_doc]").each(function(){\r
+ var oldlink = $(this).attr('href');\r
+ var newlink = oldlink.replace("/en/", "/cn/");\r
+ $(this).attr('href', newlink);\r
+ });\r
+ \r
+ $("span[id=id_span_official_doc]").each(function(){\r
+ $(this).text(" 插件官网文档");\r
+ });\r
+ \r
+ $('#id_span_language').text("English");\r
+ \r
+ $("tr[id=tr_title_desc_cn]").each(function(){\r
+ $(this).show();\r
+ });\r
+ \r
+ $("tr[id=tr_title_desc_en]").each(function(){\r
+ $(this).hide();\r
+ });\r
+ \r
+ $("th[id=id_th_file_path]").each(function(){\r
+ $(this).text("文件路径");\r
+ });\r
+\r
+ $("span[id=id_span_desc_cn]").each(function(){\r
+ $(this).show();\r
+ });\r
+ }\r
+\r
+ $("span[id=id_span_menu_device]").text(g_vtoy_cur_language.STR_PLUG_DEVICE);\r
+ $("span[id=id_span_menu_control]").text(g_vtoy_cur_language.STR_PLUG_CONTROL);\r
+ $("span[id=id_span_menu_theme]").text(g_vtoy_cur_language.STR_PLUG_THEME);\r
+ $("span[id=id_span_menu_alias]").text(g_vtoy_cur_language.STR_PLUG_ALIAS);\r
+ $("span[id=id_span_menu_tip]").text(g_vtoy_cur_language.STR_PLUG_TIP);\r
+ $("span[id=id_span_menu_class]").text(g_vtoy_cur_language.STR_PLUG_CLASS);\r
+ $("span[id=id_span_menu_auto_install]").text(g_vtoy_cur_language.STR_PLUG_AUTO_INSTALL);\r
+ $("span[id=id_span_menu_persistence]").text(g_vtoy_cur_language.STR_PLUG_PERSISTENCE);\r
+ $("span[id=id_span_menu_injection]").text(g_vtoy_cur_language.STR_PLUG_INJECTION);\r
+ $("span[id=id_span_menu_conf_replace]").text(g_vtoy_cur_language.STR_PLUG_CONF_REPLACE);\r
+ $("span[id=id_span_menu_password]").text(g_vtoy_cur_language.STR_PLUG_PASSWORD);\r
+ $("span[id=id_span_menu_imagelist]").text(g_vtoy_cur_language.STR_PLUG_IMAGELIST);\r
+ $("span[id=id_span_menu_auto_memdisk]").text(g_vtoy_cur_language.STR_PLUG_AUTO_MEMDISK);\r
+ $("span[id=id_span_menu_dud]").text(g_vtoy_cur_language.STR_PLUG_DUD);\r
+ $('#id_span_save').text(g_vtoy_cur_language.STR_SAVE);\r
+ $('#id_span_reset').text(g_vtoy_cur_language.STR_RESET);\r
+ $('#id_span_donation').text(g_vtoy_cur_language.STR_PLUG_DONATION);\r
+\r
+ $("span[id=id_span_btn_add]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_ADD);\r
+ });\r
+ $("span[id=id_span_btn_del]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_DEL);\r
+ });\r
+\r
+ $("span[id=id_span_enable]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_ENABLE);\r
+ });\r
+\r
+ $("th[id=id_th_operation]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_OPERATION);\r
+ });\r
+ $("th[id=id_th_status]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_STATUS);\r
+ });\r
+\r
+ $('span [id=id_span_valid').each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_VALID);\r
+ });\r
+ $('span [id=id_span_invalid').each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_INVALID);\r
+ });\r
+\r
+ $("td[id=td_title_desc]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_OPT_DESC);\r
+ });\r
+ \r
+ $("td[id=td_title_setting]").each(function(){\r
+ $(this).text(g_vtoy_cur_language.STR_OPT_SETTING);\r
+ });\r
+}\r
+\r
+ \r
+function ventoy_get_status_line(dir, exist) {\r
+ if (dir) {\r
+ if (exist === 0) {\r
+ return '<span id="id_span_dir_nonexist" style="line-height: 1.5;" class="label pull-left bg-red">' + g_vtoy_cur_language.STR_DIR_NONEXIST + '</span>';\r
+ } else {\r
+ return '<span id="id_span_dir_exist" style="line-height: 1.5;" class="label pull-left bg-green">' + g_vtoy_cur_language.STR_DIR_EXIST + '</span>';\r
+ }\r
+ } else {\r
+ if (exist === -1) {\r
+ return '<span id="id_span_file_fuzzy" style="line-height: 1.5;" class="label pull-left bg-yellow">' + g_vtoy_cur_language.STR_FILE_FUZZY + '</span>';\r
+ } else if (exist === 1) {\r
+ return '<span id="id_span_file_exist" style="line-height: 1.5;" class="label pull-left bg-green">' + g_vtoy_cur_language.STR_FILE_EXIST + '</span>';\r
+ } else {\r
+ return '<span id="id_span_file_nonexist" style="line-height: 1.5;" class="label pull-left bg-red">' + g_vtoy_cur_language.STR_FILE_NONEXIST + '</span>';\r
+ }\r
+ }\r
+}\r
+\r
+\r
+\r
+var g_type_select_callback;\r
+\r
+var g_type_select_validator = $("#TypeSelectForm").validate({ \r
+ submitHandler: function(form) {\r
+ var sel = parseInt($('input:radio[name=name_select_type_radio]:checked').val());\r
+ if (typeof(g_type_select_callback) === 'function') {\r
+ g_type_select_callback(sel);\r
+ }\r
+\r
+ $("#TypeSelectModal").modal('hide');\r
+ }\r
+});\r
+\r
+function VtoySelectType(cb, para) {\r
+\r
+ $('#TypeSelectForm #TypeSelForm_lang_1').text(g_vtoy_cur_language.STR_SELECT);\r
+\r
+ if (g_current_language === 'en') {\r
+ $('#SetDirForm #SetDirForm_lang_2').text(" OK");\r
+ $('#SetDirForm #SetDirForm_lang_3').text("Cancel");\r
+ } else {\r
+ $('#SetDirForm #SetDirForm_lang_2').text("确定");\r
+ $('#SetDirForm #SetDirForm_lang_3').text("取消");\r
+ }\r
+ \r
+ var $tbl = $("#id_type_select_table tbody");\r
+ $tbl.empty();\r
+\r
+ for (var i = 0; i < para.length; i++) {\r
+ var $tr;\r
+\r
+ if (para[i].selected) {\r
+ $tr = $('<tr><td><label class="radio-inline"><input type="radio" checked="checked" name="name_select_type_radio" value="' + i + '"/>' + para[i].tip + '</label></td></tr>');\r
+ } else {\r
+ $tr = $('<tr><td><label class="radio-inline"><input type="radio" name="name_select_type_radio" value="' + i + '"/>' + para[i].tip + '</label></td></tr>');\r
+ }\r
+\r
+ $tbl.append($tr);\r
+ }\r
+\r
+ g_type_select_callback = cb;\r
+ g_type_select_validator.resetForm(); \r
+ $("#TypeSelectModal").modal(); \r
+}\r
+\r
+\r
+var g_set_key_callback;\r
+\r
+var g_set_key_validator = $("#SetKeyForm").validate({ \r
+ rules: { \r
+ SetKeyKey : {\r
+ required: true,\r
+ utfmaxlen: true \r
+ },\r
+ SetKeyValue : {\r
+ required: true,\r
+ utfmaxlen: true \r
+ }\r
+ },\r
+\r
+ submitHandler: function(form) {\r
+ var key = $('input:text[id=SetKeyKey]').val();\r
+ var val = $('input:text[id=SetKeyValue]').val();\r
+\r
+ if ((!key) || (!val))\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (typeof(g_set_key_callback) === 'function') {\r
+ g_set_key_callback(key, val);\r
+ }\r
+\r
+ $("#SetKeyModal").modal('hide');\r
+ }\r
+});\r
+\r
+function VtoySetKey(cb, para) {\r
+\r
+ $('#SetKeyForm #SetKeyForm_lang_1').text(para.title);\r
+ $('#SetKeyForm #SetKeyForm_lang_2').text(para.title1);\r
+ $('#SetKeyForm #SetKeyForm_lang_3').text(para.title2);\r
+\r
+ if (g_current_language === 'en') {\r
+ $('#SetDirForm #SetDirForm_lang_4').text(" OK");\r
+ $('#SetDirForm #SetDirForm_lang_5').text("Cancel");\r
+ } else {\r
+ $('#SetDirForm #SetDirForm_lang_4').text("确定");\r
+ $('#SetDirForm #SetDirForm_lang_5').text("取消");\r
+ }\r
+ \r
+ g_set_key_callback = cb;\r
+ g_set_key_validator.resetForm(); \r
+ $("#SetKeyModal").modal(); \r
+}\r
+\r
+var g_valid_color_name = [\r
+ "black",\r
+ "blue",\r
+ "green",\r
+ "cyan",\r
+ "red",\r
+ "magenta",\r
+ "brown",\r
+ "light-gray",\r
+ "dark-gray",\r
+ "light-blue",\r
+ "light-green",\r
+ "light-cyan",\r
+ "light-red",\r
+ "light-magenta",\r
+ "yellow",\r
+ "white"\r
+];\r
+\r
+function ventoy_check_color(color) {\r
+ if (/^#[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]$/.test(color)) {\r
+ return true;\r
+ } else {\r
+ for (var i = 0; i < g_valid_color_name.length; i++) {\r
+ if (g_valid_color_name[i] === color) {\r
+ return true;\r
+ }\r
+ }\r
+ }\r
+\r
+ return false;\r
+}\r
+\r
+function ventoy_check_percent(percent) {\r
+ if (percent.length > 0) {\r
+ return true;\r
+ } else {\r
+ return false;\r
+ }\r
+}\r
+\r
+\r
+function ventoy_check_file_path(isopath, fuzzy, cb) {\r
+ if (fuzzy && isopath.indexOf("*") >= 0) {\r
+ callVtoySync({\r
+ method : 'check_fuzzy',\r
+ path: isopath\r
+ }, function(data) { \r
+ if (data.exist != 0) {\r
+ if (typeof(cb) === 'function') {\r
+ cb(data.exist);\r
+ }\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ }\r
+ });\r
+ } else {\r
+ callVtoySync({\r
+ method : 'check_path',\r
+ dir: 0,\r
+ path: isopath\r
+ }, function(data) { \r
+ if (data.exist === 1) {\r
+ if (typeof(cb) === 'function') {\r
+ cb(data.exist);\r
+ }\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH);\r
+ }\r
+ });\r
+ }\r
+}\r
+\r
+function ventoy_random_string(e) { \r
+ var t = "abcdefhijkmnprstwxyz2345678";\r
+ var a = t.length;\r
+ var n = "";\r
+\r
+ e = e || 4;\r
+ for (i = 0; i < e; i++) n += t.charAt(Math.floor(Math.random() * a));\r
+ return n\r
+}\r
+\r
+\r
+var g_set_filefile_callback;\r
+\r
+var g_set_filefile_validator = $("#SetFileFileForm").validate({ \r
+ rules: { \r
+ FileFilePath1 : {\r
+ required: true,\r
+ utfmaxlen: true\r
+ },\r
+ FileFilePath2 : {\r
+ required: true,\r
+ utfmaxlen: true \r
+ }\r
+ },\r
+\r
+ submitHandler: function(form) {\r
+ var path1 = $('input:text[id=FileFilePath1]').val();\r
+ var path2 = $('input:text[id=FileFilePath2]').val();\r
+\r
+ if ((!path1) || (!path2))\r
+ {\r
+ return;\r
+ }\r
+\r
+ path1 = ventoy_replace_slash(path1);\r
+\r
+ if (!ventoy_common_check_path(path1)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH1);\r
+ return;\r
+ }\r
+\r
+ path2 = ventoy_replace_slash(path2);\r
+\r
+ if (!ventoy_common_check_path(path2)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH2);\r
+ return;\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'check_path2',\r
+ dir1: 0,\r
+ fuzzy1: 1,\r
+ path1: path1,\r
+ dir2: 0,\r
+ fuzzy2: 0,\r
+ path2: path2\r
+ }, function(retdata) {\r
+ if (retdata.exist1 != 0 && retdata.exist2 != 0) {\r
+ if (typeof(g_set_filefile_callback) === 'function') {\r
+ g_set_filefile_callback(retdata.exist1, path1, path2);\r
+ }\r
+\r
+ $("#SetFileFileModal").modal('hide');\r
+ } else if (retdata.exist1 === 0) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH1);\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH2);\r
+ }\r
+ });\r
+ }\r
+});\r
+\r
+function VtoySetFileFile(cb, para) {\r
+\r
+ $('#SetFileFileForm #SetFileFileForm_title').text(para.title);\r
+ $('#SetFileFileForm #SetFileFileForm_label1').text(para.label1);\r
+ $('#SetFileFileForm #SetFileFileForm_label2').text(para.label2);\r
+\r
+ if (g_current_language === 'en') {\r
+ $('#SetFileFileForm #SetFileFileForm_ok').text(" OK");\r
+ $('#SetFileFileForm #SetFileFileForm_cancel').text("Cancel");\r
+\r
+ $('#SetFileFileForm #id_note_filefile_cn').hide();\r
+ $('#SetFileFileForm #id_note_filefile_en').show();\r
+\r
+ } else {\r
+ $('#SetFileFileForm #SetFileFileForm_ok').text("确定");\r
+ $('#SetFileFileForm #SetFileFileForm_cancel').text("取消");\r
+\r
+ $('#SetFileFileForm #id_note_filefile_en').hide();\r
+ $('#SetFileFileForm #id_note_filefile_cn').show();\r
+ }\r
+\r
+ $('span[id=id_span_filefile_tip1]').each(function(){\r
+ $(this).text(para.tip1);\r
+ });\r
+ $('span[id=id_span_filefile_tip2]').each(function(){\r
+ $(this).text(para.tip2);\r
+ });\r
+ $('span[id=id_span_filefile_tip3]').each(function(){\r
+ $(this).text(para.tip3);\r
+ });\r
+ \r
+ g_set_filefile_callback = cb;\r
+ g_set_filefile_validator.resetForm(); \r
+ $("#SetFileFileModal").modal();\r
+}\r
+\r
+\r
+var g_set_dirfile_callback;\r
+\r
+var g_set_dirfile_validator = $("#SetDirFileForm").validate({ \r
+ rules: { \r
+ DirFilePath1 : {\r
+ required: true,\r
+ utfmaxlen: true\r
+ },\r
+ DirFilePath2 : {\r
+ required: true,\r
+ utfmaxlen: true \r
+ }\r
+ },\r
+\r
+ submitHandler: function(form) {\r
+ var path1 = $('input:text[id=DirFilePath1]').val();\r
+ var path2 = $('input:text[id=DirFilePath2]').val();\r
+\r
+ if ((!path1) || (!path2))\r
+ {\r
+ return;\r
+ }\r
+\r
+ path1 = ventoy_replace_slash(path1);\r
+\r
+ if (!ventoy_common_check_path(path1)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH1);\r
+ return;\r
+ }\r
+\r
+ path2 = ventoy_replace_slash(path2);\r
+\r
+ if (!ventoy_common_check_path(path2)) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH2);\r
+ return;\r
+ }\r
+\r
+ callVtoy({\r
+ method : 'check_path2',\r
+ dir1: 1,\r
+ fuzzy1: 0,\r
+ path1: path1,\r
+ dir2: 0,\r
+ fuzzy2: 0,\r
+ path2: path2\r
+ }, function(retdata) {\r
+ if (retdata.exist1 != 0 && retdata.exist2 != 0) {\r
+ if (typeof(g_set_dirfile_callback) === 'function') {\r
+ g_set_dirfile_callback(path1, path2);\r
+ }\r
+\r
+ $("#SetDirFileModal").modal('hide');\r
+ } else if (retdata.exist1 === 0) {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_DIR_PATH);\r
+ } else {\r
+ Message.error(g_vtoy_cur_language.STR_INVALID_FILE_PATH2);\r
+ }\r
+ });\r
+ }\r
+});\r
+\r
+function VtoySetDirFile(cb, para) {\r
+\r
+ $('#SetDirFileModal #SetDirFileForm_title').text(para.title);\r
+ $('#SetDirFileModal #SetDirFileForm_label1').text(para.label1);\r
+ $('#SetDirFileModal #SetDirFileForm_label2').text(para.label2);\r
+\r
+ if (g_current_language === 'en') {\r
+ $('#SetDirFileModal #SetDirFileModal_ok').text(" OK");\r
+ $('#SetDirFileModal #SetDirFileModal_cancel').text("Cancel");\r
+\r
+ $('#SetDirFileModal #id_note_dirfile_cn').hide();\r
+ $('#SetDirFileModal #id_note_dirfile_en').show();\r
+\r
+ } else {\r
+ $('#SetDirFileModal #SetDirFileModal_ok').text("确定");\r
+ $('#SetDirFileModal #SetDirFileModal_cancel').text("取消");\r
+\r
+ $('#SetDirFileModal #id_note_dirfile_en').hide();\r
+ $('#SetDirFileModal #id_note_dirfile_cn').show();\r
+ }\r
+\r
+ $('span[id=id_span_dirfile_tip1]').each(function(){\r
+ $(this).text(para.tip1);\r
+ });\r
+ $('span[id=id_span_dirfile_tip2]').each(function(){\r
+ $(this).text(para.tip2);\r
+ });\r
+ \r
+ g_set_dirfile_callback = cb;\r
+ g_set_dirfile_validator.resetForm(); \r
+ $("#SetDirFileModal").modal();\r
+}\r
+\r
+function ventoy_get_xslg_addbtn(mclass) {\r
+ return '<button class="btn btn-xs btn-lg btn-success btn-add ' + mclass + '"><span class="fa fa-plus"> </span><span id="id_span_btn_add">'+g_vtoy_cur_language.STR_ADD+'</span></button>';\r
+}\r
+\r
+function ventoy_get_xslg_delbtn(mclass) {\r
+ return '<button class="btn btn-xs btn-lg btn-danger btn-del '+mclass+'"><span class="fa fa-trash"> </span><span id="id_span_btn_del">'+g_vtoy_cur_language.STR_DEL+'</span></button>';\r
+}\r
+\r
+function ventoy_get_addbtn(mclass) {\r
+ return '<button class="btn btn-success btn-add ' + mclass + '"><span class="fa fa-plus"> </span><span id="id_span_btn_add">'+g_vtoy_cur_language.STR_ADD+'</span></button>';\r
+}\r
+\r
+function ventoy_get_delbtn(mclass) {\r
+ return '<button class="btn btn-danger btn-del '+mclass+'"><span class="fa fa-trash"> </span><span id="id_span_btn_del">'+g_vtoy_cur_language.STR_DEL+'</span></button>';\r
+}\r
+\r
+function ventoy_confirm(title, cb, data1, data2) {\r
+ Modal.confirm({msg:g_vtoy_cur_language.STR_DEL_LAST}).on(function(e) {\r
+ if (e) {\r
+ if (typeof(cb) === 'function') {\r
+ cb(data1, data2);\r
+ }\r
+ }\r
+ });\r
+}\r
Windows 7, Windows 8, Windows 8.1, Windows 10, Windows 11, Windows Server 2012, Windows Server 2012 R2, Windows Server 2016, Windows Server 2019, Windows Server 2022, WinPE
**Linux**
-Debian, Ubuntu, CentOS, RHEL, Deepin, Fedora, Rocky Linux, SLES, openSUSE, MX Linux, Manjaro, Linux Mint, Endless OS, openEuler, Elementary OS, Solus, Linx, Zorin, antiX, PClinuxOS, Arch, ArcoLinux, ArchLabs, BackArch, Obarun, Artix Linux, Puppy Linux, Tails, Slax, Kali, Mageia, Slackware, Q4OS, Archman, Gentoo, Pentoo, NixOS, Ubuntu Kylin, Lubuntu, Xubuntu, Kubuntu, Ubuntu MATE, Ubuntu Budgie, Ubuntu Studio, Bluestar, OpenMandriva, ExTiX, Netrunner, ALT Linux, Nitrux, Peppermint, KDE neon, Linux Lite, Parrot OS, Qubes, Pop OS, ROSA, Void Linux, Star Linux, EndeavourOS, MakuluLinux, Voyager, Feren, ArchBang, LXLE, Knoppix, Robolinux, Calculate Linux, Clear Linux, Pure OS, Oracle Linux, Trident, Septor, Porteus, Devuan, GoboLinux, 4MLinux, Simplicity Linux, Zeroshell, Android-x86, netboot.xyz, Slitaz, SuperGrub2Disk, Proxmox VE, Kaspersky Rescue, SystemRescueCD, MemTest86, MiniTool Partition Wizard, Parted Magic, veket, Sabayon, Scientific, alpine, ClearOS, CloneZilla, Berry Linux, Trisquel, Ataraxia Linux, Minimal Linux Live, BackBox Linux, Emmabuntüs, ESET SysRescue Live,Nova Linux, AV Linux, RoboLinux, NuTyX, IPFire, SELKS, ZStack, Enso Linux, Security Onion, Network Security Toolkit, Absolute Linux, TinyCore, Springdale Linux, Frost Linux, Shark Linux, LinuxFX, Snail Linux, Astra Linux, Namib Linux, Resilient Linux, Virage Linux, Blackweb Security OS, R-DriveImage, O-O.DiskImage, Macrium, ToOpPy LINUX, GNU Guix, YunoHost, foxclone, siduction, Adelie Linux, Elive, Pardus, CDlinux, AcademiX, Austrumi, Zenwalk, Anarchy, DuZeru, BigLinux, OpenMediaVault, Ubuntu DP, Exe GNU/Linux, 3CX Phone System, KANOTIX, Grml, Karoshi, PrimTux, ArchStrike, CAELinux, Refracta, Cucumber, Fatdog, ForLEx, Hanthana, Kwort, MiniNo, Redcore, Runtu, Asianux, Clu Linux Live, Uruk, OB2D, BlueOnyx, Finnix, HamoniKR, Parabola, LinHES, LinuxConsole, BEE free, Untangle, Pearl, Thinstation, TurnKey, tuxtrans, Neptune, HefftorLinux, GeckoLinux, Mabox Linux, Zentyal, Maui, Reborn OS, SereneLinux , SkyWave Linux, Kaisen Linux, Regata OS, TROM-Jaro, DRBL Linux, Chalet OS, Chapeau, Desa OS, BlankOn, OpenMamba, Frugalware, Kibojoe Linux, Revenge OS, Tsurugi Linux, Drauger OS, Hash Linux, gNewSense, Ikki Boot, SteamOS, Hyperbola, VyOS, EasyNAS, SuperGamer, Live Raizo, Swift Linux, RebeccaBlackOS, Daphile, CRUX, Univention, Ufficio Zero, Rescuezilla, Phoenix OS, Garuda Linux, Mll, NethServer, OSGeoLive, Easy OS, Volumio, FreedomBox, paldo, UBOS, Recalbox, batocera, Lakka, LibreELEC, Pardus Topluluk, Pinguy, KolibriOS, Elastix, Arya, Omoikane, Omarine, Endian Firewall, Hamara, Rocks Cluster, MorpheusArch, Redo, Slackel, SME Server, APODIO, Smoothwall, Dragora, Linspire, Secure-K OS, Peach OSI, Photon, Plamo, SuperX, Bicom, Ploplinux, HP SPP, LliureX, Freespire, DietPi, BOSS, Webconverger, Lunar, TENS, Source Mage, RancherOS, T2, Vine, Pisi, blackPanther, mAid, Acronis, Active.Boot, AOMEI, Boot.Repair, CAINE, DaRT, EasyUEFI, R-Drive, PrimeOS, Avira Rescue System, bitdefender, Checkra1n Linux, Lenovo Diagnostics, Clover, Bliss-OS, Lenovo BIOS Update, Arcabit Rescue Disk, MiyoLinux, TeLOS, Kerio Control, RED OS, OpenWrt, MocaccinoOS, EasyStartup, Pyabr, Refracta, Eset SysRescue, Linpack Xtreme, Archcraft, ......
+Debian, Ubuntu, CentOS, RHEL, Deepin, Fedora, Rocky Linux, SLES, openSUSE, MX Linux, Manjaro, Linux Mint, Endless OS, openEuler, Elementary OS, Solus, Linx, Zorin, antiX, PClinuxOS, Arch, ArcoLinux, ArchLabs, BlackArch, Obarun, Artix Linux, Puppy Linux, Tails, Slax, Kali, Mageia, Slackware, Q4OS, Archman, Gentoo, Pentoo, NixOS, Ubuntu Kylin, Lubuntu, Xubuntu, Kubuntu, Ubuntu MATE, Ubuntu Budgie, Ubuntu Studio, Bluestar, OpenMandriva, ExTiX, Netrunner, ALT Linux, Nitrux, Peppermint, KDE neon, Linux Lite, Parrot OS, Qubes, Pop OS, ROSA, Void Linux, Star Linux, EndeavourOS, MakuluLinux, Voyager, Feren, ArchBang, LXLE, Knoppix, Robolinux, Calculate Linux, Clear Linux, Pure OS, Oracle Linux, Trident, Septor, Porteus, Devuan, GoboLinux, 4MLinux, Simplicity Linux, Zeroshell, Android-x86, netboot.xyz, Slitaz, SuperGrub2Disk, Proxmox VE, Kaspersky Rescue, SystemRescueCD, MemTest86, MiniTool Partition Wizard, Parted Magic, veket, Sabayon, Scientific, alpine, ClearOS, CloneZilla, Berry Linux, Trisquel, Ataraxia Linux, Minimal Linux Live, BackBox Linux, Emmabuntüs, ESET SysRescue Live,Nova Linux, AV Linux, RoboLinux, NuTyX, IPFire, SELKS, ZStack, Enso Linux, Security Onion, Network Security Toolkit, Absolute Linux, TinyCore, Springdale Linux, Frost Linux, Shark Linux, LinuxFX, Snail Linux, Astra Linux, Namib Linux, Resilient Linux, Virage Linux, Blackweb Security OS, R-DriveImage, O-O.DiskImage, Macrium, ToOpPy LINUX, GNU Guix, YunoHost, foxclone, siduction, Adelie Linux, Elive, Pardus, CDlinux, AcademiX, Austrumi, Zenwalk, Anarchy, DuZeru, BigLinux, OpenMediaVault, Ubuntu DP, Exe GNU/Linux, 3CX Phone System, KANOTIX, Grml, Karoshi, PrimTux, ArchStrike, CAELinux, Refracta, Cucumber, Fatdog, ForLEx, Hanthana, Kwort, MiniNo, Redcore, Runtu, Asianux, Clu Linux Live, Uruk, OB2D, BlueOnyx, Finnix, HamoniKR, Parabola, LinHES, LinuxConsole, BEE free, Untangle, Pearl, Thinstation, TurnKey, tuxtrans, Neptune, HefftorLinux, GeckoLinux, Mabox Linux, Zentyal, Maui, Reborn OS, SereneLinux , SkyWave Linux, Kaisen Linux, Regata OS, TROM-Jaro, DRBL Linux, Chalet OS, Chapeau, Desa OS, BlankOn, OpenMamba, Frugalware, Kibojoe Linux, Revenge OS, Tsurugi Linux, Drauger OS, Hash Linux, gNewSense, Ikki Boot, SteamOS, Hyperbola, VyOS, EasyNAS, SuperGamer, Live Raizo, Swift Linux, RebeccaBlackOS, Daphile, CRUX, Univention, Ufficio Zero, Rescuezilla, Phoenix OS, Garuda Linux, Mll, NethServer, OSGeoLive, Easy OS, Volumio, FreedomBox, paldo, UBOS, Recalbox, batocera, Lakka, LibreELEC, Pardus Topluluk, Pinguy, KolibriOS, Elastix, Arya, Omoikane, Omarine, Endian Firewall, Hamara, Rocks Cluster, MorpheusArch, Redo, Slackel, SME Server, APODIO, Smoothwall, Dragora, Linspire, Secure-K OS, Peach OSI, Photon, Plamo, SuperX, Bicom, Ploplinux, HP SPP, LliureX, Freespire, DietPi, BOSS, Webconverger, Lunar, TENS, Source Mage, RancherOS, T2, Vine, Pisi, blackPanther, mAid, Acronis, Active.Boot, AOMEI, Boot.Repair, CAINE, DaRT, EasyUEFI, R-Drive, PrimeOS, Avira Rescue System, bitdefender, Checkra1n Linux, Lenovo Diagnostics, Clover, Bliss-OS, Lenovo BIOS Update, Arcabit Rescue Disk, MiyoLinux, TeLOS, Kerio Control, RED OS, OpenWrt, MocaccinoOS, EasyStartup, Pyabr, Refracta, Eset SysRescue, Linpack Xtreme, Archcraft, ......
**Unix**
DragonFly FreeBSD pfSense GhostBSD FreeNAS TrueNAS XigmaNAS FuryBSD OPNsense HardenedBSD MidnightBSD ClonOS EmergencyBootKit
return TRUE;\r
}\r
\r
-\r
-STATIC BOOL VDS_CallBack_ShrinkVolume(void* pInterface, VDS_DISK_PROP* pDiskProp, UINT64 data)\r
+STATIC HRESULT VDS_RealShrinkVolume(void* pInterface, VDS_DISK_PROP* pDiskProp, UINT64 data)\r
{\r
- int i;\r
HRESULT hr, hr2;\r
IVdsVolume* pVolume = (IVdsVolume*)pInterface;\r
ULONG completed;\r
IVdsAsync* pAsync;\r
- VDS_PARA *VdsPara = (VDS_PARA *)data;\r
+ VDS_PARA* VdsPara = (VDS_PARA*)data;\r
\r
(void)pDiskProp;\r
\r
- Log("VDS_CallBack_ShrinkVolume (%C:) (%llu) ...", VdsPara->DriveLetter, (ULONGLONG)VdsPara->Offset);\r
+ Log("VDS_ShrinkVolume (%C:) (%llu) ...", VdsPara->DriveLetter, (ULONGLONG)VdsPara->Offset);\r
\r
hr = IVdsVolume_Shrink(pVolume, (ULONGLONG)VdsPara->Offset, &pAsync);\r
- if (hr == VDS_E_SHRINK_DIRTY_VOLUME)\r
- {\r
- Log("Volume %C: is dirty, run chkdsk and retry.", VdsPara->DriveLetter);\r
- CHKDSK_Volume(VdsPara->DriveLetter);\r
-\r
- hr = IVdsVolume_Shrink(pVolume, (ULONGLONG)VdsPara->Offset, &pAsync);\r
- if (hr == VDS_E_SHRINK_DIRTY_VOLUME)\r
- {\r
- Log("################################################################");\r
- Log("################################################################");\r
- for (i = 0; i < 20; i++)\r
- {\r
- Log("###### Volume dirty, Please run \"chkdsk /f %C:\" and retry. ######", VdsPara->Name[0]);\r
- }\r
- Log("################################################################");\r
- Log("################################################################");\r
- }\r
- }\r
\r
while (SUCCEEDED(hr))\r
{\r
Sleep(1000);\r
}\r
\r
+ return hr;\r
+}\r
+\r
+STATIC BOOL VDS_CallBack_ShrinkVolume(void* pInterface, VDS_DISK_PROP* pDiskProp, UINT64 data)\r
+{\r
+ int i;\r
+ HRESULT hr;\r
+ VDS_PARA *VdsPara = (VDS_PARA *)data;\r
+\r
+ Log("VDS_CallBack_ShrinkVolume (%C:) (%llu) ...", VdsPara->DriveLetter, (ULONGLONG)VdsPara->Offset);\r
+\r
+ hr = VDS_RealShrinkVolume(pInterface, pDiskProp, data);\r
+ if (hr == VDS_E_SHRINK_DIRTY_VOLUME)\r
+ {\r
+ Log("Volume %C: is dirty, run chkdsk and retry.", VdsPara->DriveLetter);\r
+ CHKDSK_Volume(VdsPara->DriveLetter);\r
+\r
+ hr = VDS_RealShrinkVolume(pInterface, pDiskProp, data);\r
+ if (hr == VDS_E_SHRINK_DIRTY_VOLUME)\r
+ {\r
+ Log("################################################################");\r
+ Log("################################################################");\r
+ for (i = 0; i < 20; i++)\r
+ {\r
+ Log("###### Volume dirty, Please run \"chkdsk /f %C:\" and retry. ######", VdsPara->Name[0]);\r
+ }\r
+ Log("################################################################");\r
+ Log("################################################################");\r
+ }\r
+ }\r
+\r
if (hr != S_OK)\r
{\r
VDS_SET_ERROR(hr);\r