diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..c485be9 --- /dev/null +++ b/install.sh @@ -0,0 +1,1028 @@ +#!/bin/bash +# +# Copyright © 2016 - 2023 筱锋xiao_lfeng. All Rights Reserved. +# 开发开源遵循 MIT 许可,若需商用请联系开发者 +# https://www.x-lf.com/ +# + +PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin +export PATH +LANG=en_US.UTF-8 + +CURL_CHECK=$(which curl) +if [ "$?" == "0" ];then + curl -sS --connect-timeout 10 -m 10 https://www.bt.cn/api/wpanel/SetupCount > /dev/null 2>&1 +else + wget -O /dev/null -o /dev/null -T 5 https://www.bt.cn/api/wpanel/SetupCount +fi + +if [ $(whoami) != "root" ];then + echo "请使用root权限执行宝塔安装命令!" + exit 1; +fi + +is64bit=$(getconf LONG_BIT) +if [ "${is64bit}" != '64' ];then + Red_Error "抱歉, 当前面板版本不支持32位系统, 请使用64位系统或安装宝塔5.9!"; +fi + +Centos6Check=$(cat /etc/redhat-release | grep ' 6.' | grep -iE 'centos|Red Hat') +if [ "${Centos6Check}" ];then + echo "Centos6不支持安装宝塔面板,请更换Centos7/8安装宝塔面板" + exit 1 +fi + +UbuntuCheck=$(cat /etc/issue|grep Ubuntu|awk '{print $2}'|cut -f 1 -d '.') +if [ "${UbuntuCheck}" ] && [ "${UbuntuCheck}" -lt "16" ];then + echo "Ubuntu ${UbuntuCheck}不支持安装宝塔面板,建议更换Ubuntu18/20安装宝塔面板" + exit 1 +fi + +cd ~ +setup_path="/www" +python_bin=$setup_path/server/panel/pyenv/bin/python +cpu_cpunt=$(cat /proc/cpuinfo|grep processor|wc -l) + +# if [ "$1" ];then +# IDC_CODE=$1 +# fi + +GetSysInfo(){ + if [ -s "/etc/redhat-release" ];then + SYS_VERSION=$(cat /etc/redhat-release) + elif [ -s "/etc/issue" ]; then + SYS_VERSION=$(cat /etc/issue) + fi + SYS_INFO=$(uname -a) + SYS_BIT=$(getconf LONG_BIT) + MEM_TOTAL=$(free -m|grep Mem|awk '{print $2}') + CPU_INFO=$(getconf _NPROCESSORS_ONLN) + + echo -e ${SYS_VERSION} + echo -e Bit:${SYS_BIT} Mem:${MEM_TOTAL}M Core:${CPU_INFO} + echo -e ${SYS_INFO} + echo -e "============================================" + echo -e "请截图以上报错信息发帖至论坛www.bt.cn/bbs求助" + echo -e "============================================" + if [ -f "/usr/bin/qrencode" ];then + echo -e "或微信扫码联系企业微信技术求助" + echo -e "============================================" + qrencode -t ANSIUTF8 "https://work.weixin.qq.com/kfid/kfc9072f0e29a53bd52" + echo -e "============================================" + else + echo -e "或手机访问以下链接、扫码联系企业微信技术求助" + echo -e "============================================" + echo -e "联系链接:https://work.weixin.qq.com/kfid/kfc9072f0e29a53bd52" + echo -e "============================================" + fi +} +Red_Error(){ + echo '================================================='; + printf '\033[1;31;40m%b\033[0m\n' "$@"; + GetSysInfo + exit 1; +} +Lock_Clear(){ + if [ -f "/etc/bt_crack.pl" ];then + chattr -R -ia /www + chattr -ia /etc/init.d/bt + \cp -rpa /www/backup/panel/vhost/* /www/server/panel/vhost/ + mv /www/server/panel/BTPanel/__init__.bak /www/server/panel/BTPanel/__init__.py + rm -f /etc/bt_crack.pl + fi +} +Install_Check(){ + if [ "${INSTALL_FORCE}" ];then + return + fi + echo -e "----------------------------------------------------" + echo -e "检查已有其他Web/mysql环境,安装宝塔可能影响现有站点及数据" + echo -e "Web/mysql service is alreday installed,Can't install panel" + echo -e "----------------------------------------------------" + echo -e "已知风险/Enter yes to force installation" + read -p "输入yes强制安装: " yes; + if [ "$yes" != "yes" ];then + echo -e "------------" + echo "取消安装" + exit; + fi + INSTALL_FORCE="true" +} +System_Check(){ + MYSQLD_CHECK=$(ps -ef |grep mysqld|grep -v grep|grep -v /www/server/mysql) + PHP_CHECK=$(ps -ef|grep php-fpm|grep master|grep -v /www/server/php) + NGINX_CHECK=$(ps -ef|grep nginx|grep master|grep -v /www/server/nginx) + HTTPD_CHECK=$(ps -ef |grep -E 'httpd|apache'|grep -v /www/server/apache|grep -v grep) + if [ "${PHP_CHECK}" ] || [ "${MYSQLD_CHECK}" ] || [ "${NGINX_CHECK}" ] || [ "${HTTPD_CHECK}" ];then + Install_Check + fi +} +Set_Ssl(){ + echo -e "" + echo -e "----------------------------------------------------------------------" + echo -e "为了您的面板使用安全,建议您开启面板SSL,开启后请使用https访问宝塔面板" + echo -e "输入y回车即开启面板SSL并进行下一步安装" + echo -e "输入n回车跳过面板SSL配置,直接进行安装" + echo -e "面板SSL将在10秒钟后自动开启" + echo -e "----------------------------------------------------------------------" + echo -e "" + read -t 10 -p "是否确定开启面板SSL ? (y/n): " yes + + if [ $? != 0 ];then + SET_SSL=true + else + case "$yes" in + y) + SET_SSL=true + ;; + n) + SET_SSL=false + rm -f /www/server/panel/data/ssl.pl + ;; + *) + Set_Ssl + esac + fi +} +Get_Pack_Manager(){ + if [ -f "/usr/bin/yum" ] && [ -d "/etc/yum.repos.d" ]; then + PM="yum" + elif [ -f "/usr/bin/apt-get" ] && [ -f "/usr/bin/dpkg" ]; then + PM="apt-get" + fi +} +Auto_Swap() +{ + swap=$(free |grep Swap|awk '{print $2}') + if [ "${swap}" -gt 1 ];then + echo "Swap total sizse: $swap"; + return; + fi + if [ ! -d /www ];then + mkdir /www + fi + swapFile="/www/swap" + dd if=/dev/zero of=$swapFile bs=1M count=1025 + mkswap -f $swapFile + swapon $swapFile + echo "$swapFile swap swap defaults 0 0" >> /etc/fstab + swap=`free |grep Swap|awk '{print $2}'` + if [ $swap -gt 1 ];then + echo "Swap total sizse: $swap"; + return; + fi + + sed -i "/\/www\/swap/d" /etc/fstab + rm -f $swapFile +} +Service_Add(){ + if [ "${PM}" == "yum" ] || [ "${PM}" == "dnf" ]; then + chkconfig --add bt + chkconfig --level 2345 bt on + Centos9Check=$(cat /etc/redhat-release |grep ' 9') + if [ "${Centos9Check}" ];then + wget -O /usr/lib/systemd/system/btpanel.service ${download_Url}/init/systemd/btpanel.service + systemctl enable btpanel + fi + elif [ "${PM}" == "apt-get" ]; then + update-rc.d bt defaults + fi +} +Set_Centos_Repo(){ + HUAWEI_CHECK=$(cat /etc/motd |grep "Huawei Cloud") + if [ "${HUAWEI_CHECK}" ] && [ "${is64bit}" == "64" ];then + \cp -rpa /etc/yum.repos.d/ /etc/yumBak + sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo + sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.epel.cloud|g' /etc/yum.repos.d/CentOS-*.repo + rm -f /etc/yum.repos.d/epel.repo + rm -f /etc/yum.repos.d/epel-* + fi + ALIYUN_CHECK=$(cat /etc/motd|grep "Alibaba Cloud ") + if [ "${ALIYUN_CHECK}" ] && [ "${is64bit}" == "64" ] && [ ! -f "/etc/yum.repos.d/Centos-vault-8.5.2111.repo" ];then + rename '.repo' '.repo.bak' /etc/yum.repos.d/*.repo + wget https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo -O /etc/yum.repos.d/Centos-vault-8.5.2111.repo + wget https://mirrors.aliyun.com/repo/epel-archive-8.repo -O /etc/yum.repos.d/epel-archive-8.repo + sed -i 's/mirrors.cloud.aliyuncs.com/url_tmp/g' /etc/yum.repos.d/Centos-vault-8.5.2111.repo && sed -i 's/mirrors.aliyun.com/mirrors.cloud.aliyuncs.com/g' /etc/yum.repos.d/Centos-vault-8.5.2111.repo && sed -i 's/url_tmp/mirrors.aliyun.com/g' /etc/yum.repos.d/Centos-vault-8.5.2111.repo + sed -i 's/mirrors.aliyun.com/mirrors.cloud.aliyuncs.com/g' /etc/yum.repos.d/epel-archive-8.repo + fi + MIRROR_CHECK=$(cat /etc/yum.repos.d/CentOS-Linux-AppStream.repo |grep "[^#]mirror.centos.org") + if [ "${MIRROR_CHECK}" ] && [ "${is64bit}" == "64" ];then + \cp -rpa /etc/yum.repos.d/ /etc/yumBak + sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*.repo + sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.epel.cloud|g' /etc/yum.repos.d/CentOS-*.repo + fi +} +get_node_url(){ + if [ ! -f /bin/curl ];then + if [ "${PM}" = "yum" ]; then + yum install curl -y + elif [ "${PM}" = "apt-get" ]; then + apt-get install curl -y + fi + fi + + if [ -f "/www/node.pl" ];then + download_Url=$(cat /www/node.pl) + echo "Download node: $download_Url"; + echo '---------------------------------------------'; + return + fi + + echo '---------------------------------------------'; + echo "Selected download node..."; + nodes=(https://dg2.bt.cn https://download.bt.cn https://ctcc1-node.bt.cn https://cmcc1-node.bt.cn https://ctcc2-node.bt.cn https://hk1-node.bt.cn https://na1-node.bt.cn https://jp1-node.bt.cn); + + if [ "$1" ];then + nodes=($(echo ${nodes[*]}|sed "s#${1}##")) + fi + + tmp_file1=/dev/shm/net_test1.pl + tmp_file2=/dev/shm/net_test2.pl + [ -f "${tmp_file1}" ] && rm -f ${tmp_file1} + [ -f "${tmp_file2}" ] && rm -f ${tmp_file2} + touch $tmp_file1 + touch $tmp_file2 + for node in ${nodes[@]}; + do + NODE_CHECK=$(curl --connect-timeout 3 -m 3 2>/dev/null -w "%{http_code} %{time_total}" ${node}/net_test|xargs) + RES=$(echo ${NODE_CHECK}|awk '{print $1}') + NODE_STATUS=$(echo ${NODE_CHECK}|awk '{print $2}') + TIME_TOTAL=$(echo ${NODE_CHECK}|awk '{print $3 * 1000 - 500 }'|cut -d '.' -f 1) + if [ "${NODE_STATUS}" == "200" ];then + if [ $TIME_TOTAL -lt 100 ];then + if [ $RES -ge 1500 ];then + echo "$RES $node" >> $tmp_file1 + fi + else + if [ $RES -ge 1500 ];then + echo "$TIME_TOTAL $node" >> $tmp_file2 + fi + fi + + i=$(($i+1)) + if [ $TIME_TOTAL -lt 100 ];then + if [ $RES -ge 3000 ];then + break; + fi + fi + fi + done + + NODE_URL=$(cat $tmp_file1|sort -r -g -t " " -k 1|head -n 1|awk '{print $2}') + if [ -z "$NODE_URL" ];then + NODE_URL=$(cat $tmp_file2|sort -g -t " " -k 1|head -n 1|awk '{print $2}') + if [ -z "$NODE_URL" ];then + NODE_URL='https://download.bt.cn'; + fi + fi + rm -f $tmp_file1 + rm -f $tmp_file2 + download_Url=$NODE_URL + echo "Download node: $download_Url"; + echo '---------------------------------------------'; +} +Remove_Package(){ + local PackageNmae=$1 + if [ "${PM}" == "yum" ];then + isPackage=$(rpm -q ${PackageNmae}|grep "not installed") + if [ -z "${isPackage}" ];then + yum remove ${PackageNmae} -y + fi + elif [ "${PM}" == "apt-get" ];then + isPackage=$(dpkg -l|grep ${PackageNmae}) + if [ "${PackageNmae}" ];then + apt-get remove ${PackageNmae} -y + fi + fi +} +Install_RPM_Pack(){ + yumPath=/etc/yum.conf + Centos8Check=$(cat /etc/redhat-release | grep ' 8.' | grep -iE 'centos|Red Hat') + if [ "${Centos8Check}" ];then + Set_Centos_Repo + fi + isExc=$(cat $yumPath|grep httpd) + if [ "$isExc" = "" ];then + echo "exclude=httpd nginx php mysql mairadb python-psutil python2-psutil" >> $yumPath + fi + + if [ -f "/etc/redhat-release" ] && [ $(cat /etc/os-release|grep PLATFORM_ID|grep -oE "el8") ];then + yum config-manager --set-enabled powertools + yum config-manager --set-enabled PowerTools + fi + + if [ -f "/etc/redhat-release" ] && [ $(cat /etc/os-release|grep PLATFORM_ID|grep -oE "el9") ];then + dnf config-manager --set-enabled crb -y + fi + + #SYS_TYPE=$(uname -a|grep x86_64) + #yumBaseUrl=$(cat /etc/yum.repos.d/CentOS-Base.repo|grep baseurl=http|cut -d '=' -f 2|cut -d '$' -f 1|head -n 1) + #[ "${yumBaseUrl}" ] && checkYumRepo=$(curl --connect-timeout 5 --head -s -o /dev/null -w %{http_code} ${yumBaseUrl}) + #if [ "${checkYumRepo}" != "200" ] && [ "${SYS_TYPE}" ];then + # curl -Ss --connect-timeout 3 -m 60 http://download.bt.cn/install/yumRepo_select.sh|bash + #fi + + #尝试同步时间(从bt.cn) + echo 'Synchronizing system time...' + getBtTime=$(curl -sS --connect-timeout 3 -m 60 http://www.bt.cn/api/index/get_time) + if [ "${getBtTime}" ];then + date -s "$(date -d @$getBtTime +"%Y-%m-%d %H:%M:%S")" + fi + + if [ -z "${Centos8Check}" ]; then + yum install ntp -y + rm -rf /etc/localtime + ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime + + #尝试同步国际时间(从ntp服务器) + ntpdate 0.asia.pool.ntp.org + setenforce 0 + fi + + startTime=`date +%s` + + sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config + #yum remove -y python-requests python3-requests python-greenlet python3-greenlet + yumPacks="libcurl-devel wget tar gcc make zip unzip openssl openssl-devel gcc libxml2 libxml2-devel libxslt* zlib zlib-devel libjpeg-devel libpng-devel libwebp libwebp-devel freetype freetype-devel lsof pcre pcre-devel vixie-cron crontabs icu libicu-devel c-ares libffi-devel bzip2-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel qrencode" + yum install -y ${yumPacks} + + for yumPack in ${yumPacks} + do + rpmPack=$(rpm -q ${yumPack}) + packCheck=$(echo ${rpmPack}|grep not) + if [ "${packCheck}" ]; then + yum install ${yumPack} -y + fi + done + if [ -f "/usr/bin/dnf" ]; then + dnf install -y redhat-rpm-config + fi + + ALI_OS=$(cat /etc/redhat-release |grep "Alibaba Cloud Linux release 3") + if [ -z "${ALI_OS}" ];then + yum install epel-release -y + fi +} +Install_Deb_Pack(){ + ln -sf bash /bin/sh + UBUNTU_22=$(cat /etc/issue|grep "Ubuntu 22") + if [ "${UBUNTU_22}" ];then + apt-get remove needrestart -y + fi + ALIYUN_CHECK=$(cat /etc/motd|grep "Alibaba Cloud ") + if [ "${ALIYUN_CHECK}" ] && [ "${UBUNTU_22}" ];then + apt-get remove libicu70 -y + fi + apt-get update -y + apt-get install bash -y + if [ -f "/usr/bin/bash" ];then + ln -sf /usr/bin/bash /bin/sh + fi + apt-get install ruby -y + apt-get install lsb-release -y + #apt-get install ntp ntpdate -y + #/etc/init.d/ntp stop + #update-rc.d ntp remove + #cat >>~/.profile< /var/spool/cron/crontabs/root + chmod 600 /var/spool/cron/crontabs/root + fi + fi +} +Get_Versions(){ + redhat_version_file="/etc/redhat-release" + deb_version_file="/etc/issue" + if [ -f $redhat_version_file ];then + os_type='el' + is_aliyunos=$(cat $redhat_version_file|grep Aliyun) + if [ "$is_aliyunos" != "" ];then + return + fi + os_version=$(cat $redhat_version_file|grep CentOS|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]') + if [ "${os_version}" = "5" ];then + os_version="" + fi + if [ -z "${os_version}" ];then + os_version=$(cat /etc/redhat-release |grep Stream|grep -oE 8) + fi + else + os_type='ubuntu' + os_version=$(cat $deb_version_file|grep Ubuntu|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '^[0-9]+') + if [ "${os_version}" = "" ];then + os_type='debian' + os_version=$(cat $deb_version_file|grep Debian|grep -Eo '([0-9]+\.)+[0-9]+'|grep -Eo '[0-9]+') + if [ "${os_version}" = "" ];then + os_version=$(cat $deb_version_file|grep Debian|grep -Eo '[0-9]+') + fi + if [ "${os_version}" = "8" ];then + os_version="" + fi + if [ "${is64bit}" = '32' ];then + os_version="" + fi + else + if [ "$os_version" = "14" ];then + os_version="" + fi + if [ "$os_version" = "12" ];then + os_version="" + fi + if [ "$os_version" = "19" ];then + os_version="" + fi + if [ "$os_version" = "21" ];then + os_version="" + fi + if [ "$os_version" = "20" ];then + os_version2004=$(cat /etc/issue|grep 20.04) + if [ -z "${os_version2004}" ];then + os_version="" + fi + fi + fi + fi +} +Install_Python_Lib(){ + curl -Ss --connect-timeout 3 -m 60 $download_Url/install/pip_select.sh|bash + pyenv_path="/www/server/panel" + if [ -f $pyenv_path/pyenv/bin/python ];then + is_ssl=$($python_bin -c "import ssl" 2>&1|grep cannot) + $pyenv_path/pyenv/bin/python3.7 -V + if [ $? -eq 0 ] && [ -z "${is_ssl}" ];then + chmod -R 700 $pyenv_path/pyenv/bin + is_package=$($python_bin -m psutil 2>&1|grep package) + if [ "$is_package" = "" ];then + wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip.txt -T 5 + $pyenv_path/pyenv/bin/pip install -U pip + $pyenv_path/pyenv/bin/pip install -U setuptools==65.5.0 + $pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt + fi + source $pyenv_path/pyenv/bin/activate + chmod -R 700 $pyenv_path/pyenv/bin + return + else + rm -rf $pyenv_path/pyenv + fi + fi + + is_loongarch64=$(uname -a|grep loongarch64) + if [ "$is_loongarch64" != "" ] && [ -f "/usr/bin/yum" ];then + yumPacks="python3-devel python3-pip python3-psutil python3-gevent python3-pyOpenSSL python3-paramiko python3-flask python3-rsa python3-requests python3-six python3-websocket-client" + yum install -y ${yumPacks} + for yumPack in ${yumPacks} + do + rpmPack=$(rpm -q ${yumPack}) + packCheck=$(echo ${rpmPack}|grep not) + if [ "${packCheck}" ]; then + yum install ${yumPack} -y + fi + done + + pip3 install -U pip + pip3 install Pillow psutil pyinotify pycryptodome upyun oss2 pymysql qrcode qiniu redis pymongo Cython configparser cos-python-sdk-v5 supervisor gevent-websocket pyopenssl + pip3 install flask==1.1.4 + pip3 install Pillow -U + + pyenv_bin=/www/server/panel/pyenv/bin + mkdir -p $pyenv_bin + ln -sf /usr/local/bin/pip3 $pyenv_bin/pip + ln -sf /usr/local/bin/pip3 $pyenv_bin/pip3 + ln -sf /usr/local/bin/pip3 $pyenv_bin/pip3.7 + + if [ -f "/usr/bin/python3.7" ];then + ln -sf /usr/bin/python3.7 $pyenv_bin/python + ln -sf /usr/bin/python3.7 $pyenv_bin/python3 + ln -sf /usr/bin/python3.7 $pyenv_bin/python3.7 + elif [ -f "/usr/bin/python3.6" ]; then + ln -sf /usr/bin/python3.6 $pyenv_bin/python + ln -sf /usr/bin/python3.6 $pyenv_bin/python3 + ln -sf /usr/bin/python3.6 $pyenv_bin/python3.7 + fi + + echo > $pyenv_bin/activate + + return + fi + + py_version="3.7.16" + mkdir -p $pyenv_path + echo "True" > /www/disk.pl + if [ ! -w /www/disk.pl ];then + Red_Error "ERROR: Install python env fielded." "ERROR: /www目录无法写入,请检查目录/用户/磁盘权限!" + fi + os_type='el' + os_version='7' + is_export_openssl=0 + Get_Versions + + echo "OS: $os_type - $os_version" + is_aarch64=$(uname -a|grep aarch64) + if [ "$is_aarch64" != "" ];then + is64bit="aarch64" + fi + + if [ -f "/www/server/panel/pymake.pl" ];then + os_version="" + rm -f /www/server/panel/pymake.pl + fi + + if [ "${os_version}" != "" ];then + pyenv_file="/www/pyenv.tar.gz" + wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 10 + if [ "$?" != "0" ];then + get_node_url $download_Url + wget -O $pyenv_file $download_Url/install/pyenv/pyenv-${os_type}${os_version}-x${is64bit}.tar.gz -T 10 + fi + tmp_size=$(du -b $pyenv_file|awk '{print $1}') + if [ $tmp_size -lt 703460 ];then + rm -f $pyenv_file + echo "ERROR: Download python env fielded." + else + echo "Install python env..." + tar zxvf $pyenv_file -C $pyenv_path/ > /dev/null + chmod -R 700 $pyenv_path/pyenv/bin + if [ ! -f $pyenv_path/pyenv/bin/python ];then + rm -f $pyenv_file + Red_Error "ERROR: Install python env fielded." "ERROR: 下载宝塔运行环境失败,请尝试重新安装!" + fi + $pyenv_path/pyenv/bin/python3.7 -V + if [ $? -eq 0 ];then + rm -f $pyenv_file + ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip + ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython + source $pyenv_path/pyenv/bin/activate + return + else + rm -f $pyenv_file + rm -rf $pyenv_path/pyenv + fi + fi + fi + + cd /www + python_src='/www/python_src.tar.xz' + python_src_path="/www/Python-${py_version}" + wget -O $python_src $download_Url/src/Python-${py_version}.tar.xz -T 5 + tmp_size=$(du -b $python_src|awk '{print $1}') + if [ $tmp_size -lt 10703460 ];then + rm -f $python_src + Red_Error "ERROR: Download python source code fielded." "ERROR: 下载宝塔运行环境失败,请尝试重新安装!" + fi + tar xvf $python_src + rm -f $python_src + cd $python_src_path + ./configure --prefix=$pyenv_path/pyenv + make -j$cpu_cpunt + make install + if [ ! -f $pyenv_path/pyenv/bin/python3.7 ];then + rm -rf $python_src_path + Red_Error "ERROR: Make python env fielded." "ERROR: 编译宝塔运行环境失败!" + fi + cd ~ + rm -rf $python_src_path + wget -O $pyenv_path/pyenv/bin/activate $download_Url/install/pyenv/activate.panel -T 5 + wget -O $pyenv_path/pyenv/pip.txt $download_Url/install/pyenv/pip-3.7.16.txt -T 5 + ln -sf $pyenv_path/pyenv/bin/pip3.7 $pyenv_path/pyenv/bin/pip + ln -sf $pyenv_path/pyenv/bin/python3.7 $pyenv_path/pyenv/bin/python + ln -sf $pyenv_path/pyenv/bin/pip3.7 /usr/bin/btpip + ln -sf $pyenv_path/pyenv/bin/python3.7 /usr/bin/btpython + chmod -R 700 $pyenv_path/pyenv/bin + $pyenv_path/pyenv/bin/pip install -U pip + $pyenv_path/pyenv/bin/pip install -U setuptools==65.5.0 + $pyenv_path/pyenv/bin/pip install -U wheel==0.34.2 + $pyenv_path/pyenv/bin/pip install -r $pyenv_path/pyenv/pip.txt + + wget -O pip-packs.txt $download_Url/install/pyenv/pip-packs.txt + PIP_PACKS=$(cat pip-packs.txt) + for P_PACK in ${PIP_PACKS}; + do + btpip show ${P_PACK} > /dev/null 2>&1 + if [ "$?" == "1" ];then + btpip install ${P_PACK} + fi + done + + rm -f pip-packs.txt + + source $pyenv_path/pyenv/bin/activate + + btpip install psutil + btpip install gevent + + is_gevent=$($python_bin -m gevent 2>&1|grep -oE package) + is_psutil=$($python_bin -m psutil 2>&1|grep -oE package) + if [ "${is_gevent}" != "${is_psutil}" ];then + Red_Error "ERROR: psutil/gevent install failed!" + fi +} +Install_Bt(){ + panelPort="8888" + if [ -f ${setup_path}/server/panel/data/port.pl ];then + panelPort=$(cat ${setup_path}/server/panel/data/port.pl) + else + panelPort=$(expr $RANDOM % 55535 + 10000) + fi + if [ "${PANEL_PORT}" ];then + panelPort=$PANEL_PORT + fi + mkdir -p ${setup_path}/server/panel/logs + mkdir -p ${setup_path}/server/panel/vhost/apache + mkdir -p ${setup_path}/server/panel/vhost/nginx + mkdir -p ${setup_path}/server/panel/vhost/rewrite + mkdir -p ${setup_path}/server/panel/install + mkdir -p /www/server + mkdir -p /www/wwwroot + mkdir -p /www/wwwlogs + mkdir -p /www/backup/database + mkdir -p /www/backup/site + + if [ ! -d "/etc/init.d" ];then + mkdir -p /etc/init.d + fi + + if [ -f "/etc/init.d/bt" ]; then + /etc/init.d/bt stop + sleep 1 + fi + + wget -O /etc/init.d/bt ${download_Url}/install/src/bt6.init -T 10 + wget -O /www/server/panel/install/public.sh ${download_Url}/install/public.sh -T 10 + wget -O panel.zip ${download_Url}/install/src/panel6.zip -T 10 + + if [ -f "${setup_path}/server/panel/data/default.db" ];then + if [ -d "/${setup_path}/server/panel/old_data" ];then + rm -rf ${setup_path}/server/panel/old_data + fi + mkdir -p ${setup_path}/server/panel/old_data + d_format=$(date +"%Y%m%d_%H%M%S") + \cp -arf ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/data/default_backup_${d_format}.db + mv -f ${setup_path}/server/panel/data/default.db ${setup_path}/server/panel/old_data/default.db + mv -f ${setup_path}/server/panel/data/system.db ${setup_path}/server/panel/old_data/system.db + mv -f ${setup_path}/server/panel/data/port.pl ${setup_path}/server/panel/old_data/port.pl + mv -f ${setup_path}/server/panel/data/admin_path.pl ${setup_path}/server/panel/old_data/admin_path.pl + fi + + if [ ! -f "/usr/bin/unzip" ]; then + if [ "${PM}" = "yum" ]; then + yum install unzip -y + elif [ "${PM}" = "apt-get" ]; then + apt-get update + apt-get install unzip -y + fi + fi + + unzip -o panel.zip -d ${setup_path}/server/ > /dev/null + + if [ -d "${setup_path}/server/panel/old_data" ];then + mv -f ${setup_path}/server/panel/old_data/default.db ${setup_path}/server/panel/data/default.db + mv -f ${setup_path}/server/panel/old_data/system.db ${setup_path}/server/panel/data/system.db + mv -f ${setup_path}/server/panel/old_data/port.pl ${setup_path}/server/panel/data/port.pl + mv -f ${setup_path}/server/panel/old_data/admin_path.pl ${setup_path}/server/panel/data/admin_path.pl + if [ -d "/${setup_path}/server/panel/old_data" ];then + rm -rf ${setup_path}/server/panel/old_data + fi + fi + + if [ ! -f ${setup_path}/server/panel/tools.py ] || [ ! -f ${setup_path}/server/panel/BT-Panel ];then + ls -lh panel.zip + Red_Error "ERROR: Failed to download, please try install again!" "ERROR: 下载宝塔失败,请尝试重新安装!" + fi + + rm -f panel.zip + rm -f ${setup_path}/server/panel/class/*.pyc + rm -f ${setup_path}/server/panel/*.pyc + + chmod +x /etc/init.d/bt + chmod -R 600 ${setup_path}/server/panel + chmod -R +x ${setup_path}/server/panel/script + ln -sf /etc/init.d/bt /usr/bin/bt + echo "${panelPort}" > ${setup_path}/server/panel/data/port.pl + wget -O /etc/init.d/bt ${download_Url}/install/src/bt7.init -T 10 + wget -O /www/server/panel/init.sh ${download_Url}/install/src/bt7.init -T 10 + wget -O /www/server/panel/data/softList.conf ${download_Url}/install/conf/softList.conf + + if [ ! -f "${setup_path}/server/panel/data/installCount.pl" ];then + echo "1 $(date)" > ${setup_path}/server/panel/data/installCount.pl + elif [ -f "${setup_path}/server/panel/data/installCount.pl" ];then + INSTALL_COUNT=$(cat ${setup_path}/server/panel/data/installCount.pl|awk '{last=$1} END {print last}') + echo "$((INSTALL_COUNT+1)) $(date)" >> ${setup_path}/server/panel/data/installCount.pl + fi + +} +Set_Bt_Panel(){ + Run_User="www" + wwwUser=$(cat /etc/passwd|cut -d ":" -f 1|grep ^www$) + if [ "${wwwUser}" != "www" ];then + groupadd ${Run_User} + useradd -s /sbin/nologin -g ${Run_User} ${Run_User} + fi + + password=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8) + if [ "$PANEL_PASSWORD" ];then + password=$PANEL_PASSWORD + fi + sleep 1 + admin_auth="/www/server/panel/data/admin_path.pl" + if [ "${SAFE_PATH}" ];then + auth_path=$SAFE_PATH + echo "/${auth_path}" > ${admin_auth} + fi + if [ ! -f ${admin_auth} ];then + auth_path=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8) + echo "/${auth_path}" > ${admin_auth} + fi + auth_path=$(cat /dev/urandom | head -n 16 | md5sum | head -c 8) + echo "/${auth_path}" > ${admin_auth} + chmod -R 700 $pyenv_path/pyenv/bin + /www/server/panel/pyenv/bin/pip3 install pymongo + /www/server/panel/pyenv/bin/pip3 install psycopg2-binary + /www/server/panel/pyenv/bin/pip3 install flask -U + /www/server/panel/pyenv/bin/pip3 install flask-sock + auth_path=$(cat ${admin_auth}) + cd ${setup_path}/server/panel/ + if [ "$SET_SSL" == true ]; then + btpip install -I pyOpenSSl + btpython /www/server/panel/tools.py ssl + fi + /etc/init.d/bt start + $python_bin -m py_compile tools.py + $python_bin tools.py username + username=$($python_bin tools.py panel ${password}) + if [ "$PANEL_USER" ];then + username=$PANEL_USER + fi + cd ~ + echo "${password}" > ${setup_path}/server/panel/default.pl + chmod 600 ${setup_path}/server/panel/default.pl + sleep 3 + /etc/init.d/bt restart + sleep 3 + isStart=$(ps aux |grep 'BT-Panel'|grep -v grep|awk '{print $2}') + LOCAL_CURL=$(curl 127.0.0.1:${panelPort}/login 2>&1 |grep -i html) + if [ -z "${isStart}" ] && [ -z "${LOCAL_CURL}" ];then + /etc/init.d/bt 22 + cd /www/server/panel/pyenv/bin + touch t.pl + ls -al python3.7 python + lsattr python3.7 python + Red_Error "ERROR: The BT-Panel service startup failed." "ERROR: 宝塔启动失败" + fi + wget -O oneav_bt.sh https://download.bt.cn/install/plugin/oneav/install.sh > /dev/null 2>&1 + bash oneav_bt.sh install > /www/server/panel/install//btinstall.log 2>&1 + rm -f oneav_bt.sh + + if [ "$PANEL_USER" ];then + cd ${setup_path}/server/panel/ + btpython -c 'import tools;tools.set_panel_username("'$PANEL_USER'")' + cd ~ + fi +} +Set_Firewall(){ + sshPort=$(cat /etc/ssh/sshd_config | grep 'Port '|awk '{print $2}') + if [ "${PM}" = "apt-get" ]; then + apt-get install -y ufw + if [ -f "/usr/sbin/ufw" ];then + ufw allow 20/tcp + ufw allow 21/tcp + ufw allow 22/tcp + ufw allow 80/tcp + ufw allow 443/tcp + ufw allow 888/tcp + ufw allow ${panelPort}/tcp + ufw allow ${sshPort}/tcp + ufw allow 39000:40000/tcp + ufw_status=`ufw status` + echo y|ufw enable + ufw default deny + ufw reload + fi + else + if [ -f "/etc/init.d/iptables" ];then + iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 20 -j ACCEPT + iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 21 -j ACCEPT + iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT + iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT + iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 443 -j ACCEPT + iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${panelPort} -j ACCEPT + iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport ${sshPort} -j ACCEPT + iptables -I INPUT -p tcp -m state --state NEW -m tcp --dport 39000:40000 -j ACCEPT + #iptables -I INPUT -p tcp -m state --state NEW -m udp --dport 39000:40000 -j ACCEPT + iptables -A INPUT -p icmp --icmp-type any -j ACCEPT + iptables -A INPUT -s localhost -d localhost -j ACCEPT + iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT + iptables -P INPUT DROP + service iptables save + sed -i "s#IPTABLES_MODULES=\"\"#IPTABLES_MODULES=\"ip_conntrack_netbios_ns ip_conntrack_ftp ip_nat_ftp\"#" /etc/sysconfig/iptables-config + iptables_status=$(service iptables status | grep 'not running') + if [ "${iptables_status}" == '' ];then + service iptables restart + fi + else + AliyunCheck=$(cat /etc/redhat-release|grep "Aliyun Linux") + [ "${AliyunCheck}" ] && return + yum install firewalld -y + [ "${Centos8Check}" ] && yum reinstall python3-six -y + systemctl enable firewalld + systemctl start firewalld + firewall-cmd --set-default-zone=public > /dev/null 2>&1 + firewall-cmd --permanent --zone=public --add-port=20/tcp > /dev/null 2>&1 + firewall-cmd --permanent --zone=public --add-port=21/tcp > /dev/null 2>&1 + firewall-cmd --permanent --zone=public --add-port=22/tcp > /dev/null 2>&1 + firewall-cmd --permanent --zone=public --add-port=80/tcp > /dev/null 2>&1 + firewall-cmd --permanent --zone=public --add-port=443/tcp > /dev/null 2>&1 + firewall-cmd --permanent --zone=public --add-port=${panelPort}/tcp > /dev/null 2>&1 + firewall-cmd --permanent --zone=public --add-port=${sshPort}/tcp > /dev/null 2>&1 + firewall-cmd --permanent --zone=public --add-port=39000-40000/tcp > /dev/null 2>&1 + #firewall-cmd --permanent --zone=public --add-port=39000-40000/udp > /dev/null 2>&1 + firewall-cmd --reload + fi + fi +} +Get_Ip_Address(){ + getIpAddress="" + getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress) + if [ -z "${getIpAddress}" ] || [ "${getIpAddress}" = "0.0.0.0" ]; then + isHosts=$(cat /etc/hosts|grep 'www.bt.cn') + if [ -z "${isHosts}" ];then + echo "" >> /etc/hosts + echo "116.213.43.206 www.bt.cn" >> /etc/hosts + getIpAddress=$(curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/getIpAddress) + if [ -z "${getIpAddress}" ];then + sed -i "/bt.cn/d" /etc/hosts + fi + fi + fi + + ipv4Check=$($python_bin -c "import re; print(re.match('^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$','${getIpAddress}'))") + if [ "${ipv4Check}" == "None" ];then + ipv6Address=$(echo ${getIpAddress}|tr -d "[]") + ipv6Check=$($python_bin -c "import re; print(re.match('^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}$','${ipv6Address}'))") + if [ "${ipv6Check}" == "None" ]; then + getIpAddress="SERVER_IP" + else + echo "True" > ${setup_path}/server/panel/data/ipv6.pl + sleep 1 + /etc/init.d/bt restart + fi + fi + + if [ "${getIpAddress}" != "SERVER_IP" ];then + echo "${getIpAddress}" > ${setup_path}/server/panel/data/iplist.txt + fi + LOCAL_IP=$(ip addr | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -E -v "^127\.|^255\.|^0\." | head -n 1) +} +Setup_Count(){ + curl -sS --connect-timeout 10 -m 60 https://www.bt.cn/Api/SetupCount?type=Linux\&o=$1 > /dev/null 2>&1 + if [ "$1" != "" ];then + echo $1 > /www/server/panel/data/o.pl + cd /www/server/panel + $python_bin tools.py o + fi + echo /www > /var/bt_setupPath.conf +} +Install_Main(){ + Set_Ssl + startTime=`date +%s` + Lock_Clear + System_Check + Get_Pack_Manager + get_node_url + + MEM_TOTAL=$(free -g|grep Mem|awk '{print $2}') + if [ "${MEM_TOTAL}" -le "1" ];then + Auto_Swap + fi + + if [ "${PM}" = "yum" ]; then + Install_RPM_Pack + elif [ "${PM}" = "apt-get" ]; then + Install_Deb_Pack + fi + + Install_Python_Lib + Install_Bt + + + Set_Bt_Panel + Service_Add + Set_Firewall + + Get_Ip_Address + Setup_Count ${IDC_CODE} +} + +echo " ++---------------------------------------------------------------------- +| Bt-WebPanel FOR CentOS/Ubuntu/Debian ++---------------------------------------------------------------------- +| Copyright © 2015-2099 BT-SOFT(http://www.bt.cn) All rights reserved. ++---------------------------------------------------------------------- +| The WebPanel URL will be http://SERVER_IP:8888 when installed. ++---------------------------------------------------------------------- +| 为了您的正常使用,请确保使用全新或纯净的系统安装宝塔面板,不支持已部署项目/环境的系统安装 ++---------------------------------------------------------------------- +" + +while [ ${#} -gt 0 ]; do + case $1 in + -u|--user) + PANEL_USER=$2 + shift 1 + ;; + -p|--password) + PANEL_PASSWORD=$2 + shift 1 + ;; + -P|--port) + PANEL_PORT=$2 + shift 1 + ;; + --safe-path) + SAFE_PATH=$2 + shift 1 + ;; + -y) + go="y" + ;; + *) + IDC_CODE=$1 + ;; + esac + shift 1 +done + +while [ "$go" != 'y' ] && [ "$go" != 'n' ] +do + read -p "Do you want to install Bt-Panel to the $setup_path directory now?(y/n): " go; +done + +if [ "$go" == 'n' ];then + exit; +fi + +ARCH_LINUX=$(cat /etc/os-release |grep "Arch Linux") +if [ "${ARCH_LINUX}" ] && [ -f "/usr/bin/pacman" ];then + pacman -Sy + pacman -S curl wget unzip firewalld openssl pkg-config make gcc cmake libxml2 libxslt libvpx gd libsodium oniguruma sqlite libzip autoconf inetutils sudo --noconfirm +fi + +Install_Main + +PANEL_SSL=$(cat /www/server/panel/data/ssl.pl 2> /dev/null) +if [ "${PANEL_SSL}" == "True" ];then + HTTP_S="https" +else + HTTP_S="http" +fi + +echo > /www/server/panel/data/bind.pl +echo -e "==================================================================" +echo -e "\033[32mCongratulations! Installed successfully!\033[0m" +echo -e "==================================================================" +echo "外网面板地址: ${HTTP_S}://${getIpAddress}:${panelPort}${auth_path}" +echo "内网面板地址: ${HTTP_S}://${LOCAL_IP}:${panelPort}${auth_path}" +echo -e "username: $username" +echo -e "password: $password" +echo -e "\033[33mIf you cannot access the panel,\033[0m" +echo -e "\033[33mrelease the following panel port [${panelPort}] in the security group\033[0m" +echo -e "\033[33m若无法访问面板,请检查防火墙/安全组是否有放行面板[${panelPort}]端口\033[0m" +if [ "${HTTP_S}" == "https" ];then + echo -e "\033[33m因已开启面板自签证书,访问面板会提示不匹配证书,请参考以下链接配置证书\033[0m" + echo -e "\033[33mhttps://www.bt.cn/bbs/thread-105443-1-1.html\033[0m" +fi +echo -e "==================================================================" + +endTime=`date +%s` +((outTime=($endTime-$startTime)/60)) +echo -e "Time consumed:\033[32m $outTime \033[0mMinute!" + + + diff --git a/public/.user.ini b/public/.user.ini new file mode 100644 index 0000000..8240ec9 --- /dev/null +++ b/public/.user.ini @@ -0,0 +1 @@ +open_basedir=/home/xiao_lfeng/Project/PHP/XF_index/:/tmp/ \ No newline at end of file diff --git a/resources/js/jquery.min.js b/resources/js/jquery.min.js new file mode 100644 index 0000000..b633504 --- /dev/null +++ b/resources/js/jquery.min.js @@ -0,0 +1,8 @@ +/* + * Copyright © 2016 - 2023 筱锋xiao_lfeng. All Rights Reserved. + * 开发开源遵循 MIT 许可,若需商用请联系开发者 + * https://www.x-lf.com/ + */ + +/*! jQuery v3.6.3 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},S=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||S).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.3",E=function(e,t){return new E.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,S)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=E)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{if(d.cssSupportsSelector&&!CSS.supports("selector(:is("+c+"))"))throw new Error;return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===E&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[E]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,S=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.cssSupportsSelector=ce(function(){return CSS.supports("selector(*)")&&C.querySelectorAll(":is(:jqfake)")&&!CSS.supports("selector(:is(*,:jqfake))")}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=E,!C.getElementsByName||!C.getElementsByName(E).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&S){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&S)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+E+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+E+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),d.cssSupportsSelector||y.push(":has"),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType&&e.documentElement||e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&S&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?E.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?E.grep(e,function(e){return e===n!==r}):"string"!=typeof n?E.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(E.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof E?t[0]:t,E.merge(this,E.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:S,!0)),N.test(r[1])&&E.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=S.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(E):E.makeArray(e,this)}).prototype=E.fn,D=E(S);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}E.fn.extend({has:function(e){var t=E(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=S.createDocumentFragment().appendChild(S.createElement("div")),(fe=S.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?E.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&E(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),S.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;E.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||E.expando+"_"+Ct.guid++;return this[e]=!0,e}}),E.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||E.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?E(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=S.implementation.createHTMLDocument("").body).innerHTML="
",2===Ut.childNodes.length),E.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=S.implementation.createHTMLDocument("")).createElement("base")).href=S.location.href,t.head.appendChild(r)):t=S),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&E(o).remove(),E.merge([],i.childNodes)));var r,i,o},E.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(E.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},E.expr.pseudos.animated=function(t){return E.grep(E.timers,function(e){return t===e.elem}).length},E.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=E.css(e,"position"),c=E(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=E.css(e,"top"),u=E.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,E.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},E.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){E.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===E.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===E.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=E(e).offset()).top+=E.css(e,"borderTopWidth",!0),i.left+=E.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-E.css(r,"marginTop",!0),left:t.left-i.left-E.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===E.css(e,"position"))e=e.offsetParent;return e||re})}}),E.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;E.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),E.each(["top","left"],function(e,n){E.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?E(e).position()[n]+"px":t})}),E.each({Height:"height",Width:"width"},function(a,s){E.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){E.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?E.css(e,t,i):E.style(e,t,n,i)},s,n?e:void 0,n)}})}),E.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){E.fn[t]=function(e){return this.on(t,e)}}),E.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),E.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){E.fn[n]=function(e,t){return 0