From 62f67967ba5ea639880021cd8aa5befdff0c64f2 Mon Sep 17 00:00:00 2001 From: Roman Hergenreder Date: Sun, 9 Feb 2020 23:02:19 +0100 Subject: [PATCH] Initial Commit --- .htaccess | 8 + core/Api/ExecuteSelect.class.php | 111 + core/Api/ExecuteStatement.class.php | 97 + core/Api/Parameter/Parameter.class.php | 161 + core/Api/Parameter/StringType.class.php | 43 + core/Api/Request.class.php | 195 + core/Configuration/.gitignore | 4 + core/Configuration/.htaccess | 1 + core/Configuration/Configuration.class.php | 106 + core/Configuration/database.sql | 59 + core/Documents/Install.class.php | 721 +++ core/Driver/SQL.class.php | 124 + core/Elements/Body.class.php | 10 + core/Elements/Document.class.php | 80 + core/Elements/Head.class.php | 126 + core/Elements/Link.class.php | 42 + core/Elements/Script.class.php | 53 + core/Elements/Source.class.php | 22 + core/Elements/Style.class.php | 19 + core/External/PHPMailer/Exception.php | 39 + core/External/PHPMailer/OAuth.php | 138 + core/External/PHPMailer/PHPMailer.php | 4778 ++++++++++++++++ core/External/PHPMailer/POP3.php | 419 ++ core/External/PHPMailer/SMTP.php | 1370 +++++ core/External/jwt.php | 199 + core/External/phpQuery.php | 5702 ++++++++++++++++++++ core/Objects/ApiObject.class.php | 14 + core/Objects/ConnectionData.class.php | 46 + core/Objects/Language.class.php | 133 + core/Objects/Session.class.php | 105 + core/Objects/User.class.php | 189 + core/Objects/lang/General.php | 17 + core/Objects/lang/LanguageModule.php | 9 + core/View.class.php | 229 + core/constants.php | 6 + core/core.php | 137 + core/datetime.php | 121 + css/bootstrap.min.css | 7 + css/fontawesome.min.css | 5 + css/style.css | 226 + fonts/fa-brands-400.eot | Bin 0 -> 129734 bytes fonts/fa-brands-400.svg | 3451 ++++++++++++ fonts/fa-brands-400.ttf | Bin 0 -> 129428 bytes fonts/fa-brands-400.woff | Bin 0 -> 87644 bytes fonts/fa-brands-400.woff2 | Bin 0 -> 74680 bytes fonts/fa-regular-400.eot | Bin 0 -> 34394 bytes fonts/fa-regular-400.svg | 803 +++ fonts/fa-regular-400.ttf | Bin 0 -> 34096 bytes fonts/fa-regular-400.woff | Bin 0 -> 16804 bytes fonts/fa-regular-400.woff2 | Bin 0 -> 13596 bytes fonts/fa-solid-900.eot | Bin 0 -> 192122 bytes fonts/fa-solid-900.svg | 4649 ++++++++++++++++ fonts/fa-solid-900.ttf | Bin 0 -> 191836 bytes fonts/fa-solid-900.woff | Bin 0 -> 98020 bytes fonts/fa-solid-900.woff2 | Bin 0 -> 75356 bytes index.php | 62 + js/bootstrap.min.js | 7 + js/install.js | 127 + js/jquery.min.js | 2 + js/script.js | 395 ++ robots.txt | 2 + 61 files changed, 25369 insertions(+) create mode 100644 .htaccess create mode 100644 core/Api/ExecuteSelect.class.php create mode 100644 core/Api/ExecuteStatement.class.php create mode 100644 core/Api/Parameter/Parameter.class.php create mode 100644 core/Api/Parameter/StringType.class.php create mode 100644 core/Api/Request.class.php create mode 100644 core/Configuration/.gitignore create mode 100644 core/Configuration/.htaccess create mode 100644 core/Configuration/Configuration.class.php create mode 100644 core/Configuration/database.sql create mode 100644 core/Documents/Install.class.php create mode 100644 core/Driver/SQL.class.php create mode 100644 core/Elements/Body.class.php create mode 100644 core/Elements/Document.class.php create mode 100644 core/Elements/Head.class.php create mode 100644 core/Elements/Link.class.php create mode 100644 core/Elements/Script.class.php create mode 100644 core/Elements/Source.class.php create mode 100644 core/Elements/Style.class.php create mode 100644 core/External/PHPMailer/Exception.php create mode 100644 core/External/PHPMailer/OAuth.php create mode 100644 core/External/PHPMailer/PHPMailer.php create mode 100644 core/External/PHPMailer/POP3.php create mode 100644 core/External/PHPMailer/SMTP.php create mode 100644 core/External/jwt.php create mode 100644 core/External/phpQuery.php create mode 100644 core/Objects/ApiObject.class.php create mode 100644 core/Objects/ConnectionData.class.php create mode 100644 core/Objects/Language.class.php create mode 100644 core/Objects/Session.class.php create mode 100644 core/Objects/User.class.php create mode 100644 core/Objects/lang/General.php create mode 100644 core/Objects/lang/LanguageModule.php create mode 100644 core/View.class.php create mode 100644 core/constants.php create mode 100644 core/core.php create mode 100644 core/datetime.php create mode 100644 css/bootstrap.min.css create mode 100644 css/fontawesome.min.css create mode 100644 css/style.css create mode 100644 fonts/fa-brands-400.eot create mode 100644 fonts/fa-brands-400.svg create mode 100644 fonts/fa-brands-400.ttf create mode 100644 fonts/fa-brands-400.woff create mode 100644 fonts/fa-brands-400.woff2 create mode 100644 fonts/fa-regular-400.eot create mode 100644 fonts/fa-regular-400.svg create mode 100644 fonts/fa-regular-400.ttf create mode 100644 fonts/fa-regular-400.woff create mode 100644 fonts/fa-regular-400.woff2 create mode 100644 fonts/fa-solid-900.eot create mode 100644 fonts/fa-solid-900.svg create mode 100644 fonts/fa-solid-900.ttf create mode 100644 fonts/fa-solid-900.woff create mode 100644 fonts/fa-solid-900.woff2 create mode 100644 index.php create mode 100644 js/bootstrap.min.js create mode 100644 js/install.js create mode 100644 js/jquery.min.js create mode 100644 js/script.js create mode 100644 robots.txt diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..a7528a3 --- /dev/null +++ b/.htaccess @@ -0,0 +1,8 @@ +php_flag display_errors on +Options -Indexes + +ErrorDocument 404 /s/404 + +RewriteEngine on +RewriteRule ^s/(.*)?$ index.php?s=$1&$2 [L,QSA] + diff --git a/core/Api/ExecuteSelect.class.php b/core/Api/ExecuteSelect.class.php new file mode 100644 index 0000000..99d468b --- /dev/null +++ b/core/Api/ExecuteSelect.class.php @@ -0,0 +1,111 @@ + new StringType('query') + )); + + $this->isPublic = false; + $this->variableParamCount = true; + } + + public function getDescription() { return 'Führt ein SELECT Statement aus.'; } + public function getSection() { return "Internal"; } + + public function execute($aValues = array()) { + if(!parent::execute($aValues)) { + return false; + } + + $this->success = false; + $this->result['rows'] = array(); + + if(count($this->params) === 1) { + $res = $this->user->getSQL()->query($this->getParam('query')); + if(!$res) { + $this->lastError = 'Database Error: query() failed with ' . $this->user->getSQL()->getLastError(); + return false; + } + + while($row = $res->fetch_assoc()) { + array_push($this->result['rows'], $row); + } + + $this->success = true; + $res->close(); + } else { + $aSqlParams = array(''); + foreach($this->params as $param) { + if($param->name === 'query') continue; + + $value = $param->value; + switch($param->type) { + case Parameter::TYPE_BOOLEAN: + $value = $param->value ? 1 : 0; + case Parameter::TYPE_INT: + $aSqlParams[0] .= 'i'; + break; + case Parameter::TYPE_FLOAT: + $aSqlParams[0] .= 'd'; + break; + case Parameter::TYPE_DATE: + $value = $value->format('Y-m-d'); + $aSqlParams[0] .= 's'; + break; + case Parameter::TYPE_TIME: + $value = $value->format('H:i:s'); + $aSqlParams[0] .= 's'; + break; + case Parameter::TYPE_DATE_TIME: + $value = $value->format('Y-m-d H:i:s'); + $aSqlParams[0] .= 's'; + break; + case Parameter::TYPE_EMAIL: + default: + $aSqlParams[0] .= 's'; + } + + $aSqlParams[] = $value; + } + + $tmp = array(); + foreach($aSqlParams as $key => $value) $tmp[$key] = &$aSqlParams[$key]; + if($stmt = $this->user->getSQL()->connection->prepare($this->getParam('query'))) { + if(call_user_func_array(array($stmt, "bind_param"), $tmp)) + { + if($stmt->execute()) { + $res = $stmt->get_result(); + if($res) { + while($row = $res->fetch_assoc()) { + array_push($this->result['rows'], $row); + } + $res->close(); + $this->success = true; + } else { + $this->lastError = 'Database Error: execute() failed with ' . $this->user->getSQL()->getLastError(); + } + } else { + $this->lastError = 'Database Error: get_result() failed with ' . $this->user->getSQL()->getLastError(); + } + } else { + $this->lastError = 'Database Error: bind_param() failed with ' . $this->user->getSQL()->getLastError(); + } + + $stmt->close(); + } else { + $this->lastError = 'Database Error: prepare failed with() ' . $this->user->getSQL()->getLastError(); + } + } + + return $this->success; + } +}; + +?> diff --git a/core/Api/ExecuteStatement.class.php b/core/Api/ExecuteStatement.class.php new file mode 100644 index 0000000..309af75 --- /dev/null +++ b/core/Api/ExecuteStatement.class.php @@ -0,0 +1,97 @@ + new StringType('query') + )); + + $this->isPublic = false; + $this->variableParamCount = true; + } + + public function execute($aValues = array()) { + if(!parent::execute($aValues)) { + return false; + } + + $this->success = false; + $this->result['rows'] = array(); + + if(count($this->params) == 1) { + $this->success = $this->user->getSQL()->execute($this->getParam('query')); + if(!$this->success) { + $this->lastError = $this->user->getSQL()->getLastError(); + } + } else { + $aSqlParams = array(''); + foreach($this->params as $param) { + if($param->name === 'query') continue; + + $value = $param->value; + if(is_null($value)) { + $aSqlParams[0] .= 's'; + } else { + switch($param->type) { + case Parameter::TYPE_BOOLEAN: + $value = $param->value ? 1 : 0; + $aSqlParams[0] .= 'i'; + break; + case Parameter::TYPE_INT: + $aSqlParams[0] .= 'i'; + break; + case Parameter::TYPE_FLOAT: + $aSqlParams[0] .= 'd'; + break; + case Parameter::TYPE_DATE: + $value = $value->format('Y-m-d'); + $aSqlParams[0] .= 's'; + break; + case Parameter::TYPE_TIME: + $value = $value->format('H:i:s'); + $aSqlParams[0] .= 's'; + break; + case Parameter::TYPE_DATE_TIME: + $value = $value->format('Y-m-d H:i:s'); + $aSqlParams[0] .= 's'; + break; + case Parameter::TYPE_EMAIL: + default: + $aSqlParams[0] .= 's'; + } + } + + $aSqlParams[] = $value; + } + + $tmp = array(); + foreach($aSqlParams as $key => $value) $tmp[$key] = &$aSqlParams[$key]; + if($stmt = $this->user->getSQL()->connection->prepare($this->getParam('query'))) { + if(call_user_func_array(array($stmt, "bind_param"), $tmp)) { + if($stmt->execute()) { + $this->result['rows'] = $stmt->affected_rows; + $this->success = true; + } else { + $this->lastError = 'Database Error: execute() failed with ' . $this->user->getSQL()->getLastError(); + } + } else { + $this->lastError = 'Database Error: bind_param() failed with ' . $this->user->getSQL()->getLastError(); + } + + $stmt->close(); + } else { + $this->lastError = 'Database Error: prepare() failed with ' . $this->user->getSQL()->getLastError(); + } + } + + return $this->success; + } +}; + +?> diff --git a/core/Api/Parameter/Parameter.class.php b/core/Api/Parameter/Parameter.class.php new file mode 100644 index 0000000..7b70e90 --- /dev/null +++ b/core/Api/Parameter/Parameter.class.php @@ -0,0 +1,161 @@ +name = $name; + $this->optional = $optional; + $this->value = $defaultValue; + $this->type = $type; + $this->typeName = $this->getTypeName(); + } + + public function getTypeName() { + return ($this->type >= 0 && $this->type < count(Parameter::names)) ? Parameter::names[$this->type] : "INVALID"; + } + + public function toString() { + $typeName = Parameter::names[$this->type]; + + $str = "$typeName $this->name"; + $defaultValue = (is_null($this->value) ? 'NULL' : $this->value); + if($this->optional) { + $str = "[$str = $defaultValue]"; + } + + return $str; + } + + public static function parseType($value) { + if(is_array($value)) + return Parameter::TYPE_ARRAY; + else if(is_numeric($value) && intval($value) == $value) + return Parameter::TYPE_INT; + else if(is_float($value) || (is_numeric($value) && floatval($value) == $value)) + return Parameter::TYPE_FLOAT; + else if(is_bool($value) || $value == "true" || $value == "false") + return Parameter::TYPE_BOOLEAN; + else if(is_a($value, 'DateTime')) + return Parameter::TYPE_DATE_TIME; + else if(($d = \DateTime::createFromFormat('Y-m-d', $value)) && $d->format('Y-m-d') === $value) + return Parameter::TYPE_DATE; + else if(($d = \DateTime::createFromFormat('H:i:s', $value)) && $d->format('H:i:s') === $value) + return Parameter::TYPE_TIME; + else if(($d = \DateTime::createFromFormat('Y-m-d H:i:s', $value)) && $d->format('Y-m-d H:i:s') === $value) + return Parameter::TYPE_DATE_TIME; + else if (filter_var($value, FILTER_VALIDATE_EMAIL)) + return Parameter::TYPE_EMAIL; + else + return Parameter::TYPE_STRING; + } + + public function parseParam($value) { + switch($this->type) { + case Parameter::TYPE_INT: + if(is_numeric($value) && intval($value) == $value) { + $this->value = intval($value); + return true; + } + return false; + + case Parameter::TYPE_FLOAT: + if(is_numeric($value) && (floatval($value) == $value || intval($value) == $value)) { + $this->value = floatval($value); + return true; + } + return false; + + case Parameter::TYPE_BOOLEAN: + if(strcasecmp($value, 'true') === 0) + $this->value = true; + else if(strcasecmp($value, 'false') === 0) + $this->value = false; + else if(is_bool($value)) + $this->value = (bool)$value; + else + return false; + return true; + + case Parameter::TYPE_DATE: + if(is_a($value, "DateTime")) { + $this->value = $value; + return true; + } + + $d = DateTime::createFromFormat('Y-m-d', $value); + if($d && $d->format('Y-m-d') === $value) { + $this->value = $d; + return true; + } + return false; + + case Parameter::TYPE_TIME: + if(is_a($value, "DateTime")) { + $this->value = $value; + return true; + } + + $d = DateTime::createFromFormat('H:i:s', $value); + if($d && $d->format('H:i:s') === $value) { + $this->value = $d; + return true; + } + return false; + + case Parameter::TYPE_DATE_TIME: + if(is_a($value, 'DateTime')) { + $this->value = $value; + return true; + } else { + $d = DateTime::createFromFormat('Y-m-d H:i:s', $value); + if($d && $d->format('Y-m-d H:i:s') === $value) { + $this->value = $d; + return true; + } + } + return false; + + case Parameter::TYPE_EMAIL: + if (filter_var($value, FILTER_VALIDATE_EMAIL)) { + $this->value = $value; + return true; + } + return false; + + case Parameter::TYPE_ARRAY: + if(is_array($value)) { + $this->value = $value; + return true; + } + return false; + + default: + $this->value = $value; + return true; + } + } +} + +?> diff --git a/core/Api/Parameter/StringType.class.php b/core/Api/Parameter/StringType.class.php new file mode 100644 index 0000000..2d92808 --- /dev/null +++ b/core/Api/Parameter/StringType.class.php @@ -0,0 +1,43 @@ +maxLength = $maxLength; + } + + public function parseParam($value) { + if(!is_string($value)) { + return false; + } + + if($this->maxLength > 0 && strlen($value) > $this->maxLength) { + return false; + } + + $this->value = $value; + return true; + } + + public function getTypeName() { + $maxLength = ($this->maxLength > 0 ? "($this->maxLength)" : ""); + return parent::getTypeName() . $maxLength; + } + + public function toString() { + $typeName = $this->getTypeName(); + $str = "$typeName $this->name"; + $defaultValue = (is_null($this->value) ? 'NULL' : $this->value); + if($this->optional) { + $str = "[$str = $defaultValue]"; + } + + return $str; + } +} + +?> diff --git a/core/Api/Request.class.php b/core/Api/Request.class.php new file mode 100644 index 0000000..dd54166 --- /dev/null +++ b/core/Api/Request.class.php @@ -0,0 +1,195 @@ +user = $user; + $this->aDefaultParams = $params; + $this->lastError = ''; + $this->success = false; + $this->result = array(); + $this->externCall = $externCall; + $this->isPublic = true; + $this->isDisabled = false; + $this->loginRequired = false; + $this->variableParamCount = false; + $this->apiKeyAllowed = true; + $this->allowedMethods = array("GET", "POST"); + } + + protected function forbidMethod($method) { + if (($key = array_search($method, $this->allowedMethods)) !== false) { + unset($this->allowedMethods[$key]); + } + } + + public function getParamsString() { + $str = ""; + $count = count($this->params); + $i = 0; + foreach($this->params as $param) { + $str .= $param->toString(); + if($i < $count - 1) $str .= ", "; + $i++; + } + + return "($str)"; + } + + public function parseParams($aValues) { + foreach($this->params as $name => $param) { + $value = (isset($aValues[$name]) ? $aValues[$name] : NULL); + + if(!$param->optional && is_null($value)) { + $this->lastError = 'Missing parameter: ' . $name; + return false; + } + + if(!is_null($value)) { + if(!$param->parseParam($value)) { + $value = print_r($value, true); + $this->lastError = "Invalid Type for parameter: $name '$value' (Required: " . $param->getTypeName() . ")"; + return false; + } + } + } + return true; + } + + public function parseVariableParams($aValues) { + foreach($aValues as $name => $value) { + if(isset($this->params[$name])) continue; + $type = Parameter\Parameter::parseType($value); + $param = new Parameter\Parameter($name, $type, true); + $param->parseParam($value); + $this->params[$name] = $param; + } + } + + public function execute($aValues = array()) { + $this->params = $this->aDefaultParams; + $this->success = false; + $this->result = array(); + $this->lastError = ''; + + if($this->user->isLoggedIn()) { + $this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds(); + } + + if($this->externCall) { + $aValues = $_REQUEST; + if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER["CONTENT_TYPE"]) && in_array("application/json", explode(";", $_SERVER["CONTENT_TYPE"]))) { + $jsonData = json_decode(file_get_contents('php://input'), true); + $aValues = array_merge($aValues, $jsonData); + } + } + + if($this->isDisabled) { + $this->lastError = "This function is currently disabled."; + return false; + } + + if($this->externCall && !$this->isPublic) { + $this->lastError = 'This function is private.'; + header('HTTP 1.1 403 Forbidden'); + return false; + } + + if(!in_array($_SERVER['REQUEST_METHOD'], $this->allowedMethods)) { + $this->lastError = 'This method is not allowed'; + header('HTTP 1.1 405 Method Not Allowed'); + return false; + } + + + if($this->loginRequired) { + $authorized = false; + if(isset($aValues['api_key']) && $this->apiKeyAllowed) { + $apiKey = $aValues['api_key']; + $authorized = $this->user->authorize($apiKey); + } + + if(!$this->user->isLoggedIn() && !$authorized) { + $this->lastError = 'You are not logged in.'; + header('HTTP 1.1 401 Unauthorized'); + return false; + } + } + + if(!$this->parseParams($aValues)) + return false; + + if($this->variableParamCount) + $this->parseVariableParams($aValues); + + if(!$this->user->getSQL()->isConnected()) { + $this->lastError = $this->user->getSQL()->getLastError(); + return false; + } + + $this->user->getSQL()->setLastError(''); + $this->success = true; + return true; + } + + protected function isValidString($str, $regex) { + return preg_replace($regex, "", $str) === $str; + } + + protected function createError($err) { + $this->success = false; + $this->lastError = $err; + return false; + } + // + // public static function callDirectly($class, $db) { + // header('Content-Type: application/json'); + // require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/api/objects/User.php'; + // require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/sql.php'; + // require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/conf/sql.php'; + // + // $sql = connectSQL(getSqlData($db)); + // $user = new CUser($sql); + // $request = new $class($user, true); + // $request->execute(); + // $sql->close(); + // $user->sendCookies(); + // return $request->getJsonResult(); + // } + + protected function getParam($name) { return isset($this->params[$name]) ? $this->params[$name]->value : NULL; } + public function isPublic() { return $this->isPublic; } + public function getDescription() { return ''; } + public function getSection() { return 'Default'; } + public function getLastError() { return $this->lastError; } + public function getResult() { return $this->result; } + public function success() { return $this->success; } + public function loginRequired() { return $this->loginRequired; } + public function isExternCall() { return $this->externCall; } + + public function getJsonResult() { + $this->result['success'] = $this->success; + $this->result['msg'] = $this->lastError; + return json_encode($this->result); + } +}; + + +?> diff --git a/core/Configuration/.gitignore b/core/Configuration/.gitignore new file mode 100644 index 0000000..387c25f --- /dev/null +++ b/core/Configuration/.gitignore @@ -0,0 +1,4 @@ +Mail\.class\.php +JWT\.class\.php +Database\.class\.php +Google\.class\.php diff --git a/core/Configuration/.htaccess b/core/Configuration/.htaccess new file mode 100644 index 0000000..d3223d4 --- /dev/null +++ b/core/Configuration/.htaccess @@ -0,0 +1 @@ +DENY FROM ALL diff --git a/core/Configuration/Configuration.class.php b/core/Configuration/Configuration.class.php new file mode 100644 index 0000000..88c836f --- /dev/null +++ b/core/Configuration/Configuration.class.php @@ -0,0 +1,106 @@ + &$this->database, + \Configuration\Mail::class => &$this->mail, + \Configuration\JWT::class => &$this->jwt, + \Configuration\Google::class => &$this->google, + ); + + $success = true; + foreach($classes as $class => &$ref) { + $path = getClassPath($class); + if(!file_exists($path)) { + $success = false; + } else { + include_once $path; + if(class_exists($class)) { + $ref = new $class(); + } + } + } + + return $success; + } catch(\Error $e) { + die($e); + } + } + + public function getDatabase() { return $this->database; } + public function getJWT() { return $this->jwt; } + public function getMail() { return $this->mail; } + + public function isFilePresent($className) { + $path = getClassPath("\\Configuration\\$className"); + return file_exists($path); + } + + public function create($className, $data) { + $path = getClassPath("\\Configuration\\$className"); + + if($data) { + + // TODO: Generalize this... + $superClass = get_class($data); + $host = addslashes($data->getHost()); + $port = intval($data->getPort()); + $login = addslashes($data->getLogin()); + $password = addslashes($data->getPassword()); + + $properties = ""; + foreach($data->getProperties() as $key => $val) { + $key = addslashes($key); + $val = is_string($val) ? "'" . addslashes($val) . "'" : $val; + $properties .= "\n\$this->setProperty('$key', $val);"; + } + + $code = intendCode( + "", false + ); + } else { + $code = intendCode( + "", false); + } + + return file_put_contents($path, $code); + } + + public function delete($className) { + $path = getClassPath("\\Configuration\\$className"); + if(file_exists($path)) { + return unlink($path); + } + + return true; + } +}; + +?> diff --git a/core/Configuration/database.sql b/core/Configuration/database.sql new file mode 100644 index 0000000..7833a24 --- /dev/null +++ b/core/Configuration/database.sql @@ -0,0 +1,59 @@ +-- +-- API +-- +CREATE TABLE IF NOT EXISTS User ( + `uid` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, + `email` VARCHAR(256) UNIQUE DEFAULT NULL, + `name` VARCHAR(32) UNIQUE NOT NULL, + `salt` varchar(16) NOT NULL, + `password` varchar(64) NOT NULL, + `uidLanguage` int(11) DEFAULT 1 +); + +CREATE TABLE IF NOT EXISTS UserInvitation ( + `email` VARCHAR(256) NOT NULL, + `token` VARCHAR(36) UNIQUE NOT NULL, + `valid_until` DATETIME NOT NULL +); + +CREATE TABLE IF NOT EXISTS `Group` ( + `gid` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, + `name` VARCHAR(32) NOT NULL +); + +INSERT INTO `Group` (gid, name) VALUES (1, "Default"), (2, "Administrator") + ON DUPLICATE KEY UPDATE name=name; + +CREATE TABLE IF NOT EXISTS UserGroup ( + `uid` INTEGER NOT NULL, + `gid` INTEGER NOT NULL, + UNIQUE(`uid`, `gid`) +); + +CREATE TABLE Session IF NOT EXISTS ( + `uid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, + `expires` timestamp NOT NULL, + `uidUser` int(11) NOT NULL, + `ipAddress` varchar(45) NOT NULL, + `os` varchar(64) NOT NULL, + `browser` varchar(64) NOT NULL +); + +CREATE TABLE IF NOT EXISTS ApiKey ( + `uid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, + `uidUser` int(11) NOT NULL, + `api_key` VARCHAR(64) NOT NULL, + `valid_until` DATETIME NOT NULL +); + +CREATE TABLE IF NOT EXISTS Language ( + `uid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT, + `code` VARCHAR(5) UNIQUE NOT NULL, + `name` VARCHAR(32) UNIQUE NOT NULL +); + +CREATE TABLE IF NOT EXISTS ExternalSiteCache ( + `url` VARCHAR(256) PRIMARY KEY, + `data` TEXT NOT NULL, + `expires` TIMESTAMP DEFAULT NULL +); diff --git a/core/Documents/Install.class.php b/core/Documents/Install.class.php new file mode 100644 index 0000000..4903b1d --- /dev/null +++ b/core/Documents/Install.class.php @@ -0,0 +1,721 @@ +databseRequired = false; + } + } +} + +namespace Documents\Install { + + class Head extends \Elements\Head { + + public function __construct($document) { + parent::__construct($document); + } + + protected function initSources() { + $this->loadJQuery(); + $this->loadBootstrap(); + $this->loadFontawesome(); + $this->addJS(\Elements\Script::CORE); + $this->addCSS(\Elements\Link::CORE); + $this->addJS(\Elements\Script::INSTALL); + } + + protected function initMetas() { + return array( + array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'), + array('name' => 'format-detection', 'content' => 'telephone=yes'), + array('charset' => 'utf-8'), + array("http-equiv" => 'expires', 'content' => '0'), + array("name" => 'robots', 'content' => 'noarchive'), + ); + } + + protected function initRawFields() { + return array(); + } + + protected function initTitle() { + return "WebBase - Installation"; + } + + } + + class Body extends \Elements\Body { + + // Status enum + const NOT_STARTED = 0; + const PENDING = 1; + const SUCCESFULL = 2; + const ERROR = 3; + + // Step enum + const CHECKING_REQUIRMENTS = 1; + const DATABASE_CONFIGURATION = 2; + const CREATE_USER = 3; + const ADD_MAIL_SERVICE = 4; + const ADD_GOOGLE_SERVICE = 5; + + // + private $configDirectory; + private $databaseScript; + + function __construct($document) { + parent::__construct($document); + + // TODO: make better + $this->configDirectory = getWebRoot() . '/core/Configuration'; + $this->databaseScript = getWebRoot() . '/core/Configuration/database.sql'; + } + + private function getParameter($name) { + if(isset($_REQUEST[$name]) && is_string($_REQUEST[$name])) { + return trim($_REQUEST[$name]); + } + + return NULL; + } + + private function getCurrentStep() { + + if(!$this->checkRequirements()) { + return self::CHECKING_REQUIRMENTS; + } + + $user = $this->getDocument()->getUser(); + $config = $user->getConfiguration(); + + // Check if database configuration exists + if(!$config->getDatabase()) { + return self::DATABASE_CONFIGURATION; + } + + $query = "SELECT * FROM User"; + $sql = $user->getSQL(); + if(!is_null($sql) && $sql->isConnected()) { + $this->getDocument()->getUser()->setSql($sql); + $res = $sql->query($query); + if($res) { + if($res->num_rows === 0) { + $step = self::CREATE_USER; + } else { + $step = self::ADD_MAIL_SERVICE; + } + } + } else { + $step = self::DATABASE_CONFIGURATION; + } + + if($step == self::ADD_MAIL_SERVICE && $config->isFilePresent("Mail")) { + $step = self::ADD_GOOGLE_SERVICE; + } + + return $step; + } + + private function checkRequirements() { + + $msg = ""; + $success = true; + $failedRequirements = array(); + + if(!is_writeable($this->configDirectory)) { + $failedRequirements[] = "$this->configDirectory is not writeable. Try running chmod 600"; + $success = false; + } + + if(!is_readable($this->databaseScript)) { + $failedRequirements[] = "$this->databaseScript is not readable."; + $success = false; + } + + if(version_compare(PHP_VERSION, '7.1', '<')) { + $failedRequirements[] = "PHP Version >= 7.1 is required. Got: " . PHP_VERSION . ""; + $success = false; + } + + if(!function_exists('mysqli_connect')) { + $link = $this->createExternalLink("https://secure.php.net/manual/en/mysqli.setup.php"); + $failedRequirements[] = "mysqli is not enabled yet. See: $link"; + $success = false; + } + + if(!$success) { + $msg = "The following requirements failed the check:
" . + $this->createUnorderedList($failedRequirements); + } + + return array("success" => $success, "msg" => $msg); + } + + private function databaseConfiguration() { + + $host = $this->getParameter("host"); + $port = $this->getParameter("port"); + $username = $this->getParameter("username"); + $password = $this->getParameter("password"); + $database = $this->getParameter("database"); + $success = true; + + $missingInputs = array(); + if(is_null($host) || empty($host)) { + $success = false; + $missingInputs[] = "Host"; + } + + if(is_null($port) || empty($port)) { + $success = false; + $missingInputs[] = "Port"; + } + + if(is_null($username) || empty($username)) { + $success = false; + $missingInputs[] = "Username"; + } + + if(is_null($password)) { + $success = false; + $missingInputs[] = "Password"; + } + + if(is_null($database) || empty($database)) { + $success = false; + $missingInputs[] = "Database"; + } + + if(!$success) { + $msg = "Please fill out the following inputs:
" . + $this->createUnorderedList($missingInputs); + } else if(!is_numeric($port) || ($port = intval($port)) < 1 || $port > 65535) { + $msg = "Port must be in range of 1-65535."; + $success = false; + } else { + $connectionData = new \Objects\ConnectionData($host, $port, $username, $password); + $connectionData->setProperty('database', $database); + $connectionData->setProperty('encoding', 'utf8'); + $sql = new \Driver\SQL($connectionData); + $success = $sql->connect(); + + if(!$success) { + $msg = "Error connecting to database:
" . $sql->getLastError(); + } else { + try { + $msg = "Error loading database script $this->databaseScript"; + $commands = file_get_contents($this->databaseScript); + $success = $sql->executeMulti($commands); + if(!$success) { + $msg = $sql->getLastError(); + } else if(!$this->getDocument()->getUser()->getConfiguration()->create("Database", $connectionData)) { + $success = false; + $msg = "Unable to write file"; + } else { + $msg = ""; + } + } catch(Exception $e) { + $success = false; + $msg .= ": " . $e->getMessage(); + } + + if($sql) { + $sql->close(); + } + } + } + + return array("success" => $success, "msg" => $msg); + } + + private function createUser() { + + $user = $this->getDocument()->getUser(); + if($this->getParameter("prev") === "true") { + $success = $user->getConfiguration()->delete("Database"); + $msg = $success ? "" : error_get_last(); + return array("success" => $success, "msg" => $msg); + } + + $username = $this->getParameter("username"); + $password = $this->getParameter("password"); + $confirmPassword = $this->getParameter("confirmPassword"); + + $msg = ""; + $success = true; + $missingInputs = array(); + + if(is_null($username) || empty($username)) { + $success = false; + $missingInputs[] = "Username"; + } + + if(is_null($password) || empty($password)) { + $success = false; + $missingInputs[] = "Password"; + } + + if(is_null($confirmPassword) || empty($confirmPassword)) { + $success = false; + $missingInputs[] = "Confirm Password"; + } + + if(!$success) { + $msg = "Please fill out the following inputs:
" . + $this->createUnorderedList($missingInputs); + } else if(strlen($username) < 5 || strlen($username) > 32) { + $msg = "The username should be between 5 and 32 characters long"; + $success = false; + } else if(strcmp($password, $confirmPassword) !== 0) { + $msg = "The given passwords do not match"; + $success = false; + } else if(strlen($password) < 6) { + $msg = "The password should be at least 6 characters long"; + $success = false; + } else { + $salt = generateRandomString(16); + $hash = hash('sha256', $password . $salt); + $query = "INSERT INTO User (name, salt, password) VALUES (?,?,?)"; + $req = new \Api\ExecuteStatement($user); + $success = $req->execute(array("query" => $query, $username, $salt, $hash)); + $nsg = $req->getLastError(); + } + + return array("msg" => $msg, "success" => $success); + } + + private function addMailService() { + + $user = $this->getDocument()->getUser(); + if($this->getParameter("prev") === "true") { + $req = new \Api\ExecuteStatement($user); + $success = $req->execute(array("query" => "TRUNCATE User")); + $msg = $req->getLastError(); + return array("success" => $success, "msg" => $msg); + } + + $success = true; + $msg = ""; + if($this->getParameter("skip") === "true") { + if(!$user->getConfiguration()->create("Mail", null)) { + $success = false; + $msg = "Unable to create file"; + } + } else { + + $address = $this->getParameter("address"); + $port = $this->getParameter("port"); + $username = $this->getParameter("username"); + $password = $this->getParameter("password"); + $success = true; + + $missingInputs = array(); + if(is_null($address) || empty($address)) { + $success = false; + $missingInputs[] = "SMTP Address"; + } + + if(is_null($port) || empty($port)) { + $success = false; + $missingInputs[] = "Port"; + } + + if(is_null($username) || empty($username)) { + $success = false; + $missingInputs[] = "Username"; + } + + if(is_null($password)) { + $success = false; + $missingInputs[] = "Password"; + } + + if(!$success) { + $msg = "Please fill out the following inputs:
" . + $this->createUnorderedList($missingInputs); + } else if(!is_numeric($port) || ($port = intval($port)) < 1 || $port > 65535) { + $msg = "Port must be in range of 1-65535."; + $success = false; + } else { + $success = false; + + $mail = new \External\PHPMailer\PHPMailer(true); + $mail->IsSMTP(); + $mail->SMTPAuth = true; + $mail->Username = $username; + $mail->Password = $password; + $mail->Host = $address; + $mail->Port = $port; + $mail->SMTPSecure = 'tls'; + $mail->Timeout = 10; + + try { + $success = $mail->SmtpConnect(); + if(!$success) { + $error = empty($mail->ErrorInfo) ? "Unknown Error" : $mail->ErrorInfo; + $msg = "Could not connect to SMTP Server: $error"; + } else { + $success = true; + $msg = ""; + $mail->smtpClose(); + } + } catch(\External\PHPMailer\Exception $error) { + $msg = "Could not connect to SMTP Server: " . $error->errorMessage(); + } + + if($success) { + $connectionData = new \Objects\ConnectionData($address, $port, $username, $password); + if(!$user->getConfiguration()->create("Mail", $connectionData)) { + $success = false; + $msg = "Unable to create file"; + } + } + } + } + + return array("success" => $success, "msg" => $msg); + } + + private function addGoogleService() { + // return array("success" => $success, "msg" => $msg); + } + + private function performStep() { + + switch($this->currentStep) { + + case self::CHECKING_REQUIRMENTS: + return $this->checkRequirements(); + + case self::DATABASE_CONFIGURATION: + return $this->databaseConfiguration(); + + case self::CREATE_USER: + return $this->createUser(); + + case self::ADD_MAIL_SERVICE: + return $this->addMailService(); + + case self::ADD_GOOGLE_SERVICE: + return $this->addGoogleService(); + + default: + return array( + "success" => false, + "msg" => "Invalid step number" + ); + } + } + + private function createProgressSidebar() { + $items = array(); + foreach($this->steps as $num => $step) { + + $title = $step["title"]; + $status = $step["status"]; + $currentStep = ($num == $this->currentStep) ? " id=\"currentStep\"" : ""; + + switch($status) { + case self::PENDING: + $statusIcon = ''; + $statusText = "Loading…"; + $statusColor = "muted"; + break; + + case self::SUCCESFULL: + $statusIcon = ''; + $statusText = "Successfull"; + $statusColor = "success"; + break; + + case self::ERROR: + $statusIcon = ''; + $statusText = "Failed"; + $statusColor = "danger"; + break; + + case self::NOT_STARTED: + default: + $statusIcon = ''; + $statusText = "Pending"; + $statusColor = "muted"; + break; + } + + $items[] = " +
  • +
    +
    $title
    + $statusText +
    + $statusIcon +
  • "; + } + + return implode("", $items); + } + + private function createFormItem($formItem, $inline=false) { + + $title = $formItem["title"]; + $name = $formItem["name"]; + $type = $formItem["type"]; + + $attributes = array( + "name" => $name, + "id" => $name, + "class" => "form-control", + "type" => $type, + ); + + if(isset($formItem["required"]) && $formItem["required"]) { + $attributes["required"] = ""; + } + + if(isset($formItem["value"]) && $formItem["value"]) { + $attributes["value"] = $formItem["value"]; + } + + if($type === "number") { + if(isset($formItem["min"]) && is_numeric($formItem["min"])) + $attributes["min"] = $formItem["min"]; + if(isset($formItem["max"]) && is_numeric($formItem["max"])) + $attributes["max"] = $formItem["max"]; + if(isset($formItem["step"]) && is_numeric($formItem["step"])) + $attributes["step"] = $formItem["step"]; + } + + $attributes = str_replace("+", " ", str_replace("&", "\" ", str_replace("=", "=\"", http_build_query($attributes)))) . "\""; + + if(!$inline) { + return + "
    + + +
    "; + } else { + return + "
    + + +
    "; + } + } + + private function createProgessMainview() { + + $views = array( + self::CHECKING_REQUIRMENTS => array( + "title" => "Application Requirements", + "progressText" => "Checking requirements, please wait a moment…" + ), + self::DATABASE_CONFIGURATION => array( + "title" => "Database configuration", + "form" => array( + array("title" => "Username", "name" => "username", "type" => "text", "required" => true), + array("title" => "Password", "name" => "password", "type" => "password"), + array("title" => "Database", "name" => "database", "type" => "text", "required" => true), + array("type" => "row", "items" => array( + array( + "title" => "Address", "name" => "host", "type" => "text", "required" => true, + "value" => "localhost", "row" => true + ), + array( + "title" => "Port", "name" => "port", "type" => "number", "required" => true, + "value" => "3306", "min" => "1", "max" => "65535", "row" => true + ) + )), + ) + ), + self::CREATE_USER => array( + "title" => "Create a User", + "form" => array( + array("title" => "Username", "name" => "username", "type" => "text", "required" => true), + array("title" => "Password", "name" => "password", "type" => "password", "required" => true), + array("title" => "Confirm Password", "name" => "confirmPassword", "type" => "password", "required" => true), + ) + ), + self::ADD_MAIL_SERVICE => array( + "title" => "Optional: Add Mail Service", + "form" => array( + array("title" => "Username", "name" => "username", "type" => "text", "required" => true), + array("title" => "Password", "name" => "password", "type" => "password"), + array("type" => "row", "items" => array( + array( + "title" => "SMTP Address", "name" => "address", "type" => "text", "required" => true, + "value" => "localhost", "row" => true + ), + array( + "title" => "Port", "name" => "port", "type" => "number", "required" => true, + "value" => "587", "min" => "1", "max" => "65535", "row" => true + ) + )), + ), + "skip" => true + ), + self::ADD_GOOGLE_SERVICE => array( + "title" => "Optional: Add Google Services", + ) + ); + + if(!isset($views[$this->currentStep])) { + return ""; + } + + $prevDisabled = ($this->currentStep <= self::DATABASE_CONFIGURATION); + $currentView = $views[$this->currentStep]; + $spinnerIcon = $this->createIcon("spinner"); + $title = $currentView["title"]; + + $html = "

    $title


    "; + + if(isset($currentView["progressText"])) { + $progressText = $currentView["progressText"]; + $html .= "
    $progressText$spinnerIcon
    "; + } + + if(isset($currentView["form"])) { + $html .= "
    "; + + foreach($currentView["form"] as $formItem) { + + if($formItem["type"] === "row") { + $html .= "
    "; + foreach($formItem["items"] as $item) { + $html .= $this->createFormItem($item, true); + } + $html .= "
    "; + } else { + $html .= $this->createFormItem($formItem); + } + } + + $html .= " +
    "; + } + + $buttons = array( + array("title" => "Go Back", "type" => "info", "id" => "btnPrev", "float" => "left", "disabled" => $prevDisabled), + array("title" => "Submit", "type" => "success", "id" => "btnSubmit", "float" => "right") + ); + + if(isset($currentView["skip"])) { + $buttons[] = array("title" => "Skip", "type" => "secondary", "id" => "btnSkip", "float" => "right"); + } + + $buttonsLeft = ""; + $buttonsRight = ""; + + foreach($buttons as $button) { + $title = $button["title"]; + $type = $button["type"]; + $id = $button["id"]; + $float = $button["float"]; + $disabled = (isset($button["disabled"]) && $button["disabled"]) ? " disabled" : ""; + $button = ""; + + if($float === "left") { + $buttonsLeft .= $button; + } else { + $buttonsRight .= $button; + } + } + + $html .= + "
    +
    $buttonsLeft
    +
    $buttonsRight
    +
    "; + + return $html; + } + + + function getCode() { + $html = parent::getCode(); + + $this->steps = array( + self::CHECKING_REQUIRMENTS => array( + "title" => "Checking requirements", + "status" => self::NOT_STARTED + ), + self::DATABASE_CONFIGURATION => array( + "title" => "Database configuration", + "status" => self::NOT_STARTED + ), + self::CREATE_USER => array( + "title" => "Create User", + "status" => self::NOT_STARTED + ), + self::ADD_MAIL_SERVICE => array( + "title" => "Add Mail Service", + "status" => self::NOT_STARTED + ), + self::ADD_GOOGLE_SERVICE => array( + "title" => "Add Google Services", + "status" => self::NOT_STARTED + ), + ); + + $this->currentStep = $this->getCurrentStep(); + + // set status + for($step = self::CHECKING_REQUIRMENTS; $step < $this->currentStep; $step++) { + $this->steps[$step]["status"] = self::SUCCESFULL; + } + + // POST + if($_SERVER['REQUEST_METHOD'] == 'POST') { + $response = $this->performStep(); + die(json_encode($response)); + } + + if($this->currentStep == self::CHECKING_REQUIRMENTS) { + $this->getDocument()->getHead()->addJSCode(" + $(document).ready(function() { + retry(); + }); + "); + } + + $progressSidebar = $this->createProgressSidebar(); + $progressMainview = $this->createProgessMainview(); + + $html .= " + +
    +
    +

    WebBase - Installation

    +

    + Process the following steps and fill out the required forms to install your WebBase-Installation. +

    +
    + +
    +
    +

    + Progress +

    + +
      + $progressSidebar +
    +
    +
    + $progressMainview +
    +
    +
    +
    + "; + + return $html; + } + + } + +} + +?> diff --git a/core/Driver/SQL.class.php b/core/Driver/SQL.class.php new file mode 100644 index 0000000..d5c3e89 --- /dev/null +++ b/core/Driver/SQL.class.php @@ -0,0 +1,124 @@ +connection = NULL; + $this->lastError = 'Not connected'; + $this->connectionData = $connectionData; + } + + public function connect() { + if(!is_null($this->connection)) + return true; + + @$this->connection = mysqli_connect( + $this->connectionData->getHost(), + $this->connectionData->getLogin(), + $this->connectionData->getPassword(), + $this->connectionData->getProperty('database'), + $this->connectionData->getPort() + ); + + if (mysqli_connect_errno($this->connection)) { + $this->lastError = "Failed to connect to MySQL: " . mysqli_connect_error(); + $this->connection = NULL; + return false; + } + + mysqli_set_charset($this->connection, $this->connectionData->getProperty('encoding')); + return true; + } + + public function disconnect() { + if(is_null($this->connection)) + return; + + mysqli_close($this->connection); + $this->connection = NULL; + } + + public function isConnected() { + return !is_null($this->connection); + } + + public function getLastError() { + return empty(trim($this->lastError)) ? mysqli_error($this->connection) . " " . $this->getLastErrorNumber() : trim($this->lastError); + } + + public function setLastError($str) { + $this->lastError = $str; + } + + public function getLastErrorNumber() { + return mysqli_errno($this->connection); + } + + public function getLastInsertId() { + return $this->connection->insert_id; + } + + public function close() { + if(!is_null($this->connection)) { + $this->connection->close(); + } + } + + public function getAffectedRows() { + return $this->connection->affected_rows; + } + + public function execute($query) { + if(!$this->isConnected()) { + return false; + } + + if(!mysqli_query($this->connection, $query)) { + $this->lastError = mysqli_error($this->connection); + return false; + } + + return true; + } + + public function executeMulti($queries) { + if(!$this->isConnected()) { + return false; + } + + if(!$this->connection->multi_query($queries)) { + $this->lastError = mysqli_error($this->connection); + return false; + } + + return true; + } + + public function query($query) { + if(!$this->isConnected()) { + return false; + } + + $res = mysqli_query($this->connection, $query); + if(!$res) { + $this->lastError = mysqli_error($this->connection); + return false; + } + + return $res; + } + + public static function createConnection($connectionData) { + $sql = new SQL($connectionData); + $sql->connect(); + return $sql; + } +} + +?> diff --git a/core/Elements/Body.class.php b/core/Elements/Body.class.php new file mode 100644 index 0000000..b016dbf --- /dev/null +++ b/core/Elements/Body.class.php @@ -0,0 +1,10 @@ + diff --git a/core/Elements/Document.class.php b/core/Elements/Document.class.php new file mode 100644 index 0000000..6199428 --- /dev/null +++ b/core/Elements/Document.class.php @@ -0,0 +1,80 @@ +head = new $headClass($this); + $this->body = new $bodyClass($this); + $this->user = $user; + $this->databseRequired = true; + } + + public function getHead() { return $this->head; } + public function getBody() { return $this->body; } + public function getSQL() { return $this->user->getSQL(); } + public function getUser() { return $this->user; } + + protected function sendHeaders() { + header("X-Frame-Options: DENY"); + } + + public static function createSearchableDocument($documentClass, $user) { + return new $documentClass($user); + } + + public static function createDocument($class) { + // TODO: check instance, configuration, .. + + require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/sql.php'; + // require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/conf/config.php'; + // require_once realpath($_SERVER['DOCUMENT_ROOT']) . "/php/pages/$file.php"; + require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/api/objects/User.php'; + + $connectionData = getSqlData($database); + $sql = connectSQL($connectionData); + if(!$sql->isConnected()) { + http_response_code(500); + die('Internal Database error'); + } + + $user = new CUser($sql); + $document = new $class($user); + $code = $document->getCode(); + + $document->sendHeaders(); + $user->sendCookies(); + die($code); + } + + function getCode() { + + if ($this->databseRequired) { + $sql = $this->user->getSQL(); + if (is_null($sql)) { + die("Database is not configured yet."); + } else { + die("Database is not connected: " . $sql->getLastError()); + } + } + + $body = $this->body->getCode(); + $head = $this->head->getCode(); + + $html = ""; + $html .= ""; + $html .= $head; + $html .= $body; + $html .= ""; + return $html; + } + +}; + +?> diff --git a/core/Elements/Head.class.php b/core/Elements/Head.class.php new file mode 100644 index 0000000..3eab8d8 --- /dev/null +++ b/core/Elements/Head.class.php @@ -0,0 +1,126 @@ +sources = array(); + $this->metas = $this->initMetas(); + $this->rawFields = $this->initRawFields(); + $this->title = $this->initTitle(); + $this->initSources(); + $this->init(); + } + + protected abstract function initSources(); + protected abstract function initMetas(); + protected abstract function initRawFields(); + protected abstract function initTitle(); + + protected function init() { + $this->keywords = array(); + $this->description = ""; + $this->baseUrl = ""; + } + + public function setBaseUrl($baseUrl) { $this->baseUrl = $baseUrl; } + public function setDescription($description) { $this->description = $description; } + public function setKeywords($keywords) { $this->keywords = $keywords; } + public function setTitle($title) { $this->title = $title; } + public function getSources() { return $this->sources; } + public function addScript($type, $url, $js = '') { $this->sources[] = new Script($type, $url, $js); } + public function addRawField($rawField) { $this->rawFields[] = $rawField; } + public function addMeta($aMeta) { $this->metas[] = $aMeta; } + public function addLink($rel, $href, $type = "") { $this->sources[] = new Link($rel, $href, $type); } + public function addKeywords($keywords) { array_merge($this->keywords, $keywords); } + public function getTitle() { return $this->title; } + + public function addCSS($href, $type = Link::MIME_TEXT_CSS) { $this->sources[] = new Link("stylesheet", $href, $type); } + public function addStyle($style) { $this->sources[] = new Style($style); } + public function addJS($url) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, $url, ""); } + public function addJSCode($code) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, "", $code); } + + public function loadFontawesome() { + $this->addCSS(Link::FONTAWESOME); + } + + public function loadSyntaxHighlighting() { + $this->addJS(Script::HIGHLIGHT); + $this->addJSCode(Script::HIGHLIGHT_JS_LOADER); + $this->addCSS(Link::HIGHLIGHT); + $this->addCSS(Link::HIGHLIGHT_THEME); + } + + public function loadJQueryTerminal($unixFormatting = true) { + $this->addJS(Script::JQUERY_TERMINAL); + if($unixFormatting) $this->addJS(Script::JQUERY_TERMINAL_UNIX); + $this->addCSS(Link::JQUERY_TERMINAL); + } + + public function loadGoogleRecaptcha($siteKey) { + $this->addJS("https://www.google.com/recaptcha/api.js?render=$siteKey"); + } + + public function loadJQuery() { + $this->addJS(Script::JQUERY); + } + + public function loadBootstrap() { + $this->addCSS(Link::BOOTSTRAP); + $this->addJS(Script::BOOTSTRAP); + } + + public function loadChartJS() { + $this->addJS(Script::MOMENT); + $this->addJS(Script::CHART); + } + + public function getCode() { + $header = ""; + + foreach($this->metas as $aMeta) { + $header .= ' $val) { + $header .= " $key=\"$val\""; + } + $header .= ' />'; + } + + if(!empty($this->description)) { + $header .= "description\" />"; + } + + if(!empty($this->keywords)) { + $keywords = implode(", ", $this->keywords); + $header .= ""; + } + + if(!empty($this->baseUrl)) { + $header .= "baseUrl\">"; + } + + $header .= "$this->title"; + + foreach($this->sources as $src) { + $header .= $src->getCode(); + } + + foreach($this->rawFields as $raw) { + $header .= $raw; + } + + $header .= ""; + return $header; + } +} +?> diff --git a/core/Elements/Link.class.php b/core/Elements/Link.class.php new file mode 100644 index 0000000..18e9176 --- /dev/null +++ b/core/Elements/Link.class.php @@ -0,0 +1,42 @@ +type = $type; + $this->rel = $rel; + } + + function getCode() { + $type = (empty($this->type) ? "" : " type=\"$this->type\""); + $link = "rel\" href=\"$this->url\" $type/>"; + return $link; + } +} + +?> diff --git a/core/Elements/Script.class.php b/core/Elements/Script.class.php new file mode 100644 index 0000000..022351c --- /dev/null +++ b/core/Elements/Script.class.php @@ -0,0 +1,53 @@ +type = $type; + $this->content = $content; + } + + function getCode() { + $src = (empty($this->url) ? "" : " src=\"$this->url\""); + $script = "'; + return $script; + } +} + +?> diff --git a/core/Elements/Source.class.php b/core/Elements/Source.class.php new file mode 100644 index 0000000..fb2d59b --- /dev/null +++ b/core/Elements/Source.class.php @@ -0,0 +1,22 @@ +sourceType = $sourceType; + $this->url = $url; + } + + public function getCode() { + return "<$sourceType />"; + } + + public function getUrl() { return $this->url; } +} + +?> diff --git a/core/Elements/Style.class.php b/core/Elements/Style.class.php new file mode 100644 index 0000000..35c8968 --- /dev/null +++ b/core/Elements/Style.class.php @@ -0,0 +1,19 @@ +style = $style; + } + + function getCode() { + return ""; + } +} + +?> diff --git a/core/External/PHPMailer/Exception.php b/core/External/PHPMailer/Exception.php new file mode 100644 index 0000000..383ff64 --- /dev/null +++ b/core/External/PHPMailer/Exception.php @@ -0,0 +1,39 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2017 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace External\PHPMailer; + +/** + * PHPMailer exception handler. + * + * @author Marcus Bointon + */ +class Exception extends \Exception +{ + /** + * Prettify error message output. + * + * @return string + */ + public function errorMessage() + { + return '' . htmlspecialchars($this->getMessage()) . "
    \n"; + } +} diff --git a/core/External/PHPMailer/OAuth.php b/core/External/PHPMailer/OAuth.php new file mode 100644 index 0000000..c1c34c4 --- /dev/null +++ b/core/External/PHPMailer/OAuth.php @@ -0,0 +1,138 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2015 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace External\PHPMailer; + +use League\OAuth2\Client\Grant\RefreshToken; +use League\OAuth2\Client\Provider\AbstractProvider; +use League\OAuth2\Client\Token\AccessToken; + +/** + * OAuth - OAuth2 authentication wrapper class. + * Uses the oauth2-client package from the League of Extraordinary Packages. + * + * @see http://oauth2-client.thephpleague.com + * + * @author Marcus Bointon (Synchro/coolbru) + */ +class OAuth +{ + /** + * An instance of the League OAuth Client Provider. + * + * @var AbstractProvider + */ + protected $provider; + + /** + * The current OAuth access token. + * + * @var AccessToken + */ + protected $oauthToken; + + /** + * The user's email address, usually used as the login ID + * and also the from address when sending email. + * + * @var string + */ + protected $oauthUserEmail = ''; + + /** + * The client secret, generated in the app definition of the service you're connecting to. + * + * @var string + */ + protected $oauthClientSecret = ''; + + /** + * The client ID, generated in the app definition of the service you're connecting to. + * + * @var string + */ + protected $oauthClientId = ''; + + /** + * The refresh token, used to obtain new AccessTokens. + * + * @var string + */ + protected $oauthRefreshToken = ''; + + /** + * OAuth constructor. + * + * @param array $options Associative array containing + * `provider`, `userName`, `clientSecret`, `clientId` and `refreshToken` elements + */ + public function __construct($options) + { + $this->provider = $options['provider']; + $this->oauthUserEmail = $options['userName']; + $this->oauthClientSecret = $options['clientSecret']; + $this->oauthClientId = $options['clientId']; + $this->oauthRefreshToken = $options['refreshToken']; + } + + /** + * Get a new RefreshToken. + * + * @return RefreshToken + */ + protected function getGrant() + { + return new RefreshToken(); + } + + /** + * Get a new AccessToken. + * + * @return AccessToken + */ + protected function getToken() + { + return $this->provider->getAccessToken( + $this->getGrant(), + ['refresh_token' => $this->oauthRefreshToken] + ); + } + + /** + * Generate a base64-encoded OAuth token. + * + * @return string + */ + public function getOauth64() + { + // Get a new token if it's not available or has expired + if (null === $this->oauthToken || $this->oauthToken->hasExpired()) { + $this->oauthToken = $this->getToken(); + } + + return base64_encode( + 'user=' . + $this->oauthUserEmail . + "\001auth=Bearer " . + $this->oauthToken . + "\001\001" + ); + } +} diff --git a/core/External/PHPMailer/PHPMailer.php b/core/External/PHPMailer/PHPMailer.php new file mode 100644 index 0000000..86c1a82 --- /dev/null +++ b/core/External/PHPMailer/PHPMailer.php @@ -0,0 +1,4778 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2019 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace External\PHPMailer; + +/** + * PHPMailer - PHP email creation and transport class. + * + * @author Marcus Bointon (Synchro/coolbru) + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + */ +class PHPMailer +{ + const CHARSET_ASCII = 'us-ascii'; + const CHARSET_ISO88591 = 'iso-8859-1'; + const CHARSET_UTF8 = 'utf-8'; + + const CONTENT_TYPE_PLAINTEXT = 'text/plain'; + const CONTENT_TYPE_TEXT_CALENDAR = 'text/calendar'; + const CONTENT_TYPE_TEXT_HTML = 'text/html'; + const CONTENT_TYPE_MULTIPART_ALTERNATIVE = 'multipart/alternative'; + const CONTENT_TYPE_MULTIPART_MIXED = 'multipart/mixed'; + const CONTENT_TYPE_MULTIPART_RELATED = 'multipart/related'; + + const ENCODING_7BIT = '7bit'; + const ENCODING_8BIT = '8bit'; + const ENCODING_BASE64 = 'base64'; + const ENCODING_BINARY = 'binary'; + const ENCODING_QUOTED_PRINTABLE = 'quoted-printable'; + + const ENCRYPTION_STARTTLS = 'tls'; + const ENCRYPTION_SMTPS = 'ssl'; + + const ICAL_METHOD_REQUEST = 'REQUEST'; + const ICAL_METHOD_PUBLISH = 'PUBLISH'; + const ICAL_METHOD_REPLY = 'REPLY'; + const ICAL_METHOD_ADD = 'ADD'; + const ICAL_METHOD_CANCEL = 'CANCEL'; + const ICAL_METHOD_REFRESH = 'REFRESH'; + const ICAL_METHOD_COUNTER = 'COUNTER'; + const ICAL_METHOD_DECLINECOUNTER = 'DECLINECOUNTER'; + + /** + * Email priority. + * Options: null (default), 1 = High, 3 = Normal, 5 = low. + * When null, the header is not set at all. + * + * @var int + */ + public $Priority; + + /** + * The character set of the message. + * + * @var string + */ + public $CharSet = self::CHARSET_ISO88591; + + /** + * The MIME Content-type of the message. + * + * @var string + */ + public $ContentType = self::CONTENT_TYPE_PLAINTEXT; + + /** + * The message encoding. + * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable". + * + * @var string + */ + public $Encoding = self::ENCODING_8BIT; + + /** + * Holds the most recent mailer error message. + * + * @var string + */ + public $ErrorInfo = ''; + + /** + * The From email address for the message. + * + * @var string + */ + public $From = 'root@localhost'; + + /** + * The From name of the message. + * + * @var string + */ + public $FromName = 'Root User'; + + /** + * The envelope sender of the message. + * This will usually be turned into a Return-Path header by the receiver, + * and is the address that bounces will be sent to. + * If not empty, will be passed via `-f` to sendmail or as the 'MAIL FROM' value over SMTP. + * + * @var string + */ + public $Sender = ''; + + /** + * The Subject of the message. + * + * @var string + */ + public $Subject = ''; + + /** + * An HTML or plain text message body. + * If HTML then call isHTML(true). + * + * @var string + */ + public $Body = ''; + + /** + * The plain-text message body. + * This body can be read by mail clients that do not have HTML email + * capability such as mutt & Eudora. + * Clients that can read HTML will view the normal Body. + * + * @var string + */ + public $AltBody = ''; + + /** + * An iCal message part body. + * Only supported in simple alt or alt_inline message types + * To generate iCal event structures, use classes like EasyPeasyICS or iCalcreator. + * + * @see http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/ + * @see http://kigkonsult.se/iCalcreator/ + * + * @var string + */ + public $Ical = ''; + + /** + * Value-array of "method" in Contenttype header "text/calendar" + * + * @var string[] + */ + protected static $IcalMethods = [ + self::ICAL_METHOD_REQUEST, + self::ICAL_METHOD_PUBLISH, + self::ICAL_METHOD_REPLY, + self::ICAL_METHOD_ADD, + self::ICAL_METHOD_CANCEL, + self::ICAL_METHOD_REFRESH, + self::ICAL_METHOD_COUNTER, + self::ICAL_METHOD_DECLINECOUNTER, + ]; + + /** + * The complete compiled MIME message body. + * + * @var string + */ + protected $MIMEBody = ''; + + /** + * The complete compiled MIME message headers. + * + * @var string + */ + protected $MIMEHeader = ''; + + /** + * Extra headers that createHeader() doesn't fold in. + * + * @var string + */ + protected $mailHeader = ''; + + /** + * Word-wrap the message body to this number of chars. + * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance. + * + * @see static::STD_LINE_LENGTH + * + * @var int + */ + public $WordWrap = 0; + + /** + * Which method to use to send mail. + * Options: "mail", "sendmail", or "smtp". + * + * @var string + */ + public $Mailer = 'mail'; + + /** + * The path to the sendmail program. + * + * @var string + */ + public $Sendmail = '/usr/sbin/sendmail'; + + /** + * Whether mail() uses a fully sendmail-compatible MTA. + * One which supports sendmail's "-oi -f" options. + * + * @var bool + */ + public $UseSendmailOptions = true; + + /** + * The email address that a reading confirmation should be sent to, also known as read receipt. + * + * @var string + */ + public $ConfirmReadingTo = ''; + + /** + * The hostname to use in the Message-ID header and as default HELO string. + * If empty, PHPMailer attempts to find one with, in order, + * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value + * 'localhost.localdomain'. + * + * @see PHPMailer::$Helo + * + * @var string + */ + public $Hostname = ''; + + /** + * An ID to be used in the Message-ID header. + * If empty, a unique id will be generated. + * You can set your own, but it must be in the format "", + * as defined in RFC5322 section 3.6.4 or it will be ignored. + * + * @see https://tools.ietf.org/html/rfc5322#section-3.6.4 + * + * @var string + */ + public $MessageID = ''; + + /** + * The message Date to be used in the Date header. + * If empty, the current date will be added. + * + * @var string + */ + public $MessageDate = ''; + + /** + * SMTP hosts. + * Either a single hostname or multiple semicolon-delimited hostnames. + * You can also specify a different port + * for each host by using this format: [hostname:port] + * (e.g. "smtp1.example.com:25;smtp2.example.com"). + * You can also specify encryption type, for example: + * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465"). + * Hosts will be tried in order. + * + * @var string + */ + public $Host = 'localhost'; + + /** + * The default SMTP server port. + * + * @var int + */ + public $Port = 25; + + /** + * The SMTP HELO/EHLO name used for the SMTP connection. + * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find + * one with the same method described above for $Hostname. + * + * @see PHPMailer::$Hostname + * + * @var string + */ + public $Helo = ''; + + /** + * What kind of encryption to use on the SMTP connection. + * Options: '', static::ENCRYPTION_STARTTLS, or static::ENCRYPTION_SMTPS. + * + * @var string + */ + public $SMTPSecure = ''; + + /** + * Whether to enable TLS encryption automatically if a server supports it, + * even if `SMTPSecure` is not set to 'tls'. + * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid. + * + * @var bool + */ + public $SMTPAutoTLS = true; + + /** + * Whether to use SMTP authentication. + * Uses the Username and Password properties. + * + * @see PHPMailer::$Username + * @see PHPMailer::$Password + * + * @var bool + */ + public $SMTPAuth = false; + + /** + * Options array passed to stream_context_create when connecting via SMTP. + * + * @var array + */ + public $SMTPOptions = []; + + /** + * SMTP username. + * + * @var string + */ + public $Username = ''; + + /** + * SMTP password. + * + * @var string + */ + public $Password = ''; + + /** + * SMTP auth type. + * Options are CRAM-MD5, LOGIN, PLAIN, XOAUTH2, attempted in that order if not specified. + * + * @var string + */ + public $AuthType = ''; + + /** + * An instance of the PHPMailer OAuth class. + * + * @var OAuth + */ + protected $oauth; + + /** + * The SMTP server timeout in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * + * @var int + */ + public $Timeout = 300; + + /** + * Comma separated list of DSN notifications + * 'NEVER' under no circumstances a DSN must be returned to the sender. + * If you use NEVER all other notifications will be ignored. + * 'SUCCESS' will notify you when your mail has arrived at its destination. + * 'FAILURE' will arrive if an error occurred during delivery. + * 'DELAY' will notify you if there is an unusual delay in delivery, but the actual + * delivery's outcome (success or failure) is not yet decided. + * + * @see https://tools.ietf.org/html/rfc3461 See section 4.1 for more information about NOTIFY + */ + public $dsn = ''; + + /** + * SMTP class debug output mode. + * Debug output level. + * Options: + * * SMTP::DEBUG_OFF: No output + * * SMTP::DEBUG_CLIENT: Client messages + * * SMTP::DEBUG_SERVER: Client and server messages + * * SMTP::DEBUG_CONNECTION: As SERVER plus connection status + * * SMTP::DEBUG_LOWLEVEL: Noisy, low-level data output, rarely needed + * + * @see SMTP::$do_debug + * + * @var int + */ + public $SMTPDebug = 0; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `
    `, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * By default PHPMailer will use `echo` if run from a `cli` or `cli-server` SAPI, `html` otherwise. + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * ```php + * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * ``` + * + * Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug` + * level output is used: + * + * ```php + * $mail->Debugoutput = new myPsr3Logger; + * ``` + * + * @see SMTP::$Debugoutput + * + * @var string|callable|\Psr\Log\LoggerInterface + */ + public $Debugoutput = 'echo'; + + /** + * Whether to keep SMTP connection open after each message. + * If this is set to true then to close the connection + * requires an explicit call to smtpClose(). + * + * @var bool + */ + public $SMTPKeepAlive = false; + + /** + * Whether to split multiple to addresses into multiple messages + * or send them all in one message. + * Only supported in `mail` and `sendmail` transports, not in SMTP. + * + * @var bool + */ + public $SingleTo = false; + + /** + * Storage for addresses when SingleTo is enabled. + * + * @var array + */ + protected $SingleToArray = []; + + /** + * Whether to generate VERP addresses on send. + * Only applicable when sending via SMTP. + * + * @see https://en.wikipedia.org/wiki/Variable_envelope_return_path + * @see http://www.postfix.org/VERP_README.html Postfix VERP info + * + * @var bool + */ + public $do_verp = false; + + /** + * Whether to allow sending messages with an empty body. + * + * @var bool + */ + public $AllowEmpty = false; + + /** + * DKIM selector. + * + * @var string + */ + public $DKIM_selector = ''; + + /** + * DKIM Identity. + * Usually the email address used as the source of the email. + * + * @var string + */ + public $DKIM_identity = ''; + + /** + * DKIM passphrase. + * Used if your key is encrypted. + * + * @var string + */ + public $DKIM_passphrase = ''; + + /** + * DKIM signing domain name. + * + * @example 'example.com' + * + * @var string + */ + public $DKIM_domain = ''; + + /** + * DKIM Copy header field values for diagnostic use. + * + * @var bool + */ + public $DKIM_copyHeaderFields = true; + + /** + * DKIM Extra signing headers. + * + * @example ['List-Unsubscribe', 'List-Help'] + * + * @var array + */ + public $DKIM_extraHeaders = []; + + /** + * DKIM private key file path. + * + * @var string + */ + public $DKIM_private = ''; + + /** + * DKIM private key string. + * + * If set, takes precedence over `$DKIM_private`. + * + * @var string + */ + public $DKIM_private_string = ''; + + /** + * Callback Action function name. + * + * The function that handles the result of the send email action. + * It is called out by send() for each email sent. + * + * Value can be any php callable: http://www.php.net/is_callable + * + * Parameters: + * bool $result result of the send action + * array $to email addresses of the recipients + * array $cc cc email addresses + * array $bcc bcc email addresses + * string $subject the subject + * string $body the email body + * string $from email address of sender + * string $extra extra information of possible use + * "smtp_transaction_id' => last smtp transaction id + * + * @var string + */ + public $action_function = ''; + + /** + * What to put in the X-Mailer header. + * Options: An empty string for PHPMailer default, whitespace/null for none, or a string to use. + * + * @var string|null + */ + public $XMailer = ''; + + /** + * Which validator to use by default when validating email addresses. + * May be a callable to inject your own validator, but there are several built-in validators. + * The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option. + * + * @see PHPMailer::validateAddress() + * + * @var string|callable + */ + public static $validator = 'php'; + + /** + * An instance of the SMTP sender class. + * + * @var SMTP + */ + protected $smtp; + + /** + * The array of 'to' names and addresses. + * + * @var array + */ + protected $to = []; + + /** + * The array of 'cc' names and addresses. + * + * @var array + */ + protected $cc = []; + + /** + * The array of 'bcc' names and addresses. + * + * @var array + */ + protected $bcc = []; + + /** + * The array of reply-to names and addresses. + * + * @var array + */ + protected $ReplyTo = []; + + /** + * An array of all kinds of addresses. + * Includes all of $to, $cc, $bcc. + * + * @see PHPMailer::$to + * @see PHPMailer::$cc + * @see PHPMailer::$bcc + * + * @var array + */ + protected $all_recipients = []; + + /** + * An array of names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $all_recipients + * and one of $to, $cc, or $bcc. + * This array is used only for addresses with IDN. + * + * @see PHPMailer::$to + * @see PHPMailer::$cc + * @see PHPMailer::$bcc + * @see PHPMailer::$all_recipients + * + * @var array + */ + protected $RecipientsQueue = []; + + /** + * An array of reply-to names and addresses queued for validation. + * In send(), valid and non duplicate entries are moved to $ReplyTo. + * This array is used only for addresses with IDN. + * + * @see PHPMailer::$ReplyTo + * + * @var array + */ + protected $ReplyToQueue = []; + + /** + * The array of attachments. + * + * @var array + */ + protected $attachment = []; + + /** + * The array of custom headers. + * + * @var array + */ + protected $CustomHeader = []; + + /** + * The most recent Message-ID (including angular brackets). + * + * @var string + */ + protected $lastMessageID = ''; + + /** + * The message's MIME type. + * + * @var string + */ + protected $message_type = ''; + + /** + * The array of MIME boundary strings. + * + * @var array + */ + protected $boundary = []; + + /** + * The array of available languages. + * + * @var array + */ + protected $language = []; + + /** + * The number of errors encountered. + * + * @var int + */ + protected $error_count = 0; + + /** + * The S/MIME certificate file path. + * + * @var string + */ + protected $sign_cert_file = ''; + + /** + * The S/MIME key file path. + * + * @var string + */ + protected $sign_key_file = ''; + + /** + * The optional S/MIME extra certificates ("CA Chain") file path. + * + * @var string + */ + protected $sign_extracerts_file = ''; + + /** + * The S/MIME password for the key. + * Used only if the key is encrypted. + * + * @var string + */ + protected $sign_key_pass = ''; + + /** + * Whether to throw exceptions for errors. + * + * @var bool + */ + protected $exceptions = false; + + /** + * Unique ID used for message ID and boundaries. + * + * @var string + */ + protected $uniqueid = ''; + + /** + * The PHPMailer Version number. + * + * @var string + */ + const VERSION = '6.1.4'; + + /** + * Error severity: message only, continue processing. + * + * @var int + */ + const STOP_MESSAGE = 0; + + /** + * Error severity: message, likely ok to continue processing. + * + * @var int + */ + const STOP_CONTINUE = 1; + + /** + * Error severity: message, plus full stop, critical error reached. + * + * @var int + */ + const STOP_CRITICAL = 2; + + /** + * SMTP RFC standard line ending. + * + * @var string + */ + protected static $LE = "\r\n"; + + /** + * The maximum line length supported by mail(). + * + * Background: mail() will sometimes corrupt messages + * with headers headers longer than 65 chars, see #818. + * + * @var int + */ + const MAIL_MAX_LINE_LENGTH = 63; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1. + * + * @var int + */ + const MAX_LINE_LENGTH = 998; + + /** + * The lower maximum line length allowed by RFC 2822 section 2.1.1. + * This length does NOT include the line break + * 76 means that lines will be 77 or 78 chars depending on whether + * the line break format is LF or CRLF; both are valid. + * + * @var int + */ + const STD_LINE_LENGTH = 76; + + /** + * Constructor. + * + * @param bool $exceptions Should we throw external exceptions? + */ + public function __construct($exceptions = null) + { + if (null !== $exceptions) { + $this->exceptions = (bool) $exceptions; + } + //Pick an appropriate debug output format automatically + $this->Debugoutput = (strpos(PHP_SAPI, 'cli') !== false ? 'echo' : 'html'); + } + + /** + * Destructor. + */ + public function __destruct() + { + //Close any open SMTP connection nicely + $this->smtpClose(); + } + + /** + * Call mail() in a safe_mode-aware fashion. + * Also, unless sendmail_path points to sendmail (or something that + * claims to be sendmail), don't pass params (not a perfect fix, + * but it will do). + * + * @param string $to To + * @param string $subject Subject + * @param string $body Message Body + * @param string $header Additional Header(s) + * @param string|null $params Params + * + * @return bool + */ + private function mailPassthru($to, $subject, $body, $header, $params) + { + //Check overloading of mail function to avoid double-encoding + if (ini_get('mbstring.func_overload') & 1) { + $subject = $this->secureHeader($subject); + } else { + $subject = $this->encodeHeader($this->secureHeader($subject)); + } + //Calling mail() with null params breaks + if (!$this->UseSendmailOptions || null === $params) { + $result = @mail($to, $subject, $body, $header); + } else { + $result = @mail($to, $subject, $body, $header, $params); + } + + return $result; + } + + /** + * Output debugging info via user-defined method. + * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug). + * + * @see PHPMailer::$Debugoutput + * @see PHPMailer::$SMTPDebug + * + * @param string $str + */ + protected function edebug($str) + { + if ($this->SMTPDebug <= 0) { + return; + } + //Is this a PSR-3 logger? + if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) { + $this->Debugoutput->debug($str); + + return; + } + //Avoid clash with built-in function names + if (is_callable($this->Debugoutput) && !in_array($this->Debugoutput, ['error_log', 'html', 'echo'])) { + call_user_func($this->Debugoutput, $str, $this->SMTPDebug); + + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ), "
    \n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/\r\n|\r/m', "\n", $str); + echo gmdate('Y-m-d H:i:s'), + "\t", + //Trim trailing space + trim( + //Indent for readability, except for trailing break + str_replace( + "\n", + "\n \t ", + trim($str) + ) + ), + "\n"; + } + } + + /** + * Sets message type to HTML or plain. + * + * @param bool $isHtml True for HTML mode + */ + public function isHTML($isHtml = true) + { + if ($isHtml) { + $this->ContentType = static::CONTENT_TYPE_TEXT_HTML; + } else { + $this->ContentType = static::CONTENT_TYPE_PLAINTEXT; + } + } + + /** + * Send messages using SMTP. + */ + public function isSMTP() + { + $this->Mailer = 'smtp'; + } + + /** + * Send messages using PHP's mail() function. + */ + public function isMail() + { + $this->Mailer = 'mail'; + } + + /** + * Send messages using $Sendmail. + */ + public function isSendmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (false === stripos($ini_sendmail_path, 'sendmail')) { + $this->Sendmail = '/usr/sbin/sendmail'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'sendmail'; + } + + /** + * Send messages using qmail. + */ + public function isQmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (false === stripos($ini_sendmail_path, 'qmail')) { + $this->Sendmail = '/var/qmail/bin/qmail-inject'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'qmail'; + } + + /** + * Add a "To" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addAddress($address, $name = '') + { + return $this->addOrEnqueueAnAddress('to', $address, $name); + } + + /** + * Add a "CC" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('cc', $address, $name); + } + + /** + * Add a "BCC" address. + * + * @param string $address The email address to send to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addBCC($address, $name = '') + { + return $this->addOrEnqueueAnAddress('bcc', $address, $name); + } + + /** + * Add a "Reply-To" address. + * + * @param string $address The email address to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + public function addReplyTo($address, $name = '') + { + return $this->addOrEnqueueAnAddress('Reply-To', $address, $name); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer + * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still + * be modified after calling this function), addition of such addresses is delayed until send(). + * Addresses that have been added already return false, but do not throw exceptions. + * + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + protected function addOrEnqueueAnAddress($kind, $address, $name) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + $pos = strrpos($address, '@'); + if (false === $pos) { + // At-sign is missing. + $error_message = sprintf( + '%s (%s): %s', + $this->lang('invalid_address'), + $kind, + $address + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + $params = [$kind, $address, $name]; + // Enqueue addresses with IDN until we know the PHPMailer::$CharSet. + if (static::idnSupported() && $this->has8bitChars(substr($address, ++$pos))) { + if ('Reply-To' !== $kind) { + if (!array_key_exists($address, $this->RecipientsQueue)) { + $this->RecipientsQueue[$address] = $params; + + return true; + } + } elseif (!array_key_exists($address, $this->ReplyToQueue)) { + $this->ReplyToQueue[$address] = $params; + + return true; + } + + return false; + } + + // Immediately add standard addresses without IDN. + return call_user_func_array([$this, 'addAnAddress'], $params); + } + + /** + * Add an address to one of the recipient arrays or to the ReplyTo array. + * Addresses that have been added already return false, but do not throw exceptions. + * + * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo' + * @param string $address The email address to send, resp. to reply to + * @param string $name + * + * @throws Exception + * + * @return bool true on success, false if address already used or invalid in some way + */ + protected function addAnAddress($kind, $address, $name = '') + { + if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) { + $error_message = sprintf( + '%s: %s', + $this->lang('Invalid recipient kind'), + $kind + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if (!static::validateAddress($address)) { + $error_message = sprintf( + '%s (%s): %s', + $this->lang('invalid_address'), + $kind, + $address + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + if ('Reply-To' !== $kind) { + if (!array_key_exists(strtolower($address), $this->all_recipients)) { + $this->{$kind}[] = [$address, $name]; + $this->all_recipients[strtolower($address)] = true; + + return true; + } + } elseif (!array_key_exists(strtolower($address), $this->ReplyTo)) { + $this->ReplyTo[strtolower($address)] = [$address, $name]; + + return true; + } + + return false; + } + + /** + * Parse and validate a string containing one or more RFC822-style comma-separated email addresses + * of the form "display name
    " into an array of name/address pairs. + * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. + * Note that quotes in the name part are removed. + * + * @see http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation + * + * @param string $addrstr The address list string + * @param bool $useimap Whether to use the IMAP extension to parse the list + * + * @return array + */ + public static function parseAddresses($addrstr, $useimap = true) + { + $addresses = []; + if ($useimap && function_exists('imap_rfc822_parse_adrlist')) { + //Use this built-in parser if it's available + $list = imap_rfc822_parse_adrlist($addrstr, ''); + foreach ($list as $address) { + if (('.SYNTAX-ERROR.' !== $address->host) && static::validateAddress( + $address->mailbox . '@' . $address->host + )) { + $addresses[] = [ + 'name' => (property_exists($address, 'personal') ? $address->personal : ''), + 'address' => $address->mailbox . '@' . $address->host, + ]; + } + } + } else { + //Use this simpler parser + $list = explode(',', $addrstr); + foreach ($list as $address) { + $address = trim($address); + //Is there a separate name part? + if (strpos($address, '<') === false) { + //No separate name, just use the whole thing + if (static::validateAddress($address)) { + $addresses[] = [ + 'name' => '', + 'address' => $address, + ]; + } + } else { + list($name, $email) = explode('<', $address); + $email = trim(str_replace('>', '', $email)); + if (static::validateAddress($email)) { + $addresses[] = [ + 'name' => trim(str_replace(['"', "'"], '', $name)), + 'address' => $email, + ]; + } + } + } + } + + return $addresses; + } + + /** + * Set the From and FromName properties. + * + * @param string $address + * @param string $name + * @param bool $auto Whether to also set the Sender address, defaults to true + * + * @throws Exception + * + * @return bool + */ + public function setFrom($address, $name = '', $auto = true) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + // Don't validate now addresses with IDN. Will be done in send(). + $pos = strrpos($address, '@'); + if ((false === $pos) + || ((!$this->has8bitChars(substr($address, ++$pos)) || !static::idnSupported()) + && !static::validateAddress($address)) + ) { + $error_message = sprintf( + '%s (From): %s', + $this->lang('invalid_address'), + $address + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + $this->From = $address; + $this->FromName = $name; + if ($auto && empty($this->Sender)) { + $this->Sender = $address; + } + + return true; + } + + /** + * Return the Message-ID header of the last email. + * Technically this is the value from the last time the headers were created, + * but it's also the message ID of the last sent message except in + * pathological cases. + * + * @return string + */ + public function getLastMessageID() + { + return $this->lastMessageID; + } + + /** + * Check that a string looks like an email address. + * Validation patterns supported: + * * `auto` Pick best pattern automatically; + * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0; + * * `pcre` Use old PCRE implementation; + * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; + * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements. + * * `noregex` Don't use a regex: super fast, really dumb. + * Alternatively you may pass in a callable to inject your own validator, for example: + * + * ```php + * PHPMailer::validateAddress('user@example.com', function($address) { + * return (strpos($address, '@') !== false); + * }); + * ``` + * + * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator. + * + * @param string $address The email address to check + * @param string|callable $patternselect Which pattern to use + * + * @return bool + */ + public static function validateAddress($address, $patternselect = null) + { + if (null === $patternselect) { + $patternselect = static::$validator; + } + if (is_callable($patternselect)) { + return $patternselect($address); + } + //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 + if (strpos($address, "\n") !== false || strpos($address, "\r") !== false) { + return false; + } + switch ($patternselect) { + case 'pcre': //Kept for BC + case 'pcre8': + /* + * A more complex and more permissive version of the RFC5322 regex on which FILTER_VALIDATE_EMAIL + * is based. + * In addition to the addresses allowed by filter_var, also permits: + * * dotless domains: `a@b` + * * comments: `1234 @ local(blah) .machine .example` + * * quoted elements: `'"test blah"@example.org'` + * * numeric TLDs: `a@b.123` + * * unbracketed IPv4 literals: `a@192.168.0.1` + * * IPv6 literals: 'first.last@[IPv6:a1::]' + * Not all of these will necessarily work for sending! + * + * @see http://squiloople.com/2009/12/20/email-address-validation/ + * @copyright 2009-2010 Michael Rushton + * Feel free to use and redistribute this code. But please keep this copyright notice. + */ + return (bool) preg_match( + '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' . + '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' . + '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' . + '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' . + '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' . + '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' . + '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' . + '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' . + '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', + $address + ); + case 'html5': + /* + * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. + * + * @see http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) + */ + return (bool) preg_match( + '/^[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])?)*$/sD', + $address + ); + case 'php': + default: + return filter_var($address, FILTER_VALIDATE_EMAIL) !== false; + } + } + + /** + * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the + * `intl` and `mbstring` PHP extensions. + * + * @return bool `true` if required functions for IDN support are present + */ + public static function idnSupported() + { + return function_exists('idn_to_ascii') && function_exists('mb_convert_encoding'); + } + + /** + * Converts IDN in given email address to its ASCII form, also known as punycode, if possible. + * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet. + * This function silently returns unmodified address if: + * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form) + * - Conversion to punycode is impossible (e.g. required PHP functions are not available) + * or fails for any reason (e.g. domain contains characters not allowed in an IDN). + * + * @see PHPMailer::$CharSet + * + * @param string $address The email address to convert + * + * @return string The encoded address in ASCII form + */ + public function punyencodeAddress($address) + { + // Verify we have required functions, CharSet, and at-sign. + $pos = strrpos($address, '@'); + if (!empty($this->CharSet) && + false !== $pos && + static::idnSupported() + ) { + $domain = substr($address, ++$pos); + // Verify CharSet string is a valid one, and domain properly encoded in this CharSet. + if ($this->has8bitChars($domain) && @mb_check_encoding($domain, $this->CharSet)) { + $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet); + //Ignore IDE complaints about this line - method signature changed in PHP 5.4 + $errorcode = 0; + if (defined('INTL_IDNA_VARIANT_UTS46')) { + $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_UTS46); + } elseif (defined('INTL_IDNA_VARIANT_2003')) { + $punycode = idn_to_ascii($domain, $errorcode, INTL_IDNA_VARIANT_2003); + } else { + $punycode = idn_to_ascii($domain, $errorcode); + } + if (false !== $punycode) { + return substr($address, 0, $pos) . $punycode; + } + } + } + + return $address; + } + + /** + * Create a message and send it. + * Uses the sending method specified by $Mailer. + * + * @throws Exception + * + * @return bool false on error - See the ErrorInfo property for details of the error + */ + public function send() + { + try { + if (!$this->preSend()) { + return false; + } + + return $this->postSend(); + } catch (Exception $exc) { + $this->mailHeader = ''; + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + } + + /** + * Prepare a message for sending. + * + * @throws Exception + * + * @return bool + */ + public function preSend() + { + if ('smtp' === $this->Mailer + || ('mail' === $this->Mailer && stripos(PHP_OS, 'WIN') === 0) + ) { + //SMTP mandates RFC-compliant line endings + //and it's also used with mail() on Windows + static::setLE("\r\n"); + } else { + //Maintain backward compatibility with legacy Linux command line mailers + static::setLE(PHP_EOL); + } + //Check for buggy PHP versions that add a header with an incorrect line break + if ('mail' === $this->Mailer + && ((PHP_VERSION_ID >= 70000 && PHP_VERSION_ID < 70017) + || (PHP_VERSION_ID >= 70100 && PHP_VERSION_ID < 70103)) + && ini_get('mail.add_x_header') === '1' + && stripos(PHP_OS, 'WIN') === 0 + ) { + trigger_error( + 'Your version of PHP is affected by a bug that may result in corrupted messages.' . + ' To fix it, switch to sending using SMTP, disable the mail.add_x_header option in' . + ' your php.ini, switch to MacOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.', + E_USER_WARNING + ); + } + + try { + $this->error_count = 0; // Reset errors + $this->mailHeader = ''; + + // Dequeue recipient and Reply-To addresses with IDN + foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) { + $params[1] = $this->punyencodeAddress($params[1]); + call_user_func_array([$this, 'addAnAddress'], $params); + } + if (count($this->to) + count($this->cc) + count($this->bcc) < 1) { + throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL); + } + + // Validate From, Sender, and ConfirmReadingTo addresses + foreach (['From', 'Sender', 'ConfirmReadingTo'] as $address_kind) { + $this->$address_kind = trim($this->$address_kind); + if (empty($this->$address_kind)) { + continue; + } + $this->$address_kind = $this->punyencodeAddress($this->$address_kind); + if (!static::validateAddress($this->$address_kind)) { + $error_message = sprintf( + '%s (%s): %s', + $this->lang('invalid_address'), + $address_kind, + $this->$address_kind + ); + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new Exception($error_message); + } + + return false; + } + } + + // Set whether the message is multipart/alternative + if ($this->alternativeExists()) { + $this->ContentType = static::CONTENT_TYPE_MULTIPART_ALTERNATIVE; + } + + $this->setMessageType(); + // Refuse to send an empty message unless we are specifically allowing it + if (!$this->AllowEmpty && empty($this->Body)) { + throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL); + } + + //Trim subject consistently + $this->Subject = trim($this->Subject); + // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) + $this->MIMEHeader = ''; + $this->MIMEBody = $this->createBody(); + // createBody may have added some headers, so retain them + $tempheaders = $this->MIMEHeader; + $this->MIMEHeader = $this->createHeader(); + $this->MIMEHeader .= $tempheaders; + + // To capture the complete message when using mail(), create + // an extra header list which createHeader() doesn't fold in + if ('mail' === $this->Mailer) { + if (count($this->to) > 0) { + $this->mailHeader .= $this->addrAppend('To', $this->to); + } else { + $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + $this->mailHeader .= $this->headerLine( + 'Subject', + $this->encodeHeader($this->secureHeader($this->Subject)) + ); + } + + // Sign with DKIM if enabled + if (!empty($this->DKIM_domain) + && !empty($this->DKIM_selector) + && (!empty($this->DKIM_private_string) + || (!empty($this->DKIM_private) + && static::isPermittedPath($this->DKIM_private) + && file_exists($this->DKIM_private) + ) + ) + ) { + $header_dkim = $this->DKIM_Add( + $this->MIMEHeader . $this->mailHeader, + $this->encodeHeader($this->secureHeader($this->Subject)), + $this->MIMEBody + ); + $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . static::$LE . + static::normalizeBreaks($header_dkim) . static::$LE; + } + + return true; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + } + + /** + * Actually send a message via the selected mechanism. + * + * @throws Exception + * + * @return bool + */ + public function postSend() + { + try { + // Choose the mailer and send through it + switch ($this->Mailer) { + case 'sendmail': + case 'qmail': + return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody); + case 'smtp': + return $this->smtpSend($this->MIMEHeader, $this->MIMEBody); + case 'mail': + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + default: + $sendMethod = $this->Mailer . 'Send'; + if (method_exists($this, $sendMethod)) { + return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody); + } + + return $this->mailSend($this->MIMEHeader, $this->MIMEBody); + } + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + } + + return false; + } + + /** + * Send mail using the $Sendmail program. + * + * @see PHPMailer::$Sendmail + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function sendmailSend($header, $body) + { + $header = rtrim($header, "\r\n ") . static::$LE . static::$LE; + + // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (!empty($this->Sender) && self::isShellSafe($this->Sender)) { + if ('qmail' === $this->Mailer) { + $sendmailFmt = '%s -f%s'; + } else { + $sendmailFmt = '%s -oi -f%s -t'; + } + } elseif ('qmail' === $this->Mailer) { + $sendmailFmt = '%s'; + } else { + $sendmailFmt = '%s -oi -t'; + } + + $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender); + + if ($this->SingleTo) { + foreach ($this->SingleToArray as $toAddr) { + $mail = @popen($sendmail, 'w'); + if (!$mail) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fwrite($mail, 'To: ' . $toAddr . "\n"); + fwrite($mail, $header); + fwrite($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result === 0), + [$toAddr], + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + if (0 !== $result) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + } else { + $mail = @popen($sendmail, 'w'); + if (!$mail) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fwrite($mail, $header); + fwrite($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result === 0), + $this->to, + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From, + [] + ); + if (0 !== $result) { + throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + + return true; + } + + /** + * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters. + * Note that escapeshellarg and escapeshellcmd are inadequate for our purposes, especially on Windows. + * + * @see https://github.com/PHPMailer/PHPMailer/issues/924 CVE-2016-10045 bug report + * + * @param string $string The string to be validated + * + * @return bool + */ + protected static function isShellSafe($string) + { + // Future-proof + if (escapeshellcmd($string) !== $string + || !in_array(escapeshellarg($string), ["'$string'", "\"$string\""]) + ) { + return false; + } + + $length = strlen($string); + + for ($i = 0; $i < $length; ++$i) { + $c = $string[$i]; + + // All other characters have a special meaning in at least one common shell, including = and +. + // Full stop (.) has a special meaning in cmd.exe, but its impact should be negligible here. + // Note that this does permit non-Latin alphanumeric characters based on the current locale. + if (!ctype_alnum($c) && strpos('@_-.', $c) === false) { + return false; + } + } + + return true; + } + + /** + * Check whether a file path is of a permitted type. + * Used to reject URLs and phar files from functions that access local file paths, + * such as addAttachment. + * + * @param string $path A relative or absolute path to a file + * + * @return bool + */ + protected static function isPermittedPath($path) + { + return !preg_match('#^[a-z]+://#i', $path); + } + + /** + * Send mail using the PHP mail() function. + * + * @see http://www.php.net/manual/en/book.mail.php + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function mailSend($header, $body) + { + $header = rtrim($header, "\r\n ") . static::$LE . static::$LE; + + $toArr = []; + foreach ($this->to as $toaddr) { + $toArr[] = $this->addrFormat($toaddr); + } + $to = implode(', ', $toArr); + + $params = null; + //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver + //A space after `-f` is optional, but there is a long history of its presence + //causing problems, so we don't use one + //Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html + //Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html + //Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html + //Example problem: https://www.drupal.org/node/1057954 + // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. + if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) { + $params = sprintf('-f%s', $this->Sender); + } + if (!empty($this->Sender) && static::validateAddress($this->Sender)) { + $old_from = ini_get('sendmail_from'); + ini_set('sendmail_from', $this->Sender); + } + $result = false; + if ($this->SingleTo && count($toArr) > 1) { + foreach ($toArr as $toAddr) { + $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params); + $this->doCallback($result, [$toAddr], $this->cc, $this->bcc, $this->Subject, $body, $this->From, []); + } + } else { + $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params); + $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From, []); + } + if (isset($old_from)) { + ini_set('sendmail_from', $old_from); + } + if (!$result) { + throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL); + } + + return true; + } + + /** + * Get an instance to use for SMTP operations. + * Override this function to load your own SMTP implementation, + * or set one with setSMTPInstance. + * + * @return SMTP + */ + public function getSMTPInstance() + { + if (!is_object($this->smtp)) { + $this->smtp = new SMTP(); + } + + return $this->smtp; + } + + /** + * Provide an instance to use for SMTP operations. + * + * @return SMTP + */ + public function setSMTPInstance(SMTP $smtp) + { + $this->smtp = $smtp; + + return $this->smtp; + } + + /** + * Send mail via SMTP. + * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. + * + * @see PHPMailer::setSMTPInstance() to use a different class. + * + * @uses \PHPMailer\PHPMailer\SMTP + * + * @param string $header The message headers + * @param string $body The message body + * + * @throws Exception + * + * @return bool + */ + protected function smtpSend($header, $body) + { + $header = rtrim($header, "\r\n ") . static::$LE . static::$LE; + $bad_rcpt = []; + if (!$this->smtpConnect($this->SMTPOptions)) { + throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); + } + //Sender already validated in preSend() + if ('' === $this->Sender) { + $smtp_from = $this->From; + } else { + $smtp_from = $this->Sender; + } + if (!$this->smtp->mail($smtp_from)) { + $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError())); + throw new Exception($this->ErrorInfo, self::STOP_CRITICAL); + } + + $callbacks = []; + // Attempt to send to all recipients + foreach ([$this->to, $this->cc, $this->bcc] as $togroup) { + foreach ($togroup as $to) { + if (!$this->smtp->recipient($to[0], $this->dsn)) { + $error = $this->smtp->getError(); + $bad_rcpt[] = ['to' => $to[0], 'error' => $error['detail']]; + $isSent = false; + } else { + $isSent = true; + } + + $callbacks[] = ['issent'=>$isSent, 'to'=>$to[0]]; + } + } + + // Only send the DATA command if we have viable recipients + if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) { + throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL); + } + + $smtp_transaction_id = $this->smtp->getLastTransactionID(); + + if ($this->SMTPKeepAlive) { + $this->smtp->reset(); + } else { + $this->smtp->quit(); + $this->smtp->close(); + } + + foreach ($callbacks as $cb) { + $this->doCallback( + $cb['issent'], + [$cb['to']], + [], + [], + $this->Subject, + $body, + $this->From, + ['smtp_transaction_id' => $smtp_transaction_id] + ); + } + + //Create error message for any bad addresses + if (count($bad_rcpt) > 0) { + $errstr = ''; + foreach ($bad_rcpt as $bad) { + $errstr .= $bad['to'] . ': ' . $bad['error']; + } + throw new Exception($this->lang('recipients_failed') . $errstr, self::STOP_CONTINUE); + } + + return true; + } + + /** + * Initiate a connection to an SMTP server. + * Returns false if the operation failed. + * + * @param array $options An array of options compatible with stream_context_create() + * + * @throws Exception + * + * @uses \PHPMailer\PHPMailer\SMTP + * + * @return bool + */ + public function smtpConnect($options = null) + { + if (null === $this->smtp) { + $this->smtp = $this->getSMTPInstance(); + } + + //If no options are provided, use whatever is set in the instance + if (null === $options) { + $options = $this->SMTPOptions; + } + + // Already connected? + if ($this->smtp->connected()) { + return true; + } + + $this->smtp->setTimeout($this->Timeout); + $this->smtp->setDebugLevel($this->SMTPDebug); + $this->smtp->setDebugOutput($this->Debugoutput); + $this->smtp->setVerp($this->do_verp); + $hosts = explode(';', $this->Host); + $lastexception = null; + + foreach ($hosts as $hostentry) { + $hostinfo = []; + if (!preg_match( + '/^(?:(ssl|tls):\/\/)?(.+?)(?::(\d+))?$/', + trim($hostentry), + $hostinfo + )) { + $this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry)); + // Not a valid host entry + continue; + } + // $hostinfo[1]: optional ssl or tls prefix + // $hostinfo[2]: the hostname + // $hostinfo[3]: optional port number + // The host string prefix can temporarily override the current setting for SMTPSecure + // If it's not specified, the default value is used + + //Check the host name is a valid name or IP address before trying to use it + if (!static::isValidHost($hostinfo[2])) { + $this->edebug($this->lang('invalid_host') . ' ' . $hostinfo[2]); + continue; + } + $prefix = ''; + $secure = $this->SMTPSecure; + $tls = (static::ENCRYPTION_STARTTLS === $this->SMTPSecure); + if ('ssl' === $hostinfo[1] || ('' === $hostinfo[1] && static::ENCRYPTION_SMTPS === $this->SMTPSecure)) { + $prefix = 'ssl://'; + $tls = false; // Can't have SSL and TLS at the same time + $secure = static::ENCRYPTION_SMTPS; + } elseif ('tls' === $hostinfo[1]) { + $tls = true; + // tls doesn't use a prefix + $secure = static::ENCRYPTION_STARTTLS; + } + //Do we need the OpenSSL extension? + $sslext = defined('OPENSSL_ALGO_SHA256'); + if (static::ENCRYPTION_STARTTLS === $secure || static::ENCRYPTION_SMTPS === $secure) { + //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled + if (!$sslext) { + throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL); + } + } + $host = $hostinfo[2]; + $port = $this->Port; + if (array_key_exists(3, $hostinfo) && is_numeric($hostinfo[3]) && $hostinfo[3] > 0 && $hostinfo[3] < 65536) { + $port = (int) $hostinfo[3]; + } + if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) { + try { + if ($this->Helo) { + $hello = $this->Helo; + } else { + $hello = $this->serverHostname(); + } + $this->smtp->hello($hello); + //Automatically enable TLS encryption if: + // * it's not disabled + // * we have openssl extension + // * we are not already using SSL + // * the server offers STARTTLS + if ($this->SMTPAutoTLS && $sslext && 'ssl' !== $secure && $this->smtp->getServerExt('STARTTLS')) { + $tls = true; + } + if ($tls) { + if (!$this->smtp->startTLS()) { + throw new Exception($this->lang('connect_host')); + } + // We must resend EHLO after TLS negotiation + $this->smtp->hello($hello); + } + if ($this->SMTPAuth && !$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->oauth + )) { + throw new Exception($this->lang('authenticate')); + } + + return true; + } catch (Exception $exc) { + $lastexception = $exc; + $this->edebug($exc->getMessage()); + // We must have connected, but then failed TLS or Auth, so close connection nicely + $this->smtp->quit(); + } + } + } + // If we get here, all connection attempts have failed, so close connection hard + $this->smtp->close(); + // As we've caught all exceptions, just report whatever the last one was + if ($this->exceptions && null !== $lastexception) { + throw $lastexception; + } + + return false; + } + + /** + * Close the active SMTP session if one exists. + */ + public function smtpClose() + { + if ((null !== $this->smtp) && $this->smtp->connected()) { + $this->smtp->quit(); + $this->smtp->close(); + } + } + + /** + * Set the language for error messages. + * Returns false if it cannot load the language file. + * The default language is English. + * + * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr") + * @param string $lang_path Path to the language file directory, with trailing separator (slash) + * + * @return bool + */ + public function setLanguage($langcode = 'en', $lang_path = '') + { + // Backwards compatibility for renamed language codes + $renamed_langcodes = [ + 'br' => 'pt_br', + 'cz' => 'cs', + 'dk' => 'da', + 'no' => 'nb', + 'se' => 'sv', + 'rs' => 'sr', + 'tg' => 'tl', + ]; + + if (isset($renamed_langcodes[$langcode])) { + $langcode = $renamed_langcodes[$langcode]; + } + + // Define full set of translatable strings in English + $PHPMAILER_LANG = [ + 'authenticate' => 'SMTP Error: Could not authenticate.', + 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', + 'data_not_accepted' => 'SMTP Error: data not accepted.', + 'empty_message' => 'Message body empty', + 'encoding' => 'Unknown encoding: ', + 'execute' => 'Could not execute: ', + 'file_access' => 'Could not access file: ', + 'file_open' => 'File Error: Could not open file: ', + 'from_failed' => 'The following From address failed: ', + 'instantiate' => 'Could not instantiate mail function.', + 'invalid_address' => 'Invalid address: ', + 'invalid_hostentry' => 'Invalid hostentry: ', + 'invalid_host' => 'Invalid host: ', + 'mailer_not_supported' => ' mailer is not supported.', + 'provide_address' => 'You must provide at least one recipient email address.', + 'recipients_failed' => 'SMTP Error: The following recipients failed: ', + 'signing' => 'Signing Error: ', + 'smtp_connect_failed' => 'SMTP connect() failed.', + 'smtp_error' => 'SMTP server error: ', + 'variable_set' => 'Cannot set or reset variable: ', + 'extension_missing' => 'Extension missing: ', + ]; + if (empty($lang_path)) { + // Calculate an absolute path so it can work if CWD is not here + $lang_path = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR; + } + //Validate $langcode + if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) { + $langcode = 'en'; + } + $foundlang = true; + $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php'; + // There is no English translation file + if ('en' !== $langcode) { + // Make sure language file path is readable + if (!static::isPermittedPath($lang_file) || !file_exists($lang_file)) { + $foundlang = false; + } else { + // Overwrite language-specific strings. + // This way we'll never have missing translation keys. + $foundlang = include $lang_file; + } + } + $this->language = $PHPMAILER_LANG; + + return (bool) $foundlang; // Returns false if language not found + } + + /** + * Get the array of strings for the current language. + * + * @return array + */ + public function getTranslations() + { + return $this->language; + } + + /** + * Create recipient headers. + * + * @param string $type + * @param array $addr An array of recipients, + * where each recipient is a 2-element indexed array with element 0 containing an address + * and element 1 containing a name, like: + * [['joe@example.com', 'Joe User'], ['zoe@example.com', 'Zoe User']] + * + * @return string + */ + public function addrAppend($type, $addr) + { + $addresses = []; + foreach ($addr as $address) { + $addresses[] = $this->addrFormat($address); + } + + return $type . ': ' . implode(', ', $addresses) . static::$LE; + } + + /** + * Format an address for use in a message header. + * + * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name like + * ['joe@example.com', 'Joe User'] + * + * @return string + */ + public function addrFormat($addr) + { + if (empty($addr[1])) { // No name provided + return $this->secureHeader($addr[0]); + } + + return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . + ' <' . $this->secureHeader($addr[0]) . '>'; + } + + /** + * Word-wrap message. + * For use with mailers that do not automatically perform wrapping + * and for quoted-printable encoded messages. + * Original written by philippe. + * + * @param string $message The message to wrap + * @param int $length The line length to wrap to + * @param bool $qp_mode Whether to run in Quoted-Printable mode + * + * @return string + */ + public function wrapText($message, $length, $qp_mode = false) + { + if ($qp_mode) { + $soft_break = sprintf(' =%s', static::$LE); + } else { + $soft_break = static::$LE; + } + // If utf-8 encoding is used, we will need to make sure we don't + // split multibyte characters when we wrap + $is_utf8 = static::CHARSET_UTF8 === strtolower($this->CharSet); + $lelen = strlen(static::$LE); + $crlflen = strlen(static::$LE); + + $message = static::normalizeBreaks($message); + //Remove a trailing line break + if (substr($message, -$lelen) === static::$LE) { + $message = substr($message, 0, -$lelen); + } + + //Split message into lines + $lines = explode(static::$LE, $message); + //Message will be rebuilt in here + $message = ''; + foreach ($lines as $line) { + $words = explode(' ', $line); + $buf = ''; + $firstword = true; + foreach ($words as $word) { + if ($qp_mode && (strlen($word) > $length)) { + $space_left = $length - strlen($buf) - $crlflen; + if (!$firstword) { + if ($space_left > 20) { + $len = $space_left; + if ($is_utf8) { + $len = $this->utf8CharBoundary($word, $len); + } elseif ('=' === substr($word, $len - 1, 1)) { + --$len; + } elseif ('=' === substr($word, $len - 2, 1)) { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = substr($word, $len); + $buf .= ' ' . $part; + $message .= $buf . sprintf('=%s', static::$LE); + } else { + $message .= $buf . $soft_break; + } + $buf = ''; + } + while ($word !== '') { + if ($length <= 0) { + break; + } + $len = $length; + if ($is_utf8) { + $len = $this->utf8CharBoundary($word, $len); + } elseif ('=' === substr($word, $len - 1, 1)) { + --$len; + } elseif ('=' === substr($word, $len - 2, 1)) { + $len -= 2; + } + $part = substr($word, 0, $len); + $word = (string) substr($word, $len); + + if ($word !== '') { + $message .= $part . sprintf('=%s', static::$LE); + } else { + $buf = $part; + } + } + } else { + $buf_o = $buf; + if (!$firstword) { + $buf .= ' '; + } + $buf .= $word; + + if ('' !== $buf_o && strlen($buf) > $length) { + $message .= $buf_o . $soft_break; + $buf = $word; + } + } + $firstword = false; + } + $message .= $buf . static::$LE; + } + + return $message; + } + + /** + * Find the last character boundary prior to $maxLength in a utf-8 + * quoted-printable encoded string. + * Original written by Colin Brown. + * + * @param string $encodedText utf-8 QP text + * @param int $maxLength Find the last character boundary prior to this length + * + * @return int + */ + public function utf8CharBoundary($encodedText, $maxLength) + { + $foundSplitPos = false; + $lookBack = 3; + while (!$foundSplitPos) { + $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); + $encodedCharPos = strpos($lastChunk, '='); + if (false !== $encodedCharPos) { + // Found start of encoded character byte within $lookBack block. + // Check the encoded byte value (the 2 chars after the '=') + $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); + $dec = hexdec($hex); + if ($dec < 128) { + // Single byte character. + // If the encoded char was found at pos 0, it will fit + // otherwise reduce maxLength to start of the encoded char + if ($encodedCharPos > 0) { + $maxLength -= $lookBack - $encodedCharPos; + } + $foundSplitPos = true; + } elseif ($dec >= 192) { + // First byte of a multi byte character + // Reduce maxLength to split at start of character + $maxLength -= $lookBack - $encodedCharPos; + $foundSplitPos = true; + } elseif ($dec < 192) { + // Middle byte of a multi byte character, look further back + $lookBack += 3; + } + } else { + // No encoded character found + $foundSplitPos = true; + } + } + + return $maxLength; + } + + /** + * Apply word wrapping to the message body. + * Wraps the message body to the number of chars set in the WordWrap property. + * You should only do this to plain-text bodies as wrapping HTML tags may break them. + * This is called automatically by createBody(), so you don't need to call it yourself. + */ + public function setWordWrap() + { + if ($this->WordWrap < 1) { + return; + } + + switch ($this->message_type) { + case 'alt': + case 'alt_inline': + case 'alt_attach': + case 'alt_inline_attach': + $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap); + break; + default: + $this->Body = $this->wrapText($this->Body, $this->WordWrap); + break; + } + } + + /** + * Assemble message headers. + * + * @return string The assembled headers + */ + public function createHeader() + { + $result = ''; + + $result .= $this->headerLine('Date', '' === $this->MessageDate ? self::rfcDate() : $this->MessageDate); + + // To be created automatically by mail() + if ($this->SingleTo) { + if ('mail' !== $this->Mailer) { + foreach ($this->to as $toaddr) { + $this->SingleToArray[] = $this->addrFormat($toaddr); + } + } + } elseif (count($this->to) > 0) { + if ('mail' !== $this->Mailer) { + $result .= $this->addrAppend('To', $this->to); + } + } elseif (count($this->cc) === 0) { + $result .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + + $result .= $this->addrAppend('From', [[trim($this->From), $this->FromName]]); + + // sendmail and mail() extract Cc from the header before sending + if (count($this->cc) > 0) { + $result .= $this->addrAppend('Cc', $this->cc); + } + + // sendmail and mail() extract Bcc from the header before sending + if (( + 'sendmail' === $this->Mailer || 'qmail' === $this->Mailer || 'mail' === $this->Mailer + ) + && count($this->bcc) > 0 + ) { + $result .= $this->addrAppend('Bcc', $this->bcc); + } + + if (count($this->ReplyTo) > 0) { + $result .= $this->addrAppend('Reply-To', $this->ReplyTo); + } + + // mail() sets the subject itself + if ('mail' !== $this->Mailer) { + $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject))); + } + + // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4 + // https://tools.ietf.org/html/rfc5322#section-3.6.4 + if ('' !== $this->MessageID && preg_match('/^<.*@.*>$/', $this->MessageID)) { + $this->lastMessageID = $this->MessageID; + } else { + $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname()); + } + $result .= $this->headerLine('Message-ID', $this->lastMessageID); + if (null !== $this->Priority) { + $result .= $this->headerLine('X-Priority', $this->Priority); + } + if ('' === $this->XMailer) { + $result .= $this->headerLine( + 'X-Mailer', + 'PHPMailer ' . self::VERSION . ' (https://github.com/PHPMailer/PHPMailer)' + ); + } else { + $myXmailer = trim($this->XMailer); + if ($myXmailer) { + $result .= $this->headerLine('X-Mailer', $myXmailer); + } + } + + if ('' !== $this->ConfirmReadingTo) { + $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>'); + } + + // Add custom headers + foreach ($this->CustomHeader as $header) { + $result .= $this->headerLine( + trim($header[0]), + $this->encodeHeader(trim($header[1])) + ); + } + if (!$this->sign_key_file) { + $result .= $this->headerLine('MIME-Version', '1.0'); + $result .= $this->getMailMIME(); + } + + return $result; + } + + /** + * Get the message MIME type headers. + * + * @return string + */ + public function getMailMIME() + { + $result = ''; + $ismultipart = true; + switch ($this->message_type) { + case 'inline': + $result .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_RELATED . ';'); + $result .= $this->textLine(' boundary="' . $this->boundary[1] . '"'); + break; + case 'attach': + case 'inline_attach': + case 'alt_attach': + case 'alt_inline_attach': + $result .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_MIXED . ';'); + $result .= $this->textLine(' boundary="' . $this->boundary[1] . '"'); + break; + case 'alt': + case 'alt_inline': + $result .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_ALTERNATIVE . ';'); + $result .= $this->textLine(' boundary="' . $this->boundary[1] . '"'); + break; + default: + // Catches case 'plain': and case '': + $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet); + $ismultipart = false; + break; + } + // RFC1341 part 5 says 7bit is assumed if not specified + if (static::ENCODING_7BIT !== $this->Encoding) { + // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE + if ($ismultipart) { + if (static::ENCODING_8BIT === $this->Encoding) { + $result .= $this->headerLine('Content-Transfer-Encoding', static::ENCODING_8BIT); + } + // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible + } else { + $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding); + } + } + + if ('mail' !== $this->Mailer) { +// $result .= static::$LE; + } + + return $result; + } + + /** + * Returns the whole MIME message. + * Includes complete headers and body. + * Only valid post preSend(). + * + * @see PHPMailer::preSend() + * + * @return string + */ + public function getSentMIMEMessage() + { + return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . static::$LE . static::$LE . $this->MIMEBody; + } + + /** + * Create a unique ID to use for boundaries. + * + * @return string + */ + protected function generateId() + { + $len = 32; //32 bytes = 256 bits + $bytes = ''; + if (function_exists('random_bytes')) { + try { + $bytes = random_bytes($len); + } catch (\Exception $e) { + //Do nothing + } + } elseif (function_exists('openssl_random_pseudo_bytes')) { + /** @noinspection CryptographicallySecureRandomnessInspection */ + $bytes = openssl_random_pseudo_bytes($len); + } + if ($bytes === '') { + //We failed to produce a proper random string, so make do. + //Use a hash to force the length to the same as the other methods + $bytes = hash('sha256', uniqid((string) mt_rand(), true), true); + } + + //We don't care about messing up base64 format here, just want a random string + return str_replace(['=', '+', '/'], '', base64_encode(hash('sha256', $bytes, true))); + } + + /** + * Assemble the message body. + * Returns an empty string on failure. + * + * @throws Exception + * + * @return string The assembled message body + */ + public function createBody() + { + $body = ''; + //Create unique IDs and preset boundaries + $this->uniqueid = $this->generateId(); + $this->boundary[1] = 'b1_' . $this->uniqueid; + $this->boundary[2] = 'b2_' . $this->uniqueid; + $this->boundary[3] = 'b3_' . $this->uniqueid; + + if ($this->sign_key_file) { + $body .= $this->getMailMIME() . static::$LE; + } + + $this->setWordWrap(); + + $bodyEncoding = $this->Encoding; + $bodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if (static::ENCODING_8BIT === $bodyEncoding && !$this->has8bitChars($this->Body)) { + $bodyEncoding = static::ENCODING_7BIT; + //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit + $bodyCharSet = static::CHARSET_ASCII; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding for the body part only + if (static::ENCODING_BASE64 !== $this->Encoding && static::hasLineLongerThanMax($this->Body)) { + $bodyEncoding = static::ENCODING_QUOTED_PRINTABLE; + } + + $altBodyEncoding = $this->Encoding; + $altBodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if (static::ENCODING_8BIT === $altBodyEncoding && !$this->has8bitChars($this->AltBody)) { + $altBodyEncoding = static::ENCODING_7BIT; + //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit + $altBodyCharSet = static::CHARSET_ASCII; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding for the alt body part only + if (static::ENCODING_BASE64 !== $altBodyEncoding && static::hasLineLongerThanMax($this->AltBody)) { + $altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE; + } + //Use this as a preamble in all multipart message types + $mimepre = 'This is a multi-part message in MIME format.' . static::$LE; + switch ($this->message_type) { + case 'inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[1]); + break; + case 'attach': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'inline_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_RELATED . ';'); + $body .= $this->textLine(' boundary="' . $this->boundary[2] . '";'); + $body .= $this->textLine(' type="' . static::CONTENT_TYPE_TEXT_HTML . '"'); + $body .= static::$LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt': + $body .= $mimepre; + $body .= $this->getBoundary( + $this->boundary[1], + $altBodyCharSet, + static::CONTENT_TYPE_PLAINTEXT, + $altBodyEncoding + ); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->getBoundary( + $this->boundary[1], + $bodyCharSet, + static::CONTENT_TYPE_TEXT_HTML, + $bodyEncoding + ); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + if (!empty($this->Ical)) { + $method = static::ICAL_METHOD_REQUEST; + foreach (static::$IcalMethods as $imethod) { + if (stripos($this->Ical, 'METHOD:' . $imethod) !== false) { + $method = $imethod; + break; + } + } + $body .= $this->getBoundary( + $this->boundary[1], + '', + static::CONTENT_TYPE_TEXT_CALENDAR . '; method=' . $method, + '' + ); + $body .= $this->encodeString($this->Ical, $this->Encoding); + $body .= static::$LE; + } + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_inline': + $body .= $mimepre; + $body .= $this->getBoundary( + $this->boundary[1], + $altBodyCharSet, + static::CONTENT_TYPE_PLAINTEXT, + $altBodyEncoding + ); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_RELATED . ';'); + $body .= $this->textLine(' boundary="' . $this->boundary[2] . '";'); + $body .= $this->textLine(' type="' . static::CONTENT_TYPE_TEXT_HTML . '"'); + $body .= static::$LE; + $body .= $this->getBoundary( + $this->boundary[2], + $bodyCharSet, + static::CONTENT_TYPE_TEXT_HTML, + $bodyEncoding + ); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= static::$LE; + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_ALTERNATIVE . ';'); + $body .= $this->textLine(' boundary="' . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary( + $this->boundary[2], + $altBodyCharSet, + static::CONTENT_TYPE_PLAINTEXT, + $altBodyEncoding + ); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->getBoundary( + $this->boundary[2], + $bodyCharSet, + static::CONTENT_TYPE_TEXT_HTML, + $bodyEncoding + ); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + if (!empty($this->Ical)) { + $method = static::ICAL_METHOD_REQUEST; + foreach (static::$IcalMethods as $imethod) { + if (stripos($this->Ical, 'METHOD:' . $imethod) !== false) { + $method = $imethod; + break; + } + } + $body .= $this->getBoundary( + $this->boundary[2], + '', + static::CONTENT_TYPE_TEXT_CALENDAR . '; method=' . $method, + '' + ); + $body .= $this->encodeString($this->Ical, $this->Encoding); + } + $body .= $this->endBoundary($this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt_inline_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_ALTERNATIVE . ';'); + $body .= $this->textLine(' boundary="' . $this->boundary[2] . '"'); + $body .= static::$LE; + $body .= $this->getBoundary( + $this->boundary[2], + $altBodyCharSet, + static::CONTENT_TYPE_PLAINTEXT, + $altBodyEncoding + ); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= static::$LE; + $body .= $this->textLine('--' . $this->boundary[2]); + $body .= $this->headerLine('Content-Type', static::CONTENT_TYPE_MULTIPART_RELATED . ';'); + $body .= $this->textLine(' boundary="' . $this->boundary[3] . '";'); + $body .= $this->textLine(' type="' . static::CONTENT_TYPE_TEXT_HTML . '"'); + $body .= static::$LE; + $body .= $this->getBoundary( + $this->boundary[3], + $bodyCharSet, + static::CONTENT_TYPE_TEXT_HTML, + $bodyEncoding + ); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= static::$LE; + $body .= $this->attachAll('inline', $this->boundary[3]); + $body .= static::$LE; + $body .= $this->endBoundary($this->boundary[2]); + $body .= static::$LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + default: + // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types + //Reset the `Encoding` property in case we changed it for line length reasons + $this->Encoding = $bodyEncoding; + $body .= $this->encodeString($this->Body, $this->Encoding); + break; + } + + if ($this->isError()) { + $body = ''; + if ($this->exceptions) { + throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL); + } + } elseif ($this->sign_key_file) { + try { + if (!defined('PKCS7_TEXT')) { + throw new Exception($this->lang('extension_missing') . 'openssl'); + } + + $file = tempnam(sys_get_temp_dir(), 'srcsign'); + $signed = tempnam(sys_get_temp_dir(), 'mailsign'); + file_put_contents($file, $body); + + //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197 + if (empty($this->sign_extracerts_file)) { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + ['file://' . realpath($this->sign_key_file), $this->sign_key_pass], + [] + ); + } else { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + ['file://' . realpath($this->sign_key_file), $this->sign_key_pass], + [], + PKCS7_DETACHED, + $this->sign_extracerts_file + ); + } + + @unlink($file); + if ($sign) { + $body = file_get_contents($signed); + @unlink($signed); + //The message returned by openssl contains both headers and body, so need to split them up + $parts = explode("\n\n", $body, 2); + $this->MIMEHeader .= $parts[0] . static::$LE . static::$LE; + $body = $parts[1]; + } else { + @unlink($signed); + throw new Exception($this->lang('signing') . openssl_error_string()); + } + } catch (Exception $exc) { + $body = ''; + if ($this->exceptions) { + throw $exc; + } + } + } + + return $body; + } + + /** + * Return the start of a message boundary. + * + * @param string $boundary + * @param string $charSet + * @param string $contentType + * @param string $encoding + * + * @return string + */ + protected function getBoundary($boundary, $charSet, $contentType, $encoding) + { + $result = ''; + if ('' === $charSet) { + $charSet = $this->CharSet; + } + if ('' === $contentType) { + $contentType = $this->ContentType; + } + if ('' === $encoding) { + $encoding = $this->Encoding; + } + $result .= $this->textLine('--' . $boundary); + $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet); + $result .= static::$LE; + // RFC1341 part 5 says 7bit is assumed if not specified + if (static::ENCODING_7BIT !== $encoding) { + $result .= $this->headerLine('Content-Transfer-Encoding', $encoding); + } + $result .= static::$LE; + + return $result; + } + + /** + * Return the end of a message boundary. + * + * @param string $boundary + * + * @return string + */ + protected function endBoundary($boundary) + { + return static::$LE . '--' . $boundary . '--' . static::$LE; + } + + /** + * Set the message type. + * PHPMailer only supports some preset message types, not arbitrary MIME structures. + */ + protected function setMessageType() + { + $type = []; + if ($this->alternativeExists()) { + $type[] = 'alt'; + } + if ($this->inlineImageExists()) { + $type[] = 'inline'; + } + if ($this->attachmentExists()) { + $type[] = 'attach'; + } + $this->message_type = implode('_', $type); + if ('' === $this->message_type) { + //The 'plain' message_type refers to the message having a single body element, not that it is plain-text + $this->message_type = 'plain'; + } + } + + /** + * Format a header line. + * + * @param string $name + * @param string|int $value + * + * @return string + */ + public function headerLine($name, $value) + { + return $name . ': ' . $value . static::$LE; + } + + /** + * Return a formatted mail line. + * + * @param string $value + * + * @return string + */ + public function textLine($value) + { + return $value . static::$LE; + } + + /** + * Add an attachment from a path on the filesystem. + * Never use a user-supplied path to a file! + * Returns false if the file could not be found or read. + * Explicitly *does not* support passing URLs; PHPMailer is not an HTTP client. + * If you need to do that, fetch the resource yourself and pass it in via a local file or string. + * + * @param string $path Path to the attachment + * @param string $name Overrides the attachment name + * @param string $encoding File encoding (see $Encoding) + * @param string $type File extension (MIME) type + * @param string $disposition Disposition to use + * + * @throws Exception + * + * @return bool + */ + public function addAttachment( + $path, + $name = '', + $encoding = self::ENCODING_BASE64, + $type = '', + $disposition = 'attachment' + ) { + try { + if (!static::isPermittedPath($path) || !@is_file($path)) { + throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE); + } + + // If a MIME type is not specified, try to work it out from the file name + if ('' === $type) { + $type = static::filenameToType($path); + } + + $filename = (string) static::mb_pathinfo($path, PATHINFO_BASENAME); + if ('' === $name) { + $name = $filename; + } + + if (!$this->validateEncoding($encoding)) { + throw new Exception($this->lang('encoding') . $encoding); + } + + $this->attachment[] = [ + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => $name, + ]; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + + return true; + } + + /** + * Return the array of attachments. + * + * @return array + */ + public function getAttachments() + { + return $this->attachment; + } + + /** + * Attach all file, string, and binary attachments to the message. + * Returns an empty string on failure. + * + * @param string $disposition_type + * @param string $boundary + * + * @throws Exception + * + * @return string + */ + protected function attachAll($disposition_type, $boundary) + { + // Return text of body + $mime = []; + $cidUniq = []; + $incl = []; + + // Add all attachments + foreach ($this->attachment as $attachment) { + // Check if it is a valid disposition_filter + if ($attachment[6] === $disposition_type) { + // Check for string attachment + $string = ''; + $path = ''; + $bString = $attachment[5]; + if ($bString) { + $string = $attachment[0]; + } else { + $path = $attachment[0]; + } + + $inclhash = hash('sha256', serialize($attachment)); + if (in_array($inclhash, $incl, true)) { + continue; + } + $incl[] = $inclhash; + $name = $attachment[2]; + $encoding = $attachment[3]; + $type = $attachment[4]; + $disposition = $attachment[6]; + $cid = $attachment[7]; + if ('inline' === $disposition && array_key_exists($cid, $cidUniq)) { + continue; + } + $cidUniq[$cid] = true; + + $mime[] = sprintf('--%s%s', $boundary, static::$LE); + //Only include a filename property if we have one + if (!empty($name)) { + $mime[] = sprintf( + 'Content-Type: %s; name="%s"%s', + $type, + $this->encodeHeader($this->secureHeader($name)), + static::$LE + ); + } else { + $mime[] = sprintf( + 'Content-Type: %s%s', + $type, + static::$LE + ); + } + // RFC1341 part 5 says 7bit is assumed if not specified + if (static::ENCODING_7BIT !== $encoding) { + $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, static::$LE); + } + + //Only set Content-IDs on inline attachments + if ((string) $cid !== '' && $disposition === 'inline') { + $mime[] = 'Content-ID: <' . $this->encodeHeader($this->secureHeader($cid)) . '>' . static::$LE; + } + + // If a filename contains any of these chars, it should be quoted, + // but not otherwise: RFC2183 & RFC2045 5.1 + // Fixes a warning in IETF's msglint MIME checker + // Allow for bypassing the Content-Disposition header totally + if (!empty($disposition)) { + $encoded_name = $this->encodeHeader($this->secureHeader($name)); + if (preg_match('/[ ()<>@,;:"\/\[\]?=]/', $encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename="%s"%s', + $disposition, + $encoded_name, + static::$LE . static::$LE + ); + } elseif (!empty($encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename=%s%s', + $disposition, + $encoded_name, + static::$LE . static::$LE + ); + } else { + $mime[] = sprintf( + 'Content-Disposition: %s%s', + $disposition, + static::$LE . static::$LE + ); + } + } else { + $mime[] = static::$LE; + } + + // Encode as string attachment + if ($bString) { + $mime[] = $this->encodeString($string, $encoding); + } else { + $mime[] = $this->encodeFile($path, $encoding); + } + if ($this->isError()) { + return ''; + } + $mime[] = static::$LE; + } + } + + $mime[] = sprintf('--%s--%s', $boundary, static::$LE); + + return implode('', $mime); + } + + /** + * Encode a file attachment in requested format. + * Returns an empty string on failure. + * + * @param string $path The full path to the file + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' + * + * @return string + */ + protected function encodeFile($path, $encoding = self::ENCODING_BASE64) + { + try { + if (!static::isPermittedPath($path) || !file_exists($path)) { + throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE); + } + $file_buffer = file_get_contents($path); + if (false === $file_buffer) { + throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE); + } + $file_buffer = $this->encodeString($file_buffer, $encoding); + + return $file_buffer; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + + return ''; + } + } + + /** + * Encode a string in requested format. + * Returns an empty string on failure. + * + * @param string $str The text to encode + * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable' + * + * @throws Exception + * + * @return string + */ + public function encodeString($str, $encoding = self::ENCODING_BASE64) + { + $encoded = ''; + switch (strtolower($encoding)) { + case static::ENCODING_BASE64: + $encoded = chunk_split( + base64_encode($str), + static::STD_LINE_LENGTH, + static::$LE + ); + break; + case static::ENCODING_7BIT: + case static::ENCODING_8BIT: + $encoded = static::normalizeBreaks($str); + // Make sure it ends with a line break + if (substr($encoded, -(strlen(static::$LE))) !== static::$LE) { + $encoded .= static::$LE; + } + break; + case static::ENCODING_BINARY: + $encoded = $str; + break; + case static::ENCODING_QUOTED_PRINTABLE: + $encoded = $this->encodeQP($str); + break; + default: + $this->setError($this->lang('encoding') . $encoding); + if ($this->exceptions) { + throw new Exception($this->lang('encoding') . $encoding); + } + break; + } + + return $encoded; + } + + /** + * Encode a header value (not including its label) optimally. + * Picks shortest of Q, B, or none. Result includes folding if needed. + * See RFC822 definitions for phrase, comment and text positions. + * + * @param string $str The header value to encode + * @param string $position What context the string will be used in + * + * @return string + */ + public function encodeHeader($str, $position = 'text') + { + $matchcount = 0; + switch (strtolower($position)) { + case 'phrase': + if (!preg_match('/[\200-\377]/', $str)) { + // Can't use addslashes as we don't know the value of magic_quotes_sybase + $encoded = addcslashes($str, "\0..\37\177\\\""); + if (($str === $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { + return $encoded; + } + + return "\"$encoded\""; + } + $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); + break; + /* @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + $matchcount = preg_match_all('/[()"]/', $str, $matches); + //fallthrough + case 'text': + default: + $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + break; + } + + if ($this->has8bitChars($str)) { + $charset = $this->CharSet; + } else { + $charset = static::CHARSET_ASCII; + } + + // Q/B encoding adds 8 chars and the charset ("` =??[QB]??=`"). + $overhead = 8 + strlen($charset); + + if ('mail' === $this->Mailer) { + $maxlen = static::MAIL_MAX_LINE_LENGTH - $overhead; + } else { + $maxlen = static::MAX_LINE_LENGTH - $overhead; + } + + // Select the encoding that produces the shortest output and/or prevents corruption. + if ($matchcount > strlen($str) / 3) { + // More than 1/3 of the content needs encoding, use B-encode. + $encoding = 'B'; + } elseif ($matchcount > 0) { + // Less than 1/3 of the content needs encoding, use Q-encode. + $encoding = 'Q'; + } elseif (strlen($str) > $maxlen) { + // No encoding needed, but value exceeds max line length, use Q-encode to prevent corruption. + $encoding = 'Q'; + } else { + // No reformatting needed + $encoding = false; + } + + switch ($encoding) { + case 'B': + if ($this->hasMultiBytes($str)) { + // Use a custom function which correctly encodes and wraps long + // multibyte strings without breaking lines within a character + $encoded = $this->base64EncodeWrapMB($str, "\n"); + } else { + $encoded = base64_encode($str); + $maxlen -= $maxlen % 4; + $encoded = trim(chunk_split($encoded, $maxlen, "\n")); + } + $encoded = preg_replace('/^(.*)$/m', ' =?' . $charset . "?$encoding?\\1?=", $encoded); + break; + case 'Q': + $encoded = $this->encodeQ($str, $position); + $encoded = $this->wrapText($encoded, $maxlen, true); + $encoded = str_replace('=' . static::$LE, "\n", trim($encoded)); + $encoded = preg_replace('/^(.*)$/m', ' =?' . $charset . "?$encoding?\\1?=", $encoded); + break; + default: + return $str; + } + + return trim(static::normalizeBreaks($encoded)); + } + + /** + * Check if a string contains multi-byte characters. + * + * @param string $str multi-byte text to wrap encode + * + * @return bool + */ + public function hasMultiBytes($str) + { + if (function_exists('mb_strlen')) { + return strlen($str) > mb_strlen($str, $this->CharSet); + } + + // Assume no multibytes (we can't handle without mbstring functions anyway) + return false; + } + + /** + * Does a string contain any 8-bit chars (in any charset)? + * + * @param string $text + * + * @return bool + */ + public function has8bitChars($text) + { + return (bool) preg_match('/[\x80-\xFF]/', $text); + } + + /** + * Encode and wrap long multibyte strings for mail headers + * without breaking lines within a character. + * Adapted from a function by paravoid. + * + * @see http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283 + * + * @param string $str multi-byte text to wrap encode + * @param string $linebreak string to use as linefeed/end-of-line + * + * @return string + */ + public function base64EncodeWrapMB($str, $linebreak = null) + { + $start = '=?' . $this->CharSet . '?B?'; + $end = '?='; + $encoded = ''; + if (null === $linebreak) { + $linebreak = static::$LE; + } + + $mb_length = mb_strlen($str, $this->CharSet); + // Each line must have length <= 75, including $start and $end + $length = 75 - strlen($start) - strlen($end); + // Average multi-byte ratio + $ratio = $mb_length / strlen($str); + // Base64 has a 4:3 ratio + $avgLength = floor($length * $ratio * .75); + + $offset = 0; + for ($i = 0; $i < $mb_length; $i += $offset) { + $lookBack = 0; + do { + $offset = $avgLength - $lookBack; + $chunk = mb_substr($str, $i, $offset, $this->CharSet); + $chunk = base64_encode($chunk); + ++$lookBack; + } while (strlen($chunk) > $length); + $encoded .= $chunk . $linebreak; + } + + // Chomp the last linefeed + return substr($encoded, 0, -strlen($linebreak)); + } + + /** + * Encode a string in quoted-printable format. + * According to RFC2045 section 6.7. + * + * @param string $string The text to encode + * + * @return string + */ + public function encodeQP($string) + { + return static::normalizeBreaks(quoted_printable_encode($string)); + } + + /** + * Encode a string using Q encoding. + * + * @see http://tools.ietf.org/html/rfc2047#section-4.2 + * + * @param string $str the text to encode + * @param string $position Where the text is going to be used, see the RFC for what that means + * + * @return string + */ + public function encodeQ($str, $position = 'text') + { + // There should not be any EOL in the string + $pattern = ''; + $encoded = str_replace(["\r", "\n"], '', $str); + switch (strtolower($position)) { + case 'phrase': + // RFC 2047 section 5.3 + $pattern = '^A-Za-z0-9!*+\/ -'; + break; + /* + * RFC 2047 section 5.2. + * Build $pattern without including delimiters and [] + */ + /* @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + $pattern = '\(\)"'; + /* Intentional fall through */ + case 'text': + default: + // RFC 2047 section 5.1 + // Replace every high ascii, control, =, ? and _ characters + $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern; + break; + } + $matches = []; + if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) { + // If the string contains an '=', make sure it's the first thing we replace + // so as to avoid double-encoding + $eqkey = array_search('=', $matches[0], true); + if (false !== $eqkey) { + unset($matches[0][$eqkey]); + array_unshift($matches[0], '='); + } + foreach (array_unique($matches[0]) as $char) { + $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded); + } + } + // Replace spaces with _ (more readable than =20) + // RFC 2047 section 4.2(2) + return str_replace(' ', '_', $encoded); + } + + /** + * Add a string or binary attachment (non-filesystem). + * This method can be used to attach ascii or binary data, + * such as a BLOB record from a database. + * + * @param string $string String attachment data + * @param string $filename Name of the attachment + * @param string $encoding File encoding (see $Encoding) + * @param string $type File extension (MIME) type + * @param string $disposition Disposition to use + * + * @throws Exception + * + * @return bool True on successfully adding an attachment + */ + public function addStringAttachment( + $string, + $filename, + $encoding = self::ENCODING_BASE64, + $type = '', + $disposition = 'attachment' + ) { + try { + // If a MIME type is not specified, try to work it out from the file name + if ('' === $type) { + $type = static::filenameToType($filename); + } + + if (!$this->validateEncoding($encoding)) { + throw new Exception($this->lang('encoding') . $encoding); + } + + // Append to $attachment array + $this->attachment[] = [ + 0 => $string, + 1 => $filename, + 2 => static::mb_pathinfo($filename, PATHINFO_BASENAME), + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => 0, + ]; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + + return true; + } + + /** + * Add an embedded (inline) attachment from a file. + * This can include images, sounds, and just about any other document type. + * These differ from 'regular' attachments in that they are intended to be + * displayed inline with the message, not just attached for download. + * This is used in HTML messages that embed the images + * the HTML refers to using the $cid value. + * Never use a user-supplied path to a file! + * + * @param string $path Path to the attachment + * @param string $cid Content ID of the attachment; Use this to reference + * the content when using an embedded image in HTML + * @param string $name Overrides the attachment name + * @param string $encoding File encoding (see $Encoding) + * @param string $type File MIME type + * @param string $disposition Disposition to use + * + * @throws Exception + * + * @return bool True on successfully adding an attachment + */ + public function addEmbeddedImage( + $path, + $cid, + $name = '', + $encoding = self::ENCODING_BASE64, + $type = '', + $disposition = 'inline' + ) { + try { + if (!static::isPermittedPath($path) || !@is_file($path)) { + throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE); + } + + // If a MIME type is not specified, try to work it out from the file name + if ('' === $type) { + $type = static::filenameToType($path); + } + + if (!$this->validateEncoding($encoding)) { + throw new Exception($this->lang('encoding') . $encoding); + } + + $filename = (string) static::mb_pathinfo($path, PATHINFO_BASENAME); + if ('' === $name) { + $name = $filename; + } + + // Append to $attachment array + $this->attachment[] = [ + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => $cid, + ]; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + + return true; + } + + /** + * Add an embedded stringified attachment. + * This can include images, sounds, and just about any other document type. + * If your filename doesn't contain an extension, be sure to set the $type to an appropriate MIME type. + * + * @param string $string The attachment binary data + * @param string $cid Content ID of the attachment; Use this to reference + * the content when using an embedded image in HTML + * @param string $name A filename for the attachment. If this contains an extension, + * PHPMailer will attempt to set a MIME type for the attachment. + * For example 'file.jpg' would get an 'image/jpeg' MIME type. + * @param string $encoding File encoding (see $Encoding), defaults to 'base64' + * @param string $type MIME type - will be used in preference to any automatically derived type + * @param string $disposition Disposition to use + * + * @throws Exception + * + * @return bool True on successfully adding an attachment + */ + public function addStringEmbeddedImage( + $string, + $cid, + $name = '', + $encoding = self::ENCODING_BASE64, + $type = '', + $disposition = 'inline' + ) { + try { + // If a MIME type is not specified, try to work it out from the name + if ('' === $type && !empty($name)) { + $type = static::filenameToType($name); + } + + if (!$this->validateEncoding($encoding)) { + throw new Exception($this->lang('encoding') . $encoding); + } + + // Append to $attachment array + $this->attachment[] = [ + 0 => $string, + 1 => $name, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => $cid, + ]; + } catch (Exception $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + + return false; + } + + return true; + } + + /** + * Validate encodings. + * + * @param string $encoding + * + * @return bool + */ + protected function validateEncoding($encoding) + { + return in_array( + $encoding, + [ + self::ENCODING_7BIT, + self::ENCODING_QUOTED_PRINTABLE, + self::ENCODING_BASE64, + self::ENCODING_8BIT, + self::ENCODING_BINARY, + ], + true + ); + } + + /** + * Check if an embedded attachment is present with this cid. + * + * @param string $cid + * + * @return bool + */ + protected function cidExists($cid) + { + foreach ($this->attachment as $attachment) { + if ('inline' === $attachment[6] && $cid === $attachment[7]) { + return true; + } + } + + return false; + } + + /** + * Check if an inline attachment is present. + * + * @return bool + */ + public function inlineImageExists() + { + foreach ($this->attachment as $attachment) { + if ('inline' === $attachment[6]) { + return true; + } + } + + return false; + } + + /** + * Check if an attachment (non-inline) is present. + * + * @return bool + */ + public function attachmentExists() + { + foreach ($this->attachment as $attachment) { + if ('attachment' === $attachment[6]) { + return true; + } + } + + return false; + } + + /** + * Check if this message has an alternative body set. + * + * @return bool + */ + public function alternativeExists() + { + return !empty($this->AltBody); + } + + /** + * Clear queued addresses of given kind. + * + * @param string $kind 'to', 'cc', or 'bcc' + */ + public function clearQueuedAddresses($kind) + { + $this->RecipientsQueue = array_filter( + $this->RecipientsQueue, + static function ($params) use ($kind) { + return $params[0] !== $kind; + } + ); + } + + /** + * Clear all To recipients. + */ + public function clearAddresses() + { + foreach ($this->to as $to) { + unset($this->all_recipients[strtolower($to[0])]); + } + $this->to = []; + $this->clearQueuedAddresses('to'); + } + + /** + * Clear all CC recipients. + */ + public function clearCCs() + { + foreach ($this->cc as $cc) { + unset($this->all_recipients[strtolower($cc[0])]); + } + $this->cc = []; + $this->clearQueuedAddresses('cc'); + } + + /** + * Clear all BCC recipients. + */ + public function clearBCCs() + { + foreach ($this->bcc as $bcc) { + unset($this->all_recipients[strtolower($bcc[0])]); + } + $this->bcc = []; + $this->clearQueuedAddresses('bcc'); + } + + /** + * Clear all ReplyTo recipients. + */ + public function clearReplyTos() + { + $this->ReplyTo = []; + $this->ReplyToQueue = []; + } + + /** + * Clear all recipient types. + */ + public function clearAllRecipients() + { + $this->to = []; + $this->cc = []; + $this->bcc = []; + $this->all_recipients = []; + $this->RecipientsQueue = []; + } + + /** + * Clear all filesystem, string, and binary attachments. + */ + public function clearAttachments() + { + $this->attachment = []; + } + + /** + * Clear all custom headers. + */ + public function clearCustomHeaders() + { + $this->CustomHeader = []; + } + + /** + * Add an error message to the error container. + * + * @param string $msg + */ + protected function setError($msg) + { + ++$this->error_count; + if ('smtp' === $this->Mailer && null !== $this->smtp) { + $lasterror = $this->smtp->getError(); + if (!empty($lasterror['error'])) { + $msg .= $this->lang('smtp_error') . $lasterror['error']; + if (!empty($lasterror['detail'])) { + $msg .= ' Detail: ' . $lasterror['detail']; + } + if (!empty($lasterror['smtp_code'])) { + $msg .= ' SMTP code: ' . $lasterror['smtp_code']; + } + if (!empty($lasterror['smtp_code_ex'])) { + $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex']; + } + } + } + $this->ErrorInfo = $msg; + } + + /** + * Return an RFC 822 formatted date. + * + * @return string + */ + public static function rfcDate() + { + // Set the time zone to whatever the default is to avoid 500 errors + // Will default to UTC if it's not set properly in php.ini + date_default_timezone_set(@date_default_timezone_get()); + + return date('D, j M Y H:i:s O'); + } + + /** + * Get the server hostname. + * Returns 'localhost.localdomain' if unknown. + * + * @return string + */ + protected function serverHostname() + { + $result = ''; + if (!empty($this->Hostname)) { + $result = $this->Hostname; + } elseif (isset($_SERVER) && array_key_exists('SERVER_NAME', $_SERVER)) { + $result = $_SERVER['SERVER_NAME']; + } elseif (function_exists('gethostname') && gethostname() !== false) { + $result = gethostname(); + } elseif (php_uname('n') !== false) { + $result = php_uname('n'); + } + if (!static::isValidHost($result)) { + return 'localhost.localdomain'; + } + + return $result; + } + + /** + * Validate whether a string contains a valid value to use as a hostname or IP address. + * IPv6 addresses must include [], e.g. `[::1]`, not just `::1`. + * + * @param string $host The host name or IP address to check + * + * @return bool + */ + public static function isValidHost($host) + { + //Simple syntax limits + if (empty($host) + || !is_string($host) + || strlen($host) > 256 + || !preg_match('/^([a-zA-Z\d.-]*|\[[a-fA-F\d:]+])$/', $host) + ) { + return false; + } + //Looks like a bracketed IPv6 address + if (strlen($host) > 2 && substr($host, 0, 1) === '[' && substr($host, -1, 1) === ']') { + return filter_var(substr($host, 1, -1), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false; + } + //If removing all the dots results in a numeric string, it must be an IPv4 address. + //Need to check this first because otherwise things like `999.0.0.0` are considered valid host names + if (is_numeric(str_replace('.', '', $host))) { + //Is it a valid IPv4 address? + return filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false; + } + if (filter_var('http://' . $host, FILTER_VALIDATE_URL) !== false) { + //Is it a syntactically valid hostname? + return true; + } + + return false; + } + + /** + * Get an error message in the current language. + * + * @param string $key + * + * @return string + */ + protected function lang($key) + { + if (count($this->language) < 1) { + $this->setLanguage(); // set the default language + } + + if (array_key_exists($key, $this->language)) { + if ('smtp_connect_failed' === $key) { + //Include a link to troubleshooting docs on SMTP connection failure + //this is by far the biggest cause of support questions + //but it's usually not PHPMailer's fault. + return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting'; + } + + return $this->language[$key]; + } + + //Return the key as a fallback + return $key; + } + + /** + * Check if an error occurred. + * + * @return bool True if an error did occur + */ + public function isError() + { + return $this->error_count > 0; + } + + /** + * Add a custom header. + * $name value can be overloaded to contain + * both header name and value (name:value). + * + * @param string $name Custom header name + * @param string|null $value Header value + */ + public function addCustomHeader($name, $value = null) + { + if (null === $value) { + // Value passed in as name:value + $this->CustomHeader[] = explode(':', $name, 2); + } else { + $this->CustomHeader[] = [$name, $value]; + } + } + + /** + * Returns all custom headers. + * + * @return array + */ + public function getCustomHeaders() + { + return $this->CustomHeader; + } + + /** + * Create a message body from an HTML string. + * Automatically inlines images and creates a plain-text version by converting the HTML, + * overwriting any existing values in Body and AltBody. + * Do not source $message content from user input! + * $basedir is prepended when handling relative URLs, e.g. and must not be empty + * will look for an image file in $basedir/images/a.png and convert it to inline. + * If you don't provide a $basedir, relative paths will be left untouched (and thus probably break in email) + * Converts data-uri images into embedded attachments. + * If you don't want to apply these transformations to your HTML, just set Body and AltBody directly. + * + * @param string $message HTML message string + * @param string $basedir Absolute path to a base directory to prepend to relative paths to images + * @param bool|callable $advanced Whether to use the internal HTML to text converter + * or your own custom converter @return string $message The transformed message Body + * + * @throws Exception + * + * @see PHPMailer::html2text() + */ + public function msgHTML($message, $basedir = '', $advanced = false) + { + preg_match_all('/(? 1 && '/' !== substr($basedir, -1)) { + // Ensure $basedir has a trailing / + $basedir .= '/'; + } + foreach ($images[2] as $imgindex => $url) { + // Convert data URIs into embedded images + //e.g. "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" + if (preg_match('#^data:(image/(?:jpe?g|gif|png));?(base64)?,(.+)#', $url, $match)) { + if (count($match) === 4 && static::ENCODING_BASE64 === $match[2]) { + $data = base64_decode($match[3]); + } elseif ('' === $match[2]) { + $data = rawurldecode($match[3]); + } else { + //Not recognised so leave it alone + continue; + } + //Hash the decoded data, not the URL, so that the same data-URI image used in multiple places + //will only be embedded once, even if it used a different encoding + $cid = substr(hash('sha256', $data), 0, 32) . '@phpmailer.0'; // RFC2392 S 2 + + if (!$this->cidExists($cid)) { + $this->addStringEmbeddedImage( + $data, + $cid, + 'embed' . $imgindex, + static::ENCODING_BASE64, + $match[1] + ); + } + $message = str_replace( + $images[0][$imgindex], + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + continue; + } + if (// Only process relative URLs if a basedir is provided (i.e. no absolute local paths) + !empty($basedir) + // Ignore URLs containing parent dir traversal (..) + && (strpos($url, '..') === false) + // Do not change urls that are already inline images + && 0 !== strpos($url, 'cid:') + // Do not change absolute URLs, including anonymous protocol + && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url) + ) { + $filename = static::mb_pathinfo($url, PATHINFO_BASENAME); + $directory = dirname($url); + if ('.' === $directory) { + $directory = ''; + } + // RFC2392 S 2 + $cid = substr(hash('sha256', $url), 0, 32) . '@phpmailer.0'; + if (strlen($basedir) > 1 && '/' !== substr($basedir, -1)) { + $basedir .= '/'; + } + if (strlen($directory) > 1 && '/' !== substr($directory, -1)) { + $directory .= '/'; + } + if ($this->addEmbeddedImage( + $basedir . $directory . $filename, + $cid, + $filename, + static::ENCODING_BASE64, + static::_mime_types((string) static::mb_pathinfo($filename, PATHINFO_EXTENSION)) + ) + ) { + $message = preg_replace( + '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui', + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + } + } + } + } + $this->isHTML(); + // Convert all message body line breaks to LE, makes quoted-printable encoding work much better + $this->Body = static::normalizeBreaks($message); + $this->AltBody = static::normalizeBreaks($this->html2text($message, $advanced)); + if (!$this->alternativeExists()) { + $this->AltBody = 'This is an HTML-only message. To view it, activate HTML in your email application.' + . static::$LE; + } + + return $this->Body; + } + + /** + * Convert an HTML string into plain text. + * This is used by msgHTML(). + * Note - older versions of this function used a bundled advanced converter + * which was removed for license reasons in #232. + * Example usage: + * + * ```php + * // Use default conversion + * $plain = $mail->html2text($html); + * // Use your own custom converter + * $plain = $mail->html2text($html, function($html) { + * $converter = new MyHtml2text($html); + * return $converter->get_text(); + * }); + * ``` + * + * @param string $html The HTML text to convert + * @param bool|callable $advanced Any boolean value to use the internal converter, + * or provide your own callable for custom conversion + * + * @return string + */ + public function html2text($html, $advanced = false) + { + if (is_callable($advanced)) { + return $advanced($html); + } + + return html_entity_decode( + trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))), + ENT_QUOTES, + $this->CharSet + ); + } + + /** + * Get the MIME type for a file extension. + * + * @param string $ext File extension + * + * @return string MIME type of file + */ + public static function _mime_types($ext = '') + { + $mimes = [ + 'xl' => 'application/excel', + 'js' => 'application/javascript', + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'bin' => 'application/macbinary', + 'doc' => 'application/msword', + 'word' => 'application/msword', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'class' => 'application/octet-stream', + 'dll' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'exe' => 'application/octet-stream', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'psd' => 'application/octet-stream', + 'sea' => 'application/octet-stream', + 'so' => 'application/octet-stream', + 'oda' => 'application/oda', + 'pdf' => 'application/pdf', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'mif' => 'application/vnd.mif', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'gtar' => 'application/x-gtar', + 'php3' => 'application/x-httpd-php', + 'php4' => 'application/x-httpd-php', + 'php' => 'application/x-httpd-php', + 'phtml' => 'application/x-httpd-php', + 'phps' => 'application/x-httpd-php-source', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'tar' => 'application/x-tar', + 'tgz' => 'application/x-tar', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'zip' => 'application/zip', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'm4a' => 'audio/mp4', + 'mpga' => 'audio/mpeg', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'ra' => 'audio/x-realaudio', + 'wav' => 'audio/x-wav', + 'mka' => 'audio/x-matroska', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'png' => 'image/png', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'webp' => 'image/webp', + 'heif' => 'image/heif', + 'heifs' => 'image/heif-sequence', + 'heic' => 'image/heic', + 'heics' => 'image/heic-sequence', + 'eml' => 'message/rfc822', + 'css' => 'text/css', + 'html' => 'text/html', + 'htm' => 'text/html', + 'shtml' => 'text/html', + 'log' => 'text/plain', + 'text' => 'text/plain', + 'txt' => 'text/plain', + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'vcf' => 'text/vcard', + 'vcard' => 'text/vcard', + 'ics' => 'text/calendar', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'wmv' => 'video/x-ms-wmv', + 'mpeg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mp4' => 'video/mp4', + 'm4v' => 'video/mp4', + 'mov' => 'video/quicktime', + 'qt' => 'video/quicktime', + 'rv' => 'video/vnd.rn-realvideo', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie', + 'webm' => 'video/webm', + 'mkv' => 'video/x-matroska', + ]; + $ext = strtolower($ext); + if (array_key_exists($ext, $mimes)) { + return $mimes[$ext]; + } + + return 'application/octet-stream'; + } + + /** + * Map a file name to a MIME type. + * Defaults to 'application/octet-stream', i.e.. arbitrary binary data. + * + * @param string $filename A file name or full path, does not need to exist as a file + * + * @return string + */ + public static function filenameToType($filename) + { + // In case the path is a URL, strip any query string before getting extension + $qpos = strpos($filename, '?'); + if (false !== $qpos) { + $filename = substr($filename, 0, $qpos); + } + $ext = static::mb_pathinfo($filename, PATHINFO_EXTENSION); + + return static::_mime_types($ext); + } + + /** + * Multi-byte-safe pathinfo replacement. + * Drop-in replacement for pathinfo(), but multibyte- and cross-platform-safe. + * + * @see http://www.php.net/manual/en/function.pathinfo.php#107461 + * + * @param string $path A filename or path, does not need to exist as a file + * @param int|string $options Either a PATHINFO_* constant, + * or a string name to return only the specified piece + * + * @return string|array + */ + public static function mb_pathinfo($path, $options = null) + { + $ret = ['dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '']; + $pathinfo = []; + if (preg_match('#^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^.\\\\/]+?)|))[\\\\/.]*$#m', $path, $pathinfo)) { + if (array_key_exists(1, $pathinfo)) { + $ret['dirname'] = $pathinfo[1]; + } + if (array_key_exists(2, $pathinfo)) { + $ret['basename'] = $pathinfo[2]; + } + if (array_key_exists(5, $pathinfo)) { + $ret['extension'] = $pathinfo[5]; + } + if (array_key_exists(3, $pathinfo)) { + $ret['filename'] = $pathinfo[3]; + } + } + switch ($options) { + case PATHINFO_DIRNAME: + case 'dirname': + return $ret['dirname']; + case PATHINFO_BASENAME: + case 'basename': + return $ret['basename']; + case PATHINFO_EXTENSION: + case 'extension': + return $ret['extension']; + case PATHINFO_FILENAME: + case 'filename': + return $ret['filename']; + default: + return $ret; + } + } + + /** + * Set or reset instance properties. + * You should avoid this function - it's more verbose, less efficient, more error-prone and + * harder to debug than setting properties directly. + * Usage Example: + * `$mail->set('SMTPSecure', static::ENCRYPTION_STARTTLS);` + * is the same as: + * `$mail->SMTPSecure = static::ENCRYPTION_STARTTLS;`. + * + * @param string $name The property name to set + * @param mixed $value The value to set the property to + * + * @return bool + */ + public function set($name, $value = '') + { + if (property_exists($this, $name)) { + $this->$name = $value; + + return true; + } + $this->setError($this->lang('variable_set') . $name); + + return false; + } + + /** + * Strip newlines to prevent header injection. + * + * @param string $str + * + * @return string + */ + public function secureHeader($str) + { + return trim(str_replace(["\r", "\n"], '', $str)); + } + + /** + * Normalize line breaks in a string. + * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format. + * Defaults to CRLF (for message bodies) and preserves consecutive breaks. + * + * @param string $text + * @param string $breaktype What kind of line break to use; defaults to static::$LE + * + * @return string + */ + public static function normalizeBreaks($text, $breaktype = null) + { + if (null === $breaktype) { + $breaktype = static::$LE; + } + // Normalise to \n + $text = str_replace(["\r\n", "\r"], "\n", $text); + // Now convert LE as needed + if ("\n" !== $breaktype) { + $text = str_replace("\n", $breaktype, $text); + } + + return $text; + } + + /** + * Return the current line break format string. + * + * @return string + */ + public static function getLE() + { + return static::$LE; + } + + /** + * Set the line break format string, e.g. "\r\n". + * + * @param string $le + */ + protected static function setLE($le) + { + static::$LE = $le; + } + + /** + * Set the public and private key files and password for S/MIME signing. + * + * @param string $cert_filename + * @param string $key_filename + * @param string $key_pass Password for private key + * @param string $extracerts_filename Optional path to chain certificate + */ + public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '') + { + $this->sign_cert_file = $cert_filename; + $this->sign_key_file = $key_filename; + $this->sign_key_pass = $key_pass; + $this->sign_extracerts_file = $extracerts_filename; + } + + /** + * Quoted-Printable-encode a DKIM header. + * + * @param string $txt + * + * @return string + */ + public function DKIM_QP($txt) + { + $line = ''; + $len = strlen($txt); + for ($i = 0; $i < $len; ++$i) { + $ord = ord($txt[$i]); + if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord === 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) { + $line .= $txt[$i]; + } else { + $line .= '=' . sprintf('%02X', $ord); + } + } + + return $line; + } + + /** + * Generate a DKIM signature. + * + * @param string $signHeader + * + * @throws Exception + * + * @return string The DKIM signature value + */ + public function DKIM_Sign($signHeader) + { + if (!defined('PKCS7_TEXT')) { + if ($this->exceptions) { + throw new Exception($this->lang('extension_missing') . 'openssl'); + } + + return ''; + } + $privKeyStr = !empty($this->DKIM_private_string) ? + $this->DKIM_private_string : + file_get_contents($this->DKIM_private); + if ('' !== $this->DKIM_passphrase) { + $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); + } else { + $privKey = openssl_pkey_get_private($privKeyStr); + } + if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) { + openssl_pkey_free($privKey); + + return base64_encode($signature); + } + openssl_pkey_free($privKey); + + return ''; + } + + /** + * Generate a DKIM canonicalization header. + * Uses the 'relaxed' algorithm from RFC6376 section 3.4.2. + * Canonicalized headers should *always* use CRLF, regardless of mailer setting. + * + * @see https://tools.ietf.org/html/rfc6376#section-3.4.2 + * + * @param string $signHeader Header + * + * @return string + */ + public function DKIM_HeaderC($signHeader) + { + //Note PCRE \s is too broad a definition of whitespace; RFC5322 defines it as `[ \t]` + //@see https://tools.ietf.org/html/rfc5322#section-2.2 + //That means this may break if you do something daft like put vertical tabs in your headers. + //Unfold header lines + $signHeader = preg_replace('/\r\n[ \t]+/', ' ', $signHeader); + //Break headers out into an array + $lines = explode("\r\n", $signHeader); + foreach ($lines as $key => $line) { + //If the header is missing a :, skip it as it's invalid + //This is likely to happen because the explode() above will also split + //on the trailing LE, leaving an empty line + if (strpos($line, ':') === false) { + continue; + } + list($heading, $value) = explode(':', $line, 2); + //Lower-case header name + $heading = strtolower($heading); + //Collapse white space within the value, also convert WSP to space + $value = preg_replace('/[ \t]+/', ' ', $value); + //RFC6376 is slightly unclear here - it says to delete space at the *end* of each value + //But then says to delete space before and after the colon. + //Net result is the same as trimming both ends of the value. + //By elimination, the same applies to the field name + $lines[$key] = trim($heading, " \t") . ':' . trim($value, " \t"); + } + + return implode("\r\n", $lines); + } + + /** + * Generate a DKIM canonicalization body. + * Uses the 'simple' algorithm from RFC6376 section 3.4.3. + * Canonicalized bodies should *always* use CRLF, regardless of mailer setting. + * + * @see https://tools.ietf.org/html/rfc6376#section-3.4.3 + * + * @param string $body Message Body + * + * @return string + */ + public function DKIM_BodyC($body) + { + if (empty($body)) { + return "\r\n"; + } + // Normalize line endings to CRLF + $body = static::normalizeBreaks($body, "\r\n"); + + //Reduce multiple trailing line breaks to a single one + return rtrim($body, "\r\n") . "\r\n"; + } + + /** + * Create the DKIM header and body in a new message header. + * + * @param string $headers_line Header lines + * @param string $subject Subject + * @param string $body Body + * + * @throws Exception + * + * @return string + */ + public function DKIM_Add($headers_line, $subject, $body) + { + $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms + $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization methods of header & body + $DKIMquery = 'dns/txt'; // Query method + $DKIMtime = time(); + //Always sign these headers without being asked + $autoSignHeaders = [ + 'From', + 'To', + 'CC', + 'Date', + 'Subject', + 'Reply-To', + 'Message-ID', + 'Content-Type', + 'Mime-Version', + 'X-Mailer', + ]; + if (stripos($headers_line, 'Subject') === false) { + $headers_line .= 'Subject: ' . $subject . static::$LE; + } + $headerLines = explode(static::$LE, $headers_line); + $currentHeaderLabel = ''; + $currentHeaderValue = ''; + $parsedHeaders = []; + $headerLineIndex = 0; + $headerLineCount = count($headerLines); + foreach ($headerLines as $headerLine) { + $matches = []; + if (preg_match('/^([^ \t]*?)(?::[ \t]*)(.*)$/', $headerLine, $matches)) { + if ($currentHeaderLabel !== '') { + //We were previously in another header; This is the start of a new header, so save the previous one + $parsedHeaders[] = ['label' => $currentHeaderLabel, 'value' => $currentHeaderValue]; + } + $currentHeaderLabel = $matches[1]; + $currentHeaderValue = $matches[2]; + } elseif (preg_match('/^[ \t]+(.*)$/', $headerLine, $matches)) { + //This is a folded continuation of the current header, so unfold it + $currentHeaderValue .= ' ' . $matches[1]; + } + ++$headerLineIndex; + if ($headerLineIndex >= $headerLineCount) { + //This was the last line, so finish off this header + $parsedHeaders[] = ['label' => $currentHeaderLabel, 'value' => $currentHeaderValue]; + } + } + $copiedHeaders = []; + $headersToSignKeys = []; + $headersToSign = []; + foreach ($parsedHeaders as $header) { + //Is this header one that must be included in the DKIM signature? + if (in_array($header['label'], $autoSignHeaders, true)) { + $headersToSignKeys[] = $header['label']; + $headersToSign[] = $header['label'] . ': ' . $header['value']; + if ($this->DKIM_copyHeaderFields) { + $copiedHeaders[] = $header['label'] . ':' . //Note no space after this, as per RFC + str_replace('|', '=7C', $this->DKIM_QP($header['value'])); + } + continue; + } + //Is this an extra custom header we've been asked to sign? + if (in_array($header['label'], $this->DKIM_extraHeaders, true)) { + //Find its value in custom headers + foreach ($this->CustomHeader as $customHeader) { + if ($customHeader[0] === $header['label']) { + $headersToSignKeys[] = $header['label']; + $headersToSign[] = $header['label'] . ': ' . $header['value']; + if ($this->DKIM_copyHeaderFields) { + $copiedHeaders[] = $header['label'] . ':' . //Note no space after this, as per RFC + str_replace('|', '=7C', $this->DKIM_QP($header['value'])); + } + //Skip straight to the next header + continue 2; + } + } + } + } + $copiedHeaderFields = ''; + if ($this->DKIM_copyHeaderFields && count($copiedHeaders) > 0) { + //Assemble a DKIM 'z' tag + $copiedHeaderFields = ' z='; + $first = true; + foreach ($copiedHeaders as $copiedHeader) { + if (!$first) { + $copiedHeaderFields .= static::$LE . ' |'; + } + //Fold long values + if (strlen($copiedHeader) > self::STD_LINE_LENGTH - 3) { + $copiedHeaderFields .= substr( + chunk_split($copiedHeader, self::STD_LINE_LENGTH - 3, static::$LE . ' '), + 0, + -strlen(static::$LE . ' ') + ); + } else { + $copiedHeaderFields .= $copiedHeader; + } + $first = false; + } + $copiedHeaderFields .= ';' . static::$LE; + } + $headerKeys = ' h=' . implode(':', $headersToSignKeys) . ';' . static::$LE; + $headerValues = implode(static::$LE, $headersToSign); + $body = $this->DKIM_BodyC($body); + $DKIMlen = strlen($body); // Length of body + $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body + $ident = ''; + if ('' !== $this->DKIM_identity) { + $ident = ' i=' . $this->DKIM_identity . ';' . static::$LE; + } + //The DKIM-Signature header is included in the signature *except for* the value of the `b` tag + //which is appended after calculating the signature + //https://tools.ietf.org/html/rfc6376#section-3.5 + $dkimSignatureHeader = 'DKIM-Signature: v=1;' . + ' d=' . $this->DKIM_domain . ';' . + ' s=' . $this->DKIM_selector . ';' . static::$LE . + ' a=' . $DKIMsignatureType . ';' . + ' q=' . $DKIMquery . ';' . + ' l=' . $DKIMlen . ';' . + ' t=' . $DKIMtime . ';' . + ' c=' . $DKIMcanonicalization . ';' . static::$LE . + $headerKeys . + $ident . + $copiedHeaderFields . + ' bh=' . $DKIMb64 . ';' . static::$LE . + ' b='; + //Canonicalize the set of headers + $canonicalizedHeaders = $this->DKIM_HeaderC( + $headerValues . static::$LE . $dkimSignatureHeader + ); + $signature = $this->DKIM_Sign($canonicalizedHeaders); + $signature = trim(chunk_split($signature, self::STD_LINE_LENGTH - 3, static::$LE . ' ')); + + return static::normalizeBreaks($dkimSignatureHeader . $signature) . static::$LE; + } + + /** + * Detect if a string contains a line longer than the maximum line length + * allowed by RFC 2822 section 2.1.1. + * + * @param string $str + * + * @return bool + */ + public static function hasLineLongerThanMax($str) + { + return (bool) preg_match('/^(.{' . (self::MAX_LINE_LENGTH + strlen(static::$LE)) . ',})/m', $str); + } + + /** + * Allows for public read access to 'to' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getToAddresses() + { + return $this->to; + } + + /** + * Allows for public read access to 'cc' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getCcAddresses() + { + return $this->cc; + } + + /** + * Allows for public read access to 'bcc' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getBccAddresses() + { + return $this->bcc; + } + + /** + * Allows for public read access to 'ReplyTo' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getReplyToAddresses() + { + return $this->ReplyTo; + } + + /** + * Allows for public read access to 'all_recipients' property. + * Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * + * @return array + */ + public function getAllRecipientAddresses() + { + return $this->all_recipients; + } + + /** + * Perform a callback. + * + * @param bool $isSent + * @param array $to + * @param array $cc + * @param array $bcc + * @param string $subject + * @param string $body + * @param string $from + * @param array $extra + */ + protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from, $extra) + { + if (!empty($this->action_function) && is_callable($this->action_function)) { + call_user_func($this->action_function, $isSent, $to, $cc, $bcc, $subject, $body, $from, $extra); + } + } + + /** + * Get the OAuth instance. + * + * @return OAuth + */ + public function getOAuth() + { + return $this->oauth; + } + + /** + * Set an OAuth instance. + */ + public function setOAuth(OAuth $oauth) + { + $this->oauth = $oauth; + } +} diff --git a/core/External/PHPMailer/POP3.php b/core/External/PHPMailer/POP3.php new file mode 100644 index 0000000..3b89c33 --- /dev/null +++ b/core/External/PHPMailer/POP3.php @@ -0,0 +1,419 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2019 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace External\PHPMailer; + +/** + * PHPMailer POP-Before-SMTP Authentication Class. + * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication. + * 1) This class does not support APOP authentication. + * 2) Opening and closing lots of POP3 connections can be quite slow. If you need + * to send a batch of emails then just perform the authentication once at the start, + * and then loop through your mail sending script. Providing this process doesn't + * take longer than the verification period lasts on your POP3 server, you should be fine. + * 3) This is really ancient technology; you should only need to use it to talk to very old systems. + * 4) This POP3 class is deliberately lightweight and incomplete, implementing just + * enough to do authentication. + * If you want a more complete class there are other POP3 classes for PHP available. + * + * @author Richard Davey (original author) + * @author Marcus Bointon (Synchro/coolbru) + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + */ +class POP3 +{ + /** + * The POP3 PHPMailer Version number. + * + * @var string + */ + const VERSION = '6.1.4'; + + /** + * Default POP3 port number. + * + * @var int + */ + const DEFAULT_PORT = 110; + + /** + * Default timeout in seconds. + * + * @var int + */ + const DEFAULT_TIMEOUT = 30; + + /** + * Debug display level. + * Options: 0 = no, 1+ = yes. + * + * @var int + */ + public $do_debug = 0; + + /** + * POP3 mail server hostname. + * + * @var string + */ + public $host; + + /** + * POP3 port number. + * + * @var int + */ + public $port; + + /** + * POP3 Timeout Value in seconds. + * + * @var int + */ + public $tval; + + /** + * POP3 username. + * + * @var string + */ + public $username; + + /** + * POP3 password. + * + * @var string + */ + public $password; + + /** + * Resource handle for the POP3 connection socket. + * + * @var resource + */ + protected $pop_conn; + + /** + * Are we connected? + * + * @var bool + */ + protected $connected = false; + + /** + * Error container. + * + * @var array + */ + protected $errors = []; + + /** + * Line break constant. + */ + const LE = "\r\n"; + + /** + * Simple static wrapper for all-in-one POP before SMTP. + * + * @param string $host The hostname to connect to + * @param int|bool $port The port number to connect to + * @param int|bool $timeout The timeout value + * @param string $username + * @param string $password + * @param int $debug_level + * + * @return bool + */ + public static function popBeforeSmtp( + $host, + $port = false, + $timeout = false, + $username = '', + $password = '', + $debug_level = 0 + ) { + $pop = new self(); + + return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level); + } + + /** + * Authenticate with a POP3 server. + * A connect, login, disconnect sequence + * appropriate for POP-before SMTP authorisation. + * + * @param string $host The hostname to connect to + * @param int|bool $port The port number to connect to + * @param int|bool $timeout The timeout value + * @param string $username + * @param string $password + * @param int $debug_level + * + * @return bool + */ + public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0) + { + $this->host = $host; + // If no port value provided, use default + if (false === $port) { + $this->port = static::DEFAULT_PORT; + } else { + $this->port = (int) $port; + } + // If no timeout value provided, use default + if (false === $timeout) { + $this->tval = static::DEFAULT_TIMEOUT; + } else { + $this->tval = (int) $timeout; + } + $this->do_debug = $debug_level; + $this->username = $username; + $this->password = $password; + // Reset the error log + $this->errors = []; + // connect + $result = $this->connect($this->host, $this->port, $this->tval); + if ($result) { + $login_result = $this->login($this->username, $this->password); + if ($login_result) { + $this->disconnect(); + + return true; + } + } + // We need to disconnect regardless of whether the login succeeded + $this->disconnect(); + + return false; + } + + /** + * Connect to a POP3 server. + * + * @param string $host + * @param int|bool $port + * @param int $tval + * + * @return bool + */ + public function connect($host, $port = false, $tval = 30) + { + // Are we already connected? + if ($this->connected) { + return true; + } + + //On Windows this will raise a PHP Warning error if the hostname doesn't exist. + //Rather than suppress it with @fsockopen, capture it cleanly instead + set_error_handler([$this, 'catchWarning']); + + if (false === $port) { + $port = static::DEFAULT_PORT; + } + + // connect to the POP3 server + $this->pop_conn = fsockopen( + $host, // POP3 Host + $port, // Port # + $errno, // Error Number + $errstr, // Error Message + $tval + ); // Timeout (seconds) + // Restore the error handler + restore_error_handler(); + + // Did we connect? + if (false === $this->pop_conn) { + // It would appear not... + $this->setError( + "Failed to connect to server $host on port $port. errno: $errno; errstr: $errstr" + ); + + return false; + } + + // Increase the stream time-out + stream_set_timeout($this->pop_conn, $tval, 0); + + // Get the POP3 server response + $pop3_response = $this->getResponse(); + // Check for the +OK + if ($this->checkResponse($pop3_response)) { + // The connection is established and the POP3 server is talking + $this->connected = true; + + return true; + } + + return false; + } + + /** + * Log in to the POP3 server. + * Does not support APOP (RFC 2828, 4949). + * + * @param string $username + * @param string $password + * + * @return bool + */ + public function login($username = '', $password = '') + { + if (!$this->connected) { + $this->setError('Not connected to POP3 server'); + } + if (empty($username)) { + $username = $this->username; + } + if (empty($password)) { + $password = $this->password; + } + + // Send the Username + $this->sendString("USER $username" . static::LE); + $pop3_response = $this->getResponse(); + if ($this->checkResponse($pop3_response)) { + // Send the Password + $this->sendString("PASS $password" . static::LE); + $pop3_response = $this->getResponse(); + if ($this->checkResponse($pop3_response)) { + return true; + } + } + + return false; + } + + /** + * Disconnect from the POP3 server. + */ + public function disconnect() + { + $this->sendString('QUIT'); + //The QUIT command may cause the daemon to exit, which will kill our connection + //So ignore errors here + try { + @fclose($this->pop_conn); + } catch (Exception $e) { + //Do nothing + } + } + + /** + * Get a response from the POP3 server. + * + * @param int $size The maximum number of bytes to retrieve + * + * @return string + */ + protected function getResponse($size = 128) + { + $response = fgets($this->pop_conn, $size); + if ($this->do_debug >= 1) { + echo 'Server -> Client: ', $response; + } + + return $response; + } + + /** + * Send raw data to the POP3 server. + * + * @param string $string + * + * @return int + */ + protected function sendString($string) + { + if ($this->pop_conn) { + if ($this->do_debug >= 2) { //Show client messages when debug >= 2 + echo 'Client -> Server: ', $string; + } + + return fwrite($this->pop_conn, $string, strlen($string)); + } + + return 0; + } + + /** + * Checks the POP3 server response. + * Looks for for +OK or -ERR. + * + * @param string $string + * + * @return bool + */ + protected function checkResponse($string) + { + if (strpos($string, '+OK') !== 0) { + $this->setError("Server reported an error: $string"); + + return false; + } + + return true; + } + + /** + * Add an error to the internal error store. + * Also display debug output if it's enabled. + * + * @param string $error + */ + protected function setError($error) + { + $this->errors[] = $error; + if ($this->do_debug >= 1) { + echo '
    ';
    +            foreach ($this->errors as $e) {
    +                print_r($e);
    +            }
    +            echo '
    '; + } + } + + /** + * Get an array of error messages, if any. + * + * @return array + */ + public function getErrors() + { + return $this->errors; + } + + /** + * POP3 connection error handler. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + */ + protected function catchWarning($errno, $errstr, $errfile, $errline) + { + $this->setError( + 'Connecting to the POP3 server raised a PHP warning:' . + "errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline" + ); + } +} diff --git a/core/External/PHPMailer/SMTP.php b/core/External/PHPMailer/SMTP.php new file mode 100644 index 0000000..1f9c989 --- /dev/null +++ b/core/External/PHPMailer/SMTP.php @@ -0,0 +1,1370 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2019 Marcus Bointon + * @copyright 2010 - 2012 Jim Jagielski + * @copyright 2004 - 2009 Andy Prevost + * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License + * @note This program is distributed in the hope that it will be useful - WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +namespace External\PHPMailer; + +/** + * PHPMailer RFC821 SMTP email transport class. + * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. + * + * @author Chris Ryan + * @author Marcus Bointon + */ +class SMTP +{ + /** + * The PHPMailer SMTP version number. + * + * @var string + */ + const VERSION = '6.1.4'; + + /** + * SMTP line break constant. + * + * @var string + */ + const LE = "\r\n"; + + /** + * The SMTP port to use if one is not specified. + * + * @var int + */ + const DEFAULT_PORT = 25; + + /** + * The maximum line length allowed by RFC 5321 section 4.5.3.1.6, + * *excluding* a trailing CRLF break. + * + * @see https://tools.ietf.org/html/rfc5321#section-4.5.3.1.6 + * + * @var int + */ + const MAX_LINE_LENGTH = 998; + + /** + * The maximum line length allowed for replies in RFC 5321 section 4.5.3.1.5, + * *including* a trailing CRLF line break. + * + * @see https://tools.ietf.org/html/rfc5321#section-4.5.3.1.5 + * + * @var int + */ + const MAX_REPLY_LENGTH = 512; + + /** + * Debug level for no output. + * + * @var int + */ + const DEBUG_OFF = 0; + + /** + * Debug level to show client -> server messages. + * + * @var int + */ + const DEBUG_CLIENT = 1; + + /** + * Debug level to show client -> server and server -> client messages. + * + * @var int + */ + const DEBUG_SERVER = 2; + + /** + * Debug level to show connection status, client -> server and server -> client messages. + * + * @var int + */ + const DEBUG_CONNECTION = 3; + + /** + * Debug level to show all messages. + * + * @var int + */ + const DEBUG_LOWLEVEL = 4; + + /** + * Debug output level. + * Options: + * * self::DEBUG_OFF (`0`) No debug output, default + * * self::DEBUG_CLIENT (`1`) Client commands + * * self::DEBUG_SERVER (`2`) Client commands and server responses + * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status + * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages. + * + * @var int + */ + public $do_debug = self::DEBUG_OFF; + + /** + * How to handle debug output. + * Options: + * * `echo` Output plain-text as-is, appropriate for CLI + * * `html` Output escaped, line breaks converted to `
    `, appropriate for browser output + * * `error_log` Output to error log as configured in php.ini + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * ```php + * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * ``` + * + * Alternatively, you can pass in an instance of a PSR-3 compatible logger, though only `debug` + * level output is used: + * + * ```php + * $mail->Debugoutput = new myPsr3Logger; + * ``` + * + * @var string|callable|\Psr\Log\LoggerInterface + */ + public $Debugoutput = 'echo'; + + /** + * Whether to use VERP. + * + * @see http://en.wikipedia.org/wiki/Variable_envelope_return_path + * @see http://www.postfix.org/VERP_README.html Info on VERP + * + * @var bool + */ + public $do_verp = false; + + /** + * The timeout value for connection, in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure. + * + * @see http://tools.ietf.org/html/rfc2821#section-4.5.3.2 + * + * @var int + */ + public $Timeout = 300; + + /** + * How long to wait for commands to complete, in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2. + * + * @var int + */ + public $Timelimit = 300; + + /** + * Patterns to extract an SMTP transaction id from reply to a DATA command. + * The first capture group in each regex will be used as the ID. + * MS ESMTP returns the message ID, which may not be correct for internal tracking. + * + * @var string[] + */ + protected $smtp_transaction_id_patterns = [ + 'exim' => '/[\d]{3} OK id=(.*)/', + 'sendmail' => '/[\d]{3} 2.0.0 (.*) Message/', + 'postfix' => '/[\d]{3} 2.0.0 Ok: queued as (.*)/', + 'Microsoft_ESMTP' => '/[0-9]{3} 2.[\d].0 (.*)@(?:.*) Queued mail for delivery/', + 'Amazon_SES' => '/[\d]{3} Ok (.*)/', + 'SendGrid' => '/[\d]{3} Ok: queued as (.*)/', + 'CampaignMonitor' => '/[\d]{3} 2.0.0 OK:([a-zA-Z\d]{48})/', + ]; + + /** + * The last transaction ID issued in response to a DATA command, + * if one was detected. + * + * @var string|bool|null + */ + protected $last_smtp_transaction_id; + + /** + * The socket for the server connection. + * + * @var ?resource + */ + protected $smtp_conn; + + /** + * Error information, if any, for the last SMTP command. + * + * @var array + */ + protected $error = [ + 'error' => '', + 'detail' => '', + 'smtp_code' => '', + 'smtp_code_ex' => '', + ]; + + /** + * The reply the server sent to us for HELO. + * If null, no HELO string has yet been received. + * + * @var string|null + */ + protected $helo_rply; + + /** + * The set of SMTP extensions sent in reply to EHLO command. + * Indexes of the array are extension names. + * Value at index 'HELO' or 'EHLO' (according to command that was sent) + * represents the server name. In case of HELO it is the only element of the array. + * Other values can be boolean TRUE or an array containing extension options. + * If null, no HELO/EHLO string has yet been received. + * + * @var array|null + */ + protected $server_caps; + + /** + * The most recent reply received from the server. + * + * @var string + */ + protected $last_reply = ''; + + /** + * Output debugging info via a user-selected method. + * + * @param string $str Debug string to output + * @param int $level The debug level of this message; see DEBUG_* constants + * + * @see SMTP::$Debugoutput + * @see SMTP::$do_debug + */ + protected function edebug($str, $level = 0) + { + if ($level > $this->do_debug) { + return; + } + //Is this a PSR-3 logger? + if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) { + $this->Debugoutput->debug($str); + + return; + } + //Avoid clash with built-in function names + if (is_callable($this->Debugoutput) && !in_array($this->Debugoutput, ['error_log', 'html', 'echo'])) { + call_user_func($this->Debugoutput, $str, $level); + + return; + } + switch ($this->Debugoutput) { + case 'error_log': + //Don't output, just log + error_log($str); + break; + case 'html': + //Cleans up output a bit for a better looking, HTML-safe output + echo gmdate('Y-m-d H:i:s'), ' ', htmlentities( + preg_replace('/[\r\n]+/', '', $str), + ENT_QUOTES, + 'UTF-8' + ), "
    \n"; + break; + case 'echo': + default: + //Normalize line breaks + $str = preg_replace('/\r\n|\r/m', "\n", $str); + echo gmdate('Y-m-d H:i:s'), + "\t", + //Trim trailing space + trim( + //Indent for readability, except for trailing break + str_replace( + "\n", + "\n \t ", + trim($str) + ) + ), + "\n"; + } + } + + /** + * Connect to an SMTP server. + * + * @param string $host SMTP server IP or host name + * @param int $port The port number to connect to + * @param int $timeout How long to wait for the connection to open + * @param array $options An array of options for stream_context_create() + * + * @return bool + */ + public function connect($host, $port = null, $timeout = 30, $options = []) + { + static $streamok; + //This is enabled by default since 5.0.0 but some providers disable it + //Check this once and cache the result + if (null === $streamok) { + $streamok = function_exists('stream_socket_client'); + } + // Clear errors to avoid confusion + $this->setError(''); + // Make sure we are __not__ connected + if ($this->connected()) { + // Already connected, generate error + $this->setError('Already connected to a server'); + + return false; + } + if (empty($port)) { + $port = self::DEFAULT_PORT; + } + // Connect to the SMTP server + $this->edebug( + "Connection: opening to $host:$port, timeout=$timeout, options=" . + (count($options) > 0 ? var_export($options, true) : 'array()'), + self::DEBUG_CONNECTION + ); + $errno = 0; + $errstr = ''; + if ($streamok) { + $socket_context = stream_context_create($options); + set_error_handler([$this, 'errorHandler']); + $this->smtp_conn = stream_socket_client( + $host . ':' . $port, + $errno, + $errstr, + $timeout, + STREAM_CLIENT_CONNECT, + $socket_context + ); + restore_error_handler(); + } else { + //Fall back to fsockopen which should work in more places, but is missing some features + $this->edebug( + 'Connection: stream_socket_client not available, falling back to fsockopen', + self::DEBUG_CONNECTION + ); + set_error_handler([$this, 'errorHandler']); + $this->smtp_conn = fsockopen( + $host, + $port, + $errno, + $errstr, + $timeout + ); + restore_error_handler(); + } + // Verify we connected properly + if (!is_resource($this->smtp_conn)) { + $this->setError( + 'Failed to connect to server', + '', + (string) $errno, + $errstr + ); + $this->edebug( + 'SMTP ERROR: ' . $this->error['error'] + . ": $errstr ($errno)", + self::DEBUG_CLIENT + ); + + return false; + } + $this->edebug('Connection: opened', self::DEBUG_CONNECTION); + // SMTP server can take longer to respond, give longer timeout for first read + // Windows does not have support for this timeout function + if (strpos(PHP_OS, 'WIN') !== 0) { + $max = (int) ini_get('max_execution_time'); + // Don't bother if unlimited + if (0 !== $max && $timeout > $max) { + @set_time_limit($timeout); + } + stream_set_timeout($this->smtp_conn, $timeout, 0); + } + // Get any announcement + $announce = $this->get_lines(); + $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); + + return true; + } + + /** + * Initiate a TLS (encrypted) session. + * + * @return bool + */ + public function startTLS() + { + if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { + return false; + } + + //Allow the best TLS version(s) we can + $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT; + + //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT + //so add them back in manually if we can + if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) { + $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT; + } + + // Begin encrypted connection + set_error_handler([$this, 'errorHandler']); + $crypto_ok = stream_socket_enable_crypto( + $this->smtp_conn, + true, + $crypto_method + ); + restore_error_handler(); + + return (bool) $crypto_ok; + } + + /** + * Perform SMTP authentication. + * Must be run after hello(). + * + * @see hello() + * + * @param string $username The user name + * @param string $password The password + * @param string $authtype The auth type (CRAM-MD5, PLAIN, LOGIN, XOAUTH2) + * @param OAuth $OAuth An optional OAuth instance for XOAUTH2 authentication + * + * @return bool True if successfully authenticated + */ + public function authenticate( + $username, + $password, + $authtype = null, + $OAuth = null + ) { + if (!$this->server_caps) { + $this->setError('Authentication is not allowed before HELO/EHLO'); + + return false; + } + + if (array_key_exists('EHLO', $this->server_caps)) { + // SMTP extensions are available; try to find a proper authentication method + if (!array_key_exists('AUTH', $this->server_caps)) { + $this->setError('Authentication is not allowed at this stage'); + // 'at this stage' means that auth may be allowed after the stage changes + // e.g. after STARTTLS + + return false; + } + + $this->edebug('Auth method requested: ' . ($authtype ?: 'UNSPECIFIED'), self::DEBUG_LOWLEVEL); + $this->edebug( + 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), + self::DEBUG_LOWLEVEL + ); + + //If we have requested a specific auth type, check the server supports it before trying others + if (null !== $authtype && !in_array($authtype, $this->server_caps['AUTH'], true)) { + $this->edebug('Requested auth method not available: ' . $authtype, self::DEBUG_LOWLEVEL); + $authtype = null; + } + + if (empty($authtype)) { + //If no auth mechanism is specified, attempt to use these, in this order + //Try CRAM-MD5 first as it's more secure than the others + foreach (['CRAM-MD5', 'LOGIN', 'PLAIN', 'XOAUTH2'] as $method) { + if (in_array($method, $this->server_caps['AUTH'], true)) { + $authtype = $method; + break; + } + } + if (empty($authtype)) { + $this->setError('No supported authentication methods found'); + + return false; + } + $this->edebug('Auth method selected: ' . $authtype, self::DEBUG_LOWLEVEL); + } + + if (!in_array($authtype, $this->server_caps['AUTH'], true)) { + $this->setError("The requested authentication method \"$authtype\" is not supported by the server"); + + return false; + } + } elseif (empty($authtype)) { + $authtype = 'LOGIN'; + } + switch ($authtype) { + case 'PLAIN': + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { + return false; + } + // Send encoded username and password + if (!$this->sendCommand( + 'User & Password', + base64_encode("\0" . $username . "\0" . $password), + 235 + ) + ) { + return false; + } + break; + case 'LOGIN': + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { + return false; + } + if (!$this->sendCommand('Username', base64_encode($username), 334)) { + return false; + } + if (!$this->sendCommand('Password', base64_encode($password), 235)) { + return false; + } + break; + case 'CRAM-MD5': + // Start authentication + if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { + return false; + } + // Get the challenge + $challenge = base64_decode(substr($this->last_reply, 4)); + + // Build the response + $response = $username . ' ' . $this->hmac($challenge, $password); + + // send encoded credentials + return $this->sendCommand('Username', base64_encode($response), 235); + case 'XOAUTH2': + //The OAuth instance must be set up prior to requesting auth. + if (null === $OAuth) { + return false; + } + $oauth = $OAuth->getOauth64(); + + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { + return false; + } + break; + default: + $this->setError("Authentication method \"$authtype\" is not supported"); + + return false; + } + + return true; + } + + /** + * Calculate an MD5 HMAC hash. + * Works like hash_hmac('md5', $data, $key) + * in case that function is not available. + * + * @param string $data The data to hash + * @param string $key The key to hash with + * + * @return string + */ + protected function hmac($data, $key) + { + if (function_exists('hash_hmac')) { + return hash_hmac('md5', $data, $key); + } + + // The following borrowed from + // http://php.net/manual/en/function.mhash.php#27225 + + // RFC 2104 HMAC implementation for php. + // Creates an md5 HMAC. + // Eliminates the need to install mhash to compute a HMAC + // by Lance Rushing + + $bytelen = 64; // byte length for md5 + if (strlen($key) > $bytelen) { + $key = pack('H*', md5($key)); + } + $key = str_pad($key, $bytelen, chr(0x00)); + $ipad = str_pad('', $bytelen, chr(0x36)); + $opad = str_pad('', $bytelen, chr(0x5c)); + $k_ipad = $key ^ $ipad; + $k_opad = $key ^ $opad; + + return md5($k_opad . pack('H*', md5($k_ipad . $data))); + } + + /** + * Check connection state. + * + * @return bool True if connected + */ + public function connected() + { + if (is_resource($this->smtp_conn)) { + $sock_status = stream_get_meta_data($this->smtp_conn); + if ($sock_status['eof']) { + // The socket is valid but we are not connected + $this->edebug( + 'SMTP NOTICE: EOF caught while checking if connected', + self::DEBUG_CLIENT + ); + $this->close(); + + return false; + } + + return true; // everything looks good + } + + return false; + } + + /** + * Close the socket and clean up the state of the class. + * Don't use this function without first trying to use QUIT. + * + * @see quit() + */ + public function close() + { + $this->setError(''); + $this->server_caps = null; + $this->helo_rply = null; + if (is_resource($this->smtp_conn)) { + // close the connection and cleanup + fclose($this->smtp_conn); + $this->smtp_conn = null; //Makes for cleaner serialization + $this->edebug('Connection: closed', self::DEBUG_CONNECTION); + } + } + + /** + * Send an SMTP DATA command. + * Issues a data command and sends the msg_data to the server, + * finializing the mail transaction. $msg_data is the message + * that is to be send with the headers. Each header needs to be + * on a single line followed by a with the message headers + * and the message body being separated by an additional . + * Implements RFC 821: DATA . + * + * @param string $msg_data Message data to send + * + * @return bool + */ + public function data($msg_data) + { + //This will use the standard timelimit + if (!$this->sendCommand('DATA', 'DATA', 354)) { + return false; + } + + /* The server is ready to accept data! + * According to rfc821 we should not send more than 1000 characters on a single line (including the LE) + * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into + * smaller lines to fit within the limit. + * We will also look for lines that start with a '.' and prepend an additional '.'. + * NOTE: this does not count towards line-length limit. + */ + + // Normalize line breaks before exploding + $lines = explode("\n", str_replace(["\r\n", "\r"], "\n", $msg_data)); + + /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field + * of the first line (':' separated) does not contain a space then it _should_ be a header and we will + * process all lines before a blank line as headers. + */ + + $field = substr($lines[0], 0, strpos($lines[0], ':')); + $in_headers = false; + if (!empty($field) && strpos($field, ' ') === false) { + $in_headers = true; + } + + foreach ($lines as $line) { + $lines_out = []; + if ($in_headers && $line === '') { + $in_headers = false; + } + //Break this line up into several smaller lines if it's too long + //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len), + while (isset($line[self::MAX_LINE_LENGTH])) { + //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on + //so as to avoid breaking in the middle of a word + $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); + //Deliberately matches both false and 0 + if (!$pos) { + //No nice break found, add a hard break + $pos = self::MAX_LINE_LENGTH - 1; + $lines_out[] = substr($line, 0, $pos); + $line = substr($line, $pos); + } else { + //Break at the found point + $lines_out[] = substr($line, 0, $pos); + //Move along by the amount we dealt with + $line = substr($line, $pos + 1); + } + //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1 + if ($in_headers) { + $line = "\t" . $line; + } + } + $lines_out[] = $line; + + //Send the lines to the server + foreach ($lines_out as $line_out) { + //RFC2821 section 4.5.2 + if (!empty($line_out) && $line_out[0] === '.') { + $line_out = '.' . $line_out; + } + $this->client_send($line_out . static::LE, 'DATA'); + } + } + + //Message data has been sent, complete the command + //Increase timelimit for end of DATA command + $savetimelimit = $this->Timelimit; + $this->Timelimit *= 2; + $result = $this->sendCommand('DATA END', '.', 250); + $this->recordLastTransactionID(); + //Restore timelimit + $this->Timelimit = $savetimelimit; + + return $result; + } + + /** + * Send an SMTP HELO or EHLO command. + * Used to identify the sending server to the receiving server. + * This makes sure that client and server are in a known state. + * Implements RFC 821: HELO + * and RFC 2821 EHLO. + * + * @param string $host The host name or IP to connect to + * + * @return bool + */ + public function hello($host = '') + { + //Try extended hello first (RFC 2821) + return $this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host); + } + + /** + * Send an SMTP HELO or EHLO command. + * Low-level implementation used by hello(). + * + * @param string $hello The HELO string + * @param string $host The hostname to say we are + * + * @return bool + * + * @see hello() + */ + protected function sendHello($hello, $host) + { + $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); + $this->helo_rply = $this->last_reply; + if ($noerror) { + $this->parseHelloFields($hello); + } else { + $this->server_caps = null; + } + + return $noerror; + } + + /** + * Parse a reply to HELO/EHLO command to discover server extensions. + * In case of HELO, the only parameter that can be discovered is a server name. + * + * @param string $type `HELO` or `EHLO` + */ + protected function parseHelloFields($type) + { + $this->server_caps = []; + $lines = explode("\n", $this->helo_rply); + + foreach ($lines as $n => $s) { + //First 4 chars contain response code followed by - or space + $s = trim(substr($s, 4)); + if (empty($s)) { + continue; + } + $fields = explode(' ', $s); + if (!empty($fields)) { + if (!$n) { + $name = $type; + $fields = $fields[0]; + } else { + $name = array_shift($fields); + switch ($name) { + case 'SIZE': + $fields = ($fields ? $fields[0] : 0); + break; + case 'AUTH': + if (!is_array($fields)) { + $fields = []; + } + break; + default: + $fields = true; + } + } + $this->server_caps[$name] = $fields; + } + } + } + + /** + * Send an SMTP MAIL command. + * Starts a mail transaction from the email address specified in + * $from. Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more recipient + * commands may be called followed by a data command. + * Implements RFC 821: MAIL FROM: . + * + * @param string $from Source address of this message + * + * @return bool + */ + public function mail($from) + { + $useVerp = ($this->do_verp ? ' XVERP' : ''); + + return $this->sendCommand( + 'MAIL FROM', + 'MAIL FROM:<' . $from . '>' . $useVerp, + 250 + ); + } + + /** + * Send an SMTP QUIT command. + * Closes the socket if there is no error or the $close_on_error argument is true. + * Implements from RFC 821: QUIT . + * + * @param bool $close_on_error Should the connection close if an error occurs? + * + * @return bool + */ + public function quit($close_on_error = true) + { + $noerror = $this->sendCommand('QUIT', 'QUIT', 221); + $err = $this->error; //Save any error + if ($noerror || $close_on_error) { + $this->close(); + $this->error = $err; //Restore any error from the quit command + } + + return $noerror; + } + + /** + * Send an SMTP RCPT command. + * Sets the TO argument to $toaddr. + * Returns true if the recipient was accepted false if it was rejected. + * Implements from RFC 821: RCPT TO: . + * + * @param string $address The address the message is being sent to + * @param string $dsn Comma separated list of DSN notifications. NEVER, SUCCESS, FAILURE + * or DELAY. If you specify NEVER all other notifications are ignored. + * + * @return bool + */ + public function recipient($address, $dsn = '') + { + if (empty($dsn)) { + $rcpt = 'RCPT TO:<' . $address . '>'; + } else { + $dsn = strtoupper($dsn); + $notify = []; + + if (strpos($dsn, 'NEVER') !== false) { + $notify[] = 'NEVER'; + } else { + foreach (['SUCCESS', 'FAILURE', 'DELAY'] as $value) { + if (strpos($dsn, $value) !== false) { + $notify[] = $value; + } + } + } + + $rcpt = 'RCPT TO:<' . $address . '> NOTIFY=' . implode(',', $notify); + } + + return $this->sendCommand( + 'RCPT TO', + $rcpt, + [250, 251] + ); + } + + /** + * Send an SMTP RSET command. + * Abort any transaction that is currently in progress. + * Implements RFC 821: RSET . + * + * @return bool True on success + */ + public function reset() + { + return $this->sendCommand('RSET', 'RSET', 250); + } + + /** + * Send a command to an SMTP server and check its return code. + * + * @param string $command The command name - not sent to the server + * @param string $commandstring The actual command to send + * @param int|array $expect One or more expected integer success codes + * + * @return bool True on success + */ + protected function sendCommand($command, $commandstring, $expect) + { + if (!$this->connected()) { + $this->setError("Called $command without being connected"); + + return false; + } + //Reject line breaks in all commands + if ((strpos($commandstring, "\n") !== false) || (strpos($commandstring, "\r") !== false)) { + $this->setError("Command '$command' contained line breaks"); + + return false; + } + $this->client_send($commandstring . static::LE, $command); + + $this->last_reply = $this->get_lines(); + // Fetch SMTP code and possible error code explanation + $matches = []; + if (preg_match('/^([\d]{3})[ -](?:([\d]\\.[\d]\\.[\d]{1,2}) )?/', $this->last_reply, $matches)) { + $code = (int) $matches[1]; + $code_ex = (count($matches) > 2 ? $matches[2] : null); + // Cut off error code from each response line + $detail = preg_replace( + "/{$code}[ -]" . + ($code_ex ? str_replace('.', '\\.', $code_ex) . ' ' : '') . '/m', + '', + $this->last_reply + ); + } else { + // Fall back to simple parsing if regex fails + $code = (int) substr($this->last_reply, 0, 3); + $code_ex = null; + $detail = substr($this->last_reply, 4); + } + + $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); + + if (!in_array($code, (array) $expect, true)) { + $this->setError( + "$command command failed", + $detail, + $code, + $code_ex + ); + $this->edebug( + 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, + self::DEBUG_CLIENT + ); + + return false; + } + + $this->setError(''); + + return true; + } + + /** + * Send an SMTP SAML command. + * Starts a mail transaction from the email address specified in $from. + * Returns true if successful or false otherwise. If True + * the mail transaction is started and then one or more recipient + * commands may be called followed by a data command. This command + * will send the message to the users terminal if they are logged + * in and send them an email. + * Implements RFC 821: SAML FROM: . + * + * @param string $from The address the message is from + * + * @return bool + */ + public function sendAndMail($from) + { + return $this->sendCommand('SAML', "SAML FROM:$from", 250); + } + + /** + * Send an SMTP VRFY command. + * + * @param string $name The name to verify + * + * @return bool + */ + public function verify($name) + { + return $this->sendCommand('VRFY', "VRFY $name", [250, 251]); + } + + /** + * Send an SMTP NOOP command. + * Used to keep keep-alives alive, doesn't actually do anything. + * + * @return bool + */ + public function noop() + { + return $this->sendCommand('NOOP', 'NOOP', 250); + } + + /** + * Send an SMTP TURN command. + * This is an optional command for SMTP that this class does not support. + * This method is here to make the RFC821 Definition complete for this class + * and _may_ be implemented in future. + * Implements from RFC 821: TURN . + * + * @return bool + */ + public function turn() + { + $this->setError('The SMTP TURN command is not implemented'); + $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); + + return false; + } + + /** + * Send raw data to the server. + * + * @param string $data The data to send + * @param string $command Optionally, the command this is part of, used only for controlling debug output + * + * @return int|bool The number of bytes sent to the server or false on error + */ + public function client_send($data, $command = '') + { + //If SMTP transcripts are left enabled, or debug output is posted online + //it can leak credentials, so hide credentials in all but lowest level + if (self::DEBUG_LOWLEVEL > $this->do_debug && + in_array($command, ['User & Password', 'Username', 'Password'], true)) { + $this->edebug('CLIENT -> SERVER: [credentials hidden]', self::DEBUG_CLIENT); + } else { + $this->edebug('CLIENT -> SERVER: ' . $data, self::DEBUG_CLIENT); + } + set_error_handler([$this, 'errorHandler']); + $result = fwrite($this->smtp_conn, $data); + restore_error_handler(); + + return $result; + } + + /** + * Get the latest error. + * + * @return array + */ + public function getError() + { + return $this->error; + } + + /** + * Get SMTP extensions available on the server. + * + * @return array|null + */ + public function getServerExtList() + { + return $this->server_caps; + } + + /** + * Get metadata about the SMTP server from its HELO/EHLO response. + * The method works in three ways, dependent on argument value and current state: + * 1. HELO/EHLO has not been sent - returns null and populates $this->error. + * 2. HELO has been sent - + * $name == 'HELO': returns server name + * $name == 'EHLO': returns boolean false + * $name == any other string: returns null and populates $this->error + * 3. EHLO has been sent - + * $name == 'HELO'|'EHLO': returns the server name + * $name == any other string: if extension $name exists, returns True + * or its options (e.g. AUTH mechanisms supported). Otherwise returns False. + * + * @param string $name Name of SMTP extension or 'HELO'|'EHLO' + * + * @return string|bool|null + */ + public function getServerExt($name) + { + if (!$this->server_caps) { + $this->setError('No HELO/EHLO was sent'); + + return; + } + + if (!array_key_exists($name, $this->server_caps)) { + if ('HELO' === $name) { + return $this->server_caps['EHLO']; + } + if ('EHLO' === $name || array_key_exists('EHLO', $this->server_caps)) { + return false; + } + $this->setError('HELO handshake was used; No information about server extensions available'); + + return; + } + + return $this->server_caps[$name]; + } + + /** + * Get the last reply from the server. + * + * @return string + */ + public function getLastReply() + { + return $this->last_reply; + } + + /** + * Read the SMTP server's response. + * Either before eof or socket timeout occurs on the operation. + * With SMTP we can tell if we have more lines to read if the + * 4th character is '-' symbol. If it is a space then we don't + * need to read anything else. + * + * @return string + */ + protected function get_lines() + { + // If the connection is bad, give up straight away + if (!is_resource($this->smtp_conn)) { + return ''; + } + $data = ''; + $endtime = 0; + stream_set_timeout($this->smtp_conn, $this->Timeout); + if ($this->Timelimit > 0) { + $endtime = time() + $this->Timelimit; + } + $selR = [$this->smtp_conn]; + $selW = null; + while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { + //Must pass vars in here as params are by reference + if (!stream_select($selR, $selW, $selW, $this->Timelimit)) { + $this->edebug( + 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + //Deliberate noise suppression - errors are handled afterwards + $str = @fgets($this->smtp_conn, self::MAX_REPLY_LENGTH); + $this->edebug('SMTP INBOUND: "' . trim($str) . '"', self::DEBUG_LOWLEVEL); + $data .= $str; + // If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled), + // or 4th character is a space or a line break char, we are done reading, break the loop. + // String array access is a significant micro-optimisation over strlen + if (!isset($str[3]) || $str[3] === ' ' || $str[3] === "\r" || $str[3] === "\n") { + break; + } + // Timed-out? Log and break + $info = stream_get_meta_data($this->smtp_conn); + if ($info['timed_out']) { + $this->edebug( + 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + // Now check if reads took too long + if ($endtime && time() > $endtime) { + $this->edebug( + 'SMTP -> get_lines(): timelimit reached (' . + $this->Timelimit . ' sec)', + self::DEBUG_LOWLEVEL + ); + break; + } + } + + return $data; + } + + /** + * Enable or disable VERP address generation. + * + * @param bool $enabled + */ + public function setVerp($enabled = false) + { + $this->do_verp = $enabled; + } + + /** + * Get VERP address generation mode. + * + * @return bool + */ + public function getVerp() + { + return $this->do_verp; + } + + /** + * Set error messages and codes. + * + * @param string $message The error message + * @param string $detail Further detail on the error + * @param string $smtp_code An associated SMTP error code + * @param string $smtp_code_ex Extended SMTP code + */ + protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '') + { + $this->error = [ + 'error' => $message, + 'detail' => $detail, + 'smtp_code' => $smtp_code, + 'smtp_code_ex' => $smtp_code_ex, + ]; + } + + /** + * Set debug output method. + * + * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it + */ + public function setDebugOutput($method = 'echo') + { + $this->Debugoutput = $method; + } + + /** + * Get debug output method. + * + * @return string + */ + public function getDebugOutput() + { + return $this->Debugoutput; + } + + /** + * Set debug output level. + * + * @param int $level + */ + public function setDebugLevel($level = 0) + { + $this->do_debug = $level; + } + + /** + * Get debug output level. + * + * @return int + */ + public function getDebugLevel() + { + return $this->do_debug; + } + + /** + * Set SMTP timeout. + * + * @param int $timeout The timeout duration in seconds + */ + public function setTimeout($timeout = 0) + { + $this->Timeout = $timeout; + } + + /** + * Get SMTP timeout. + * + * @return int + */ + public function getTimeout() + { + return $this->Timeout; + } + + /** + * Reports an error number and string. + * + * @param int $errno The error number returned by PHP + * @param string $errmsg The error message returned by PHP + * @param string $errfile The file the error occurred in + * @param int $errline The line number the error occurred on + */ + protected function errorHandler($errno, $errmsg, $errfile = '', $errline = 0) + { + $notice = 'Connection failed.'; + $this->setError( + $notice, + $errmsg, + (string) $errno + ); + $this->edebug( + "$notice Error #$errno: $errmsg [$errfile line $errline]", + self::DEBUG_CONNECTION + ); + } + + /** + * Extract and return the ID of the last SMTP transaction based on + * a list of patterns provided in SMTP::$smtp_transaction_id_patterns. + * Relies on the host providing the ID in response to a DATA command. + * If no reply has been received yet, it will return null. + * If no pattern was matched, it will return false. + * + * @return bool|string|null + */ + protected function recordLastTransactionID() + { + $reply = $this->getLastReply(); + + if (empty($reply)) { + $this->last_smtp_transaction_id = null; + } else { + $this->last_smtp_transaction_id = false; + foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) { + if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) { + $this->last_smtp_transaction_id = trim($matches[1]); + break; + } + } + } + + return $this->last_smtp_transaction_id; + } + + /** + * Get the queue/transaction ID of the last SMTP transaction + * If no reply has been received yet, it will return null. + * If no pattern was matched, it will return false. + * + * @return bool|string|null + * + * @see recordLastTransactionID() + */ + public function getLastTransactionID() + { + return $this->last_smtp_transaction_id; + } +} diff --git a/core/External/jwt.php b/core/External/jwt.php new file mode 100644 index 0000000..ad81484 --- /dev/null +++ b/core/External/jwt.php @@ -0,0 +1,199 @@ + + * @author Anant Narayanan + * @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD + * @link https://github.com/firebase/php-jwt + */ + +namespace External; + +class JWT +{ + /** + * Decodes a JWT string into a PHP object. + * + * @param string $jwt The JWT + * @param string|null $key The secret key + * @param bool $verify Don't skip verification process + * + * @return object The JWT's payload as a PHP object + * @throws UnexpectedValueException Provided JWT was invalid + * @throws DomainException Algorithm was not provided + * + * @uses jsonDecode + * @uses urlsafeB64Decode + */ + public static function decode($jwt, $key = null, $verify = true) + { + $tks = explode('.', $jwt); + if (count($tks) != 3) { + throw new UnexpectedValueException('Wrong number of segments'); + } + list($headb64, $bodyb64, $cryptob64) = $tks; + if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) { + throw new UnexpectedValueException('Invalid segment encoding'); + } + if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) { + throw new UnexpectedValueException('Invalid segment encoding'); + } + $sig = JWT::urlsafeB64Decode($cryptob64); + if ($verify) { + if (empty($header->alg)) { + throw new DomainException('Empty algorithm'); + } + if ($sig != JWT::sign("$headb64.$bodyb64", $key, $header->alg)) { + throw new UnexpectedValueException('Signature verification failed'); + } + } + return $payload; + } + + /** + * Converts and signs a PHP object or array into a JWT string. + * + * @param object|array $payload PHP object or array + * @param string $key The secret key + * @param string $algo The signing algorithm. Supported + * algorithms are 'HS256', 'HS384' and 'HS512' + * + * @return string A signed JWT + * @uses jsonEncode + * @uses urlsafeB64Encode + */ + public static function encode($payload, $key, $algo = 'HS256') + { + $header = array('typ' => 'JWT', 'alg' => $algo); + + $segments = array(); + $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header)); + $segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload)); + $signing_input = implode('.', $segments); + + $signature = JWT::sign($signing_input, $key, $algo); + $segments[] = JWT::urlsafeB64Encode($signature); + + return implode('.', $segments); + } + + /** + * Sign a string with a given key and algorithm. + * + * @param string $msg The message to sign + * @param string $key The secret key + * @param string $method The signing algorithm. Supported + * algorithms are 'HS256', 'HS384' and 'HS512' + * + * @return string An encrypted message + * @throws DomainException Unsupported algorithm was specified + */ + public static function sign($msg, $key, $method = 'HS256') + { + $methods = array( + 'HS256' => 'sha256', + 'HS384' => 'sha384', + 'HS512' => 'sha512', + ); + if (empty($methods[$method])) { + throw new DomainException('Algorithm not supported'); + } + return hash_hmac($methods[$method], $msg, $key, true); + } + + /** + * Decode a JSON string into a PHP object. + * + * @param string $input JSON string + * + * @return object Object representation of JSON string + * @throws DomainException Provided string was invalid JSON + */ + public static function jsonDecode($input) + { + $obj = json_decode($input); + if (function_exists('json_last_error') && $errno = json_last_error()) { + JWT::_handleJsonError($errno); + } else if ($obj === null && $input !== 'null') { + throw new DomainException('Null result with non-null input'); + } + return $obj; + } + + /** + * Encode a PHP object into a JSON string. + * + * @param object|array $input A PHP object or array + * + * @return string JSON representation of the PHP object or array + * @throws DomainException Provided object could not be encoded to valid JSON + */ + public static function jsonEncode($input) + { + $json = json_encode($input); + if (function_exists('json_last_error') && $errno = json_last_error()) { + JWT::_handleJsonError($errno); + } else if ($json === 'null' && $input !== null) { + throw new DomainException('Null result with non-null input'); + } + return $json; + } + + /** + * Decode a string with URL-safe Base64. + * + * @param string $input A Base64 encoded string + * + * @return string A decoded string + */ + public static function urlsafeB64Decode($input) + { + $remainder = strlen($input) % 4; + if ($remainder) { + $padlen = 4 - $remainder; + $input .= str_repeat('=', $padlen); + } + return base64_decode(strtr($input, '-_', '+/')); + } + + /** + * Encode a string with URL-safe Base64. + * + * @param string $input The string you want encoded + * + * @return string The base64 encode of what you passed in + */ + public static function urlsafeB64Encode($input) + { + return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); + } + + /** + * Helper method to create a JSON error. + * + * @param int $errno An error number from json_last_error() + * + * @return void + */ + private static function _handleJsonError($errno) + { + $messages = array( + JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', + JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON' + ); + throw new DomainException( + isset($messages[$errno]) + ? $messages[$errno] + : 'Unknown JSON error: ' . $errno + ); + } + +} diff --git a/core/External/phpQuery.php b/core/External/phpQuery.php new file mode 100644 index 0000000..703cb81 --- /dev/null +++ b/core/External/phpQuery.php @@ -0,0 +1,5702 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @package phpQuery + */ + +// class names for instanceof +// TODO move them as class constants into phpQuery +define('DOMDOCUMENT', 'DOMDocument'); +define('DOMELEMENT', 'DOMElement'); +define('DOMNODELIST', 'DOMNodeList'); +define('DOMNODE', 'DOMNode'); + +/** + * DOMEvent class. + * + * Based on + * @link http://developer.mozilla.org/En/DOM:event + * @author Tobiasz Cudnik + * @package phpQuery + * @todo implement ArrayAccess ? + */ +class DOMEvent { + /** + * Returns a boolean indicating whether the event bubbles up through the DOM or not. + * + * @var unknown_type + */ + public $bubbles = true; + /** + * Returns a boolean indicating whether the event is cancelable. + * + * @var unknown_type + */ + public $cancelable = true; + /** + * Returns a reference to the currently registered target for the event. + * + * @var unknown_type + */ + public $currentTarget; + /** + * Returns detail about the event, depending on the type of event. + * + * @var unknown_type + * @link http://developer.mozilla.org/en/DOM/event.detail + */ + public $detail; // ??? + /** + * Used to indicate which phase of the event flow is currently being evaluated. + * + * NOT IMPLEMENTED + * + * @var unknown_type + * @link http://developer.mozilla.org/en/DOM/event.eventPhase + */ + public $eventPhase; // ??? + /** + * The explicit original target of the event (Mozilla-specific). + * + * NOT IMPLEMENTED + * + * @var unknown_type + */ + public $explicitOriginalTarget; // moz only + /** + * The original target of the event, before any retargetings (Mozilla-specific). + * + * NOT IMPLEMENTED + * + * @var unknown_type + */ + public $originalTarget; // moz only + /** + * Identifies a secondary target for the event. + * + * @var unknown_type + */ + public $relatedTarget; + /** + * Returns a reference to the target to which the event was originally dispatched. + * + * @var unknown_type + */ + public $target; + /** + * Returns the time that the event was created. + * + * @var unknown_type + */ + public $timeStamp; + /** + * Returns the name of the event (case-insensitive). + */ + public $type; + public $runDefault = true; + public $data = null; + public function __construct($data) { + foreach($data as $k => $v) { + $this->$k = $v; + } + if (! $this->timeStamp) + $this->timeStamp = time(); + } + /** + * Cancels the event (if it is cancelable). + * + */ + public function preventDefault() { + $this->runDefault = false; + } + /** + * Stops the propagation of events further along in the DOM. + * + */ + public function stopPropagation() { + $this->bubbles = false; + } +} + + +/** + * DOMDocumentWrapper class simplifies work with DOMDocument. + * + * Know bug: + * - in XHTML fragments,
    changes to
    + * + * @todo check XML catalogs compatibility + * @author Tobiasz Cudnik + * @package phpQuery + */ +class DOMDocumentWrapper { + /** + * @var DOMDocument + */ + public $document; + public $id; + /** + * @todo Rewrite as method and quess if null. + * @var unknown_type + */ + public $contentType = ''; + public $xpath; + public $uuid = 0; + public $data = array(); + public $dataNodes = array(); + public $events = array(); + public $eventsNodes = array(); + public $eventsGlobal = array(); + /** + * @TODO iframes support http://code.google.com/p/phpquery/issues/detail?id=28 + * @var unknown_type + */ + public $frames = array(); + /** + * Document root, by default equals to document itself. + * Used by documentFragments. + * + * @var DOMNode + */ + public $root; + public $isDocumentFragment; + public $isXML = false; + public $isXHTML = false; + public $isHTML = false; + public $charset; + public function __construct($markup = null, $contentType = null, $newDocumentID = null) { + if (isset($markup)) + $this->load($markup, $contentType, $newDocumentID); + $this->id = $newDocumentID + ? $newDocumentID + : md5(microtime()); + } + public function load($markup, $contentType = null, $newDocumentID = null) { +// phpQuery::$documents[$id] = $this; + $this->contentType = strtolower($contentType); + if ($markup instanceof DOMDOCUMENT) { + $this->document = $markup; + $this->root = $this->document; + $this->charset = $this->document->encoding; + // TODO isDocumentFragment + } else { + $loaded = $this->loadMarkup($markup); + } + if ($loaded) { +// $this->document->formatOutput = true; + $this->document->preserveWhiteSpace = true; + $this->xpath = new DOMXPath($this->document); + $this->afterMarkupLoad(); + return true; + // remember last loaded document +// return phpQuery::selectDocument($id); + } + return false; + } + protected function afterMarkupLoad() { + if ($this->isXHTML) { + $this->xpath->registerNamespace("html", "http://www.w3.org/1999/xhtml"); + } + } + protected function loadMarkup($markup) { + $loaded = false; + if ($this->contentType) { + self::debug("Load markup for content type {$this->contentType}"); + // content determined by contentType + list($contentType, $charset) = $this->contentTypeToArray($this->contentType); + switch($contentType) { + case 'text/html': + phpQuery::debug("Loading HTML, content type '{$this->contentType}'"); + $loaded = $this->loadMarkupHTML($markup, $charset); + break; + case 'text/xml': + case 'application/xhtml+xml': + phpQuery::debug("Loading XML, content type '{$this->contentType}'"); + $loaded = $this->loadMarkupXML($markup, $charset); + break; + default: + // for feeds or anything that sometimes doesn't use text/xml + if (strpos('xml', $this->contentType) !== false) { + phpQuery::debug("Loading XML, content type '{$this->contentType}'"); + $loaded = $this->loadMarkupXML($markup, $charset); + } else + phpQuery::debug("Could not determine document type from content type '{$this->contentType}'"); + } + } else { + // content type autodetection + if ($this->isXML($markup)) { + phpQuery::debug("Loading XML, isXML() == true"); + $loaded = $this->loadMarkupXML($markup); + if (! $loaded && $this->isXHTML) { + phpQuery::debug('Loading as XML failed, trying to load as HTML, isXHTML == true'); + $loaded = $this->loadMarkupHTML($markup); + } + } else { + phpQuery::debug("Loading HTML, isXML() == false"); + $loaded = $this->loadMarkupHTML($markup); + } + } + return $loaded; + } + protected function loadMarkupReset() { + $this->isXML = $this->isXHTML = $this->isHTML = false; + } + protected function documentCreate($charset, $version = '1.0') { + if (! $version) + $version = '1.0'; + $this->document = new DOMDocument($version, $charset); + $this->charset = $this->document->encoding; +// $this->document->encoding = $charset; + $this->document->formatOutput = true; + $this->document->preserveWhiteSpace = true; + } + protected function loadMarkupHTML($markup, $requestedCharset = null) { + if (phpQuery::$debug) + phpQuery::debug('Full markup load (HTML): '.substr($markup, 0, 250)); + $this->loadMarkupReset(); + $this->isHTML = true; + if (!isset($this->isDocumentFragment)) + $this->isDocumentFragment = self::isDocumentFragmentHTML($markup); + $charset = null; + $documentCharset = $this->charsetFromHTML($markup); + $addDocumentCharset = false; + if ($documentCharset) { + $charset = $documentCharset; + $markup = $this->charsetFixHTML($markup); + } else if ($requestedCharset) { + $charset = $requestedCharset; + } + if (! $charset) + $charset = phpQuery::$defaultCharset; + // HTTP 1.1 says that the default charset is ISO-8859-1 + // @see http://www.w3.org/International/O-HTTP-charset + if (! $documentCharset) { + $documentCharset = 'ISO-8859-1'; + $addDocumentCharset = true; + } + // Should be careful here, still need 'magic encoding detection' since lots of pages have other 'default encoding' + // Worse, some pages can have mixed encodings... we'll try not to worry about that + $requestedCharset = strtoupper($requestedCharset); + $documentCharset = strtoupper($documentCharset); + phpQuery::debug("DOC: $documentCharset REQ: $requestedCharset"); + if ($requestedCharset && $documentCharset && $requestedCharset !== $documentCharset) { + phpQuery::debug("CHARSET CONVERT"); + // Document Encoding Conversion + // http://code.google.com/p/phpquery/issues/detail?id=86 + if (function_exists('mb_detect_encoding')) { + $possibleCharsets = array($documentCharset, $requestedCharset, 'AUTO'); + $docEncoding = mb_detect_encoding($markup, implode(', ', $possibleCharsets)); + if (! $docEncoding) + $docEncoding = $documentCharset; // ok trust the document + phpQuery::debug("DETECTED '$docEncoding'"); + // Detected does not match what document says... + if ($docEncoding !== $documentCharset) { + // Tricky.. + } + if ($docEncoding !== $requestedCharset) { + phpQuery::debug("CONVERT $docEncoding => $requestedCharset"); + $markup = mb_convert_encoding($markup, $requestedCharset, $docEncoding); + $markup = $this->charsetAppendToHTML($markup, $requestedCharset); + $charset = $requestedCharset; + } + } else { + phpQuery::debug("TODO: charset conversion without mbstring..."); + } + } + $return = false; + if ($this->isDocumentFragment) { + phpQuery::debug("Full markup load (HTML), DocumentFragment detected, using charset '$charset'"); + $return = $this->documentFragmentLoadMarkup($this, $charset, $markup); + } else { + if ($addDocumentCharset) { + phpQuery::debug("Full markup load (HTML), appending charset: '$charset'"); + $markup = $this->charsetAppendToHTML($markup, $charset); + } + phpQuery::debug("Full markup load (HTML), documentCreate('$charset')"); + $this->documentCreate($charset); + $return = phpQuery::$debug === 2 + ? $this->document->loadHTML($markup) + : @$this->document->loadHTML($markup); + if ($return) + $this->root = $this->document; + } + if ($return && ! $this->contentType) + $this->contentType = 'text/html'; + return $return; + } + protected function loadMarkupXML($markup, $requestedCharset = null) { + if (phpQuery::$debug) + phpQuery::debug('Full markup load (XML): '.substr($markup, 0, 250)); + $this->loadMarkupReset(); + $this->isXML = true; + // check agains XHTML in contentType or markup + $isContentTypeXHTML = $this->isXHTML(); + $isMarkupXHTML = $this->isXHTML($markup); + if ($isContentTypeXHTML || $isMarkupXHTML) { + self::debug('Full markup load (XML), XHTML detected'); + $this->isXHTML = true; + } + // determine document fragment + if (! isset($this->isDocumentFragment)) + $this->isDocumentFragment = $this->isXHTML + ? self::isDocumentFragmentXHTML($markup) + : self::isDocumentFragmentXML($markup); + // this charset will be used + $charset = null; + // charset from XML declaration @var string + $documentCharset = $this->charsetFromXML($markup); + if (! $documentCharset) { + if ($this->isXHTML) { + // this is XHTML, try to get charset from content-type meta header + $documentCharset = $this->charsetFromHTML($markup); + if ($documentCharset) { + phpQuery::debug("Full markup load (XML), appending XHTML charset '$documentCharset'"); + $this->charsetAppendToXML($markup, $documentCharset); + $charset = $documentCharset; + } + } + if (! $documentCharset) { + // if still no document charset... + $charset = $requestedCharset; + } + } else if ($requestedCharset) { + $charset = $requestedCharset; + } + if (! $charset) { + $charset = phpQuery::$defaultCharset; + } + if ($requestedCharset && $documentCharset && $requestedCharset != $documentCharset) { + // TODO place for charset conversion +// $charset = $requestedCharset; + } + $return = false; + if ($this->isDocumentFragment) { + phpQuery::debug("Full markup load (XML), DocumentFragment detected, using charset '$charset'"); + $return = $this->documentFragmentLoadMarkup($this, $charset, $markup); + } else { + // FIXME ??? + if ($isContentTypeXHTML && ! $isMarkupXHTML) + if (! $documentCharset) { + phpQuery::debug("Full markup load (XML), appending charset '$charset'"); + $markup = $this->charsetAppendToXML($markup, $charset); + } + // see http://pl2.php.net/manual/en/book.dom.php#78929 + // LIBXML_DTDLOAD (>= PHP 5.1) + // does XML ctalogues works with LIBXML_NONET + // $this->document->resolveExternals = true; + // TODO test LIBXML_COMPACT for performance improvement + // create document + $this->documentCreate($charset); + if (phpversion() < 5.1) { + $this->document->resolveExternals = true; + $return = phpQuery::$debug === 2 + ? $this->document->loadXML($markup) + : @$this->document->loadXML($markup); + } else { + /** @link http://pl2.php.net/manual/en/libxml.constants.php */ + $libxmlStatic = phpQuery::$debug === 2 + ? LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET + : LIBXML_DTDLOAD|LIBXML_DTDATTR|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOERROR; + $return = $this->document->loadXML($markup, $libxmlStatic); +// if (! $return) +// $return = $this->document->loadHTML($markup); + } + if ($return) + $this->root = $this->document; + } + if ($return) { + if (! $this->contentType) { + if ($this->isXHTML) + $this->contentType = 'application/xhtml+xml'; + else + $this->contentType = 'text/xml'; + } + return $return; + } else { + throw new Exception("Error loading XML markup"); + } + } + protected function isXHTML($markup = null) { + if (! isset($markup)) { + return strpos($this->contentType, 'xhtml') !== false; + } + // XXX ok ? + return strpos($markup, "doctype) && is_object($dom->doctype) +// ? $dom->doctype->publicId +// : self::$defaultDoctype; + } + protected function isXML($markup) { +// return strpos($markup, ']+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', + $markup, $matches + ); + if (! isset($matches[0])) + return array(null, null); + // get attr 'content' + preg_match('@content\\s*=\\s*(["|\'])(.+?)\\1@', $matches[0], $matches); + if (! isset($matches[0])) + return array(null, null); + return $this->contentTypeToArray($matches[2]); + } + protected function charsetFromHTML($markup) { + $contentType = $this->contentTypeFromHTML($markup); + return $contentType[1]; + } + protected function charsetFromXML($markup) { + $matches; + // find declaration + preg_match('@<'.'?xml[^>]+encoding\\s*=\\s*(["|\'])(.*?)\\1@i', + $markup, $matches + ); + return isset($matches[2]) + ? strtolower($matches[2]) + : null; + } + /** + * Repositions meta[type=charset] at the start of head. Bypasses DOMDocument bug. + * + * @link http://code.google.com/p/phpquery/issues/detail?id=80 + * @param $html + */ + protected function charsetFixHTML($markup) { + $matches = array(); + // find meta tag + preg_match('@\s*]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', + $markup, $matches, PREG_OFFSET_CAPTURE + ); + if (! isset($matches[0])) + return; + $metaContentType = $matches[0][0]; + $markup = substr($markup, 0, $matches[0][1]) + .substr($markup, $matches[0][1]+strlen($metaContentType)); + $headStart = stripos($markup, ''); + $markup = substr($markup, 0, $headStart+6).$metaContentType + .substr($markup, $headStart+6); + return $markup; + } + protected function charsetAppendToHTML($html, $charset, $xhtml = false) { + // remove existing meta[type=content-type] + $html = preg_replace('@\s*]+http-equiv\\s*=\\s*(["|\'])Content-Type\\1([^>]+?)>@i', '', $html); + $meta = ''; + if (strpos($html, ')@s', + "{$meta}", + $html + ); + } + } else { + return preg_replace( + '@)@s', + ''.$meta, + $html + ); + } + } + protected function charsetAppendToXML($markup, $charset) { + $declaration = '<'.'?xml version="1.0" encoding="'.$charset.'"?'.'>'; + return $declaration.$markup; + } + public static function isDocumentFragmentHTML($markup) { + return stripos($markup, 'documentFragmentCreate($node, $sourceCharset); +// if ($fake === false) +// throw new Exception("Error loading documentFragment markup"); +// else +// $return = array_merge($return, +// $this->import($fake->root->childNodes) +// ); +// } else { +// $return[] = $this->document->importNode($node, true); +// } +// } +// return $return; +// } else { +// // string markup +// $fake = $this->documentFragmentCreate($source, $sourceCharset); +// if ($fake === false) +// throw new Exception("Error loading documentFragment markup"); +// else +// return $this->import($fake->root->childNodes); +// } + if (is_array($source) || $source instanceof DOMNODELIST) { + // dom nodes + self::debug('Importing nodes to document'); + foreach($source as $node) + $return[] = $this->document->importNode($node, true); + } else { + // string markup + $fake = $this->documentFragmentCreate($source, $sourceCharset); + if ($fake === false) + throw new Exception("Error loading documentFragment markup"); + else + return $this->import($fake->root->childNodes); + } + return $return; + } + /** + * Creates new document fragment. + * + * @param $source + * @return DOMDocumentWrapper + */ + protected function documentFragmentCreate($source, $charset = null) { + $fake = new DOMDocumentWrapper(); + $fake->contentType = $this->contentType; + $fake->isXML = $this->isXML; + $fake->isHTML = $this->isHTML; + $fake->isXHTML = $this->isXHTML; + $fake->root = $fake->document; + if (! $charset) + $charset = $this->charset; +// $fake->documentCreate($this->charset); + if ($source instanceof DOMNODE && !($source instanceof DOMNODELIST)) + $source = array($source); + if (is_array($source) || $source instanceof DOMNODELIST) { + // dom nodes + // load fake document + if (! $this->documentFragmentLoadMarkup($fake, $charset)) + return false; + $nodes = $fake->import($source); + foreach($nodes as $node) + $fake->root->appendChild($node); + } else { + // string markup + $this->documentFragmentLoadMarkup($fake, $charset, $source); + } + return $fake; + } + /** + * + * @param $document DOMDocumentWrapper + * @param $markup + * @return $document + */ + private function documentFragmentLoadMarkup($fragment, $charset, $markup = null) { + // TODO error handling + // TODO copy doctype + // tempolary turn off + $fragment->isDocumentFragment = false; + if ($fragment->isXML) { + if ($fragment->isXHTML) { + // add FAKE element to set default namespace + $fragment->loadMarkupXML('' + .'' + .''.$markup.''); + $fragment->root = $fragment->document->firstChild->nextSibling; + } else { + $fragment->loadMarkupXML(''.$markup.''); + $fragment->root = $fragment->document->firstChild; + } + } else { + $markup2 = phpQuery::$defaultDoctype.''; + $noBody = strpos($markup, 'loadMarkupHTML($markup2); + // TODO resolv body tag merging issue + $fragment->root = $noBody + ? $fragment->document->firstChild->nextSibling->firstChild->nextSibling + : $fragment->document->firstChild->nextSibling->firstChild->nextSibling; + } + if (! $fragment->root) + return false; + $fragment->isDocumentFragment = true; + return true; + } + protected function documentFragmentToMarkup($fragment) { + phpQuery::debug('documentFragmentToMarkup'); + $tmp = $fragment->isDocumentFragment; + $fragment->isDocumentFragment = false; + $markup = $fragment->markup(); + if ($fragment->isXML) { + $markup = substr($markup, 0, strrpos($markup, '')); + if ($fragment->isXHTML) { + $markup = substr($markup, strpos($markup, '')+6); + } + } else { + $markup = substr($markup, strpos($markup, '')+6); + $markup = substr($markup, 0, strrpos($markup, '')); + } + $fragment->isDocumentFragment = $tmp; + if (phpQuery::$debug) + phpQuery::debug('documentFragmentToMarkup: '.substr($markup, 0, 150)); + return $markup; + } + /** + * Return document markup, starting with optional $nodes as root. + * + * @param $nodes DOMNode|DOMNodeList + * @return string + */ + public function markup($nodes = null, $innerMarkup = false) { + if (isset($nodes) && count($nodes) == 1 && $nodes[0] instanceof DOMDOCUMENT) + $nodes = null; + if (isset($nodes)) { + $markup = ''; + if (!is_array($nodes) && !($nodes instanceof DOMNODELIST) ) + $nodes = array($nodes); + if ($this->isDocumentFragment && ! $innerMarkup) + foreach($nodes as $i => $node) + if ($node->isSameNode($this->root)) { + // var_dump($node); + $nodes = array_slice($nodes, 0, $i) + + phpQuery::DOMNodeListToArray($node->childNodes) + + array_slice($nodes, $i+1); + } + if ($this->isXML && ! $innerMarkup) { + self::debug("Getting outerXML with charset '{$this->charset}'"); + // we need outerXML, so we can benefit from + // $node param support in saveXML() + foreach($nodes as $node) + $markup .= $this->document->saveXML($node); + } else { + $loop = array(); + if ($innerMarkup) + foreach($nodes as $node) { + if ($node->childNodes) + foreach($node->childNodes as $child) + $loop[] = $child; + else + $loop[] = $node; + } + else + $loop = $nodes; + self::debug("Getting markup, moving selected nodes (".count($loop).") to new DocumentFragment"); + $fake = $this->documentFragmentCreate($loop); + $markup = $this->documentFragmentToMarkup($fake); + } + if ($this->isXHTML) { + self::debug("Fixing XHTML"); + $markup = self::markupFixXHTML($markup); + } + self::debug("Markup: ".substr($markup, 0, 250)); + return $markup; + } else { + if ($this->isDocumentFragment) { + // documentFragment, html only... + self::debug("Getting markup, DocumentFragment detected"); +// return $this->markup( +//// $this->document->getElementsByTagName('body')->item(0) +// $this->document->root, true +// ); + $markup = $this->documentFragmentToMarkup($this); + // no need for markupFixXHTML, as it's done thought markup($nodes) method + return $markup; + } else { + self::debug("Getting markup (".($this->isXML?'XML':'HTML')."), final with charset '{$this->charset}'"); + $markup = $this->isXML + ? $this->document->saveXML() + : $this->document->saveHTML(); + if ($this->isXHTML) { + self::debug("Fixing XHTML"); + $markup = self::markupFixXHTML($markup); + } + self::debug("Markup: ".substr($markup, 0, 250)); + return $markup; + } + } + } + protected static function markupFixXHTML($markup) { + $markup = self::expandEmptyTag('script', $markup); + $markup = self::expandEmptyTag('select', $markup); + $markup = self::expandEmptyTag('textarea', $markup); + return $markup; + } + public static function debug($text) { + phpQuery::debug($text); + } + /** + * expandEmptyTag + * + * @param $tag + * @param $xml + * @return unknown_type + * @author mjaque at ilkebenson dot com + * @link http://php.net/manual/en/domdocument.savehtml.php#81256 + */ + public static function expandEmptyTag($tag, $xml){ + $indice = 0; + while ($indice< strlen($xml)){ + $pos = strpos($xml, "<$tag ", $indice); + if ($pos){ + $posCierre = strpos($xml, ">", $pos); + if ($xml[$posCierre-1] == "/"){ + $xml = substr_replace($xml, ">", $posCierre-1, 2); + } + $indice = $posCierre; + } + else break; + } + return $xml; + } +} + +/** + * Event handling class. + * + * @author Tobiasz Cudnik + * @package phpQuery + * @static + */ +abstract class phpQueryEvents { + /** + * Trigger a type of event on every matched element. + * + * @param DOMNode|phpQueryObject|string $document + * @param unknown_type $type + * @param unknown_type $data + * + * @TODO exclusive events (with !) + * @TODO global events (test) + * @TODO support more than event in $type (space-separated) + */ + public static function trigger($document, $type, $data = array(), $node = null) { + // trigger: function(type, data, elem, donative, extra) { + $documentID = phpQuery::getDocumentID($document); + $namespace = null; + if (strpos($type, '.') !== false) + list($name, $namespace) = explode('.', $type); + else + $name = $type; + if (! $node) { + if (self::issetGlobal($documentID, $type)) { + $pq = phpQuery::getDocument($documentID); + // TODO check add($pq->document) + $pq->find('*')->add($pq->document) + ->trigger($type, $data); + } + } else { + if (isset($data[0]) && $data[0] instanceof DOMEvent) { + $event = $data[0]; + $event->relatedTarget = $event->target; + $event->target = $node; + $data = array_slice($data, 1); + } else { + $event = new DOMEvent(array( + 'type' => $type, + 'target' => $node, + 'timeStamp' => time(), + )); + } + $i = 0; + while($node) { + // TODO whois + phpQuery::debug("Triggering ".($i?"bubbled ":'')."event '{$type}' on " + ."node \n");//.phpQueryObject::whois($node)."\n"); + $event->currentTarget = $node; + $eventNode = self::getNode($documentID, $node); + if (isset($eventNode->eventHandlers)) { + foreach($eventNode->eventHandlers as $eventType => $handlers) { + $eventNamespace = null; + if (strpos($type, '.') !== false) + list($eventName, $eventNamespace) = explode('.', $eventType); + else + $eventName = $eventType; + if ($name != $eventName) + continue; + if ($namespace && $eventNamespace && $namespace != $eventNamespace) + continue; + foreach($handlers as $handler) { + phpQuery::debug("Calling event handler\n"); + $event->data = $handler['data'] + ? $handler['data'] + : null; + $params = array_merge(array($event), $data); + $return = phpQuery::callbackRun($handler['callback'], $params); + if ($return === false) { + $event->bubbles = false; + } + } + } + } + // to bubble or not to bubble... + if (! $event->bubbles) + break; + $node = $node->parentNode; + $i++; + } + } + } + /** + * Binds a handler to one or more events (like click) for each matched element. + * Can also bind custom events. + * + * @param DOMNode|phpQueryObject|string $document + * @param unknown_type $type + * @param unknown_type $data Optional + * @param unknown_type $callback + * + * @TODO support '!' (exclusive) events + * @TODO support more than event in $type (space-separated) + * @TODO support binding to global events + */ + public static function add($document, $node, $type, $data, $callback = null) { + phpQuery::debug("Binding '$type' event"); + $documentID = phpQuery::getDocumentID($document); +// if (is_null($callback) && is_callable($data)) { +// $callback = $data; +// $data = null; +// } + $eventNode = self::getNode($documentID, $node); + if (! $eventNode) + $eventNode = self::setNode($documentID, $node); + if (!isset($eventNode->eventHandlers[$type])) + $eventNode->eventHandlers[$type] = array(); + $eventNode->eventHandlers[$type][] = array( + 'callback' => $callback, + 'data' => $data, + ); + } + /** + * Enter description here... + * + * @param DOMNode|phpQueryObject|string $document + * @param unknown_type $type + * @param unknown_type $callback + * + * @TODO namespace events + * @TODO support more than event in $type (space-separated) + */ + public static function remove($document, $node, $type = null, $callback = null) { + $documentID = phpQuery::getDocumentID($document); + $eventNode = self::getNode($documentID, $node); + if (is_object($eventNode) && isset($eventNode->eventHandlers[$type])) { + if ($callback) { + foreach($eventNode->eventHandlers[$type] as $k => $handler) + if ($handler['callback'] == $callback) + unset($eventNode->eventHandlers[$type][$k]); + } else { + unset($eventNode->eventHandlers[$type]); + } + } + } + protected static function getNode($documentID, $node) { + foreach(phpQuery::$documents[$documentID]->eventsNodes as $eventNode) { + if ($node->isSameNode($eventNode)) + return $eventNode; + } + } + protected static function setNode($documentID, $node) { + phpQuery::$documents[$documentID]->eventsNodes[] = $node; + return phpQuery::$documents[$documentID]->eventsNodes[ + count(phpQuery::$documents[$documentID]->eventsNodes)-1 + ]; + } + protected static function issetGlobal($documentID, $type) { + return isset(phpQuery::$documents[$documentID]) + ? in_array($type, phpQuery::$documents[$documentID]->eventsGlobal) + : false; + } +} + + +interface ICallbackNamed { + function hasName(); + function getName(); +} +/** + * Callback class introduces currying-like pattern. + * + * Example: + * function foo($param1, $param2, $param3) { + * var_dump($param1, $param2, $param3); + * } + * $fooCurried = new Callback('foo', + * 'param1 is now statically set', + * new CallbackParam, new CallbackParam + * ); + * phpQuery::callbackRun($fooCurried, + * array('param2 value', 'param3 value' + * ); + * + * Callback class is supported in all phpQuery methods which accepts callbacks. + * + * @link http://code.google.com/p/phpquery/wiki/Callbacks#Param_Structures + * @author Tobiasz Cudnik + * + * @TODO??? return fake forwarding function created via create_function + * @TODO honor paramStructure + */ +class Callback + implements ICallbackNamed { + public $callback = null; + public $params = null; + protected $name; + public function __construct($callback, $param1 = null, $param2 = null, + $param3 = null) { + $params = func_get_args(); + $params = array_slice($params, 1); + if ($callback instanceof Callback) { + // TODO implement recurention + } else { + $this->callback = $callback; + $this->params = $params; + } + } + public function getName() { + return 'Callback: '.$this->name; + } + public function hasName() { + return isset($this->name) && $this->name; + } + public function setName($name) { + $this->name = $name; + return $this; + } + // TODO test me +// public function addParams() { +// $params = func_get_args(); +// return new Callback($this->callback, $this->params+$params); +// } +} +/** + * Shorthand for new Callback(create_function(...), ...); + * + * @author Tobiasz Cudnik + */ +class CallbackBody extends Callback { + public function __construct($paramList, $code, $param1 = null, $param2 = null, + $param3 = null) { + $params = func_get_args(); + $params = array_slice($params, 2); + $this->callback = create_function($paramList, $code); + $this->params = $params; + } +} +/** + * Callback type which on execution returns reference passed during creation. + * + * @author Tobiasz Cudnik + */ +class CallbackReturnReference extends Callback + implements ICallbackNamed { + protected $reference; + public function __construct(&$reference, $name = null){ + $this->reference =& $reference; + $this->callback = array($this, 'callback'); + } + public function callback() { + return $this->reference; + } + public function getName() { + return 'Callback: '.$this->name; + } + public function hasName() { + return isset($this->name) && $this->name; + } +} +/** + * Callback type which on execution returns value passed during creation. + * + * @author Tobiasz Cudnik + */ +class CallbackReturnValue extends Callback + implements ICallbackNamed { + protected $value; + protected $name; + public function __construct($value, $name = null){ + $this->value =& $value; + $this->name = $name; + $this->callback = array($this, 'callback'); + } + public function callback() { + return $this->value; + } + public function __toString() { + return $this->getName(); + } + public function getName() { + return 'Callback: '.$this->name; + } + public function hasName() { + return isset($this->name) && $this->name; + } +} +/** + * CallbackParameterToReference can be used when we don't really want a callback, + * only parameter passed to it. CallbackParameterToReference takes first + * parameter's value and passes it to reference. + * + * @author Tobiasz Cudnik + */ +class CallbackParameterToReference extends Callback { + /** + * @param $reference + * @TODO implement $paramIndex; + * param index choose which callback param will be passed to reference + */ + public function __construct(&$reference){ + $this->callback =& $reference; + } +} +//class CallbackReference extends Callback { +// /** +// * +// * @param $reference +// * @param $paramIndex +// * @todo implement $paramIndex; param index choose which callback param will be passed to reference +// */ +// public function __construct(&$reference, $name = null){ +// $this->callback =& $reference; +// } +//} +class CallbackParam {} + +/** + * Class representing phpQuery objects. + * + * @author Tobiasz Cudnik + * @package phpQuery + * @method phpQueryObject clone() clone() + * @method phpQueryObject empty() empty() + * @method phpQueryObject next() next($selector = null) + * @method phpQueryObject prev() prev($selector = null) + * @property Int $length + */ +class phpQueryObject + implements Iterator, Countable, ArrayAccess { + public $documentID = null; + /** + * DOMDocument class. + * + * @var DOMDocument + */ + public $document = null; + public $charset = null; + /** + * + * @var DOMDocumentWrapper + */ + public $documentWrapper = null; + /** + * XPath interface. + * + * @var DOMXPath + */ + public $xpath = null; + /** + * Stack of selected elements. + * @TODO refactor to ->nodes + * @var array + */ + public $elements = array(); + /** + * @access private + */ + protected $elementsBackup = array(); + /** + * @access private + */ + protected $previous = null; + /** + * @access private + * @TODO deprecate + */ + protected $root = array(); + /** + * Indicated if doument is just a fragment (no tag). + * + * Every document is realy a full document, so even documentFragments can + * be queried against , but getDocument(id)->htmlOuter() will return + * only contents of . + * + * @var bool + */ + public $documentFragment = true; + /** + * Iterator interface helper + * @access private + */ + protected $elementsInterator = array(); + /** + * Iterator interface helper + * @access private + */ + protected $valid = false; + /** + * Iterator interface helper + * @access private + */ + protected $current = null; + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function __construct($documentID) { +// if ($documentID instanceof self) +// var_dump($documentID->getDocumentID()); + $id = $documentID instanceof self + ? $documentID->getDocumentID() + : $documentID; +// var_dump($id); + if (! isset(phpQuery::$documents[$id] )) { +// var_dump(phpQuery::$documents); + throw new Exception("Document with ID '{$id}' isn't loaded. Use phpQuery::newDocument(\$html) or phpQuery::newDocumentFile(\$file) first."); + } + $this->documentID = $id; + $this->documentWrapper =& phpQuery::$documents[$id]; + $this->document =& $this->documentWrapper->document; + $this->xpath =& $this->documentWrapper->xpath; + $this->charset =& $this->documentWrapper->charset; + $this->documentFragment =& $this->documentWrapper->isDocumentFragment; + // TODO check $this->DOM->documentElement; +// $this->root = $this->document->documentElement; + $this->root =& $this->documentWrapper->root; +// $this->toRoot(); + $this->elements = array($this->root); + } + /** + * + * @access private + * @param $attr + * @return unknown_type + */ + public function __get($attr) { + switch($attr) { + // FIXME doesnt work at all ? + case 'length': + return $this->size(); + break; + default: + return $this->$attr; + } + } + /** + * Saves actual object to $var by reference. + * Useful when need to break chain. + * @param phpQueryObject $var + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function toReference(&$var) { + return $var = $this; + } + public function documentFragment($state = null) { + if ($state) { + phpQuery::$documents[$this->getDocumentID()]['documentFragment'] = $state; + return $this; + } + return $this->documentFragment; + } + /** + * @access private + * @TODO documentWrapper + */ + protected function isRoot( $node) { +// return $node instanceof DOMDOCUMENT || $node->tagName == 'html'; + return $node instanceof DOMDOCUMENT + || ($node instanceof DOMELEMENT && $node->tagName == 'html') + || $this->root->isSameNode($node); + } + /** + * @access private + */ + protected function stackIsRoot() { + return $this->size() == 1 && $this->isRoot($this->elements[0]); + } + /** + * Enter description here... + * NON JQUERY METHOD + * + * Watch out, it doesn't creates new instance, can be reverted with end(). + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function toRoot() { + $this->elements = array($this->root); + return $this; +// return $this->newInstance(array($this->root)); + } + /** + * Saves object's DocumentID to $var by reference. + * + * $myDocumentId; + * phpQuery::newDocument('
    ') + * ->getDocumentIDRef($myDocumentId) + * ->find('div')->... + * + * + * @param unknown_type $domId + * @see phpQuery::newDocument + * @see phpQuery::newDocumentFile + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function getDocumentIDRef(&$documentID) { + $documentID = $this->getDocumentID(); + return $this; + } + /** + * Returns object with stack set to document root. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function getDocument() { + return phpQuery::getDocument($this->getDocumentID()); + } + /** + * + * @return DOMDocument + */ + public function getDOMDocument() { + return $this->document; + } + /** + * Get object's Document ID. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function getDocumentID() { + return $this->documentID; + } + /** + * Unloads whole document from memory. + * CAUTION! None further operations will be possible on this document. + * All objects refering to it will be useless. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function unloadDocument() { + phpQuery::unloadDocuments($this->getDocumentID()); + } + public function isHTML() { + return $this->documentWrapper->isHTML; + } + public function isXHTML() { + return $this->documentWrapper->isXHTML; + } + public function isXML() { + return $this->documentWrapper->isXML; + } + /** + * Enter description here... + * + * @link http://docs.jquery.com/Ajax/serialize + * @return string + */ + public function serialize() { + return phpQuery::param($this->serializeArray()); + } + /** + * Enter description here... + * + * @link http://docs.jquery.com/Ajax/serializeArray + * @return array + */ + public function serializeArray($submit = null) { + $source = $this->filter('form, input, select, textarea') + ->find('input, select, textarea') + ->andSelf() + ->not('form'); + $return = array(); +// $source->dumpDie(); + foreach($source as $input) { + $input = phpQuery::pq($input); + if ($input->is('[disabled]')) + continue; + if (!$input->is('[name]')) + continue; + if ($input->is('[type=checkbox]') && !$input->is('[checked]')) + continue; + // jquery diff + if ($submit && $input->is('[type=submit]')) { + if ($submit instanceof DOMELEMENT && ! $input->elements[0]->isSameNode($submit)) + continue; + else if (is_string($submit) && $input->attr('name') != $submit) + continue; + } + $return[] = array( + 'name' => $input->attr('name'), + 'value' => $input->val(), + ); + } + return $return; + } + /** + * @access private + */ + protected function debug($in) { + if (! phpQuery::$debug ) + return; + print('
    ');
    +		print_r($in);
    +		// file debug
    +//		file_put_contents(dirname(__FILE__).'/phpQuery.log', print_r($in, true)."\n", FILE_APPEND);
    +		// quite handy debug trace
    +//		if ( is_array($in))
    +//			print_r(array_slice(debug_backtrace(), 3));
    +		print("
    \n"); + } + /** + * @access private + */ + protected function isRegexp($pattern) { + return in_array( + $pattern[ mb_strlen($pattern)-1 ], + array('^','*','$') + ); + } + /** + * Determines if $char is really a char. + * + * @param string $char + * @return bool + * @todo rewrite me to charcode range ! ;) + * @access private + */ + protected function isChar($char) { + return extension_loaded('mbstring') && phpQuery::$mbstringSupport + ? mb_eregi('\w', $char) + : preg_match('@\w@', $char); + } + /** + * @access private + */ + protected function parseSelector($query) { + // clean spaces + // TODO include this inside parsing ? + $query = trim( + preg_replace('@\s+@', ' ', + preg_replace('@\s*(>|\\+|~)\s*@', '\\1', $query) + ) + ); + $queries = array(array()); + if (! $query) + return $queries; + $return =& $queries[0]; + $specialChars = array('>',' '); +// $specialCharsMapping = array('/' => '>'); + $specialCharsMapping = array(); + $strlen = mb_strlen($query); + $classChars = array('.', '-'); + $pseudoChars = array('-'); + $tagChars = array('*', '|', '-'); + // split multibyte string + // http://code.google.com/p/phpquery/issues/detail?id=76 + $_query = array(); + for ($i=0; $i<$strlen; $i++) + $_query[] = mb_substr($query, $i, 1); + $query = $_query; + // it works, but i dont like it... + $i = 0; + while( $i < $strlen) { + $c = $query[$i]; + $tmp = ''; + // TAG + if ($this->isChar($c) || in_array($c, $tagChars)) { + while(isset($query[$i]) + && ($this->isChar($query[$i]) || in_array($query[$i], $tagChars))) { + $tmp .= $query[$i]; + $i++; + } + $return[] = $tmp; + // IDs + } else if ( $c == '#') { + $i++; + while( isset($query[$i]) && ($this->isChar($query[$i]) || $query[$i] == '-')) { + $tmp .= $query[$i]; + $i++; + } + $return[] = '#'.$tmp; + // SPECIAL CHARS + } else if (in_array($c, $specialChars)) { + $return[] = $c; + $i++; + // MAPPED SPECIAL MULTICHARS +// } else if ( $c.$query[$i+1] == '//') { +// $return[] = ' '; +// $i = $i+2; + // MAPPED SPECIAL CHARS + } else if ( isset($specialCharsMapping[$c])) { + $return[] = $specialCharsMapping[$c]; + $i++; + // COMMA + } else if ( $c == ',') { + $queries[] = array(); + $return =& $queries[ count($queries)-1 ]; + $i++; + while( isset($query[$i]) && $query[$i] == ' ') + $i++; + // CLASSES + } else if ($c == '.') { + while( isset($query[$i]) && ($this->isChar($query[$i]) || in_array($query[$i], $classChars))) { + $tmp .= $query[$i]; + $i++; + } + $return[] = $tmp; + // ~ General Sibling Selector + } else if ($c == '~') { + $spaceAllowed = true; + $tmp .= $query[$i++]; + while( isset($query[$i]) + && ($this->isChar($query[$i]) + || in_array($query[$i], $classChars) + || $query[$i] == '*' + || ($query[$i] == ' ' && $spaceAllowed) + )) { + if ($query[$i] != ' ') + $spaceAllowed = false; + $tmp .= $query[$i]; + $i++; + } + $return[] = $tmp; + // + Adjacent sibling selectors + } else if ($c == '+') { + $spaceAllowed = true; + $tmp .= $query[$i++]; + while( isset($query[$i]) + && ($this->isChar($query[$i]) + || in_array($query[$i], $classChars) + || $query[$i] == '*' + || ($spaceAllowed && $query[$i] == ' ') + )) { + if ($query[$i] != ' ') + $spaceAllowed = false; + $tmp .= $query[$i]; + $i++; + } + $return[] = $tmp; + // ATTRS + } else if ($c == '[') { + $stack = 1; + $tmp .= $c; + while( isset($query[++$i])) { + $tmp .= $query[$i]; + if ( $query[$i] == '[') { + $stack++; + } else if ( $query[$i] == ']') { + $stack--; + if (! $stack ) + break; + } + } + $return[] = $tmp; + $i++; + // PSEUDO CLASSES + } else if ($c == ':') { + $stack = 1; + $tmp .= $query[$i++]; + while( isset($query[$i]) && ($this->isChar($query[$i]) || in_array($query[$i], $pseudoChars))) { + $tmp .= $query[$i]; + $i++; + } + // with arguments ? + if ( isset($query[$i]) && $query[$i] == '(') { + $tmp .= $query[$i]; + $stack = 1; + while( isset($query[++$i])) { + $tmp .= $query[$i]; + if ( $query[$i] == '(') { + $stack++; + } else if ( $query[$i] == ')') { + $stack--; + if (! $stack ) + break; + } + } + $return[] = $tmp; + $i++; + } else { + $return[] = $tmp; + } + } else { + $i++; + } + } + foreach($queries as $k => $q) { + if (isset($q[0])) { + if (isset($q[0][0]) && $q[0][0] == ':') + array_unshift($queries[$k], '*'); + if ($q[0] != '>') + array_unshift($queries[$k], ' '); + } + } + return $queries; + } + /** + * Return matched DOM nodes. + * + * @param int $index + * @return array|DOMElement Single DOMElement or array of DOMElement. + */ + public function get($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { + $return = isset($index) + ? (isset($this->elements[$index]) ? $this->elements[$index] : null) + : $this->elements; + // pass thou callbacks + $args = func_get_args(); + $args = array_slice($args, 1); + foreach($args as $callback) { + if (is_array($return)) + foreach($return as $k => $v) + $return[$k] = phpQuery::callbackRun($callback, array($v)); + else + $return = phpQuery::callbackRun($callback, array($return)); + } + return $return; + } + /** + * Return matched DOM nodes. + * jQuery difference. + * + * @param int $index + * @return array|string Returns string if $index != null + * @todo implement callbacks + * @todo return only arrays ? + * @todo maybe other name... + */ + public function getString($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { + if ($index) + $return = $this->eq($index)->text(); + else { + $return = array(); + for($i = 0; $i < $this->size(); $i++) { + $return[] = $this->eq($i)->text(); + } + } + // pass thou callbacks + $args = func_get_args(); + $args = array_slice($args, 1); + foreach($args as $callback) { + $return = phpQuery::callbackRun($callback, array($return)); + } + return $return; + } + /** + * Return matched DOM nodes. + * jQuery difference. + * + * @param int $index + * @return array|string Returns string if $index != null + * @todo implement callbacks + * @todo return only arrays ? + * @todo maybe other name... + */ + public function getStrings($index = null, $callback1 = null, $callback2 = null, $callback3 = null) { + if ($index) + $return = $this->eq($index)->text(); + else { + $return = array(); + for($i = 0; $i < $this->size(); $i++) { + $return[] = $this->eq($i)->text(); + } + // pass thou callbacks + $args = func_get_args(); + $args = array_slice($args, 1); + } + foreach($args as $callback) { + if (is_array($return)) + foreach($return as $k => $v) + $return[$k] = phpQuery::callbackRun($callback, array($v)); + else + $return = phpQuery::callbackRun($callback, array($return)); + } + return $return; + } + /** + * Returns new instance of actual class. + * + * @param array $newStack Optional. Will replace old stack with new and move old one to history.c + */ + public function newInstance($newStack = null) { + $class = get_class($this); + // support inheritance by passing old object to overloaded constructor + $new = $class != 'phpQuery' + ? new $class($this, $this->getDocumentID()) + : new phpQueryObject($this->getDocumentID()); + $new->previous = $this; + if (is_null($newStack)) { + $new->elements = $this->elements; + if ($this->elementsBackup) + $this->elements = $this->elementsBackup; + } else if (is_string($newStack)) { + $new->elements = phpQuery::pq($newStack, $this->getDocumentID())->stack(); + } else { + $new->elements = $newStack; + } + return $new; + } + /** + * Enter description here... + * + * In the future, when PHP will support XLS 2.0, then we would do that this way: + * contains(tokenize(@class, '\s'), "something") + * @param unknown_type $class + * @param unknown_type $node + * @return boolean + * @access private + */ + protected function matchClasses($class, $node) { + // multi-class + if ( mb_strpos($class, '.', 1)) { + $classes = explode('.', substr($class, 1)); + $classesCount = count( $classes ); + $nodeClasses = explode(' ', $node->getAttribute('class') ); + $nodeClassesCount = count( $nodeClasses ); + if ( $classesCount > $nodeClassesCount ) + return false; + $diff = count( + array_diff( + $classes, + $nodeClasses + ) + ); + if (! $diff ) + return true; + // single-class + } else { + return in_array( + // strip leading dot from class name + substr($class, 1), + // get classes for element as array + explode(' ', $node->getAttribute('class') ) + ); + } + } + /** + * @access private + */ + protected function runQuery($XQuery, $selector = null, $compare = null) { + if ($compare && ! method_exists($this, $compare)) + return false; + $stack = array(); + if (! $this->elements) + $this->debug('Stack empty, skipping...'); +// var_dump($this->elements[0]->nodeType); + // element, document + foreach($this->stack(array(1, 9, 13)) as $k => $stackNode) { + $detachAfter = false; + // to work on detached nodes we need temporary place them somewhere + // thats because context xpath queries sucks ;] + $testNode = $stackNode; + while ($testNode) { + if (! $testNode->parentNode && ! $this->isRoot($testNode)) { + $this->root->appendChild($testNode); + $detachAfter = $testNode; + break; + } + $testNode = isset($testNode->parentNode) + ? $testNode->parentNode + : null; + } + // XXX tmp ? + $xpath = $this->documentWrapper->isXHTML + ? $this->getNodeXpath($stackNode, 'html') + : $this->getNodeXpath($stackNode); + // FIXME pseudoclasses-only query, support XML + $query = $XQuery == '//' && $xpath == '/html[1]' + ? '//*' + : $xpath.$XQuery; + $this->debug("XPATH: {$query}"); + // run query, get elements + $nodes = $this->xpath->query($query); + $this->debug("QUERY FETCHED"); + if (! $nodes->length ) + $this->debug('Nothing found'); + $debug = array(); + foreach($nodes as $node) { + $matched = false; + if ( $compare) { + phpQuery::$debug ? + $this->debug("Found: ".$this->whois( $node ).", comparing with {$compare}()") + : null; + $phpQueryDebug = phpQuery::$debug; + phpQuery::$debug = false; + // TODO ??? use phpQuery::callbackRun() + if (call_user_func_array(array($this, $compare), array($selector, $node))) + $matched = true; + phpQuery::$debug = $phpQueryDebug; + } else { + $matched = true; + } + if ( $matched) { + if (phpQuery::$debug) + $debug[] = $this->whois( $node ); + $stack[] = $node; + } + } + if (phpQuery::$debug) { + $this->debug("Matched ".count($debug).": ".implode(', ', $debug)); + } + if ($detachAfter) + $this->root->removeChild($detachAfter); + } + $this->elements = $stack; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function find($selectors, $context = null, $noHistory = false) { + if (!$noHistory) + // backup last stack /for end()/ + $this->elementsBackup = $this->elements; + // allow to define context + // TODO combine code below with phpQuery::pq() context guessing code + // as generic function + if ($context) { + if (! is_array($context) && $context instanceof DOMELEMENT) + $this->elements = array($context); + else if (is_array($context)) { + $this->elements = array(); + foreach ($context as $c) + if ($c instanceof DOMELEMENT) + $this->elements[] = $c; + } else if ( $context instanceof self ) + $this->elements = $context->elements; + } + $queries = $this->parseSelector($selectors); + $this->debug(array('FIND', $selectors, $queries)); + $XQuery = ''; + // remember stack state because of multi-queries + $oldStack = $this->elements; + // here we will be keeping found elements + $stack = array(); + foreach($queries as $selector) { + $this->elements = $oldStack; + $delimiterBefore = false; + foreach($selector as $s) { + // TAG + $isTag = extension_loaded('mbstring') && phpQuery::$mbstringSupport + ? mb_ereg_match('^[\w|\||-]+$', $s) || $s == '*' + : preg_match('@^[\w|\||-]+$@', $s) || $s == '*'; + if ($isTag) { + if ($this->isXML()) { + // namespace support + if (mb_strpos($s, '|') !== false) { + $ns = $tag = null; + list($ns, $tag) = explode('|', $s); + $XQuery .= "$ns:$tag"; + } else if ($s == '*') { + $XQuery .= "*"; + } else { + $XQuery .= "*[local-name()='$s']"; + } + } else { + $XQuery .= $s; + } + // ID + } else if ($s[0] == '#') { + if ($delimiterBefore) + $XQuery .= '*'; + $XQuery .= "[@id='".substr($s, 1)."']"; + // ATTRIBUTES + } else if ($s[0] == '[') { + if ($delimiterBefore) + $XQuery .= '*'; + // strip side brackets + $attr = trim($s, ']['); + $execute = false; + // attr with specifed value + if (mb_strpos($s, '=')) { + $value = null; + list($attr, $value) = explode('=', $attr); + $value = trim($value, "'\""); + if ($this->isRegexp($attr)) { + // cut regexp character + $attr = substr($attr, 0, -1); + $execute = true; + $XQuery .= "[@{$attr}]"; + } else { + $XQuery .= "[@{$attr}='{$value}']"; + } + // attr without specified value + } else { + $XQuery .= "[@{$attr}]"; + } + if ($execute) { + $this->runQuery($XQuery, $s, 'is'); + $XQuery = ''; + if (! $this->length()) + break; + } + // CLASSES + } else if ($s[0] == '.') { + // TODO use return $this->find("./self::*[contains(concat(\" \",@class,\" \"), \" $class \")]"); + // thx wizDom ;) + if ($delimiterBefore) + $XQuery .= '*'; + $XQuery .= '[@class]'; + $this->runQuery($XQuery, $s, 'matchClasses'); + $XQuery = ''; + if (! $this->length() ) + break; + // ~ General Sibling Selector + } else if ($s[0] == '~') { + $this->runQuery($XQuery); + $XQuery = ''; + $this->elements = $this + ->siblings( + substr($s, 1) + )->elements; + if (! $this->length() ) + break; + // + Adjacent sibling selectors + } else if ($s[0] == '+') { + // TODO /following-sibling:: + $this->runQuery($XQuery); + $XQuery = ''; + $subSelector = substr($s, 1); + $subElements = $this->elements; + $this->elements = array(); + foreach($subElements as $node) { + // search first DOMElement sibling + $test = $node->nextSibling; + while($test && ! ($test instanceof DOMELEMENT)) + $test = $test->nextSibling; + if ($test && $this->is($subSelector, $test)) + $this->elements[] = $test; + } + if (! $this->length() ) + break; + // PSEUDO CLASSES + } else if ($s[0] == ':') { + // TODO optimization for :first :last + if ($XQuery) { + $this->runQuery($XQuery); + $XQuery = ''; + } + if (! $this->length()) + break; + $this->pseudoClasses($s); + if (! $this->length()) + break; + // DIRECT DESCENDANDS + } else if ($s == '>') { + $XQuery .= '/'; + $delimiterBefore = 2; + // ALL DESCENDANDS + } else if ($s == ' ') { + $XQuery .= '//'; + $delimiterBefore = 2; + // ERRORS + } else { + phpQuery::debug("Unrecognized token '$s'"); + } + $delimiterBefore = $delimiterBefore === 2; + } + // run query if any + if ($XQuery && $XQuery != '//') { + $this->runQuery($XQuery); + $XQuery = ''; + } + foreach($this->elements as $node) + if (! $this->elementsContainsNode($node, $stack)) + $stack[] = $node; + } + $this->elements = $stack; + return $this->newInstance(); + } + /** + * @todo create API for classes with pseudoselectors + * @access private + */ + protected function pseudoClasses($class) { + // TODO clean args parsing ? + $class = ltrim($class, ':'); + $haveArgs = mb_strpos($class, '('); + if ($haveArgs !== false) { + $args = substr($class, $haveArgs+1, -1); + $class = substr($class, 0, $haveArgs); + } + switch($class) { + case 'even': + case 'odd': + $stack = array(); + foreach($this->elements as $i => $node) { + if ($class == 'even' && ($i%2) == 0) + $stack[] = $node; + else if ( $class == 'odd' && $i % 2 ) + $stack[] = $node; + } + $this->elements = $stack; + break; + case 'eq': + $k = intval($args); + $this->elements = isset( $this->elements[$k] ) + ? array( $this->elements[$k] ) + : array(); + break; + case 'gt': + $this->elements = array_slice($this->elements, $args+1); + break; + case 'lt': + $this->elements = array_slice($this->elements, 0, $args+1); + break; + case 'first': + if (isset($this->elements[0])) + $this->elements = array($this->elements[0]); + break; + case 'last': + if ($this->elements) + $this->elements = array($this->elements[count($this->elements)-1]); + break; + /*case 'parent': + $stack = array(); + foreach($this->elements as $node) { + if ( $node->childNodes->length ) + $stack[] = $node; + } + $this->elements = $stack; + break;*/ + case 'contains': + $text = trim($args, "\"'"); + $stack = array(); + foreach($this->elements as $node) { + if (mb_stripos($node->textContent, $text) === false) + continue; + $stack[] = $node; + } + $this->elements = $stack; + break; + case 'not': + $selector = self::unQuote($args); + $this->elements = $this->not($selector)->stack(); + break; + case 'slice': + // TODO jQuery difference ? + $args = explode(',', + str_replace(', ', ',', trim($args, "\"'")) + ); + $start = $args[0]; + $end = isset($args[1]) + ? $args[1] + : null; + if ($end > 0) + $end = $end-$start; + $this->elements = array_slice($this->elements, $start, $end); + break; + case 'has': + $selector = trim($args, "\"'"); + $stack = array(); + foreach($this->stack(1) as $el) { + if ($this->find($selector, $el, true)->length) + $stack[] = $el; + } + $this->elements = $stack; + break; + case 'submit': + case 'reset': + $this->elements = phpQuery::merge( + $this->map(array($this, 'is'), + "input[type=$class]", new CallbackParam() + ), + $this->map(array($this, 'is'), + "button[type=$class]", new CallbackParam() + ) + ); + break; +// $stack = array(); +// foreach($this->elements as $node) +// if ($node->is('input[type=submit]') || $node->is('button[type=submit]')) +// $stack[] = $el; +// $this->elements = $stack; + case 'input': + $this->elements = $this->map( + array($this, 'is'), + 'input', new CallbackParam() + )->elements; + break; + case 'password': + case 'checkbox': + case 'radio': + case 'hidden': + case 'image': + case 'file': + $this->elements = $this->map( + array($this, 'is'), + "input[type=$class]", new CallbackParam() + )->elements; + break; + case 'parent': + $this->elements = $this->map( + create_function('$node', ' + return $node instanceof DOMELEMENT && $node->childNodes->length + ? $node : null;') + )->elements; + break; + case 'empty': + $this->elements = $this->map( + create_function('$node', ' + return $node instanceof DOMELEMENT && $node->childNodes->length + ? null : $node;') + )->elements; + break; + case 'disabled': + case 'selected': + case 'checked': + $this->elements = $this->map( + array($this, 'is'), + "[$class]", new CallbackParam() + )->elements; + break; + case 'enabled': + $this->elements = $this->map( + create_function('$node', ' + return pq($node)->not(":disabled") ? $node : null;') + )->elements; + break; + case 'header': + $this->elements = $this->map( + create_function('$node', + '$isHeader = isset($node->tagName) && in_array($node->tagName, array( + "h1", "h2", "h3", "h4", "h5", "h6", "h7" + )); + return $isHeader + ? $node + : null;') + )->elements; +// $this->elements = $this->map( +// create_function('$node', '$node = pq($node); +// return $node->is("h1") +// || $node->is("h2") +// || $node->is("h3") +// || $node->is("h4") +// || $node->is("h5") +// || $node->is("h6") +// || $node->is("h7") +// ? $node +// : null;') +// )->elements; + break; + case 'only-child': + $this->elements = $this->map( + create_function('$node', + 'return pq($node)->siblings()->size() == 0 ? $node : null;') + )->elements; + break; + case 'first-child': + $this->elements = $this->map( + create_function('$node', 'return pq($node)->prevAll()->size() == 0 ? $node : null;') + )->elements; + break; + case 'last-child': + $this->elements = $this->map( + create_function('$node', 'return pq($node)->nextAll()->size() == 0 ? $node : null;') + )->elements; + break; + case 'nth-child': + $param = trim($args, "\"'"); + if (! $param) + break; + // nth-child(n+b) to nth-child(1n+b) + if ($param{0} == 'n') + $param = '1'.$param; + // :nth-child(index/even/odd/equation) + if ($param == 'even' || $param == 'odd') + $mapped = $this->map( + create_function('$node, $param', + '$index = pq($node)->prevAll()->size()+1; + if ($param == "even" && ($index%2) == 0) + return $node; + else if ($param == "odd" && $index%2 == 1) + return $node; + else + return null;'), + new CallbackParam(), $param + ); + else if (mb_strlen($param) > 1 && $param{1} == 'n') + // an+b + $mapped = $this->map( + create_function('$node, $param', + '$prevs = pq($node)->prevAll()->size(); + $index = 1+$prevs; + $b = mb_strlen($param) > 3 + ? $param{3} + : 0; + $a = $param{0}; + if ($b && $param{2} == "-") + $b = -$b; + if ($a > 0) { + return ($index-$b)%$a == 0 + ? $node + : null; + phpQuery::debug($a."*".floor($index/$a)."+$b-1 == ".($a*floor($index/$a)+$b-1)." ?= $prevs"); + return $a*floor($index/$a)+$b-1 == $prevs + ? $node + : null; + } else if ($a == 0) + return $index == $b + ? $node + : null; + else + // negative value + return $index <= $b + ? $node + : null; +// if (! $b) +// return $index%$a == 0 +// ? $node +// : null; +// else +// return ($index-$b)%$a == 0 +// ? $node +// : null; + '), + new CallbackParam(), $param + ); + else + // index + $mapped = $this->map( + create_function('$node, $index', + '$prevs = pq($node)->prevAll()->size(); + if ($prevs && $prevs == $index-1) + return $node; + else if (! $prevs && $index == 1) + return $node; + else + return null;'), + new CallbackParam(), $param + ); + $this->elements = $mapped->elements; + break; + default: + $this->debug("Unknown pseudoclass '{$class}', skipping..."); + } + } + /** + * @access private + */ + protected function __pseudoClassParam($paramsString) { + // TODO; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function is($selector, $nodes = null) { + phpQuery::debug(array("Is:", $selector)); + if (! $selector) + return false; + $oldStack = $this->elements; + $returnArray = false; + if ($nodes && is_array($nodes)) { + $this->elements = $nodes; + } else if ($nodes) + $this->elements = array($nodes); + $this->filter($selector, true); + $stack = $this->elements; + $this->elements = $oldStack; + if ($nodes) + return $stack ? $stack : null; + return (bool)count($stack); + } + /** + * Enter description here... + * jQuery difference. + * + * Callback: + * - $index int + * - $node DOMNode + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @link http://docs.jquery.com/Traversing/filter + */ + public function filterCallback($callback, $_skipHistory = false) { + if (! $_skipHistory) { + $this->elementsBackup = $this->elements; + $this->debug("Filtering by callback"); + } + $newStack = array(); + foreach($this->elements as $index => $node) { + $result = phpQuery::callbackRun($callback, array($index, $node)); + if (is_null($result) || (! is_null($result) && $result)) + $newStack[] = $node; + } + $this->elements = $newStack; + return $_skipHistory + ? $this + : $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @link http://docs.jquery.com/Traversing/filter + */ + public function filter($selectors, $_skipHistory = false) { + if ($selectors instanceof Callback OR $selectors instanceof Closure) + return $this->filterCallback($selectors, $_skipHistory); + if (! $_skipHistory) + $this->elementsBackup = $this->elements; + $notSimpleSelector = array(' ', '>', '~', '+', '/'); + if (! is_array($selectors)) + $selectors = $this->parseSelector($selectors); + if (! $_skipHistory) + $this->debug(array("Filtering:", $selectors)); + $finalStack = array(); + foreach($selectors as $selector) { + $stack = array(); + if (! $selector) + break; + // avoid first space or / + if (in_array($selector[0], $notSimpleSelector)) + $selector = array_slice($selector, 1); + // PER NODE selector chunks + foreach($this->stack() as $node) { + $break = false; + foreach($selector as $s) { + if (!($node instanceof DOMELEMENT)) { + // all besides DOMElement + if ( $s[0] == '[') { + $attr = trim($s, '[]'); + if ( mb_strpos($attr, '=')) { + list( $attr, $val ) = explode('=', $attr); + if ($attr == 'nodeType' && $node->nodeType != $val) + $break = true; + } + } else + $break = true; + } else { + // DOMElement only + // ID + if ( $s[0] == '#') { + if ( $node->getAttribute('id') != substr($s, 1) ) + $break = true; + // CLASSES + } else if ( $s[0] == '.') { + if (! $this->matchClasses( $s, $node ) ) + $break = true; + // ATTRS + } else if ( $s[0] == '[') { + // strip side brackets + $attr = trim($s, '[]'); + if (mb_strpos($attr, '=')) { + list($attr, $val) = explode('=', $attr); + $val = self::unQuote($val); + if ($attr == 'nodeType') { + if ($val != $node->nodeType) + $break = true; + } else if ($this->isRegexp($attr)) { + $val = extension_loaded('mbstring') && phpQuery::$mbstringSupport + ? quotemeta(trim($val, '"\'')) + : preg_quote(trim($val, '"\''), '@'); + // switch last character + switch( substr($attr, -1)) { + // quotemeta used insted of preg_quote + // http://code.google.com/p/phpquery/issues/detail?id=76 + case '^': + $pattern = '^'.$val; + break; + case '*': + $pattern = '.*'.$val.'.*'; + break; + case '$': + $pattern = '.*'.$val.'$'; + break; + } + // cut last character + $attr = substr($attr, 0, -1); + $isMatch = extension_loaded('mbstring') && phpQuery::$mbstringSupport + ? mb_ereg_match($pattern, $node->getAttribute($attr)) + : preg_match("@{$pattern}@", $node->getAttribute($attr)); + if (! $isMatch) + $break = true; + } else if ($node->getAttribute($attr) != $val) + $break = true; + } else if (! $node->hasAttribute($attr)) + $break = true; + // PSEUDO CLASSES + } else if ( $s[0] == ':') { + // skip + // TAG + } else if (trim($s)) { + if ($s != '*') { + // TODO namespaces + if (isset($node->tagName)) { + if ($node->tagName != $s) + $break = true; + } else if ($s == 'html' && ! $this->isRoot($node)) + $break = true; + } + // AVOID NON-SIMPLE SELECTORS + } else if (in_array($s, $notSimpleSelector)) { + $break = true; + $this->debug(array('Skipping non simple selector', $selector)); + } + } + if ($break) + break; + } + // if element passed all chunks of selector - add it to new stack + if (! $break ) + $stack[] = $node; + } + $tmpStack = $this->elements; + $this->elements = $stack; + // PER ALL NODES selector chunks + foreach($selector as $s) + // PSEUDO CLASSES + if ($s[0] == ':') + $this->pseudoClasses($s); + foreach($this->elements as $node) + // XXX it should be merged without duplicates + // but jQuery doesnt do that + $finalStack[] = $node; + $this->elements = $tmpStack; + } + $this->elements = $finalStack; + if ($_skipHistory) { + return $this; + } else { + $this->debug("Stack length after filter(): ".count($finalStack)); + return $this->newInstance(); + } + } + /** + * + * @param $value + * @return unknown_type + * @TODO implement in all methods using passed parameters + */ + protected static function unQuote($value) { + return $value[0] == '\'' || $value[0] == '"' + ? substr($value, 1, -1) + : $value; + } + /** + * Enter description here... + * + * @link http://docs.jquery.com/Ajax/load + * @return phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo Support $selector + */ + public function load($url, $data = null, $callback = null) { + if ($data && ! is_array($data)) { + $callback = $data; + $data = null; + } + if (mb_strpos($url, ' ') !== false) { + $matches = null; + if (extension_loaded('mbstring') && phpQuery::$mbstringSupport) + mb_ereg('^([^ ]+) (.*)$', $url, $matches); + else + preg_match('^([^ ]+) (.*)$', $url, $matches); + $url = $matches[1]; + $selector = $matches[2]; + // FIXME this sucks, pass as callback param + $this->_loadSelector = $selector; + } + $ajax = array( + 'url' => $url, + 'type' => $data ? 'POST' : 'GET', + 'data' => $data, + 'complete' => $callback, + 'success' => array($this, '__loadSuccess') + ); + phpQuery::ajax($ajax); + return $this; + } + /** + * @access private + * @param $html + * @return unknown_type + */ + public function __loadSuccess($html) { + if ($this->_loadSelector) { + $html = phpQuery::newDocument($html)->find($this->_loadSelector); + unset($this->_loadSelector); + } + foreach($this->stack(1) as $node) { + phpQuery::pq($node, $this->getDocumentID()) + ->markup($html); + } + } + /** + * Enter description here... + * + * @return phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo + */ + public function css() { + // TODO + return $this; + } + /** + * @todo + * + */ + public function show(){ + // TODO + return $this; + } + /** + * @todo + * + */ + public function hide(){ + // TODO + return $this; + } + /** + * Trigger a type of event on every matched element. + * + * @param unknown_type $type + * @param unknown_type $data + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO support more than event in $type (space-separated) + */ + public function trigger($type, $data = array()) { + foreach($this->elements as $node) + phpQueryEvents::trigger($this->getDocumentID(), $type, $data, $node); + return $this; + } + /** + * This particular method triggers all bound event handlers on an element (for a specific event type) WITHOUT executing the browsers default actions. + * + * @param unknown_type $type + * @param unknown_type $data + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO + */ + public function triggerHandler($type, $data = array()) { + // TODO; + } + /** + * Binds a handler to one or more events (like click) for each matched element. + * Can also bind custom events. + * + * @param unknown_type $type + * @param unknown_type $data Optional + * @param unknown_type $callback + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO support '!' (exclusive) events + * @TODO support more than event in $type (space-separated) + */ + public function bind($type, $data, $callback = null) { + // TODO check if $data is callable, not using is_callable + if (! isset($callback)) { + $callback = $data; + $data = null; + } + foreach($this->elements as $node) + phpQueryEvents::add($this->getDocumentID(), $node, $type, $data, $callback); + return $this; + } + /** + * Enter description here... + * + * @param unknown_type $type + * @param unknown_type $callback + * @return unknown + * @TODO namespace events + * @TODO support more than event in $type (space-separated) + */ + public function unbind($type = null, $callback = null) { + foreach($this->elements as $node) + phpQueryEvents::remove($this->getDocumentID(), $node, $type, $callback); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function change($callback = null) { + if ($callback) + return $this->bind('change', $callback); + return $this->trigger('change'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function submit($callback = null) { + if ($callback) + return $this->bind('submit', $callback); + return $this->trigger('submit'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function click($callback = null) { + if ($callback) + return $this->bind('click', $callback); + return $this->trigger('click'); + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapAllOld($wrapper) { + $wrapper = pq($wrapper)->_clone(); + if (! $wrapper->length() || ! $this->length() ) + return $this; + $wrapper->insertBefore($this->elements[0]); + $deepest = $wrapper->elements[0]; + while($deepest->firstChild && $deepest->firstChild instanceof DOMELEMENT) + $deepest = $deepest->firstChild; + pq($deepest)->append($this); + return $this; + } + /** + * Enter description here... + * + * TODO testme... + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapAll($wrapper) { + if (! $this->length()) + return $this; + return phpQuery::pq($wrapper, $this->getDocumentID()) + ->clone() + ->insertBefore($this->get(0)) + ->map(array($this, '___wrapAllCallback')) + ->append($this); + } + /** + * + * @param $node + * @return unknown_type + * @access private + */ + public function ___wrapAllCallback($node) { + $deepest = $node; + while($deepest->firstChild && $deepest->firstChild instanceof DOMELEMENT) + $deepest = $deepest->firstChild; + return $deepest; + } + /** + * Enter description here... + * NON JQUERY METHOD + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapAllPHP($codeBefore, $codeAfter) { + return $this + ->slice(0, 1) + ->beforePHP($codeBefore) + ->end() + ->slice(-1) + ->afterPHP($codeAfter) + ->end(); + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrap($wrapper) { + foreach($this->stack() as $node) + phpQuery::pq($node, $this->getDocumentID())->wrapAll($wrapper); + return $this; + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapPHP($codeBefore, $codeAfter) { + foreach($this->stack() as $node) + phpQuery::pq($node, $this->getDocumentID())->wrapAllPHP($codeBefore, $codeAfter); + return $this; + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapInner($wrapper) { + foreach($this->stack() as $node) + phpQuery::pq($node, $this->getDocumentID())->contents()->wrapAll($wrapper); + return $this; + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function wrapInnerPHP($codeBefore, $codeAfter) { + foreach($this->stack(1) as $node) + phpQuery::pq($node, $this->getDocumentID())->contents() + ->wrapAllPHP($codeBefore, $codeAfter); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @testme Support for text nodes + */ + public function contents() { + $stack = array(); + foreach($this->stack(1) as $el) { + // FIXME (fixed) http://code.google.com/p/phpquery/issues/detail?id=56 +// if (! isset($el->childNodes)) +// continue; + foreach($el->childNodes as $node) { + $stack[] = $node; + } + } + return $this->newInstance($stack); + } + /** + * Enter description here... + * + * jQuery difference. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function contentsUnwrap() { + foreach($this->stack(1) as $node) { + if (! $node->parentNode ) + continue; + $childNodes = array(); + // any modification in DOM tree breaks childNodes iteration, so cache them first + foreach($node->childNodes as $chNode ) + $childNodes[] = $chNode; + foreach($childNodes as $chNode ) +// $node->parentNode->appendChild($chNode); + $node->parentNode->insertBefore($chNode, $node); + $node->parentNode->removeChild($node); + } + return $this; + } + /** + * Enter description here... + * + * jQuery difference. + */ + public function switchWith($markup) { + $markup = pq($markup, $this->getDocumentID()); + $content = null; + foreach($this->stack(1) as $node) { + pq($node) + ->contents()->toReference($content)->end() + ->replaceWith($markup->clone()->append($content)); + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function eq($num) { + $oldStack = $this->elements; + $this->elementsBackup = $this->elements; + $this->elements = array(); + if ( isset($oldStack[$num]) ) + $this->elements[] = $oldStack[$num]; + return $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function size() { + return count($this->elements); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @deprecated Use length as attribute + */ + public function length() { + return $this->size(); + } + public function count() { + return $this->size(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo $level + */ + public function end($level = 1) { +// $this->elements = array_pop( $this->history ); +// return $this; +// $this->previous->DOM = $this->DOM; +// $this->previous->XPath = $this->XPath; + return $this->previous + ? $this->previous + : $this; + } + /** + * Enter description here... + * Normal use ->clone() . + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function _clone() { + $newStack = array(); + //pr(array('copy... ', $this->whois())); + //$this->dumpHistory('copy'); + $this->elementsBackup = $this->elements; + foreach($this->elements as $node) { + $newStack[] = $node->cloneNode(true); + } + $this->elements = $newStack; + return $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function replaceWithPHP($code) { + return $this->replaceWith(phpQuery::php($code)); + } + /** + * Enter description here... + * + * @param String|phpQuery $content + * @link http://docs.jquery.com/Manipulation/replaceWith#content + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function replaceWith($content) { + return $this->after($content)->remove(); + } + /** + * Enter description here... + * + * @param String $selector + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo this works ? + */ + public function replaceAll($selector) { + foreach(phpQuery::pq($selector, $this->getDocumentID()) as $node) + phpQuery::pq($node, $this->getDocumentID()) + ->after($this->_clone()) + ->remove(); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function remove($selector = null) { + $loop = $selector + ? $this->filter($selector)->elements + : $this->elements; + foreach($loop as $node) { + if (! $node->parentNode ) + continue; + if (isset($node->tagName)) + $this->debug("Removing '{$node->tagName}'"); + $node->parentNode->removeChild($node); + // Mutation event + $event = new DOMEvent(array( + 'target' => $node, + 'type' => 'DOMNodeRemoved' + )); + phpQueryEvents::trigger($this->getDocumentID(), + $event->type, array($event), $node + ); + } + return $this; + } + protected function markupEvents($newMarkup, $oldMarkup, $node) { + if ($node->tagName == 'textarea' && $newMarkup != $oldMarkup) { + $event = new DOMEvent(array( + 'target' => $node, + 'type' => 'change' + )); + phpQueryEvents::trigger($this->getDocumentID(), + $event->type, array($event), $node + ); + } + } + /** + * jQuey difference + * + * @param $markup + * @return unknown_type + * @TODO trigger change event for textarea + */ + public function markup($markup = null, $callback1 = null, $callback2 = null, $callback3 = null) { + $args = func_get_args(); + if ($this->documentWrapper->isXML) + return call_user_func_array(array($this, 'xml'), $args); + else + return call_user_func_array(array($this, 'html'), $args); + } + /** + * jQuey difference + * + * @param $markup + * @return unknown_type + */ + public function markupOuter($callback1 = null, $callback2 = null, $callback3 = null) { + $args = func_get_args(); + if ($this->documentWrapper->isXML) + return call_user_func_array(array($this, 'xmlOuter'), $args); + else + return call_user_func_array(array($this, 'htmlOuter'), $args); + } + /** + * Enter description here... + * + * @param unknown_type $html + * @return string|phpQuery|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO force html result + */ + public function html($html = null, $callback1 = null, $callback2 = null, $callback3 = null) { + if (isset($html)) { + // INSERT + $nodes = $this->documentWrapper->import($html); + $this->empty(); + foreach($this->stack(1) as $alreadyAdded => $node) { + // for now, limit events for textarea + if (($this->isXHTML() || $this->isHTML()) && $node->tagName == 'textarea') + $oldHtml = pq($node, $this->getDocumentID())->markup(); + foreach($nodes as $newNode) { + $node->appendChild($alreadyAdded + ? $newNode->cloneNode(true) + : $newNode + ); + } + // for now, limit events for textarea + if (($this->isXHTML() || $this->isHTML()) && $node->tagName == 'textarea') + $this->markupEvents($html, $oldHtml, $node); + } + return $this; + } else { + // FETCH + $return = $this->documentWrapper->markup($this->elements, true); + $args = func_get_args(); + foreach(array_slice($args, 1) as $callback) { + $return = phpQuery::callbackRun($callback, array($return)); + } + return $return; + } + } + /** + * @TODO force xml result + */ + public function xml($xml = null, $callback1 = null, $callback2 = null, $callback3 = null) { + $args = func_get_args(); + return call_user_func_array(array($this, 'html'), $args); + } + /** + * Enter description here... + * @TODO force html result + * + * @return String + */ + public function htmlOuter($callback1 = null, $callback2 = null, $callback3 = null) { + $markup = $this->documentWrapper->markup($this->elements); + // pass thou callbacks + $args = func_get_args(); + foreach($args as $callback) { + $markup = phpQuery::callbackRun($callback, array($markup)); + } + return $markup; + } + /** + * @TODO force xml result + */ + public function xmlOuter($callback1 = null, $callback2 = null, $callback3 = null) { + $args = func_get_args(); + return call_user_func_array(array($this, 'htmlOuter'), $args); + } + public function __toString() { + return $this->markupOuter(); + } + /** + * Just like html(), but returns markup with VALID (dangerous) PHP tags. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo support returning markup with PHP tags when called without param + */ + public function php($code = null) { + return $this->markupPHP($code); + } + /** + * Enter description here... + * + * @param $code + * @return unknown_type + */ + public function markupPHP($code = null) { + return isset($code) + ? $this->markup(phpQuery::php($code)) + : phpQuery::markupToPHP($this->markup()); + } + /** + * Enter description here... + * + * @param $code + * @return unknown_type + */ + public function markupOuterPHP() { + return phpQuery::markupToPHP($this->markupOuter()); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function children($selector = null) { + $stack = array(); + foreach($this->stack(1) as $node) { +// foreach($node->getElementsByTagName('*') as $newNode) { + foreach($node->childNodes as $newNode) { + if ($newNode->nodeType != 1) + continue; + if ($selector && ! $this->is($selector, $newNode)) + continue; + if ($this->elementsContainsNode($newNode, $stack)) + continue; + $stack[] = $newNode; + } + } + $this->elementsBackup = $this->elements; + $this->elements = $stack; + return $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function ancestors($selector = null) { + return $this->children( $selector ); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function append( $content) { + return $this->insert($content, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function appendPHP( $content) { + return $this->insert("", 'append'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function appendTo( $seletor) { + return $this->insert($seletor, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function prepend( $content) { + return $this->insert($content, __FUNCTION__); + } + /** + * Enter description here... + * + * @todo accept many arguments, which are joined, arrays maybe also + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function prependPHP( $content) { + return $this->insert("", 'prepend'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function prependTo( $seletor) { + return $this->insert($seletor, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function before($content) { + return $this->insert($content, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function beforePHP( $content) { + return $this->insert("", 'before'); + } + /** + * Enter description here... + * + * @param String|phpQuery + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function insertBefore( $seletor) { + return $this->insert($seletor, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function after( $content) { + return $this->insert($content, __FUNCTION__); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function afterPHP( $content) { + return $this->insert("", 'after'); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function insertAfter( $seletor) { + return $this->insert($seletor, __FUNCTION__); + } + /** + * Internal insert method. Don't use it. + * + * @param unknown_type $target + * @param unknown_type $type + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function insert($target, $type) { + $this->debug("Inserting data with '{$type}'"); + $to = false; + switch( $type) { + case 'appendTo': + case 'prependTo': + case 'insertBefore': + case 'insertAfter': + $to = true; + } + switch(gettype($target)) { + case 'string': + $insertFrom = $insertTo = array(); + if ($to) { + // INSERT TO + $insertFrom = $this->elements; + if (phpQuery::isMarkup($target)) { + // $target is new markup, import it + $insertTo = $this->documentWrapper->import($target); + // insert into selected element + } else { + // $tagret is a selector + $thisStack = $this->elements; + $this->toRoot(); + $insertTo = $this->find($target)->elements; + $this->elements = $thisStack; + } + } else { + // INSERT FROM + $insertTo = $this->elements; + $insertFrom = $this->documentWrapper->import($target); + } + break; + case 'object': + $insertFrom = $insertTo = array(); + // phpQuery + if ($target instanceof self) { + if ($to) { + $insertTo = $target->elements; + if ($this->documentFragment && $this->stackIsRoot()) + // get all body children +// $loop = $this->find('body > *')->elements; + // TODO test it, test it hard... +// $loop = $this->newInstance($this->root)->find('> *')->elements; + $loop = $this->root->childNodes; + else + $loop = $this->elements; + // import nodes if needed + $insertFrom = $this->getDocumentID() == $target->getDocumentID() + ? $loop + : $target->documentWrapper->import($loop); + } else { + $insertTo = $this->elements; + if ( $target->documentFragment && $target->stackIsRoot() ) + // get all body children +// $loop = $target->find('body > *')->elements; + $loop = $target->root->childNodes; + else + $loop = $target->elements; + // import nodes if needed + $insertFrom = $this->getDocumentID() == $target->getDocumentID() + ? $loop + : $this->documentWrapper->import($loop); + } + // DOMNODE + } elseif ($target instanceof DOMNODE) { + // import node if needed +// if ( $target->ownerDocument != $this->DOM ) +// $target = $this->DOM->importNode($target, true); + if ( $to) { + $insertTo = array($target); + if ($this->documentFragment && $this->stackIsRoot()) + // get all body children + $loop = $this->root->childNodes; +// $loop = $this->find('body > *')->elements; + else + $loop = $this->elements; + foreach($loop as $fromNode) + // import nodes if needed + $insertFrom[] = ! $fromNode->ownerDocument->isSameNode($target->ownerDocument) + ? $target->ownerDocument->importNode($fromNode, true) + : $fromNode; + } else { + // import node if needed + if (! $target->ownerDocument->isSameNode($this->document)) + $target = $this->document->importNode($target, true); + $insertTo = $this->elements; + $insertFrom[] = $target; + } + } + break; + } + phpQuery::debug("From ".count($insertFrom)."; To ".count($insertTo)." nodes"); + foreach($insertTo as $insertNumber => $toNode) { + // we need static relative elements in some cases + switch( $type) { + case 'prependTo': + case 'prepend': + $firstChild = $toNode->firstChild; + break; + case 'insertAfter': + case 'after': + $nextSibling = $toNode->nextSibling; + break; + } + foreach($insertFrom as $fromNode) { + // clone if inserted already before + $insert = $insertNumber + ? $fromNode->cloneNode(true) + : $fromNode; + switch($type) { + case 'appendTo': + case 'append': +// $toNode->insertBefore( +// $fromNode, +// $toNode->lastChild->nextSibling +// ); + $toNode->appendChild($insert); + $eventTarget = $insert; + break; + case 'prependTo': + case 'prepend': + $toNode->insertBefore( + $insert, + $firstChild + ); + break; + case 'insertBefore': + case 'before': + if (! $toNode->parentNode) + throw new Exception("No parentNode, can't do {$type}()"); + else + $toNode->parentNode->insertBefore( + $insert, + $toNode + ); + break; + case 'insertAfter': + case 'after': + if (! $toNode->parentNode) + throw new Exception("No parentNode, can't do {$type}()"); + else + $toNode->parentNode->insertBefore( + $insert, + $nextSibling + ); + break; + } + // Mutation event + $event = new DOMEvent(array( + 'target' => $insert, + 'type' => 'DOMNodeInserted' + )); + phpQueryEvents::trigger($this->getDocumentID(), + $event->type, array($event), $insert + ); + } + } + return $this; + } + /** + * Enter description here... + * + * @return Int + */ + public function index($subject) { + $index = -1; + $subject = $subject instanceof phpQueryObject + ? $subject->elements[0] + : $subject; + foreach($this->newInstance() as $k => $node) { + if ($node->isSameNode($subject)) + $index = $k; + } + return $index; + } + /** + * Enter description here... + * + * @param unknown_type $start + * @param unknown_type $end + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @testme + */ + public function slice($start, $end = null) { +// $last = count($this->elements)-1; +// $end = $end +// ? min($end, $last) +// : $last; +// if ($start < 0) +// $start = $last+$start; +// if ($start > $last) +// return array(); + if ($end > 0) + $end = $end-$start; + return $this->newInstance( + array_slice($this->elements, $start, $end) + ); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function reverse() { + $this->elementsBackup = $this->elements; + $this->elements = array_reverse($this->elements); + return $this->newInstance(); + } + /** + * Return joined text content. + * @return String + */ + public function text($text = null, $callback1 = null, $callback2 = null, $callback3 = null) { + if (isset($text)) + return $this->html(htmlspecialchars($text)); + $args = func_get_args(); + $args = array_slice($args, 1); + $return = ''; + foreach($this->elements as $node) { + $text = $node->textContent; + if (count($this->elements) > 1 && $text) + $text .= "\n"; + foreach($args as $callback) { + $text = phpQuery::callbackRun($callback, array($text)); + } + $return .= $text; + } + return $return; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function plugin($class, $file = null) { + phpQuery::plugin($class, $file); + return $this; + } + /** + * Deprecated, use $pq->plugin() instead. + * + * @deprecated + * @param $class + * @param $file + * @return unknown_type + */ + public static function extend($class, $file = null) { + return $this->plugin($class, $file); + } + /** + * + * @access private + * @param $method + * @param $args + * @return unknown_type + */ + public function __call($method, $args) { + $aliasMethods = array('clone', 'empty'); + if (isset(phpQuery::$extendMethods[$method])) { + array_unshift($args, $this); + return phpQuery::callbackRun( + phpQuery::$extendMethods[$method], $args + ); + } else if (isset(phpQuery::$pluginsMethods[$method])) { + array_unshift($args, $this); + $class = phpQuery::$pluginsMethods[$method]; + $realClass = "phpQueryObjectPlugin_$class"; + $return = call_user_func_array( + array($realClass, $method), + $args + ); + // XXX deprecate ? + return is_null($return) + ? $this + : $return; + } else if (in_array($method, $aliasMethods)) { + return call_user_func_array(array($this, '_'.$method), $args); + } else + throw new Exception("Method '{$method}' doesnt exist"); + } + /** + * Safe rename of next(). + * + * Use it ONLY when need to call next() on an iterated object (in same time). + * Normaly there is no need to do such thing ;) + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function _next($selector = null) { + return $this->newInstance( + $this->getElementSiblings('nextSibling', $selector, true) + ); + } + /** + * Use prev() and next(). + * + * @deprecated + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function _prev($selector = null) { + return $this->prev($selector); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function prev($selector = null) { + return $this->newInstance( + $this->getElementSiblings('previousSibling', $selector, true) + ); + } + /** + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo + */ + public function prevAll($selector = null) { + return $this->newInstance( + $this->getElementSiblings('previousSibling', $selector) + ); + } + /** + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo FIXME: returns source elements insted of next siblings + */ + public function nextAll($selector = null) { + return $this->newInstance( + $this->getElementSiblings('nextSibling', $selector) + ); + } + /** + * @access private + */ + protected function getElementSiblings($direction, $selector = null, $limitToOne = false) { + $stack = array(); + $count = 0; + foreach($this->stack() as $node) { + $test = $node; + while( isset($test->{$direction}) && $test->{$direction}) { + $test = $test->{$direction}; + if (! $test instanceof DOMELEMENT) + continue; + $stack[] = $test; + if ($limitToOne) + break; + } + } + if ($selector) { + $stackOld = $this->elements; + $this->elements = $stack; + $stack = $this->filter($selector, true)->stack(); + $this->elements = $stackOld; + } + return $stack; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function siblings($selector = null) { + $stack = array(); + $siblings = array_merge( + $this->getElementSiblings('previousSibling', $selector), + $this->getElementSiblings('nextSibling', $selector) + ); + foreach($siblings as $node) { + if (! $this->elementsContainsNode($node, $stack)) + $stack[] = $node; + } + return $this->newInstance($stack); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function not($selector = null) { + if (is_string($selector)) + phpQuery::debug(array('not', $selector)); + else + phpQuery::debug('not'); + $stack = array(); + if ($selector instanceof self || $selector instanceof DOMNODE) { + foreach($this->stack() as $node) { + if ($selector instanceof self) { + $matchFound = false; + foreach($selector->stack() as $notNode) { + if ($notNode->isSameNode($node)) + $matchFound = true; + } + if (! $matchFound) + $stack[] = $node; + } else if ($selector instanceof DOMNODE) { + if (! $selector->isSameNode($node)) + $stack[] = $node; + } else { + if (! $this->is($selector)) + $stack[] = $node; + } + } + } else { + $orgStack = $this->stack(); + $matched = $this->filter($selector, true)->stack(); +// $matched = array(); +// // simulate OR in filter() instead of AND 5y +// foreach($this->parseSelector($selector) as $s) { +// $matched = array_merge($matched, +// $this->filter(array($s))->stack() +// ); +// } + foreach($orgStack as $node) + if (! $this->elementsContainsNode($node, $matched)) + $stack[] = $node; + } + return $this->newInstance($stack); + } + /** + * Enter description here... + * + * @param string|phpQueryObject + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function add($selector = null) { + if (! $selector) + return $this; + $stack = array(); + $this->elementsBackup = $this->elements; + $found = phpQuery::pq($selector, $this->getDocumentID()); + $this->merge($found->elements); + return $this->newInstance(); + } + /** + * @access private + */ + protected function merge() { + foreach(func_get_args() as $nodes) + foreach($nodes as $newNode ) + if (! $this->elementsContainsNode($newNode) ) + $this->elements[] = $newNode; + } + /** + * @access private + * TODO refactor to stackContainsNode + */ + protected function elementsContainsNode($nodeToCheck, $elementsStack = null) { + $loop = ! is_null($elementsStack) + ? $elementsStack + : $this->elements; + foreach($loop as $node) { + if ( $node->isSameNode( $nodeToCheck ) ) + return true; + } + return false; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function parent($selector = null) { + $stack = array(); + foreach($this->elements as $node ) + if ( $node->parentNode && ! $this->elementsContainsNode($node->parentNode, $stack) ) + $stack[] = $node->parentNode; + $this->elementsBackup = $this->elements; + $this->elements = $stack; + if ( $selector ) + $this->filter($selector, true); + return $this->newInstance(); + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function parents($selector = null) { + $stack = array(); + if (! $this->elements ) + $this->debug('parents() - stack empty'); + foreach($this->elements as $node) { + $test = $node; + while( $test->parentNode) { + $test = $test->parentNode; + if ($this->isRoot($test)) + break; + if (! $this->elementsContainsNode($test, $stack)) { + $stack[] = $test; + continue; + } + } + } + $this->elementsBackup = $this->elements; + $this->elements = $stack; + if ( $selector ) + $this->filter($selector, true); + return $this->newInstance(); + } + /** + * Internal stack iterator. + * + * @access private + */ + public function stack($nodeTypes = null) { + if (!isset($nodeTypes)) + return $this->elements; + if (!is_array($nodeTypes)) + $nodeTypes = array($nodeTypes); + $return = array(); + foreach($this->elements as $node) { + if (in_array($node->nodeType, $nodeTypes)) + $return[] = $node; + } + return $return; + } + // TODO phpdoc; $oldAttr is result of hasAttribute, before any changes + protected function attrEvents($attr, $oldAttr, $oldValue, $node) { + // skip events for XML documents + if (! $this->isXHTML() && ! $this->isHTML()) + return; + $event = null; + // identify + $isInputValue = $node->tagName == 'input' + && ( + in_array($node->getAttribute('type'), + array('text', 'password', 'hidden')) + || !$node->getAttribute('type') + ); + $isRadio = $node->tagName == 'input' + && $node->getAttribute('type') == 'radio'; + $isCheckbox = $node->tagName == 'input' + && $node->getAttribute('type') == 'checkbox'; + $isOption = $node->tagName == 'option'; + if ($isInputValue && $attr == 'value' && $oldValue != $node->getAttribute($attr)) { + $event = new DOMEvent(array( + 'target' => $node, + 'type' => 'change' + )); + } else if (($isRadio || $isCheckbox) && $attr == 'checked' && ( + // check + (! $oldAttr && $node->hasAttribute($attr)) + // un-check + || (! $node->hasAttribute($attr) && $oldAttr) + )) { + $event = new DOMEvent(array( + 'target' => $node, + 'type' => 'change' + )); + } else if ($isOption && $node->parentNode && $attr == 'selected' && ( + // select + (! $oldAttr && $node->hasAttribute($attr)) + // un-select + || (! $node->hasAttribute($attr) && $oldAttr) + )) { + $event = new DOMEvent(array( + 'target' => $node->parentNode, + 'type' => 'change' + )); + } + if ($event) { + phpQueryEvents::trigger($this->getDocumentID(), + $event->type, array($event), $node + ); + } + } + public function attr($attr = null, $value = null) { + foreach($this->stack(1) as $node) { + if (! is_null($value)) { + $loop = $attr == '*' + ? $this->getNodeAttrs($node) + : array($attr); + foreach($loop as $a) { + $oldValue = $node->getAttribute($a); + $oldAttr = $node->hasAttribute($a); + // TODO raises an error when charset other than UTF-8 + // while document's charset is also not UTF-8 + @$node->setAttribute($a, $value); + $this->attrEvents($a, $oldAttr, $oldValue, $node); + } + } else if ($attr == '*') { + // jQuery difference + $return = array(); + foreach($node->attributes as $n => $v) + $return[$n] = $v->value; + return $return; + } else + return $node->hasAttribute($attr) + ? $node->getAttribute($attr) + : null; + } + return is_null($value) + ? '' : $this; + } + /** + * @access private + */ + protected function getNodeAttrs($node) { + $return = array(); + foreach($node->attributes as $n => $o) + $return[] = $n; + return $return; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo check CDATA ??? + */ + public function attrPHP($attr, $code) { + if (! is_null($code)) { + $value = '<'.'?php '.$code.' ?'.'>'; + // TODO tempolary solution + // http://code.google.com/p/phpquery/issues/detail?id=17 +// if (function_exists('mb_detect_encoding') && mb_detect_encoding($value) == 'ASCII') +// $value = mb_convert_encoding($value, 'UTF-8', 'HTML-ENTITIES'); + } + foreach($this->stack(1) as $node) { + if (! is_null($code)) { +// $attrNode = $this->DOM->createAttribute($attr); + $node->setAttribute($attr, $value); +// $attrNode->value = $value; +// $node->appendChild($attrNode); + } else if ( $attr == '*') { + // jQuery diff + $return = array(); + foreach($node->attributes as $n => $v) + $return[$n] = $v->value; + return $return; + } else + return $node->getAttribute($attr); + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function removeAttr($attr) { + foreach($this->stack(1) as $node) { + $loop = $attr == '*' + ? $this->getNodeAttrs($node) + : array($attr); + foreach($loop as $a) { + $oldValue = $node->getAttribute($a); + $node->removeAttribute($a); + $this->attrEvents($a, $oldValue, null, $node); + } + } + return $this; + } + /** + * Return form element value. + * + * @return String Fields value. + */ + public function val($val = null) { + if (! isset($val)) { + if ($this->eq(0)->is('select')) { + $selected = $this->eq(0)->find('option[selected=selected]'); + if ($selected->is('[value]')) + return $selected->attr('value'); + else + return $selected->text(); + } else if ($this->eq(0)->is('textarea')) + return $this->eq(0)->markup(); + else + return $this->eq(0)->attr('value'); + } else { + $_val = null; + foreach($this->stack(1) as $node) { + $node = pq($node, $this->getDocumentID()); + if (is_array($val) && in_array($node->attr('type'), array('checkbox', 'radio'))) { + $isChecked = in_array($node->attr('value'), $val) + || in_array($node->attr('name'), $val); + if ($isChecked) + $node->attr('checked', 'checked'); + else + $node->removeAttr('checked'); + } else if ($node->get(0)->tagName == 'select') { + if (! isset($_val)) { + $_val = array(); + if (! is_array($val)) + $_val = array((string)$val); + else + foreach($val as $v) + $_val[] = $v; + } + foreach($node['option']->stack(1) as $option) { + $option = pq($option, $this->getDocumentID()); + $selected = false; + // XXX: workaround for string comparsion, see issue #96 + // http://code.google.com/p/phpquery/issues/detail?id=96 + $selected = is_null($option->attr('value')) + ? in_array($option->markup(), $_val) + : in_array($option->attr('value'), $_val); +// $optionValue = $option->attr('value'); +// $optionText = $option->text(); +// $optionTextLenght = mb_strlen($optionText); +// foreach($_val as $v) +// if ($optionValue == $v) +// $selected = true; +// else if ($optionText == $v && $optionTextLenght == mb_strlen($v)) +// $selected = true; + if ($selected) + $option->attr('selected', 'selected'); + else + $option->removeAttr('selected'); + } + } else if ($node->get(0)->tagName == 'textarea') + $node->markup($val); + else + $node->attr('value', $val); + } + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function andSelf() { + if ( $this->previous ) + $this->elements = array_merge($this->elements, $this->previous->elements); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function addClass( $className) { + if (! $className) + return $this; + foreach($this->stack(1) as $node) { + if (! $this->is(".$className", $node)) + $node->setAttribute( + 'class', + trim($node->getAttribute('class').' '.$className) + ); + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function addClassPHP( $className) { + foreach($this->stack(1) as $node) { + $classes = $node->getAttribute('class'); + $newValue = $classes + ? $classes.' <'.'?php '.$className.' ?'.'>' + : '<'.'?php '.$className.' ?'.'>'; + $node->setAttribute('class', $newValue); + } + return $this; + } + /** + * Enter description here... + * + * @param string $className + * @return bool + */ + public function hasClass($className) { + foreach($this->stack(1) as $node) { + if ( $this->is(".$className", $node)) + return true; + } + return false; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function removeClass($className) { + foreach($this->stack(1) as $node) { + $classes = explode( ' ', $node->getAttribute('class')); + if ( in_array($className, $classes)) { + $classes = array_diff($classes, array($className)); + if ( $classes ) + $node->setAttribute('class', implode(' ', $classes)); + else + $node->removeAttribute('class'); + } + } + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function toggleClass($className) { + foreach($this->stack(1) as $node) { + if ( $this->is( $node, '.'.$className )) + $this->removeClass($className); + else + $this->addClass($className); + } + return $this; + } + /** + * Proper name without underscore (just ->empty()) also works. + * + * Removes all child nodes from the set of matched elements. + * + * Example: + * pq("p")._empty() + * + * HTML: + *

    Hello, Person and person

    + * + * Result: + * [

    ] + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @access private + */ + public function _empty() { + foreach($this->stack(1) as $node) { + // thx to 'dave at dgx dot cz' + $node->nodeValue = ''; + } + return $this; + } + /** + * Enter description here... + * + * @param array|string $callback Expects $node as first param, $index as second + * @param array $scope External variables passed to callback. Use compact('varName1', 'varName2'...) and extract($scope) + * @param array $arg1 Will ba passed as third and futher args to callback. + * @param array $arg2 Will ba passed as fourth and futher args to callback, and so on... + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function each($callback, $param1 = null, $param2 = null, $param3 = null) { + $paramStructure = null; + if (func_num_args() > 1) { + $paramStructure = func_get_args(); + $paramStructure = array_slice($paramStructure, 1); + } + foreach($this->elements as $v) + phpQuery::callbackRun($callback, array($v), $paramStructure); + return $this; + } + /** + * Run callback on actual object. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function callback($callback, $param1 = null, $param2 = null, $param3 = null) { + $params = func_get_args(); + $params[0] = $this; + phpQuery::callbackRun($callback, $params); + return $this; + } + /** + * Enter description here... + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @todo add $scope and $args as in each() ??? + */ + public function map($callback, $param1 = null, $param2 = null, $param3 = null) { +// $stack = array(); +//// foreach($this->newInstance() as $node) { +// foreach($this->newInstance() as $node) { +// $result = call_user_func($callback, $node); +// if ($result) +// $stack[] = $result; +// } + $params = func_get_args(); + array_unshift($params, $this->elements); + return $this->newInstance( + call_user_func_array(array('phpQuery', 'map'), $params) +// phpQuery::map($this->elements, $callback) + ); + } + /** + * Enter description here... + * + * @param $key + * @param $value + */ + public function data($key, $value = null) { + if (! isset($value)) { + // TODO? implement specific jQuery behavior od returning parent values + // is child which we look up doesn't exist + return phpQuery::data($this->get(0), $key, $value, $this->getDocumentID()); + } else { + foreach($this as $node) + phpQuery::data($node, $key, $value, $this->getDocumentID()); + return $this; + } + } + /** + * Enter description here... + * + * @param $key + */ + public function removeData($key) { + foreach($this as $node) + phpQuery::removeData($node, $key, $this->getDocumentID()); + return $this; + } + // INTERFACE IMPLEMENTATIONS + + // ITERATOR INTERFACE + /** + * @access private + */ + public function rewind(){ + $this->debug('iterating foreach'); +// phpQuery::selectDocument($this->getDocumentID()); + $this->elementsBackup = $this->elements; + $this->elementsInterator = $this->elements; + $this->valid = isset( $this->elements[0] ) + ? 1 : 0; +// $this->elements = $this->valid +// ? array($this->elements[0]) +// : array(); + $this->current = 0; + } + /** + * @access private + */ + public function current(){ + return $this->elementsInterator[ $this->current ]; + } + /** + * @access private + */ + public function key(){ + return $this->current; + } + /** + * Double-function method. + * + * First: main iterator interface method. + * Second: Returning next sibling, alias for _next(). + * + * Proper functionality is choosed automagicaly. + * + * @see phpQueryObject::_next() + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public function next($cssSelector = null){ +// if ($cssSelector || $this->valid) +// return $this->_next($cssSelector); + $this->valid = isset( $this->elementsInterator[ $this->current+1 ] ) + ? true + : false; + if (! $this->valid && $this->elementsInterator) { + $this->elementsInterator = null; + } else if ($this->valid) { + $this->current++; + } else { + return $this->_next($cssSelector); + } + } + /** + * @access private + */ + public function valid(){ + return $this->valid; + } + // ITERATOR INTERFACE END + // ARRAYACCESS INTERFACE + /** + * @access private + */ + public function offsetExists($offset) { + return $this->find($offset)->size() > 0; + } + /** + * @access private + */ + public function offsetGet($offset) { + return $this->find($offset); + } + /** + * @access private + */ + public function offsetSet($offset, $value) { +// $this->find($offset)->replaceWith($value); + $this->find($offset)->html($value); + } + /** + * @access private + */ + public function offsetUnset($offset) { + // empty + throw new Exception("Can't do unset, use array interface only for calling queries and replacing HTML."); + } + // ARRAYACCESS INTERFACE END + /** + * Returns node's XPath. + * + * @param unknown_type $oneNode + * @return string + * @TODO use native getNodePath is avaible + * @access private + */ + protected function getNodeXpath($oneNode = null, $namespace = null) { + $return = array(); + $loop = $oneNode + ? array($oneNode) + : $this->elements; +// if ($namespace) +// $namespace .= ':'; + foreach($loop as $node) { + if ($node instanceof DOMDOCUMENT) { + $return[] = ''; + continue; + } + $xpath = array(); + while(! ($node instanceof DOMDOCUMENT)) { + $i = 1; + $sibling = $node; + while($sibling->previousSibling) { + $sibling = $sibling->previousSibling; + $isElement = $sibling instanceof DOMELEMENT; + if ($isElement && $sibling->tagName == $node->tagName) + $i++; + } + $xpath[] = $this->isXML() + ? "*[local-name()='{$node->tagName}'][{$i}]" + : "{$node->tagName}[{$i}]"; + $node = $node->parentNode; + } + $xpath = join('/', array_reverse($xpath)); + $return[] = '/'.$xpath; + } + return $oneNode + ? $return[0] + : $return; + } + // HELPERS + public function whois($oneNode = null) { + $return = array(); + $loop = $oneNode + ? array( $oneNode ) + : $this->elements; + foreach($loop as $node) { + if (isset($node->tagName)) { + $tag = in_array($node->tagName, array('php', 'js')) + ? strtoupper($node->tagName) + : $node->tagName; + $return[] = $tag + .($node->getAttribute('id') + ? '#'.$node->getAttribute('id'):'') + .($node->getAttribute('class') + ? '.'.join('.', explode(' ', $node->getAttribute('class'))):'') + .($node->getAttribute('name') + ? '[name="'.$node->getAttribute('name').'"]':'') + .($node->getAttribute('value') && strpos($node->getAttribute('value'), '<'.'?php') === false + ? '[value="'.substr(str_replace("\n", '', $node->getAttribute('value')), 0, 15).'"]':'') + .($node->getAttribute('value') && strpos($node->getAttribute('value'), '<'.'?php') !== false + ? '[value=PHP]':'') + .($node->getAttribute('selected') + ? '[selected]':'') + .($node->getAttribute('checked') + ? '[checked]':'') + ; + } else if ($node instanceof DOMTEXT) { + if (trim($node->textContent)) + $return[] = 'Text:'.substr(str_replace("\n", ' ', $node->textContent), 0, 15); + } else { + + } + } + return $oneNode && isset($return[0]) + ? $return[0] + : $return; + } + /** + * Dump htmlOuter and preserve chain. Usefull for debugging. + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * + */ + public function dump() { + print 'DUMP #'.(phpQuery::$dumpCount++).' '; + $debug = phpQuery::$debug; + phpQuery::$debug = false; +// print __FILE__.':'.__LINE__."\n"; + var_dump($this->htmlOuter()); + return $this; + } + public function dumpWhois() { + print 'DUMP #'.(phpQuery::$dumpCount++).' '; + $debug = phpQuery::$debug; + phpQuery::$debug = false; +// print __FILE__.':'.__LINE__."\n"; + var_dump('whois', $this->whois()); + phpQuery::$debug = $debug; + return $this; + } + public function dumpLength() { + print 'DUMP #'.(phpQuery::$dumpCount++).' '; + $debug = phpQuery::$debug; + phpQuery::$debug = false; +// print __FILE__.':'.__LINE__."\n"; + var_dump('length', $this->length()); + phpQuery::$debug = $debug; + return $this; + } + public function dumpTree($html = true, $title = true) { + $output = $title + ? 'DUMP #'.(phpQuery::$dumpCount++)." \n" : ''; + $debug = phpQuery::$debug; + phpQuery::$debug = false; + foreach($this->stack() as $node) + $output .= $this->__dumpTree($node); + phpQuery::$debug = $debug; + print $html + ? nl2br(str_replace(' ', ' ', $output)) + : $output; + return $this; + } + private function __dumpTree($node, $intend = 0) { + $whois = $this->whois($node); + $return = ''; + if ($whois) + $return .= str_repeat(' - ', $intend).$whois."\n"; + if (isset($node->childNodes)) + foreach($node->childNodes as $chNode) + $return .= $this->__dumpTree($chNode, $intend+1); + return $return; + } + /** + * Dump htmlOuter and stop script execution. Usefull for debugging. + * + */ + public function dumpDie() { + print __FILE__.':'.__LINE__; + var_dump($this->htmlOuter()); + die(); + } +} + + +// -- Multibyte Compatibility functions --------------------------------------- +// http://svn.iphonewebdev.com/lace/lib/mb_compat.php + +/** + * mb_internal_encoding() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_internal_encoding')) +{ + function mb_internal_encoding($enc) {return true; } +} + +/** + * mb_regex_encoding() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_regex_encoding')) +{ + function mb_regex_encoding($enc) {return true; } +} + +/** + * mb_strlen() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_strlen')) +{ + function mb_strlen($str) + { + return strlen($str); + } +} + +/** + * mb_strpos() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_strpos')) +{ + function mb_strpos($haystack, $needle, $offset=0) + { + return strpos($haystack, $needle, $offset); + } +} +/** + * mb_stripos() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_stripos')) +{ + function mb_stripos($haystack, $needle, $offset=0) + { + return stripos($haystack, $needle, $offset); + } +} + +/** + * mb_substr() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_substr')) +{ + function mb_substr($str, $start, $length=0) + { + return substr($str, $start, $length); + } +} + +/** + * mb_substr_count() + * + * Included for mbstring pseudo-compatability. + */ +if (!function_exists('mb_substr_count')) +{ + function mb_substr_count($haystack, $needle) + { + return substr_count($haystack, $needle); + } +} + + +/** + * Static namespace for phpQuery functions. + * + * @author Tobiasz Cudnik + * @package phpQuery + */ +abstract class phpQuery { + /** + * XXX: Workaround for mbstring problems + * + * @var bool + */ + public static $mbstringSupport = true; + public static $debug = false; + public static $documents = array(); + public static $defaultDocumentID = null; +// public static $defaultDoctype = 'html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"'; + /** + * Applies only to HTML. + * + * @var unknown_type + */ + public static $defaultDoctype = ''; + public static $defaultCharset = 'UTF-8'; + /** + * Static namespace for plugins. + * + * @var object + */ + public static $plugins = array(); + /** + * List of loaded plugins. + * + * @var unknown_type + */ + public static $pluginsLoaded = array(); + public static $pluginsMethods = array(); + public static $pluginsStaticMethods = array(); + public static $extendMethods = array(); + /** + * @TODO implement + */ + public static $extendStaticMethods = array(); + /** + * Hosts allowed for AJAX connections. + * Dot '.' means $_SERVER['HTTP_HOST'] (if any). + * + * @var array + */ + public static $ajaxAllowedHosts = array( + '.' + ); + /** + * AJAX settings. + * + * @var array + * XXX should it be static or not ? + */ + public static $ajaxSettings = array( + 'url' => '',//TODO + 'global' => true, + 'type' => "GET", + 'timeout' => null, + 'contentType' => "application/x-www-form-urlencoded", + 'processData' => true, +// 'async' => true, + 'data' => null, + 'username' => null, + 'password' => null, + 'accepts' => array( + 'xml' => "application/xml, text/xml", + 'html' => "text/html", + 'script' => "text/javascript, application/javascript", + 'json' => "application/json, text/javascript", + 'text' => "text/plain", + '_default' => "*/*" + ) + ); + public static $lastModified = null; + public static $active = 0; + public static $dumpCount = 0; + /** + * Multi-purpose function. + * Use pq() as shortcut. + * + * In below examples, $pq is any result of pq(); function. + * + * 1. Import markup into existing document (without any attaching): + * - Import into selected document: + * pq('
    ') // DOESNT accept text nodes at beginning of input string ! + * - Import into document with ID from $pq->getDocumentID(): + * pq('
    ', $pq->getDocumentID()) + * - Import into same document as DOMNode belongs to: + * pq('
    ', DOMNode) + * - Import into document from phpQuery object: + * pq('
    ', $pq) + * + * 2. Run query: + * - Run query on last selected document: + * pq('div.myClass') + * - Run query on document with ID from $pq->getDocumentID(): + * pq('div.myClass', $pq->getDocumentID()) + * - Run query on same document as DOMNode belongs to and use node(s)as root for query: + * pq('div.myClass', DOMNode) + * - Run query on document from phpQuery object + * and use object's stack as root node(s) for query: + * pq('div.myClass', $pq) + * + * @param string|DOMNode|DOMNodeList|array $arg1 HTML markup, CSS Selector, DOMNode or array of DOMNodes + * @param string|phpQueryObject|DOMNode $context DOM ID from $pq->getDocumentID(), phpQuery object (determines also query root) or DOMNode (determines also query root) + * + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery|QueryTemplatesPhpQuery|false + * phpQuery object or false in case of error. + */ + public static function pq($arg1, $context = null) { + if ($arg1 instanceof DOMNODE && ! isset($context)) { + foreach(phpQuery::$documents as $documentWrapper) { + $compare = $arg1 instanceof DOMDocument + ? $arg1 : $arg1->ownerDocument; + if ($documentWrapper->document->isSameNode($compare)) + $context = $documentWrapper->id; + } + } + if (! $context) { + $domId = self::$defaultDocumentID; + if (! $domId) + throw new Exception("Can't use last created DOM, because there isn't any. Use phpQuery::newDocument() first."); +// } else if (is_object($context) && ($context instanceof PHPQUERY || is_subclass_of($context, 'phpQueryObject'))) + } else if (is_object($context) && $context instanceof phpQueryObject) + $domId = $context->getDocumentID(); + else if ($context instanceof DOMDOCUMENT) { + $domId = self::getDocumentID($context); + if (! $domId) { + //throw new Exception('Orphaned DOMDocument'); + $domId = self::newDocument($context)->getDocumentID(); + } + } else if ($context instanceof DOMNODE) { + $domId = self::getDocumentID($context); + if (! $domId) { + throw new Exception('Orphaned DOMNode'); +// $domId = self::newDocument($context->ownerDocument); + } + } else + $domId = $context; + if ($arg1 instanceof phpQueryObject) { +// if (is_object($arg1) && (get_class($arg1) == 'phpQueryObject' || $arg1 instanceof PHPQUERY || is_subclass_of($arg1, 'phpQueryObject'))) { + /** + * Return $arg1 or import $arg1 stack if document differs: + * pq(pq('
    ')) + */ + if ($arg1->getDocumentID() == $domId) + return $arg1; + $class = get_class($arg1); + // support inheritance by passing old object to overloaded constructor + $phpQuery = $class != 'phpQuery' + ? new $class($arg1, $domId) + : new phpQueryObject($domId); + $phpQuery->elements = array(); + foreach($arg1->elements as $node) + $phpQuery->elements[] = $phpQuery->document->importNode($node, true); + return $phpQuery; + } else if ($arg1 instanceof DOMNODE || (is_array($arg1) && isset($arg1[0]) && $arg1[0] instanceof DOMNODE)) { + /* + * Wrap DOM nodes with phpQuery object, import into document when needed: + * pq(array($domNode1, $domNode2)) + */ + $phpQuery = new phpQueryObject($domId); + if (!($arg1 instanceof DOMNODELIST) && ! is_array($arg1)) + $arg1 = array($arg1); + $phpQuery->elements = array(); + foreach($arg1 as $node) { + $sameDocument = $node->ownerDocument instanceof DOMDOCUMENT + && ! $node->ownerDocument->isSameNode($phpQuery->document); + $phpQuery->elements[] = $sameDocument + ? $phpQuery->document->importNode($node, true) + : $node; + } + return $phpQuery; + } else if (self::isMarkup($arg1)) { + /** + * Import HTML: + * pq('
    ') + */ + $phpQuery = new phpQueryObject($domId); + return $phpQuery->newInstance( + $phpQuery->documentWrapper->import($arg1) + ); + } else { + /** + * Run CSS query: + * pq('div.myClass') + */ + $phpQuery = new phpQueryObject($domId); +// if ($context && ($context instanceof PHPQUERY || is_subclass_of($context, 'phpQueryObject'))) + if ($context && $context instanceof phpQueryObject) + $phpQuery->elements = $context->elements; + else if ($context && $context instanceof DOMNODELIST) { + $phpQuery->elements = array(); + foreach($context as $node) + $phpQuery->elements[] = $node; + } else if ($context && $context instanceof DOMNODE) + $phpQuery->elements = array($context); + return $phpQuery->find($arg1); + } + } + /** + * Sets default document to $id. Document has to be loaded prior + * to using this method. + * $id can be retrived via getDocumentID() or getDocumentIDRef(). + * + * @param unknown_type $id + */ + public static function selectDocument($id) { + $id = self::getDocumentID($id); + self::debug("Selecting document '$id' as default one"); + self::$defaultDocumentID = self::getDocumentID($id); + } + /** + * Returns document with id $id or last used as phpQueryObject. + * $id can be retrived via getDocumentID() or getDocumentIDRef(). + * Chainable. + * + * @see phpQuery::selectDocument() + * @param unknown_type $id + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function getDocument($id = null) { + if ($id) + phpQuery::selectDocument($id); + else + $id = phpQuery::$defaultDocumentID; + return new phpQueryObject($id); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocument($markup = null, $contentType = null) { + if (! $markup) + $markup = ''; + $documentID = phpQuery::createDocumentWrapper($markup, $contentType); + return new phpQueryObject($documentID); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentHTML($markup = null, $charset = null) { + $contentType = $charset + ? ";charset=$charset" + : ''; + return self::newDocument($markup, "text/html{$contentType}"); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentXML($markup = null, $charset = null) { + $contentType = $charset + ? ";charset=$charset" + : ''; + return self::newDocument($markup, "text/xml{$contentType}"); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentXHTML($markup = null, $charset = null) { + $contentType = $charset + ? ";charset=$charset" + : ''; + return self::newDocument($markup, "application/xhtml+xml{$contentType}"); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentPHP($markup = null, $contentType = "text/html") { + // TODO pass charset to phpToMarkup if possible (use DOMDocumentWrapper function) + $markup = phpQuery::phpToMarkup($markup, self::$defaultCharset); + return self::newDocument($markup, $contentType); + } + public static function phpToMarkup($php, $charset = 'utf-8') { + $regexes = array( + '@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)<'.'?php?(.*?)(?:\\?>)([^\']*)\'@s', + '@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)<'.'?php?(.*?)(?:\\?>)([^"]*)"@s', + ); + foreach($regexes as $regex) + while (preg_match($regex, $php, $matches)) { + $php = preg_replace_callback( + $regex, +// create_function('$m, $charset = "'.$charset.'"', +// 'return $m[1].$m[2] +// .htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset) +// .$m[5].$m[2];' +// ), + array('phpQuery', '_phpToMarkupCallback'), + $php + ); + } + $regex = '@(^|>[^<]*)+?(<\?php(.*?)(\?>))@s'; +//preg_match_all($regex, $php, $matches); +//var_dump($matches); + $php = preg_replace($regex, '\\1', $php); + return $php; + } + public static function _phpToMarkupCallback($php, $charset = 'utf-8') { + return $m[1].$m[2] + .htmlspecialchars("<"."?php".$m[4]."?".">", ENT_QUOTES|ENT_NOQUOTES, $charset) + .$m[5].$m[2]; + } + public static function _markupToPHPCallback($m) { + return "<"."?php ".htmlspecialchars_decode($m[1])." ?".">"; + } + /** + * Converts document markup containing PHP code generated by phpQuery::php() + * into valid (executable) PHP code syntax. + * + * @param string|phpQueryObject $content + * @return string PHP code. + */ + public static function markupToPHP($content) { + if ($content instanceof phpQueryObject) + $content = $content->markupOuter(); + /* ... to */ + $content = preg_replace_callback( + '@\s*\s*@s', +// create_function('$m', +// 'return "<'.'?php ".htmlspecialchars_decode($m[1])." ?'.'>";' +// ), + array('phpQuery', '_markupToPHPCallback'), + $content + ); + /* extra space added to save highlighters */ + $regexes = array( + '@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(\')([^\']*)(?:<|%3C)\\?(?:php)?(.*?)(?:\\?(?:>|%3E))([^\']*)\'@s', + '@(<(?!\\?)(?:[^>]|\\?>)+\\w+\\s*=\\s*)(")([^"]*)(?:<|%3C)\\?(?:php)?(.*?)(?:\\?(?:>|%3E))([^"]*)"@s', + ); + foreach($regexes as $regex) + while (preg_match($regex, $content)) + $content = preg_replace_callback( + $regex, + create_function('$m', + 'return $m[1].$m[2].$m[3]."", " ", "\n", " ", "{", "$", "}", \'"\', "[", "]"), + htmlspecialchars_decode($m[4]) + ) + ." ?>".$m[5].$m[2];' + ), + $content + ); + return $content; + } + /** + * Creates new document from file $file. + * Chainable. + * + * @param string $file URLs allowed. See File wrapper page at php.net for more supported sources. + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentFile($file, $contentType = null) { + $documentID = self::createDocumentWrapper( + file_get_contents($file), $contentType + ); + return new phpQueryObject($documentID); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentFileHTML($file, $charset = null) { + $contentType = $charset + ? ";charset=$charset" + : ''; + return self::newDocumentFile($file, "text/html{$contentType}"); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentFileXML($file, $charset = null) { + $contentType = $charset + ? ";charset=$charset" + : ''; + return self::newDocumentFile($file, "text/xml{$contentType}"); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentFileXHTML($file, $charset = null) { + $contentType = $charset + ? ";charset=$charset" + : ''; + return self::newDocumentFile($file, "application/xhtml+xml{$contentType}"); + } + /** + * Creates new document from markup. + * Chainable. + * + * @param unknown_type $markup + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + */ + public static function newDocumentFilePHP($file, $contentType = null) { + return self::newDocumentPHP(file_get_contents($file), $contentType); + } + /** + * Reuses existing DOMDocument object. + * Chainable. + * + * @param $document DOMDocument + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @TODO support DOMDocument + */ + public static function loadDocument($document) { + // TODO + die('TODO loadDocument'); + } + /** + * Enter description here... + * + * @param unknown_type $html + * @param unknown_type $domId + * @return unknown New DOM ID + * @todo support PHP tags in input + * @todo support passing DOMDocument object from self::loadDocument + */ + protected static function createDocumentWrapper($html, $contentType = null, $documentID = null) { + if (function_exists('domxml_open_mem')) + throw new Exception("Old PHP4 DOM XML extension detected. phpQuery won't work until this extension is enabled."); +// $id = $documentID +// ? $documentID +// : md5(microtime()); + $document = null; + if ($html instanceof DOMDOCUMENT) { + if (self::getDocumentID($html)) { + // document already exists in phpQuery::$documents, make a copy + $document = clone $html; + } else { + // new document, add it to phpQuery::$documents + $wrapper = new DOMDocumentWrapper($html, $contentType, $documentID); + } + } else { + $wrapper = new DOMDocumentWrapper($html, $contentType, $documentID); + } +// $wrapper->id = $id; + // bind document + phpQuery::$documents[$wrapper->id] = $wrapper; + // remember last loaded document + phpQuery::selectDocument($wrapper->id); + return $wrapper->id; + } + /** + * Extend class namespace. + * + * @param string|array $target + * @param array $source + * @TODO support string $source + * @return unknown_type + */ + public static function extend($target, $source) { + switch($target) { + case 'phpQueryObject': + $targetRef = &self::$extendMethods; + $targetRef2 = &self::$pluginsMethods; + break; + case 'phpQuery': + $targetRef = &self::$extendStaticMethods; + $targetRef2 = &self::$pluginsStaticMethods; + break; + default: + throw new Exception("Unsupported \$target type"); + } + if (is_string($source)) + $source = array($source => $source); + foreach($source as $method => $callback) { + if (isset($targetRef[$method])) { +// throw new Exception + self::debug("Duplicate method '{$method}', can\'t extend '{$target}'"); + continue; + } + if (isset($targetRef2[$method])) { +// throw new Exception + self::debug("Duplicate method '{$method}' from plugin '{$targetRef2[$method]}'," + ." can\'t extend '{$target}'"); + continue; + } + $targetRef[$method] = $callback; + } + return true; + } + /** + * Extend phpQuery with $class from $file. + * + * @param string $class Extending class name. Real class name can be prepended phpQuery_. + * @param string $file Filename to include. Defaults to "{$class}.php". + */ + public static function plugin($class, $file = null) { + // TODO $class checked agains phpQuery_$class +// if (strpos($class, 'phpQuery') === 0) +// $class = substr($class, 8); + if (in_array($class, self::$pluginsLoaded)) + return true; + if (! $file) + $file = $class.'.php'; + $objectClassExists = class_exists('phpQueryObjectPlugin_'.$class); + $staticClassExists = class_exists('phpQueryPlugin_'.$class); + if (! $objectClassExists && ! $staticClassExists) + require_once($file); + self::$pluginsLoaded[] = $class; + // static methods + if (class_exists('phpQueryPlugin_'.$class)) { + $realClass = 'phpQueryPlugin_'.$class; + $vars = get_class_vars($realClass); + $loop = isset($vars['phpQueryMethods']) + && ! is_null($vars['phpQueryMethods']) + ? $vars['phpQueryMethods'] + : get_class_methods($realClass); + foreach($loop as $method) { + if ($method == '__initialize') + continue; + if (! is_callable(array($realClass, $method))) + continue; + if (isset(self::$pluginsStaticMethods[$method])) { + throw new Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '".self::$pluginsStaticMethods[$method]."'"); + return; + } + self::$pluginsStaticMethods[$method] = $class; + } + if (method_exists($realClass, '__initialize')) + call_user_func_array(array($realClass, '__initialize'), array()); + } + // object methods + if (class_exists('phpQueryObjectPlugin_'.$class)) { + $realClass = 'phpQueryObjectPlugin_'.$class; + $vars = get_class_vars($realClass); + $loop = isset($vars['phpQueryMethods']) + && ! is_null($vars['phpQueryMethods']) + ? $vars['phpQueryMethods'] + : get_class_methods($realClass); + foreach($loop as $method) { + if (! is_callable(array($realClass, $method))) + continue; + if (isset(self::$pluginsMethods[$method])) { + throw new Exception("Duplicate method '{$method}' from plugin '{$c}' conflicts with same method from plugin '".self::$pluginsMethods[$method]."'"); + continue; + } + self::$pluginsMethods[$method] = $class; + } + } + return true; + } + /** + * Unloades all or specified document from memory. + * + * @param mixed $documentID @see phpQuery::getDocumentID() for supported types. + */ + public static function unloadDocuments($id = null) { + if (isset($id)) { + if ($id = self::getDocumentID($id)) + unset(phpQuery::$documents[$id]); + } else { + foreach(phpQuery::$documents as $k => $v) { + unset(phpQuery::$documents[$k]); + } + } + } + /** + * Parses phpQuery object or HTML result against PHP tags and makes them active. + * + * @param phpQuery|string $content + * @deprecated + * @return string + */ + public static function unsafePHPTags($content) { + return self::markupToPHP($content); + } + public static function DOMNodeListToArray($DOMNodeList) { + $array = array(); + if (! $DOMNodeList) + return $array; + foreach($DOMNodeList as $node) + $array[] = $node; + return $array; + } + /** + * Checks if $input is HTML string, which has to start with '<'. + * + * @deprecated + * @param String $input + * @return Bool + * @todo still used ? + */ + public static function isMarkup($input) { + return ! is_array($input) && substr(trim($input), 0, 1) == '<'; + } + public static function debug($text) { + if (self::$debug) + print var_dump($text); + } + /** + * Make an AJAX request. + * + * @param array See $options http://docs.jquery.com/Ajax/jQuery.ajax#toptions + * Additional options are: + * 'document' - document for global events, @see phpQuery::getDocumentID() + * 'referer' - implemented + * 'requested_with' - TODO; not implemented (X-Requested-With) + * @return Zend_Http_Client + * @link http://docs.jquery.com/Ajax/jQuery.ajax + * + * @TODO $options['cache'] + * @TODO $options['processData'] + * @TODO $options['xhr'] + * @TODO $options['data'] as string + * @TODO XHR interface + */ + public static function ajax($options = array(), $xhr = null) { + $options = array_merge( + self::$ajaxSettings, $options + ); + $documentID = isset($options['document']) + ? self::getDocumentID($options['document']) + : null; + if ($xhr) { + // reuse existing XHR object, but clean it up + $client = $xhr; +// $client->setParameterPost(null); +// $client->setParameterGet(null); + $client->setAuth(false); + $client->setHeaders("If-Modified-Since", null); + $client->setHeaders("Referer", null); + $client->resetParameters(); + } else { + // create new XHR object + require_once('Zend/Http/Client.php'); + $client = new Zend_Http_Client(); + $client->setCookieJar(); + } + if (isset($options['timeout'])) + $client->setConfig(array( + 'timeout' => $options['timeout'], + )); +// 'maxredirects' => 0, + foreach(self::$ajaxAllowedHosts as $k => $host) + if ($host == '.' && isset($_SERVER['HTTP_HOST'])) + self::$ajaxAllowedHosts[$k] = $_SERVER['HTTP_HOST']; + $host = parse_url($options['url'], PHP_URL_HOST); + if (! in_array($host, self::$ajaxAllowedHosts)) { + throw new Exception("Request not permitted, host '$host' not present in " + ."phpQuery::\$ajaxAllowedHosts"); + } + // JSONP + $jsre = "/=\\?(&|$)/"; + if (isset($options['dataType']) && $options['dataType'] == 'jsonp') { + $jsonpCallbackParam = $options['jsonp'] + ? $options['jsonp'] : 'callback'; + if (strtolower($options['type']) == 'get') { + if (! preg_match($jsre, $options['url'])) { + $sep = strpos($options['url'], '?') + ? '&' : '?'; + $options['url'] .= "$sep$jsonpCallbackParam=?"; + } + } else if ($options['data']) { + $jsonp = false; + foreach($options['data'] as $n => $v) { + if ($v == '?') + $jsonp = true; + } + if (! $jsonp) { + $options['data'][$jsonpCallbackParam] = '?'; + } + } + $options['dataType'] = 'json'; + } + if (isset($options['dataType']) && $options['dataType'] == 'json') { + $jsonpCallback = 'json_'.md5(microtime()); + $jsonpData = $jsonpUrl = false; + if ($options['data']) { + foreach($options['data'] as $n => $v) { + if ($v == '?') + $jsonpData = $n; + } + } + if (preg_match($jsre, $options['url'])) + $jsonpUrl = true; + if ($jsonpData !== false || $jsonpUrl) { + // remember callback name for httpData() + $options['_jsonp'] = $jsonpCallback; + if ($jsonpData !== false) + $options['data'][$jsonpData] = $jsonpCallback; + if ($jsonpUrl) + $options['url'] = preg_replace($jsre, "=$jsonpCallback\\1", $options['url']); + } + } + $client->setUri($options['url']); + $client->setMethod(strtoupper($options['type'])); + if (isset($options['referer']) && $options['referer']) + $client->setHeaders('Referer', $options['referer']); + $client->setHeaders(array( +// 'content-type' => $options['contentType'], + 'User-Agent' => 'Mozilla/5.0 (X11; U; Linux x86; en-US; rv:1.9.0.5) Gecko' + .'/2008122010 Firefox/3.0.5', + // TODO custom charset + 'Accept-Charset' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', +// 'Connection' => 'keep-alive', +// 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language' => 'en-us,en;q=0.5', + )); + if ($options['username']) + $client->setAuth($options['username'], $options['password']); + if (isset($options['ifModified']) && $options['ifModified']) + $client->setHeaders("If-Modified-Since", + self::$lastModified + ? self::$lastModified + : "Thu, 01 Jan 1970 00:00:00 GMT" + ); + $client->setHeaders("Accept", + isset($options['dataType']) + && isset(self::$ajaxSettings['accepts'][ $options['dataType'] ]) + ? self::$ajaxSettings['accepts'][ $options['dataType'] ].", */*" + : self::$ajaxSettings['accepts']['_default'] + ); + // TODO $options['processData'] + if ($options['data'] instanceof phpQueryObject) { + $serialized = $options['data']->serializeArray($options['data']); + $options['data'] = array(); + foreach($serialized as $r) + $options['data'][ $r['name'] ] = $r['value']; + } + if (strtolower($options['type']) == 'get') { + $client->setParameterGet($options['data']); + } else if (strtolower($options['type']) == 'post') { + $client->setEncType($options['contentType']); + $client->setParameterPost($options['data']); + } + if (self::$active == 0 && $options['global']) + phpQueryEvents::trigger($documentID, 'ajaxStart'); + self::$active++; + // beforeSend callback + if (isset($options['beforeSend']) && $options['beforeSend']) + phpQuery::callbackRun($options['beforeSend'], array($client)); + // ajaxSend event + if ($options['global']) + phpQueryEvents::trigger($documentID, 'ajaxSend', array($client, $options)); + if (phpQuery::$debug) { + self::debug("{$options['type']}: {$options['url']}\n"); + self::debug("Options:
    ".var_export($options, true)."
    \n"); +// if ($client->getCookieJar()) +// self::debug("Cookies:
    ".var_export($client->getCookieJar()->getMatchingCookies($options['url']), true)."
    \n"); + } + // request + $response = $client->request(); + if (phpQuery::$debug) { + self::debug('Status: '.$response->getStatus().' / '.$response->getMessage()); + self::debug($client->getLastRequest()); + self::debug($response->getHeaders()); + } + if ($response->isSuccessful()) { + // XXX tempolary + self::$lastModified = $response->getHeader('Last-Modified'); + $data = self::httpData($response->getBody(), $options['dataType'], $options); + if (isset($options['success']) && $options['success']) + phpQuery::callbackRun($options['success'], array($data, $response->getStatus(), $options)); + if ($options['global']) + phpQueryEvents::trigger($documentID, 'ajaxSuccess', array($client, $options)); + } else { + if (isset($options['error']) && $options['error']) + phpQuery::callbackRun($options['error'], array($client, $response->getStatus(), $response->getMessage())); + if ($options['global']) + phpQueryEvents::trigger($documentID, 'ajaxError', array($client, /*$response->getStatus(),*/$response->getMessage(), $options)); + } + if (isset($options['complete']) && $options['complete']) + phpQuery::callbackRun($options['complete'], array($client, $response->getStatus())); + if ($options['global']) + phpQueryEvents::trigger($documentID, 'ajaxComplete', array($client, $options)); + if ($options['global'] && ! --self::$active) + phpQueryEvents::trigger($documentID, 'ajaxStop'); + return $client; +// if (is_null($domId)) +// $domId = self::$defaultDocumentID ? self::$defaultDocumentID : false; +// return new phpQueryAjaxResponse($response, $domId); + } + protected static function httpData($data, $type, $options) { + if (isset($options['dataFilter']) && $options['dataFilter']) + $data = self::callbackRun($options['dataFilter'], array($data, $type)); + if (is_string($data)) { + if ($type == "json") { + if (isset($options['_jsonp']) && $options['_jsonp']) { + $data = preg_replace('/^\s*\w+\((.*)\)\s*$/s', '$1', $data); + } + $data = self::parseJSON($data); + } + } + return $data; + } + /** + * Enter description here... + * + * @param array|phpQuery $data + * + */ + public static function param($data) { + return http_build_query($data, null, '&'); + } + public static function get($url, $data = null, $callback = null, $type = null) { + if (!is_array($data)) { + $callback = $data; + $data = null; + } + // TODO some array_values on this shit + return phpQuery::ajax(array( + 'type' => 'GET', + 'url' => $url, + 'data' => $data, + 'success' => $callback, + 'dataType' => $type, + )); + } + public static function post($url, $data = null, $callback = null, $type = null) { + if (!is_array($data)) { + $callback = $data; + $data = null; + } + return phpQuery::ajax(array( + 'type' => 'POST', + 'url' => $url, + 'data' => $data, + 'success' => $callback, + 'dataType' => $type, + )); + } + public static function getJSON($url, $data = null, $callback = null) { + if (!is_array($data)) { + $callback = $data; + $data = null; + } + // TODO some array_values on this shit + return phpQuery::ajax(array( + 'type' => 'GET', + 'url' => $url, + 'data' => $data, + 'success' => $callback, + 'dataType' => 'json', + )); + } + public static function ajaxSetup($options) { + self::$ajaxSettings = array_merge( + self::$ajaxSettings, + $options + ); + } + public static function ajaxAllowHost($host1, $host2 = null, $host3 = null) { + $loop = is_array($host1) + ? $host1 + : func_get_args(); + foreach($loop as $host) { + if ($host && ! in_array($host, phpQuery::$ajaxAllowedHosts)) { + phpQuery::$ajaxAllowedHosts[] = $host; + } + } + } + public static function ajaxAllowURL($url1, $url2 = null, $url3 = null) { + $loop = is_array($url1) + ? $url1 + : func_get_args(); + foreach($loop as $url) + phpQuery::ajaxAllowHost(parse_url($url, PHP_URL_HOST)); + } + /** + * Returns JSON representation of $data. + * + * @static + * @param mixed $data + * @return string + */ + public static function toJSON($data) { + if (function_exists('json_encode')) + return json_encode($data); + require_once('Zend/Json/Encoder.php'); + return Zend_Json_Encoder::encode($data); + } + /** + * Parses JSON into proper PHP type. + * + * @static + * @param string $json + * @return mixed + */ + public static function parseJSON($json) { + if (function_exists('json_decode')) { + $return = json_decode(trim($json), true); + // json_decode and UTF8 issues + if (isset($return)) + return $return; + } + require_once('Zend/Json/Decoder.php'); + return Zend_Json_Decoder::decode($json); + } + /** + * Returns source's document ID. + * + * @param $source DOMNode|phpQueryObject + * @return string + */ + public static function getDocumentID($source) { + if ($source instanceof DOMDOCUMENT) { + foreach(phpQuery::$documents as $id => $document) { + if ($source->isSameNode($document->document)) + return $id; + } + } else if ($source instanceof DOMNODE) { + foreach(phpQuery::$documents as $id => $document) { + if ($source->ownerDocument->isSameNode($document->document)) + return $id; + } + } else if ($source instanceof phpQueryObject) + return $source->getDocumentID(); + else if (is_string($source) && isset(phpQuery::$documents[$source])) + return $source; + } + /** + * Get DOMDocument object related to $source. + * Returns null if such document doesn't exist. + * + * @param $source DOMNode|phpQueryObject|string + * @return string + */ + public static function getDOMDocument($source) { + if ($source instanceof DOMDOCUMENT) + return $source; + $source = self::getDocumentID($source); + return $source + ? self::$documents[$id]['document'] + : null; + } + + // UTILITIES + // http://docs.jquery.com/Utilities + + /** + * + * @return unknown_type + * @link http://docs.jquery.com/Utilities/jQuery.makeArray + */ + public static function makeArray($obj) { + $array = array(); + if (is_object($object) && $object instanceof DOMNODELIST) { + foreach($object as $value) + $array[] = $value; + } else if (is_object($object) && ! ($object instanceof Iterator)) { + foreach(get_object_vars($object) as $name => $value) + $array[0][$name] = $value; + } else { + foreach($object as $name => $value) + $array[0][$name] = $value; + } + return $array; + } + public static function inArray($value, $array) { + return in_array($value, $array); + } + /** + * + * @param $object + * @param $callback + * @return unknown_type + * @link http://docs.jquery.com/Utilities/jQuery.each + */ + public static function each($object, $callback, $param1 = null, $param2 = null, $param3 = null) { + $paramStructure = null; + if (func_num_args() > 2) { + $paramStructure = func_get_args(); + $paramStructure = array_slice($paramStructure, 2); + } + if (is_object($object) && ! ($object instanceof Iterator)) { + foreach(get_object_vars($object) as $name => $value) + phpQuery::callbackRun($callback, array($name, $value), $paramStructure); + } else { + foreach($object as $name => $value) + phpQuery::callbackRun($callback, array($name, $value), $paramStructure); + } + } + /** + * + * @link http://docs.jquery.com/Utilities/jQuery.map + */ + public static function map($array, $callback, $param1 = null, $param2 = null, $param3 = null) { + $result = array(); + $paramStructure = null; + if (func_num_args() > 2) { + $paramStructure = func_get_args(); + $paramStructure = array_slice($paramStructure, 2); + } + foreach($array as $v) { + $vv = phpQuery::callbackRun($callback, array($v), $paramStructure); +// $callbackArgs = $args; +// foreach($args as $i => $arg) { +// $callbackArgs[$i] = $arg instanceof CallbackParam +// ? $v +// : $arg; +// } +// $vv = call_user_func_array($callback, $callbackArgs); + if (is_array($vv)) { + foreach($vv as $vvv) + $result[] = $vvv; + } else if ($vv !== null) { + $result[] = $vv; + } + } + return $result; + } + /** + * + * @param $callback Callback + * @param $params + * @param $paramStructure + * @return unknown_type + */ + public static function callbackRun($callback, $params = array(), $paramStructure = null) { + if (! $callback) + return; + if ($callback instanceof CallbackParameterToReference) { + // TODO support ParamStructure to select which $param push to reference + if (isset($params[0])) + $callback->callback = $params[0]; + return true; + } + if ($callback instanceof Callback) { + $paramStructure = $callback->params; + $callback = $callback->callback; + } + if (! $paramStructure) + return call_user_func_array($callback, $params); + $p = 0; + foreach($paramStructure as $i => $v) { + $paramStructure[$i] = $v instanceof CallbackParam + ? $params[$p++] + : $v; + } + return call_user_func_array($callback, $paramStructure); + } + /** + * Merge 2 phpQuery objects. + * @param array $one + * @param array $two + * @protected + * @todo node lists, phpQueryObject + */ + public static function merge($one, $two) { + $elements = $one->elements; + foreach($two->elements as $node) { + $exists = false; + foreach($elements as $node2) { + if ($node2->isSameNode($node)) + $exists = true; + } + if (! $exists) + $elements[] = $node; + } + return $elements; +// $one = $one->newInstance(); +// $one->elements = $elements; +// return $one; + } + /** + * + * @param $array + * @param $callback + * @param $invert + * @return unknown_type + * @link http://docs.jquery.com/Utilities/jQuery.grep + */ + public static function grep($array, $callback, $invert = false) { + $result = array(); + foreach($array as $k => $v) { + $r = call_user_func_array($callback, array($v, $k)); + if ($r === !(bool)$invert) + $result[] = $v; + } + return $result; + } + public static function unique($array) { + return array_unique($array); + } + /** + * + * @param $function + * @return unknown_type + * @TODO there are problems with non-static methods, second parameter pass it + * but doesnt verify is method is really callable + */ + public static function isFunction($function) { + return is_callable($function); + } + public static function trim($str) { + return trim($str); + } + /* PLUGINS NAMESPACE */ + /** + * + * @param $url + * @param $callback + * @param $param1 + * @param $param2 + * @param $param3 + * @return phpQueryObject + */ + public static function browserGet($url, $callback, $param1 = null, $param2 = null, $param3 = null) { + if (self::plugin('WebBrowser')) { + $params = func_get_args(); + return self::callbackRun(array(self::$plugins, 'browserGet'), $params); + } else { + self::debug('WebBrowser plugin not available...'); + } + } + /** + * + * @param $url + * @param $data + * @param $callback + * @param $param1 + * @param $param2 + * @param $param3 + * @return phpQueryObject + */ + public static function browserPost($url, $data, $callback, $param1 = null, $param2 = null, $param3 = null) { + if (self::plugin('WebBrowser')) { + $params = func_get_args(); + return self::callbackRun(array(self::$plugins, 'browserPost'), $params); + } else { + self::debug('WebBrowser plugin not available...'); + } + } + /** + * + * @param $ajaxSettings + * @param $callback + * @param $param1 + * @param $param2 + * @param $param3 + * @return phpQueryObject + */ + public static function browser($ajaxSettings, $callback, $param1 = null, $param2 = null, $param3 = null) { + if (self::plugin('WebBrowser')) { + $params = func_get_args(); + return self::callbackRun(array(self::$plugins, 'browser'), $params); + } else { + self::debug('WebBrowser plugin not available...'); + } + } + /** + * + * @param $code + * @return string + */ + public static function php($code) { + return self::code('php', $code); + } + /** + * + * @param $type + * @param $code + * @return string + */ + public static function code($type, $code) { + return "<$type>"; + } + + public static function __callStatic($method, $params) { + return call_user_func_array( + array(phpQuery::$plugins, $method), + $params + ); + } + protected static function dataSetupNode($node, $documentID) { + // search are return if alredy exists + foreach(phpQuery::$documents[$documentID]->dataNodes as $dataNode) { + if ($node->isSameNode($dataNode)) + return $dataNode; + } + // if doesn't, add it + phpQuery::$documents[$documentID]->dataNodes[] = $node; + return $node; + } + protected static function dataRemoveNode($node, $documentID) { + // search are return if alredy exists + foreach(phpQuery::$documents[$documentID]->dataNodes as $k => $dataNode) { + if ($node->isSameNode($dataNode)) { + unset(self::$documents[$documentID]->dataNodes[$k]); + unset(self::$documents[$documentID]->data[ $dataNode->dataID ]); + } + } + } + public static function data($node, $name, $data, $documentID = null) { + if (! $documentID) + // TODO check if this works + $documentID = self::getDocumentID($node); + $document = phpQuery::$documents[$documentID]; + $node = self::dataSetupNode($node, $documentID); + if (! isset($node->dataID)) + $node->dataID = ++phpQuery::$documents[$documentID]->uuid; + $id = $node->dataID; + if (! isset($document->data[$id])) + $document->data[$id] = array(); + if (! is_null($data)) + $document->data[$id][$name] = $data; + if ($name) { + if (isset($document->data[$id][$name])) + return $document->data[$id][$name]; + } else + return $id; + } + public static function removeData($node, $name, $documentID) { + if (! $documentID) + // TODO check if this works + $documentID = self::getDocumentID($node); + $document = phpQuery::$documents[$documentID]; + $node = self::dataSetupNode($node, $documentID); + $id = $node->dataID; + if ($name) { + if (isset($document->data[$id][$name])) + unset($document->data[$id][$name]); + $name = null; + foreach($document->data[$id] as $name) + break; + if (! $name) + self::removeData($node, $name, $documentID); + } else { + self::dataRemoveNode($node, $documentID); + } + } +} +/** + * Plugins static namespace class. + * + * @author Tobiasz Cudnik + * @package phpQuery + * @todo move plugin methods here (as statics) + */ +class phpQueryPlugins { + public function __call($method, $args) { + if (isset(phpQuery::$extendStaticMethods[$method])) { + $return = call_user_func_array( + phpQuery::$extendStaticMethods[$method], + $args + ); + } else if (isset(phpQuery::$pluginsStaticMethods[$method])) { + $class = phpQuery::$pluginsStaticMethods[$method]; + $realClass = "phpQueryPlugin_$class"; + $return = call_user_func_array( + array($realClass, $method), + $args + ); + return isset($return) + ? $return + : $this; + } else + throw new Exception("Method '{$method}' doesnt exist"); + } +} +/** + * Shortcut to phpQuery::pq($arg1, $context) + * Chainable. + * + * @see phpQuery::pq() + * @return phpQueryObject|QueryTemplatesSource|QueryTemplatesParse|QueryTemplatesSourceQuery + * @author Tobiasz Cudnik + * @package phpQuery + */ +function pq($arg1, $context = null) { + $args = func_get_args(); + return call_user_func_array( + array('phpQuery', 'pq'), + $args + ); +} +// add plugins dir and Zend framework to include path +set_include_path( + get_include_path() + .PATH_SEPARATOR.dirname(__FILE__).'/phpQuery/' + .PATH_SEPARATOR.dirname(__FILE__).'/phpQuery/plugins/' +); +// why ? no __call nor __get for statics in php... +// XXX __callStatic will be available in PHP 5.3 +phpQuery::$plugins = new phpQueryPlugins(); +// include bootstrap file (personal library config) +if (file_exists(dirname(__FILE__).'/phpQuery/bootstrap.php')) + require_once dirname(__FILE__).'/phpQuery/bootstrap.php'; diff --git a/core/Objects/ApiObject.class.php b/core/Objects/ApiObject.class.php new file mode 100644 index 0000000..52ab893 --- /dev/null +++ b/core/Objects/ApiObject.class.php @@ -0,0 +1,14 @@ + diff --git a/core/Objects/ConnectionData.class.php b/core/Objects/ConnectionData.class.php new file mode 100644 index 0000000..0b845f9 --- /dev/null +++ b/core/Objects/ConnectionData.class.php @@ -0,0 +1,46 @@ +host = $host; + $this->port = $port; + $this->login = $login; + $this->password = $password; + $this->properties = array(); + } + + public function getProperties() { + return $this->properties; + } + + public function getProperty($key) { + if(isset($this->properties[$key])) + return $this->properties[$key]; + else + return ''; + } + + public function setProperty($key, $val) { + if(!is_string($val)) { + return false; + } + + $this->properties[$key] = $val; + } + + public function getHost() { return $this->host; } + public function getPort() { return $this->port; } + public function getLogin() { return $this->login; } + public function getPassword() { return $this->password; } +} + +?> diff --git a/core/Objects/Language.class.php b/core/Objects/Language.class.php new file mode 100644 index 0000000..c20e380 --- /dev/null +++ b/core/Objects/Language.class.php @@ -0,0 +1,133 @@ +languageId = $languageId; + $this->langCode = $langCode; + $this->langName = $langName; + $this->entries = array(); + $this->modules = array(); + } + + public function getId() { return $this->languageId; } + public function getCode() { return $this->langCode; } + public function getShortCode() { return substr($this->langCode, 0, 2); } + public function getName() { return $this->langName; } + public function getIconPath() { return "/img/icons/lang/$this->langCode.gif"; } + public function getEntries() { return $this->entries; } + public function getModules() { return $this->modules; } + + public function loadModule($module) { + if(!is_object($module)) + $module = new $module; + + $aModuleEntries = $module->getEntries($this->langCode); + $this->entries = array_merge($this->entries, $aModuleEntries); + $this->modules[] = $module; + } + + public function translate($key) { + if(isset($this->entries[$key])) + return $this->entries[$key]; + + return $key; + } + + public function sendCookie() { + setcookie('lang', $this->langCode, 0, "/", ""); + } + + public function jsonSerialize() { + return array( + 'uid' => $this->languageId, + 'code' => $this->langCode, + 'name' => $this->langName, + ); + } + + public static function newInstance($languageId, $langCode, $langName) { + + if(!preg_match(Language::LANG_CODE_PATTERN, $langCode)) { + return false; + } + + // TODO: include dynamically wanted Language + return new Language($languageId, $langCode, $langName); + + // $className = $langCode + // return new $className($languageId, $langCode); + } + + public function load() { + global $LANGUAGE; + $LANGUAGE = $this; + } + + public static function DEFAULT_LANGUAGE() { + if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { + $acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE']; + $aSplit = explode(',',$acceptLanguage); + foreach($aSplit as $code) { + if(strlen($code) == 2) { + $code = $code . '_' . strtoupper($code); + } + + $code = str_replace("-", "_", $code); + if(strlen($code) != 5) + continue; + + $lang = Language::newInstance(0, $code, ""); + if($lang) + return $lang; + } + } + + return Language::newInstance(1, "en_US", "American English"); + } +}; + +function L($key) { + if(!array_key_exists('LANGUAGE', $GLOBALS)) + return $key; + + global $LANGUAGE; + return $LANGUAGE->translate($key); +} + +function LANG_NAME() { + if(!array_key_exists('LANGUAGE', $GLOBALS)) + return "LANG_NAME"; + + global $LANGUAGE; + return $LANGUAGE->getName(); +} + +function LANG_CODE() { + if(!array_key_exists('LANGUAGE', $GLOBALS)) + return "LANG_CODE"; + + global $LANGUAGE; + return $LANGUAGE->getCode(); +} + +function SHORT_LANG_CODE() { + if(!array_key_exists('LANGUAGE', $GLOBALS)) + return "SHORT_LANG_CODE"; + + global $LANGUAGE; + return $LANGUAGE->getShortCode(); +} + +?> diff --git a/core/Objects/Session.class.php b/core/Objects/Session.class.php new file mode 100644 index 0000000..2441146 --- /dev/null +++ b/core/Objects/Session.class.php @@ -0,0 +1,105 @@ +user = $user; + $this->sessionId = $sessionId; + } + + private function updateMetaData() { + $userAgent = get_browser($_SERVER['HTTP_USER_AGENT'], true); + $this->expires = time() + Session::DURATION * 60; + $this->ipAddress = $_SERVER['REMOTE_ADDR']; + $this->os = $userAgent['platform']; + $this->browser = $userAgent['parent']; + } + + public function sendCookie() { + $this->updateMetaData(); + $token = array('userId' => $this->user->getId(), 'sessionId' => $this->sessionId); + $sessionCookie = JWT::encode($token, getJwtKey()); + setcookie('session', $sessionCookie, $this->expires, "/", "", true); + } + + public function getExpiresTime() { + return $this->expires; + } + + public function getExpiresSeconds() { + return ($this->expires - time()); + } + + public function jsonSerialize() { + return array( + 'uid' => $this->sessionId, + 'uidUser' => $this->user->getId(), + 'expires' => $this->expires, + 'ipAddress' => $this->ipAddress, + 'os' => $this->os, + 'browser' => $this->browser, + ); + } + + public function insert() { + $this->updateMetaData(); + $query = 'INSERT INTO Session (expires, uidUser, ipAddress, os, browser) + VALUES (DATE_ADD(NOW(), INTERVAL ? MINUTE),?,?,?,?)'; + $request = new CExecuteStatement($this->user); + + $success = $request->execute(array( + 'query' => $query, + Session::DURATION, + $this->user->getId(), + $this->ipAddress, + $this->os, + $this->browser, + )); + + if($success) { + $this->sessionId = $this->user->getSQL()->getLastInsertId(); + return true; + } + + return false; + } + + public function destroy() { + $query = 'DELETE FROM Session WHERE Session.uid=? OR Session.expires<=NOW()'; + $request = new CExecuteStatement($this->user); + $success = $request->execute(array('query' => $query, $this->sessionId)); + return $success; + } + + public function update() { + $this->updateMetaData(); + $query = 'UPDATE Session + SET Session.expires=DATE_ADD(NOW(), INTERVAL ? MINUTE), Session.ipAddress=?, + Session.os=?, Session.browser=? + WHERE Session.uid=?'; + $request = new CExecuteStatement($this->user); + $success = $request->execute(array( + 'query' => $query, + Session::DURATION, + $this->ipAddress, + $this->os, + $this->browser, + $this->sessionId, + )); + + return $success; + } +} + +?> diff --git a/core/Objects/User.class.php b/core/Objects/User.class.php new file mode 100644 index 0000000..1131599 --- /dev/null +++ b/core/Objects/User.class.php @@ -0,0 +1,189 @@ +configuration = $configuration; + $this->setLangauge(Language::DEFAULT_LANGUAGE()); + $this->reset(); + $this->connectDb(); + $this->parseCookies(); + } + + public function __destruct() { + if($this->sql && $this->sql->isConnected()) { + $this->sql->close(); + } + } + + private function connectDb() { + $databaseConf = $this->configuration->getDatabase(); + if($databaseConf) { + $this->sql = \Driver\SQL::createConnection($databaseConf); + } + } + + public function setSql($sql) { $this->sql = $sql; } + public function getId() { return $this->uid; } + public function isLoggedIn() { return $this->loggedIn; } + public function getUsername() { return $this->username; } + public function getSQL() { return $this->sql; } + public function getLanguage() { return $this->language; } + public function setLangauge($language) { $this->language = $language; $language->load(); } + public function getSession() { return $this->session; } + public function getConfiguration() { return $this->configuration; } + + public function __debugInfo() { + $debugInfo = array( + 'loggedIn' => $this->loggedIn, + 'language' => $this->language->getName(), + ); + + if($this->loggedIn) { + $debugInfo['uid'] = $this->uid; + $debugInfo['username'] = $this->username; + } + + return $debugInfo; + } + + public function jsonSerialize() { + return array( + 'uid' => $this->uid, + 'name' => $this->username, + 'language' => $this->language, + 'session' => $this->session, + ); + } + + private function reset() { + $this->uid = 0; + $this->username = ''; + $this->loggedIn = false; + $this->session = false; + } + + public function logout() { + if($this->loggedIn) { + $this->session->destroy(); + $this->reset(); + } + } + + public function updateLanguage($lang) { + $request = new CSetLanguage($this); + return $request->execute(array("langCode" => $lang)); + } + + public function sendCookies() { + if($this->loggedIn) { + $this->session->sendCookie(); + } + + $this->language->sendCookie(); + } + + public function readData($userId, $sessionId, $sessionUpdate = true) { + $query = 'SELECT User.name as userName, Language.uid as langId, Language.code as langCode + FROM User + INNER JOIN Session ON User.uid=Session.uidUser + LEFT JOIN Language ON User.uidLanguage=Language.uid + WHERE User.uid=? AND Session.uid=? AND Session.expires>now()'; + $request = new CExecuteSelect($this); + $success = $request->execute(array('query' => $query, $userId, $sessionId)); + + if($success) { + if(count($request->getResult()['rows']) === 0) { + $success = false; + } else { + $row = $request->getResult()['rows'][0]; + $this->username = $row['userName']; + $this->uid = $userId; + $this->session = new CSession($this, $sessionId); + if($sessionUpdate) $this->session->update(); + $this->loggedIn = true; + + if(!is_null($row['langId'])) { + $this->setLangauge(CLanguage::newInstance($row['langId'], $row['langCode'])); + } + } + } + + return $success; + } + + private function parseCookies() { + if(isset($_COOKIE['session']) + && is_string($_COOKIE['session']) + && !empty($_COOKIE['session']) + && ($jwt = $this->configuration->getJWT())) { + try { + $token = $_COOKIE['session']; + $decoded = (array)External\JWT::decode($token, $jwt->getKey()); + if(!is_null($decoded)) { + $userId = (isset($decoded['userId']) ? $decoded['userId'] : NULL); + $sessionId = (isset($decoded['sessionId']) ? $decoded['sessionId'] : NULL); + if(!is_null($userId) && !is_null($sessionId)) { + $this->readData($userId, $sessionId); + } + } + } catch(Exception $e) { + echo $e; + } + } + + if(isset($_GET['lang']) && is_string($_GET["lang"]) && !empty($_GET["lang"])) { + $this->updateLanguage($_GET['lang']); + } else if(isset($_COOKIE['lang']) && is_string($_COOKIE["lang"]) && !empty($_COOKIE["lang"])) { + $this->updateLanguage($_COOKIE['lang']); + } + } + + public function createSession($userId) { + $this->uid = $userId; + $this->session = new Session($this); + $this->loggedIn = $this->session->insert(); + return $this->loggedIn; + } + + public function authorize($apiKey) { + if($this->loggedIn) + return true; + + $query = 'SELECT ApiKey.uidUser as uid, User.name as username, Language.uid as langId, Language.code as langCode + FROM ApiKey, User + LEFT JOIN Language ON User.uidLanguage=Language.uid + WHERE api_key=? AND valid_until > now() AND User.uid = ApiKey.uidUser'; + + $request = new CExecuteSelect($this); + $success = $request->execute(array('query' => $query, $apiKey)); + + if($success) { + if(count($request->getResult()['rows']) === 0) { + $success = false; + } else { + $row = $request->getResult()['rows'][0]; + $this->uid = $row['uid']; + $this->username = $row['username']; + + if(!is_null($row['langId'])) { + $this->setLangauge(Language::newInstance($row['langId'], $row['langCode'])); + } + } + } + + return $success; + } +} + +?> diff --git a/core/Objects/lang/General.php b/core/Objects/lang/General.php new file mode 100644 index 0000000..6d1874c --- /dev/null +++ b/core/Objects/lang/General.php @@ -0,0 +1,17 @@ +entries[""] = ""; + break; + } + } + +} + +?> diff --git a/core/Objects/lang/LanguageModule.php b/core/Objects/lang/LanguageModule.php new file mode 100644 index 0000000..6a24aa5 --- /dev/null +++ b/core/Objects/lang/LanguageModule.php @@ -0,0 +1,9 @@ + diff --git a/core/View.class.php b/core/View.class.php new file mode 100644 index 0000000..c6293f9 --- /dev/null +++ b/core/View.class.php @@ -0,0 +1,229 @@ +document = $document; + $this->searchable = false; + $this->printable = false; + $this->reference = ""; + $this->title = "Untitled View"; + $this->langModules = array(); + $this->loadView = $loadView; + } + + public function getTitle() { return $this->title; } + public function __toString() { return $this->getCode(); } + public function getDocument() { return $this->document; } + public function isSearchable() { return $this->searchable; } + public function getReference() { return $this->reference; } + + private function loadLanguageModules() { + $lang = $this->document->getUser()->getLanguage(); + foreach($this->langModules as $langModule) { + $lang->loadModule($langModule); + } + } + + // Virtual Methods + public function loadView() { } + + public function getCode() { + + // Load translations + $this->loadLanguageModules(); + + // Load Meta Data + Head (title, scripts, includes, ...) + if($this->loadView) { + $this->loadView(); + } + + return ''; + } + + // UI Functions + + // TODO: do we need this in our general web-base? + public function createFileIcon($mimeType) { + $mimeType = htmlspecialchars($mimeType); + return "\"[$mimeType"; + } + + public function createParagraph($title, $id, $content) { + $id = replaceCssSelector($id); + $iconId = urlencode("$id-icon"); + return " +
    +
    + +

    $title

    +

    $content
    +
    +
    "; + } + + public function createSimpleParagraph($content, $class="") { + if($class) $class = " class=\"$class\""; + return "$content

    "; + } + + private function createList($items, $tag) { + if(count($items) === 0) + return "<$tag>"; + else + return "<$tag>
  • " . implode("
  • ", $items) . "
  • "; + } + + public function createOrderedList($items=array()) { + return $this->createList($items, "ol"); + } + + public function createUnorderedList($items=array()) { + return $this->createList($items, "ul"); + } + + public function createJumbotron($content, $lastModified=false) { + $lastModified = ($lastModified ? "Last modified: $lastModified" : ""); + return " +
    +
    +
    + $content + $lastModified +
    +
    +
    "; + } + + protected function createLink($link, $title=null) { + if(is_null($title)) $title=$link; + return "$title"; + } + + protected function createExternalLink($link, $title=null) { + if(is_null($title)) $title=$link; + return "$title"; + } + + protected function createCodeBlock($code, $lang="") { + if($lang) $lang = " class=\"$lang\""; + $html = "
    ";
    +    $html .= intendCode($code);
    +    $html .= "
    "; + return $html; + } + + protected function createIcon($icon, $margin = NULL) { + $marginStr = (is_null($margin) ? "" : " margin-$margin"); + $iconClass = $this->getIconClass($icon); + return ""; + } + + protected function getIconClass($icon) { + + $mappings = array( + "sign-out" => "sign-out-alt", + "bank" => "university", + "line-chart" => "chart-line", + "circle-right" => "arrow-alt-circle-right", + "refresh" => "sync" + ); + + if(isset($mappings[$icon])) + $icon = $mappings[$icon]; + + if($icon === "spinner") + $icon .= " fa-spin"; + + return "fas fa-$icon"; + } + + protected function createBootstrapTable($data) { + $code = "
    "; + foreach($data as $row) { + $code .= "
    "; + $columnCount = count($row); + if($columnCount > 0) { + $remainingSize = 12; + $columnSize = 12 / $columnCount; + foreach($row as $col) { + $size = ($columnSize <= $remainingSize ? $columnSize : $remainingSize); + $content = $col; + $class = ""; + $code .= " $val) { + if(strcmp($key, "content") === 0) { + $content = $val; + } else if(strcmp($key, "class") === 0) { + $class = " " . $col["class"]; + } else if(strcmp($key, "cols") === 0 && is_numeric($val)) { + $size = intval($val); + } else { + $code .= " $key=\"$val\""; + } + } + + $content = (isset($col["content"]) ? $col["content"] : ""); + if(isset($col["class"])) $class = " " . $col["class"]; + } + + if($size <= 6) $class .= " col-md-" . intval($size * 2); + $code .= " class=\"col-lg-$size$class\">$content
    "; + $remainingSize -= $size; + } + } + $code .= "
    "; + } + + $code .= "
    "; + return $code; + } + + protected function createBash($command, $output="", $prefix="") { + $command = htmlspecialchars($command); + $output = htmlspecialchars($output); + $output = str_replace("\n", "
    ", $output); + return "
    + $prefix$  + $command
    + $output +
    "; + } + + protected function createErrorText($text, $id="", $hidden=false) { + return $this->createStatusText("danger", $text, $id, $hidden); + } + + protected function createWarningText($text, $id="", $hidden=false) { + return $this->createStatusText("warning", $text, $id, $hidden); + } + + protected function createSuccessText($text, $id="", $hidden=false) { + return $this->createStatusText("success", $text, $id, $hidden); + } + + protected function createSecondaryText($text, $id="", $hidden=false) { + return $this->createStatusText("secondary", $text, $id, $hidden); + } + + protected function createInfoText($text, $id="", $hidden=false) { + return $this->createStatusText("info", $text, $id, $hidden); + } + + protected function createStatusText($type, $text, $id="", $hidden=false) { + if(strlen($id) > 0) $id = " id=\"$id\""; + $hidden = ($hidden?" hidden" : ""); + return "
    $text
    "; + } +}; + +?> diff --git a/core/constants.php b/core/constants.php new file mode 100644 index 0000000..43e399c --- /dev/null +++ b/core/constants.php @@ -0,0 +1,6 @@ + diff --git a/core/core.php b/core/core.php new file mode 100644 index 0000000..082eb5c --- /dev/null +++ b/core/core.php @@ -0,0 +1,137 @@ + $max) return $max; + return $val; + } + + function downloadFile($url) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_URL, $url); + $data = curl_exec($ch); + curl_close($ch); + return $data; + } + + function getSubclassesOf($parent) { + $result = array(); + foreach (get_declared_classes() as $class) { + if (is_subclass_of($class, $parent)) + $result[] = $class; + } + return $result; + } + + function includeDir($dir, $aIgnore = array(), $recursive = false) { + $aIgnore[] = '.'; + $aIgnore[] = '..'; + $aFiles = array_diff(scandir($dir), $aIgnore); + + foreach($aFiles as $file) { + $file = $dir . '/' . $file; + if(is_dir($file)) { + if($recursive) { + includeDir($file, $aIgnore, true); + } + } else { + require_once $file; + } + } + } + + function generateRandomString($length) { + $randomString = ''; + if($length > 0) { + $numCharacters = 26 + 26 + 10; // a-z + A-Z + 0-9 + for ($i = 0; $i < $length; $i++) + { + $num = random_int(0, $numCharacters - 1); + if($num < 26) $randomString .= chr(ord('a') + $num); + else if($num - 26 < 26) $randomString .= chr(ord('A') + $num - 26); + else $randomString .= chr(ord('0') + $num - 26 - 26); + } + } + + return $randomString; + } + + function cleanPath($path) { + if($path === '') + return $path; + + $path = str_replace('\\', '/', $path); + $path = str_replace('/./', '/', $path); + + if($path[0] !== '/') + $path = '/' . $path; + + $path = str_replace('/../', '/', $path); + return $path; + } + + function startsWith($haystack, $needle) { + $length = strlen($needle); + return (substr($haystack, 0, $length) === $needle); + } + + function endsWith($haystack, $needle) { + $length = strlen($needle); + if ($length == 0) + return true; + + return (substr($haystack, -$length) === $needle); + } + + function isCalledDirectly($file) { + return $_SERVER['SCRIPT_FILENAME'] === $file; + } + + function anonymzeEmail($mail) { + if(($pos = strpos($mail, '@')) !== -1) { + $name = substr($mail, 0, $pos); + $host = substr($mail, $pos + 1); + if(strlen($name) > 2) $mail = substr($name, 0, 2) . str_repeat('*', strlen($name) - 2) . "@$host"; + else $mail = $mail = str_repeat('*', strlen($name)) . "@$host"; + } + + return $mail; + } + + function intendCode($code, $escape=true) { + $newCode = ""; + $first = true; + $brackets = array(); + $intend = 0; + + foreach(explode("\n", $code) as $line) { + if(!$first) $newCode .= "\n"; + if($escape) $line = htmlspecialchars($line); + $line = trim($line); + + if(count($brackets) > 0 && startsWith($line, current($brackets))) { + $intend = max(0, $intend - 2); + array_pop($brackets); + } + + $newCode .= str_repeat(" ", $intend); + $newCode .= $line; + $first = false; + + if(endsWith($line, "{")) { + $intend += 2; + array_push($brackets, "}"); + } else if(endsWith($line, "(")) { + $intend += 2; + array_push($brackets, ")"); + } + } + + return $newCode; + } + + function replaceCssSelector($sel) { + return preg_replace("~[.#<>]~", "_", preg_replace("~[:\-]~", "", $sel)); + } +?> diff --git a/core/datetime.php b/core/datetime.php new file mode 100644 index 0000000..8b2ec23 --- /dev/null +++ b/core/datetime.php @@ -0,0 +1,121 @@ +modify('first day of this month'); + return intval($dt->format('N')); +} + +function getDayCount($d = NULL) { + if(is_null($d)) $d = date('Y-m-d H:i:s'); + $dt = new DateTime($d); + $dt->modify('last day of this month'); + return intval($dt->format('j')); +} + +function prevMonth($d = NULL) { + if(is_null($d)) $d = date('Y-m-d H:i:s'); + $dt = new DateTime($d); + $dt->modify('previous month'); + return $dt->format('Y-m-d H:i:s'); +} + +function prevDay($d = NULL) { + if(is_null($d)) $d = date('Y-m-d H:i:s'); + $dt = new DateTime($d); + $dt->modify('previous day'); + return $dt->format('Y-m-d H:i:s'); +} + +function nextDay($d = NULL) { + if(is_null($d)) $d = date('Y-m-d H:i:s'); + $dt = new DateTime($d); + $dt->modify('next day'); + return $dt->format('Y-m-d H:i:s'); +} + +function nextMonth($d = NULL) { + if(is_null($d)) $d = date('Y-m-d H:i:s'); + $dt = new DateTime($d); + $dt->modify('next month'); + return $dt->format('Y-m-d H:i:s'); +} + +function formatPeriod($d1, $d2) { + $timeStr = dateFunction('d.m.Y H:i', $d1); + if($timeStr == dateFunction('d.m.Y H:i', $d2)) { + if(dateFunction('H:i', $d1) === '00:00') { + return dateFunction('d.m.Y', $d1); + } + } else if(dateFunction('d.m.Y', $d1) !== dateFunction('d.m.Y', $d2)) { + $timeStr .= " - " . dateFunction('d.m.Y H:i', $d2); + } elseif(dateFunction('H:i', $d1) !== dateFunction('H:i', $d2)) { + $timeStr .= " - " . dateFunction('H:i', $d2); + } + return $timeStr; +} + +function now() { return new DateTime(); } +function getTime($d = NULL) { return dateFunction('H:i', $d); } +function getHour($d = NULL){ return dateFunction('H', $d); } +function getMinute($d = NULL){ return dateFunction('i', $d); } +function getYear($d = NULL) { return intval(dateFunction('Y', $d)); } +function getMonth($d = NULL) { return intval(dateFunction('n', $d)); } +function getDay($d = NULL) { return intval(dateFunction('d', $d)); } +function getDayOfWeek($d = NULL) { return intval(dateFunction('N', $d)); } +function getDayNumberOfWeek($d = NULL) { return intval(dateFunction('N', $d)); } +function getDateTime($d = NULL) { return dateFunction('Y-m-d H:i:s', $d); } +function getFirstDay($d = NULL) { return dateFunction('Y-m-01', $d); } +function getLastDay($d = NULL) { return dateFunction('t', $d); } +function getPrevMonth($d = NULL) { return dateFunction("-1 month", $d); } +function getLocalizedDateTime($d = NULL) { return dateFunction(L('Y/m/d H:i'), $d); } + +function getJavascriptDate($d = NULL) { + if(is_null($d)) $d = date('Y-m-d H:i:s'); + if(!is_a($d, "DateTime")) $d = new DateTime($d); + $year = getYear($d); + $month = getMonth($d) - 1; + $day = getDay($d); + $hour = getHour($d); + $minute = getMinute($d); + + return "new Date($year, $month, $day, $hour, $minute)"; +} + +function getWeekDayName($day) { + $aWeekDays = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'); + return L($aWeekDays[$day - 1]); +} + +function getMonthName($month) { + $aMonthNames = array("January", "February", "March", "April", "May", "Juni", "July", "August", "September", "October", "November", "December"); + return L($aMonthNames[$month - 1]); +} + +function isInPast($d) { + $now = date('Y-m-d H:i:s'); + if(is_a($d, "DateTime")) $d = $d->format('Y-m-d H:i:s'); + return (strtotime($d) < strtotime($now)); +} + +function datetimeDiff($d1, $d2) { + if(!($d1 instanceof DateTime)) $d1 = new DateTime($d1); + if(!($d2 instanceof DateTime)) $d2 = new DateTime($d2); + return $d2->getTimestamp() - $d1->getTimestamp(); +} + +function durationIn($d1, $d2, $str) { + if(!($d1 instanceof DateTime)) $d1 = new DateTime($d1); + if(!($d2 instanceof DateTime)) $d2 = new DateTime($d2); + $interval = $d1->diff($d2); + return intval($interval->format($str)); +} + +function dateFunction($str, $d = NULL) { + if(is_null($d)) $d = date('Y-m-d H:i:s'); + if(!is_a($d, "DateTime")) $d = new DateTime($d); + return $d->format($str); +} + +?> diff --git a/css/bootstrap.min.css b/css/bootstrap.min.css new file mode 100644 index 0000000..92e3fe8 --- /dev/null +++ b/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.3.1 (https://getbootstrap.com/) + * Copyright 2011-2019 The Bootstrap Authors + * Copyright 2011-2019 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#007bff;--secondary:#6c757d;--success:#28a745;--info:#17a2b8;--warning:#ffc107;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}.h2,h2{font-size:2rem}.h3,h3{font-size:1.75rem}.h4,h4{font-size:1.5rem}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code{font-size:87.5%;color:#e83e8c;word-break:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.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-lg-auto,.col-md,.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-md-auto,.col-sm,.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-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-first{-ms-flex-order:-1;order:-1}.order-last{-ms-flex-order:13;order:13}.order-0{-ms-flex-order:0;order:0}.order-1{-ms-flex-order:1;order:1}.order-2{-ms-flex-order:2;order:2}.order-3{-ms-flex-order:3;order:3}.order-4{-ms-flex-order:4;order:4}.order-5{-ms-flex-order:5;order:5}.order-6{-ms-flex-order:6;order:6}.order-7{-ms-flex-order:7;order:7}.order-8{-ms-flex-order:8;order:8}.order-9{-ms-flex-order:9;order:9}.order-10{-ms-flex-order:10;order:10}.order-11{-ms-flex-order:11;order:11}.order-12{-ms-flex-order:12;order:12}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-sm-first{-ms-flex-order:-1;order:-1}.order-sm-last{-ms-flex-order:13;order:13}.order-sm-0{-ms-flex-order:0;order:0}.order-sm-1{-ms-flex-order:1;order:1}.order-sm-2{-ms-flex-order:2;order:2}.order-sm-3{-ms-flex-order:3;order:3}.order-sm-4{-ms-flex-order:4;order:4}.order-sm-5{-ms-flex-order:5;order:5}.order-sm-6{-ms-flex-order:6;order:6}.order-sm-7{-ms-flex-order:7;order:7}.order-sm-8{-ms-flex-order:8;order:8}.order-sm-9{-ms-flex-order:9;order:9}.order-sm-10{-ms-flex-order:10;order:10}.order-sm-11{-ms-flex-order:11;order:11}.order-sm-12{-ms-flex-order:12;order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-md-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-md-first{-ms-flex-order:-1;order:-1}.order-md-last{-ms-flex-order:13;order:13}.order-md-0{-ms-flex-order:0;order:0}.order-md-1{-ms-flex-order:1;order:1}.order-md-2{-ms-flex-order:2;order:2}.order-md-3{-ms-flex-order:3;order:3}.order-md-4{-ms-flex-order:4;order:4}.order-md-5{-ms-flex-order:5;order:5}.order-md-6{-ms-flex-order:6;order:6}.order-md-7{-ms-flex-order:7;order:7}.order-md-8{-ms-flex-order:8;order:8}.order-md-9{-ms-flex-order:9;order:9}.order-md-10{-ms-flex-order:10;order:10}.order-md-11{-ms-flex-order:11;order:11}.order-md-12{-ms-flex-order:12;order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-lg-first{-ms-flex-order:-1;order:-1}.order-lg-last{-ms-flex-order:13;order:13}.order-lg-0{-ms-flex-order:0;order:0}.order-lg-1{-ms-flex-order:1;order:1}.order-lg-2{-ms-flex-order:2;order:2}.order-lg-3{-ms-flex-order:3;order:3}.order-lg-4{-ms-flex-order:4;order:4}.order-lg-5{-ms-flex-order:5;order:5}.order-lg-6{-ms-flex-order:6;order:6}.order-lg-7{-ms-flex-order:7;order:7}.order-lg-8{-ms-flex-order:8;order:8}.order-lg-9{-ms-flex-order:9;order:9}.order-lg-10{-ms-flex-order:10;order:10}.order-lg-11{-ms-flex-order:11;order:11}.order-lg-12{-ms-flex-order:12;order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-ms-flex:0 0 auto;flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.order-xl-first{-ms-flex-order:-1;order:-1}.order-xl-last{-ms-flex-order:13;order:13}.order-xl-0{-ms-flex-order:0;order:0}.order-xl-1{-ms-flex-order:1;order:1}.order-xl-2{-ms-flex-order:2;order:2}.order-xl-3{-ms-flex-order:3;order:3}.order-xl-4{-ms-flex-order:4;order:4}.order-xl-5{-ms-flex-order:5;order:5}.order-xl-6{-ms-flex-order:6;order:6}.order-xl-7{-ms-flex-order:7;order:7}.order-xl-8{-ms-flex-order:8;order:8}.order-xl-9{-ms-flex-order:9;order:9}.order-xl-10{-ms-flex-order:10;order:10}.order-xl-11{-ms-flex-order:11;order:11}.order-xl-12{-ms-flex-order:12;order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}.table{width:100%;margin-bottom:1rem;color:#212529}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #dee2e6}.table thead th{vertical-align:bottom;border-bottom:2px solid #dee2e6}.table tbody+tbody{border-top:2px solid #dee2e6}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #dee2e6}.table-bordered td,.table-bordered th{border:1px solid #dee2e6}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(0,0,0,.05)}.table-hover tbody tr:hover{color:#212529;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8daff}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7abaff}.table-hover .table-primary:hover{background-color:#9fcdff}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#9fcdff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#b3b7bb}.table-hover .table-secondary:hover{background-color:#c8cbcf}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#c3e6cb}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#8fd19e}.table-hover .table-success:hover{background-color:#b1dfbb}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b1dfbb}.table-info,.table-info>td,.table-info>th{background-color:#bee5eb}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#86cfda}.table-hover .table-info:hover{background-color:#abdde5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#abdde5}.table-warning,.table-warning>td,.table-warning>th{background-color:#ffeeba}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ffdf7e}.table-hover .table-warning:hover{background-color:#ffe8a1}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#ffe8a1}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#ed969e}.table-hover .table-danger:hover{background-color:#f1b0b7}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfcfc}.table-hover .table-light:hover{background-color:#ececf6}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#95999c}.table-hover .table-dark:hover{background-color:#b9bbbe}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#343a40;border-color:#454d55}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#dee2e6}.table-dark{color:#fff;background-color:#343a40}.table-dark td,.table-dark th,.table-dark thead th{border-color:#454d55}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#495057;background-color:#fff;border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.form-control::-webkit-input-placeholder{color:#6c757d;opacity:1}.form-control::-moz-placeholder{color:#6c757d;opacity:1}.form-control:-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::-ms-input-placeholder{color:#6c757d;opacity:1}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}select.form-control:focus::-ms-value{color:#495057;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding-top:.375rem;padding-bottom:.375rem;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#6c757d}.form-check-label{margin-bottom:0}.form-check-inline{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#28a745}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(40,167,69,.9);border-radius:.25rem}.form-control.is-valid,.was-validated .form-control:valid{border-color:#28a745;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:center right calc(.375em + .1875rem);background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#28a745;padding-right:calc((1em + .75rem) * 3 / 4 + 1.75rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%2328a745' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip{display:block}.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip{display:block}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#28a745}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#28a745}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#28a745}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#34ce57;background-color:#34ce57}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#28a745}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#28a745}.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip{display:block}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#28a745;box-shadow:0 0 0 .2rem rgba(40,167,69,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#dc3545;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E");background-repeat:no-repeat;background-position:center right calc(.375em + .1875rem);background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#dc3545;padding-right:calc((1em + .75rem) * 3 / 4 + 1.75rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip{display:block}.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip{display:block}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#dc3545}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#dc3545}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#e4606d;background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip{display:block}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:-ms-flexbox;display:flex;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-flow:row wrap;flex-flow:row wrap;-ms-flex-align:center;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;-ms-flex-negative:0;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#212529;text-align:center;vertical-align:middle;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#212529;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.btn.disabled,.btn:disabled{opacity:.65}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:hover{color:#fff;background-color:#0069d9;border-color:#0062cc}.btn-primary.focus,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#007bff;border-color:#007bff}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0062cc;border-color:#005cbf}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,143,255,.5)}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5a6268;border-color:#545b62}.btn-secondary.focus,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#545b62;border-color:#4e555b}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(130,138,145,.5)}.btn-success{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:hover{color:#fff;background-color:#218838;border-color:#1e7e34}.btn-success.focus,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#28a745;border-color:#28a745}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#1e7e34;border-color:#1c7430}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(72,180,97,.5)}.btn-info{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:hover{color:#fff;background-color:#138496;border-color:#117a8b}.btn-info.focus,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#117a8b;border-color:#10707f}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(58,176,195,.5)}.btn-warning{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#212529;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#212529;background-color:#d39e00;border-color:#c69500}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,170,12,.5)}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#c82333;border-color:#bd2130}.btn-danger.focus,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#bd2130;border-color:#b21f2d}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(225,83,97,.5)}.btn-light{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#212529;background-color:#e2e6ea;border-color:#dae0e5}.btn-light.focus,.btn-light:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-light.disabled,.btn-light:disabled{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#212529;background-color:#dae0e5;border-color:#d3d9df}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(216,217,219,.5)}.btn-dark{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:hover{color:#fff;background-color:#23272b;border-color:#1d2124}.btn-dark.focus,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#fff;background-color:#343a40;border-color:#343a40}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1d2124;border-color:#171a1d}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,88,93,.5)}.btn-outline-primary{color:#007bff;border-color:#007bff}.btn-outline-primary:hover{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#007bff;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#007bff;border-color:#007bff}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.btn-outline-secondary{color:#6c757d;border-color:#6c757d}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#6c757d;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.btn-outline-success{color:#28a745;border-color:#28a745}.btn-outline-success:hover{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#28a745;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#28a745;border-color:#28a745}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.btn-outline-info{color:#17a2b8;border-color:#17a2b8}.btn-outline-info:hover{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#17a2b8;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#17a2b8;border-color:#17a2b8}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ffc107;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#212529;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.btn-outline-danger{color:#dc3545;border-color:#dc3545}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#dc3545;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:hover{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f8f9fa;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#212529;background-color:#f8f9fa;border-color:#f8f9fa}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.btn-outline-dark{color:#343a40;border-color:#343a40}.btn-outline-dark:hover{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#343a40;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#fff;background-color:#343a40;border-color:#343a40}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#007bff;text-decoration:none}.btn-link:hover{color:#0056b3;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline;box-shadow:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e9ecef}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#212529;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#16181b;text-decoration:none;background-color:#f8f9fa}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#007bff}.dropdown-item.disabled,.dropdown-item:disabled{color:#6c757d;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:-ms-inline-flexbox;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;-ms-flex:1 1 auto;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-pack:start;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:center;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:stretch;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;width:1%;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:-ms-flexbox;display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:-ms-inline-flexbox;display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#007bff;background-color:#007bff}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#80bdff}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#b3d7ff;border-color:#b3d7ff}.custom-control-input:disabled~.custom-control-label{color:#6c757d}.custom-control-input:disabled~.custom-control-label::before{background-color:#e9ecef}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#fff;border:#adb5bd solid 1px}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#007bff;background-color:#007bff}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;-webkit-transform:translateX(.75rem);transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,123,255,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#495057;vertical-align:middle;background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-select:focus::-ms-value{color:#495057;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-select::-ms-expand{display:none}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#80bdff;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.custom-file-input:disabled~.custom-file-label{background-color:#e9ecef}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-weight:400;line-height:1.5;color:#495057;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#495057;content:"Browse";background-color:#e9ecef;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:calc(1rem + .4rem);padding:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(0,123,255,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#b3d7ff}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#b3d7ff}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#007bff;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#b3d7ff}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#007bff}.nav-fill .nav-item{-ms-flex:1 1 auto;flex:1 1 auto;text-align:center}.nav-justified .nav-item{-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;padding:.5rem 1rem}.navbar>.container,.navbar>.container-fluid{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{-ms-flex-preferred-size:100%;flex-basis:100%;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-sm .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-md .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-lg .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand-xl .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-pack:start;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{-ms-flex-direction:row;flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{-ms-flex-wrap:nowrap;flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:-ms-flexbox!important;display:flex!important;-ms-flex-preferred-size:auto;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:rgba(0,0,0,.9)}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a{color:rgba(0,0,0,.9)}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.card-body{-ms-flex:1 1 auto;flex:1 1 auto;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(.25rem - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{-ms-flex-flow:row wrap;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{display:-ms-flexbox;display:flex;-ms-flex:1 0 0%;flex:1 0 0%;-ms-flex-direction:column;flex-direction:column;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{-ms-flex-flow:row wrap;flex-flow:row wrap}.card-group>.card{-ms-flex:1 0 0%;flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{-webkit-column-count:3;-moz-column-count:3;column-count:3;-webkit-column-gap:1.25rem;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion>.card{overflow:hidden}.accordion>.card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion>.card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion>.card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.accordion>.card .card-header{margin-bottom:-1px}.breadcrumb{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#e9ecef;border-radius:.25rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#6c757d;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#6c757d}.pagination{display:-ms-flexbox;display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#007bff;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#0056b3;text-decoration:none;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:1;color:#fff;background-color:#007bff;border-color:#007bff}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;cursor:auto;background-color:#fff;border-color:#dee2e6}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#007bff}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#0062cc}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,123,255,.5)}.badge-secondary{color:#fff;background-color:#6c757d}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#545b62}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(108,117,125,.5)}.badge-success{color:#fff;background-color:#28a745}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#1e7e34}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(40,167,69,.5)}.badge-info{color:#fff;background-color:#17a2b8}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#117a8b}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(23,162,184,.5)}.badge-warning{color:#212529;background-color:#ffc107}a.badge-warning:focus,a.badge-warning:hover{color:#212529;background-color:#d39e00}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(255,193,7,.5)}.badge-danger{color:#fff;background-color:#dc3545}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#bd2130}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(220,53,69,.5)}.badge-light{color:#212529;background-color:#f8f9fa}a.badge-light:focus,a.badge-light:hover{color:#212529;background-color:#dae0e5}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(248,249,250,.5)}.badge-dark{color:#fff;background-color:#343a40}a.badge-dark:focus,a.badge-dark:hover{color:#fff;background-color:#1d2124}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,58,64,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#e9ecef;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#004085;background-color:#cce5ff;border-color:#b8daff}.alert-primary hr{border-top-color:#9fcdff}.alert-primary .alert-link{color:#002752}.alert-secondary{color:#383d41;background-color:#e2e3e5;border-color:#d6d8db}.alert-secondary hr{border-top-color:#c8cbcf}.alert-secondary .alert-link{color:#202326}.alert-success{color:#155724;background-color:#d4edda;border-color:#c3e6cb}.alert-success hr{border-top-color:#b1dfbb}.alert-success .alert-link{color:#0b2e13}.alert-info{color:#0c5460;background-color:#d1ecf1;border-color:#bee5eb}.alert-info hr{border-top-color:#abdde5}.alert-info .alert-link{color:#062c33}.alert-warning{color:#856404;background-color:#fff3cd;border-color:#ffeeba}.alert-warning hr{border-top-color:#ffe8a1}.alert-warning .alert-link{color:#533f03}.alert-danger{color:#721c24;background-color:#f8d7da;border-color:#f5c6cb}.alert-danger hr{border-top-color:#f1b0b7}.alert-danger .alert-link{color:#491217}.alert-light{color:#818182;background-color:#fefefe;border-color:#fdfdfe}.alert-light hr{border-top-color:#ececf6}.alert-light .alert-link{color:#686868}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@-webkit-keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:-ms-flexbox;display:flex;height:1rem;overflow:hidden;font-size:.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#007bff;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{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);background-size:1rem 1rem}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.media{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start}.media-body{-ms-flex:1;flex:1}.list-group{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#007bff;border-color:#007bff}.list-group-horizontal{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}@media (min-width:576px){.list-group-horizontal-sm{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-sm .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-sm .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:768px){.list-group-horizontal-md{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-md .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-md .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:992px){.list-group-horizontal-lg{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-lg .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-lg .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}@media (min-width:1200px){.list-group-horizontal-xl{-ms-flex-direction:row;flex-direction:row}.list-group-horizontal-xl .list-group-item{margin-right:-1px;margin-bottom:0}.list-group-horizontal-xl .list-group-item:first-child{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl .list-group-item:last-child{margin-right:0;border-top-right-radius:.25rem;border-bottom-right-radius:.25rem;border-bottom-left-radius:0}}.list-group-flush .list-group-item{border-right:0;border-left:0;border-radius:0}.list-group-flush .list-group-item:last-child{margin-bottom:-1px}.list-group-flush:first-child .list-group-item:first-child{border-top:0}.list-group-flush:last-child .list-group-item:last-child{margin-bottom:0;border-bottom:0}.list-group-item-primary{color:#004085;background-color:#b8daff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#004085;background-color:#9fcdff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#004085;border-color:#004085}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#155724;background-color:#c3e6cb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#155724;background-color:#b1dfbb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#155724;border-color:#155724}.list-group-item-info{color:#0c5460;background-color:#bee5eb}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#0c5460;background-color:#abdde5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#0c5460;border-color:#0c5460}.list-group-item-warning{color:#856404;background-color:#ffeeba}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#856404;background-color:#ffe8a1}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#856404;border-color:#856404}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.close:hover{color:#000;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}a.close.disabled{pointer-events:none}.toast{max-width:350px;overflow:hidden;font-size:.875rem;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;padding:.25rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:-webkit-transform .3s ease-out;transition:transform .3s ease-out;transition:transform .3s ease-out,-webkit-transform .3s ease-out;-webkit-transform:translate(0,-50px);transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{-webkit-transform:none;transform:none}.modal-dialog-scrollable{display:-ms-flexbox;display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{-ms-flex-negative:0;flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);content:""}.modal-dialog-centered.modal-dialog-scrollable{-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:-ms-flexbox;display:flex;-ms-flex-align:start;align-items:flex-start;-ms-flex-pack:justify;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:.3rem;border-top-right-radius:.3rem}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;-ms-flex:1 1 auto;flex:1 1 auto;padding:1rem}.modal-footer{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end;padding:1rem;border-top:1px solid #dee2e6;border-bottom-right-radius:.3rem;border-bottom-left-radius:.3rem}.modal-footer>:not(:first-child){margin-left:.25rem}.modal-footer>:not(:last-child){margin-right:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc((.5rem + 1px) * -1)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{-ms-touch-action:pan-y;touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:-webkit-transform .6s ease-in-out;transition:transform .6s ease-in-out;transition:transform .6s ease-in-out,-webkit-transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){-webkit-transform:translateX(100%);transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){-webkit-transform:translateX(-100%);transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;-webkit-transform:none;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:0s .6s opacity}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:-ms-flexbox;display:flex;-ms-flex-pack:center;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;-ms-flex:0 1 auto;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@-webkit-keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-border{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;-webkit-animation:spinner-border .75s linear infinite;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@-webkit-keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1}}@keyframes spinner-grow{0%{-webkit-transform:scale(0);transform:scale(0)}50%{opacity:1}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;-webkit-animation:spinner-grow .75s linear infinite;animation:spinner-grow .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#007bff!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#0062cc!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#28a745!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#1e7e34!important}.bg-info{background-color:#17a2b8!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#117a8b!important}.bg-warning{background-color:#ffc107!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#d39e00!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#007bff!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#28a745!important}.border-info{border-color:#17a2b8!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:-ms-flexbox!important;display:flex!important}.d-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:-ms-flexbox!important;display:flex!important}.d-sm-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:-ms-flexbox!important;display:flex!important}.d-md-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:-ms-flexbox!important;display:flex!important}.d-lg-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:-ms-flexbox!important;display:flex!important}.d-xl-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:-ms-flexbox!important;display:flex!important}.d-print-inline-flex{display:-ms-inline-flexbox!important;display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.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-21by9::before{padding-top:42.857143%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-center{-ms-flex-align:center!important;align-items:center!important}.align-items-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}@media (min-width:576px){.flex-sm-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-sm-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-sm-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-sm-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-sm-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-sm-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-sm-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-sm-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-sm-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-sm-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-sm-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-sm-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-sm-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-sm-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-sm-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-sm-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-sm-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-sm-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-sm-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-sm-center{-ms-flex-align:center!important;align-items:center!important}.align-items-sm-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-sm-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-sm-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-sm-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-sm-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-sm-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-sm-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-sm-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-sm-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-sm-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-sm-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-sm-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-sm-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-sm-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:768px){.flex-md-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-md-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-md-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-md-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-md-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-md-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-md-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-md-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-md-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-md-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-md-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-md-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-md-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-md-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-md-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-md-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-md-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-md-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-md-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-md-center{-ms-flex-align:center!important;align-items:center!important}.align-items-md-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-md-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-md-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-md-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-md-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-md-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-md-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-md-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-md-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-md-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-md-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-md-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-md-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-md-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-lg-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-lg-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-lg-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-lg-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-lg-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-lg-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-lg-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-lg-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-lg-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-lg-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-lg-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-lg-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-lg-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-lg-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-lg-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-lg-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-lg-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-lg-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-lg-center{-ms-flex-align:center!important;align-items:center!important}.align-items-lg-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-lg-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-lg-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-lg-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-lg-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-lg-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-lg-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-lg-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-lg-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-lg-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-lg-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-lg-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-lg-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-lg-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{-ms-flex-direction:row!important;flex-direction:row!important}.flex-xl-column{-ms-flex-direction:column!important;flex-direction:column!important}.flex-xl-row-reverse{-ms-flex-direction:row-reverse!important;flex-direction:row-reverse!important}.flex-xl-column-reverse{-ms-flex-direction:column-reverse!important;flex-direction:column-reverse!important}.flex-xl-wrap{-ms-flex-wrap:wrap!important;flex-wrap:wrap!important}.flex-xl-nowrap{-ms-flex-wrap:nowrap!important;flex-wrap:nowrap!important}.flex-xl-wrap-reverse{-ms-flex-wrap:wrap-reverse!important;flex-wrap:wrap-reverse!important}.flex-xl-fill{-ms-flex:1 1 auto!important;flex:1 1 auto!important}.flex-xl-grow-0{-ms-flex-positive:0!important;flex-grow:0!important}.flex-xl-grow-1{-ms-flex-positive:1!important;flex-grow:1!important}.flex-xl-shrink-0{-ms-flex-negative:0!important;flex-shrink:0!important}.flex-xl-shrink-1{-ms-flex-negative:1!important;flex-shrink:1!important}.justify-content-xl-start{-ms-flex-pack:start!important;justify-content:flex-start!important}.justify-content-xl-end{-ms-flex-pack:end!important;justify-content:flex-end!important}.justify-content-xl-center{-ms-flex-pack:center!important;justify-content:center!important}.justify-content-xl-between{-ms-flex-pack:justify!important;justify-content:space-between!important}.justify-content-xl-around{-ms-flex-pack:distribute!important;justify-content:space-around!important}.align-items-xl-start{-ms-flex-align:start!important;align-items:flex-start!important}.align-items-xl-end{-ms-flex-align:end!important;align-items:flex-end!important}.align-items-xl-center{-ms-flex-align:center!important;align-items:center!important}.align-items-xl-baseline{-ms-flex-align:baseline!important;align-items:baseline!important}.align-items-xl-stretch{-ms-flex-align:stretch!important;align-items:stretch!important}.align-content-xl-start{-ms-flex-line-pack:start!important;align-content:flex-start!important}.align-content-xl-end{-ms-flex-line-pack:end!important;align-content:flex-end!important}.align-content-xl-center{-ms-flex-line-pack:center!important;align-content:center!important}.align-content-xl-between{-ms-flex-line-pack:justify!important;align-content:space-between!important}.align-content-xl-around{-ms-flex-line-pack:distribute!important;align-content:space-around!important}.align-content-xl-stretch{-ms-flex-line-pack:stretch!important;align-content:stretch!important}.align-self-xl-auto{-ms-flex-item-align:auto!important;align-self:auto!important}.align-self-xl-start{-ms-flex-item-align:start!important;align-self:flex-start!important}.align-self-xl-end{-ms-flex-item-align:end!important;align-self:flex-end!important}.align-self-xl-center{-ms-flex-item-align:center!important;align-self:center!important}.align-self-xl-baseline{-ms-flex-item-align:baseline!important;align-self:baseline!important}.align-self-xl-stretch{-ms-flex-item-align:stretch!important;align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports ((position:-webkit-sticky) or (position:sticky)){.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#007bff!important}a.text-primary:focus,a.text-primary:hover{color:#0056b3!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#494f54!important}.text-success{color:#28a745!important}a.text-success:focus,a.text-success:hover{color:#19692c!important}.text-info{color:#17a2b8!important}a.text-info:focus,a.text-info:hover{color:#0f6674!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#a71d2a!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#cbd3da!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#212529!important}.text-muted{color:#6c757d!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-break:break-word!important;overflow-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{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 #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#dee2e6}.table .thead-dark th{color:inherit;border-color:#dee2e6}} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file diff --git a/css/fontawesome.min.css b/css/fontawesome.min.css new file mode 100644 index 0000000..b18246e --- /dev/null +++ b/css/fontawesome.min.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.10.1 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + */ +.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../fonts/fa-brands-400.eot);src:url(../fonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../fonts/fa-brands-400.woff2) format("woff2"),url(../fonts/fa-brands-400.woff) format("woff"),url(../fonts/fa-brands-400.ttf) format("truetype"),url(../fonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../fonts/fa-regular-400.eot);src:url(../fonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../fonts/fa-regular-400.woff2) format("woff2"),url(../fonts/fa-regular-400.woff) format("woff"),url(../fonts/fa-regular-400.ttf) format("truetype"),url(../fonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../fonts/fa-solid-900.eot);src:url(../fonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../fonts/fa-solid-900.woff2) format("woff2"),url(../fonts/fa-solid-900.woff) format("woff"),url(../fonts/fa-solid-900.ttf) format("truetype"),url(../fonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..24f9e65 --- /dev/null +++ b/css/style.css @@ -0,0 +1,226 @@ +html, body { + height: 100%; + margin: 0; + padding: 0; + font-family: "Verdana"; + color: #555; +} + +.syntaxhighlighter { margin-left: -25px; } + +.no-underline:hover { text-decoration: none; } +.background { background-color: #fefefe; } +.background-gray { background-color: gray; } +.background-lightgray { background-color: lightgray; } +.background-light-blue { background-color: rgb(88, 160, 224); } +.background-jumbotron { background-color: #e9ecef; } + +/* TEXT COLOR */ +.text-white, .text-white:hover { color: white } +.text-black, .text-black:hover { color: black; } +.text-gray, .text-gray:hover { color: gray; } +.text-default, .text-default:hover { color: #555; } +.text-title, .text-title:hover { color: #333; text-decoration: underline; font-weight: bold; font-size: 1.7em; } +.text-red, .text-red:hover { color: red; } +.text-inherit, .text-inherit:hover { color: inherit; } +.text-green-attr { color: #50a14f; } +.text-cyan { color: cyan; } +.highlight { background-color: yellow; } + +.code-box { background-color: #e0e0e0; + color: rgba(0,0,0,.87); + border-radius: 1px; + padding: 2px; + border: 1px solid #ddd; + word-break: break-all; + overflow-wrap: anywhere; +} + + +/* TEXT TRANSFORM */ +.underline { text-decoration: underline; } +.italic { font-style: italic; } +.bold { font-weight: bold; } +.text-super { vertical-align : super; } + +/* TEXT SIZE */ +.text-xxs { font-size: 13px; } +.text-xs { font-size: 15px; } +.text-m { font-size: 20px; } +.text-xl { font-size: 22px; } +.text-xxl { font-size: 25px; } +.text-xxxl { font-size: 30px; } + +/* MARGINS */ +.margin-xs { margin: 5px; } +.margin-m { margin: 10px; } +.margin-xl { margin: 15px; } +.margin-top-xxs { margin-top: 10px; } +.margin-top-xs { margin-top: 15px; } +.margin-top-m { margin-top: 20px; } +.margin-top-xl { margin-top: 25px; } +.margin-top-xxl { margin-top: 30px; } +.margin-top-xxxl { margin-top: 40px; } +.margin-bottom-xxs { margin-bottom: 10px; } +.margin-bottom-xs { margin-bottom: 15px; } +.margin-bottom-m { margin-bottom: 20px; } +.margin-bottom-xl { margin-bottom: 25px; } +.margin-bottom-xxl { margin-bottom: 30px; } +.margin-bottom-xxxl { margin-bottom: 40px; } +.margin-left-xxs { margin-left: 10px; } +.margin-left-xs { margin-left: 15px; } +.margin-left-m { margin-left: 20px; } +.margin-left-xl { margin-left: 25px; } +.margin-left-xxl { margin-left: 30px; } +.margin-center { margin-left: auto; margin-right: auto; } +.margin-none { margin: 0 !important; } + +/* PADDINGS */ +.padding-xs { padding: 5px; } +.padding-m { padding: 10px; } +.padding-xl { padding: 15px; } +.padding-xxl { padding: 20px; } +.padding-xxxl { padding: 25px; } +.padding-top-m { padding-top: 10px; } +.padding-top-xl { padding-top: 15px; } +.padding-top-xxl { padding-top: 20px; } +.padding-bottom-m { padding-bottom: 10px; } +.padding-bottom-xxl { padding-bottom: 20px; } +.padding-left-xs { padding-left: 5px; } +.padding-left-xl { padding-left: 15px; } +.padding-none { padding: 0; } + +/* BORDER */ +.round { border-radius: 50%; } +.border-white { border-color: white; } +.border-grey { border-color: grey; } +.border-xxs { border: 1px solid; } +.border-xs { border: 2px solid; } +.border-m { border: 3px solid; } +.border-bottom-xss { border-bottom: 1px solid; } +.round-border-xs { border-radius: 2px; } +.round-border { border-radius: 5px; } +.round-border-xl { border-radius: 10px; } +.self-center { align-self: center; } + +/* LAYOUT */ +.fullheight { height: 100%; } +.fullwidth { width: 100%; } +.max-full-width { max-width: 100%; } +.restwidth { width: auto; } +.width-75 { width: 75%; } +.relative { position: relative; } +.absolute { position: absolute; } + +.bottom { bottom: 0; } +.hide-overflow { overflow: hidden; } +.hidden { display: none; } +.clickable { cursor: pointer; } + +/* SCROLLBARS */ +.vertical-scroll { overflow-y: auto; } + +.mainContent { + margin-top: 40px; + margin-bottom: 100px; +} + +.sidebar-toggle { + position: absolute; + top: 15px; + left: 15px; +} + +.sidebar-toggle:hover { + background-color: rgb(69, 150, 240); +} + +.external::after { + font-family: "Font Awesome 5 Free"; + font-weight: 600; + content: " \f35d"; + font-size: 10px; + vertical-align: super; +} + +.navigation { + padding-left: 15px; +} + +.fullscreen-container { + margin: auto; + position: fixed; + top: 0; left: 0; bottom: 0; right: 0; + z-index: 9999; + overflow-y: auto; + overflow-x: hidden; + background-color: transparent; + background-color: #000; + background-color: rgba(0, 0, 0, 0.6); +} + +.thumbnail { + border: 3px solid gray; +} + +.fullscreen-container > img { + position: fixed; + z-index: 1000; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + max-width: 95%; + max-height: 95%; + height: auto; + border: 3px solid gray; +} + +.closeButton { + position: fixed; + top: 30px; + right: 30px; + padding: 5px 9px 5px 9px; + background-color: #ddd; + border: 1px solid black; + font-size: 20px; + font-weight: bold; + cursor: pointer; +} + +.flags { + padding: 3px; +} + +.flags > a { + margin: 5px; +} + +span > .hljs { + display: inline; + padding: .2em; +} + +.inlineLink:hover { + text-decoration: underline; + cursor: pointer; +} + +.bash { + background-color: #2E3436; + padding: 3px 5px 3px 5px; +} + +.bash > span { + color: #D3D7CF; + overflow-wrap: anywhere; + word-break: break-all; +} + +.bash > span:first-child { + display: inline; + color: #4E9A06; +} + +.file-icon { + padding-bottom: 5px; +} diff --git a/fonts/fa-brands-400.eot b/fonts/fa-brands-400.eot new file mode 100644 index 0000000000000000000000000000000000000000..a619622eb7dc9cedff51ab6cf7c9129ff0f7e6b9 GIT binary patch literal 129734 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
    _-(cMNOm&U@x*_|z4sa{lZWUgf<$C+gzFKa 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%0Dh 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 literal 0 HcmV?d00001 diff --git a/fonts/fa-brands-400.svg b/fonts/fa-brands-400.svg new file mode 100644 index 0000000..33efe39 --- /dev/null +++ b/fonts/fa-brands-400.svg @@ -0,0 +1,3451 @@ + + + + + +Created by FontForge 20190112 at Fri Aug 2 14:42:17 2019 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/fa-brands-400.ttf b/fonts/fa-brands-400.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c3edffda1aec1119deaa70db1194ebb7198511ce GIT binary patch literal 129428 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 Km9L`hBmWP$9MoL^ literal 0 HcmV?d00001 diff --git a/fonts/fa-brands-400.woff b/fonts/fa-brands-400.woff new file mode 100644 index 0000000000000000000000000000000000000000..13125dceb3a221bcfdb33b1989eadc56dc6d9c96 GIT binary patch literal 87644 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 literal 0 HcmV?d00001 diff --git a/fonts/fa-brands-400.woff2 b/fonts/fa-brands-400.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..ce25be0b171badd09da50e0d4643510aba0535a6 GIT binary patch literal 74680 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

    ',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",sanitize:!0,sanitizeFn:null,whiteList:Ee},je="show",He="out",Re={HIDE:"hide"+De,HIDDEN:"hidden"+De,SHOW:"show"+De,SHOWN:"shown"+De,INSERTED:"inserted"+De,CLICK:"click"+De,FOCUSIN:"focusin"+De,FOCUSOUT:"focusout"+De,MOUSEENTER:"mouseenter"+De,MOUSELEAVE:"mouseleave"+De},xe="fade",Fe="show",Ue=".tooltip-inner",We=".arrow",qe="hover",Me="focus",Ke="click",Qe="manual",Be=function(){function i(t,e){if("undefined"==typeof u)throw new TypeError("Bootstrap's tooltips require Popper.js (https://popper.js.org/)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=g(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(g(this.getTipElement()).hasClass(Fe))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),g.removeData(this.element,this.constructor.DATA_KEY),g(this.element).off(this.constructor.EVENT_KEY),g(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&g(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===g(this.element).css("display"))throw new Error("Please use show on visible elements");var t=g.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){g(this.element).trigger(t);var n=_.findShadowRoot(this.element),i=g.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=_.getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&g(o).addClass(xe);var s="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,a=this._getAttachment(s);this.addAttachmentClass(a);var l=this._getContainer();g(o).data(this.constructor.DATA_KEY,this),g.contains(this.element.ownerDocument.documentElement,this.tip)||g(o).appendTo(l),g(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new u(this.element,o,{placement:a,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:We},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}}),g(o).addClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().on("mouseover",null,g.noop);var c=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,g(e.element).trigger(e.constructor.Event.SHOWN),t===He&&e._leave(null,e)};if(g(this.tip).hasClass(xe)){var h=_.getTransitionDurationFromElement(this.tip);g(this.tip).one(_.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=g.Event(this.constructor.Event.HIDE),o=function(){e._hoverState!==je&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),g(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(g(this.element).trigger(i),!i.isDefaultPrevented()){if(g(n).removeClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().off("mouseover",null,g.noop),this._activeTrigger[Ke]=!1,this._activeTrigger[Me]=!1,this._activeTrigger[qe]=!1,g(this.tip).hasClass(xe)){var r=_.getTransitionDurationFromElement(n);g(n).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){g(this.getTipElement()).addClass(Ae+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(g(t.querySelectorAll(Ue)),this.getTitle()),g(t).removeClass(xe+" "+Fe)},t.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Se(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?g(e).parent().is(t)||t.empty().append(e):t.text(g(e).text())},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getOffset=function(){var e=this,t={};return"function"==typeof this.config.offset?t.fn=function(t){return t.offsets=l({},t.offsets,e.config.offset(t.offsets,e.element)||{}),t}:t.offset=this.config.offset,t},t._getContainer=function(){return!1===this.config.container?document.body:_.isElement(this.config.container)?g(this.config.container):g(document).find(this.config.container)},t._getAttachment=function(t){return Pe[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)g(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==Qe){var e=t===qe?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===qe?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;g(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}}),g(this.element).closest(".modal").on("hide.bs.modal",function(){i.element&&i.hide()}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Me:qe]=!0),g(e.getTipElement()).hasClass(Fe)||e._hoverState===je?e._hoverState=je:(clearTimeout(e._timeout),e._hoverState=je,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===je&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Me:qe]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=He,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===He&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){var e=g(this.element).data();return Object.keys(e).forEach(function(t){-1!==Oe.indexOf(t)&&delete e[t]}),"number"==typeof(t=l({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),_.typeCheckConfig(be,t,this.constructor.DefaultType),t.sanitize&&(t.template=Se(t.template,t.whiteList,t.sanitizeFn)),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ne);null!==e&&e.length&&t.removeClass(e.join(""))},t._handlePopperPlacementChange=function(t){var e=t.instance;this.tip=e.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},t._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(g(t).removeClass(xe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=g(this).data(Ie),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),g(this).data(Ie,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return Le}},{key:"NAME",get:function(){return be}},{key:"DATA_KEY",get:function(){return Ie}},{key:"Event",get:function(){return Re}},{key:"EVENT_KEY",get:function(){return De}},{key:"DefaultType",get:function(){return ke}}]),i}();g.fn[be]=Be._jQueryInterface,g.fn[be].Constructor=Be,g.fn[be].noConflict=function(){return g.fn[be]=we,Be._jQueryInterface};var Ve="popover",Ye="bs.popover",ze="."+Ye,Xe=g.fn[Ve],$e="bs-popover",Ge=new RegExp("(^|\\s)"+$e+"\\S+","g"),Je=l({},Be.Default,{placement:"right",trigger:"click",content:"",template:''}),Ze=l({},Be.DefaultType,{content:"(string|element|function)"}),tn="fade",en="show",nn=".popover-header",on=".popover-body",rn={HIDE:"hide"+ze,HIDDEN:"hidden"+ze,SHOW:"show"+ze,SHOWN:"shown"+ze,INSERTED:"inserted"+ze,CLICK:"click"+ze,FOCUSIN:"focusin"+ze,FOCUSOUT:"focusout"+ze,MOUSEENTER:"mouseenter"+ze,MOUSELEAVE:"mouseleave"+ze},sn=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var o=i.prototype;return o.isWithContent=function(){return this.getTitle()||this._getContent()},o.addAttachmentClass=function(t){g(this.getTipElement()).addClass($e+"-"+t)},o.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},o.setContent=function(){var t=g(this.getTipElement());this.setElementContent(t.find(nn),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(on),e),t.removeClass(tn+" "+en)},o._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},o._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ge);null!==e&&0=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||trestarting the process."); + $("#status").show(); + }).always(function() { + if(done) done(success); + }); +} + +function retry() { + $("#btnRetry").hide(); + $("#progressText").show(); + sendRequest({ }, function(success) { + $("#progressText").hide(); + if(!success) $("#btnRetry").show(); + }); +} + +$(document).ready(function() { + + $("#btnSubmit").click(function() { + params = { }; + var textBefore = $("#btnSubmit").text(); + $("#btnSubmit").prop("disabled", true); + $("#btnSubmit").html("Submitting… "); + $("#installForm input").each(function() { + var type = $(this).attr("type"); + var name = $(this).attr("name"); + if(type === "text") { + params[name] = $(this).val().trim(); + } else if(type === "password" || type === "number") { + params[name] = $(this).val(); + } + }).promise().done(function() { + sendRequest(params, function(success) { + if(!success) { + $("#btnSubmit").prop("disabled",false); + $("#btnSubmit").text(textBefore); + } else { + setState(SUCCESFULL); + } + }); + }); + }); + + $("#btnPrev").click(function() { + $("#btnPrev").prop("disabled", true); + sendRequest({ "prev": true }, function(success) { + if(!success) { + $("#btnPrev").prop("disabled",false); + } else { + window.location.reload(); + } + }); + }); + + $("#btnSkip").click(function() { + $("#btnSkip").prop("disabled", true); + sendRequest({ "skip": true }, function(success) { + if(!success) { + $("#btnSkip").prop("btnSkip",false); + } else { + window.location.reload(); + } + }); + }); + + $("#btnRetry").click(function() { + retry(); + }); + +}); diff --git a/js/jquery.min.js b/js/jquery.min.js new file mode 100644 index 0000000..a1c07fd --- /dev/null +++ b/js/jquery.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.4.1 | (c) JS 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=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).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.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(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($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),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-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|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(m.childNodes),m.childNodes),t[m.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&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){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))&&y(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&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&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[k]=!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 ve(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 ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(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:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),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=k,!C.getElementsByName||!C.getElementsByName(k).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&&E){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&&E){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&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),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&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.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("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=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},D=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===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,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]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(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=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(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)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.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 k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.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(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(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,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(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)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").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)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.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(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.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?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.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,k.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)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.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"===k.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"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(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)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(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?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.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){k.fn[n]=function(e,t){return 0 0) { + $("#logoutTimer").attr("data-time", data.logoutIn); + } + + if(!data.success) { + onerror.call(this, data.msg); + } else { + callback.call(this, data); + } + }, "json").fail(function(jqXHR, textStatus, errorThrown) { + console.log("API-Function Error: " + func + " Status: " + textStatus + " error thrown: " + errorThrown); + onerror.call(this, "Ein Fehler ist aufgetreten. API-Funktion: " + func + " Status: " + textStatus + " - " + errorThrown); + }); + }; + + this.getCookie = function(cname) { + var name = cname + "="; + var decodedCookie = decodeURIComponent(document.cookie); + var ca = decodedCookie.split(";"); + for(var i = 0; i 0) + return true; + + callback = typeof callback !== 'undefined' ? callback : function() { }; + var core = this; + + var dialog = bootbox.dialog({ + message: 'Loading ' + src + '... ', + closeButton: false + }).bind('shown.bs.modal',function(){ + core.apiCall(api, { }, function(data) { + for(var id in data[src]) + dest[id] = data[src][id]; + + dialog.modal('hide'); + callback.call(this); + }, function(msg) { + bootbox.alert("Ein Fehler ist aufgetreten: " + msg); + dialog.modal('hide'); + }); + }); + + return false; + }; + + this.requestTags = function(callback) { + this.aTags = typeof this.aTags == "undefined" ? { } : this.aTags; + return this.requestData('tags/getTags', this.aTags, 'tags', callback); + }; + + this.requestAccounts = function(callback) { + this.aAccounts = typeof this.aAccounts == "undefined" ? { } : this.aAccounts; + return this.requestData('accounts/getAccounts', this.aAccounts, 'accounts', callback); + }; + + this.requestPartners = function(callback) { + this.aPartners = typeof this.aPartners == "undefined" ? { } : this.aPartners; + return this.requestData('accounts/getPartners', this.aPartners, 'partners', callback); + }; + + this.addLangEntry = function(key, val) { this.langEntries[key] = val; }; + this.getLangEntry = function(key) { + if(typeof this.langEntries[key] !== 'undefined' && this.langEntries.hasOwnProperty(key)) { + return this.langEntries[key]; + } + + return key; + }; + + this.getUrl = function() { return this.url; }; + this.getParameters = function() { return this.aParameters; }; + + this.setTitle = function(title) { + document.title = title; + }; + + this.changeURL = function(history) { + if(history) { + window.history.pushState({ + "html": document.getElementsByTagName("body")[0].innerHTML, + "pageTitle": document.title + }, "", this.url); + } else { + window.history.replaceState({ + "html": document.getElementsByTagName("body")[0].innerHTML, + "pageTitle": document.title + }, "", this.url); + } + }; + + this.redirect = function() { + window.location = this.url; + }; + + this.reload = function() { + window.location.reload(); + }; + + this.removeParameter = function(param) { + if (typeof this.aParameters[param] !== 'undefined' && this.aParameters.hasOwnProperty(param)) { + delete this.aParameters[param]; + } + this.updateUrl(); + }; + + this.getParameter = function(param) { + if (typeof this.aParameters[param] !== 'undefined' && this.aParameters.hasOwnProperty(param)) + return this.aParameters[param]; + else + return null; + }; + + this.setParameter = function(param, newvalue) { + newvalue = typeof newvalue !== 'undefined' ? newvalue : ''; + this.aParameters[param] = newvalue; + this.updateUrl(); + }; + + this.parseParameters = function() { + this.aParameters = []; + if(this.url.indexOf('?') === -1) + return; + + var paramString = this.url.substring(this.url.indexOf('?') + 1); + var split = paramString.split('&'); + for (var i = 0; i < split.length; i++) { + var param = split[i]; + var index = param.indexOf('='); + if(index !== -1) { + var key = param.substr(0, index); + var val = param.substr(index + 1); + this.aParameters[key] = val; + } else + this.aParameters[param] = ''; + } + }; + + this.updateUrl = function() { + this.clearUrl(); + var i = 0; + for (var parameter in this.aParameters) { + this.url += (i === 0 ? "?" : "&") + parameter; + if (this.aParameters.hasOwnProperty(parameter) && this.aParameters[parameter].toString().length > 0) { + this.url += "=" + this.aParameters[parameter]; + } + i++; + } + }; + + this.clearParameters = function() { + this.aParameters = []; + this.updateUrl(); + }; + + this.clearUrl = function() { + if(this.url.indexOf('?') !== -1) + this.url = this.url.substring(0, this.url.indexOf('?')); + }; + + this.logout = function() { + this.apiCall('logout'); + }; + + this.getJsonDateTime = function(date) { + return date.getFullYear() + "-" + + ((date.getMonth() + 1 < 10) ? "0" : "") + (date.getMonth() + 1) + "-" + + (date.getDate() < 10 ? "0" : "") + date.getDate() + " " + + (date.getHours() < 10 ? "0" : "") + date.getHours() + "-" + + (date.getMinutes() < 10 ? "0" : "") + date.getMinutes() + "-" + + (date.getSeconds() < 10 ? "0" : "") + date.getSeconds(); + }; + + this.getJsonDate = function(date) { + return this.getJsonDateTime(date).split(' ')[0]; + }; + + this.getJsonTime = function(date) { + return this.getJsonDateTime(date).split(' ')[1]; + }; + + this.showInputDialog = function(title, aInputs, callback, element, onCreated) { + title = typeof title !== "undefined" ? title : ""; + aInputs = typeof aInputs !== "undefined" ? aInputs : {}; + callback = typeof callback !== "undefined" ? callback : function(aResult, element) {}; + onCreated = typeof onCreated !== "undefined" ? onCreated : function() {}; + + var html = '' + + '
    '; + + for (var i in aInputs) { + var input = aInputs[i]; + + if(input.type !== "hidden" && input.type !== "checkbox") + html += ''; + + if(input.type === "select") { + html += ''; + input.type = "select"; + } else if(input.type === "checkbox") { + html += '
    ' + + '' + + '
    '; + } else if(input.type === "date") { + html += ''; + } else if(input.type === "time") { + html += '
    ' + + '' + + ':' + + '' + + '
    '; + } else { + html += ''; + } + } + + html += '
    '; + var dialog = bootbox.confirm(html, function(result) { + if(result) { + var aResult = []; + for (var i in aInputs) { + var input = aInputs[i]; + var value = $("#" + input.id).val(); + + if(input.type === "select") + value = $("#" + input.id).find(":selected").val(); + else if(input.type === "checkbox") + value = $("#" + input.id).prop("checked"); + + aResult[input.id] = value; + } + callback.call(this, aResult, element); + } + }); + + dialog.init(function() { + $(".modal-body").on("keypress", "input", function(e) { + if(e.keyCode == 13) { + e.preventDefault(); + $(".modal-footer .btn-primary").click(); + } + }); + onCreated.call(this); + }); + }; + + this.__construct(); +}; + + +function findGetParameter(parameterName) { + var result = null, tmp = []; + location.search.substr(1).split("&").forEach(function (item) { + tmp = item.split("="); + if (tmp[0] === parameterName) { + result = decodeURIComponent(tmp[1]); + } + }); + return result; +} + +var jsCore = new Core(); +$(document).ready(function() { + + $(".nav-toggle-menu").click(function(e) { + e.preventDefault(); + var ul = $(this).parents('li').find('ul'); + if(ul.hasClass('closed')) { + $(this).removeClass('fa-caret-down'); + $(this).addClass('fa-caret-up'); + + ul.animate({ + "max-height": (ul.find('li').length * 38) + "px" + }, { + duration: 350, + easing: "swing", + complete: function() { ul.removeClass('closed'); } + }); + } else { + $(this).removeClass('fa-caret-up'); + $(this).addClass('fa-caret-down'); + + ul.animate({ + "max-height": "0" + }, { + duration: 350, + easing: "swing", + complete: function() { ul.addClass('closed'); } + }); + } + }); + + $(".copy").click(function() { + var text = $(this).text(); + if(navigator.clipboard) { + navigator.clipboard.writeText(text).then(function() { }, function(err) { + console.error('Async: Could not copy text: ', err); + }); + } + }); + + function toggleLinkIcon(icon, show, parent) { + if(show) { + icon.show(); + if(parent) { + icon.position({ + my: "right-5", + at: "left", + of: parent + }); + } + } else { + icon.hide(); + } + } + + $(".inlineLink").mouseenter(function() { + var target = $(this).data("target"); + if(target) { + var icon = $("#" + target); + toggleLinkIcon(icon, true, $(this)); + } + }); + + $(".inlineLink").mouseleave(function() { + var target = $(this).data("target"); + if(target) { + var icon = $("#" + target); + toggleLinkIcon(icon, false); + } + }); + + $(".inlineLink").click(function() { + var id = $(this).attr('id'); + if(id) { + var url = window.location.href; + var index = url.indexOf("#"); + if(index !== -1) { + url = url.substring(0, index); + } + + window.location.href = url + "#" + id; + } + }); +}); diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..3f5c8f8 --- /dev/null +++ b/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: /core