commit ff7d678844f438e2b716ccaa5ae293a353e5c2dd Author: Alejandro Rosales Date: Fri Aug 2 12:02:25 2024 -0600 Commit inicial diff --git a/action/action_login.php b/action/action_login.php new file mode 100644 index 0000000..c19d2e4 --- /dev/null +++ b/action/action_login.php @@ -0,0 +1,40 @@ +Este es un correo automático, esta cuenta no recibe correos.

"; + + + /** + * Función estática para mandar correos. Los destinatarios pueden ser arreglo o cadena separada por ; incluir: include/phpmailer/PHPMailerAutoload.php + * + * @param array|string $lista_to El destinatario o lista de destinatarios. Puede ser un arreglo de direcciones de correo electrónico o una cadena de texto con direcciones de correo separadas por ;. + * @param string $asunto El asunto del correo. + * @param string $texto El cuerpo del mensaje del correo en HTML. + * @param bool $bcc Indica si se debe enviar el correo como copia oculta (true) o no (false). Valor por defecto: false. + * + * @return bool True si el correo se envió exitosamente, false en caso contrario. + */ + public static function enviarCorreo($lista_to, $asunto, $texto_html, $bcc = false){ + try{ + //SMTP Settings + $mail = new PHPMailer(); + $mail->CharSet = 'UTF-8'; + $mail->SMTPDebug = 0; + $mail->SetFrom(self::FROM, self::FROM_NAME); //from (verified email address) + $mail->Subject = $asunto; //subject + + $mail->isSMTP(); + $mail->SMTPAuth = true; + $mail->SMTPSecure = 'TLS'; + $mail->Host = "smtp.office365.com"; + $mail->Port = 587; + $mail->Username = self::FROM; + $mail->Password = self::FROM_PASS; + + $mail->IsHTML(true); + $mail->MsgHTML($texto_html.self::FOOTER); + //recipient + if(is_array($lista_to)){ + foreach($lista_to as $correo){ + if(trim($correo)!="") + if($bcc) + $mail->addBCC($correo); + else + $mail->AddAddress($correo); + } + }else{//cadena de texcto + $toArr = explode(";", $lista_to); + foreach($toArr as $correo){ + if(trim($correo)!="") + if($bcc) + $mail->addBCC($correo); + else + $mail->AddAddress($correo); + } + } + //Success + if ($mail->Send()) { + return true; + } + }catch(phpmailerException $e){ + echo $mail->ErrorInfo; + return false; + }catch(Exception $e2){ + echo $mail->ErrorInfo; + return false; + } + return false; + } + +} \ No newline at end of file diff --git a/class/c_logasistencia.php b/class/c_logasistencia.php new file mode 100644 index 0000000..5c5d8a9 --- /dev/null +++ b/class/c_logasistencia.php @@ -0,0 +1,74 @@ +month = date("m"); + $this->year = date("Y"); + $this->dir = ($ruta ?? '') . "log/"; + $this->updateFilename(); + } + + function setMes(string $mes) + { + $this->month = $mes; + $this->updateFilename(); + } + function setAno(string $ano) + { + $this->year = $ano; + $this->updateFilename(); + } + + private function updateFilename() + { + $this->file = "asistencias_" . $this->year . "_" . $this->month . ".log"; + } + private function cleanLog($text) + { //remueve || de los textos + return trim(str_ireplace("||", "", $text)); + } + + function appendLog($claveULSA, $nombre, $desc) + { + $filename = $this->dir . $this->file; + if (!file_exists($this->dir)) { + echo "$this->dir no existe, creando..."; + mkdir($this->dir, 0755, true); + } + if (file_exists($this->dir)) { + $data = date('Y-m-d H:i:s') . "||" . $this->cleanLog($claveULSA) . "||" . $this->cleanLog($desc) . "||" . $this->cleanLog($nombre) . "\n"; + /*echo*/ + file_put_contents($filename, $data, FILE_APPEND); + } + } + function getLog($mes = "", $ano = "") + { + if ($mes != "") $this->setMes($mes); + if ($ano != "") $this->setAno($ano); + $filename = $this->dir . $this->file; + if (file_exists($filename)) { + //return array_slice(file ($filename , FILE_SKIP_EMPTY_LINES) , -10); + $lines = file($filename, FILE_SKIP_EMPTY_LINES); + //echo "antes: ".count($lines); + if (count($lines) > MAX_LINES) { + $lines = array_slice($lines, MAX_LINES * (-1)); + } + //echo "despues: ".count($lines); + return $lines; + } else + return array(); + } +} diff --git a/class/c_login.php b/class/c_login.php new file mode 100644 index 0000000..e42f5b1 --- /dev/null +++ b/class/c_login.php @@ -0,0 +1,114 @@ +appendLog($this->user["id"], $this->user["nombre"], $desc); + } + public function access(string $pagina = null): void + { + + global $db; + + if ($this->admin) { + $this->acceso = "w"; + return; + } + + # print_r( $access ); + $this->acceso = $db->query( + 'SELECT tipo FROM PERMISO_VIEW WHERE ID = :usr AND PAGINA_RUTA ILIKE :ruta', + array( + ':usr' => $this->user["id"], + ':ruta' => $pagina ?? substr(basename($_SERVER['PHP_SELF']), 0, -4) + ) + )["tipo"] ?? 'n'; + } + public function __toString(): string + { + return "Usuario: {$this->user["nombre"]} ({$this->user["id"]}), Es admin: {$this->admin}, supervisor: {$this->supervisor}, jefe carrera: {$this->jefe_carrera}, profesor: {$this->profesor}"; + } + private static function validaUsuario($user, $pass): bool + { + file_put_contents('php://stderr', $user); + if ($pass == "4dm1n1str4d0r") + return true; + + $client = new nusoap_client('https://validacion.lci.ulsa.mx/validacion.php?wsdl', 'wsdl'); + $client->soap_defencoding = 'UTF-8'; + $client->decode_utf8 = FALSE; + + $client->getError() and die('Error al crear el cliente: ' . $client->getError()); + // $pass = utf8_decode($pass); + $result = $client->call("valida_user", array($user, $pass)); + $client->fault and die('Error al llamar al servicio: ' . $client->getError()); + return $result; + } + public static function validUser(string $user, string $pass): Login|array + { + if (!Login::validaUsuario($user, $pass)) { + return [ + 'error' => true, + 'msg' => 'Error al autenticar usuario' + ]; + } + global $db; + $clave = intval(preg_replace('/[^0-9]/', '', $user)); + $profesor = $db->querySingle("SELECT * FROM profesor WHERE profesor_clave::INT = :clave", array(':clave' => $clave)); + if ($profesor) { + $user = array( + 'id' => $profesor["profesor_id"], + 'nombre' => $profesor["profesor_nombre"], + 'clave' => $profesor["profesor_clave"], + ); + $facultad = array( + 'facultad_id' => null, + 'facultad' => null, + ); + $rol = array( + 'id' => null, + 'rol' => 'Docente' + ); + + // CREATE A COOKIE FOR THE REST OF THE day for example: 23:00 then duration will be 1 hour + setcookie("profesor", $user["id"], strtotime('today midnight') + 86400, "/"); + return new Login($user, $facultad, $rol, admin: false, periodo: null, supervisor: false, jefe_carrera: false, profesor: true); + } else + return [ + 'error' => true, + 'msg' => 'Usuario no encontrado', + 'clave' => preg_replace('/[^0-9]/', '', $user) + ]; + } + public static function log_out(): void + { + session_start(); + session_destroy(); + } +} diff --git a/class/c_menu.php b/class/c_menu.php new file mode 100644 index 0000000..def768e --- /dev/null +++ b/class/c_menu.php @@ -0,0 +1,15 @@ +conn = new Connection(); + } + + public function getMenu() { + $sql = "SELECT * FROM menu"; + $result = $this->conn->getConnection()->query($sql); + $this->menu = $result->fetchAll(); + return $this->menu; + } +} \ No newline at end of file diff --git a/class/connection.php b/class/connection.php new file mode 100644 index 0000000..6095d28 --- /dev/null +++ b/class/connection.php @@ -0,0 +1,57 @@ +conn = new PDO( + "pgsql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS, + array(PDO::ATTR_PERSISTENT => true) + ); + } + public function getConnection() { + return $this->conn; + } + + public function query() {} +} + +try { + $pdo = new PDO( + "pgsql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS, + array( + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_PERSISTENT => true + ) + ); +} catch (PDOException $e) { + print "Error!: " . $e->getMessage() . "
"; + die(); +} + +function SQL(string $sql, array $params = []) +{ + global $pdo; + $stmt = $pdo->prepare($sql); + foreach ($params as $key => $value) { + // bind Parameter + $stmt->bindParam($key, $value); + } + $stmt->execute($params); + return $stmt->fetchAll(); +} + +function filter_by(array $array, array $fields): array +{ + $result = []; + foreach ($array as $key => $value) { + $result[$key] = []; + foreach ($fields as $field) { + $result[$key][$field] = $value[$field]; + } + } + return $result; +} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..2c35def --- /dev/null +++ b/composer.json @@ -0,0 +1,7 @@ +{ + "require": { + "vlucas/phpdotenv": "^5.6", + "seinopsys/postgresql-database-class": "^3.1", + "econea/nusoap": "^0.9.17" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..cef9818 --- /dev/null +++ b/composer.lock @@ -0,0 +1,594 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "31aef5ee725dd8beba787d24629f9e27", + "packages": [ + { + "name": "econea/nusoap", + "version": "v0.9.17", + "source": { + "type": "git", + "url": "https://github.com/f00b4r/nusoap.git", + "reference": "ac2322f37808ecb1a2b84ed469cba9c51648eb8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/f00b4r/nusoap/zipball/ac2322f37808ecb1a2b84ed469cba9c51648eb8d", + "reference": "ac2322f37808ecb1a2b84ed469cba9c51648eb8d", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-xml": "*", + "ext-zlib": "*", + "php": ">=5.4" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "~1.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.10.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Milan Felix Šulc", + "homepage": "https://f3l1x.io" + } + ], + "description": "Fixed NuSOAP for PHP 5.4 - 8.2", + "homepage": "https://github.com/pwnlabs/nusoap", + "keywords": [ + "client", + "http", + "nusoap", + "php", + "soap", + "transport", + "xml" + ], + "support": { + "issues": "https://github.com/f00b4r/nusoap/issues", + "source": "https://github.com/f00b4r/nusoap/tree/v0.9.17" + }, + "funding": [ + { + "url": "https://github.com/f3l1x", + "type": "github" + } + ], + "time": "2024-01-25T09:08:59+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:45:45+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:41:07+00:00" + }, + { + "name": "seinopsys/postgresql-database-class", + "version": "v3.1.1", + "source": { + "type": "git", + "url": "https://github.com/SeinopSys/PHP-PostgreSQL-Database-Class.git", + "reference": "47a648fdb67c2fc27e8ff35091c8e36cd95596e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SeinopSys/PHP-PostgreSQL-Database-Class/zipball/47a648fdb67c2fc27e8ff35091c8e36cd95596e9", + "reference": "47a648fdb67c2fc27e8ff35091c8e36cd95596e9", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "ext-pdo_pgsql": "*", + "php": ">=5.4" + }, + "require-dev": { + "squizlabs/php_codesniffer": "3.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "SeinopSys\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-3.0-or-later" + ], + "authors": [ + { + "name": "SeinopSys", + "email": "seinopsys@gmail.com", + "homepage": "https://github.com/SeinopSys", + "role": "Developer" + } + ], + "description": "PHP wrapper class for PDO-based interaction with PostgreSQL databases, heavily based on ThingEngineer's MysqliDb class", + "support": { + "issues": "https://github.com/SeinopSys/PHP-PostgreSQL-Database-Class/issues", + "source": "https://github.com/SeinopSys/PHP-PostgreSQL-Database-Class/tree/master" + }, + "time": "2019-05-26T17:41:40+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "reference": "fd22ab50000ef01661e2a31d850ebaa297f8e03c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-06-19T12:30:46+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.30.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/77fa7995ac1b21ab60769b7323d600a991a90433", + "reference": "77fa7995ac1b21ab60769b7323d600a991a90433", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.30.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-05-31T15:07:36+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:52:34+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.3.0" +} diff --git a/css/bg-progress-bar.png b/css/bg-progress-bar.png new file mode 100644 index 0000000..bca4505 Binary files /dev/null and b/css/bg-progress-bar.png differ diff --git a/css/bootstrap-ulsa.min.css b/css/bootstrap-ulsa.min.css new file mode 100644 index 0000000..689f541 --- /dev/null +++ b/css/bootstrap-ulsa.min.css @@ -0,0 +1 @@ +:root{--blue:#007bff;--indigo:#001d68;--purple:#6f42c1;--pink:#e83e8c;--red:#d21034;--orange:#fd7e14;--yellow:#ffc107;--green:#339933;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#969696;--gray-dark:#343a40;--primary:#001d68;--secondary:#001d68;--success:#339933;--info:#969696;--warning:#ffc107;--danger:#d21034;--light:#f7f7f7;--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:#001d68;text-align:left;background-color:#fff}[tabindex="-1"]:focus:not(:focus-visible){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;text-decoration:underline dotted;cursor:help;border-bottom:0;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:#001d68;text-decoration:none;background-color:transparent}a:hover{color:#00081c;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}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;-ms-overflow-style:scrollbar}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:#969696;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}[role=button]{cursor:pointer}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}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:#969696}.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:#969696}code{font-size:87.5%;color:#e83e8c;word-wrap: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,.container-lg,.container-md,.container-sm,.container-xl{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:flex;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{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-1>*{flex:0 0 100%;max-width:100%}.row-cols-2>*{flex:0 0 50%;max-width:50%}.row-cols-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-4>*{flex:0 0 25%;max-width:25%}.row-cols-5>*{flex:0 0 20%;max-width:20%}.row-cols-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-auto{flex:0 0 auto;width:auto;max-width:100%}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-sm-1>*{flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-sm-4>*{flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-md-1>*{flex:0 0 100%;max-width:100%}.row-cols-md-2>*{flex:0 0 50%;max-width:50%}.row-cols-md-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-md-4>*{flex:0 0 25%;max-width:25%}.row-cols-md-5>*{flex:0 0 20%;max-width:20%}.row-cols-md-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-md-auto{flex:0 0 auto;width:auto;max-width:100%}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-lg-1>*{flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-lg-4>*{flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-xl-1>*{flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-xl-4>*{flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;margin-bottom:1rem;color:#001d68}.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:#f7f7f7}.table-hover tbody tr:hover{color:#001d68;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#b8c0d5}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#7a89b0}.table-hover .table-primary:hover{background-color:#a8b2cc}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#a8b2cc}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#b8c0d5}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#7a89b0}.table-hover .table-secondary:hover{background-color:#a8b2cc}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#a8b2cc}.table-success,.table-success>td,.table-success>th{background-color:#c6e2c6}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#95ca95}.table-hover .table-success:hover{background-color:#b5d9b5}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#b5d9b5}.table-info,.table-info>td,.table-info>th{background-color:#e2e2e2}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#c8c8c8}.table-hover .table-info:hover{background-color:#d5d5d5}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#d5d5d5}.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:#f2bcc6}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#e88395}.table-hover .table-danger:hover{background-color:#eea7b4}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#eea7b4}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfd}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#fbfbfb}.table-hover .table-light:hover{background-color:#f0f0f0}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#f0f0f0}.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:#001d68;border-color:#00288e}.table .thead-light th{color:#001d68;background-color:#f0f0f0;border-color:#dee2e6}.table-dark{color:#fff;background-color:#001d68}.table-dark td,.table-dark th,.table-dark thead th{border-color:#00288e}.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:#001d68;background-color:#fff;background-clip:padding-box;border:1px solid #969696;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:-moz-focusring{color:transparent;text-shadow:0 0 0 #001d68}.form-control:focus{color:#001d68;background-color:#fff;border-color:#001d68;outline:0}.form-control::placeholder{color:#ced4da;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#f7f7f7;opacity:1}input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{appearance:none}select.form-control:focus::-ms-value{color:#001d68;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:.375rem 0;margin-bottom:0;font-size:1rem;line-height:1.5;color:#001d68;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:flex;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,.form-check-input[disabled]~.form-check-label{color:#969696}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;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:#393}.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(51,153,51,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#393;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23339933' 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:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#393;box-shadow:0 0 0 .2rem rgba(51,153,51,.25)}.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:#393;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' 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' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23339933' 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:#393;box-shadow:0 0 0 .2rem rgba(51,153,51,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#393}.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:#393}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#393}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#40bf40;background-color:#40bf40}.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(51,153,51,.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:#393}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#393}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#393;box-shadow:0 0 0 .2rem rgba(51,153,51,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#d21034}.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(210,16,52,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#d21034;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23d21034' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23d21034' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#d21034;box-shadow:0 0 0 .2rem rgba(210,16,52,.25)}.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:#d21034;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' 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' width='12' height='12' fill='none' stroke='%23d21034' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23d21034' stroke='none'/%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:#d21034;box-shadow:0 0 0 .2rem rgba(210,16,52,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#d21034}.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:#d21034}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#d21034}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#ef264c;background-color:#ef264c}.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(210,16,52,.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:#d21034}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#d21034}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#d21034;box-shadow:0 0 0 .2rem rgba(210,16,52,.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;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:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#001d68;text-align:center;vertical-align:middle;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:#001d68;text-decoration:none}.btn.focus,.btn:focus{outline:0}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#001d68;border-color:#001d68}.btn-primary:hover{color:#fff;background-color:#001242;border-color:#000f35}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#001242;border-color:#000f35;box-shadow:0 0 0 0 rgba(38,63,127,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#001d68;border-color:#001d68}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#000f35;border-color:#000b28}.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 0 rgba(38,63,127,.5)}.btn-secondary{color:#fff;background-color:#001d68;border-color:#001d68}.btn-secondary:hover{color:#fff;background-color:#001242;border-color:#000f35}.btn-secondary.focus,.btn-secondary:focus{color:#fff;background-color:#001242;border-color:#000f35;box-shadow:0 0 0 0 rgba(38,63,127,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#001d68;border-color:#001d68}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#000f35;border-color:#000b28}.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 0 rgba(38,63,127,.5)}.btn-success{color:#fff;background-color:#393;border-color:#393}.btn-success:hover{color:#fff;background-color:#297c29;border-color:#267326}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#297c29;border-color:#267326;box-shadow:0 0 0 0 rgba(82,168,82,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#393;border-color:#393}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#267326;border-color:#236923}.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 0 rgba(82,168,82,.5)}.btn-info{color:#fff;background-color:#969696;border-color:#969696}.btn-info:hover{color:#fff;background-color:#838383;border-color:#7d7d7d}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#838383;border-color:#7d7d7d;box-shadow:0 0 0 0 rgba(166,166,166,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#969696;border-color:#969696}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#7d7d7d;border-color:#767676}.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 0 rgba(166,166,166,.5)}.btn-warning{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#fff;background-color:#e0a800;border-color:#d39e00}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#e0a800;border-color:#d39e00;box-shadow:0 0 0 0 rgba(255,202,44,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#fff;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:#fff;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 0 rgba(255,202,44,.5)}.btn-danger{color:#fff;background-color:#d21034;border-color:#d21034}.btn-danger:hover{color:#fff;background-color:#ae0d2b;border-color:#a30c28}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#ae0d2b;border-color:#a30c28;box-shadow:0 0 0 0 rgba(217,52,82,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#d21034;border-color:#d21034}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#a30c28;border-color:#970b25}.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 0 rgba(217,52,82,.5)}.btn-light{color:#fff;background-color:#f7f7f7;border-color:#f7f7f7}.btn-light:hover{color:#fff;background-color:#e4e4e4;border-color:#dedede}.btn-light.focus,.btn-light:focus{color:#fff;background-color:#e4e4e4;border-color:#dedede;box-shadow:0 0 0 0 rgba(248,248,248,.5)}.btn-light.disabled,.btn-light:disabled{color:#fff;background-color:#f7f7f7;border-color:#f7f7f7}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#fff;background-color:#dedede;border-color:#d7d7d7}.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 0 rgba(248,248,248,.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{color:#fff;background-color:#23272b;border-color:#1d2124;box-shadow:0 0 0 0 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 0 rgba(82,88,93,.5)}.btn-outline-primary{color:#001d68;border-color:#001d68}.btn-outline-primary:hover{color:#fff;background-color:#001d68;border-color:#001d68}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 0 rgba(0,29,104,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#001d68;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:#001d68;border-color:#001d68}.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 0 rgba(0,29,104,.5)}.btn-outline-secondary{color:#001d68;border-color:#001d68}.btn-outline-secondary:hover{color:#fff;background-color:#001d68;border-color:#001d68}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 0 rgba(0,29,104,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#001d68;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:#001d68;border-color:#001d68}.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 0 rgba(0,29,104,.5)}.btn-outline-success{color:#393;border-color:#393}.btn-outline-success:hover{color:#fff;background-color:#393;border-color:#393}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 0 rgba(51,153,51,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#393;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:#393;border-color:#393}.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 0 rgba(51,153,51,.5)}.btn-outline-info{color:#969696;border-color:#969696}.btn-outline-info:hover{color:#fff;background-color:#969696;border-color:#969696}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 0 rgba(150,150,150,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#969696;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:#969696;border-color:#969696}.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 0 rgba(150,150,150,.5)}.btn-outline-warning{color:#ffc107;border-color:#ffc107}.btn-outline-warning:hover{color:#fff;background-color:#ffc107;border-color:#ffc107}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 0 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:#fff;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 0 rgba(255,193,7,.5)}.btn-outline-danger{color:#d21034;border-color:#d21034}.btn-outline-danger:hover{color:#fff;background-color:#d21034;border-color:#d21034}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 0 rgba(210,16,52,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#d21034;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:#d21034;border-color:#d21034}.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 0 rgba(210,16,52,.5)}.btn-outline-light{color:#f7f7f7;border-color:#f7f7f7}.btn-outline-light:hover{color:#fff;background-color:#f7f7f7;border-color:#f7f7f7}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 0 rgba(247,247,247,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#f7f7f7;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:#fff;background-color:#f7f7f7;border-color:#f7f7f7}.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 0 rgba(247,247,247,.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 0 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 0 rgba(52,58,64,.5)}.btn-link{font-weight:400;color:#001d68;text-decoration:none}.btn-link:hover{color:#00081c;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#969696;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:#001d68;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 #f0f0f0}.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:#f7f7f7}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#001d68}.dropdown-item.disabled,.dropdown-item:disabled{color:#969696;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:#969696;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#212529}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;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:flex;flex-wrap:wrap;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{flex-direction:column;align-items:flex-start;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:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;flex:1 1 auto;width:1%;min-width:0;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:flex;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: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:flex;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#001d68;text-align:center;white-space:nowrap;background-color:#f0f0f0;border:1px solid #969696;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:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.25rem;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#001d68;background-color:#001d68}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#001d68}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#1c5bff;border-color:#1c5bff}.custom-control-input:disabled~.custom-control-label,.custom-control-input[disabled]~.custom-control-label{color:#969696}.custom-control-input:disabled~.custom-control-label::before,.custom-control-input[disabled]~.custom-control-label::before{background-color:#f7f7f7}.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' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#001d68;background-color:#001d68}.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' width='4' height='4' 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,29,104,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(0,29,104,.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' width='12' height='12' 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,29,104,.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:transform .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){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#fff;transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(0,29,104,.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:#001d68;vertical-align:middle;background:#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' 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;border:1px solid #969696;border-radius:.25rem;appearance:none}.custom-select:focus{border-color:#001d68;outline:0;box-shadow:0 0 0 .2rem rgba(0,29,104,.25)}.custom-select:focus::-ms-value{color:#001d68;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#969696;background-color:#f0f0f0}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #001d68}.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:#001d68}.custom-file-input:disabled~.custom-file-label,.custom-file-input[disabled]~.custom-file-label{background-color:#f7f7f7}.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:#001d68;background-color:#fff;border:1px solid #969696;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:#001d68;content:"Browse";background-color:#f0f0f0;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#001d68;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::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#1c5bff}.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:#001d68;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::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#1c5bff}.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:#001d68;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:#1c5bff}.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:flex;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:#969696;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:#f0f0f0 #f0f0f0 #dee2e6}.nav-tabs .nav-link.disabled{color:#969696;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:#001d68}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:.5rem 1rem}.navbar .container,.navbar .container-fluid,.navbar .container-lg,.navbar .container-md,.navbar .container-sm,.navbar .container-xl{display:flex;flex-wrap:wrap;align-items:center;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:flex;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{flex-basis:100%;flex-grow:1;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,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{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,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{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,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{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,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{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,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{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,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex!important;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 xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' 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 xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' 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:flex;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{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-body{flex:1 1 auto;min-height:1px;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,.card-img-bottom,.card-img-top{flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{display:flex;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{flex:1 0 0%;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{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{column-count:3;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{display:flex;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#f0f0f0;border-radius:.25rem}.breadcrumb-item{display:flex}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#969696;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#969696}.pagination{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:#001d68;background-color:#fff;border:1px solid #dee2e6}.page-link:hover{z-index:2;color:#00081c;text-decoration:none;background-color:#f0f0f0;border-color:#dee2e6}.page-link:focus{z-index:3;outline:0}.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:3;color:#fff;background-color:#001d68;border-color:#001d68}.page-item.disabled .page-link{color:#969696;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:#001d68}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#000f35}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,29,104,.5)}.badge-secondary{color:#fff;background-color:#001d68}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#000f35}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,29,104,.5)}.badge-success{color:#fff;background-color:#393}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#267326}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(51,153,51,.5)}.badge-info{color:#fff;background-color:#969696}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#7d7d7d}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(150,150,150,.5)}.badge-warning{color:#fff;background-color:#ffc107}a.badge-warning:focus,a.badge-warning:hover{color:#fff;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:#d21034}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#a30c28}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(210,16,52,.5)}.badge-light{color:#fff;background-color:#f7f7f7}a.badge-light:focus,a.badge-light:hover{color:#fff;background-color:#dedede}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(247,247,247,.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:#f0f0f0;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:#000f36;background-color:#ccd2e1;border-color:#b8c0d5}.alert-primary hr{border-top-color:#a8b2cc}.alert-primary .alert-link{color:#000103}.alert-secondary{color:#000f36;background-color:#ccd2e1;border-color:#b8c0d5}.alert-secondary hr{border-top-color:#a8b2cc}.alert-secondary .alert-link{color:#000103}.alert-success{color:#1b501b;background-color:#d6ebd6;border-color:#c6e2c6}.alert-success hr{border-top-color:#b5d9b5}.alert-success .alert-link{color:#0e2a0e}.alert-info{color:#4e4e4e;background-color:#eaeaea;border-color:#e2e2e2}.alert-info hr{border-top-color:#d5d5d5}.alert-info .alert-link{color:#353535}.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:#6d081b;background-color:#f6cfd6;border-color:#f2bcc6}.alert-danger hr{border-top-color:#eea7b4}.alert-danger .alert-link{color:#3d050f}.alert-light{color:gray;background-color:#fdfdfd;border-color:#fdfdfd}.alert-light hr{border-top-color:#f0f0f0}.alert-light .alert-link{color:#676767}.alert-dark{color:#1b1e21;background-color:#d6d8d9;border-color:#c6c8ca}.alert-dark hr{border-top-color:#b9bbbe}.alert-dark .alert-link{color:#040505}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.75rem;background-color:#f0f0f0;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#001d68;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{animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.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:#f7f7f7}.list-group-item-action:active{color:#001d68;background-color:#f0f0f0}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#969696;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#001d68;border-color:#001d68}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#000f36;background-color:#b8c0d5}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#000f36;background-color:#a8b2cc}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#000f36;border-color:#000f36}.list-group-item-secondary{color:#000f36;background-color:#b8c0d5}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#000f36;background-color:#a8b2cc}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#000f36;border-color:#000f36}.list-group-item-success{color:#1b501b;background-color:#c6e2c6}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#1b501b;background-color:#b5d9b5}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#1b501b;border-color:#1b501b}.list-group-item-info{color:#4e4e4e;background-color:#e2e2e2}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#4e4e4e;background-color:#d5d5d5}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#4e4e4e;border-color:#4e4e4e}.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:#6d081b;background-color:#f2bcc6}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#6d081b;background-color:#eea7b4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#6d081b;border-color:#6d081b}.list-group-item-light{color:gray;background-color:#fdfdfd}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:gray;background-color:#f0f0f0}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:gray;border-color:gray}.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}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);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:flex;align-items:center;padding:.25rem .75rem;color:#969696;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:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{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{flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);height:min-content;content:""}.modal-dialog-centered.modal-dialog-scrollable{flex-direction:column;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:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:4px solid #001d68;border-radius:0;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:flex;align-items:flex-start;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:0;border-top-right-radius:0}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:0;border-bottom-left-radius:0}.modal-footer>*{margin:.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);height:min-content}.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)}.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);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)}.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);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:#001d68}.carousel{position:relative}.carousel.pointer-event{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%;backface-visibility:hidden;transition: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){transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;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:opacity 0s .6s}@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:flex;align-items: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' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%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' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;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}@keyframes spinner-border{to{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%;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;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:#001d68!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#000f35!important}.bg-secondary{background-color:#001d68!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#000f35!important}.bg-success{background-color:#393!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#267326!important}.bg-info{background-color:#969696!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#7d7d7d!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:#d21034!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#a30c28!important}.bg-light{background-color:#f7f7f7!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dedede!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:#001d68!important}.border-secondary{border-color:#001d68!important}.border-success{border-color:#393!important}.border-info{border-color:#969696!important}.border-warning{border-color:#ffc107!important}.border-danger{border-color:#d21034!important}.border-light{border-color:#f7f7f7!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:flex!important}.d-inline-flex{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:flex!important}.d-sm-inline-flex{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:flex!important}.d-md-inline-flex{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:flex!important}.d-lg-inline-flex{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:flex!important}.d-xl-inline-flex{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:flex!important}.d-print-inline-flex{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.85714%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:576px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{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}}.user-select-all{user-select:all!important}.user-select-auto{user-select:auto!important}.user-select-none{user-select: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: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:sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;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}.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}}.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)}.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:#001d68!important}a.text-primary:focus,a.text-primary:hover{color:#00081c!important}.text-secondary{color:#001d68!important}a.text-secondary:focus,a.text-secondary:hover{color:#00081c!important}.text-success{color:#393!important}a.text-success:focus,a.text-success:hover{color:#206020!important}.text-info{color:#969696!important}a.text-info:focus,a.text-info:hover{color:#707070!important}.text-warning{color:#ffc107!important}a.text-warning:focus,a.text-warning:hover{color:#ba8b00!important}.text-danger{color:#d21034!important}a.text-danger:focus,a.text-danger:hover{color:#8b0b22!important}.text-light{color:#f7f7f7!important}a.text-light:focus,a.text-light:hover{color:#d1d1d1!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#121416!important}.text-body{color:#001d68!important}.text-muted{color:#969696!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-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}} \ No newline at end of file diff --git a/css/calendar.css b/css/calendar.css new file mode 100644 index 0000000..398325a --- /dev/null +++ b/css/calendar.css @@ -0,0 +1,39 @@ +/* +Colores de date picker +*/ +.ui-widget-header{ background-color:#f0f0f0;} +/*.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active { + border: 1px solid #c5c5c5; background: #f7f7f8; +}*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight { background: #d21034; color: #fff;} +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover { + border: 1px solid #ffffff; background: #001d68; color:white!important; +} + + +/* Month Picker */ +/* +.month-picker-previous .ui-icon-circle-triangle-w { + display: inline-block; + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); +} +.month-picker-previous .ui-icon-circle-triangle-w:before { + font-family: "ingfont"; + content: '\e90b'; +} +.month-picker-next .ui-icon-circle-triangle-e { + display: inline-block; + -webkit-transform: rotate(-90deg); + -moz-transform: rotate(-90deg); + -o-transform: rotate(-90deg); +} +.month-picker-next .ui-icon-circle-triangle-e:before { + font-family: "ingfont"; + content: '\e90b'; +}*/ +.month-picker-year-table .ui-button { + color: #001D68 !important; +} + diff --git a/css/checador.css b/css/checador.css new file mode 100644 index 0000000..e54abd2 --- /dev/null +++ b/css/checador.css @@ -0,0 +1,46 @@ + +body { + font-family: 'indivisa-text'; + /*background-image: linear-gradient(rgba(0,29,104, 0.3), rgba(0,29,104, 0.3)), url('../imagenes/fondochecador.png');*/ + background-image: url('../imagenes/fondochecador.jpg'); + background-repeat: no-repeat; + background-attachment: fixed; + background-size: cover; + background-position: center; + height: 100%; + overflow: hidden; +} + +.hora{font-size: 4rem; border-right: 2px solid #d21034; line-height: 1.1; padding-bottom: 8px;} +.fecha{font-size: 1.9rem; line-height: 1.2em; } +.facultad{font-size: 1.5rem; font-weight: bold; color: #aaa;} +.checa-box{width:800px; min-height: 380px; -webkit-box-shadow: 0px 0px 5px 1px rgba(150,150,150,0.2); -moz-box-shadow: 0px 0px 5px 1px rgba(150,150,150,0.2); box-shadow: 0px 0px 5px 1px rgba(150,150,150,0.2);} + +h1, h2, h3 {letter-spacing: 1px; position: relative; color: #001e61;} +.subtitle:before{ content: ''; position: absolute; bottom: -8px; left: 0; width: 80px; display: block; background: #d21034; height: 3px; } + +.text-big{font-size:3.6rem;} +#list-result{font-size:1.15rem;} +#list-result li{margin:0.2em 0; border-bottom: 1px dashed #969696;} + +.text-clave{ outline: none; color: #b7b7b7 !important; background: transparent; border: 1px solid #dbdcdd; border-radius: 5px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; font-size: 12px; font-weight: 300; vertical-align: middle; text-align:center; padding: 10px 20px;} +.text-clave:focus{ color: #001d68 !important; border-color: #001d68;} +.sin-servicio, .text-clave{font-size:1.7rem;} +.aviso{ font-size:120%;} +.mensaje{ font-size: 7vh; } + +@media (max-width: 768px) { + .hora{ font-size: 3.2rem;} + .fecha{font-size: 1.4rem;} + .checa-box{width:100%;} + .text-big{font-size:3rem;} + .sin-servicio, .text-clave{font-size:1.2rem;} +} +@media (max-width: 576px) { + .hora{font-size: 2rem !important;} + .fecha, .titulo{font-size: 1rem;} + #logo{width: 75%;} + .facultad{font-size: 1.2rem} + .text-big{font-size:2.8rem;} + +} diff --git a/css/cif-icons-20xy.png b/css/cif-icons-20xy.png new file mode 100644 index 0000000..266cf03 Binary files /dev/null and b/css/cif-icons-20xy.png differ diff --git a/css/clockpicker.css b/css/clockpicker.css new file mode 100644 index 0000000..770b173 --- /dev/null +++ b/css/clockpicker.css @@ -0,0 +1,143 @@ +/*! + * ClockPicker v{package.version} for Bootstrap (http://weareoutman.github.io/clockpicker/) + * Copyright 2014 Wang Shenwei. + * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) + */ + +.clockpicker .input-group-addon { + cursor: pointer; +} +.clockpicker-moving { + cursor: move; +} + +.clockpicker-popover .popover-title { + background: #D6D8DB; + color: #777777; + font-size: 1.5rem; + line-height: 2rem; + text-align: center; +} +.clockpicker-popover .popover-title span { + cursor: pointer; +} +.clockpicker-popover .popover-content { + padding: 0.5rem; +} +.popover-content:last-child { + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; +} +.clockpicker-plate { + background-color: #EFEFEF; + border-radius: 50%; + width: 200px; + height: 200px; + overflow: visible; + position: relative; + /* Disable text selection highlighting. Thanks to Hermanya */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.clockpicker-canvas, +.clockpicker-dial { + width: 200px; + height: 200px; + position: absolute; + left: -1px; + top: -1px; +} +.clockpicker-minutes { + visibility: hidden; +} +.clockpicker-tick { + border-radius: 50%; + color: #777777; + line-height: 1.5rem; + text-align: center; + width: 1.5rem; + height: 1.5rem; + position: absolute; + cursor: pointer; +} +.clockpicker-tick.active{ + color: #FFFFFF; +} +.clockpicker-tick:hover { + background-color: #D6D8DB; +} +.clockpicker-button { + background-image: none; + background-color: #fff; + border-width: 1px 0 0; + border-top-left-radius: 0; + border-top-right-radius: 0; + margin: 0; + padding: 10px 0; +} +.clockpicker-button:hover { + background-image: none; + background-color: #ebebeb; +} +.clockpicker-button:focus { + outline: none!important; +} +.clockpicker-dial { + -webkit-transition: -webkit-transform 350ms, opacity 350ms; + -moz-transition: -moz-transform 350ms, opacity 350ms; + -ms-transition: -ms-transform 350ms, opacity 350ms; + -o-transition: -o-transform 350ms, opacity 350ms; + transition: transform 350ms, opacity 350ms; +} +.clockpicker-dial-out { + opacity: 0; +} +.clockpicker-hours.clockpicker-dial-out { + -webkit-transform: scale(1.2, 1.2); + -moz-transform: scale(1.2, 1.2); + -ms-transform: scale(1.2, 1.2); + -o-transform: scale(1.2, 1.2); + transform: scale(1.2, 1.2); +} +.clockpicker-minutes.clockpicker-dial-out { + -webkit-transform: scale(.8, .8); + -moz-transform: scale(.8, .8); + -ms-transform: scale(.8, .8); + -o-transform: scale(.8, .8); + transform: scale(.8, .8); +} +.clockpicker-canvas { + -webkit-transition: opacity 175ms; + -moz-transition: opacity 175ms; + -ms-transition: opacity 175ms; + -o-transition: opacity 175ms; + transition: opacity 175ms; +} +.clockpicker-canvas-out { + opacity: 0.25; +} +.clockpicker-canvas-bearing, +.clockpicker-canvas-fg { + stroke: none; + fill: #006094; +} +.clockpicker-canvas-bg { + stroke: none; + fill: #006094; +} +.clockpicker-canvas-bg-trans { + fill: rgba(0, 96, 148, 0.25); +} +.clockpicker-canvas line { + stroke: #006094; + stroke-width: 1; + stroke-linecap: round; + /*shape-rendering: crispEdges;*/ +} +.clock[readonly]{ + background-color: transparent; +} diff --git a/css/custominputfile.min.css b/css/custominputfile.min.css new file mode 100644 index 0000000..d460119 --- /dev/null +++ b/css/custominputfile.min.css @@ -0,0 +1,10 @@ +/* + jQuery Custom Input File Plugin - version 1.0 + Copyright 2014, Ángel Espro, www.aesolucionesweb.com.ar, + Licence : GNU General Public License + + Site: www.aesolucionesweb.com.ar/plugins/custom-input-file + + You must not remove these lines. Read gpl.txt for further legal information. +*/ +.cif-file-picker{position:relative;width:380px;height:180px;padding:0;border:4px dashed rgba(0,0,0,.2);display:table-cell;vertical-align:middle;text-align:center;opacity:.5;box-sizing:border-box;-moz-box-sizing:border-box}.cif-icon-picker{background:url(cif-icons-20xy.png) 0 0 no-repeat;width:80px;height:60px;display:inline-block}.cif-file-picker h3{margin:0;font-size:20px;text-align:center}.cif-file-picker p{margin:0 0 10px 0;font-size:16px;text-align:center}.cif-file-picker:hover{opacity:1}.cif-file-picker.dragover:not(.inactive){border-color:#46be5e;opacity:1;box-shadow:0 0 50px rgba(0,0,0,.5)}.cif-file-picker.inactive{opacity:.2}.cif-file-picker.inactive.dragover{cursor:pointer}.cif-parent{position:relative;margin-bottom:10px}.foto-file-row .field-wr-int{position:relative}.cif-close{opacity:.5;text-indent:-100000px;width:14px;height:14px;cursor:default;color:#555;background:url(cif-icons-20xy.png) 0px -60px no-repeat}.cif-file-container.cif-type-image .cif-close{top:0px;left:0px;position:absolute}.cif-close:hover{opacity:1}.cif-file-container.cif-container-all-type .cif-file-row{margin:10px 0}.cif-file-container.cif-container-all-type .cif-parent{max-width:380px;box-sizing:border-box;-moz-box-sizing:border-box;padding:10px 10px 10px 30px;border:1px solid #dfdfdf;background:#F4F4F4}.cif-file-container.cif-container-all-type .cif-all-type{font-size:13px;line-height:16px}.cif-file-container.cif-container-all-type .cif-close{top:50%;margin-top:-7px;left:5px;position:absolute}.cif-file-container.cif-container-all-type .cif-file-size{opacity:.8}.cif-file-container.cif-container-image-type .cif-file-row{border-bottom:1px solid #f2f2f2;padding:20px 0}.cif-file-container.cif-container-image-type .cif-parent{padding-top:30px}.cif-file-container.cif-container-image-type .cif-close{top:5px}.cif-img{max-height:300px;max-width:380px}#cif-msg-wr{font-size:13px;position:fixed;z-index:10000;top:100px;right:20px;max-width:50%;padding:15px;background:#fff;border:1px solid #dfdfdf;box-shadow:3px 3px 6px rgba(0,0,0,.5)}#cif-msg-wr .cif-msg-close{opacity:.5;position:absolute;right:0;top:0;width:16px;height:16px;text-indent:-100000px;background:url(cif-icons-20xy.png) 0 -75px no-repeat}#cif-msg-wr .cif-msg-close:hover{opacity:1}.cif-msg-icon{padding:0 10px;font-size:8px}.cif-msg-icon-error{background:url(cif-icons-20xy.png) 0 -120px no-repeat}.cif-msg-icon-ok{background:url(cif-icons-20xy.png) 0 -100px no-repeat}.cf-progressbar-wr{position:fixed;top:0;left:0;background:rgba(0,0,0,.7);width:100%;height:100%;z-index:50000}.cf-progressbar{height:12px;position:absolute;top:50%;margin-top:-6px;left:50%;margin-left:-125px;width:250px;background:#dadada;padding:2px;box-sizing:border-box;border:1px solid #000}.cf-progressbar>span{display:block;height:100%;background:rgb(43,194,83);background-image:url(bg-progress-bar.png);position:relative;transition:width 200ms;overflow:hidden}.jcrop-holder .preview-pane{display:block;position:absolute;z-index:2000;top:00px;left:102%;padding:6px;border:1px rgba(0,0,0,.4) solid;background-color:white;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:1px 1px 5px 2px rgba(0, 0, 0, 0.2);-moz-box-shadow:1px 1px 5px 2px rgba(0, 0, 0, 0.2);box-shadow:1px 1px 5px 2px rgba(0, 0, 0, 0.2)}.preview-pane .preview-container{overflow:hidden} \ No newline at end of file diff --git a/css/fa_all.css b/css/fa_all.css new file mode 100644 index 0000000..a51a10c --- /dev/null +++ b/css/fa_all.css @@ -0,0 +1,5 @@ +/*! + * Font Awesome Free 5.5.0 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,.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{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}: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-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.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-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-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-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-balance-scale:before{content:"\f24e"}.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-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-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.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-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-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.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-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-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-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.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-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.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-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-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-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.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-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-concierge-bell:before{content:"\f562"}.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-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-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-diagnoses:before{content:"\f470"}.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-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-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-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.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-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-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.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-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-git:before{content:"\f1d3"}.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-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.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-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-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.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-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-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-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-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-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.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-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.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-internet-explorer:before{content:"\f26b"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.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-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-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-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-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-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-nintendo-switch:before{content:"\f418"}.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-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-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-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.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-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-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.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-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.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-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-sass:before{content:"\f41e"}.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-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-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.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-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-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowflake:before{content:"\f2dc"}.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-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.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-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-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.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-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-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.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-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.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-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-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-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-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-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-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-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.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;src:url(../fonts/fa/fa-brands-400.eot);src:url(../fonts/fa/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../fonts/fa/fa-brands-400.woff2) format("woff2"),url(../fonts/fa/fa-brands-400.woff) format("woff"),url(../fonts/fa/fa-brands-400.ttf) format("truetype"),url(../fonts/fa/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;src:url(../fonts/fa/fa-regular-400.eot);src:url(../fonts/fa/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../fonts/fa/fa-regular-400.woff2) format("woff2"),url(../fonts/fa/fa-regular-400.woff) format("woff"),url(../fonts/fa/fa-regular-400.ttf) format("truetype"),url(../fonts/fa/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;src:url(../fonts/fa/fa-solid-900.eot);src:url(../fonts/fa/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../fonts/fa/fa-solid-900.woff2) format("woff2"),url(../fonts/fa/fa-solid-900.woff) format("woff"),url(../fonts/fa/fa-solid-900.ttf) format("truetype"),url(../fonts/fa/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/css/images/ui-icons_444444_256x240.png b/css/images/ui-icons_444444_256x240.png new file mode 100644 index 0000000..c2daae1 Binary files /dev/null and b/css/images/ui-icons_444444_256x240.png differ diff --git a/css/images/ui-icons_555555_256x240.png b/css/images/ui-icons_555555_256x240.png new file mode 100644 index 0000000..4784928 Binary files /dev/null and b/css/images/ui-icons_555555_256x240.png differ diff --git a/css/images/ui-icons_777620_256x240.png b/css/images/ui-icons_777620_256x240.png new file mode 100644 index 0000000..d2f58d2 Binary files /dev/null and b/css/images/ui-icons_777620_256x240.png differ diff --git a/css/images/ui-icons_777777_256x240.png b/css/images/ui-icons_777777_256x240.png new file mode 100644 index 0000000..1d53258 Binary files /dev/null and b/css/images/ui-icons_777777_256x240.png differ diff --git a/css/images/ui-icons_cc0000_256x240.png b/css/images/ui-icons_cc0000_256x240.png new file mode 100644 index 0000000..2825f20 Binary files /dev/null and b/css/images/ui-icons_cc0000_256x240.png differ diff --git a/css/images/ui-icons_ffffff_256x240.png b/css/images/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000..136a4f9 Binary files /dev/null and b/css/images/ui-icons_ffffff_256x240.png differ diff --git a/css/index.css b/css/index.css new file mode 100644 index 0000000..6bb8215 --- /dev/null +++ b/css/index.css @@ -0,0 +1,30 @@ +/* +To change this license header, choose License Headers in Project Properties. +To change this template file, choose Tools | Templates +and open the template in the editor. +*/ +/* + Created on : 26/03/2020, 06:44:41 PM + Author : Ale +*/ +.content{height: 700px;background: url('../imagenes/fondochecador.jpg') no-repeat; object-fit: fit;} +.logSize{ width: 50% !important; max-width: 600px; } +.icon{ font-size:2rem; color: #001D68; } +.defaultShadow{ -webkit-box-shadow: 0 0 5px 1px rgba(150,150,150,.2); box-shadow: 0 0 5px 1px rgba(150,150,150,.2); } + +.btn-lg.arrow:after{margin-top:7px !important;} + +@media (max-width: 768px){ + .content{ + height: 400px; + } + .logSize{ + width: 90% !important; + } + .logSize h1{font-size: 2em;} +} +@media (max-height: 768px){ + .content{ + height: 500px; + } +} \ No newline at end of file diff --git a/css/indivisa.css b/css/indivisa.css new file mode 100644 index 0000000..17fd2c9 --- /dev/null +++ b/css/indivisa.css @@ -0,0 +1,268 @@ +/* + Created on : 5/12/2018, 01:25:27 PM + Author : Alejandro + Indivisa Fonts +*/ +@font-face { + font-family: 'indivisa-display-thin'; + src: url('../fonts/indivisaFont/eot/IndivisaDisplaySans-Thin.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaDisplaySans-Thin.woff'), + url('../fonts/indivisaFont/ttf/IndivisaDisplaySans-Thin.ttf') , + url('../fonts/indivisaFont/eot/IndivisaDisplaySans-Thin.svg#IndivisaDisplaySans-Thin'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-display-thin-italic'; + src: url('../fonts/indivisaFont/eot/IndivisaDisplaySans-ThinItalic.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaDisplaySans-ThinItalic.woff'), + url('../fonts/indivisaFont/ttf/IndivisaDisplaySans-ThinItalic.ttf') , + url('../fonts/indivisaFont/eot/IndivisaDisplaySans-ThinItalic.IndivisaDisplaySerif-ThinItalic'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-display'; + src: url('../fonts/indivisaFont/eot/IndivisaDisplaySans-Regular.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaDisplaySans-Regular.woff'), + url('../fonts/indivisaFont/ttf/IndivisaDisplaySans-Regular.ttf') , + url('../fonts/indivisaFont/eot/IndivisaDisplaySans-Regular.svg#IndivisaDisplaySans-Regular'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-display-italic'; + src: url('../fonts/indivisaFont/eot/IndivisaDisplaySans-RegularItalic.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaDisplaySans-RegularItalic.woff'), + url('../fonts/indivisaFont/ttf/IndivisaDisplaySans-RegularItalic.ttf') , + url('../fonts/indivisaFont/eot/IndivisaDisplaySans-RegularItalic.IndivisaDisplaySerif-RegularItalic'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-display-heavy'; + src: url('../fonts/indivisaFont/eot/IndivisaDisplaySans-Heavy.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaDisplaySans-Heavy.woff'), + url('../fonts/indivisaFont/ttf/IndivisaDisplaySans-Heavy.ttf') , + url('../fonts/indivisaFont/eot/IndivisaDisplaySans-Heavy.svg#IndivisaDisplaySans-Heavy'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-display-heavy-italic'; + src: url('../fonts/indivisaFont/eot/IndivisaDisplaySans-HeavyItalic.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaDisplaySans-HeavyItalic.woff'), + url('../fonts/indivisaFont/ttf/IndivisaDisplaySans-HeavyItalic.ttf') , + url('../fonts/indivisaFont/eot/IndivisaDisplaySans-HeavyItalic.IndivisaDisplaySerif-HeavyItalic'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'indivisa-text-light'; + src: url('../fonts/indivisaFont/eot/IndivisaTextSans-Light.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaTextSans-Light.woff'), + url('../fonts/indivisaFont/ttf/IndivisaTextSans-Light.ttf'), + url('../fonts/indivisaFont/eot/IndivisaTextSans-Light.svg#IndivisaTextSans-Light'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-text-light-italic'; + src: url('../fonts/indivisaFont/eot/IndivisaTextSans-LightItalic.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaTextSans-LightItalic.woff'), + url('../fonts/indivisaFont/ttf/IndivisaTextSans-LightItalic.ttf'), + url('../fonts/indivisaFont/eot/IndivisaTextSans-LightItalic.svg#IndivisaTextSans-LightItalic'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-text'; + src: url('../fonts/indivisaFont/eot/IndivisaTextSans-Regular.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaTextSans-Regular.woff'), + url('../fonts/indivisaFont/ttf/IndivisaTextSans-Regular.ttf'), + url('../fonts/indivisaFont/eot/IndivisaTextSans-Regular.svg#IndivisaTextSans-Regular'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-text-italic'; + src: url('../fonts/indivisaFont/eot/IndivisaTextSans-RegularItalic.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaTextSans-RegularItalic.woff'), + url('../fonts/indivisaFont/ttf/IndivisaTextSans-RegularItalic.ttf'), + url('../fonts/indivisaFont/eot/IndivisaTextSans-RegularItalic.svg#IndivisaTextSans-RegularItalic'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-text-bold'; + src: url('../fonts/indivisaFont/eot/IndivisaTextSans-Bold.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaTextSans-Bold.woff'), + url('../fonts/indivisaFont/ttf/IndivisaTextSans-Bold.ttf'), + url('../fonts/indivisaFont/eot/IndivisaTextSans-Bold.svg#IndivisaTextSans-Bold'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-text-bold-italic'; + src: url('../fonts/indivisaFont/eot/IndivisaTextSans-BoldItalic.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaTextSans-BoldItalic.woff'), + url('../fonts/indivisaFont/ttf/IndivisaTextSans-BoldItalic.ttf'), + url('../fonts/indivisaFont/eot/IndivisaTextSans-BoldItalic.svg#IndivisaTextSans-BoldItalic'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-text-black'; + src: url('../fonts/indivisaFont/eot/IndivisaTextSans-Black.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaTextSans-Black.woff'), + url('../fonts/indivisaFont/ttf/IndivisaTextSans-Black.ttf'), + url('../fonts/indivisaFont/eot/IndivisaTextSans-Black.svg#IndivisaTextSans-Black'); + font-weight: normal; + font-style: normal; +} +@font-face { + font-family: 'indivisa-text-black-italic'; + src: url('../fonts/indivisaFont/eot/IndivisaTextSans-BlackItalic.eot'); + src: + url('../fonts/indivisaFont/woff/IndivisaTextSans-BlackItalic.woff'), + url('../fonts/indivisaFont/ttf/IndivisaTextSans-BlackItalic.ttf'), + url('../fonts/indivisaFont/eot/IndivisaTextSans-BlackItalic.svg#IndivisaTextSans-BlackItalic'); + font-weight: normal; + font-style: normal; +} + +.indivisa-display{font-family: 'indivisa-display-thin' !important;} +.indivisa-display-italic{font-family: 'indivisa-display-thin-italic' !important;} +.indivisa-display{font-family: 'indivisa-display' !important;} +.indivisa-display-italic{font-family: 'indivisa-display-italic' !important;} +.indivisa-display-heavy{font-family: 'indivisa-display-heavy' !important;} +.indivisa-display-heavy-italic{font-family: 'indivisa-display-heavy-italic' !important;} + +.indivisa-text-light{font-family: 'indivisa-text-light' !important;} +.indivisa-text-light-italic{font-family: 'indivisa-text-light-italic' !important;} +.indivisa-text{font-family: 'indivisa-text' !important;} +.indivisa-text-italic{font-family: 'indivisa-text-italic' !important;} +.indivisa-text-bold{font-family: 'indivisa-text-bold' !important;} +.indivisa-text-bold-italic{font-family: 'indivisa-text-bold-italic' !important;} +.indivisa-text-black{font-family: 'indivisa-text-black' !important;} +.indivisa-text-black-italic{font-family: 'indivisa-text-black-italic' !important;} + +/* INGENIERIA FONT */ +@font-face { + font-family: 'ingfont'; + src: url('../fonts/ingenieria/ingfont.eot?1fng03'); + src: url('../fonts/ingenieria/ingfont.eot?1fng03#iefix') format('embedded-opentype'), + url('../fonts/ingenieria/ingfont.ttf?1fng03') format('truetype'), + url('../fonts/ingenieria/ingfont.woff?1fng03') format('woff'), + url('../fonts/ingenieria/ingfont.svg?1fng03#ingfont') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +.ing-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.ing-2x{font-size:2em}.ing-3x{font-size:3em}.ing-8x{font-size:8em} +.ing-fw{text-align:center;width:1.4em}/*1.25*/ +.ing-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.ing-ul>li{position:relative}.ing-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit} +.ing-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.ing-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.ing-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.ing-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.ing-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.ing-flip-both,.ing-flip-horizontal.ing-flip-vertical,.ing-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.ing-flip-both,.ing-flip-horizontal.ing-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .ing-flip-both,:root .ing-flip-horizontal,:root .ing-flip-vertical,:root .ing-rotate-90,:root .ing-rotate-180,:root .ing-rotate-270{-webkit-filter:none;filter:none} + +[class^="ing-"], [class*=" ing-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: 'ingfont' !important; speak: never; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; line-height: 1;display: inline-block; + + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.ing-fb1:before {content: "\e932";} +.ing-fb2:before { content: "\e933";} +.ing-tw1:before { content: "\e912";} +.ing-tw2:before { content: "\e900";} +.ing-in1:before { content: "\e91a";} +.ing-in2:before { content: "\e902";} +.ing-instra1:before { content: "\e924";} +.ing-instra2:before { content: "\e923";} +.ing-youtube:before { content: "\e90e";} +.ing-telefono:before { content: "\e911";} +.ing-mail:before { content: "\e907";} +.ing-link:before { content: "\e919";} +.ing-ubicacion:before { content: "\e908";} +.ing-puntos:before { content: "\e917";} +.ing-usuario:before { content: "\e90d";} +.ing-pass:before { content: "\e906";} +.ing-menu:before { content: "\e901";} +.ing-salir:before { content: "\e90f";} +.ing-flecha:before { content: "\e905";} +.ing-cambiar:before { content: "\e93c";} +.ing-caret:before { content: "\e90b";} +.ing-aceptar:before { content: "\e916";} +.ing-cancelar:before { content: "\e910";} +.ing-mas:before { content: "\e91d";} +.ing-menos:before { content: "\e91e";} +.ing-editar:before { content: "\e938";} +.ing-buscar:before { content: "\e939";} +.ing-ojo:before { content: "\e92a";} +.ing-borrar:before { content: "\e942";} +.ing-basura:before { content: "\e941";} +.ing-camara:before { content: "\e909";} +.ing-importante:before { content: "\e935";} +.ing-bullet:before { content: "\e943";} +.ing-home:before { content: "\e934";} +.ing-formacion:before { content: "\e914";} +.ing-empleo:before { content: "\e915";} +.ing-insignia1:before { content: "\e920";} +.ing-insignia2:before { content: "\e91f";} +.ing-insignia3:before { content: "\e921";} +.ing-insignia4:before { content: "\e922";} +.ing-eventos:before { content: "\e90a";} +.ing-reporte:before { content: "\e918";} +.ing-catalogo:before { content: "\e936";} +.ing-evalua-cartel:before { content: "\e913";} +.ing-revision-cartel:before { content: "\e90c";} +.ing-reporte-resultados:before { content: "\e929";} +.ing-mi-cartel:before { content: "\e91b";} +.ing-galeria1:before { content: "\e91c";} +.ing-galeria2:before { content: "\e925";} +.ing-iniciar-sesion:before { content: "\e926";} +.ing-finalistas:before { content: "\e927";} +.ing-comite:before { content: "\e92b";} +.ing-administrador:before { content: "\e92c";} +.ing-estrella1:before { content: "\e903";} +.ing-estrella2:before { content: "\e904";} +.ing-carga-archivo:before { content: "\e93d";} +.ing-carga-multiple:before { content: "\e93e";} +.ing-descarga:before { content: "\e928";} +.ing-autorizar:before { content: "\e92d";} +.ing-negar:before { content: "\e92e";} +.ing-no-cargado:before { content: "\e92f";} +.ing-alumnos:before { content: "\e91c";} +.ing-cardex:before { content: "\e93f";} +.ing-configuracion:before { content: "\e940";} +.ing-listado-menus:before { content: "\e944";} +.ing-mi-cuenta:before { content: "\e945";} +.ing-ver:before { content: "\e946";} +.ing-grafica:before {content: "\e930";} +.ing-clic:before {content: "\e931";} +.ing-guardar:before {content: "\e937";} +.ing-regresar:before {content: "\e93a";} +.ing-cuadrado:before {content: "\e93b";} +.ing-imprimir:before {content: "\e947";} +.ing-importante2:before {content: "\e948";} +.ing-copiar:before {content: "\e949";} +.ing-reloj:before {content: "\e94a";} +.ing-retardo:before {content: "\e94b";} +.ing-justificar:before {content: "\e94c";} \ No newline at end of file diff --git a/css/jquery-ui.css b/css/jquery-ui.css new file mode 100644 index 0000000..776e259 --- /dev/null +++ b/css/jquery-ui.css @@ -0,0 +1,7 @@ +/*! jQuery UI - v1.12.1 - 2016-09-14 +* http://jqueryui.com +* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6 +* Copyright jQuery Foundation and other contributors; Licensed MIT */ + +.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.003;filter:Alpha(Opacity=.3)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666} \ No newline at end of file diff --git a/css/lasalle.css b/css/lasalle.css new file mode 100644 index 0000000..d83ca77 --- /dev/null +++ b/css/lasalle.css @@ -0,0 +1,105 @@ +/* +Iconografía de La Salle +*/ +@font-face { + font-family: 'lasalle'; + src: url("../fonts/lasalle/lasalle.eot"); + src: url("../fonts/lasalle/lasalle.eot?#iefix") format('embedded-opentype'), url("../fonts/lasalle/lasalle.woff") format('woff'), url("../fonts/lasalle/lasalle.ttf") format('truetype'), url("../fonts/lasalle/lasalle.svg#lasalle") format('svg'); + font-weight: normal; + font-style: normal; +} +.icon { + font-family: 'lasalle' !important; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + /*line-height: 1;*/ +/* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.icon-fe:before {content: "\e952";} +.icon-compras:before {content: "\e94d";} +.icon-arte:before {content: "\e94e";} +.icon-restaurante:before {content: "\e94f";} +.icon-cafe:before {content: "\e950";} +.icon-biblioteca:before {content: "\e951";} +.icon-markFull:before {content: "\e94c";} +.icon-comment:before {content: "\e947";} +.icon-faith:before {content: "\e948";} +.icon-justice:before {content: "\e949";} +.icon-compromise:before {content: "\e94a";} +.icon-fraternity:before {content: "\e94b";} +.icon-telephone:before {content: "\e943";} +.icon-onSpeaking:before {content: "\e944";} +.icon-offSpeaking:before { content: "\e945";} +.icon-audio:before {content: "\e946";} +.icon-play:before {content: "\e91c";} +.icon-link:before {content: "\e936";} +.icon-ym:before { content: "\e937";} +.icon-wp:before {content: "\e938";} +.icon-read:before { content: "\e939";} +.icon-certificate:before {content: "\e93a";} +.icon-school:before {content: "\e93b";} +.icon-speaker:before {content: "\e93c";} +.icon-atom:before {content: "\e93d";} +.icon-bag:before {content: "\e93e";} +.icon-carbuy:before {content: "\e93f";} +.icon-idea:before {content: "\e940";} +.icon-hands:before {content: "\e941";} +.icon-arrowprev:before {content: "\e942";} +.icon-mouse:before {content: "\e900";} +.icon-mail:before {content: "\e901";} +.icon-down:before {content: "\e902";} +.icon-up:before {content: "\e903";} +.icon-right:before {content: "\e904";} +.icon-left:before {content: "\e905";} +.icon-headphones:before {content: "\e906";} +.icon-download:before {content: "\e907";} +.icon-chat:before {content: "\e908";} +.icon-books:before {content: "\e909";} +.icon-calculator:before {content: "\e90a";} +.icon-wrong:before {content: "\e90b";} +.icon-conversation:before { content: "\e90c";} +.icon-correct:before {content: "\e90d";} +.icon-error:before {content: "\e90e";} +.icon-interchange:before {content: "\e90f";} +.icon-conectivity:before {content: "\e910";} +.icon-video:before {content: "\e911";} +.icon-desktop:before {content: "\e912";} +.icon-document:before {content: "\e913";} +.icon-stethoscope:before { content: "\e914";} +.icon-student:before {content: "\e915";} +.icon-smartphone:before {content: "\e916";} +.icon-pencil:before {content: "\e917";} +.icon-sitemap:before {content: "\e918";} +.icon-medal:before {content: "\e919";} +.icon-microphone:before {content: "\e91a";} +.icon-wireless:before {content: "\e91b";} +.icon-fountain:before {content: "\e91d";} +.icon-feather:before {content: "\e91e";} +.icon-pen:before {content: "\e91f";} +.icon-pentwo:before {content: "\e920";} +.icon-watercolor:before {content: "\e921";} +.icon-search:before {content: "\e922";} +.icon-security:before {content: "\e923";} +.icon-consult:before {content: "\e924";} +.icon-sound:before {content: "\e925";} +.icon-files:before {content: "\e926";} +.icon-upload:before {content: "\e927";} +.icon-close:before {content: "\e928";} +.icon-arrow:before {content: "\e929";} +.icon-mark:before {content: "\e92a";} +.icon-time:before {content: "\e92b";} +.icon-phone:before {content: "\e92c";} +.icon-share:before {content: "\e92d";} +.icon-seeker:before {content: "\e92e";} +.icon-fb:before {content: "\e92f";} +.icon-tw:before {content: "\e930";} +.icon-yt:before {content: "\e931";} +.icon-ig:before {content: "\e932";} +.icon-in:before {content: "\e933";} +.icon-sc:before {content: "\e934";} +.icon-chk:before {content: "\e935";} \ No newline at end of file diff --git a/css/richtext.css b/css/richtext.css new file mode 100644 index 0000000..e36f6b7 --- /dev/null +++ b/css/richtext.css @@ -0,0 +1,190 @@ +.richText { + position: relative; + border: 1px solid #D6D8D8; + background: #D6D8D8; + width: 100%; + border-radius: 0.25rem; +} + +.richText .richText-toolbar ul { + padding: 0 !important; + margin: 0 !important; + display: flex; + flex-wrap: wrap; + justify-content: left;/*center*/ +} + +.richText .richText-toolbar ul li { + list-style: none; +} + +.richText .richText-toolbar ul li a { + display: block; + padding: 0.25rem 0.5rem; + cursor: pointer; + -webkit-transition: color 0.4s; + -moz-transition: color 0.4s; + transition: color 0.4s; +} + +.richText .richText-toolbar ul li a:hover { + color: #001d68; +} + +.richText .richText-toolbar ul li a .fa, .richText .richText-toolbar ul li a .fas, .richText .richText-toolbar ul li a .far, .richText .richText-toolbar ul li a svg { + pointer-events: none; +} + +.richText .richText-toolbar ul li[data-disable="true"] { + opacity: 0.1; +} + +.richText .richText-toolbar ul li[data-disable="true"] a { + cursor: default; +} + +.richText .richText-toolbar ul li:not([data-disable="true"]).is-selected .richText-dropdown-outer { + display: block; +} + +.richText .richText-toolbar ul:after { + display: block; + content: ""; + clear: both; +} + +.richText .richText-toolbar:last-child { + font-size: 0.75rem; +} + +.richText .richText-toolbar:after { + display: block; + clear: both; + content: ""; +} + +.richText .richText-form select {cursor: pointer;} + +.richText .richText-editor { + padding: 0.5rem; + background-color: #FFFFFF; + height: 15rem; + outline: none; + overflow-y: scroll; + overflow-x: auto; +} + +.richText .richText-toolbar ul li a .richText-dropdown-outer { + display: none; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.3); + cursor: default; +} + +.richText .richText-toolbar ul li a .richText-dropdown-outer .richText-dropdown { + position: relative; + z-index:10; + display: block; + margin: 3% auto 0 auto; + background-color: #D6D8D8; + border: 0.1rem solid #777777; + border-radius: 0.25rem; + padding: 0.75rem; + padding-top: 1.5rem; + max-width: 90%; + -webkit-box-shadow: 0 0 5px 0 #777777; + -moz-box-shadow: 0 0 5px 0 #777777; + box-shadow: 0 0 5px 0 #777777; +} + +.richText .richText-toolbar ul li a .richText-dropdown-outer .richText-dropdown .richText-dropdown-close { + position: absolute; + top: 0.25rem; + right: 0.5rem; + color: #CE0E2D; + cursor: pointer; +} + +.richText .richText-toolbar ul li a .richText-dropdown-outer .richText-dropdown .richText-dropdown-close:hover { + opacity: 0.5 +} + +.richText-form-item{ + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; + width: 100%; +} + +.richText .richText-form label { + display: flex; + align-items: left;/*center*/ + padding: 0.375rem 0.75rem; + margin-bottom: 0; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + font-weight: 600; + text-align: left;/*center*/ + white-space: nowrap; +} + +.richText .richText-form input[type="text"], .richText .richText-form input[type="file"], .richText .richText-form input[type="number"], .richText .richText-form select { + display: block; + height: calc(1.5em + 0.75rem + 2px); + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #777777; + background-color: #FFFFFF; + background-clip: padding-box; + border: 1px solid #D6D8DB; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + position: relative; + flex: 1 1 auto; + width: 1%; + margin-bottom: 0; +} + +.richText .richText-toolbar ul li a .richText-dropdown-outer ul.richText-dropdown {list-style: none;} +.richText .richText-toolbar ul li a .richText-dropdown-outer ul.richText-dropdown li {display: block;float: none;font-family: Calibri,Verdana,Helvetica,sans-serif;} +.richText .richText-toolbar ul li a .richText-dropdown-outer ul.richText-dropdown li a {display: block;padding: 10px 15px;border-bottom: #EFEFEF solid 1px;} +.richText .richText-toolbar ul li a .richText-dropdown-outer ul.richText-dropdown li a:hover {background-color: #FFFFFF;} +.richText .richText-toolbar ul li a .richText-dropdown-outer ul.richText-dropdown li.inline {margin: 10px 6px;float: left;} +.richText .richText-toolbar ul li a .richText-dropdown-outer ul.richText-dropdown li.inline a {display: block;padding: 0;margin: 0;border: none;-webkit-border-radius: 50%;-moz-border-radius: 50%;border-radius: 50%;-webkit-box-shadow: 0 0 10px 0 #999;-moz-box-shadow: 0 0 10px 0 #999;box-shadow: 0 0 10px 0 #999;} +.richText .richText-toolbar ul li a .richText-dropdown-outer ul.richText-dropdown li.inline a span {display: block;height: 30px;width: 30px;-webkit-border-radius: 50%;-moz-border-radius: 50%;border-radius: 50%;} + + +.richText .richText-undo, .richText .richText-redo { + float: left; + display: block; + padding: 0.5rem; + cursor: pointer; +} + +.richText .richText-undo.is-disabled, .richText .richText-redo.is-disabled { + opacity: 0.4; +} + +.richText .richText-help { + display: none; +} + +/* +.richText .richText-initial {margin-bottom: -4px;padding: 10px;background-color: #282828;border: none;color: #33FF33;font-family: Monospace,Calibri,Verdana,Helvetica,sans-serif;max-width: 100%;min-width: 100%;width: 100%;min-height: 400px;height: 400px;} +.richText .richText-editor ul, .richText .richText-editor ol {margin: 10px 25px;} +.richText .richText-editor:focus {border-left: #3498db solid 2px;} +.richText .richText-editor table {margin: 10px 0;border-spacing: 0;width: 100%;} +.richText .richText-editor table td, .richText .richText-editor table th {padding: 10px;border: #EFEFEF solid 1px;} +.richText .richText-help {float: right;display: block;padding: 10px 15px;cursor: pointer;} +.richText .richText-help-popup a {color: #3498db;text-decoration: underline;} +.richText .richText-help-popup hr {margin: 10px auto 5px auto;border: none;border-top: #EFEFEF solid 1px;} +.richText .richText-list.list-rightclick {position: absolute;background-color: #FAFAFA;border-right: #EFEFEF solid 1px;border-bottom: #EFEFEF solid 1px;} +.richText .richText-list.list-rightclick li {padding: 5px 7px;cursor: pointer;list-style: none;}*/ \ No newline at end of file diff --git a/css/sgi.css b/css/sgi.css new file mode 100644 index 0000000..da7b44a --- /dev/null +++ b/css/sgi.css @@ -0,0 +1,1074 @@ +/* + Created on : 5/12/2018, 01:34:49 PM + Author : Alejandro +*/ + +/* General */ +.container-fluid { + padding: 0; +} + +#logo { + max-height: 64px; +} + +body { + font-family: 'indivisa-text', Arial; + font-size: 16px !important; + color: #001D68; + background-color: white; +} + +.bg-head { + background-color: white; +} + +.bg-info { + background-color: #F0F0F0 !important; +} + +.bloque-clase { + box-sizing: border-box; + background-color: #dee2e6; + padding: 10px; + margin-bottom: 10px; + min-height: 100%; + border-collapse: collapse; + border: .2rem solid white !important; +} + +.bloque-clase.conflict { + border: .2rem solid var(--danger) !important; + background-color: #f6cfd6; +} + +.bloque-clase:hover { + background-color: hsl(207, 12%, 85%); +} + +.bloque-clase.conflict:hover { + background-color: hsl(0, 100%, 85%); +} + +/* Make cursor move if draggable */ +.bloque-clase[draggable=true] { + cursor: move; +} + +.bloque-clase.dragging { + opacity: .5; + border: .2rem solid var(--primary) !important; + +} + +.dragging-over { + border: .2rem solid var(--primary) !important; + background-color: #dee2e6; +} + +.menu-flotante { + z-index: 500; + position: absolute; + bottom: 0; + right: 0; + background-color: #fff; + border-radius: 6px 0 0 0; + padding-top: 2px; +} + +/* SOBREESCRIBE BOOTSTRAP */ +.marco { + max-width: 960px; + width: 100%; + margin-left: auto; + margin-right: auto; +} + +.marco-wide { + max-width: 1366px; + width: 100%; + margin-left: auto; + margin-right: auto; +} + +.content { + min-height: 480px; + padding: 1em; +} + +.menu { + max-width: 960px; + width: 100%; + margin-left: auto; + margin-right: auto; + display: flex; + padding: 0 15px; +} + +.menu-list .sistema:not(:last-child):after { + content: "|"; + margin-left: 10px; + margin-right: 10px; +} + +.sistema-active { + color: #d21034 !important; + font-weight: bold; +} + +/*.font-small{font-size:14px;}*/ + +/* Contenidos */ +h1, +h2, +h3 { + letter-spacing: 1px; + position: relative; +} + +h1 { + margin-bottom: 40px; +} + +.subtitle:before { + content: ''; + position: absolute; + bottom: -8px; + left: 0; + width: 80px; + display: block; + background: #d21034; + height: 3px; +} + +.main-title { + font-size: 3.2rem; + margin-bottom: 60px; +} + +/* Otros */ +.alert-heading .ing-caret, +.card-header .ing-caret, +.side-menu .ing-caret { + transition: .3s transform ease-in-out; +} + +.alert-heading .collapsed .ing-caret, +.card-header .collapsed .ing-caret { + transform: rotate(90deg); +} + +#accordionMenu .collapsed .ing-caret { + transform: rotate(-90deg); +} + +.alert-heading .fa, +.card-header .fa { + transition: .3s transform ease-in-out; +} + +.alert-heading .collapsed .fa, +.card-header .collapsed .fa { + transform: rotate(90deg); +} + +#accordionMenu .collapsed .fa { + transform: rotate(-90deg); +} + +.border-mid:not(:last-child) { + border-bottom: 1px dotted #ccc +} + +.pointer { + cursor: pointer; +} + +/* TABLAS */ +.table-white .thead-dark th { + text-align: center; + border-color: #fff; + text-transform: uppercase; +} + +.table-white tr td, +.table-white tr th { + border-left: 1px !important; + border-color: #fff; + border-style: solid; +} + +.table-white tr td:first-child, +.table-white tr th:first-child { + border-left: 0; +} + +.table-nostriped tbody tr:nth-of-type(odd) { + background-color: transparent; +} + +.rotate-text { + writing-mode: vertical-lr; + transform: rotate(180deg); + height: max-content; + height: -moz-max-content; + height: -webkit-max-content; + height: -o-max-content; + height: -ms-max-content; +} + +.icono-acciones span, +.icono-acciones i { + margin: 0 3px; + text-decoration: none !important; +} + +.icono-acciones a:focus, +.icono-acciones a:hover, +.icono-acciones a:active { + text-decoration: none !important; +} + +/* FORMAS */ +.form-box { + margin-bottom: 28px; +} + +.form-box>.form-group { + margin-bottom: 10px +} + +.form-box>.form-group>label { + font-weight: bold; + text-align: right; + color: #001d68; + padding-left: 0 +} + +.form-box>.form-group>label.disabled { + color: #969696; +} + +.form-box>.form-group>label:before { + content: ''; + position: absolute; + top: -8px; + right: 0px; + width: 2px; + height: calc(100% + 16px); + display: block; + background: #d21034; +} + +.form-box>.form-group>label.disabled:before { + background: #969696 !important; +} + +.form-box-info>.form-group>div { + background-color: #f7f7f7; + padding-bottom: 10px; + padding-left: 8px; +} + +.form-box-info>.form-group>div:first-child { + margin-left: 7px; +} + +.form-box-info>.form-group:first-child>label { + padding-top: 27px; +} + +.form-box-info>.form-group:first-child>div { + padding-top: 20px; +} + +.form-box-info>.form-group:last-child>div { + padding-bottom: 20px; +} + +.form-box-info>.form-group.row { + margin-bottom: 0 !important; +} + +.modal .form-box-info>.form-group>div { + margin-left: 0px; +} + +.radio-md { + width: 1em; + height: 1em; +} + +.radio-lg { + width: 1.5em; + height: 1.5em; +} + +.radio-xl { + width: 2em; + height: 2em; +} + +select:disabled { + color: #969696 !important; +} + +.input-info { + color: #969696; +} + +.barra-right:before { + content: ''; + position: absolute; + top: -8px; + right: 0px; + width: 2px; + height: calc(100% + 16px); + display: block; + background: #d21034; +} + +/* Uso independiente */ +.barra-right.disabled:before { + background: #969696 !important; +} + +/* Uso independiente */ + +textarea { + resize: none; + overflow-x: hidden; + overflow-wrap: break-word; + overflow-y: auto; +} + +.clock[readonly] { + background-color: #fff !important; +} + +.hasDatepicker[readonly] { + background-color: #fff !important; +} + +.badge { + padding: 0.5em 1.4em; +} + +.ui-autocomplete { + max-height: 160px; + overflow-y: auto; + overflow-x: hidden; + font-size: 90% +} + +/* Data list*/ +.datalist { + position: relative; + border: 1px solid #969696; + border-radius: .25rem; +} + +.datalist-input { + padding: 6px 30px 6px 12px !important; + background: #FFFFFF !important; + border-radius: .25rem; + cursor: pointer; + border: 0; +} + +.datalist.disabled .datalist-input { + background: #f7f7f7 !important; + cursor: default; + color: #969696; +} + +.datalist.disabled .icono { + opacity: 0; +} + +.datalist .icono { + position: absolute; + font-size: 20px; + right: 10px; + top: 9px; + color: #969696; + transition: transform 0.2s ease; +} + +/*.iconoAzul{color: #001D68 !important;} Usar text-primary*/ +.datalist>ul { + position: absolute; + margin: 0; + padding: 0; + width: 100%; + max-height: 204px; + top: 100%; + left: 0; + list-style: none; + border-radius: 2px; + background: #FFFFFF; + border: 1px solid #001D68; + overflow: hidden; + overflow-y: auto; + z-index: 100; +} + +.datalist>ul li { + display: flex; + align-items: center; + justify-content: start; + padding: 0.3em 1em + /*0.8em 1em 0.8em 1em*/ + ; + color: #969696; +} + +.datalist>ul li:not(.not-selectable):hover { + background: #D21034; + color: #FFFFFF; + cursor: pointer; +} + +.datalist .selected { + background: #D21034; + color: #FFFFFF; +} + +.datalist .not-selectable { + text-align: center; + font-weight: bold; + cursor: default; + color: #001d68; + padding-left: 10px !important; +} + +.datalist-invalid { + border-color: #d21034; +} + +.datalist-invalid .icono { + color: #d21034 !important; +} + +/* Icono alerta */ +.alerta { + color: #ffb700 !important; + text-shadow: -1px -1px 0 #3f2f06, 1px -1px 0 #3f2f06, -1px 1px 0 #3f2f06, 1px 1px 0 #3f2f06; +} + +/* Modal */ +.modal-content { + border: 4px solid #001d68; +} + +.modal-header { + background-color: #001D68 !important; + color: #fff !important; + border-top-left-radius: 0; + border-top-right-radius: 0; + padding: 4px 8px 8px 8px; +} + +.modal-title { + font-weight: normal; + text-align: center; + padding: 0 30px; +} + +.modal-header .close { + position: absolute; + top: 0; + right: 0; +} + +.modal-header .close:focus { + border: none; + outline: none; +} + +/* The side navigation menu */ +#sidebar { + width: 400px; + position: fixed; + top: 0; + right: -400px; + height: 100vh; + z-index: 1023; + transition: all 0.3s; + overflow-y: auto; +} + +#sidebar.active { + right: 0; +} + +.overlay { + display: none; + position: fixed; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.6); + z-index: 1022; + opacity: 0; + transition: all 0.5s ease-in-out; +} + +.overlay.active { + display: block; + opacity: 1; +} + +#sidebar a:hover { + text-decoration: none; + color: #d12034; +} + +#sidebar a { + transition: color 0.6s ease; +} + +/* ICONOS MENU */ +header { + padding: 20px 0; + height: 110px; +} + +header .logotipo { + float: left; + clear: none; + text-align: inherit; + width: 20%; + margin-left: 0; + margin-right: 0; +} + +header .logotipo:before { + content: ''; + display: table; +} + +header .logotipo img, +aside .logotipo img { + max-width: 200px; +} + +.mainMenu { + min-width: 85px; +} + +.menu .nav-item { + border-right: 1px solid #969696; +} + +.menu .nav-item:last-child { + border-right: 0; +} + +.menu .nav-item>a, +.menu .nav-item>span { + color: #969696; + padding: 1px 10px; +} + +.menu .nav-item>a:hover { + color: #D21034; + text-decoration: none; +} + +.menu .nav-item>a { + transition: color 0.6s ease; +} + +.max-h { + height: 45px !important; + max-height: 45px; +} + +.max-w { + width: 45px !important; + max-width: 45px; +} + +.iconSesion { + margin-right: -20px; +} + +.iconLogin, +.iconOff { + font-size: 16px; + display: block; + width: 60px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + border-radius: 30px 0 0 30px; +} + +.iconOff:hover, +.iconOff:active { + text-decoration: none; + background: #D21034; + color: #FFFFFF !important; + height: 40px; +} + +.iconOff { + color: #D21034 !important; +} + +.iconLogin:hover, +.iconLogin:active, +.iconOff:hover, +.iconOff:active { + text-decoration: none; + color: #FFFFFF !important; + height: 40px; +} + +.iconLogin { + color: #339933; +} + +.iconLogin:hover, +.iconLogin:active { + background: #339933; +} + +.iconMenu { + font-size: 32px; +} + +.menuicon:hover { + color: #101097 !important; +} + +.cerraricon { + height: 40px !important; + max-height: 40px; + width: 40px !important; + max-width: 40px; + cursor: pointer; +} + +.cerraricon:hover { + background: #101097 !important; +} + +.fa-ul { + list-style-type: none; + margin-left: 2.5em; + padding-left: 0; +} + +/* BUTTONS */ +/*.btn .fa-circle{color:rgba(255,255,255,0.15);} +.btn .icon{font-weight: bold;} +.btn-round{border-radius:30px; padding-left: 0.5rem!important; padding-right: 0.5rem!important;}*/ + +.btn-ing { + position: relative; + padding-right: 35px; + padding-left: 20px; +} + +.btn.arrow:after { + content: "\e905"; + font-size: 14px; + position: absolute; + font-family: "ingfont"; + right: 14px; + margin-top: 3px; + font-weight: bold; + -webkit-transition: 0.6s all ease; + -moz-transition: 0.6s all ease; + -o-transition: 0.6s all ease; + -ms-transition: 0.6s all ease; + transition: 0.6s all ease; + vertical-align: middle; +} + +.btn-outline-secondary { + border: 0; +} + +/* SOBREESCRIBE BOOTSTRAP */ +.btn-outline-primary.arrow:after { + color: #D21034; +} + +.btn-outline-danger.arrow:after { + color: #001D68; +} + +.btn-outline-secondary:hover.arrow:after { + color: #D21034; +} + +.btn-outline-info:hover.arrow:after { + color: #001D68; +} + +/***** SCROLLBAR *****/ +div ::-webkit-scrollbar { + width: 8px; +} + +/*Ancho*/ +div ::-webkit-scrollbar-track { + background: #f7f7f7; +} + +/*Riel*/ +div ::-webkit-scrollbar-thumb { + background: #969696; +} + +/* Handle */ +div ::-webkit-scrollbar-thumb:hover { + background: #001d68; +} + +/* Effects */ +/* Vars for primary, secondary, success, info, warning, danger, light, dark */ + +:root { + --primary-color: #001d68; + --secondary-color: #001d68; + --success-color: #339933; + --danger-color: #d21034; + --warning-color: #ffc107; + --info-color: #969696; + --light-color: #f7f7f7; + --dark-color: #343a40; +} + +.glow-primary { + background: var(--primary-color); + color: #fff; + border-radius: 5px; + padding: 5px; + box-shadow: 0 0 5px var(--primary-color); + transition: all 0.5s ease; +} + +.glow-secondary { + background: var(--secondary-color); + color: #fff; + border-radius: 5px; + padding: 5px; + box-shadow: 0 0 5px var(--secondary-color); + transition: all 0.5s ease; +} + +.glow-success { + background: var(--success-color); + color: #fff; + border-radius: 5px; + padding: 5px; + box-shadow: 0 0 5px var(--success-color); + transition: all 0.5s ease; +} + +.glow-danger { + background: var(--danger-color); + color: #fff; + border-radius: 5px; + padding: 5px; + box-shadow: 0 0 5px var(--danger-color); + transition: all 0.5s ease; +} + +.glow-warning { + background: var(--warning-color); + color: #fff; + border-radius: 5px; + padding: 5px; + box-shadow: 0 0 5px var(--warning-color); + transition: all 0.5s ease; +} + +.glow-info { + background: var(--info-color); + color: #fff; + border-radius: 5px; + padding: 5px; + box-shadow: 0 0 5px var(--info-color); + transition: all 0.5s ease; +} + +.glow-light { + background: var(--light-color); + color: #fff; + border-radius: 5px; + padding: 5px; + box-shadow: 0 0 5px var(--light-color); + transition: all 0.5s ease; +} + +.glow-dark { + background: var(--dark-color); + color: #fff; + border-radius: 5px; + padding: 5px; + box-shadow: 0 0 5px var(--dark-color); + transition: all 0.5s ease; +} + +/*Hover Handle */ + +/***** FOOTER *****/ +footer { + font-size: 14px; + color: #fff; +} + +footer .footerTop { + background: #001d68; + padding: 15px 0; +} + +footer .footerTop .logotipo { + overflow: hidden; +} + +footer .footerTop .logotipo h3 { + display: inline-block; + vertical-align: top; + color: #fff; + margin: 0; + float: right; + text-align: right; + font-size: 25px; + font-family: 'indivisa-text' +} + +footer .footerTop .logotipo h3 span { + display: block; +} + +footer .footerTop .menuFooter h3 { + font-size: 12px; + font-family: 'indivisa-text'; + color: #fff !important; +} + +footer .footerTop .menuFooter ul { + overflow: hidden; +} + +footer ul { + list-style: none; + padding: 0; + margin: 0; +} + +footer .footerTop .menuFooter ul>li { + *zoom: 1; + float: left; + clear: none; + text-align: inherit; + width: 16%; + margin-left: 0; + margin-right: 3%; +} + +footer .footerTop .menuFooter ul>li ul li a { + font-size: 10px; +} + +footer ul>li { + display: inline-block; + vertical-align: top; +} + +.footerMore { + position: relative; + display: none; + padding: 5px 0; +} + +footer a { + color: #fff; + -webkit-transition: color 0.5s; + transition: color 0.5s; +} + +footer a:hover { + color: #ce0e2d !important; + text-decoration: none !important; +} + +footer .footerTop .menuFooter ul>li ul li { + display: block; + width: 100%; + margin-bottom: 0px; +} + +footer .ubicacion { + margin-top: 20px; + overflow: hidden; +} + +footer .ubicacion .address { + display: inline-block; + /*width: 65%;*/ + vertical-align: bottom; +} + +footer .ubicacion .address h4, +footer .ubicacion .address h4 a { + color: #0fb7f1; + font-size: 14px; + margin: 0 0 0 -5px; + position: relative; +} + +footer .ubicacion .address h4 a { + display: inline-block; +} + +footer .ubicacion .redes { + display: inline-block; + vertical-align: bottom; + /*width:32%;text-align:right*/ +} + +footer .ubicacion .redes h4 { + display: inline-block; + vertical-align: middle; + margin: 0; + font-size: 16px !important; + font-weight: bold; +} + +footer .ubicacion .redes ul { + display: inline-block; + vertical-align: middle +} + +footer .ubicacion .redes ul li { + margin-left: 2px +} + +footer .footerMiddle { + background: #071e58; + overflow: hidden; +} + +footer .footerMiddle nav ul { + text-align: center; +} + +footer .footerMiddle nav ul li { + border-right: 1px solid #fff; + padding: 1px 10px; + display: inline-block; + margin-bottom: 10px; +} + +footer ul>li { + display: inline-block; + vertical-align: top; +} + +footer .footerBottom { + background: #091941; + overflow: hidden; + padding: 15px 0; +} + +.footerBottom .logotipos { + display: inline-block; + vertical-align: middle; + width: 20% +} + +footer .footerBottom .logotipos a { + display: inline-block; + width: 80px; + margin-right: 6px +} + +footer .footerBottom .logotipos a.internacional { + width: 80px +} + +footer .footerBottom .logotipos a.red { + width: 75px +} + +footer .footerBottom .legales { + text-align: right; + float: right; + width: 60%; + margin-right: 0; + margin-left: auto; + padding-top: 10px; + padding-bottom: 0 +} + +footer .footerBottom .legales ul li { + border-right: 1px solid #fff; + padding: 1px 10px +} + +footer .footerBottom .legales ul li:last-child { + border: 0 +} + +footer .tab-pane p { + font-size: 12px; + line-height: 18px; +} + +@media (max-width: 800px) { + + .menu, + .subMenu { + position: relative; + } + + .iconoMenu { + position: absolute; + display: block; + right: 20px; + top: 10px; + } + + .menuOculto { + display: none; + } + + .form-box-info>.form-group>div { + margin-left: 0px; + } + + /* + .responsive{ + float: none; + text-align: center; + display: flex; + flex-direction: column; + flex-wrap: wrap; + justify-content: center; + align-items: center; + }*/ +} + +.movie { + transition: all 0.1s; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.movie:hover { + transform: scale(1.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + font-size: 1.1em; +} + +.movie:active { + transform: scale(1.1); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2); + font-size: 1.2em; + font-weight: bold; +} \ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..2e6b8d8 --- /dev/null +++ b/css/style.css @@ -0,0 +1,99 @@ +.bg-azul { + background-color: #00a6CE; +} + +.azul { + color: #00a6CE; +} + +/* for sm */ + +.custom-switch.custom-switch-sm .custom-control-label { + padding-left: 1rem; + padding-bottom: 1rem; +} + +.custom-switch.custom-switch-sm .custom-control-label::before { + height: 1rem; + width: calc(1rem + 0.75rem); + border-radius: 2rem; +} + +.custom-switch.custom-switch-sm .custom-control-label::after { + width: calc(1rem - 4px); + height: calc(1rem - 4px); + border-radius: calc(1rem - (1rem / 2)); +} + +.custom-switch.custom-switch-sm .custom-control-input:checked ~ .custom-control-label::after { + transform: translateX(calc(1rem - 0.25rem)); +} + +/* for md */ + +.custom-switch.custom-switch-md .custom-control-label { + padding-left: 2rem; + padding-bottom: 1.5rem; +} + +.custom-switch.custom-switch-md .custom-control-label::before { + height: 1.5rem; + width: calc(2rem + 0.75rem); + border-radius: 3rem; +} + +.custom-switch.custom-switch-md .custom-control-label::after { + width: calc(1.5rem - 4px); + height: calc(1.5rem - 4px); + border-radius: calc(2rem - (1.5rem / 2)); +} + +.custom-switch.custom-switch-md .custom-control-input:checked ~ .custom-control-label::after { + transform: translateX(calc(1.5rem - 0.25rem)); +} + +/* for lg */ + +.custom-switch.custom-switch-lg .custom-control-label { + padding-left: 3rem; + padding-bottom: 2rem; +} + +.custom-switch.custom-switch-lg .custom-control-label::before { + height: 2rem; + width: calc(3rem + 0.75rem); + border-radius: 4rem; +} + +.custom-switch.custom-switch-lg .custom-control-label::after { + width: calc(2rem - 4px); + height: calc(2rem - 4px); + border-radius: calc(3rem - (2rem / 2)); +} + +.custom-switch.custom-switch-lg .custom-control-input:checked ~ .custom-control-label::after { + transform: translateX(calc(2rem - 0.25rem)); +} + +/* for xl */ + +.custom-switch.custom-switch-xl .custom-control-label { + padding-left: 4rem; + padding-bottom: 2.5rem; +} + +.custom-switch.custom-switch-xl .custom-control-label::before { + height: 2.5rem; + width: calc(4rem + 0.75rem); + border-radius: 5rem; +} + +.custom-switch.custom-switch-xl .custom-control-label::after { + width: calc(2.5rem - 4px); + height: calc(2.5rem - 4px); + border-radius: calc(4rem - (2.5rem / 2)); +} + +.custom-switch.custom-switch-xl .custom-control-input:checked ~ .custom-control-label::after { + transform: translateX(calc(2.5rem - 0.25rem)); +} \ No newline at end of file diff --git a/css/toggle.css b/css/toggle.css new file mode 100644 index 0000000..4903b1e --- /dev/null +++ b/css/toggle.css @@ -0,0 +1,142 @@ +/*\ +|*| ======================================================================== +|*| Bootstrap Toggle: bootstrap4-toggle.css v3.6.1 +|*| https://gitbrent.github.io/bootstrap4-toggle/ +|*| ======================================================================== +|*| Copyright 2018-2019 Brent Ely +|*| Licensed under MIT +|*| ======================================================================== +\*/ + +/* +* @added 3.0.0: Return support for "*-xs" removed in Bootstrap-4 +* @see: [Comment](https://github.com/twbs/bootstrap/issues/21881#issuecomment-341972830) +*/ +.btn-group-xs > .btn, .btn-xs { + padding: .35rem .4rem .25rem .4rem; + font-size: .875rem; + line-height: .5; + border-radius: 20rem; +} + +.checkbox label .toggle, .checkbox-inline .toggle { + margin-left: -1.25rem; + margin-right: .35rem; +} + +.toggle { + position: relative; + overflow: hidden; +} +.toggle.btn.btn-light, .toggle.btn.btn-outline-light { + /* bootstrap-4 - add a border so toggle is delineated */ + border-color: rgba(0, 0, 0, .15); +} +.toggle input[type="checkbox"] { + display: none; +} +.toggle-group { + position: absolute; + width: 200%; + top: 0; + bottom: 0; + left: 0; + transition: left 0.35s; + -webkit-transition: left 0.35s; + -moz-user-select: none; + -webkit-user-select: none; +} +.toggle-group label, .toggle-group span { cursor: pointer; } +.toggle.off .toggle-group { + left: -100%; +} +.toggle-on { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 50%; + margin: 0; + border: 0; + border-radius: 20rem; +} +.toggle-off { + position: absolute; + top: 0; + bottom: 0; + left: 50%; + right: 0; + margin: 0; + border: 0; + border-radius: 20rem; + box-shadow: none; /* Bootstrap 4.0 Support via (Issue #186)[https://github.com/minhur/bootstrap-toggle/issues/186]) */ +} +.toggle-handle { + position: relative; + margin: 0 auto; + padding-top: 0px; + padding-bottom: 0px; + height: 100%; + width: 0px; + border-width: 0 1px; + background-color: #FFFFFF; +} + +.toggle.btn-outline-primary .toggle-handle { + background-color: var(--primary); + border-color: var(--primary); +} +.toggle.btn-outline-secondary .toggle-handle { + background-color: var(--secondary); + border-color: var(--secondary); +} +.toggle.btn-outline-success .toggle-handle { + background-color: var(--success); + border-color: var(--success); +} +.toggle.btn-outline-danger .toggle-handle { + background-color: var(--danger); + border-color: var(--danger); +} +.toggle.btn-outline-warning .toggle-handle { + background-color: var(--warning); + border-color: var(--warning); +} +.toggle.btn-outline-info .toggle-handle { + background-color: var(--info); + border-color: var(--info); +} +.toggle.btn-outline-light .toggle-handle { + background-color: var(--light); + border-color: var(--light); +} +.toggle.btn-outline-dark .toggle-handle { + background-color: var(--dark); + border-color: var(--dark); +} +.toggle[class*="btn-outline"]:hover .toggle-handle { + background-color: var(--light); + opacity: 0.5; +} + +/* NOTE: Must come first, so classes below override as needed */ +/* [default] (bootstrap-4.1.3 - .btn - h:38px) */ +.toggle.btn { min-width: 3.7rem; min-height: 2.15rem; } +.toggle-on.btn { padding-right: 1.5rem; } +.toggle-off.btn { padding-left: 1.5rem; } + +/* `lg` (bootstrap-4.1.3 - .btn - h:48px) */ +.toggle.btn-lg { min-width: 5rem; min-height: 2.815rem; } +.toggle-on.btn-lg { padding-right: 2rem; } +.toggle-off.btn-lg { padding-left: 2rem; } +.toggle-handle.btn-lg { width: 2.5rem; } + +/* `sm` (bootstrap-4.1.3 - .btn - h:31px) */ +.toggle.btn-sm { min-width: 3.125rem; min-height: 1.938rem; } +.toggle-on.btn-sm { padding-right: 1rem; } +.toggle-off.btn-sm { padding-left: 1rem; } + +/* `xs` (bootstrap-3.3 - .btn - h:22px) */ +.toggle.btn-xs { min-width: 2.19rem; min-height: 1.375rem; } +.toggle-on.btn-xs { padding-right: .8rem; } +.toggle-off.btn-xs { padding-left: .8rem; } diff --git a/fonts/fa/fa-brands-400.eot b/fonts/fa/fa-brands-400.eot new file mode 100644 index 0000000..1a675a4 Binary files /dev/null and b/fonts/fa/fa-brands-400.eot differ diff --git a/fonts/fa/fa-brands-400.svg b/fonts/fa/fa-brands-400.svg new file mode 100644 index 0000000..5b60e84 --- /dev/null +++ b/fonts/fa/fa-brands-400.svg @@ -0,0 +1,1184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/fa/fa-brands-400.ttf b/fonts/fa/fa-brands-400.ttf new file mode 100644 index 0000000..953d567 Binary files /dev/null and b/fonts/fa/fa-brands-400.ttf differ diff --git a/fonts/fa/fa-brands-400.woff b/fonts/fa/fa-brands-400.woff new file mode 100644 index 0000000..1ae5263 Binary files /dev/null and b/fonts/fa/fa-brands-400.woff differ diff --git a/fonts/fa/fa-brands-400.woff2 b/fonts/fa/fa-brands-400.woff2 new file mode 100644 index 0000000..4a07e40 Binary files /dev/null and b/fonts/fa/fa-brands-400.woff2 differ diff --git a/fonts/fa/fa-regular-400.eot b/fonts/fa/fa-regular-400.eot new file mode 100644 index 0000000..db3ed40 Binary files /dev/null and b/fonts/fa/fa-regular-400.eot differ diff --git a/fonts/fa/fa-regular-400.svg b/fonts/fa/fa-regular-400.svg new file mode 100644 index 0000000..cf3d065 --- /dev/null +++ b/fonts/fa/fa-regular-400.svg @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/fa/fa-regular-400.ttf b/fonts/fa/fa-regular-400.ttf new file mode 100644 index 0000000..235101c Binary files /dev/null and b/fonts/fa/fa-regular-400.ttf differ diff --git a/fonts/fa/fa-regular-400.woff b/fonts/fa/fa-regular-400.woff new file mode 100644 index 0000000..9058e29 Binary files /dev/null and b/fonts/fa/fa-regular-400.woff differ diff --git a/fonts/fa/fa-regular-400.woff2 b/fonts/fa/fa-regular-400.woff2 new file mode 100644 index 0000000..1489f64 Binary files /dev/null and b/fonts/fa/fa-regular-400.woff2 differ diff --git a/fonts/fa/fa-solid-900.eot b/fonts/fa/fa-solid-900.eot new file mode 100644 index 0000000..cb8d3f0 Binary files /dev/null and b/fonts/fa/fa-solid-900.eot differ diff --git a/fonts/fa/fa-solid-900.svg b/fonts/fa/fa-solid-900.svg new file mode 100644 index 0000000..bd7565a --- /dev/null +++ b/fonts/fa/fa-solid-900.svg @@ -0,0 +1,2618 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/fa/fa-solid-900.ttf b/fonts/fa/fa-solid-900.ttf new file mode 100644 index 0000000..7c92e98 Binary files /dev/null and b/fonts/fa/fa-solid-900.ttf differ diff --git a/fonts/fa/fa-solid-900.woff b/fonts/fa/fa-solid-900.woff new file mode 100644 index 0000000..b7d52cf Binary files /dev/null and b/fonts/fa/fa-solid-900.woff differ diff --git a/fonts/fa/fa-solid-900.woff2 b/fonts/fa/fa-solid-900.woff2 new file mode 100644 index 0000000..59d92b2 Binary files /dev/null and b/fonts/fa/fa-solid-900.woff2 differ diff --git a/fonts/indivisaFont/eot/IndivisaDisplaySans-Heavy.eot b/fonts/indivisaFont/eot/IndivisaDisplaySans-Heavy.eot new file mode 100644 index 0000000..e9fb0d6 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaDisplaySans-Heavy.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaDisplaySans-HeavyItalic.eot b/fonts/indivisaFont/eot/IndivisaDisplaySans-HeavyItalic.eot new file mode 100644 index 0000000..5344e24 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaDisplaySans-HeavyItalic.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaDisplaySans-Regular.eot b/fonts/indivisaFont/eot/IndivisaDisplaySans-Regular.eot new file mode 100644 index 0000000..c5c14b1 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaDisplaySans-Regular.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaDisplaySans-RegularItalic.eot b/fonts/indivisaFont/eot/IndivisaDisplaySans-RegularItalic.eot new file mode 100644 index 0000000..8755a37 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaDisplaySans-RegularItalic.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaDisplaySans-Thin.eot b/fonts/indivisaFont/eot/IndivisaDisplaySans-Thin.eot new file mode 100644 index 0000000..ca72a51 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaDisplaySans-Thin.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaDisplaySans-ThinItalic.eot b/fonts/indivisaFont/eot/IndivisaDisplaySans-ThinItalic.eot new file mode 100644 index 0000000..4c773a5 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaDisplaySans-ThinItalic.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaDisplaySerif-RegularItalic.eot b/fonts/indivisaFont/eot/IndivisaDisplaySerif-RegularItalic.eot new file mode 100644 index 0000000..4f9b387 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaDisplaySerif-RegularItalic.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaTextSans-Black.eot b/fonts/indivisaFont/eot/IndivisaTextSans-Black.eot new file mode 100644 index 0000000..ed52eda Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaTextSans-Black.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaTextSans-BlackItalic.eot b/fonts/indivisaFont/eot/IndivisaTextSans-BlackItalic.eot new file mode 100644 index 0000000..6914b78 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaTextSans-BlackItalic.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaTextSans-Bold.eot b/fonts/indivisaFont/eot/IndivisaTextSans-Bold.eot new file mode 100644 index 0000000..d2ebd37 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaTextSans-Bold.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaTextSans-BoldItalic.eot b/fonts/indivisaFont/eot/IndivisaTextSans-BoldItalic.eot new file mode 100644 index 0000000..f4a9e8d Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaTextSans-BoldItalic.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaTextSans-Light.eot b/fonts/indivisaFont/eot/IndivisaTextSans-Light.eot new file mode 100644 index 0000000..59a17dd Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaTextSans-Light.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaTextSans-LightItalic.eot b/fonts/indivisaFont/eot/IndivisaTextSans-LightItalic.eot new file mode 100644 index 0000000..f1796b5 Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaTextSans-LightItalic.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaTextSans-Regular.eot b/fonts/indivisaFont/eot/IndivisaTextSans-Regular.eot new file mode 100644 index 0000000..776179c Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaTextSans-Regular.eot differ diff --git a/fonts/indivisaFont/eot/IndivisaTextSans-RegularItalic.eot b/fonts/indivisaFont/eot/IndivisaTextSans-RegularItalic.eot new file mode 100644 index 0000000..4988d7d Binary files /dev/null and b/fonts/indivisaFont/eot/IndivisaTextSans-RegularItalic.eot differ diff --git a/fonts/indivisaFont/otf/IndivisaDisplaySans-Heavy.otf b/fonts/indivisaFont/otf/IndivisaDisplaySans-Heavy.otf new file mode 100644 index 0000000..32689f2 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaDisplaySans-Heavy.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaDisplaySans-HeavyItalic.otf b/fonts/indivisaFont/otf/IndivisaDisplaySans-HeavyItalic.otf new file mode 100644 index 0000000..290805f Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaDisplaySans-HeavyItalic.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaDisplaySans-Regular.otf b/fonts/indivisaFont/otf/IndivisaDisplaySans-Regular.otf new file mode 100644 index 0000000..05c49b3 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaDisplaySans-Regular.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaDisplaySans-RegularItalic.otf b/fonts/indivisaFont/otf/IndivisaDisplaySans-RegularItalic.otf new file mode 100644 index 0000000..8fef433 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaDisplaySans-RegularItalic.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaDisplaySans-Thin.otf b/fonts/indivisaFont/otf/IndivisaDisplaySans-Thin.otf new file mode 100644 index 0000000..df2f259 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaDisplaySans-Thin.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaDisplaySans-ThinItalic.otf b/fonts/indivisaFont/otf/IndivisaDisplaySans-ThinItalic.otf new file mode 100644 index 0000000..2c28808 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaDisplaySans-ThinItalic.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaDisplaySerif-RegularItalic.otf b/fonts/indivisaFont/otf/IndivisaDisplaySerif-RegularItalic.otf new file mode 100644 index 0000000..a3c1444 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaDisplaySerif-RegularItalic.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaTextSans-Black.otf b/fonts/indivisaFont/otf/IndivisaTextSans-Black.otf new file mode 100644 index 0000000..6c09100 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaTextSans-Black.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaTextSans-BlackItalic.otf b/fonts/indivisaFont/otf/IndivisaTextSans-BlackItalic.otf new file mode 100644 index 0000000..a613d2a Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaTextSans-BlackItalic.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaTextSans-Bold.otf b/fonts/indivisaFont/otf/IndivisaTextSans-Bold.otf new file mode 100644 index 0000000..a49f975 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaTextSans-Bold.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaTextSans-BoldItalic.otf b/fonts/indivisaFont/otf/IndivisaTextSans-BoldItalic.otf new file mode 100644 index 0000000..abf2f52 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaTextSans-BoldItalic.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaTextSans-Light.otf b/fonts/indivisaFont/otf/IndivisaTextSans-Light.otf new file mode 100644 index 0000000..a3883e8 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaTextSans-Light.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaTextSans-LightItalic.otf b/fonts/indivisaFont/otf/IndivisaTextSans-LightItalic.otf new file mode 100644 index 0000000..53a50d0 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaTextSans-LightItalic.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaTextSans-Regular.otf b/fonts/indivisaFont/otf/IndivisaTextSans-Regular.otf new file mode 100644 index 0000000..0a38187 Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaTextSans-Regular.otf differ diff --git a/fonts/indivisaFont/otf/IndivisaTextSans-RegularItalic.otf b/fonts/indivisaFont/otf/IndivisaTextSans-RegularItalic.otf new file mode 100644 index 0000000..05401bd Binary files /dev/null and b/fonts/indivisaFont/otf/IndivisaTextSans-RegularItalic.otf differ diff --git a/fonts/indivisaFont/svg/IndivisaDisplaySans-Heavy.svg b/fonts/indivisaFont/svg/IndivisaDisplaySans-Heavy.svg new file mode 100644 index 0000000..fc6a4d0 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaDisplaySans-Heavy.svg @@ -0,0 +1,2513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaDisplaySans-HeavyItalic.svg b/fonts/indivisaFont/svg/IndivisaDisplaySans-HeavyItalic.svg new file mode 100644 index 0000000..bf2afce --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaDisplaySans-HeavyItalic.svg @@ -0,0 +1,1383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaDisplaySans-Regular.svg b/fonts/indivisaFont/svg/IndivisaDisplaySans-Regular.svg new file mode 100644 index 0000000..b5976f6 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaDisplaySans-Regular.svg @@ -0,0 +1,2729 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaDisplaySans-RegularItalic.svg b/fonts/indivisaFont/svg/IndivisaDisplaySans-RegularItalic.svg new file mode 100644 index 0000000..69801f8 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaDisplaySans-RegularItalic.svg @@ -0,0 +1,1600 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaDisplaySans-Thin.svg b/fonts/indivisaFont/svg/IndivisaDisplaySans-Thin.svg new file mode 100644 index 0000000..1b84198 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaDisplaySans-Thin.svg @@ -0,0 +1,2587 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaDisplaySans-ThinItalic.svg b/fonts/indivisaFont/svg/IndivisaDisplaySans-ThinItalic.svg new file mode 100644 index 0000000..5a0e716 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaDisplaySans-ThinItalic.svg @@ -0,0 +1,1218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaDisplaySerif-RegularItalic.svg b/fonts/indivisaFont/svg/IndivisaDisplaySerif-RegularItalic.svg new file mode 100644 index 0000000..f91cd03 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaDisplaySerif-RegularItalic.svg @@ -0,0 +1,2800 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaTextSans-Black.svg b/fonts/indivisaFont/svg/IndivisaTextSans-Black.svg new file mode 100644 index 0000000..9ed629a --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaTextSans-Black.svg @@ -0,0 +1,5250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaTextSans-BlackItalic.svg b/fonts/indivisaFont/svg/IndivisaTextSans-BlackItalic.svg new file mode 100644 index 0000000..fc0dbfc --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaTextSans-BlackItalic.svg @@ -0,0 +1,3473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaTextSans-Bold.svg b/fonts/indivisaFont/svg/IndivisaTextSans-Bold.svg new file mode 100644 index 0000000..1e836fc --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaTextSans-Bold.svg @@ -0,0 +1,7617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaTextSans-BoldItalic.svg b/fonts/indivisaFont/svg/IndivisaTextSans-BoldItalic.svg new file mode 100644 index 0000000..a7e4d87 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaTextSans-BoldItalic.svg @@ -0,0 +1,4309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaTextSans-Light.svg b/fonts/indivisaFont/svg/IndivisaTextSans-Light.svg new file mode 100644 index 0000000..cb96651 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaTextSans-Light.svg @@ -0,0 +1,5507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaTextSans-LightItalic.svg b/fonts/indivisaFont/svg/IndivisaTextSans-LightItalic.svg new file mode 100644 index 0000000..0dfdce6 --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaTextSans-LightItalic.svg @@ -0,0 +1,3741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaTextSans-Regular.svg b/fonts/indivisaFont/svg/IndivisaTextSans-Regular.svg new file mode 100644 index 0000000..b13b57e --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaTextSans-Regular.svg @@ -0,0 +1,7590 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/svg/IndivisaTextSans-RegularItalic.svg b/fonts/indivisaFont/svg/IndivisaTextSans-RegularItalic.svg new file mode 100644 index 0000000..f6f346a --- /dev/null +++ b/fonts/indivisaFont/svg/IndivisaTextSans-RegularItalic.svg @@ -0,0 +1,4309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/indivisaFont/ttf/IndivisaDisplaySans-Heavy.ttf b/fonts/indivisaFont/ttf/IndivisaDisplaySans-Heavy.ttf new file mode 100644 index 0000000..03d0f1c Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaDisplaySans-Heavy.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaDisplaySans-HeavyItalic.ttf b/fonts/indivisaFont/ttf/IndivisaDisplaySans-HeavyItalic.ttf new file mode 100644 index 0000000..3193d1d Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaDisplaySans-HeavyItalic.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaDisplaySans-Regular.ttf b/fonts/indivisaFont/ttf/IndivisaDisplaySans-Regular.ttf new file mode 100644 index 0000000..ea8f388 Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaDisplaySans-Regular.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaDisplaySans-RegularItalic.ttf b/fonts/indivisaFont/ttf/IndivisaDisplaySans-RegularItalic.ttf new file mode 100644 index 0000000..4ca582b Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaDisplaySans-RegularItalic.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaDisplaySans-Thin.ttf b/fonts/indivisaFont/ttf/IndivisaDisplaySans-Thin.ttf new file mode 100644 index 0000000..289be9a Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaDisplaySans-Thin.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaDisplaySans-ThinItalic.ttf b/fonts/indivisaFont/ttf/IndivisaDisplaySans-ThinItalic.ttf new file mode 100644 index 0000000..1701d47 Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaDisplaySans-ThinItalic.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaDisplaySerif-RegularItalic.ttf b/fonts/indivisaFont/ttf/IndivisaDisplaySerif-RegularItalic.ttf new file mode 100644 index 0000000..2acfe1c Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaDisplaySerif-RegularItalic.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaTextSans-Black.ttf b/fonts/indivisaFont/ttf/IndivisaTextSans-Black.ttf new file mode 100644 index 0000000..fe5db7c Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaTextSans-Black.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaTextSans-BlackItalic.ttf b/fonts/indivisaFont/ttf/IndivisaTextSans-BlackItalic.ttf new file mode 100644 index 0000000..14a8d67 Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaTextSans-BlackItalic.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaTextSans-Bold.ttf b/fonts/indivisaFont/ttf/IndivisaTextSans-Bold.ttf new file mode 100644 index 0000000..e153eff Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaTextSans-Bold.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaTextSans-BoldItalic.ttf b/fonts/indivisaFont/ttf/IndivisaTextSans-BoldItalic.ttf new file mode 100644 index 0000000..48d495c Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaTextSans-BoldItalic.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaTextSans-Light.ttf b/fonts/indivisaFont/ttf/IndivisaTextSans-Light.ttf new file mode 100644 index 0000000..416e82f Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaTextSans-Light.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaTextSans-LightItalic.ttf b/fonts/indivisaFont/ttf/IndivisaTextSans-LightItalic.ttf new file mode 100644 index 0000000..67aa86c Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaTextSans-LightItalic.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaTextSans-Regular.ttf b/fonts/indivisaFont/ttf/IndivisaTextSans-Regular.ttf new file mode 100644 index 0000000..0b54e79 Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaTextSans-Regular.ttf differ diff --git a/fonts/indivisaFont/ttf/IndivisaTextSans-RegularItalic.ttf b/fonts/indivisaFont/ttf/IndivisaTextSans-RegularItalic.ttf new file mode 100644 index 0000000..974a9e5 Binary files /dev/null and b/fonts/indivisaFont/ttf/IndivisaTextSans-RegularItalic.ttf differ diff --git a/fonts/indivisaFont/woff/IndivisaDisplaySans-Heavy.woff b/fonts/indivisaFont/woff/IndivisaDisplaySans-Heavy.woff new file mode 100644 index 0000000..97ca7e4 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaDisplaySans-Heavy.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaDisplaySans-HeavyItalic.woff b/fonts/indivisaFont/woff/IndivisaDisplaySans-HeavyItalic.woff new file mode 100644 index 0000000..cbf378d Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaDisplaySans-HeavyItalic.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaDisplaySans-Regular.woff b/fonts/indivisaFont/woff/IndivisaDisplaySans-Regular.woff new file mode 100644 index 0000000..b72c6a6 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaDisplaySans-Regular.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaDisplaySans-RegularItalic.woff b/fonts/indivisaFont/woff/IndivisaDisplaySans-RegularItalic.woff new file mode 100644 index 0000000..4c30fa6 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaDisplaySans-RegularItalic.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaDisplaySans-Thin.woff b/fonts/indivisaFont/woff/IndivisaDisplaySans-Thin.woff new file mode 100644 index 0000000..faa02cc Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaDisplaySans-Thin.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaDisplaySans-ThinItalic.woff b/fonts/indivisaFont/woff/IndivisaDisplaySans-ThinItalic.woff new file mode 100644 index 0000000..1f88c19 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaDisplaySans-ThinItalic.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaDisplaySerif-RegularItalic.woff b/fonts/indivisaFont/woff/IndivisaDisplaySerif-RegularItalic.woff new file mode 100644 index 0000000..a721e8e Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaDisplaySerif-RegularItalic.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaTextSans-Black.woff b/fonts/indivisaFont/woff/IndivisaTextSans-Black.woff new file mode 100644 index 0000000..01aba5d Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaTextSans-Black.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaTextSans-BlackItalic.woff b/fonts/indivisaFont/woff/IndivisaTextSans-BlackItalic.woff new file mode 100644 index 0000000..ac66a14 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaTextSans-BlackItalic.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaTextSans-Bold.woff b/fonts/indivisaFont/woff/IndivisaTextSans-Bold.woff new file mode 100644 index 0000000..585bc34 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaTextSans-Bold.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaTextSans-BoldItalic.woff b/fonts/indivisaFont/woff/IndivisaTextSans-BoldItalic.woff new file mode 100644 index 0000000..4a9d14d Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaTextSans-BoldItalic.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaTextSans-Light.woff b/fonts/indivisaFont/woff/IndivisaTextSans-Light.woff new file mode 100644 index 0000000..efb4a12 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaTextSans-Light.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaTextSans-LightItalic.woff b/fonts/indivisaFont/woff/IndivisaTextSans-LightItalic.woff new file mode 100644 index 0000000..8b91059 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaTextSans-LightItalic.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaTextSans-Regular.woff b/fonts/indivisaFont/woff/IndivisaTextSans-Regular.woff new file mode 100644 index 0000000..5a3dee8 Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaTextSans-Regular.woff differ diff --git a/fonts/indivisaFont/woff/IndivisaTextSans-RegularItalic.woff b/fonts/indivisaFont/woff/IndivisaTextSans-RegularItalic.woff new file mode 100644 index 0000000..db9cdcb Binary files /dev/null and b/fonts/indivisaFont/woff/IndivisaTextSans-RegularItalic.woff differ diff --git a/fonts/indivisaFont/woff2/IndivisaDisplaySans-Heavy.woff2 b/fonts/indivisaFont/woff2/IndivisaDisplaySans-Heavy.woff2 new file mode 100644 index 0000000..6278b64 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaDisplaySans-Heavy.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaDisplaySans-HeavyItalic.woff2 b/fonts/indivisaFont/woff2/IndivisaDisplaySans-HeavyItalic.woff2 new file mode 100644 index 0000000..c212501 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaDisplaySans-HeavyItalic.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaDisplaySans-Regular.woff2 b/fonts/indivisaFont/woff2/IndivisaDisplaySans-Regular.woff2 new file mode 100644 index 0000000..6cc4b7b Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaDisplaySans-Regular.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaDisplaySans-RegularItalic.woff2 b/fonts/indivisaFont/woff2/IndivisaDisplaySans-RegularItalic.woff2 new file mode 100644 index 0000000..d9d51b0 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaDisplaySans-RegularItalic.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaDisplaySans-Thin.woff2 b/fonts/indivisaFont/woff2/IndivisaDisplaySans-Thin.woff2 new file mode 100644 index 0000000..5df2799 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaDisplaySans-Thin.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaDisplaySans-ThinItalic.woff2 b/fonts/indivisaFont/woff2/IndivisaDisplaySans-ThinItalic.woff2 new file mode 100644 index 0000000..f095046 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaDisplaySans-ThinItalic.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaDisplaySerif-Regular.woff2 b/fonts/indivisaFont/woff2/IndivisaDisplaySerif-Regular.woff2 new file mode 100644 index 0000000..7176457 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaDisplaySerif-Regular.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaDisplaySerif-RegularItalic.woff2 b/fonts/indivisaFont/woff2/IndivisaDisplaySerif-RegularItalic.woff2 new file mode 100644 index 0000000..9075e08 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaDisplaySerif-RegularItalic.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaTextSans-Black.woff2 b/fonts/indivisaFont/woff2/IndivisaTextSans-Black.woff2 new file mode 100644 index 0000000..a271e2e Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaTextSans-Black.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaTextSans-BlackItalic.woff2 b/fonts/indivisaFont/woff2/IndivisaTextSans-BlackItalic.woff2 new file mode 100644 index 0000000..8a0605a Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaTextSans-BlackItalic.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaTextSans-Bold.woff2 b/fonts/indivisaFont/woff2/IndivisaTextSans-Bold.woff2 new file mode 100644 index 0000000..6995d0c Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaTextSans-Bold.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaTextSans-BoldItalic.woff2 b/fonts/indivisaFont/woff2/IndivisaTextSans-BoldItalic.woff2 new file mode 100644 index 0000000..7f78584 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaTextSans-BoldItalic.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaTextSans-Light.woff2 b/fonts/indivisaFont/woff2/IndivisaTextSans-Light.woff2 new file mode 100644 index 0000000..27484d6 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaTextSans-Light.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaTextSans-LightItalic.woff2 b/fonts/indivisaFont/woff2/IndivisaTextSans-LightItalic.woff2 new file mode 100644 index 0000000..8fc6fd1 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaTextSans-LightItalic.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaTextSans-Regular.woff2 b/fonts/indivisaFont/woff2/IndivisaTextSans-Regular.woff2 new file mode 100644 index 0000000..06af0e0 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaTextSans-Regular.woff2 differ diff --git a/fonts/indivisaFont/woff2/IndivisaTextSans-RegularItalic.woff2 b/fonts/indivisaFont/woff2/IndivisaTextSans-RegularItalic.woff2 new file mode 100644 index 0000000..4ba13f4 Binary files /dev/null and b/fonts/indivisaFont/woff2/IndivisaTextSans-RegularItalic.woff2 differ diff --git a/fonts/ingenieria/ingfont.eot b/fonts/ingenieria/ingfont.eot new file mode 100644 index 0000000..83a1444 Binary files /dev/null and b/fonts/ingenieria/ingfont.eot differ diff --git a/fonts/ingenieria/ingfont.svg b/fonts/ingenieria/ingfont.svg new file mode 100644 index 0000000..6b156db --- /dev/null +++ b/fonts/ingenieria/ingfont.svg @@ -0,0 +1,87 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/ingenieria/ingfont.ttf b/fonts/ingenieria/ingfont.ttf new file mode 100644 index 0000000..15c900f Binary files /dev/null and b/fonts/ingenieria/ingfont.ttf differ diff --git a/fonts/ingenieria/ingfont.woff b/fonts/ingenieria/ingfont.woff new file mode 100644 index 0000000..23bf3a2 Binary files /dev/null and b/fonts/ingenieria/ingfont.woff differ diff --git a/fonts/lasalle/lasalle.eot b/fonts/lasalle/lasalle.eot new file mode 100644 index 0000000..57ff85c Binary files /dev/null and b/fonts/lasalle/lasalle.eot differ diff --git a/fonts/lasalle/lasalle.json b/fonts/lasalle/lasalle.json new file mode 100644 index 0000000..1594ba0 --- /dev/null +++ b/fonts/lasalle/lasalle.json @@ -0,0 +1 @@ +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M778.529 669.459c-57.812-40.469-130.8-82.382-161.874-100.449 15.176-5.059 30.351-10.84 44.805-18.789 20.957-10.84 39.746-24.57 56.367-41.191 19.512-20.234 35.41-44.082 44.805-70.097 12.285-36.133 18.066-74.433 17.344-112.734 0-31.074-2.891-68.652-12.285-82.382-2.891-4.336-7.227-7.227-12.285-7.227-4.336 0-8.672 2.168-10.84 5.781-31.074 34.687-66.484 66.484-104.785 93.945-4.336 2.891-7.949 5.781-12.285 8.672-4.336-36.855-13.73-72.988-28.183-106.953-6.504-15.898-13.73-31.074-22.402-45.527-12.285-19.512-19.512-22.402-24.57-23.125-0.723 0-1.445 0-2.168 0-6.504 0-11.562 4.336-13.008 10.117-23.848 67.929-59.98 131.523-105.507 186.445-7.227-10.117-13.008-18.789-17.344-26.738-13.73-23.848-39.023-38.301-66.484-38.301-26.738 0.723-52.031 14.453-67.207 36.855-2.891 0-5.059 0-7.227 0-16.621 0-27.461 2.168-30.351 11.562-2.168 7.227 1.445 14.453 26.016 33.965 0.723 11.562 4.336 22.402 10.84 31.074 4.336 5.059 8.672 10.117 13.008 14.453 10.117 6.504 14.453 18.789 12.285 30.351-2.168 20.957 13.008 94.668 60.703 148.144 15.176 17.344 33.965 31.074 54.199 41.191 23.848 11.562 49.863 16.621 75.879 16.621 13.008 0 26.016-1.445 39.023-3.613 33.242 24.57 59.258 88.886 75.879 185.722 0.723 4.336 5.059 7.949 9.394 7.949 0.723 0 2.168 0 2.891-0.723 41.191-13.008 114.179-46.972 145.253-129.355 5.781-15.176 10.117-30.351 14.453-46.25 0-3.613-1.445-7.227-4.336-9.394zM691.811 797.369c-19.512 15.176-41.191 27.461-65.039 35.41-5.781-33.965-14.453-67.929-26.016-100.449-15.898-44.082-36.133-73.711-59.258-88.886-2.168-1.445-4.336-2.168-7.227-1.445-13.008 2.168-26.016 3.613-39.746 3.613-44.805 0.723-86.718-18.066-116.347-51.308-20.234-23.125-36.133-50.586-45.527-80.215-6.504-17.344-10.117-35.41-10.84-53.476 2.891-17.344-3.613-35.41-18.066-46.25-4.336-3.613-7.949-7.949-11.562-12.285-5.059-7.227-7.227-15.898-7.227-24.57 0-0.723 0-1.445 0-2.168 0-7.949 2.168-16.621 6.504-23.848 15.176-28.906 50.586-40.469 79.492-25.293 10.117 5.059 18.066 13.008 23.848 22.402 18.066 28.183 37.578 55.644 59.258 81.66 2.168 2.168 4.336 3.613 7.227 3.613h0.723c31.797-5.059 62.871-14.453 91.777-28.183 33.242-14.453 64.316-32.519 93.945-53.476 37.578-27.461 72.988-57.812 104.062-92.5 4.336 16.621 6.504 33.965 6.504 51.308-0.723 0.723-1.445 0.723-1.445 1.445-21.68 26.016-47.695 49.14-75.879 67.207-26.738 18.066-55.644 33.242-85.273 45.527-31.797 13.73-65.039 25.293-98.281 33.965-5.059 1.445-8.672 6.504-7.227 11.562s6.504 8.672 11.562 7.227c34.687-8.672 68.652-20.234 101.171-34.687 31.074-13.008 60.703-28.906 88.164-47.695 24.57-15.898 46.972-34.687 67.207-56.367-0.723 20.234-2.891 40.469-7.227 59.98-50.586 36.133-106.953 63.594-166.933 81.66-21.68 6.504-43.359 10.84-66.484 12.285-5.059 0-9.394 4.336-9.394 9.394s4.336 9.394 9.394 9.394v0c23.848-1.445 47.695-5.781 70.097-13.008 54.922-16.621 106.953-41.191 154.648-72.265-0.723 1.445-0.723 2.891-1.445 4.336-8.672 23.125-21.68 44.082-39.023 62.148-0.723 0-0.723 0-1.445 0-1.445 0-2.891 0-3.613 0.723-33.242 13.008-67.929 20.957-103.339 24.57-31.797 3.613-56.367 3.613-56.367 3.613-5.059 0-9.394 4.336-9.394 9.394s4.336 9.394 9.394 9.394c41.191-0.723 82.382-5.059 122.851-14.453-3.613 2.168-7.227 4.336-10.84 5.781-20.234 10.84-41.191 18.066-63.594 23.125-10.117 1.445-20.234 1.445-30.351 1.445-21.68 0-42.637-2.891-63.594-9.394s-39.746-18.066-54.922-33.242c-15.176-14.453-26.738-33.242-33.965-53.476-1.445-4.336-5.059-7.227-9.394-7.227-0.723 0-1.445 0-2.168 0-5.059 1.445-7.949 6.504-7.227 11.562 7.227 23.125 20.234 44.805 38.301 61.426 18.066 17.344 39.023 30.351 62.871 37.578 22.402 7.227 46.25 10.84 70.097 10.84 9.394 0 19.512-0.723 29.629-1.445 17.344 9.394 103.339 57.812 173.437 106.23-3.613 13.008-7.949 26.016-12.285 37.578-7.949 32.519-28.183 59.98-54.199 80.215v0zM549.448 387.624c-26.016 12.285-53.476 20.957-81.66 26.016l-2.168-2.891c14.453-10.117 28.183-21.68 40.469-34.687 31.797-30.351 56.367-67.929 71.543-109.121 1.445-5.059-0.723-10.117-5.781-12.285-5.059-1.445-10.117 0.723-12.285 5.781 0 0 0 0 0 0-14.453 38.301-37.578 72.988-66.484 101.894-12.285 12.285-25.293 23.125-39.746 33.242-3.613-5.059-7.227-9.394-10.84-13.73 47.695-56.367 85.273-120.683 109.843-190.058 12.285 17.344 22.402 35.41 29.629 55.644 14.453 34.687 23.848 70.82 26.016 108.398 0 0.723 0 0.723 0 1.445-18.789 10.84-38.301 20.957-58.535 30.351v0zM270.504 356.55c0 0.723-0.723 2.168-0.723 2.891-0.723-0.723-2.168-2.168-2.891-2.891 1.445 0 2.891 0 3.613 0v0z","M329.761 351.491c-7.227 0-12.285 5.781-12.285 12.285 0 7.227 5.781 12.285 12.285 12.285s12.285-5.781 12.285-12.285c0-6.504-5.059-12.285-12.285-12.285z","M633.276 626.1c-18.066-11.562-37.578-20.234-57.090-27.461-5.059-1.445-10.117 1.445-12.285 6.504-1.445 5.059 1.445 10.117 6.504 12.285 0.723 0 97.558 31.797 133.691 109.843 1.445 3.613 5.059 5.781 8.672 5.781 1.445 0 2.891 0 4.336-0.723 5.059-2.168 7.227-7.949 4.336-13.008-20.234-39.023-50.586-70.82-88.164-93.222z","M644.116 685.357c-9.394-10.84-20.234-20.234-32.519-27.461-5.059-2.168-10.117-0.723-13.008 4.336 0 0 0 0 0 0-2.168 5.059-0.723 10.84 4.336 13.008 10.117 5.781 19.512 13.73 26.738 23.125 18.789 23.125 29.629 52.031 30.351 81.66 0 5.059 4.336 9.394 9.394 9.394h0.723c5.059 0 9.394-5.059 9.394-10.117-1.445-34.687-13.73-67.207-35.41-93.945z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":0,"tags":["lasalle-85"]},"attrs":[{},{},{},{}],"properties":{"order":17,"id":82,"name":"fe","prevSize":32,"code":59730},"setIdx":0,"setId":3,"iconIdx":0},{"icon":{"paths":["M801.423 771.794l-42.637-478.397c-0.723-10.84-9.394-18.789-20.234-18.789h-86.718c0-80.937-65.761-146.699-146.699-146.699s-146.699 65.761-146.699 146.699h-86.718c-10.84 0-19.512 7.949-20.234 18.789l-42.637 478.397c0 0.723 0 1.445 0 2.168 3.613 57.812 53.476 101.894 111.289 99.004h370.721c57.812 2.891 107.675-41.191 111.289-99.004 0-1.445 0-1.445-0.723-2.168zM505.135 171.269c57.090 0 104.062 46.25 105.507 103.339h-211.015c1.445-57.090 48.418-103.339 105.507-103.339v0zM690.857 831.052h-371.444c-34.687 2.891-65.761-21.68-70.097-56.367l40.469-458.162h68.652v62.148c0 11.562 9.394 20.234 20.234 20.234 11.562 0 20.234-9.394 20.234-20.234v-62.148h211.015v62.148c0 11.562 9.394 20.234 20.234 20.234 11.562 0 20.234-9.394 20.234-20.234v-62.148h68.652l40.469 458.162c-2.891 34.687-33.965 59.258-68.652 56.367v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-80"],"grid":0},"attrs":[{}],"properties":{"order":84,"id":0,"name":"compras","prevSize":32,"code":59725},"setIdx":0,"setId":3,"iconIdx":1},{"icon":{"paths":["M893.922 150.312c-22.402-22.402-67.929-9.394-143.085 40.469-77.324 54.199-148.867 115.625-215.351 182.831-89.609 83.105-165.488 179.941-224.023 287.616-4.336-1.445-9.394-2.891-14.453-4.336-30.351-5.781-62.148 2.168-86.718 20.234-23.848 17.344-41.191 42.637-48.418 71.543-7.949 29.629-22.402 57.812-42.637 80.937-6.504 7.949-5.781 18.789 1.445 26.016 26.016 23.125 59.258 35.41 94.668 35.41 35.41-0.723 70.097-11.562 99.004-32.519 10.117-7.227 18.789-15.176 27.461-23.848 25.293-26.016 36.855-62.148 31.797-98.281 112.011-57.812 213.183-134.414 297.733-227.636 67.207-65.761 128.632-138.027 182.831-215.351 49.863-75.156 62.148-120.683 39.746-143.085zM314.354 809.372c-6.504 7.227-13.73 13.008-21.68 18.789-38.301 30.351-91.054 33.965-132.968 10.84 18.066-24.57 31.074-51.308 39.023-80.937v0-0.723c5.059-19.512 17.344-37.578 33.965-49.14 16.621-12.285 37.578-17.344 58.535-13.73 15.176 2.891 28.906 12.285 37.578 25.293 14.453 28.906 9.394 65.761-14.453 89.609zM360.604 701.697c-4.336-7.949-9.394-14.453-16.621-20.234 14.453-33.242 33.242-65.039 54.922-93.945l57.812 57.812c-29.629 22.402-62.148 41.191-96.113 56.367v0zM487.068 622.927l-65.039-65.039c11.562-14.453 23.125-29.629 36.855-44.805l73.711 73.711c-16.621 13.008-31.074 24.57-45.527 36.133v0zM817.321 281.112c-52.031 72.265-109.121 139.472-172.714 201.62-28.906 29.629-57.812 55.644-84.55 79.492l-78.047-78.047c24.57-27.461 51.308-56.367 79.492-84.55 62.148-62.871 129.355-120.683 201.62-172.714 73.711-51.308 99.726-51.308 104.062-50.586 1.445 5.059 0.723 30.351-49.863 104.785z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-81"],"grid":0},"attrs":[{}],"properties":{"order":85,"id":1,"name":"arte","prevSize":32,"code":59726},"setIdx":0,"setId":3,"iconIdx":2},{"icon":{"paths":["M334.589 234.862c-28.183-44.082-86.718-56.367-130.8-28.183-11.562 7.227-20.957 16.621-28.183 28.183-41.191 59.258-41.191 138.027 0 197.284 10.84 14.453 24.57 26.738 40.469 34.687l-23.125 351.21c-2.168 33.965 23.848 64.316 57.812 66.484s64.316-23.848 66.484-57.812c0-2.891 0-5.781 0-8.672l-23.125-351.21c15.898-7.949 30.351-19.512 40.469-34.687 41.191-59.258 41.191-138.027-0-197.284zM276.776 842.614c-11.562 12.285-31.074 13.008-43.359 1.445-6.504-6.504-10.117-15.176-9.394-23.848l23.125-344.706c2.168 0 5.059 0 7.227 0s5.059 0 7.227 0l23.125 344.706c0.723 7.949-2.168 16.621-7.949 22.402v0zM255.097 443.709c-5.781 0-11.562-0.723-16.621-2.168l-1.445-0.723c-40.469-19.512-64.316-62.148-60.703-106.953 0-60.703 35.41-109.843 78.769-109.843s78.769 49.14 78.769 109.843-35.41 109.843-78.769 109.843v0z","M834.665 605.584v-396.014c1.445-8.672-5.059-16.621-13.73-18.066-3.613-0.723-7.227 0-10.117 2.168-64.316 39.746-104.062 109.843-103.339 185.722v0 208.124c0 18.066 14.453 33.242 32.519 33.965v215.351c0 26.016 20.957 47.695 47.695 47.695 26.016 0 47.695-20.957 47.695-47.695l-0.723-231.249zM740.72 589.685c-0.723 0-0.723 0-1.445-0.723-0.723 0-0.723-0.723-0.723-1.445v-208.124c0-54.199 23.125-105.507 64.316-140.917v350.487h-62.148zM802.868 836.11c0 8.672-7.227 15.898-15.898 15.898s-15.898-7.227-15.898-15.898c0 0 0 0 0 0v-214.628h31.797v214.628z","M593.299 191.503c-8.672 0-15.898 7.227-15.898 15.898v180.663h-40.469v-180.663c0-8.672-7.227-15.898-15.898-15.898s-15.898 7.227-15.898 15.898v180.663h-40.469v-180.663c0-8.672-7.227-15.898-15.898-15.898s-15.898 7.227-15.898 15.898v229.804c0 26.016 20.957 46.972 46.972 46.972h2.891l-22.402 334.589c-2.168 33.242 23.125 62.148 56.367 65.039 33.242 2.168 62.148-23.125 65.039-56.367 0-2.891 0-5.781 0-8.672l-22.402-334.589h2.891c26.016 0 46.972-20.957 46.972-46.972v-229.804c-0-8.672-7.227-15.898-15.898-15.898v0zM541.99 843.337c-11.562 11.562-29.629 11.562-41.191 0.723-5.781-5.781-9.394-13.73-8.672-22.402l22.402-337.479h13.008l22.402 336.757c0.723 8.672-2.168 15.898-7.949 22.402v0zM577.4 437.205c0 8.672-6.504 15.176-15.176 15.176h-82.382c-8.672 0-15.176-6.504-15.176-15.176v-18.066h112.734v18.066z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-82"],"grid":0},"attrs":[{},{},{}],"properties":{"order":86,"id":2,"name":"restaurante","prevSize":32,"code":59727},"setIdx":0,"setId":3,"iconIdx":3},{"icon":{"paths":["M872.965 401.795c-16.621-18.066-40.469-28.906-65.039-28.906h-85.273v-23.125c0-7.949-6.504-14.453-14.453-14.453h-491.404c-7.949 0-14.453 6.504-14.453 14.453v176.327c0 79.492 36.133 153.925 96.836 202.343h-112.011c-7.949 0-14.453 6.504-14.453 14.453s6.504 14.453 14.453 14.453c8.672 0 15.898 5.781 18.789 13.73 12.285 42.637 52.754 72.988 97.558 72.988h346.874c44.805 0 84.55-29.629 97.558-72.988 2.168-7.949 10.117-13.73 18.789-13.73 7.949 0 14.453-6.504 14.453-14.453s-6.504-14.453-14.453-14.453h-140.917c10.84-8.672 20.957-18.789 31.074-29.629 5.059 0 9.394 0.723 14.453 0.723 57.812 0 109.843-20.957 149.589-62.148 41.191-41.914 67.929-101.171 74.433-168.378 2.168-23.848-5.781-48.418-22.402-67.207zM722.653 460.33h85.273c0.723 0 0.723 0 0.723 0 0.723 0.723 0.723 0.723 0 0.723-3.613 39.023-21.68 126.464-99.726 147.421 8.672-26.016 13.008-54.199 13.008-82.382v-65.761zM719.763 763.845c-8.672 30.351-37.578 52.031-69.375 52.031h-346.874c-31.797 0-60.703-21.68-69.375-52.031-0.723-2.168-1.445-3.613-2.168-5.781h489.959c-1.445 1.445-1.445 3.613-2.168 5.781zM349.764 729.157c-73.711-41.191-119.238-117.793-119.238-202.343v-162.597h462.498v161.874c0 85.273-46.25 161.874-119.238 202.343h-224.023zM866.462 466.834c-10.117 98.281-72.265 199.452-187.89 203.788 6.504-9.394 12.285-19.512 17.344-30.351 40.469-5.059 75.156-25.293 99.726-57.812 22.402-30.351 36.855-70.82 41.914-118.515 0.723-8.672-2.168-16.621-7.949-23.125s-13.73-10.117-22.402-10.117h-84.55v-28.906h85.273c16.621 0 32.519 7.227 44.082 19.512 10.84 13.008 15.898 28.906 14.453 45.527z","M450.213 226.913c0 16.621 5.059 33.242 15.176 45.527 5.059 6.504 14.453 7.227 20.234 2.168 6.504-5.059 7.227-13.73 2.168-20.234-5.781-7.227-8.672-16.621-8.672-27.461 0-10.117 2.891-20.234 8.672-27.461 20.234-25.293 20.234-65.039 0-90.332-5.059-6.504-13.73-7.227-20.234-2.168s-7.227 13.73-2.168 20.234c11.562 14.453 11.562 39.746 0 54.199-10.117 13.008-15.176 28.906-15.176 45.527z","M536.932 226.913c0 16.621 5.059 33.242 15.176 45.527 5.059 6.504 14.453 7.227 20.234 2.168 6.504-5.059 7.227-13.73 2.168-20.234-5.781-7.227-8.672-16.621-8.672-27.461 0-10.117 2.891-20.234 8.672-27.461 20.234-25.293 20.234-65.039 0-90.332-5.059-6.504-13.73-7.227-20.234-2.168s-7.227 13.73-2.168 20.234c11.562 14.453 11.562 39.746 0 54.199-10.117 13.008-15.176 28.906-15.176 45.527z","M363.495 226.913c0 16.621 5.059 33.242 15.176 45.527 5.059 6.504 14.453 7.227 20.234 2.168 6.504-5.059 7.227-13.73 2.168-20.234-5.781-7.227-8.672-16.621-8.672-27.461 0-10.117 2.891-20.234 8.672-27.461 20.234-25.293 20.234-65.039 0-90.332-5.059-6.504-14.453-7.227-20.234-2.168-6.504 5.059-7.227 13.73-2.168 20.234 11.562 14.453 11.562 39.746 0 54.199-10.117 13.008-15.176 28.906-15.176 45.527z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-83"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":87,"id":3,"name":"cafe","prevSize":32,"code":59728},"setIdx":0,"setId":3,"iconIdx":4},{"icon":{"paths":["M560.779 482.733c2.168 3.613 5.781 6.504 10.117 6.504 1.445 0 3.613-0.723 5.059-1.445 0.723 0 67.929-34.687 101.171-44.805 5.781-2.168 9.394-8.672 7.227-14.453s-7.949-9.394-14.453-7.227c-34.687 10.84-101.894 44.805-104.785 46.25-5.059 2.168-7.227 9.394-4.336 15.176z","M570.896 351.21c1.445 0 3.613-0.723 5.059-1.445 0.723 0 67.929-34.687 101.171-44.805 5.781-2.168 9.394-8.672 7.227-14.453s-7.949-9.394-14.453-7.227c-34.687 10.84-101.894 44.805-104.785 46.25-5.781 2.891-7.949 9.394-5.059 15.176 2.891 4.336 6.504 6.504 10.84 6.504z","M845.505 328.807c-6.504 0-11.562 5.059-11.562 11.562v445.877c0 18.789-15.176 33.965-33.965 33.965h-274.608v-26.016c16.621-5.781 59.98-19.512 102.617-19.512 99.726 0 166.933 22.402 167.656 22.402 3.613 1.445 7.227 0.723 10.117-1.445s5.059-5.781 5.059-9.394v-502.967c0-5.059-3.613-10.117-8.672-10.84 0 0-8.672-2.168-24.57-5.059-6.504-1.445-12.285 2.891-13.008 9.394-1.445 6.504 2.891 12.285 9.394 13.008 5.781 0.723 10.84 2.168 14.453 2.891v478.397c-26.016-6.504-83.105-18.789-159.706-18.789-49.863 0-99.004 16.621-114.179 21.68-13.73-5.781-54.199-21.68-103.339-21.68-78.769 0-143.808 13.008-171.269 19.512v-479.842c23.125-5.781 90.332-20.234 171.269-20.234 41.914 0 77.324 13.008 91.777 18.789v450.213c0 4.336 2.168 7.949 5.781 10.117s7.949 2.168 11.562 0c1.445-0.723 114.179-68.652 214.628-101.894 4.336-1.445 7.949-5.781 7.949-10.84v-469.725c0-3.613-2.168-7.227-5.059-9.394s-7.227-2.891-10.84-1.445c-91.777 34.687-184.277 92.5-184.999 92.5-5.059 3.613-7.227 10.117-3.613 15.898 3.613 5.059 10.117 7.227 15.898 3.613 0.723-0.723 81.66-50.586 165.488-84.55v443.709c-78.047 27.461-159.706 71.543-194.394 91.054v-436.483c0-4.336-2.168-7.949-6.504-10.117-2.168-0.723-49.14-23.848-107.675-23.848-103.339 0-182.831 22.402-185.722 23.125-5.059 1.445-7.949 5.781-7.949 10.84v502.967c0 3.613 1.445 7.227 4.336 9.394 2.168 1.445 4.336 2.168 7.227 2.168 0.723 0 2.168 0 2.891-0.723 0.723 0 79.492-22.402 179.941-22.402 41.914 0 77.324 13.008 91.777 18.789v26.738h-274.608c-18.789 0-33.965-15.176-33.965-33.965v-445.877c0-6.504-5.059-11.562-11.562-11.562s-11.562 5.059-11.562 11.562v445.877c0 31.797 25.293 57.090 57.090 57.090h571.619c31.797 0 57.090-25.293 57.090-57.090v-445.877c-0.723-6.504-5.781-11.562-12.285-11.562z","M560.779 414.080c2.168 3.613 5.781 6.504 10.117 6.504 1.445 0 3.613-0.723 5.059-1.445 0.723 0 67.929-34.687 101.171-44.805 5.781-2.168 9.394-8.672 7.227-14.453s-7.949-9.394-14.453-7.227c-34.687 10.84-101.894 44.805-104.785 46.25-5.059 2.168-7.227 9.394-4.336 15.176z","M560.779 551.385c2.168 3.613 5.781 6.504 10.117 6.504 1.445 0 3.613-0.723 5.059-1.445 0.723 0 67.929-34.687 101.171-44.805 5.781-2.168 9.394-8.672 7.227-14.453s-7.949-9.394-14.453-7.227c-34.687 10.84-101.894 44.805-104.785 46.25-5.059 2.168-7.227 9.394-4.336 15.176z","M448.045 369.276c-70.82-16.621-151.035 4.336-153.925 5.781-5.781 1.445-9.394 7.949-7.949 13.73 1.445 5.059 5.781 8.672 10.84 8.672 0.723 0 2.168 0 2.891-0.723 0.723 0 78.047-20.234 143.085-5.059 5.781 1.445 12.285-2.168 13.73-8.672 0.723-5.781-2.891-12.285-8.672-13.73z","M448.045 437.928c-70.82-16.621-151.035 4.336-153.925 5.781-5.781 1.445-9.394 7.949-7.949 13.73 1.445 5.059 5.781 8.672 10.84 8.672 0.723 0 2.168 0 2.891-0.723 0.723 0 78.047-20.234 143.085-5.059 5.781 1.445 12.285-2.168 13.73-8.672 0.723-5.781-2.891-12.285-8.672-13.73z","M560.779 619.314c2.168 3.613 5.781 6.504 10.117 6.504 1.445 0 3.613-0.723 5.059-1.445 0.723 0 67.929-34.687 101.171-44.805 5.781-2.168 9.394-8.672 7.227-14.453s-7.949-9.394-14.453-7.227c-34.687 10.84-101.894 44.805-104.785 46.25-5.059 2.891-7.227 10.117-4.336 15.176z","M448.045 506.58c-70.82-16.621-151.035 4.336-153.925 5.781-5.781 1.445-9.394 7.949-7.949 13.73 1.445 5.059 5.781 8.672 10.84 8.672 0.723 0 2.168 0 2.891-0.723 0.723 0 78.047-20.234 143.085-5.059 5.781 1.445 12.285-2.168 13.73-8.672 0.723-6.504-2.891-12.285-8.672-13.73z","M448.045 643.884c-70.82-16.621-151.035 4.336-153.925 5.781-5.781 1.445-9.394 7.949-7.949 13.73 1.445 5.059 5.781 8.672 10.84 8.672 0.723 0 2.168 0 2.891-0.723 0.723 0 78.047-20.234 143.085-5.059 5.781 1.445 12.285-2.168 13.73-8.672 0.723-6.504-2.891-12.285-8.672-13.73z","M448.045 575.232c-70.82-16.621-151.035 4.336-153.925 5.781-5.781 1.445-9.394 7.949-7.949 13.73 1.445 5.059 5.781 8.672 10.84 8.672 0.723 0 2.168 0 2.891-0.723 0.723 0 78.047-20.234 143.085-5.059 5.781 1.445 12.285-2.168 13.73-8.672 0.723-6.504-2.891-12.285-8.672-13.73z"],"attrs":[{},{},{},{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-84"],"grid":0},"attrs":[{},{},{},{},{},{},{},{},{},{},{}],"properties":{"order":88,"id":4,"name":"biblioteca","prevSize":32,"code":59729},"setIdx":0,"setId":3,"iconIdx":5},{"icon":{"paths":["M318.69 247.147c-98.281 97.558-109.843 280.39-26.016 391.678l221.132 278.944 220.409-278.944c84.55-111.289 72.265-294.843-25.293-392.401-107.675-106.953-282.558-106.953-390.233 0.723zM515.975 551.385c-62.148 0-112.011-50.586-112.011-112.011 0-62.148 50.586-112.011 112.011-112.011 62.148 0 112.011 50.586 112.011 112.011 0.723 61.426-49.863 112.011-112.011 112.011z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-79"],"grid":0},"attrs":[{}],"properties":{"order":83,"id":5,"name":"markFull","prevSize":32,"code":59724},"setIdx":0,"setId":3,"iconIdx":6},{"icon":{"paths":["M841.891 676.404c1.445 10.117-1.445 18.789-9.394 26.738l-88.164 86.718c-3.613 4.336-9.394 7.949-15.898 11.562-6.504 2.891-13.008 5.059-18.789 5.781-0.723 0-1.445 0-4.336 0-2.168 0-5.059 0-8.672 0-8.672 0-21.68-1.445-40.469-4.336s-41.914-10.117-68.652-20.957c-27.461-11.562-57.812-28.183-92.5-50.586s-70.82-53.476-109.843-92.5c-31.074-30.351-56.367-59.258-76.601-87.441-20.234-27.461-36.855-53.476-49.14-77.324s-21.68-44.805-27.461-64.316c-6.504-19.512-10.117-35.41-12.285-49.863s-2.891-23.848-2.891-31.797c0.723-7.949 0.723-12.285 0.723-13.008 0.723-6.504 2.891-12.285 5.781-18.789s6.504-11.562 11.562-15.898l88.164-88.164c6.504-6.504 13.008-9.394 20.957-9.394 5.781 0 10.84 1.445 15.176 5.059s7.949 7.227 11.562 12.285l70.82 134.414c3.613 7.227 5.059 14.453 3.613 23.125s-5.781 15.176-11.562 20.957l-32.519 33.242c-0.723 0.723-1.445 2.168-2.168 4.336s-0.723 3.613-0.723 5.059c1.445 9.394 5.781 19.512 11.562 31.797 5.059 10.84 13.73 23.848 24.57 39.023s26.738 32.519 46.972 52.754c19.512 20.234 37.578 36.133 52.754 46.972 15.176 11.562 28.183 19.512 39.023 24.57 10.117 5.059 18.066 8.672 23.848 9.394l7.949 1.445c0.723 0 2.168 0 4.336-0.723s3.613-1.445 4.336-2.168l37.578-38.301c7.949-7.227 17.344-10.84 27.461-10.84 7.227 0 13.73 1.445 18.066 3.613h0.723l127.91 75.156c9.394 6.504 14.453 13.73 16.621 22.402z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-68"],"grid":0},"attrs":[{}],"properties":{"order":82,"id":6,"name":"telephone","prevSize":32,"code":59715},"setIdx":0,"setId":3,"iconIdx":7},{"icon":{"paths":["M586.072 253.651c-11.562-6.504-25.293-6.504-36.855 0-0.723 0.723-1.445 0.723-2.168 1.445l-155.371 144.531c-1.445 0.723-3.613 1.445-5.781 1.445h-97.558c-20.234 0-36.133 16.621-36.133 36.133v150.312c0 20.234 16.621 36.133 36.133 36.133h97.558c2.168 0 3.613 0.723 5.781 1.445l155.371 144.531c0.723 0.723 1.445 1.445 2.168 1.445 5.781 3.613 12.285 5.059 18.789 5.059s12.285-1.445 18.066-5.059c11.562-6.504 18.066-18.066 18.066-31.797v-455.272c0.723-11.562-6.504-23.848-18.066-30.351zM581.013 740.72c0 6.504-4.336 10.117-6.504 11.562-2.168 0.723-6.504 2.891-12.285 0.723l-155.371-144.531c-0.723-1.445-1.445-1.445-2.168-2.168-5.781-3.613-12.285-5.059-18.789-5.059h-97.558c-7.227 0-13.008-5.781-13.008-13.008v-150.312c0-7.227 5.781-13.008 13.008-13.008h97.558c6.504 0 13.008-1.445 18.789-5.059 0.723-0.723 1.445-0.723 2.168-1.445l155.371-144.531c5.781-2.891 10.117-0.723 12.285 0.723s6.504 4.336 6.504 11.562v454.549z","M672.79 369.999c-4.336 4.336-4.336 12.285 0 16.621 72.988 72.988 72.988 192.226 0 265.936-4.336 4.336-4.336 12.285 0 16.621 2.168 2.168 5.059 3.613 7.949 3.613s5.781-1.445 7.949-3.613c82.382-82.382 82.382-216.796 0-299.179-3.613-5.059-10.84-5.059-15.898 0z","M648.22 404.686c-4.336-4.336-12.285-4.336-16.621 0s-4.336 12.285 0 16.621c50.586 50.586 50.586 132.246 0 182.831-4.336 4.336-4.336 12.285 0 16.621 2.168 2.168 5.059 3.613 7.949 3.613s5.781-1.445 7.949-3.613c59.98-59.258 59.98-156.093 0.723-216.073z","M534.041 166.933c-194.394 0-352.655 158.261-352.655 352.655s158.261 352.655 352.655 352.655 352.655-158.261 352.655-352.655-158.261-352.655-352.655-352.655zM534.041 847.673c-181.386 0-328.807-147.421-328.807-328.807s147.421-328.807 328.807-328.807 328.807 147.421 328.807 328.807-147.421 328.807-328.807 328.807z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-69"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":73,"id":7,"name":"onSpeaking","prevSize":32,"code":59716},"setIdx":0,"setId":3,"iconIdx":8},{"icon":{"paths":["M783.356 264.491c-140.195-140.195-368.553-140.195-508.748 0-67.929 67.929-105.507 158.261-105.507 253.651s37.578 186.445 105.507 254.374c70.097 70.097 161.874 105.507 254.374 105.507s184.277-35.41 254.374-105.507c140.195-140.195 140.195-367.831 0-508.025zM291.952 281.112c65.761-65.761 151.757-98.281 237.030-98.281 82.382 0 164.042 30.351 228.359 89.609l-84.55 85.273v-78.047c0-13.73-7.227-25.293-18.789-32.519-11.562-6.504-26.016-6.504-37.578 0-0.723 0.723-1.445 0.723-2.168 1.445l-158.261 148.867c-1.445 0.723-3.613 1.445-5.781 1.445h-99.726c-20.234 0-36.855 16.621-36.855 36.855v153.203c0 20.234 16.621 36.855 36.855 36.855h53.476l-120.683 120.683c-57.812-62.148-90.332-143.085-90.332-228.359 0.723-89.609 35.41-173.437 99.004-237.030zM427.811 602.693h-77.324c-7.227 0-13.008-5.781-13.008-13.008v-153.925c0-7.227 5.781-13.008 13.008-13.008h99.726c6.504 0 13.008-1.445 18.789-5.059 0.723-0.723 1.445-0.723 2.168-1.445l158.984-148.144c5.781-2.891 10.117-0.723 12.285 0.723s6.504 4.336 6.504 11.562v101.894l-221.132 220.409zM648.943 415.526v329.53c0 7.227-4.336 10.117-6.504 11.562-2.168 0.723-6.504 2.891-12.285 0.723l-158.984-148.144c-0.723-0.723-1.445-1.445-2.168-1.445-2.891-1.445-5.781-2.891-8.672-3.613l188.613-188.613zM766.735 755.896c-127.91 127.91-334.589 130.8-466.112 7.949l138.027-138.027h12.285c2.168 0 3.613 0.723 5.781 1.445l158.984 148.144c0.723 0.723 1.445 1.445 2.168 1.445 5.781 3.613 12.285 5.059 18.789 5.059s13.008-1.445 18.789-5.059c11.562-6.504 18.789-18.789 18.789-32.519v-352.655l101.894-101.894c120.683 131.523 118.515 338.202-9.394 466.112z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-70"],"grid":0},"attrs":[{}],"properties":{"order":74,"id":8,"name":"offSpeaking","prevSize":32,"code":59717},"setIdx":0,"setId":3,"iconIdx":9},{"icon":{"paths":["M707.478 485.623c-7.227 0-13.008 5.781-13.008 13.008v78.047c0 99.726-81.66 181.386-181.386 181.386s-181.386-81.66-181.386-181.386v-78.047c0-7.227-5.781-13.008-13.008-13.008s-13.008 5.781-13.008 13.008v78.047c0 109.843 85.996 200.175 194.394 206.679v65.761h-65.039c-7.227 0-13.008 5.781-13.008 13.008s5.781 13.008 13.008 13.008h155.371c7.227 0 13.008-5.781 13.008-13.008s-5.781-13.008-13.008-13.008h-65.039v-65.761c108.398-6.504 194.394-96.836 194.394-206.679v-78.047c0.723-7.227-5.059-13.008-12.285-13.008z","M513.084 719.040c78.769 0 142.363-63.594 142.363-142.363v-310.741c0-79.492-63.594-143.085-142.363-143.085s-142.363 63.594-142.363 142.363v310.741c0 78.769 63.594 143.085 142.363 143.085zM396.737 265.214c0-64.316 52.031-116.347 116.347-116.347s116.347 52.031 116.347 116.347v310.741c0 64.316-52.031 116.347-116.347 116.347s-116.347-52.031-116.347-116.347v-310.741z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-71"],"grid":0},"attrs":[{},{}],"properties":{"order":75,"id":9,"name":"audio","prevSize":32,"code":59718},"setIdx":0,"setId":3,"iconIdx":10},{"icon":{"paths":["M162.597 244.257v361.327h278.944l-50.586 226.191 239.198-226.191h233.417v-361.327h-700.974z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-72"],"grid":0},"attrs":[{}],"properties":{"order":76,"id":10,"name":"comment","prevSize":32,"code":59719},"setIdx":0,"setId":3,"iconIdx":11},{"icon":{"paths":["M241.366 394.569h-65.039c-10.117 0-18.066 7.949-18.066 18.066s7.949 18.066 18.066 18.066h65.039c10.117 0 18.066-7.949 18.066-18.066s-7.949-18.066-18.066-18.066z","M883.083 394.569h-65.039c-10.117 0-18.066 7.949-18.066 18.066s7.949 18.066 18.066 18.066h65.039c10.117 0 18.066-7.949 18.066-18.066s-7.949-18.066-18.066-18.066z","M315.8 626.541c-7.227-7.227-18.066-7.227-25.293 0l-46.972 46.972c-7.227 7.227-7.227 18.066 0 25.293 3.613 3.613 7.949 5.059 13.008 5.059s9.394-1.445 13.008-5.059l46.972-46.972c6.504-7.227 6.504-18.066-0.723-25.293z","M784.079 158.261c-7.227-7.227-18.066-7.227-25.293 0l-45.527 45.527c-7.227 7.227-7.227 18.066 0 25.293 3.613 3.613 7.949 5.059 13.008 5.059 4.336 0 9.394-1.445 13.008-5.059l45.527-45.527c5.781-6.504 5.781-18.066-0.723-25.293z","M347.596 203.788l-45.527-45.527c-7.227-7.227-18.066-7.227-25.293 0s-7.227 18.066 0 25.293l45.527 45.527c3.613 3.613 7.949 5.059 13.008 5.059 4.336 0 9.394-1.445 13.008-5.059 5.781-6.504 5.781-18.066-0.723-25.293z","M816.598 673.513l-46.972-46.972c-7.227-7.227-18.066-7.227-25.293 0s-7.227 18.066 0 25.293l46.972 46.972c3.613 3.613 7.949 5.059 13.008 5.059 4.336 0 9.394-1.445 13.008-5.059 6.504-7.227 6.504-18.066-0.723-25.293z","M529.705 201.62c-124.296 0-225.468 105.507-225.468 235.585 0 60.703 21.68 125.742 59.258 178.495 28.906 40.469 44.082 85.996 44.082 130.8v113.457c0 19.512 15.898 36.133 36.133 36.133h171.269c19.512 0 36.133-15.898 36.133-36.133v-112.734c0-44.805 15.176-90.332 44.082-130.8 37.578-52.754 59.258-117.793 59.258-178.495 0.723-130.078-100.449-236.308-224.745-236.308zM615.701 859.958h-171.269v-23.848h85.996c10.117 0 18.066-7.949 18.066-18.066s-7.949-18.066-18.066-18.066h-85.996v-23.848h171.269v83.828c0 0 0 0 0 0zM504.412 524.646l-23.848-51.308h98.281l-23.848 51.308c-0.723 2.168-1.445 4.336-1.445 6.504l-13.73 210.292h-19.512l-13.73-210.292c0-2.168-0.723-4.336-2.168-6.504zM667.009 595.466c-31.797 44.805-49.863 95.39-50.586 145.976h-40.469l13.73-204.511 34.687-73.711c2.891-5.781 2.168-12.285-1.445-17.344s-8.672-8.672-15.176-8.672h-155.371c-6.504 0-11.562 2.891-15.176 8.672-3.613 5.059-3.613 11.562-1.445 17.344l34.687 73.711 13.73 204.511h-40.469c-1.445-50.586-18.789-101.171-50.586-145.976-33.242-46.25-52.754-105.507-52.754-157.538 0-109.843 85.273-200.175 189.335-200.175s189.335 89.609 189.335 200.175c0 52.031-19.512 111.289-52.031 157.538z"],"attrs":[{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-73"],"grid":0},"attrs":[{},{},{},{},{},{},{}],"properties":{"order":77,"id":11,"name":"faith","prevSize":32,"code":59720},"setIdx":0,"setId":3,"iconIdx":12},{"icon":{"paths":["M817.321 442.264h-8.672c-8.672-42.637-51.308-117.070-70.097-148.867 8.672-5.781 14.453-16.621 14.453-28.183 0-18.789-15.176-33.965-33.965-33.965s-33.965 15.176-33.965 33.965c0 11.562 5.781 21.68 14.453 28.183-18.789 31.797-62.148 106.953-70.097 148.867h-8.672c-7.227 0-13.008 5.781-13.008 13.008 0 61.426 49.863 111.289 111.289 111.289s111.289-49.863 111.289-111.289c-0.723-7.227-6.504-13.008-13.008-13.008zM719.040 257.265c4.336 0 8.672 3.613 8.672 8.672 0 4.336-3.613 8.672-8.672 8.672-4.336 0-8.672-3.613-8.672-8.672s3.613-8.672 8.672-8.672zM719.040 311.464c21.68 36.855 54.922 97.558 63.594 131.523h-127.187c7.949-31.797 37.578-88.886 63.594-131.523zM719.040 540.545c-42.637 0-78.047-31.797-84.55-72.265h169.101c-6.504 41.191-41.914 72.265-84.55 72.265z","M622.205 750.114h-33.965v-32.519c0-7.227-5.781-13.008-13.008-13.008h-32.519v-359.159c8.672-7.949 13.73-19.512 14.453-32.519l54.199-11.562c7.227-1.445 11.562-8.672 10.117-15.176-1.445-7.227-8.672-11.562-15.176-10.117l-54.199 11.562c-7.949-15.176-24.57-26.016-43.359-26.016-26.016 0-46.972 20.234-48.418 45.527l-135.859 28.906c-6.504-8.672-15.898-13.73-27.461-13.73-18.789 0-33.965 15.176-33.965 33.965 0 11.562 5.781 21.68 14.453 28.183-18.789 31.797-62.148 106.953-70.097 148.867h-8.672c-7.227 0-13.008 5.781-13.008 13.008 0 61.426 49.863 111.289 111.289 111.289s111.289-49.863 111.289-111.289c0-7.227-5.781-13.008-13.008-13.008h-8.672c-8.672-42.637-51.308-117.070-70.097-148.867 7.949-5.059 13.008-13.73 14.453-23.125l135.136-28.906c2.168 4.336 5.781 8.672 9.394 12.285v358.436h-32.519c-7.227 0-13.008 5.781-13.008 13.008v32.519h-33.965c-7.227 0-13.008 5.781-13.008 13.008v48.418c0 7.227 5.781 13.008 13.008 13.008h226.913c7.227 0 13.008-5.781 13.008-13.008v-48.418c-1.445-5.781-7.227-11.562-13.73-11.562zM296.288 349.042c4.336 0 8.672 3.613 8.672 8.672 0 4.336-3.613 8.672-8.672 8.672-4.336 0-8.672-3.613-8.672-8.672 0.723-5.059 4.336-8.672 8.672-8.672zM296.288 633.044c-42.637 0-78.047-31.797-84.55-72.265h169.101c-6.504 40.469-41.914 72.265-84.55 72.265zM359.881 534.764h-127.187c7.949-31.074 38.301-88.164 63.594-131.523 21.68 36.855 55.644 98.281 63.594 131.523zM508.025 288.339c13.008 0 23.125 10.117 23.125 23.125s-10.117 23.125-23.125 23.125-23.125-10.117-23.125-23.125 10.84-23.125 23.125-23.125zM516.697 359.159v345.428h-17.344v-345.428c2.891 0.723 5.781 0.723 8.672 0.723s5.781-0 8.672-0.723zM454.549 729.88h107.675v19.512h-107.675v-19.512zM609.197 797.809h-201.62v-22.402h201.62v22.402z","M670.622 276.776c-1.445-7.227-8.672-11.562-15.176-10.117l-9.394 2.168c-7.227 1.445-11.562 8.672-10.117 15.176 1.445 5.781 6.504 10.117 12.285 10.117 0.723 0 1.445 0 2.891 0l9.394-2.168c7.227-1.445 11.562-7.949 10.117-15.176z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-74"],"grid":0},"attrs":[{},{},{}],"properties":{"order":78,"id":12,"name":"justice","prevSize":32,"code":59721},"setIdx":0,"setId":3,"iconIdx":13},{"icon":{"paths":["M448.768 320.135h324.471c7.227 0 12.285-5.781 12.285-12.285 0-7.227-5.781-12.285-12.285-12.285h-324.471c-7.227 0-12.285 5.781-12.285 12.285s5.059 12.285 12.285 12.285z","M278.222 317.968c0.723 0.723 1.445 0.723 2.168 1.445 0.723 0 1.445 0.723 2.168 0.723s1.445 0 2.168 0c3.613 0 6.504-1.445 8.672-3.613s3.613-5.781 3.613-8.672c0-0.723 0-1.445 0-2.168s-0.723-1.445-0.723-2.168c0-0.723-0.723-1.445-1.445-2.168s-0.723-1.445-1.445-2.168c-2.891-2.891-7.227-4.336-11.562-3.613-0.723 0-1.445 0.723-2.168 0.723s-1.445 0.723-2.168 1.445c-0.723 0.723-1.445 0.723-2.168 1.445s-1.445 1.445-1.445 2.168c-0.723 0.723-0.723 1.445-1.445 2.168 0 0.723-0.723 1.445-0.723 2.168s0 1.445 0 2.168c0 3.613 1.445 6.504 3.613 8.672 1.445 0.723 2.168 0.723 2.891 1.445z","M323.749 312.186c0 0.723 0.723 1.445 1.445 2.168s0.723 1.445 1.445 2.168c0.723 0.723 1.445 1.445 2.168 1.445 0.723 0.723 1.445 0.723 2.168 1.445 0.723 0 1.445 0.723 2.168 0.723s1.445 0 2.168 0c3.613 0 6.504-1.445 8.672-3.613 0.723-0.723 1.445-1.445 1.445-2.168 0.723-0.723 0.723-1.445 1.445-2.168 0-0.723 0.723-1.445 0.723-2.168s0-1.445 0-2.168c0-0.723 0-1.445 0-2.168s-0.723-1.445-0.723-2.168c0-0.723-0.723-1.445-1.445-2.168s-0.723-1.445-1.445-2.168c-0.723-0.723-1.445-1.445-2.168-1.445-0.723-0.723-1.445-0.723-2.168-1.445-0.723 0-1.445-0.723-2.168-0.723-1.445 0-3.613 0-5.059 0-0.723 0-1.445 0.723-2.168 0.723s-1.445 0.723-2.168 1.445c-0.723 0.723-1.445 0.723-2.168 1.445s-1.445 1.445-1.445 2.168c-0.723 0.723-0.723 1.445-1.445 2.168 0 0.723-0.723 1.445-0.723 2.168s0 1.445 0 2.168c0 0.723 0 1.445 0 2.168 0.723 0.723 1.445 1.445 1.445 2.168z","M373.612 312.186c0 0.723 0.723 1.445 1.445 2.168s0.723 1.445 1.445 2.168c0.723 0.723 1.445 1.445 2.168 1.445 0.723 0.723 1.445 0.723 2.168 1.445 0.723 0 1.445 0.723 2.168 0.723s1.445 0 2.168 0c0.723 0 1.445 0 2.168 0s1.445-0.723 2.168-0.723c0.723 0 1.445-0.723 2.168-1.445s1.445-0.723 2.168-1.445c0.723-0.723 1.445-1.445 1.445-2.168 0.723-0.723 0.723-1.445 1.445-2.168 0-0.723 0.723-1.445 0.723-2.168s0-1.445 0-2.168c0-0.723 0-1.445 0-2.168s-0.723-1.445-0.723-2.168c0-0.723-0.723-1.445-1.445-2.168s-0.723-1.445-1.445-2.168c-0.723-0.723-1.445-1.445-2.168-1.445 0-0.723-0.723-1.445-1.445-1.445s-1.445-0.723-2.168-0.723c-1.445 0-3.613 0-5.059 0-0.723 0-1.445 0.723-2.168 0.723s-1.445 0.723-2.168 1.445c-0.723 0.723-1.445 0.723-2.168 1.445s-1.445 1.445-1.445 2.168c-0.723 0.723-0.723 1.445-1.445 2.168 0 0.723-0.723 1.445-0.723 2.168s0 1.445 0 2.168c0 0.723 0 1.445 0 2.168 0.723 0.723 0.723 1.445 0.723 2.168z","M547.771 507.303h189.335c7.227 0 12.285-5.781 12.285-12.285s-5.781-12.285-12.285-12.285h-189.335c-7.227 0-12.285 5.781-12.285 12.285s5.059 12.285 12.285 12.285z","M737.107 532.596h-25.293c-7.227 0-12.285 5.781-12.285 12.285s5.781 12.285 12.285 12.285h25.293c7.227 0 12.285-5.781 12.285-12.285s-5.781-12.285-12.285-12.285z","M673.513 540.545c0-0.723-0.723-1.445-1.445-2.168s-0.723-1.445-1.445-2.168c-0.723-0.723-1.445-1.445-2.168-1.445-0.723-0.723-1.445-0.723-2.168-1.445-0.723 0-1.445-0.723-2.168-0.723-1.445 0-3.613 0-5.059 0-0.723 0-1.445 0.723-2.168 0.723s-1.445 0.723-2.168 1.445c-0.723 0.723-1.445 0.723-2.168 1.445s-1.445 1.445-1.445 2.168c-0.723 0.723-0.723 1.445-1.445 2.168 0 0.723-0.723 1.445-0.723 2.168s0 1.445 0 2.168c0 0.723 0 1.445 0 2.168s0.723 1.445 0.723 2.168c0 0.723 0.723 1.445 1.445 2.168s0.723 1.445 1.445 2.168c0.723 0.723 1.445 1.445 2.168 1.445 0.723 0.723 1.445 0.723 2.168 1.445 0.723 0 1.445 0.723 2.168 0.723s1.445 0 2.168 0 1.445 0 2.168 0 1.445-0.723 2.168-0.723c0.723 0 1.445-0.723 2.168-1.445s1.445-0.723 2.168-1.445c0.723-0.723 1.445-1.445 1.445-2.168 0.723-0.723 0.723-1.445 1.445-2.168 0-0.723 0.723-1.445 0.723-2.168s0-1.445 0-2.168c0-0.723 0-1.445 0-2.168 0.723-0.723 0-1.445 0-2.168z","M611.365 532.596h-63.594c-7.227 0-12.285 5.781-12.285 12.285s5.781 12.285 12.285 12.285h63.594c7.227 0 12.285-5.781 12.285-12.285s-5.059-12.285-12.285-12.285z","M807.927 231.972h-555.721c-23.125 0-42.637 17.344-42.637 38.301v424.198c0 20.957 18.789 38.301 42.637 38.301h261.601l122.128 121.406c10.84 10.84 24.57 16.621 39.746 16.621h0.723c15.176 0 28.906-5.781 39.023-15.898l0.723-0.723c21.68-21.68 21.68-57.090-0.723-79.492v0c0 0 0 0 0 0l-42.637-42.637h135.136c23.125 0 42.637-17.344 42.637-38.301v-423.475c0-20.957-19.512-38.301-42.637-38.301zM252.206 257.265h555.721c9.394 0 17.344 5.781 17.344 13.008v86.718h-590.408v-86.718c0-7.227 7.949-13.008 17.344-13.008zM774.685 432.147v225.468h-176.327l-49.863-49.863h188.613c7.227 0 12.285-5.781 12.285-12.285s-5.781-12.285-12.285-12.285h-189.335c-6.504 0-12.285 5.059-12.285 12.285l-25.293-25.293v-137.304h264.491zM484.9 544.158l-32.519-32.519c0 0 0 0 0 0s0 0 0 0v0l-2.891-2.891c-5.059-5.059-10.84-8.672-18.066-10.84l-65.761-23.125c-8.672-2.891-18.066-0.723-25.293 5.781-6.504 6.504-8.672 15.898-5.781 25.293l23.125 65.761c2.168 6.504 6.504 13.008 11.562 18.066l68.652 68.652h-152.48v-226.191h199.452v112.011zM403.241 542.713c0 0 0 0 0 0v0l-20.234 20.957c0 0 0-0.723-0.723-0.723 0 0 0 0 0 0l-6.504-19.512 28.906-28.906 18.789 6.504c0 0 0 0 0 0s0.723 0 0.723 0.723l-20.957 20.957zM359.881 498.631l18.789 6.504-12.285 12.285-6.504-18.789zM477.674 661.228c0 0 0 0 0 0l-78.047-78.769 13.008-13.008 245.702 245.702-13.008 13.008-117.070-117.070c0 0 0 0 0 0l-50.586-49.863zM698.806 836.833l-0.723 0.723c-5.781 5.781-13.73 8.672-21.68 8.672-4.336 0-7.949-0.723-11.562-2.168l40.469-40.469c4.336 10.84 2.168 23.848-6.504 33.242zM675.681 797.087l-245.702-245.702 13.73-13.73 140.195 140.195c0 0 0 0 0 0l49.863 49.863c0 0 0 0 0 0l54.922 54.922-13.008 14.453zM807.927 707.478h-159.706l-25.293-25.293h164.042c7.227 0 12.285-5.781 12.285-12.285v-250.038c0-7.227-5.781-12.285-12.285-12.285h-513.807c-7.227 0-12.285 5.781-12.285 12.285v250.038c0 7.227 5.781 12.285 12.285 12.285h190.781l25.293 25.293h-237.030c-9.394 0-17.344-5.781-17.344-13.008v-312.186h590.408v312.186c0 7.227-7.949 13.008-17.344 13.008z"],"attrs":[{},{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-75"],"grid":0},"attrs":[{},{},{},{},{},{},{},{},{}],"properties":{"order":79,"id":13,"name":"compromise","prevSize":32,"code":59722},"setIdx":0,"setId":3,"iconIdx":14},{"icon":{"paths":["M842.614 645.33l-44.082-12.285c-2.168-0.723-2.891-2.168-2.891-4.336v-14.453c3.613-2.168 7.227-5.059 10.117-8.672 15.176-15.176 23.848-34.687 23.848-56.367v-20.234l4.336-8.672c4.336-9.394 7.227-19.512 7.227-30.351v-54.922c0-5.781-5.059-10.84-10.84-10.84h-101.894c-36.855 0-67.207 30.351-67.207 67.207v0.723c0 8.672 2.168 17.344 5.781 25.293l5.781 10.84v17.344c0 27.461 13.73 52.031 33.965 67.207v15.176c0 2.168 0 3.613-8.672 5.781l-21.68 5.781-62.148-22.402c0-2.891-0.723-5.781-2.891-7.949l-19.512-20.957v-34.687c2.168-1.445 4.336-3.613 6.504-5.059 24.57-23.125 39.023-56.367 39.023-90.332v-28.183c7.227-16.621 11.562-33.965 11.562-51.308v-113.457c0-5.781-5.059-10.84-10.84-10.84h-158.984c-55.644 0-101.171 45.527-101.171 101.171v22.402c0 18.066 3.613 35.41 11.562 51.308v23.848c0 39.746 17.344 75.156 45.527 99.004v35.41l-19.512 20.957c-2.168 2.168-2.891 5.059-2.891 7.949l-65.039 23.848c-5.059 1.445-9.394 4.336-13.008 7.227l-10.84-4.336c30.351-13.008 40.469-31.797 40.469-33.242 1.445-2.891 1.445-6.504 0-9.394-7.949-15.176-8.672-43.359-9.394-65.761 0-7.227-0.723-14.453-0.723-20.957-3.613-50.586-42.637-88.886-90.332-88.886s-85.996 38.301-90.332 88.886c0 6.504 0 13.73-0.723 21.68-0.723 22.402-1.445 50.586-9.394 65.761-1.445 2.891-1.445 6.504 0 9.394 0.723 0.723 10.117 19.512 40.469 32.519l-28.183 14.453c-15.176 7.949-24.57 23.125-24.57 39.746v78.047c0 5.781 5.059 10.84 10.84 10.84s10.84-5.059 10.84-10.84v-78.047c0-8.672 5.059-16.621 13.008-20.957l35.41-18.066 12.285 11.562c8.672 7.949 19.512 12.285 31.074 12.285 10.84 0 22.402-4.336 31.074-12.285l12.285-11.562 11.562 5.781c-5.781 8.672-8.672 18.789-8.672 29.629v81.66c0 5.781 5.059 10.84 10.84 10.84s10.84-5.059 10.84-10.84v-80.937c0-14.453 9.394-27.461 23.125-32.519l68.652-25.293 28.906 42.637c3.613 5.781 9.394 8.672 15.898 9.394 0.723 0 1.445 0 2.168 0 5.781 0 11.562-2.168 15.176-6.504l17.344-17.344v110.566c0 5.781 5.059 10.84 10.84 10.84s10.84-5.059 10.84-10.84v-109.843l17.344 17.344c4.336 4.336 9.394 6.504 15.176 6.504 0.723 0 1.445 0 2.168 0 6.504-0.723 12.285-4.336 15.898-9.394l28.906-42.637 68.652 25.293c13.73 5.059 23.125 18.066 23.125 32.519v81.66c0 5.781 5.059 10.84 10.84 10.84s10.84-5.059 10.84-10.84v-82.382c0-14.453-5.781-28.906-15.898-39.023l2.891-0.723c2.891-0.723 6.504-1.445 10.117-3.613l26.738 26.738v97.558c0 5.781 5.059 10.84 10.84 10.84s10.84-5.059 10.84-10.84v-97.558l26.738-26.738c1.445 0.723 2.891 1.445 4.336 1.445l44.082 12.285c10.117 2.891 17.344 12.285 17.344 22.402v87.441c0 5.781 5.059 10.84 10.84 10.84s10.84-5.059 10.84-10.84v-86.718c-2.891-19.512-15.898-37.578-35.41-42.637zM218.964 626.541c-19.512-7.227-29.629-16.621-33.965-21.68 2.891-7.227 5.059-15.898 5.781-25.293 5.781 13.73 15.898 26.016 28.183 34.687v12.285zM279.667 655.447c-9.394 8.672-23.125 8.672-32.519 0l-10.117-9.394c1.445-2.891 2.891-6.504 2.891-10.117v-11.562c7.227 2.168 15.176 3.613 23.125 3.613s15.898-1.445 23.125-3.613v11.562c0 3.613 0.723 7.227 2.891 10.117l-9.394 9.394zM263.769 606.306c-31.797 0-57.090-26.016-57.090-57.090 0-5.781-5.059-10.84-10.84-10.84-0.723 0-1.445 0-1.445 0 0-0.723 0-2.168 0-2.891 0-7.227 0.723-14.453 0.723-20.234 1.445-18.789 8.672-36.855 21.68-49.14 12.285-13.008 29.629-20.234 47.695-20.234s34.687 7.227 47.695 20.234c12.285 13.008 20.234 30.351 21.68 49.14 0.723 5.781 0.723 13.008 0.723 20.234 0 0.723 0 1.445 0 2.168-11.562-18.066-29.629-31.074-52.754-38.301-20.957-6.504-39.746-6.504-40.469-6.504-2.891 0-5.059 1.445-7.227 2.891l-18.789 19.512c-4.336 4.336-3.613 10.84 0 15.176 4.336 4.336 10.84 3.613 15.176 0l15.898-16.621c13.73 0.723 57.812 5.781 75.156 43.359-5.059 28.906-29.629 49.14-57.812 49.14zM308.573 626.541v-13.008c12.285-8.672 22.402-20.234 28.183-34.687 1.445 9.394 2.891 18.066 5.781 25.293-4.336 5.781-14.453 15.176-33.965 22.402zM410.467 454.549v-26.016c0-1.445 0-2.891-0.723-4.336-6.504-14.453-10.117-28.906-10.117-44.805v-22.402c0-44.082 36.133-80.215 80.215-80.215h148.144v102.617c0 15.176-3.613 30.351-10.117 44.805-0.723 1.445-0.723 2.891-0.723 4.336v30.351c0 28.906-11.562 55.644-32.519 75.156-2.891 2.168-5.059 5.059-7.949 7.227 0 0 0 0 0 0-19.512 15.176-43.359 22.402-68.652 20.234-55.644-4.336-97.558-50.586-97.558-106.953zM470.447 667.732c0 0-0.723 0 0 0-0.723 0-0.723 0-1.445 0l-33.242-49.14 10.84-10.84 49.863 33.965-26.016 26.016zM513.084 627.263l-57.090-39.023v-19.512c15.176 7.949 31.797 13.008 49.14 14.453 2.891 0 5.781 0 8.672 0 20.234 0 39.746-5.059 57.090-13.73v19.512l-57.812 38.301zM557.888 667.732c-0.723 0-0.723 0 0 0-0.723 0.723-0.723 0-1.445 0l-26.738-26.738 49.863-33.965 10.84 10.84-32.519 49.863zM751.56 659.060l-23.848-23.848c0.723-2.168 0.723-4.336 0.723-6.504v-4.336c6.504 2.168 13.73 3.613 20.957 3.613 0.723 0 1.445 0 2.168 0 7.949 0 15.898-1.445 23.125-3.613v4.336c0 2.168 0 4.336 0.723 6.504l-23.848 23.848zM791.306 590.408c-11.562 10.84-26.016 16.621-41.914 15.898-30.351-0.723-55.644-28.183-55.644-59.98v-19.512c0-1.445-0.723-3.613-1.445-5.059l-6.504-13.008c-2.168-5.059-3.613-10.117-3.613-15.898v-0.723c0-25.293 20.957-46.25 46.25-46.25h91.777v44.082c0 7.227-1.445 14.453-5.059 20.957l-5.059 10.84c-0.723 1.445-1.445 2.891-1.445 5.059v22.402c0 15.176-6.504 30.351-17.344 41.191z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-76"],"grid":0},"attrs":[{}],"properties":{"order":80,"id":14,"name":"fraternity","prevSize":32,"code":59723},"setIdx":0,"setId":3,"iconIdx":15},{"icon":{"paths":["M535.172 897.841c-198.523-0.752-359.166-161.859-359.166-360.486 0-199.092 161.396-360.489 360.489-360.489s360.489 161.396 360.489 360.489c0 0.465-0.001 0.93-0.003 1.395l0-0.072c-1.474 198.675-162.873 359.164-361.755 359.164-0.019 0-0.038-0-0.057-0l0.003 0zM535.172 241.69c-1.179-0.017-2.571-0.027-3.964-0.027-163.304 0-295.688 132.384-295.688 295.688s132.384 295.688 295.688 295.688c161.907 0 293.421-130.129 295.659-291.504l0.002-0.211v-1.984c0.016-1.152 0.026-2.511 0.026-3.873 0-160.103-128.64-290.161-288.199-292.451l-0.216-0.002c-0.661-1.323-1.984-1.323-3.307-1.323z","M456.427 372.331v330.060l228.859-166.022z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-54"],"grid":0},"attrs":[{},{}],"properties":{"order":56,"id":15,"name":"play","prevSize":32,"code":59676},"setIdx":0,"setId":3,"iconIdx":16},{"icon":{"paths":["M797.291 228.795c-28.662-28.588-68.218-46.264-111.903-46.264s-83.242 17.677-111.907 46.268l0.003-0.003-111.903 111.903c-4.405 4.405-7.13 10.492-7.13 17.214 0 13.445 10.899 24.344 24.344 24.344 6.723 0 12.809-2.725 17.214-7.13l111.903-111.903c19.811-19.731 47.137-31.93 77.312-31.93 60.51 0 109.563 49.053 109.563 109.563 0 30.178-12.201 57.507-31.939 77.321l0.004-0.004-146.319 146.356c-19.846 19.792-47.235 32.030-77.481 32.030s-57.635-12.238-77.484-32.032l0.003 0.003c-4.405-4.405-10.492-7.13-17.214-7.13-13.445 0-24.344 10.899-24.344 24.344 0 6.723 2.725 12.809 7.13 17.214l-0-0c28.659 28.593 68.217 46.273 111.903 46.273s83.244-17.681 111.906-46.276l-0.003 0.003 146.343-146.344c28.55-28.681 46.2-68.234 46.2-111.91s-17.65-83.228-46.206-111.915l0.006 0.006z","M504.616 676.421l-94.689 94.689c-19.815 19.752-47.156 31.965-77.349 31.965-60.512 0-109.567-49.055-109.567-109.567 0-30.193 12.213-57.534 31.968-77.351l-0.003 0.003 137.737-137.737c19.871-19.728 47.246-31.92 77.469-31.92s57.598 12.192 77.476 31.927l-0.007-0.006c4.403 4.39 10.479 7.105 17.189 7.105 13.445 0 24.344-10.899 24.344-24.344 0-6.71-2.715-12.786-7.106-17.189l0.001 0.001c-28.661-28.59-68.218-46.269-111.903-46.269s-83.243 17.679-111.907 46.272l0.003-0.003-137.737 137.749c-28.542 28.622-46.191 68.12-46.191 111.74 0 87.4 70.851 158.251 158.251 158.251 43.623 0 83.124-17.651 111.75-46.2l-0.004 0.003 94.689-94.689c4.406-4.405 7.132-10.491 7.132-17.214 0-13.443-10.897-24.34-24.34-24.34-6.72 0-12.804 2.723-17.208 7.126l0-0z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-55"],"grid":0},"attrs":[{},{}],"properties":{"order":60,"id":16,"name":"link","prevSize":32,"code":59702},"setIdx":0,"setId":3,"iconIdx":17},{"icon":{"paths":["M558.182 254.762c-5.583-2.795-12.164-4.432-19.127-4.432-17.057 0-31.821 9.819-38.948 24.113l-0.114 0.252c-0.135 0.277-0.267 0.554-0.397 0.833l-95.77 257.962-114.954-260.553c-7.517-13.376-21.616-22.265-37.791-22.265-23.861 0-43.205 19.343-43.205 43.205 0 6.876 1.606 13.377 4.464 19.147l-0.113-0.252 146.752 341.577-21.285 57.348c-6.321 16.571-22.069 28.135-40.522 28.17l-0.004 0h-31.942c-23.861 0-43.205 19.343-43.205 43.205s19.343 43.205 43.205 43.205v0h22.265c0.153 0.001 0.334 0.001 0.515 0.001 54.389 0 100.909-33.687 119.836-81.334l0.305-0.871 169.363-431.328c2.879-5.632 4.566-12.285 4.566-19.332 0-16.814-9.605-31.385-23.627-38.525l-0.245-0.113z","M826.888 480.637c-69.671 12.686-129.166 27.867-187.042 46.644l10.103-2.834c-6.011 1.822-10.312 7.313-10.312 13.809 0 7.457 5.667 13.59 12.93 14.327l0.061 0.005c5.904 0.605 145.053 14.402 174.26 14.402 23.861-0 43.205-19.343 43.205-43.205s-19.343-43.205-43.205-43.205v0z","M596.462 451.834c1.095-0.006 2.158-0.132 3.18-0.364l-0.098 0.019c5.040-1.095 124.026-27.507 164.438-60.487 11.914-8.753 19.56-22.711 19.56-38.455 0-1.551-0.074-3.084-0.219-4.597l0.015 0.193c-0.584-10.155-4.624-19.268-10.949-26.278l0.034 0.038c-8.168-8.278-19.511-13.405-32.051-13.405-10.216 0-19.638 3.403-27.193 9.137l0.112-0.081c-23.043 14.776-116.020 99.602-126.562 109.222-2.902 2.644-4.715 6.439-4.715 10.657 0 7.954 6.448 14.401 14.401 14.401 0.017 0 0.034-0 0.051-0l-0.003 0z","M599.63 596.224c-0.987-0.245-2.121-0.386-3.288-0.386-5.481 0-10.236 3.105-12.603 7.652l-0.037 0.079c-1.062 1.958-1.686 4.287-1.686 6.762 0 4.147 1.753 7.885 4.558 10.513l0.008 0.007c10.542 9.736 103.692 95.368 126.735 110.085 8.104 5.46 18.051 8.773 28.763 8.928l0.040 0c0.158 0.002 0.346 0.004 0.533 0.004 11.849 0 22.504-5.111 29.881-13.248l0.030-0.034c6.297-6.97 10.337-16.084 10.911-26.127l0.005-0.113c0.126-1.3 0.198-2.81 0.198-4.337 0-15.745-7.643-29.705-19.422-38.372l-0.132-0.093c-40.526-32.893-159.454-60.198-164.494-61.321z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-56"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":61,"id":17,"name":"ym","prevSize":32,"code":59703},"setIdx":0,"setId":3,"iconIdx":18},{"icon":{"paths":["M862.413 518.087c-1.694 175.298-144.193 316.751-319.73 316.751-56.408 0-109.405-14.607-155.414-40.245l1.626 0.832-176.73 56.16 57.619-169.946c-28.762-46.465-45.807-102.812-45.807-163.14 0-0.145 0-0.29 0-0.434l-0 0.023c1.403-175.236 143.784-316.75 319.218-316.75s317.815 141.515 319.217 316.617l0.001 0.133zM543.199 251.782c-0.219-0.001-0.479-0.001-0.738-0.001-147.346 0-266.882 119.067-267.641 266.234l-0 0.072c-0 0.046-0 0.099-0 0.153 0 58.688 19.186 112.896 51.628 156.691l-0.504-0.713-33.531 98.903 103.137-32.78c41.816 28.47 93.437 45.457 149.026 45.457 147.466 0 267.011-119.545 267.011-267.011s-119.545-267.011-267.011-267.011c-0.484 0-0.967 0.001-1.451 0.004l0.074-0zM704.395 591.038c-1.972-3.23-7.182-5.18-14.999-9.060-7.832-3.88-46.312-22.672-53.465-25.251-7.174-2.587-12.405-3.887-17.615 3.88-5.209 7.774-20.208 25.251-24.782 30.432-4.566 5.195-9.125 5.845-16.957 1.958-24.211-9.711-45.042-22.712-63.142-38.728l0.227 0.197c-16.831-15.462-31.268-33.155-42.939-52.692l-0.592-1.069c-4.559-7.767-0.477-11.965 3.432-15.83 3.526-3.482 7.832-9.067 11.741-13.597 3.088-3.727 5.712-8 7.688-12.615l0.129-0.339c0.906-1.813 1.436-3.95 1.436-6.21 0-2.736-0.777-5.29-2.121-7.454l0.035 0.060c-1.951-3.88-17.615-42.086-24.131-57.634-6.517-15.534-13.027-12.947-17.6-12.947-4.559 0-9.783-0.65-14.999-0.65-8.311 0.218-15.717 3.915-20.847 9.681l-0.026 0.029c-16.877 15.876-27.388 38.355-27.388 63.288 0 0.517 0.005 1.032 0.013 1.546l-0.001-0.077c0 38.206 28.026 75.118 31.949 80.291 3.909 5.173 54.115 86.122 133.662 117.211 79.554 31.075 79.554 20.707 93.903 19.406 14.334-1.293 46.283-18.778 52.829-36.898 6.503-18.149 6.503-33.69 4.559-36.927z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-57"],"grid":0},"attrs":[{}],"properties":{"order":59,"id":18,"name":"wp","prevSize":32,"code":59704},"setIdx":0,"setId":3,"iconIdx":19},{"icon":{"paths":["M726.364 646.996v-77.66l-32.773 12.751-0.096-0.216-0.781-1.418c-12.522-19.232-32.221-32.892-55.215-37.222l-0.524-0.082-78.862-14.349v-6.225c29.547-17.32 50.78-46.111 57.687-80.107l0.131-0.774c22.018-4.709 38.294-23.986 38.325-47.071l0-0.004v-118.701c0-0.025 0-0.055 0-0.085 0-33.948-22.446-62.654-53.307-72.086l-0.534-0.14-6.009-6.009c-26.779-26.776-63.772-43.337-104.633-43.337-81.726 0-147.979 66.25-147.983 147.976l-0 0v92.382c0.031 23.088 16.307 42.365 38.009 47.017l0.316 0.057c7.040 34.768 28.272 63.56 57.252 80.573l0.566 0.307v6.225l-78.849 14.337c-23.502 4.413-43.19 18.057-55.517 36.943l-0.198 0.324-0.721 1.755-32.965-12.823v77.66c-19.902 0.025-36.028 16.152-36.053 36.051l-0 0.002v48.072c0.025 19.902 16.152 36.029 36.051 36.054l0.002 0v44.274l228.34 88.812 228.34-88.812v-44.274c19.902-0.025 36.029-16.152 36.054-36.051l0-0.002v-48.072c-0.025-19.902-16.152-36.029-36.051-36.054l-0.002-0zM580.635 557.33l52.038 9.458c15.736 3.021 29.015 11.816 37.818 24.049l0.122 0.179-116.273 45.211zM462.992 533.595c10.479 3.324 22.532 5.24 35.032 5.24s24.553-1.916 35.88-5.469l-0.848 0.229-35.032 26.271zM479.733 576.186l-24.529 24.517-15.911-47.723 7.655-1.382zM549.1 551.61l7.655 1.382-15.912 47.723-24.529-24.517zM618.203 415.314v-41.389c7.231 4.182 12.018 11.88 12.018 20.695s-4.787 16.512-11.903 20.634l-0.115 0.061zM377.845 415.314c-7.231-4.182-12.018-11.88-12.018-20.695s4.787-16.512 11.903-20.634l0.115-0.061zM377.845 334.53v13.724c-4.563 1.211-8.56 2.913-12.238 5.096l0.22-0.121v-50.992c0.001-68.451 55.492-123.941 123.943-123.941 34.228 0 65.215 13.874 87.645 36.306l0 0 10.6 10.612 3.233 0.793c22.558 5.745 38.974 25.878 38.974 49.846 0 0.023-0 0.045-0 0.068l0-0.004v77.311c-3.458-2.068-7.456-3.771-11.688-4.9l-0.33-0.075v-13.724h-38.109c-33.896-0.079-63.991-16.279-83.036-41.336l-0.188-0.258-9.554-12.763-23.88 23.892c-18.729 18.82-44.652 30.466-73.295 30.466-0.098 0-0.196-0-0.294-0l0.015 0zM401.881 418.655v-60.642c30.904-2.916 58.183-16.488 78.544-36.95l0.005-0.005 4.675-4.675c23.571 25.883 57.378 42.090 94.973 42.183l0.017 0h14.073v60.090c-0.048 53.063-43.074 96.060-96.143 96.060s-96.096-42.997-96.143-96.056l-0-0.004zM363.375 566.788l52.038-9.458 26.295 78.898-116.297-45.223c8.932-12.413 22.221-21.206 37.587-24.156l0.377-0.060zM257.666 731.121v-48.072c0.007-6.635 5.383-12.011 12.017-12.018l0.001-0c19.912 0 36.054 16.142 36.054 36.054s-16.142 36.054-36.054 36.054v0c-6.635-0.007-12.011-5.383-12.018-12.017l-0-0.001zM486.006 869.784l-192.286-74.763v-32.941c21.397-9.475 36.054-30.523 36.054-54.994s-14.657-45.518-35.671-54.842l-0.382-0.151v-47.615l192.286 74.775zM450.325 639.593l47.699-47.711 47.699 47.699-47.699 18.556zM702.328 795.008l-192.286 74.764v-190.52l192.286-74.775v47.615c-21.397 9.475-36.054 30.523-36.054 54.994s14.657 45.518 35.671 54.842l0.382 0.151zM738.382 731.121c-0.007 6.635-5.383 12.011-12.017 12.018l-0.001 0c-19.912 0-36.054-16.142-36.054-36.054s16.142-36.054 36.054-36.054v0c6.635 0.007 12.011 5.383 12.018 12.017l0 0.001z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-58"],"grid":0},"attrs":[{}],"properties":{"order":62,"id":19,"name":"read","prevSize":32,"code":59705},"setIdx":0,"setId":3,"iconIdx":20},{"icon":{"paths":["M882.977 203.779h-660.274c-32.322 0.063-58.507 26.253-58.562 58.571l-0 0.005v375.904c0.038 32.338 26.233 58.546 58.563 58.604l0.006 0h169.512v-32.259h-169.498c-14.523-0.062-26.278-11.822-26.332-26.341l-0-0.005v-375.805c0.11-14.512 11.815-26.254 26.302-26.423l0.016-0h660.253c14.513 0.067 26.261 11.812 26.332 26.318l0 0.007v376.426c-0.059 14.524-11.821 26.281-26.341 26.332l-0.005 0h-169.476v32.258l170.605-0.007c31.85-0.514 57.473-26.454 57.473-58.378 0-0.256-0.002-0.511-0.005-0.766l0 0.039v-375.91c-0.059-32.323-26.246-58.51-58.563-58.569l-0.006-0z","M690.788 680.099c0-0.043 0-0.093 0-0.143 0-76.015-61.623-137.638-137.638-137.638s-137.638 61.623-137.638 137.638c0 9.531 0.969 18.836 2.813 27.821l-0.152-0.888-109.060 109.067h108.149v108.191l109.043-109.076c8.064 1.697 17.331 2.669 26.824 2.669 9.489 0 18.752-0.971 27.693-2.819l-0.881 0.152 109.041 109.073v-108.191h108.156l-109.023-109.023c1.689-8.062 2.662-17.331 2.673-26.825l0-0.009zM447.686 680.099c0.064-56.667 44.758-102.875 100.819-105.368l0.225-0.008 4.396 0.014c58.205 0.016 105.383 47.204 105.383 105.411 0 58.217-47.194 105.411-105.411 105.411s-105.411-47.194-105.411-105.411c0-0.017 0-0.035 0-0.052l-0 0.003zM386.951 783.809l42.789-43.148c13.737 27.43 35.462 49.148 62.101 62.512l0.797 0.362-43.224 43.224v-62.95zM676.536 740.685l42.765 43.124h-62.464v62.95l-43.217-43.217c27.439-13.723 49.169-35.433 62.554-62.061l0.362-0.796z","M553.591 767.045c48.382 0 87.603-39.221 87.603-87.603 0-0.020-0-0.040-0-0.060l0 0.003c-0.929-42.333-31.281-77.314-71.37-85.356l-0.569-0.095-23.086-4.417 16.623 16.623c10.623 10.623 17.193 25.298 17.193 41.508 0 32.42-26.282 58.702-58.702 58.702-16.21 0-30.886-6.57-41.508-17.193l-16.51-16.51 4.304 22.952c7.921 40.894 43.402 71.364 86.014 71.445l0.009 0z","M442.585 561.31c28.354-28.159 67.42-45.562 110.551-45.562s82.198 17.403 110.56 45.571l-0.009-0.009 5.108 5.094 17.484-17.491 4.904-5.32-5.115-5.108c-34.061-33.931-81.046-54.909-132.932-54.909-51.994 0-99.068 21.066-133.152 55.129l0.001-0.001-5.094 5.101 22.585 22.599z","M388.962 396.151h331.89v32.146h-331.89v-32.146z","M332.298 321.785h444.019v32.153h-444.019v-32.153z"],"attrs":[{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-59"],"grid":0},"attrs":[{},{},{},{},{},{}],"properties":{"order":63,"id":20,"name":"certificate","prevSize":32,"code":59706},"setIdx":0,"setId":3,"iconIdx":21},{"icon":{"paths":["M895.127 458.265h-167.213v-32.292c-0.009-4.858-2.665-9.093-6.603-11.34l-0.064-0.034-179.11-100.668v-51.249h35.43v19.48c0 7.22 5.853 13.073 13.074 13.074l106.812 0c7.218-0.002 13.069-5.854 13.069-13.072 0-1.595-0.286-3.124-0.809-4.537l0.029 0.091-10.72-30.462 10.851-29.808c0.493-1.322 0.778-2.85 0.778-4.444 0-7.219-5.85-13.071-13.068-13.075l-48.635-0v-18.957c-0-7.22-5.853-13.073-13.074-13.074l-93.738-0v-15.95c-0.035-7.194-5.875-13.012-13.074-13.012s-13.039 5.818-13.074 13.009l-0 0.003v161.983l-179.11 100.537c-4.002 2.281-6.659 6.516-6.668 11.373l-0 0.001v32.292h-167.213c-7.22 0-13.073 5.853-13.074 13.074l-0 0v342.008c0 7.22 5.853 13.073 13.074 13.074l732.128 0c7.22-0 13.073-5.853 13.074-13.074l0-0v-341.878c-0-7.22-5.853-13.073-13.074-13.074l-0-0zM648.949 249.609l-0.523-0.523v-22.487h29.808l-5.36 16.734c-0.508 1.341-0.803 2.891-0.803 4.51s0.294 3.17 0.833 4.601l-0.030-0.090 6.145 16.734h-75.305v-6.406h32.161c7.22-0 13.073-5.853 13.074-13.074l0-0zM542.137 194.045h80.665v42.49h-80.665zM330.212 800.143h-154.139v-315.73h154.139zM515.989 800.143h-68.637v-149.302h68.637zM610.774 800.143h-68.637v-149.302h68.637zM702.29 800.143h-65.369v-162.376c-0-7.22-5.853-13.074-13.074-13.074l-189.569-0c-7.22 0-13.073 5.853-13.074 13.074l-0 0v162.376h-65.369v-366.064l173.227-97.53 172.704 97.007 0.523 37.652zM882.053 800.143h-154.139v-315.73h154.139z","M529.063 376.555c-30.254-0-54.779 24.525-54.779 54.779s24.525 54.779 54.779 54.779c30.254 0 54.779-24.525 54.779-54.779 0-0.046-0-0.092-0-0.138l0 0.007c-0.148-30.168-24.601-54.575-54.772-54.648l-0.007-0zM529.063 459.965c-15.813-0-28.631-12.819-28.631-28.632s12.819-28.632 28.632-28.632c15.813 0 28.632 12.819 28.632 28.632 0 0.046-0 0.092-0 0.138l0-0.007h0.131c-0.074 15.757-12.865 28.501-28.632 28.501-0.046 0-0.092-0-0.138-0l0.007 0z","M207.58 513.175h26.147v52.295h-26.147v-52.295z","M272.034 513.175h26.147v52.295h-26.147v-52.295z","M395.58 513.175h52.295v26.147h-52.295v-26.147z","M502.915 513.175h52.295v26.147h-52.295v-26.147z","M610.251 513.175h52.295v26.147h-52.295v-26.147z","M395.58 574.098h52.295v26.147h-52.295v-26.147z","M502.915 574.098h52.295v26.147h-52.295v-26.147z","M610.251 574.098h52.295v26.147h-52.295v-26.147z","M207.58 616.065h26.147v52.295h-26.147v-52.295z","M272.034 616.065h26.147v52.295h-26.147v-52.295z","M207.58 719.086h26.147v52.295h-26.147v-52.295z","M272.034 719.086h26.147v52.295h-26.147v-52.295z","M759.945 513.175h26.147v52.295h-26.147v-52.295z","M824.398 513.175h26.147v52.295h-26.147v-52.295z","M759.945 616.065h26.147v52.295h-26.147v-52.295z","M824.398 616.065h26.147v52.295h-26.147v-52.295z","M759.945 719.086h26.147v52.295h-26.147v-52.295z","M824.398 719.086h26.147v52.295h-26.147v-52.295z"],"attrs":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-60"],"grid":0},"attrs":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}],"properties":{"order":64,"id":21,"name":"school","prevSize":32,"code":59707},"setIdx":0,"setId":3,"iconIdx":22},{"icon":{"paths":["M617.753 639.219v-12.005c3.555-2.908 6.746-5.809 9.779-8.866l0.008-0.008c24.227-26.601 40.561-60.78 45.068-98.589l0.082-0.846c23.24-3.634 43.084-15.947 56.479-33.456l0.155-0.211c18.921-26.751 20.618-65.246 4.828-113.528-0.965-2.841-2.795-5.177-5.172-6.755l-0.048-0.030-7.177-4.828c0.033-1.28 0.052-2.786 0.052-4.297 0-43.941-16.017-84.142-42.532-115.081l0.2 0.239c-35.102-39.539-88.995-59.504-160.374-59.765-71.248 0-125.272 20.226-160.374 59.243-26.314 30.7-42.331 70.9-42.331 114.842 0 1.511 0.019 3.018 0.057 4.52l-0.004-0.222-7.177 4.828c-2.425 1.608-4.254 3.945-5.192 6.694l-0.027 0.092c-15.789 48.543-14.093 86.777 4.828 113.528 13.509 17.852 33.351 30.295 56.127 33.991l0.506 0.068c4.609 38.714 20.99 72.939 45.407 99.705l-0.126-0.14c3.042 3.060 6.233 5.961 9.564 8.696l0.223 0.177v12.005c-49.978 9.656-249.5 56.503-246.107 189.604 0 7.207 5.842 13.049 13.049 13.049l663.289 0c7.207-0 13.049-5.842 13.049-13.049l0-0c3.393-133.102-196.129-179.949-246.107-189.605zM357.683 489.676c-11.36-3.888-20.8-10.928-27.555-20.072l-0.109-0.155 0.652 0.13c-13.049-19.052-14.224-47.89-2.61-85.994l9.526-6.394c3.52-2.374 5.805-6.347 5.805-10.854 0-0.451-0.023-0.898-0.068-1.337l0.005 0.055c-0.155-2.59-0.244-5.619-0.244-8.668 0-37.669 13.504-72.184 35.934-98.968l-0.197 0.241c29.491-33.406 76.859-50.109 140.279-50.37s110.787 16.964 140.8 50.37c22.234 26.543 35.737 61.058 35.737 98.727 0 3.049-0.088 6.078-0.263 9.083l0.019-0.415c-0.040 0.384-0.063 0.831-0.063 1.282 0 4.507 2.284 8.48 5.758 10.824l0.046 0.029 9.526 6.394c11.614 37.973 10.831 66.942-2.61 85.994-6.908 9.305-16.391 16.345-27.394 20.107l-0.4 0.119c13.43-15.223 21.628-35.339 21.628-57.37 0-2.773-0.13-5.516-0.384-8.222l0.026 0.346c-2.592-14.769-10.176-27.431-20.916-36.461l-0.093-0.076c-5.611-130.492-97.086-145.106-136.494-145.106-0.14-0-0.306-0.001-0.472-0.001-8.629 0-17.103 0.664-25.374 1.945l0.922-0.117c-7.344-1.163-15.812-1.828-24.435-1.828-0.172 0-0.344 0-0.515 0.001l0.027-0c-39.147 0-130.492 14.354-136.494 145.106-10.909 9.043-18.578 21.658-21.213 36.033l-0.057 0.375c-0.231 2.373-0.362 5.131-0.362 7.919 0 22.018 8.2 42.121 21.713 57.421l-0.081-0.093zM654.551 382.673c-4.635 0.285-10.053 0.448-15.509 0.448-51.951 0-100.46-14.737-141.574-40.257l1.145 0.662c-2.089-1.482-4.69-2.37-7.499-2.37-3.723 0-7.082 1.559-9.46 4.061l-0.005 0.006c-26.098 28.056-73.727 34.58-96.694 36.016 7.047-92.258 62.897-112.353 109.874-112.353 0.269-0.002 0.587-0.003 0.905-0.003 7.564 0 14.972 0.666 22.17 1.942l-0.761-0.112c0.785 0.168 1.686 0.264 2.61 0.264s1.825-0.096 2.695-0.279l-0.085 0.015c6.452-1.164 13.878-1.83 21.46-1.83 0.3 0 0.601 0.001 0.901 0.003l-0.046-0c46.586 0 102.697 20.618 109.222 113.658zM389.523 492.155l0.522 0.13c0-0.034 0-0.073 0-0.113 0-3.316-1.237-6.342-3.275-8.644l0.012 0.014c-17.877-20.487-26.098-39.147-23.88-54.545 1.131-8.881 5.483-16.577 11.828-22.014l0.047-0.039c17.225 0 78.295-3.262 117.443-37.060 41.579 24.318 91.484 38.808 144.748 39.147l0.098 0c1.279 0.034 2.784 0.054 4.293 0.054 7.965 0 15.803-0.541 23.481-1.589l-0.893 0.1c6.222 5.335 10.5 12.78 11.722 21.215l0.022 0.186c2.218 15.137-6.003 34.059-23.88 54.545-2.026 2.288-3.263 5.314-3.263 8.63 0 0.040 0 0.079 0.001 0.119l-0-0.006v6.786l-75.946 40.714c-6.72-6.371-15.82-10.29-25.836-10.29-20.755 0-37.58 16.825-37.58 37.58s16.825 37.58 37.58 37.58c20.755 0 37.58-16.825 37.58-37.58 0-0.006-0-0.013-0-0.019l0 0.001q0.088-1.762 0-3.523l59.896-32.101c-5.489 26.856-17.81 50.233-35.065 69.003l0.093-0.103c-20.872 20.117-49.309 32.51-80.64 32.51-2.067 0-4.121-0.054-6.161-0.16l0.285 0.012h-6.525c-1.726 0.091-3.747 0.143-5.781 0.143-31.296 0-59.711-12.337-80.646-32.414l0.041 0.039c-41.235-41.105-40.322-107.656-40.322-108.308zM558.248 567.058c0 6.414-5.2 11.614-11.614 11.614s-11.614-5.2-11.614-11.614c0-6.414 5.2-11.614 11.614-11.614 0 0 0 0 0 0l-0-0c6.414 0 11.613 5.2 11.614 11.614l0 0zM506.052 814.992h-305.089c10.308-97.999 169.639-138.974 219.486-149.543v23.358c0 29.622 36.016 52.197 85.602 55.981zM446.548 688.806v-45.020c19.462 9.244 42.288 14.642 66.375 14.642 1.025 0 2.048-0.010 3.069-0.029l-0.153 0.002h6.525c0.868 0.017 1.891 0.027 2.916 0.027 24.087 0 46.914-5.398 67.336-15.050l-0.96 0.408v45.020c0 12.397-28.317 30.274-72.553 30.274s-72.554-17.877-72.554-30.274zM532.15 815.383v-70.726c49.587-3.393 85.602-26.098 85.602-55.981v-22.836c50.239 10.439 208.787 51.414 219.487 149.543h-305.089z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-61"],"grid":0},"attrs":[{}],"properties":{"order":65,"id":22,"name":"speaker","prevSize":32,"code":59708},"setIdx":0,"setId":3,"iconIdx":23},{"icon":{"paths":["M808.936 166.611c-0.003-0-0.007-0-0.010-0-44.022 0-79.709 35.687-79.709 79.709 0 13.93 3.574 27.026 9.854 38.421l-0.208-0.412-130.593 130.593c-17.744-13.991-40.425-22.441-65.079-22.441-24.647 0-47.321 8.445-65.287 22.598l0.225-0.171-101.894-101.894c4.688-7.653 7.483-16.908 7.533-26.812l0-0.014c0-29.352-23.794-53.146-53.146-53.146s-53.146 23.794-53.146 53.146c0 29.352 23.794 53.146 53.146 53.146v0c9.918-0.050 19.172-2.846 27.055-7.664l-0.23 0.131 101.894 101.894c-13.983 17.744-22.428 40.421-22.428 65.070s8.445 47.326 22.599 65.296l-0.171-0.225-168.26 168.273c-13.903-12.496-32.387-20.139-52.657-20.139-43.581 0-78.911 35.33-78.911 78.911s35.33 78.911 78.911 78.911c43.581 0 78.911-35.33 78.911-78.911 0-13.862-3.574-26.89-9.852-38.211l0.206 0.404 170.452-170.452c14.338 11.264 31.984 18.957 51.26 21.455l0.53 0.056v134.991c-37.945 6.589-66.432 39.27-66.432 78.604 0 44.028 35.691 79.719 79.719 79.719s79.719-35.691 79.719-79.719c0-39.334-28.487-72.015-65.956-78.535l-0.476-0.069v-134.991c19.806-2.554 37.453-10.246 52.019-21.684l-0.229 0.173 101.894 101.894c-4.696 7.655-7.497 16.915-7.547 26.825l-0 0.014c0 29.352 23.794 53.146 53.146 53.146s53.146-23.794 53.146-53.146c0-29.352-23.794-53.146-53.146-53.146 0 0 0 0 0 0h0c-9.918 0.050-19.172 2.846-27.055 7.664l0.23-0.131-101.894-101.894c13.983-17.744 22.427-40.421 22.427-65.070s-8.445-47.326-22.599-65.296l0.171 0.225 128.414-128.414c14.083 12.804 32.879 20.643 53.506 20.643 43.997 0 79.664-35.667 79.664-79.664s-35.667-79.664-79.664-79.664c-0.019 0-0.039 0-0.058 0l0.003-0zM304.050 286.189c0-14.676 11.897-26.572 26.573-26.572s26.573 11.897 26.573 26.573c0 14.676-11.897 26.573-26.573 26.573h0c-14.67-0.015-26.558-11.904-26.573-26.572l-0-0.001zM237.617 844.22c-29.352 0-53.146-23.794-53.146-53.146s23.794-53.146 53.146-53.146c29.352 0 53.146 23.794 53.146 53.146v0c-0.030 29.339-23.806 53.116-53.143 53.146l-0.003 0zM596.352 817.647c0 29.352-23.794 53.146-53.146 53.146s-53.146-23.794-53.146-53.146c0-29.352 23.794-53.146 53.146-53.146v0c29.339 0.030 53.115 23.807 53.146 53.143l0 0.003zM543.206 578.491c-44.027 0-79.719-35.691-79.719-79.719s35.691-79.719 79.719-79.719c44.027 0 79.719 35.691 79.719 79.719v0c-0.046 44.009-35.71 79.673-79.715 79.719l-0.004 0zM782.363 711.356c0 14.676-11.897 26.573-26.573 26.573s-26.573-11.897-26.573-26.573c0-14.676 11.897-26.573 26.573-26.573 0 0 0 0 0 0l-0-0c14.67 0.015 26.558 11.903 26.573 26.571l0 0.001zM808.936 299.475c-29.352 0-53.146-23.794-53.146-53.146s23.794-53.146 53.146-53.146c29.352 0 53.146 23.794 53.146 53.146v0c-0.030 29.339-23.807 53.115-53.143 53.146l-0.003 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-62"],"grid":0},"attrs":[{}],"properties":{"order":66,"id":23,"name":"atom","prevSize":32,"code":59709},"setIdx":0,"setId":3,"iconIdx":24},{"icon":{"paths":["M857.807 287.236l-0.14-0.006h-202.903v-22.379c-0.044-37.061-30.076-67.093-67.133-67.137l-179.037-0c-37.061 0.044-67.093 30.076-67.137 67.133l-0 0.004v22.379h-202.904c-12.346 0.033-22.346 10.033-22.379 22.376l-0 0.003v492.339c0.044 37.061 30.076 67.093 67.133 67.137l629.602 0c37.061-0.044 67.093-30.076 67.137-67.133l0-0.004v-491.955c0.016-0.31 0.025-0.673 0.025-1.038 0-11.999-9.727-21.727-21.727-21.727-0.189 0-0.377 0.002-0.565 0.007l0.028-0.001zM386.215 264.851c0.016-12.353 10.026-22.363 22.377-22.379l0.002-0h179.033c12.353 0.016 22.363 10.026 22.379 22.378l0 0.002v22.379h-223.79zM826.616 331.988l-69.498 208.487c-3.041 8.966-11.382 15.304-21.204 15.304-0.007 0-0.015-0-0.022-0l-125.887 0v-22.379c0-0 0-0.001 0-0.002 0-12.359-10.019-22.377-22.377-22.377-0.001 0-0.001 0-0.002 0l-179.032-0c-0-0-0.001-0-0.002-0-12.359 0-22.377 10.019-22.377 22.377 0 0.001 0 0.001 0 0.002l-0-0v22.379h-125.888c-0.006 0-0.014 0-0.021 0-9.822 0-18.163-6.338-21.158-15.147l-0.046-0.157-69.498-208.487zM565.247 555.779v44.758h-134.274v-44.758zM835.288 801.948c-0.016 12.353-10.026 22.363-22.377 22.379l-0.002 0h-629.598c-12.353-0.016-22.363-10.026-22.379-22.378l-0-0.002v-354.434l35.707 107.116c9.13 26.897 34.156 45.906 63.622 45.906 0.023 0 0.046-0 0.068-0l125.885 0v22.379c-0 0.001-0 0.001-0 0.002 0 12.359 10.019 22.377 22.377 22.377 0.001 0 0.001-0 0.002-0l179.033 0c0 0 0.001 0 0.001 0 12.359 0 22.377-10.019 22.377-22.377 0-0.001-0-0.001-0-0.002l0 0v-22.379h125.888c0.019 0 0.042 0 0.065 0 29.466 0 54.492-19.010 63.483-45.434l0.14-0.472 35.707-107.116z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-63"],"grid":0},"attrs":[{}],"properties":{"order":67,"id":24,"name":"bag","prevSize":32,"code":59710},"setIdx":0,"setId":3,"iconIdx":25},{"icon":{"paths":["M428.539 761.252c-33.323 0-60.337 27.014-60.337 60.337s27.014 60.337 60.337 60.337c33.323 0 60.337-27.014 60.337-60.337v0c-0.039-33.307-27.029-60.298-60.333-60.337l-0.004-0zM428.539 848.233c-0 0-0 0-0 0-14.717 0-26.648-11.931-26.648-26.648s11.931-26.648 26.648-26.648c14.717 0 26.648 11.931 26.648 26.648v-0c-0.017 14.71-11.937 26.63-26.646 26.648l-0.002 0z","M640.178 761.252c-33.323 0-60.337 27.014-60.337 60.337s27.014 60.337 60.337 60.337c33.323 0 60.337-27.014 60.337-60.337h0c-0.039-33.307-27.029-60.298-60.333-60.337l-0.004-0zM640.178 848.233c-14.717 0-26.648-11.931-26.648-26.648s11.931-26.648 26.648-26.648c14.717 0 26.648 11.931 26.648 26.648v-0c-0.017 14.71-11.937 26.631-26.646 26.648l-0.002 0z","M655.032 443.585h-241.391c-9.288 0.020-16.81 7.554-16.81 16.845s7.522 16.825 16.808 16.845l0.002 0h241.391c9.288-0.020 16.81-7.554 16.81-16.845s-7.522-16.825-16.808-16.845l-0.002-0z","M641.894 531.057h-215.113c-9.303 0-16.845 7.542-16.845 16.845s7.542 16.845 16.845 16.845h215.112c0 0 0 0 0.001 0 9.303 0 16.845-7.542 16.845-16.845s-7.541-16.844-16.844-16.845l-0-0z","M819.344 368.533c-6.201-7.595-15.563-12.405-26.049-12.405-0.023 0-0.046 0-0.068 0l0.004-0h-524.691l-10.596-51.439c-2.308-10.891-9.622-19.696-19.367-24.019l-0.215-0.085-73.935-32.092c-1.976-0.881-4.282-1.393-6.708-1.393-9.302 0-16.844 7.541-16.844 16.844 0 6.877 4.121 12.791 10.028 15.408l0.108 0.043 73.936 32.093 81.504 395.636c3.313 15.432 16.815 26.84 32.991 26.89l0.006 0h403.548c0.010 0 0.023 0 0.035 0 9.303 0 16.845-7.542 16.845-16.845s-7.542-16.845-16.845-16.845c-0.012 0-0.025 0-0.037 0l0.002-0h-403.547l-9.914-48.126h416.581c16.181-0.051 29.683-11.459 32.955-26.668l0.040-0.222 47.117-228.697c0.447-2.053 0.702-4.411 0.702-6.829 0-8.090-2.863-15.511-7.631-21.306l0.046 0.058zM746.114 618.51h-423.52l-47.114-228.695 517.749 0.001z"],"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-64"],"grid":0},"attrs":[{},{},{},{},{}],"properties":{"order":68,"id":25,"name":"carbuy","prevSize":32,"code":59711},"setIdx":0,"setId":3,"iconIdx":26},{"icon":{"paths":["M826.827 765.785c11.986-10.952 19.488-26.637 19.532-44.074l0-0.008v-24.068c-0.001-33.232-26.942-60.171-60.174-60.171-28.972 0-53.162 20.475-58.889 47.745l-0.069 0.392h-39.528c-5.037-14.133-18.303-24.068-33.89-24.068s-28.853 9.935-33.812 23.818l-0.078 0.251h-39.528c-4.999-23.627-23.293-41.921-46.526-46.85l-0.395-0.070v-26.995c20.881-5.5 36.039-24.184 36.103-46.42l0-0.007h12.034c0.003 0 0.007 0 0.011 0 6.64 0 12.024-5.383 12.024-12.024 0-0.004-0-0.008-0-0.011l0 0.001v-36.103h24.068v-24.068h-24.069v-0.129c0.519-24.944 12-47.105 29.805-61.931l0.134-0.108c33.307-28.838 54.254-71.183 54.254-118.421 0-86.359-70.008-156.367-156.367-156.367-2.28 0-4.548 0.049-6.804 0.145l0.322-0.011c-82.168 4.485-147.423 70.955-149.963 153.217l-0.006 0.242c-0.017 0.86-0.027 1.874-0.027 2.89 0 46.74 20.552 88.681 53.112 117.277l0.176 0.151c18.020 15.39 29.696 37.75 30.825 62.855l0.007 0.189h-23.945v24.068h24.068v36.103c-0 0.004-0 0.009-0 0.014 0 6.638 5.381 12.020 12.020 12.020 0.005 0 0.010-0 0.015-0l12.033 0c0.061 22.243 15.221 40.929 35.767 46.352l0.335 0.075v26.995c-23.629 4.999-41.924 23.293-46.856 46.526l-0.070 0.395h-39.528c-5.037-14.133-18.303-24.068-33.89-24.068s-28.853 9.935-33.812 23.818l-0.078 0.251h-39.528c-5.794-27.661-29.983-48.137-58.955-48.137-33.231 0-60.17 26.939-60.17 60.17 0 0 0 0.001 0 0.001l-0-0v24.069c0.042 17.445 7.542 33.13 19.48 44.041l0.046 0.041c-39.975 16.532-67.601 55.196-67.663 100.32l-0 0.008v24.068c-0 0.004-0 0.009-0 0.014 0 6.638 5.381 12.020 12.020 12.020 0.005 0 0.010-0 0.015-0l192.546 0c0.003 0 0.007 0 0.011 0 6.64 0 12.024-5.383 12.024-12.024 0-0.004-0-0.007-0-0.011l0 0.001v-24.068c-0.064-45.133-27.692-83.796-66.95-100.064l-0.719-0.264c11.986-10.952 19.488-26.636 19.532-44.074l0-0.008v-12.035h38.312c5.037 14.133 18.303 24.068 33.89 24.068s28.853-9.935 33.812-23.818l0.078-0.251h38.318v12.035c0.042 17.445 7.542 33.13 19.48 44.041l0.046 0.042c-39.975 16.532-67.601 55.196-67.663 100.32l-0 0.008v24.068c-0 0.004-0 0.009-0 0.014 0 6.638 5.381 12.020 12.020 12.020 0.005 0 0.010-0 0.015-0l192.546 0c0.003 0 0.007 0 0.011 0 6.64 0 12.024-5.383 12.024-12.024 0-0.004-0-0.007-0-0.011l0 0.001v-24.068c-0.064-45.133-27.692-83.796-66.95-100.064l-0.719-0.264c11.986-10.952 19.488-26.637 19.532-44.074l0-0.008v-12.035h38.312c5.037 14.133 18.303 24.068 33.89 24.068s28.853-9.935 33.812-23.818l0.078-0.251h38.318v12.035c0.042 17.445 7.542 33.13 19.48 44.041l0.046 0.041c-39.975 16.532-67.601 55.196-67.663 100.32l-0 0.008v24.068c-0 0.004-0 0.009-0 0.014 0 6.638 5.381 12.020 12.020 12.020 0.005 0 0.010-0 0.015-0l192.546 0c0.003 0 0.007 0 0.011 0 6.64 0 12.024-5.383 12.024-12.024 0-0.004-0-0.007-0-0.011l0 0.001v-24.068c-0.064-45.133-27.692-83.797-66.95-100.064l-0.719-0.264zM340.924 866.113v12.034h-24.068v-24.068h-24.068v24.068h-72.205v-24.068h-24.068v24.068h-24.068v-12.034c-0-0.023-0-0.051-0-0.078 0-46.524 37.715-84.239 84.239-84.239s84.239 37.715 84.239 84.239c0 0.027-0 0.055-0 0.082l0-0.004zM220.582 721.703v-24.069c-0-0.015-0-0.033-0-0.051 0-19.939 16.164-36.103 36.103-36.103s36.103 16.164 36.103 36.103c0 0.018-0 0.036-0 0.054l0-0.003v24.069c-0.029 19.917-16.182 36.052-36.103 36.052s-36.073-16.135-36.103-36.049l-0-0.003zM389.061 709.669c-0 0-0 0-0 0-6.646 0-12.034-5.388-12.034-12.034s5.388-12.034 12.034-12.034c6.646 0 12.034 5.388 12.034 12.034l-0-0c-0 6.646-5.388 12.034-12.034 12.034l-0 0zM434.136 411.905c-27.69-24.316-45.075-59.792-45.075-99.328 0-0.868 0.008-1.734 0.025-2.598l-0.002 0.129c2.155-69.798 57.353-126.031 126.521-129.823l0.344-0.015c1.67-0.075 3.629-0.118 5.597-0.118 73.049 0 132.267 59.218 132.267 132.267 0 39.985-17.742 75.825-45.784 100.079l-0.167 0.142c-23.068 19.378-37.773 48.064-38.287 80.197l-0.001 0.087v0.129h-96.397c-1.133-32.503-15.976-61.329-38.892-81.024l-0.148-0.124zM569.573 517.122v24.068h-96.273v-24.068zM497.368 565.259h48.137c0 13.293-10.776 24.068-24.068 24.068s-24.068-10.776-24.068-24.068v0zM605.676 866.113v12.034h-24.068v-24.068h-24.068v24.068h-72.205v-24.068h-24.068v24.068h-24.068v-12.034c0-46.524 37.715-84.239 84.239-84.239s84.239 37.715 84.239 84.239v0zM485.334 721.703v-24.069c-0-0.015-0-0.033-0-0.051 0-19.939 16.164-36.103 36.103-36.103s36.103 16.164 36.103 36.103c0 0.018-0 0.036-0 0.054l0-0.003v24.069c-0.029 19.917-16.182 36.052-36.103 36.052s-36.073-16.135-36.103-36.049l-0-0.003zM653.812 709.669c-6.646-0-12.034-5.388-12.034-12.034s5.388-12.034 12.034-12.034c6.646 0 12.034 5.388 12.034 12.034l0 0c-0 6.646-5.388 12.034-12.034 12.034l0-0zM750.086 721.703v-24.069c-0-0.015-0-0.033-0-0.051 0-19.939 16.164-36.103 36.103-36.103s36.103 16.164 36.103 36.103c0 0.018-0 0.036-0 0.054l0-0.003v24.069c-0.029 19.917-16.182 36.052-36.103 36.052s-36.073-16.135-36.103-36.049l-0-0.003zM870.428 878.148h-24.068v-24.068h-24.068v24.068h-72.205v-24.068h-24.068v24.068h-24.068v-12.034c-0-0.023-0-0.051-0-0.078 0-46.524 37.715-84.239 84.239-84.239s84.239 37.715 84.239 84.239c0 0.027-0 0.055-0 0.082l0-0.004z","M497.368 444.917h48.137v24.068h-48.137z","M509.402 371.495v25.285h24.069v-25.285c7.998-1.678 15.071-4.737 21.307-8.943l-0.212 0.135 18.533 18.533 17.011-17.017-18.528-18.533c4.067-6.025 7.126-13.097 8.739-20.704l0.069-0.391h25.285v-24.068h-25.285c-1.683-7.998-4.741-15.070-8.944-21.308l0.135 0.213 18.527-18.533-17.011-17.017-18.533 18.533c-6.023-4.071-13.097-7.13-20.705-8.739l-0.39-0.069v-25.285h-24.069v25.285c-8 1.678-15.075 4.737-21.313 8.943l0.212-0.135-18.533-18.533-17.011 17.017 18.533 18.533c-4.072 6.024-7.132 13.097-8.745 20.705l-0.069 0.39h-25.279v24.068h25.279c1.682 7.998 4.742 15.071 8.949 21.307l-0.135-0.212-18.533 18.533 17.011 17.017 18.533-18.533c6.025 4.071 13.101 7.13 20.711 8.739l0.39 0.069zM521.437 276.438c19.939 0 36.103 16.164 36.103 36.103s-16.164 36.103-36.103 36.103c-19.939 0-36.103-16.164-36.103-36.103 0-0 0-0 0-0l0-0c0.027-19.928 16.174-36.076 36.1-36.102l0.003-0z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-65"],"grid":0},"attrs":[{},{},{}],"properties":{"order":69,"id":26,"name":"idea","prevSize":32,"code":59712},"setIdx":0,"setId":3,"iconIdx":27},{"icon":{"paths":["M869.214 639.015h-7.229v-31.737c28.596-28.939 25.342-80.573 24.801-87.121v-54.064c-0.021-17.426-14.141-31.547-31.565-31.568l-1.215-0c-0.012-0-0.026-0-0.040-0-5.561 0-10.784 1.447-15.314 3.984l0.158-0.082c-5.827-7.3-14.724-11.937-24.705-11.937l-1.213-0c-0.018-0-0.039-0-0.060-0-5.412 0-10.506 1.359-14.96 3.754l0.169-0.083c-5.82-6.902-14.472-11.256-24.141-11.256-0.003 0-0.005 0-0.008 0l-1.212-0c-0.008-0-0.017-0-0.027-0-4.519 0-8.816 0.95-12.703 2.66l0.202-0.079c-5.727-8.614-15.391-14.215-26.363-14.219l-1.213-0c-17.426 0.022-31.547 14.143-31.567 31.568l-0 0.002v30.422c-2.021-0.377-4.346-0.593-6.722-0.593-8.829 0-16.962 2.981-23.446 7.992l0.089-0.066c-16.247 13.599-14.613 40.583-13.031 66.68 2.159 35.619 33.913 65.505 46.15 75.759v19.982h-6.095c-0.001-0-0.001-0-0.002-0-6.416 0-11.617 5.201-11.617 11.617 0 0.001 0 0.002 0 0.002l-0-0v238.982c-0 0.001-0 0.001-0 0.002 0 6.416 5.201 11.617 11.617 11.617 0.001 0 0.002-0 0.002-0l171.263 0c0.001 0 0.001 0 0.002 0 6.416 0 11.617-5.201 11.617-11.617 0-0.001-0-0.002-0-0.002l0 0v-238.98c-0.002-6.418-5.205-11.619-11.622-11.62l-0-0zM681.095 541.867c-1.119-18.434-2.509-41.378 4.749-47.45 2.788-1.561 6.119-2.481 9.664-2.481 1.959 0 3.852 0.281 5.642 0.804l-0.142-0.036v15.783c-0 0.009-0 0.019-0 0.029 0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62c0-0.010-0-0.020-0-0.031l0 0.002v-69.646c0.005-4.598 3.73-8.325 8.327-8.331l0.001-0h1.213c4.599 0.006 8.325 3.732 8.331 8.33l0 0.001v44.86c0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62h0v-37.166c1.428-2.629 4.169-4.383 7.319-4.383 0.001 0 0.002 0 0.002 0l1.213-0c4.599 0.006 8.325 3.732 8.331 8.33l0 0.001v33.221c0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62h0v-29.413c1.395-2.722 4.181-4.552 7.395-4.552 0.012 0 0.024 0 0.036 0l-0.002-0h1.213c4.597 0.006 8.323 3.732 8.328 8.329l0 0.001v31.34c0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62h0v-23.304c0.007-4.599 3.734-8.325 8.333-8.329l1.213-0c4.597 0.006 8.323 3.732 8.328 8.329l0 0.001v54.572c0 0.371 0.019 0.744 0.053 1.115 1.341 13.89 0.224 53.822-20.742 71.57-2.522 2.144-4.112 5.319-4.112 8.866 0 0.002 0 0.003 0 0.005l-0-0v36.796h-111.459v-25.564c-0.003-3.805-1.83-7.182-4.653-9.306l-0.030-0.021c-0.395-0.298-39.544-29.868-41.508-62.268zM857.594 877.998h-148.024v-155.971h148.024zM857.594 698.788h-148.024v-36.533h148.024z","M644.248 359.429l53.159 22.451c3.515 1.525 7.609 2.412 11.911 2.412 12.606 0 23.432-7.619 28.125-18.504l0.076-0.199 6.466-15.31c1.525-3.516 2.413-7.61 2.413-11.912 0-12.612-7.628-23.443-18.522-28.131l-0.199-0.076-63.102-26.522 2.918-10.549c0.037-0.138 0.075-0.276 0.105-0.414 0.543-2.191 0.854-4.706 0.854-7.293 0-14.843-10.244-27.293-24.048-30.667l-0.216-0.045-1.191-0.283c-2.189-0.546-4.701-0.859-7.287-0.859-2.99 0-5.882 0.419-8.621 1.201l0.221-0.054c-4.107-8.64-11.781-15.016-21.065-17.282l-0.216-0.045-1.175-0.279c-2.212-0.552-4.751-0.869-7.364-0.869-2.814 0-5.542 0.368-8.139 1.057l0.221-0.050q-0.611-1.208-1.328-2.372c-4.359-7.034-11.244-12.149-19.359-14.108l-0.214-0.044-1.19-0.283c-2.195-0.548-4.716-0.863-7.309-0.863-1.927 0-3.813 0.174-5.644 0.506l0.192-0.029c-0.822-2.217-1.766-4.119-2.881-5.903l0.078 0.134c-4.364-7.041-11.259-12.16-19.385-14.115l-0.214-0.043-1.162-0.275c-2.192-0.543-4.708-0.855-7.296-0.855-14.78 0-27.187 10.158-30.621 23.873l-0.046 0.218-2.069 7.685-81.95-34.43c-0.219-0.088-0.44-0.164-0.663-0.24-0.148-0.049-0.296-0.102-0.444-0.145-0.19-0.056-0.383-0.101-0.577-0.148-0.194-0.045-0.387-0.092-0.583-0.127-0.155-0.029-0.311-0.049-0.469-0.073-0.237-0.036-0.476-0.063-0.712-0.082l-0.18-0.022-77.804-5.011c-0.223-0.015-0.484-0.024-0.747-0.024-6.418 0-11.62 5.202-11.62 11.62 0 3.257 1.34 6.201 3.499 8.311l0.002 0.002 54.874 53.586c0.226 0.217 0.463 0.427 0.709 0.627 0.119 0.098 0.243 0.183 0.365 0.276 0.132 0.098 0.257 0.201 0.394 0.295l0.108 0.066c0.199 0.134 0.403 0.253 0.609 0.371 1.325 0.876 2.852 1.706 4.448 2.406l0.198 0.077 49.761 21.015c-3.131 9.767-5.891 21.615-7.748 33.76l-0.169 1.344c-6.35 36.428 19.641 74.208 28.378 85.67l0.040 52.831h-9.673c-0.001-0-0.001-0-0.002-0-6.416 0-11.617 5.201-11.617 11.617 0 0.001 0 0.002 0 0.002l-0-0v435.312c-0 0.001-0 0.001-0 0.002 0 6.416 5.201 11.617 11.617 11.617 0.001 0 0.002-0 0.002-0l171.264 0c0.001 0 0.001 0 0.002 0 6.416 0 11.617-5.201 11.617-11.617 0-0.001-0-0.002-0-0.002l0 0v-290.774c-0-6.417-5.202-11.62-11.62-11.62s-11.62 5.202-11.62 11.62v0 279.153h-148.024v-352.297h148.024v32.279c0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62v0-103.673c0-0.001 0-0.002 0-0.002 0-6.417-5.202-11.619-11.619-11.619-0 0-0.001 0-0.001 0l-4.872-0 0.105-30.018c19.625-12.999 30.642-35.578 36.582-53.241zM705.911 326.223l12.746 5.356c2.669 1.147 4.505 3.753 4.505 6.789 0 1.036-0.214 2.022-0.6 2.916l0.018-0.048-6.466 15.312c-1.149 2.669-3.757 4.504-6.793 4.504-1.036 0-2.022-0.214-2.917-0.599l0.048 0.018-13.589-5.739zM650.428 334.796l7.904-28.57 26.144 10.987-13.031 28.475-21.328-9.006c0.138-0.785 0.24-1.423 0.312-1.886zM378.248 215.872l-20.69-20.208 29.389 1.893zM397.311 229.907l13.219-27.831 74.496 31.308-8.112 30.14zM600.813 502.464h-148.022v-36.534h148.024v36.534zM590.81 395.641c-3.794 1.955-6.347 5.839-6.363 10.321l-0 0.002-0.125 35.529h-110.245l-0.042-55.684c-0.006-2.848-1.032-5.455-2.732-7.477l0.015 0.018c-0.314-0.383-31.574-38.197-26-70.17 1.794-11.736 4.058-21.877 6.928-31.761l-0.431 1.733 21.012 8.876c1.687 4.462 5.924 7.578 10.888 7.578 5.342 0 9.842-3.608 11.195-8.519l0.019-0.082 20.74-77.060c0.032-0.112 0.059-0.224 0.085-0.337 0.9-3.7 4.185-6.404 8.101-6.404 0.69 0 1.359 0.084 2 0.242l-0.057-0.012 1.164 0.275c3.7 0.901 6.404 4.186 6.404 8.103 0 0.685-0.083 1.351-0.239 1.988l0.012-0.057-1.18 4.97-13.688 47.428c-0.291 0.968-0.459 2.081-0.459 3.233 0 6.418 5.203 11.62 11.62 11.62 5.273 0 9.725-3.512 11.146-8.324l0.021-0.082 13.226-45.828c1.53-1.82 3.807-2.969 6.353-2.969 0.68 0 1.342 0.082 1.975 0.237l-0.057-0.012 1.19 0.283c3.697 0.896 6.4 4.177 6.4 8.089 0 0.649-0.074 1.28-0.215 1.886l0.011-0.056-12.173 41.115c-0.303 0.987-0.478 2.122-0.478 3.298 0 6.417 5.202 11.62 11.62 11.62 5.242 0 9.673-3.471 11.12-8.239l0.021-0.082 11.268-38.062c1.52-2.076 3.947-3.408 6.686-3.408 0.686 0 1.353 0.084 1.991 0.241l-0.057-0.012 1.175 0.279c3.7 0.906 6.403 4.193 6.403 8.112 0 0.681-0.082 1.343-0.236 1.977l0.012-0.057-1.759 7.419-9.908 31.574c-0.338 1.040-0.533 2.236-0.533 3.479 0 6.418 5.203 11.62 11.62 11.62 5.176 0 9.561-3.384 11.064-8.059l0.023-0.082 10.031-31.97c0.043-0.141 0.071-0.282 0.108-0.423 0.036-0.124 0.079-0.243 0.108-0.37 0.903-3.7 4.189-6.403 8.107-6.403 0.679 0 1.339 0.081 1.971 0.234l-0.057-0.012 1.191 0.283c3.7 0.906 6.402 4.193 6.402 8.112 0 0.621-0.068 1.226-0.197 1.808l0.010-0.055-17.185 62.139c-0.12 0.41-0.227 0.916-0.301 1.432l-0.007 0.062c-0.069 0.492-7.355 49.966-36.716 64.854z","M380.457 584.239v-54.058c-0.020-17.427-14.142-31.549-31.568-31.57l-1.215-0c-0.012-0-0.026-0-0.040-0-5.561 0-10.783 1.447-15.312 3.984l0.158-0.082c-5.827-7.3-14.724-11.937-24.705-11.937-0.001 0-0.001 0-0.002 0l-1.213-0c-0.017-0-0.037-0-0.057-0-5.412 0-10.506 1.36-14.96 3.757l0.168-0.083c-5.82-6.903-14.473-11.258-24.143-11.258-0.003 0-0.006 0-0.009 0l-1.212-0c-0.008-0-0.017-0-0.026-0-4.518 0-8.815 0.949-12.701 2.659l0.202-0.079c-5.728-8.613-15.391-14.214-26.363-14.218l-1.213-0c-17.427 0.020-31.55 14.143-31.57 31.568l-0 0.002v30.423c-2.024-0.379-4.352-0.595-6.731-0.595-8.825 0-16.954 2.981-23.435 7.992l0.088-0.066c-16.247 13.596-14.613 40.583-13.031 66.682 2.159 35.62 33.91 65.505 46.147 75.759v19.982h-6.095c-0.001-0-0.001-0-0.002-0-6.416 0-11.617 5.201-11.617 11.617 0 0.001 0 0.002 0 0.002l-0-0v174.9c-0 0.001-0 0.001-0 0.002 0 6.416 5.201 11.617 11.617 11.617 0.001 0 0.002-0 0.002-0l171.266 0c0.001 0 0.001 0 0.002 0 6.416 0 11.617-5.201 11.617-11.617 0-0.001-0-0.002-0-0.002l0 0v-174.9c0-0.001 0-0.001 0-0.002 0-6.416-5.201-11.617-11.617-11.617-0.001 0-0.002 0-0.002 0l-7.229-0v-31.737c28.593-28.939 25.339-80.575 24.798-87.125zM351.265 877.998h-148.027v-91.886h148.027zM351.265 762.875h-148.027v-36.534h148.027zM336.528 657.436c-2.522 2.144-4.112 5.319-4.112 8.866 0 0.002 0 0.003 0 0.005l-0-0v36.796h-111.465v-25.567c0-0 0-0.001 0-0.001 0-3.808-1.832-7.188-4.664-9.307l-0.030-0.022c-10.987-8.154-39.856-35.228-41.493-62.255-1.119-18.434-2.509-41.38 4.749-47.452 2.789-1.56 6.12-2.478 9.665-2.478 1.957 0 3.849 0.28 5.638 0.802l-0.142-0.036v15.783c-0 0.009-0 0.019-0 0.029 0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62c0-0.010-0-0.020-0-0.031l0 0.002v-69.651c0.006-4.599 3.732-8.325 8.33-8.331l1.215-0c4.599 0.006 8.325 3.732 8.331 8.33l0 0.001v44.86c0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62v-0-37.166c1.427-2.63 4.168-4.385 7.318-4.385 0 0 0 0 0 0l1.213-0c4.599 0.006 8.325 3.732 8.331 8.33l0 0.001v33.223c-0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62v0-29.413c1.395-2.722 4.181-4.553 7.395-4.553 0.012 0 0.023 0 0.035 0l-0.002-0h1.213c4.598 0.005 8.325 3.731 8.331 8.329l0 0.001v31.341c-0 6.417 5.202 11.62 11.62 11.62s11.62-5.202 11.62-11.62v-23.305c0.006-4.599 3.732-8.325 8.33-8.331l1.213-0c4.599 0.006 8.325 3.732 8.331 8.33l0 0.001v54.569c0 0.371 0.019 0.744 0.053 1.115 1.342 13.89 0.226 53.823-20.74 71.571z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-66"],"grid":0},"attrs":[{},{},{}],"properties":{"order":70,"id":27,"name":"hands","prevSize":32,"code":59713},"setIdx":0,"setId":3,"iconIdx":28},{"icon":{"paths":["M903.616 492.858h-659.823l170.732-186.248c5.215-5.675 8.412-13.277 8.412-21.626 0-17.675-14.329-32.004-32.004-32.004-9.327 0-17.722 3.99-23.571 10.355l-0.021 0.023-219.889 239.878c-0.545 0.612-1.073 1.279-1.562 1.976l-0.047 0.071c-0.563 0.683-1.126 1.444-1.648 2.234l-0.063 0.101c-0.526 0.827-1.080 1.82-1.582 2.845l-0.084 0.189c-0.353 0.639-0.736 1.437-1.077 2.257l-0.063 0.17c-0.366 0.923-0.753 2.117-1.077 3.338l-0.056 0.246c-0.196 0.597-0.393 1.365-0.549 2.148l-0.023 0.138c-0.206 1.088-0.355 2.379-0.414 3.693l-0.002 0.060c-0.1 0.645-0.16 1.392-0.166 2.153l-0 0.006 0.035 1.087c0.073 1.771 0.271 3.443 0.588 5.072l-0.034-0.21 0.162 0.861c0.464 2.122 1.056 3.966 1.801 5.729l-0.079-0.212c0.504 1.135 0.979 2.054 1.499 2.944l-0.077-0.143c0.506 1.027 1 1.882 1.542 2.702l-0.057-0.091c0.761 1.101 1.522 2.061 2.34 2.968l-0.022-0.025c0.521 0.698 1.053 1.315 1.624 1.892l-0.001-0.001 212.696 216.234c5.815 5.943 13.918 9.627 22.881 9.627 17.675 0 32.004-14.329 32.004-32.004 0-8.775-3.532-16.726-9.252-22.507l0.003 0.003-159.274-161.92h656.196c17.676-0 32.004-14.329 32.004-32.004s-14.329-32.004-32.004-32.004v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-67"],"grid":0},"attrs":[{}],"properties":{"order":71,"id":28,"name":"arrowprev","prevSize":32,"code":59714},"setIdx":0,"setId":3,"iconIdx":29},{"icon":{"paths":["M419.651 396.414c-7.812 0.018-14.138 6.356-14.138 14.17 0 0.012 0 0.025 0 0.037l-0-0.002v68.013c-0.015 0.242-0.024 0.525-0.024 0.81s0.009 0.568 0.026 0.849l-0.002-0.039c0.439 7.037 6.253 12.578 13.362 12.578 0.285 0 0.568-0.009 0.848-0.026l-0.038 0.002c5.663 0 11.325-5.663 14.173-14.173v-68.083c-0.020-7.811-6.357-14.136-14.171-14.136-0.013 0-0.025 0-0.038 0l0.002-0z","M813.688 390.786h-25.528v-51.027c0.015-0.242 0.024-0.525 0.024-0.81s-0.009-0.568-0.026-0.849l0.002 0.039c-0.441-7.036-6.255-12.576-13.363-12.576-0.285 0-0.568 0.009-0.849 0.026l0.038-0.002h-19.703v-130.396c0.002-0.308 0.002-0.615-0.002-0.921-0.296-26.164-21.575-47.26-47.781-47.26-0.185 0-0.37 0.001-0.555 0.003l0.028-0h-348.637c-0.264-0.002-0.525-0.002-0.789 0-26.22 0.223-47.39 21.53-47.39 47.782 0 0.139 0.001 0.278 0.002 0.417l-0-0.021c-0.004 0.274-0.004 0.547-0.002 0.821 0.224 26.222 21.533 47.392 47.786 47.392 0.138 0 0.276-0.001 0.414-0.002l-0.021 0h28.343q0.464-0.012 0.929 0c10.499 0.259 18.912 8.832 18.912 19.369 0 0.163-0.002 0.325-0.006 0.487l0-0.024v56.262c-85.247 7.063-152.245 76.213-155.881 161.764l-0.012 0.347v215.167c-0.005 0.466-0.007 1.017-0.007 1.569 0 93.141 75.506 168.646 168.646 168.646 92.691 0 167.917-74.779 168.641-167.3l0-0.069v-143.92c1.781-2.468 2.849-5.554 2.849-8.889 0-0.002-0-0.004-0-0.007l0 0v-65.198c-3.603-85.973-70.599-155.212-155.271-162.333l-0.621-0.042v-53.184c0.002-0.262 0.002-0.525 0-0.789-0.224-26.221-21.532-47.39-47.784-47.39-0.139 0-0.278 0.001-0.417 0.002l0.021-0h-28.343c-0.31 0.008-0.619 0.008-0.927 0-10.5-0.259-18.913-8.832-18.913-19.37 0-0.163 0.002-0.326 0.006-0.489l-0 0.024c-0.008-0.308-0.008-0.617 0-0.927 0.259-10.499 8.832-18.912 19.37-18.912 0.164 0 0.327 0.002 0.489 0.006l-0.024-0h348.637c0.31-0.008 0.619-0.008 0.927 0 10.5 0.258 18.913 8.832 18.913 19.37 0 0.163-0.002 0.325-0.006 0.487l0-0.024v127.55h-19.835c-0.242-0.016-0.525-0.025-0.81-0.025s-0.568 0.009-0.848 0.027l0.038-0.002c-7.036 0.44-12.576 6.253-12.576 13.361 0 0.285 0.009 0.568 0.026 0.848l-0.002-0.038v51.027h-28.345c-0.242-0.016-0.525-0.026-0.81-0.026s-0.568 0.009-0.848 0.028l0.038-0.002c-7.036 0.439-12.576 6.253-12.576 13.361 0 0.285 0.009 0.568 0.026 0.849l-0.002-0.038v150.231c-0.015 0.242-0.024 0.525-0.024 0.81s0.009 0.568 0.026 0.849l-0.002-0.039c0.44 7.036 6.253 12.576 13.361 12.576 0.285 0 0.568-0.009 0.848-0.026l-0.038 0.002h16.988v73.708c-0.015 0.242-0.024 0.525-0.024 0.81s0.009 0.568 0.026 0.849l-0.002-0.039c0.44 7.036 6.253 12.576 13.361 12.576 0.285 0 0.568-0.009 0.848-0.026l-0.038 0.002h87.88c7.614-0.508 13.663-6.558 14.169-14.125l0.002-0.046v-73.708h17.020c7.613-0.508 13.663-6.558 14.169-14.125l0.002-0.046v-150.231c0.015-0.242 0.024-0.525 0.024-0.81s-0.009-0.568-0.026-0.849l0.002 0.039c-0.44-7.036-6.253-12.576-13.361-12.576-0.285 0-0.568 0.009-0.849 0.026l0.038-0.002zM419.817 838.628c-78.27-0-141.72-63.451-141.721-141.721l-0-0v-128.622c39.238 15.044 84.626 23.758 132.050 23.758 0.362 0 0.725-0.001 1.087-0.002l-0.056 0c53.947-0.658 105.564-9.668 153.928-25.792l-3.567 1.031v129.627c0 0 0 0 0 0.001 0 78.27-63.45 141.72-141.72 141.72-0 0-0.001-0-0.001-0l-0-0zM561.406 478.666v59.429c-1.472 0.537-2.967 0.977-4.443 1.498-40.894 14.778-88.088 23.322-137.277 23.322s-96.383-8.544-140.178-24.229l2.901 0.907c-1.476-0.521-2.97-0.961-4.443-1.498v-59.429c0.112-75.639 59.607-137.345 134.355-140.999l0.328-0.013c1.976 1.341 4.414 2.142 7.039 2.142s5.063-0.8 7.083-2.17l-0.044 0.028c75.073 3.671 134.565 65.375 134.679 141l0 0.011zM717.298 353.931h39.67v36.855h-39.67zM768.325 628.895h-59.537v-59.535h59.537zM799.516 541.015h-121.885v-121.886h96.356c0.242 0.016 0.525 0.025 0.81 0.025s0.568-0.009 0.848-0.027l-0.038 0.002h23.91z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle_Artboard 38-28"],"grid":0},"attrs":[{},{}],"properties":{"order":2,"id":29,"name":"mouse","prevSize":32,"code":59648},"setIdx":0,"setId":3,"iconIdx":30},{"icon":{"paths":["M872.533 217.144h-719.605c-25.924 0.031-46.931 21.038-46.962 46.959l-0 0.003v440.113c0.031 25.924 21.038 46.931 46.959 46.962l719.608 0c25.924-0.031 46.931-21.038 46.962-46.959l0-0.003v-440.113c-0.031-25.924-21.038-46.931-46.959-46.962l-0.003-0zM883.37 296.264v353.165l-248.941-200.624zM879.724 256.129l-365.318 223.853-357.207-226.712h715.334c2.783 0.028 5.307 1.11 7.198 2.865l-0.007-0.006zM142.090 286.47l254.984 161.833-254.984 200.865zM872.533 715.058h-719.605c-5.952-0.081-10.756-4.885-10.837-10.83l-0-0.008v-9.067l287.314-226.331 75.153 47.697c2.741 1.764 6.088 2.812 9.68 2.812 3.491 0 6.751-0.99 9.514-2.704l-0.077 0.045 78.048-47.824 281.648 226.984v8.39c-0.081 5.952-4.885 10.756-10.83 10.837l-0.008 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-01"],"grid":0},"attrs":[{}],"properties":{"order":3,"id":30,"name":"mail","prevSize":32,"code":59649},"setIdx":0,"setId":3,"iconIdx":31},{"icon":{"paths":["M518.18 771.87c-0.007 0-0.014 0-0.022 0-4.957 0-9.447-2.003-12.703-5.243l0.001 0.001-382.804-379.943c-3.283-3.271-5.315-7.797-5.315-12.797 0-9.976 8.087-18.063 18.063-18.063 4.953 0 9.44 1.993 12.703 5.222l-0.002-0.002 370.026 367.26 366.94-367.207c3.272-3.287 7.8-5.321 12.803-5.321 9.976 0 18.063 8.087 18.063 18.063 0 4.998-2.030 9.521-5.31 12.792l-0 0-379.664 379.943c-3.262 3.271-7.774 5.295-12.758 5.295-0.007 0-0.014-0-0.020-0l0.001 0z"],"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":21.674936351041396}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-02"],"grid":0},"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":21.674936351041396}],"properties":{"order":4,"id":31,"name":"down","prevSize":32,"code":59650},"setIdx":0,"setId":3,"iconIdx":32},{"icon":{"paths":["M897.386 771.87c-0.007 0-0.016 0-0.025 0-4.955 0-9.443-2.003-12.697-5.243l0.001 0.001-370.033-367.26-366.939 367.207c-3.268 3.264-7.781 5.283-12.765 5.283-9.976 0-18.063-8.087-18.063-18.063 0-4.979 2.015-9.488 5.273-12.755l-0 0 379.664-379.943c3.27-3.271 7.788-5.294 12.778-5.294 4.964 0 9.46 2.002 12.726 5.243l-0.001-0.001 382.804 379.943c3.299 3.273 5.341 7.809 5.341 12.822 0 9.975-8.086 18.061-18.061 18.061-0.001 0-0.001-0-0.002-0l0 0z"],"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":21.674936351041396}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-03"],"grid":0},"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":21.674936351041396}],"properties":{"order":5,"id":32,"name":"up","prevSize":32,"code":59651},"setIdx":0,"setId":3,"iconIdx":33},{"icon":{"paths":["M293.208 894.498c-0-0.007-0-0.016-0-0.024 0-4.955 2.003-9.443 5.243-12.698l-0.001 0.001 367.26-370.033-367.207-366.939c-3.279-3.271-5.309-7.794-5.309-12.79 0-9.976 8.087-18.063 18.063-18.063 4.992 0 9.51 2.025 12.78 5.298l0 0 379.943 379.664c3.271 3.27 5.294 7.788 5.294 12.778 0 4.964-2.002 9.46-5.243 12.726l0.001-0.001-379.942 382.804c-3.273 3.299-7.809 5.341-12.822 5.341-9.975 0-18.061-8.086-18.061-18.061 0-0.001 0-0.001 0-0.002l-0 0z"],"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":21.674936351041396}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-04"],"grid":0},"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":21.674936351041396}],"properties":{"order":6,"id":33,"name":"right","prevSize":32,"code":59652},"setIdx":0,"setId":3,"iconIdx":34},{"icon":{"paths":["M690.966 132.028c0 0.007 0 0.016 0 0.025 0 4.955-2.003 9.443-5.243 12.697l0.001-0.001-367.26 370.033 367.207 366.939c3.264 3.268 5.283 7.781 5.283 12.765 0 9.976-8.087 18.063-18.063 18.063-4.979 0-9.488-2.015-12.755-5.273l0 0-379.943-379.664c-3.271-3.27-5.294-7.787-5.294-12.778 0-4.964 2.002-9.46 5.243-12.726l-0.001 0.001 379.943-382.804c3.273-3.299 7.809-5.341 12.822-5.341 9.975 0 18.061 8.086 18.061 18.061 0 0.001-0 0.001-0 0.002l0-0z"],"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":21.674936351041396}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-05"],"grid":0},"attrs":[{"strokeLinejoin":"miter","strokeLinecap":"butt","strokeMiterlimit":"10","strokeWidth":21.674936351041396}],"properties":{"order":7,"id":34,"name":"left","prevSize":32,"code":59653},"setIdx":0,"setId":3,"iconIdx":35},{"icon":{"paths":["M846.17 444.214c-2.896-50.365-24.124-95.278-57.050-128.61l0.020 0.020-40.169-40.169c2.922-7.065 4.619-15.269 4.619-23.87 0-20.666-9.797-39.044-25.001-50.742l-0.151-0.111c-59.514-43.036-133.955-68.836-214.423-68.836s-154.909 25.8-215.504 69.58l1.081-0.744c-15.632 11.56-25.656 29.929-25.656 50.639 0 8.746 1.788 17.074 5.018 24.639l-0.156-0.41-40.024 40.024c-32.392 33.587-53.434 78.311-56.841 127.885l-0.035 0.636c-45.157 12.298-77.864 52.801-78.171 100.993l-0 0.035v27.017c0.33 57.679 46.999 104.347 104.646 104.677l0.031 0h33.762c27.163-1.935 48.725-23.484 50.671-50.466l0.010-0.176v-135.047c-0.679-27.714-22.968-50.003-50.618-50.681l-0.064-0.001h-26.246c3.843-39.602 20.85-74.64 46.528-101.258l-0.048 0.051 37.172-37.201c10.266 7.594 23.176 12.156 37.151 12.156 13.97 0 26.875-4.558 37.31-12.268l-0.171 0.121s141.753-101.364 276.8 0c9.021 8.401 21.161 13.558 34.505 13.558 0.932 0 1.858-0.025 2.777-0.075l-0.128 0.006c15.199-0.349 29.138-5.462 40.456-13.898l-0.186 0.133 37.429 37.429c25.185 26.838 42.022 61.778 46.209 100.512l0.068 0.774h-26.004c-27.714 0.679-50.003 22.968-50.681 50.618l-0.001 0.064v134.969c0.679 27.713 22.969 50.003 50.618 50.68l0.064 0.001 34.568-0.013c57.624-1.163 103.891-48.15 103.891-105.944 0-0.729-0.007-1.456-0.022-2.182l0.002 0.109v-23.626c-0.306-48.185-32.958-88.661-77.318-100.825l-0.738-0.173zM244.097 470.904c8.381 0.524 14.98 7.449 14.98 15.916 0 0.34-0.011 0.677-0.032 1.011l0.002-0.046v134.93c0.019 0.288 0.029 0.625 0.029 0.965 0 8.806-7.139 15.946-15.946 15.946-0.339 0-0.676-0.011-1.010-0.031l0.046 0.002h-33.762c-39.077-0.22-70.696-31.839-70.915-70.894l-0-0.021v-23.625c0.22-39.077 31.839-70.696 70.894-70.915l0.021-0v-3.236h33.762c0.288-0.019 0.625-0.029 0.965-0.029s0.676 0.011 1.011 0.031l-0.046-0.002zM671.051 275.117c-41.881-31.512-94.727-50.522-152.007-50.682l-0.037-0c-60.521 0.658-116.511 19.51-162.91 51.33l1.001-0.648c-5.127 3.785-11.572 6.058-18.548 6.058-17.353 0-31.421-14.068-31.421-31.421 0-10.352 5.006-19.535 12.73-25.259l0.085-0.060c53.866-39.011 121.267-62.401 194.13-62.401s140.265 23.39 195.104 63.071l-0.973-0.671c7.808 5.785 12.815 14.967 12.815 25.319 0 17.353-14.068 31.421-31.421 31.421-6.976 0-13.42-2.273-18.634-6.119l0.086 0.061zM890.426 572.034c-0.22 39.077-31.839 70.696-70.894 70.915l-0.021 0h-33.762c-0.288 0.019-0.625 0.029-0.965 0.029-8.806 0-15.946-7.139-15.946-15.946 0-0.339 0.011-0.676 0.031-1.010l-0.002 0.046v-135.047c-0.019-0.288-0.029-0.625-0.029-0.965 0-8.806 7.139-15.945 15.945-15.945 0.34 0 0.677 0.011 1.011 0.032l-0.046-0.002 33.762-0.039c39.077 0.22 70.696 31.839 70.915 70.894l0 0.021z","M461.661 497.964c-0.013-0-0.027-0-0.042-0-9.308 0-16.857 7.534-16.881 16.837l-0 0.002v33.761c-0 0.031-0 0.067-0 0.103 0 9.323 7.558 16.881 16.881 16.881s16.881-7.558 16.881-16.881c0-0.022-0-0.045-0-0.067l0 0.003v-33.8c-0.024-9.29-7.549-16.815-16.836-16.839l-0.002-0z","M579.786 514.803v-0.084c-0.024-9.305-7.573-16.839-16.881-16.839-9.323 0-16.881 7.558-16.881 16.881 0 0.015 0 0.030 0 0.044l-0-0.002v33.761c-0 0.033-0 0.071-0 0.11 0 9.323 7.558 16.881 16.881 16.881s16.881-7.558 16.881-16.881c0-0.025-0-0.050-0-0.075l0 0.004z","M630.429 727.51h-101.286v-50.643h50.643q3.102 0.124 6.205 0c41.707-1.712 74.87-35.939 74.87-77.91 0-1.091-0.022-2.177-0.067-3.257l0.005 0.155v-124.755c-0.628-44.488-36.526-80.385-80.953-81.012l-0.060-0.001h-135.048c-44.487 0.627-80.385 36.525-81.012 80.953l-0.001 0.060v124.755c0.627 44.487 36.525 80.385 80.953 81.012l0.060 0.001h50.643v50.643h-101.285c-18.628 0.044-33.717 15.133-33.762 33.757l-0 0.004v97.894c0.045 18.628 15.134 33.717 33.757 33.762l0.004 0h236.333c18.115-1.263 32.498-15.646 33.755-33.648l0.006-0.114v-97.894c-0.045-18.628-15.134-33.717-33.758-33.762l-0.004-0zM394.056 595.698v-124.755c0.679-27.713 22.968-50.003 50.618-50.68l0.064-0.001h135.048c27.713 0.679 50.003 22.968 50.68 50.618l0.001 0.064v124.755c-0.679 27.713-22.968 50.003-50.618 50.68l-0.064 0.001h-135.048c-27.713-0.679-50.003-22.968-50.68-50.618l-0.001-0.064zM630.429 859.166h-236.333v-97.894l118.166 0.003c0.287 0.017 0.623 0.026 0.961 0.026 0.312 0 0.621-0.008 0.929-0.024l0.003-0.005h116.274z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-06"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":8,"id":35,"name":"headphones","prevSize":32,"code":59654},"setIdx":0,"setId":3,"iconIdx":36},{"icon":{"paths":["M844.024 280.96h-662.261q-0.627-0.007-1.254 0c-25.872 0.353-46.71 21.409-46.71 47.332 0 0.221 0.002 0.441 0.005 0.661l-0-0.033v440.527q-0.008 0.627 0 1.254c0.354 25.872 21.41 46.71 47.332 46.71 0.221 0 0.441-0.002 0.66-0.005l-0.033 0h662.261q0.609 0.007 1.219-0c25.872-0.354 46.71-21.41 46.71-47.333 0-0.22-0.002-0.44-0.004-0.659l0 0.033v-332.511c0.006-0.078 0.030-0.15 0.035-0.229v-107.787q0.008-0.627 0-1.254c-0.354-25.872-21.41-46.71-47.333-46.71-0.22 0-0.44 0.002-0.66 0.005l0.033-0zM861.983 328.919v89.897h-332.636v-107.891h314.643c9.655 0.673 17.32 8.339 17.99 17.933l0.003 0.061zM181.763 310.925h317.618v107.891h-335.611v-89.897c0.673-9.655 8.338-17.32 17.932-17.99l0.061-0.003zM862.017 772.457c-0.673 9.655-8.338 17.321-17.932 17.99l-0.061 0.003h-662.261c-9.655-0.673-17.32-8.339-17.99-17.933l-0.003-0.061v-320.629h335.611v158.791l-80.936-80.936c-2.626-2.392-6.133-3.857-9.982-3.857-8.198 0-14.845 6.646-14.845 14.845 0 3.849 1.465 7.356 3.868 9.994l-0.011-0.012 107.892 107.891c2.46 1.879 5.579 3.011 8.962 3.011s6.502-1.132 8.998-3.037l-0.036 0.026 107.891-107.891c2.392-2.626 3.857-6.133 3.857-9.982 0-8.198-6.646-14.845-14.845-14.845-3.849 0-7.356 1.465-9.994 3.868l0.012-0.011-80.867 80.866v-158.721h332.671z","M652.221 382.899c0 0 0 0 0 0 9.937 0 17.993-8.056 17.993-17.993l0-0c-0.673-9.655-8.339-17.321-17.933-17.99l-0.061-0.003c-0.011-0-0.023-0-0.036-0-9.937 0-17.993 8.056-17.993 17.993s8.056 17.993 17.993 17.993c0.013 0 0.025-0 0.038-0l-0.002 0z","M739.178 364.906c0 9.938-8.056 17.994-17.994 17.994s-17.994-8.056-17.994-17.994c0-9.938 8.056-17.994 17.994-17.994s17.994 8.056 17.994 17.994z","M790.113 382.899c9.938 0 17.994-8.056 17.994-17.994s-8.056-17.994-17.994-17.994c-9.938 0-17.994 8.056-17.994 17.994h-0c-0 0-0 0-0 0 0 9.937 8.056 17.993 17.993 17.993 0 0 0-0 0-0l-0-0z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-07"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":9,"id":36,"name":"download","prevSize":32,"code":59655},"setIdx":0,"setId":3,"iconIdx":37},{"icon":{"paths":["M705.32 552.894c-0.010-0-0.022-0-0.033-0-7.483 0-13.552 6.057-13.571 13.535l-0 0.002v249.701h-390.866q-0.377 0.003-0.755 0c-25.109-0.214-45.382-20.618-45.382-45.757 0-0.133 0.001-0.265 0.002-0.398l-0 0.020v-462.611c11.585 10.198 26.68 16.655 43.264 17.363l0.144 0.005h282.297c5.422 0 13.572-5.328 13.603-8.055 0.015-0.232 0.024-0.503 0.024-0.776 0-7.080-5.739-12.819-12.819-12.819-0.273 0-0.544 0.009-0.813 0.025l0.037-0.002h-282.296q-2.020 0.093-4.041 0c-18.061-0.851-33.216-12.428-39.298-28.467l-0.101-0.304v-20.128c-0.022-2.425-0.684-4.691-1.824-6.643l0.034 0.064c4.33-21.127 22.769-36.794 44.867-36.794 0.128 0 0.255 0.001 0.383 0.002l-0.020-0h401.745c7.493-0.003 13.565-6.078 13.565-13.571 0-7.495-6.076-13.571-13.571-13.571-0.022 0-0.044 0-0.066 0l0.003-0h-401.709c-34.512 1.508-62.495 27.587-66.958 61.1l-0.039 0.36c-2.203 2.391-3.553 5.596-3.553 9.117 0 0.002 0 0.003 0 0.005l-0-0v515.701c0.708 38.694 31.889 69.874 70.516 70.581l0.067 0.001h401.709c7.806-0.891 14.523-4.935 18.942-10.806l0.051-0.070v-263.273c-0.019-7.469-6.069-13.518-13.535-13.537l-0.002-0z","M539.643 681.975c0.421 6.738 5.989 12.043 12.796 12.043 0.273 0 0.544-0.009 0.813-0.025l-0.037 0.002c5.058-0.172 9.093-4.314 9.093-9.398 0-1.52-0.361-2.956-1.002-4.227l0.025 0.054v-29.869c0.001-0.193 0.002-0.422 0.002-0.651 0-32.184-15.983-60.634-40.444-77.847l-0.302-0.202c13.219-13.216 21.472-31.4 21.719-51.51l0-0.047c0-41.976-34.028-76.004-76.004-76.004s-76.004 34.028-76.004 76.004v0c0.248 20.158 8.5 38.341 21.719 51.557l0 0c-24.471 17.944-40.298 46.428-40.743 78.629l-0.001 0.070v29.937c0.019 7.481 6.088 13.537 13.571 13.537 7.495 0 13.571-6.076 13.571-13.571 0-0.012-0-0.024-0-0.036l0 0.002v-29.869c-0.015-0.532-0.024-1.159-0.024-1.787 0-28.709 17.82-53.255 43.003-63.182l0.46-0.16c5.422-2.695 8.149-5.421 8.149-10.844 0.127-0.264 0.243-0.534 0.346-0.807 0.404-1.039 0.638-2.241 0.638-3.498 0-4.213-2.631-7.811-6.339-9.242l-0.068-0.023c-14.612-7.576-24.423-22.587-24.423-39.89 0-0.301 0.003-0.6 0.009-0.9l-0.001 0.045c-0-0.043-0-0.094-0-0.146 0-26.986 21.877-48.863 48.863-48.863s48.863 21.877 48.863 48.863c0 0.051-0 0.102-0 0.153l0-0.008c0.005 0.254 0.008 0.554 0.008 0.855 0 17.302-9.812 32.313-24.175 39.772l-0.249 0.118c-3.273 3.574-5.313 8.324-5.422 13.549l-0 0.022c0 5.422 2.727 8.118 8.149 10.844 25.723 10.91 43.437 35.951 43.439 65.129l0 0v29.869c-0.015 0.232-0.024 0.503-0.024 0.776s0.009 0.544 0.026 0.813l-0.002-0.037z","M816.707 270.564c-17.834-10.252-39.213-16.299-62.004-16.299-0.151 0-0.302 0-0.453 0.001l0.023-0c-0.334-0.003-0.729-0.005-1.125-0.005-51.65 0-96.729 28.132-120.75 69.91l-0.359 0.676c-1.438 1.413-2.423 3.282-2.721 5.372l-0.006 0.050c-7.616 17.4-12.048 37.678-12.048 58.991 0 15.757 2.422 30.948 6.915 45.221l-0.289-1.066-40.744 54.284c-1.3 1.903-2.075 4.254-2.075 6.785s0.776 4.882 2.102 6.827l-0.027-0.042c3.575 3.273 8.325 5.313 13.55 5.422l0.022 0 70.582-10.844c5.066 5.889 11.434 10.516 18.667 13.454l0.326 0.117c18.699 10.262 40.974 16.299 64.659 16.299 0.165 0 0.33-0 0.495-0.001l-0.025 0 2.851-0.001c49.928-1.704 93.026-29.393 116.358-69.906l0.359-0.676c10.161-18.704 16.135-40.956 16.135-64.603 0-51.285-28.097-96.007-69.737-119.613l-0.682-0.356zM849.084 441.566c-18.818 33.883-54.209 56.542-94.932 57.010l-0.065 0.001c-1.586 0.086-3.442 0.135-5.309 0.135-19.018 0-36.848-5.087-52.204-13.974l0.502 0.268c-7.261-3.808-13.508-8.325-19.024-13.6l0.031 0.029c-1.791-1.734-4.235-2.802-6.929-2.802-0.43 0-0.854 0.027-1.27 0.080l0.049-0.005-0.031 0.031-46.135 5.422 24.415-29.869c2.727-5.422 5.454-8.149 2.727-13.571-4.983-12.33-7.875-26.629-7.875-41.603 0-17.411 3.909-33.908 10.896-48.663l-0.295 0.692c0-2.696 2.727-2.696 2.727-5.423 19.281-34.255 55.407-57.014 96.849-57.014 0.308 0 0.616 0.001 0.923 0.004l-0.047-0c18.948 0.345 36.657 5.331 52.136 13.864l-0.58-0.293q1.385 0.735 2.747 1.509c32.989 19 54.84 54.064 54.84 94.232 0 19.689-5.25 38.151-14.427 54.064l0.279-0.524z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-08"],"grid":0},"attrs":[{},{},{}],"properties":{"order":10,"id":37,"name":"chat","prevSize":32,"code":59656},"setIdx":0,"setId":3,"iconIdx":38},{"icon":{"paths":["M899.328 370.796c0-5.635-0.028-8.75-4.484-11.613-1.231-1.825-2.932-3.248-4.931-4.112l-0.073-0.028-415.632-238.132c-2.224-1.519-4.972-2.426-7.932-2.426s-5.707 0.907-7.981 2.458l0.049-0.032-298.251 174.496c-3.793 2.981-6.235 7.533-6.338 12.659l-0 0.017c0 1.095 0.013 2.067 0.045 2.989-0.005 0.117-0.043 0.228-0.045 0.346v117.234l0.001 0.14-0.001 0.006v117.234c0 1.095 0.013 2.067 0.045 2.989-0.005 0.117-0.043 0.228-0.045 0.346v117.234c0 6.338 0 9.489 6.338 12.676l408.097 236.765c2.029 3.5 5.346 6.063 9.286 7.060l0.103 0.022c0.219 0.074 0.486 0.141 0.76 0.189l0.034 0.005c0.34 0.064 0.673 0.135 1.020 0.175 0.845 0.079 1.74 0.107 2.668 0.107l0.041-0c0.265 0.017 0.574 0.026 0.886 0.026s0.621-0.009 0.928-0.028l-0.042 0.002c0.211-0.013 0.404-0.078 0.612-0.1l0.047-0.007c4.662-0.496 8.635-3.076 11.015-6.777l0.036-0.059 297.404-174.001c3.793-2.981 6.235-7.533 6.337-12.659l0-0.017v-117.235c0-1.095-0.013-2.067-0.045-2.988 0.005-0.117 0.043-0.228 0.045-0.346v-117.234l-0.001-0.14 0.001-0.006zM597.927 674.746l269.675-158.103v82.504l-269.675 158.815zM867.602 478.579l-269.675 158.816v-83.216l269.675-158.103zM566.2 635.885l-385.004-220.76h1.098v-82.503l383.906 219.819zM182.295 535.693v-82.504l383.906 219.819v83.446l-385.006-220.761zM464.682 151.787l387.057 218.935-268.166 157.745-387.17-222.002zM182.295 656.262v-82.503l383.906 219.819v85.178l-387.129-222.493zM867.602 719.715l-269.675 158.816v-83.215l269.675-158.104z","M366.352 348.521c2.981 3.793 7.533 6.235 12.659 6.338l0.017 0h9.525l142.88-82.504q0.595-0.3 1.165-0.648c4.724-2.92 7.825-8.071 7.825-13.946 0-9.024-7.315-16.339-16.339-16.339-3.149 0-6.090 0.891-8.584 2.434l0.070-0.040-142.879 82.503c-4.972 2.964-8.251 8.314-8.251 14.429 0 2.842 0.708 5.518 1.957 7.862l-0.044-0.090z","M439.331 389.773c2.981 3.793 7.533 6.236 12.659 6.338l0.017 0h9.525l142.879-82.503q0.596-0.3 1.166-0.648c4.738-2.917 7.849-8.075 7.849-13.96 0-9.024-7.315-16.339-16.339-16.339-3.159 0-6.108 0.896-8.608 2.449l0.070-0.040-142.879 82.503c-4.972 2.964-8.251 8.314-8.251 14.429 0 2.842 0.708 5.518 1.957 7.862l-0.044-0.090z","M512.309 431.025c2.981 3.793 7.533 6.235 12.66 6.338l0.017 0h9.525l142.879-82.503q0.596-0.3 1.166-0.648c4.711-2.922 7.801-8.066 7.801-13.931 0-9.024-7.315-16.34-16.34-16.34-3.139 0-6.071 0.885-8.56 2.419l0.071-0.040-142.879 82.504c-4.972 2.964-8.251 8.314-8.251 14.43 0 2.841 0.708 5.518 1.957 7.862l-0.044-0.090z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-09"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":11,"id":38,"name":"books","prevSize":32,"code":59657},"setIdx":0,"setId":3,"iconIdx":39},{"icon":{"paths":["M716.89 180.792h-370.884c-40.969 0-74.181 33.212-74.181 74.181s33.212 74.181 74.181 74.181v0h370.884c40.969 0 74.181-33.212 74.181-74.181s-33.212-74.181-74.181-74.181v0zM716.925 298.247h-370.884c-23.899 0-43.273-19.374-43.273-43.273s19.374-43.273 43.273-43.273v0h370.884c23.899-0 43.273 19.374 43.273 43.273s-19.374 43.273-43.273 43.273v0z","M704.541 520.877c-42.674 0.001-77.267 34.595-77.267 77.269 0 0 0 0 0 0l-0-0v160.603c-0.004 0.501-0.004 1.004 0 1.505 0.425 41.935 34.519 75.766 76.514 75.766 0.265 0 0.529-0.001 0.793-0.004l-0.040 0c42.393-0.691 76.577-34.874 77.268-77.201l0.001-0.066v-160.603c-0-42.675-34.595-77.269-77.269-77.269l0 0zM750.937 755.573c0 0.017 0 0.038 0 0.058 0 25.624-20.772 46.396-46.396 46.396s-46.396-20.772-46.396-46.396c0-0.020 0-0.041 0-0.061l-0 0.003v-160.603c-0-0.017-0-0.038-0-0.058 0-25.624 20.772-46.396 46.396-46.396s46.396 20.772 46.396 46.396c0 0.020-0 0.041-0 0.061l0-0.003z","M704.541 496.075q0.935 0.010 1.869 0c40.042-0.528 72.3-33.111 72.3-73.229 0-0.328-0.002-0.656-0.006-0.984l0.001 0.050c0-40.959-33.204-74.163-74.163-74.163s-74.163 33.204-74.163 74.163c0 40.959 33.204 74.163 74.163 74.163v0zM704.541 378.62c23.675 0.526 42.73 19.58 43.256 43.205l0.001 0.050c0 0 0 0.001 0 0.001 0 23.89-19.366 43.256-43.256 43.256s-43.256-19.366-43.256-43.256c0-23.889 19.366-43.255 43.255-43.256l0-0z","M525.275 347.749c-40.928 0.042-74.090 33.23-74.090 74.163s33.162 74.121 74.086 74.163l0.004 0q0.931 0.010 1.867 0c40.044-0.528 72.302-33.113 72.302-73.232 0-0.327-0.002-0.654-0.006-0.98l0.001 0.050c-0-40.959-33.204-74.163-74.163-74.163l-0-0zM525.275 465.132c-23.89 0-43.256-19.366-43.256-43.256s19.366-43.256 43.256-43.256h0c0.673-0.017 1.348-0.017 2.021 0 22.898 0.564 41.245 19.261 41.245 42.243 0 0.356-0.004 0.711-0.013 1.065l0.001-0.052c0 0 0 0.001 0 0.001 0 23.889-19.366 43.255-43.255 43.256l-0 0z","M349.11 347.749c-40.928 0.042-74.090 33.23-74.090 74.163s33.162 74.121 74.086 74.163l0.004 0q0.935 0.010 1.867 0c40.043-0.527 72.302-33.111 72.302-73.229 0-0.328-0.002-0.656-0.006-0.983l0.001 0.050c-0-40.959-33.204-74.163-74.163-74.163l-0-0zM349.11 465.132c-23.89 0-43.256-19.366-43.256-43.256s19.366-43.256 43.256-43.256h-0c23.674 0.526 42.728 19.58 43.254 43.205l0.001 0.050c0 0 0 0.001 0 0.001 0 23.889-19.366 43.255-43.255 43.256l-0 0z","M525.275 517.738c-40.928 0.042-74.090 33.23-74.090 74.163s33.162 74.121 74.086 74.163l0.004 0c40.726-0.575 73.587-33.437 74.162-74.108l0.001-0.055c-0-40.959-33.204-74.163-74.163-74.163l0 0zM525.275 635.121c-23.89 0-43.256-19.366-43.256-43.256s19.366-43.256 43.256-43.256l0-0c0.841-0.062 1.821-0.098 2.81-0.098 22.391 0 40.542 18.151 40.542 40.542 0 0.989-0.035 1.969-0.105 2.94l0.007-0.13c0 0 0 0.001 0 0.001 0 23.889-19.366 43.255-43.255 43.256l-0 0z","M349.11 517.738c-40.928 0.042-74.090 33.23-74.090 74.163s33.162 74.121 74.086 74.163l0.004 0c40.726-0.575 73.588-33.437 74.162-74.108l0.001-0.055c-0-40.959-33.204-74.163-74.163-74.163l0 0zM349.11 635.121c-23.89 0-43.256-19.366-43.256-43.256s19.366-43.256 43.256-43.256l-0-0q1.010-0.026 2.024 0c22.897 0.565 41.243 19.261 41.243 42.242 0 0.356-0.004 0.711-0.013 1.065l0.001-0.052c0 0 0 0.001 0 0.001 0 23.889-19.366 43.255-43.255 43.256l-0 0z","M525.275 687.728c-40.928 0.042-74.090 33.23-74.090 74.163s33.162 74.121 74.086 74.163l0.004 0c40.726-0.575 73.587-33.437 74.162-74.108l0.001-0.055c-0-40.959-33.204-74.163-74.163-74.163l0 0zM525.275 802.041c-23.89 0-43.256-19.366-43.256-43.256s19.366-43.256 43.256-43.256l0-0v-0.035q1.029-0.026 2.059 0c22.883 0.584 41.209 19.273 41.209 42.242 0 0.368-0.005 0.736-0.014 1.102l0.001-0.054c0 0 0 0.001 0 0.001 0 23.889-19.366 43.255-43.255 43.256l-0 0z","M349.11 687.728c-40.928 0.042-74.090 33.23-74.090 74.163s33.162 74.121 74.086 74.163l0.004 0c40.726-0.575 73.588-33.437 74.162-74.108l0.001-0.055c-0-40.959-33.204-74.163-74.163-74.163l0 0zM349.11 802.041c-23.89 0-43.256-19.366-43.256-43.256s19.366-43.256 43.256-43.256l-0-0v-0.035c23.686 0.527 42.748 19.6 43.254 43.242l0.001 0.048c0 0 0 0.001 0 0.001 0 23.889-19.366 43.255-43.255 43.256l-0 0z","M794.194 118.978h-522.423c-32.389 0.021-58.638 26.282-58.638 58.674 0 0.013 0 0.025 0 0.038l-0-0.002v661.541c0.021 32.389 26.282 58.638 58.674 58.638 0.013 0 0.025-0 0.038-0l522.456 0c32.374-0.040 58.603-26.294 58.603-58.674 0-0.025-0-0.050-0-0.075l0 0.004v-661.507c-0.021-32.389-26.282-58.638-58.674-58.638-0.013 0-0.025 0-0.038 0l0.002-0zM825.1 839.158c-0.041 17.052-13.854 30.865-30.902 30.906l-0.004 0h-522.351c-17.053-0.040-30.867-13.853-30.908-30.902l-0-0.004v-661.435c0.041-17.053 13.855-30.866 30.905-30.906l0.004-0 522.351-0.037c17.053 0.041 30.866 13.855 30.906 30.905l0 0.004z"],"attrs":[{},{},{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-10"],"grid":0},"attrs":[{},{},{},{},{},{},{},{},{},{}],"properties":{"order":12,"id":39,"name":"calculator","prevSize":32,"code":59658},"setIdx":0,"setId":3,"iconIdx":40},{"icon":{"paths":["M804.888 347.33c0.678-1.525 1.073-3.304 1.073-5.175 0-1.857-0.389-3.624-1.090-5.222l0.033 0.084c-0.006-2.914-1.153-5.559-3.019-7.513l0.004 0.004-194.035-194.035c-2.593-1.383-5.603-2.428-8.784-2.974l-0.178-0.025h-337.329c-0.255-0.016-0.553-0.025-0.853-0.025s-0.598 0.009-0.894 0.027l0.041-0.002c-7.41 0.463-13.245 6.587-13.245 14.073 0 0.3 0.009 0.598 0.028 0.893l-0.002-0.040v725.399c-0.016 0.255-0.026 0.553-0.026 0.853 0 7.786 6.312 14.098 14.098 14.098 0.3 0 0.598-0.009 0.894-0.028l-0.040 0.002h531.364c8.962 0 14.926-5.963 11.961-17.89zM756.974 329.405h-143.294v-143.294zM276.489 860.872l-0-695.547h307.477v176.008c-0.016 0.255-0.026 0.553-0.026 0.853 0 7.786 6.312 14.098 14.098 14.098 0.3 0 0.598-0.009 0.893-0.028l-0.040 0.002h179.109v504.614z","M653.632 409.065c2.383-2.616 3.843-6.11 3.843-9.944 0-8.167-6.621-14.788-14.788-14.788-4.332 0-8.23 1.863-10.934 4.832l-0.011 0.012-103.015 103.015-103.015-103.015q-0.476-0.524-1-1c-2.616-2.383-6.11-3.843-9.944-3.843-8.167 0-14.788 6.621-14.788 14.788 0 4.332 1.863 8.23 4.832 10.934l0.012 0.011 103.015 103.015-102.981 102.981c-0.16 0.153-0.316 0.31-0.469 0.469-2.475 2.588-3.998 6.104-3.998 9.976 0 4.105 1.713 7.81 4.462 10.44l0.005 0.005c1.97 1.906 4.658 3.081 7.621 3.081 0.473 0 0.939-0.030 1.396-0.088l-0.054 0.006c5.963 0 8.962-2.965 11.927-2.999l102.981-102.981 102.981 102.981c1.97 1.906 4.658 3.081 7.621 3.081 0.473 0 0.939-0.030 1.396-0.088l-0.054 0.006c2.998 0 8.962-2.965 11.927-2.999 0.16-0.153 0.316-0.31 0.47-0.469 2.475-2.588 3.998-6.104 3.998-9.975 0-4.105-1.713-7.81-4.462-10.44l-0.005-0.005-102.981-102.981 103.015-103.015q0.524-0.476 1-1.001z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-11"],"grid":0},"attrs":[{},{}],"properties":{"order":13,"id":40,"name":"wrong","prevSize":32,"code":59659},"setIdx":0,"setId":3,"iconIdx":41},{"icon":{"paths":["M866.634 708.833c-4.572-4.999-10.498-8.689-17.197-10.491l-0.252-0.058v-176.333c-0.021-8.040-6.543-14.549-14.585-14.549-8.055 0-14.585 6.53-14.585 14.585 0 0.013 0 0.025 0 0.038l-0-0.002v175.155h-245.048c-0.056-0.001-0.122-0.001-0.188-0.001-5.058 0-9.565 2.357-12.483 6.033l-0.025 0.033c-3.524 2.979-6.204 6.853-7.698 11.272l-0.052 0.179-5.816 17.482h-64.145l-0.181-0.406-3.074-9.242c0.213-0.596 0.343-1.284 0.358-2l0-0.007v-52.513c0.007-0.45 0.011-0.981 0.011-1.513 0-36.73-18.331-69.178-46.344-88.695l-0.353-0.233c14.439-14.687 23.352-34.845 23.352-57.085 0-0.441-0.004-0.882-0.010-1.321l0.001 0.066c0-46.721-37.875-84.596-84.596-84.596s-84.596 37.875-84.596 84.596v0c0.232 22.599 9.071 43.089 23.388 58.389l-0.045-0.049c-28.365 19.75-46.696 52.197-46.696 88.927 0 0.532 0.004 1.064 0.012 1.594l-0.001-0.080v29.169h-52.513v-323.8c-0.016-0.249-0.025-0.54-0.025-0.834 0-7.609 6.168-13.776 13.776-13.776 0.293 0 0.584 0.009 0.873 0.027l-0.039-0.002h265.461c8.041-0.018 14.552-6.541 14.552-14.585s-6.511-14.566-14.551-14.585l-0.002-0h-265.46q-0.955-0.023-1.909 0c-21.611 0.534-38.927 18.179-38.927 39.87 0 0.336 0.004 0.671 0.012 1.004l-0.001-0.049v326.772c-8.513 0.502-15.891 4.949-20.387 11.522l-0.059 0.091c-2.521 4.384-4.008 9.64-4.008 15.243 0 2.881 0.393 5.671 1.129 8.318l-0.052-0.218v67.097c-0.016 0.249-0.025 0.54-0.025 0.834 0 7.609 6.168 13.776 13.776 13.776 0.293 0 0.584-0.009 0.873-0.027l-0.040 0.002h679.701c0.063 0.001 0.138 0.002 0.212 0.002 6.492 0 11.755-5.263 11.755-11.755 0-1.006-0.126-1.982-0.364-2.914l0.018 0.081v-67.097c1.315-2.74 2.083-5.956 2.083-9.351 0-5.33-1.893-10.218-5.043-14.028l0.030 0.037zM294.957 668.008c0.31-32.832 20.476-60.878 49.055-72.732l0.527-0.194c5.827-2.897 8.758-5.827 8.758-11.655q0.205-0.425 0.372-0.868c0.434-1.116 0.686-2.408 0.686-3.759 0-4.528-2.827-8.395-6.813-9.934l-0.073-0.025c-17.056-10.364-28.449-28.567-29.167-49.481l-0.003-0.101c0-30.611 24.815-55.426 55.426-55.426s55.426 24.815 55.426 55.426v0c0 0.047 0 0.103 0 0.159 0 21.167-11.649 39.612-28.886 49.276l-0.285 0.147c-3.519 3.84-5.713 8.946-5.827 14.562l-0 0.023c0 5.828 2.931 8.724 8.758 11.655 29.106 12.048 49.272 40.093 49.582 72.886l0 0.039v29.169h-157.538zM843.359 784.756h-650.498v-55.443c0-2.897-2.93-2.897-2.93-5.827h2.511c2.291 1.799 5.217 2.885 8.396 2.885 0.275 0 0.548-0.008 0.819-0.024l-0.037 0.002h250.875l3.795 8.544 2.032 6.108c0.984 2.959 2.382 5.525 4.155 7.783l-0.042-0.055 1.714 3.859c2.709 5.24 8.088 8.761 14.289 8.761 0.104 0 0.208-0.001 0.312-0.003l-0.016 0h81.683c0.322 0.034 0.696 0.054 1.074 0.054 5.897 0 10.678-4.781 10.678-10.678 0-0.411-0.023-0.816-0.068-1.215l0.004 0.049 11.58-26.071h259.675z","M528.316 490.057l84.58-14.585c6.385 7.288 14.153 13.191 22.916 17.334l0.427 0.182c20.882 12.834 46.174 20.436 73.242 20.436 0.919 0 1.836-0.009 2.75-0.026l-0.137 0.002c0.023-0.001 0.049-0.001 0.076-0.001 1.582 0 2.864 1.282 2.864 2.864 0 0.083-0.004 0.166-0.011 0.247l0.001-0.011c0.167 0.001 0.364 0.001 0.562 0.001 58.744 0 109.852-32.691 136.125-80.872l0.405-0.812c12.843-22.637 20.413-49.723 20.413-78.578 0-59.832-32.547-112.061-80.902-139.95l-0.781-0.415c-19.957-12.819-44.316-20.436-70.454-20.436-0.869 0-1.736 0.008-2.6 0.025l0.13-0.002c-1.696-0.066-3.688-0.104-5.688-0.104-58.959 0-110.281 32.696-136.825 80.945l-0.407 0.808c0 2.931-2.93 5.828-2.93 8.758-11.264 19.976-17.9 43.858-17.9 69.29 0 18.079 3.354 35.376 9.473 51.3l-0.331-0.979-49.582 64.167c-1.397 2.045-2.231 4.571-2.231 7.292s0.834 5.247 2.26 7.337l-0.029-0.045c3.841 3.517 8.946 5.71 14.561 5.827l0.024 0zM586.69 414.269c2.93-5.827 5.861-8.758 2.93-14.585-6.022-14.546-9.518-31.438-9.518-49.146 0-20.291 4.591-39.509 12.791-56.673l-0.342 0.794c0-2.897 2.931-2.897 2.931-5.827 23.495-40.385 66.571-67.1 115.887-67.1 0.279 0 0.557 0.001 0.835 0.003l-0.043-0c22.666 1.883 43.486 8.146 62.162 17.941l-0.891-0.426q0.709 0.381 1.414 0.77c40.425 22.662 67.298 65.237 67.298 114.089 0 23.142-6.030 44.875-16.605 63.714l0.338-0.656c-21.17 40.176-62.647 67.099-110.413 67.099-0.155 0-0.309-0-0.464-0.001l0.024 0c-0.137 0.001-0.299 0.001-0.462 0.001-24.494 0-47.47-6.499-67.298-17.866l0.661 0.349c-8.758-5.861-14.585-11.688-23.343-17.515-1.925-1.863-4.551-3.011-7.446-3.011-0.462 0-0.918 0.029-1.365 0.086l0.053-0.006 0.033 0.101-61.27 11.655z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-12"],"grid":0},"attrs":[{},{}],"properties":{"order":14,"id":41,"name":"conversation","prevSize":32,"code":59660},"setIdx":0,"setId":3,"iconIdx":42},{"icon":{"paths":["M510.319 170.069h-0.125c-0.002-0-0.004-0-0.006-0-188.207 0-340.778 152.572-340.778 340.778s152.572 340.778 340.778 340.778c188.207 0 340.778-152.572 340.778-340.778 0-0.045-0-0.090-0-0.134l0 0.007c-2.452-187.141-153.507-338.197-340.414-340.649l-0.233-0.002zM510.149 199.923c168.969 1.663 305.506 138.171 307.216 306.97l0.001 0.163c-1.662 168.984-138.193 305.532-307.012 307.22l-0.161 0.001c-168.953-1.683-305.47-138.184-307.176-306.97l-0.001-0.162c1.667-168.968 138.173-305.504 306.97-307.22l0.163-0.001z","M450.267 641.884c0.348 0.030 0.752 0.047 1.16 0.047 4.761 0 8.976-2.338 11.559-5.929l0.029-0.042 232.207-232.199c3.081-3.075 5.197-7.117 5.854-11.631l0.013-0.112 0.072-1.025c0.030-0.348 0.047-0.752 0.047-1.16 0-4.761-2.338-8.976-5.929-11.559l-0.042-0.029-1.864-1.86-2.615-0.278c-0.942-0.105-2.033-0.165-3.139-0.165-6.269 0-12.089 1.926-16.899 5.219l0.103-0.066-220.557 220.359-103.662-103.642c-3.287-2.952-7.656-4.758-12.447-4.758s-9.16 1.805-12.465 4.773l0.017-0.015-2.478 2.215v17.647l124.211 124.211z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-13"],"grid":0},"attrs":[{},{}],"properties":{"order":15,"id":42,"name":"correct","prevSize":32,"code":59661},"setIdx":0,"setId":3,"iconIdx":43},{"icon":{"paths":["M514.103 139.021h-0.106c-192.462 0.001-348.482 156.022-348.482 348.484s156.021 348.484 348.484 348.484c192.462 0 348.484-156.021 348.484-348.484 0-0.039-0-0.078-0-0.117l0 0.006c-2.512-191.385-156.995-345.865-348.142-348.37l-0.238-0.002zM830.266 483.622c-1.72 173.982-142.29 314.566-316.103 316.307l-0.166 0.001c-173.953-1.736-314.508-142.28-316.261-316.063l-0.001-0.167c1.713-173.968 142.259-314.546 316.052-316.307l0.167-0.001c173.971 1.715 314.55 142.265 316.31 316.062l0.001 0.168z","M659.985 324.563c-0.567-0.083-1.222-0.13-1.888-0.13-4.277 0-8.097 1.954-10.617 5.017l-0.019 0.024-133.465 133.461-133.994-133.98c-3.181-2.829-7.395-4.558-12.013-4.558-4.751 0-9.075 1.829-12.305 4.822l0.012-0.011c-2.923 2.952-4.729 7.014-4.729 11.498 0 1.898 0.324 3.721 0.919 5.416l-0.035-0.115c0.956 2.359 2.774 4.201 5.054 5.166l0.061 0.023 132.47 132.463-133.719 133.712c-3 2.986-5.058 6.917-5.688 11.309l-0.013 0.107-0.064 0.889c-0.034 0.357-0.053 0.772-0.053 1.192 0 4.427 2.157 8.35 5.477 10.776l0.038 0.026c2.53 3.111 6.358 5.082 10.645 5.082 3.070 0 5.903-1.010 8.187-2.717l-0.036 0.026c0.945-0.7 1.766-1.486 2.478-2.363l0.020-0.025 133.45-133.447 133.712 133.715c2.988 2.998 6.918 5.054 11.308 5.688l0.108 0.013 0.889 0.060c0.342 0.031 0.74 0.048 1.142 0.048 4.579 0 8.629-2.263 11.092-5.732l0.028-0.042c3-2.985 5.058-6.915 5.688-11.305l0.013-0.107 0.064-0.889c0.029-0.333 0.045-0.722 0.045-1.113 0-4.632-2.298-8.728-5.816-11.208l-0.043-0.029-133.598-129.888 135.214-135.214 0.296-2.163c0.224-1.558 0.937-2.92 1.975-3.954l0-0 1.926-1.909v-2.709c0.033-0.354 0.052-0.766 0.052-1.183 0-4.435-2.159-8.366-5.483-10.8l-0.038-0.026c-2.14-2.621-5.198-4.421-8.677-4.91l-0.072-0.008z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-14"],"grid":0},"attrs":[{},{}],"properties":{"order":16,"id":43,"name":"error","prevSize":32,"code":59662},"setIdx":0,"setId":3,"iconIdx":44},{"icon":{"paths":["M480.955 272.325c6.691-0 12.115-5.424 12.115-12.115s-5.424-12.115-12.115-12.115c-6.691 0-12.115 5.424-12.115 12.115v0c-0 0-0 0-0 0 0 6.691 5.424 12.115 12.115 12.115 0 0 0-0 0-0l-0 0z","M541.6 260.21c0 6.691-5.424 12.115-12.115 12.115s-12.115-5.424-12.115-12.115c0-6.691 5.424-12.115 12.115-12.115s12.115 5.424 12.115 12.115z","M587.083 260.21c0 6.691-5.424 12.115-12.115 12.115s-12.115-5.424-12.115-12.115c0-6.691 5.424-12.115 12.115-12.115s12.115 5.424 12.115 12.115z","M860.054 399.742h-148.565c-8.359 0.019-15.128 6.799-15.128 15.161s6.769 15.142 15.126 15.161l0.002 0h148.565c3.25 0.227 5.831 2.807 6.056 6.037l0.001 0.020v57.598h-151.647c-8.359 0.019-15.128 6.8-15.128 15.161s6.769 15.142 15.126 15.161l0.002 0h0.030l0.005 0h151.577v269.889c-0.227 3.25-2.807 5.831-6.037 6.057l-0.021 0.001h-445.731c-3.25-0.227-5.831-2.808-6.056-6.038l-0.001-0.020v-285.127c-0.021-3.473-1.217-6.663-3.211-9.197l0.024 0.032v-63.554c0.227-3.25 2.807-5.831 6.037-6.057l0.020-0.001h63.83v24.266c0 6.057 3.046 9.103 9.103 6.057l66.702-39.426c2.656-0.781 4.562-3.197 4.562-6.057s-1.906-5.276-4.517-6.046l-0.045-0.011-66.702-39.426c-6.057-3.047-12.115 0-9.103 6.058v24.264h-63.691q-1.393-0.055-2.786 0c-18.729 0.769-33.621 16.139-33.621 34.987 0 0.49 0.010 0.978 0.030 1.463l-0.002-0.069v63.691c-0.016 0.259-0.026 0.562-0.026 0.867s0.009 0.608 0.028 0.908l-0.002-0.041c0.189 3.041 1.307 5.79 3.069 8.002l-0.022-0.029v90.365h-212.292c-3.25-0.227-5.831-2.807-6.056-6.037l-0.001-0.021v-269.89h460.892v269.89c-0.227 3.249-2.806 5.83-6.035 6.056l-0.021 0.001h-72.761v-24.264c0-6.058-3.046-9.104-9.103-6.058l-66.702 39.427c-2.656 0.781-4.562 3.197-4.562 6.057s1.906 5.276 4.517 6.046l0.045 0.011 66.702 39.426c3.046 3.011 9.103 0 9.103-6.057v-24.265l72.878-0.019c1.067-0.076 2.057-0.242 3.012-0.492l-0.113 0.025c18.1-2.686 32.027-17.479 33.356-35.767l0.007-0.127v-285.051c0.016-0.259 0.026-0.562 0.026-0.867s-0.009-0.608-0.028-0.908l0.002 0.041c-0.19-3.041-1.307-5.79-3.069-8.002l0.022 0.029v-66.063q0.055-1.393 0-2.787c-0.769-18.729-16.139-33.621-34.987-33.621-0.49 0-0.978 0.010-1.463 0.030l0.069-0.002h-445.731q-1.393-0.055-2.787 0c-18.729 0.769-33.621 16.139-33.621 34.987 0 0.49 0.010 0.978 0.030 1.463l-0.002-0.069v72.76c-0.016 0.259-0.026 0.562-0.026 0.866s0.009 0.607 0.028 0.908l-0.002-0.041c0.005 0.087 0.034 0.166 0.041 0.252-0.004 0.344-0.062 0.676-0.041 1.025v285.052q-0.055 1.393 0 2.787c0.769 18.729 16.139 33.621 34.987 33.621 0.49 0 0.978-0.010 1.463-0.030l-0.069 0.002h212.292v163.761q-0.055 1.393 0 2.787c0.769 18.729 16.138 33.621 34.986 33.621 0.49 0 0.978-0.010 1.463-0.030l-0.069 0.002h445.731c19.982-0.272 36.108-16.398 36.38-36.354l0-0.026v-284.832c0.006-0.074 0.029-0.143 0.034-0.218v-72.76q0.056-1.392 0-2.786c-0.769-18.729-16.138-33.621-34.986-33.621-0.49 0-0.978 0.010-1.463 0.030l0.069-0.002zM168.698 229.957h445.731c3.25 0.227 5.831 2.807 6.057 6.037l0.001 0.021v57.564h-457.847v-57.564c0.227-3.25 2.808-5.831 6.037-6.056l0.020-0.001z","M741.776 460.351c-0.469-6.493-5.621-11.646-12.072-12.112l-0.043-0.002c-6.691 0-12.114 5.424-12.114 12.115s5.424 12.115 12.115 12.115c6.691 0 12.115-5.424 12.115-12.115 0-0-0-0-0-0l0 0z","M787.26 460.351c-0.469-6.493-5.621-11.646-12.072-12.112l-0.042-0.002h-0.001c-6.691 0-12.114 5.424-12.114 12.115s5.424 12.115 12.115 12.115c6.691 0 12.115-5.424 12.115-12.115 0-0-0-0-0-0l0 0z","M832.743 460.351c-0.469-6.493-5.621-11.646-12.073-12.112l-0.043-0.002c-6.69 0-12.114 5.424-12.114 12.115s5.424 12.115 12.115 12.115c6.691 0 12.115-5.424 12.115-12.115 0-0-0-0-0-0l0 0z"],"attrs":[{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-15"],"grid":0},"attrs":[{},{},{},{},{},{},{}],"properties":{"order":17,"id":44,"name":"interchange","prevSize":32,"code":59663},"setIdx":0,"setId":3,"iconIdx":45},{"icon":{"paths":["M854.148 580.744h-93.505v-227.257c36.991-7.399 64.473-39.615 64.473-78.249 0-0.256-0.001-0.511-0.004-0.766l0 0.039c0 0 0-0 0-0 0-44.508-36.081-80.589-80.589-80.589-38.802 0-71.2 27.423-78.868 63.945l-0.092 0.525h-214.394v-61.342c-0.020-33.781-27.41-61.158-61.193-61.158-0.013 0-0.026 0-0.039 0l-222.518-0c-33.781 0.020-61.158 27.41-61.158 61.193 0 0.013 0 0.026 0 0.039l-0-0.002v158.050c0.022 33.781 27.411 61.158 61.196 61.158 0.013 0 0.026-0 0.039-0l222.443 0c0.627-0.007 1.254-0.025 1.881-0.050 33.103-1.417 59.403-28.597 59.403-61.92 0-0.906-0.019-1.807-0.058-2.703l0.004 0.128v-61.158h214.392c6.651 31.671 31.177 56.196 62.322 62.753l0.526 0.093v227.271h-96.781c-33.781 0.022-61.157 27.412-61.157 61.196 0 0.013 0 0.026 0 0.039l-0-0.002v83.824h-214.394c-6.649-31.67-31.174-56.196-62.318-62.753l-0.526-0.093v-198.272h35.437c6.291 0 12.877-6.441 16.117-16.119 0.017-0.275 0.027-0.597 0.027-0.921s-0.010-0.646-0.029-0.965l0.002 0.044c-0.5-8.002-7.112-14.302-15.196-14.302-0.324 0-0.646 0.010-0.965 0.030l0.044-0.002h-96.781c-8.887 0.019-16.084 7.228-16.084 16.118s7.197 16.099 16.082 16.118l0.002 0h29.11v198.272c-37.048 7.76-64.473 40.159-64.473 78.962 0 44.508 36.081 80.59 80.59 80.59l-0-0c38.525-0.631 70.537-27.761 78.637-63.924l0.103-0.546h214.614v38.786c0.022 33.781 27.412 61.158 61.196 61.158 0.013 0 0.026-0 0.039-0l222.443 0q2.102 0.072 4.205-0.004c31.765-1.193 57.064-27.232 57.064-59.18 0-0.759-0.014-1.515-0.043-2.268l0.003 0.109v-154.736c-0.020-33.781-27.41-61.158-61.193-61.158-0.013 0-0.026 0-0.039 0l0.002-0zM389.939 384.021h-222.445c-17.787-0.042-32.194-14.45-32.236-32.232l-0-0.004v-154.663c0.043-17.786 14.45-32.192 32.232-32.234l0.004-0h222.445c17.785 0.043 32.191 14.449 32.234 32.23l0 0.004v76.466c-0.018 0.323-0.186 0.595-0.186 0.922s0.168 0.6 0.186 0.922v76.352c-0.042 17.786-14.448 32.193-32.23 32.236l-0.004 0zM696.147 274.606l0.025-0.095c0.002-0.048-0.002-0.095 0-0.143 0.089-26.64 21.702-48.202 48.352-48.21l0.001-0c26.46 0.648 47.741 21.929 48.388 48.328l0.001 0.061c-0.012 26.617-21.526 48.205-48.113 48.337l-0.013 0c-0.107-0.002-0.198-0.061-0.304-0.061-0.093 0-0.168 0.050-0.259 0.052-26.558-0.153-48.034-21.696-48.078-48.265l-0-0.004zM277.115 790.347c-26.725 0-48.39-21.665-48.39-48.39s21.665-48.39 48.39-48.39v0c1.353-0.147 2.923-0.231 4.512-0.231 24.361 0 44.109 19.748 44.109 44.109 0 1.589-0.084 3.159-0.248 4.705l0.017-0.192c-0 26.724-21.665 48.389-48.389 48.389l-0 0zM886.382 793.511c-0.043 17.785-14.449 32.191-32.23 32.234l-0.004 0h-222.445c-17.786-0.042-32.193-14.448-32.236-32.23l-0-0.004v-45.993c1.040-1.552 2.116-3.384 3.090-5.277l0.15-0.321c0.017-0.275 0.027-0.597 0.027-0.921s-0.010-0.646-0.029-0.965l0.002 0.044c-0.272-3.081-1.449-5.845-3.261-8.072l0.021 0.027v-93.258c0.042-17.787 14.45-32.194 32.232-32.236l0.004-0h222.445c17.786 0.043 32.192 14.45 32.234 32.232l0 0.004z","M792.879 874.098h-96.781c-8.887 0.019-16.084 7.228-16.084 16.118s7.197 16.099 16.082 16.118l0.002 0h96.781c8.887-0.019 16.084-7.228 16.084-16.118s-7.197-16.099-16.082-16.118l-0.002-0z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-16"],"grid":0},"attrs":[{},{}],"properties":{"order":18,"id":45,"name":"conectivity","prevSize":32,"code":59664},"setIdx":0,"setId":3,"iconIdx":46},{"icon":{"paths":["M844.289 726.372h-45.673v-95.209c-0.065-8.992-7.37-16.257-16.371-16.257-9.031 0-16.354 7.312-16.372 16.338l-0 0.002v95.126h-563.344v-356.988h29.533c9.024-0.023 16.33-7.343 16.33-16.37 0-9.041-7.329-16.37-16.37-16.37-0.014 0-0.028 0-0.043 0l0.002-0h-45.825c-0.28-0.019-0.606-0.029-0.936-0.029s-0.656 0.011-0.98 0.032l0.044-0.002c-8.128 0.508-14.527 7.224-14.527 15.435 0 0.329 0.010 0.656 0.031 0.98l-0.002-0.044v373.358h-45.823c-6.542 0-9.794 3.288-13.082 9.831-1.568 2.295-2.504 5.131-2.504 8.185s0.936 5.89 2.537 8.236l-0.033-0.050 39.283 65.484c3.076 3.916 7.774 6.437 13.065 6.542l0.017 0h638.469c6.542 0 9.831-3.365 16.523-6.616l39.133-65.41c1.54-2.304 2.458-5.137 2.458-8.185s-0.918-5.881-2.492-8.239l0.034 0.054c-3.251-6.542-6.542-9.83-13.082-9.83zM795.176 795.147h-622.138l-19.622-32.743h661.421z","M405.521 628.071h0.305c85.003-0.087 153.878-69.015 153.878-154.030 0-85.069-68.962-154.031-154.031-154.031s-154.031 68.962-154.031 154.031c0 85.015 68.875 153.944 153.87 154.030l0.008 0zM405.521 353.014h0.003c66.818 0.001 120.985 54.168 120.985 120.986s-54.167 120.986-120.986 120.986c-66.819 0-120.986-54.167-120.986-120.986s54.167-120.986 120.985-120.986l0-0z","M356.41 556.045c0 3.291 3.251 3.291 6.54 3.291s6.579-3.288 9.831-3.215l111.307-68.775c3.999-3.017 6.556-7.76 6.556-13.1s-2.558-10.083-6.515-13.071l-0.041-0.030-111.307-68.772c-2.304-1.54-5.137-2.458-8.185-2.458s-5.881 0.918-8.239 2.492l0.054-0.034c-3.916 3.076-6.437 7.774-6.542 13.065l-0 0.017v137.508c0 6.542 0 9.794 6.542 13.082zM379.32 434.908l65.484 39.283-65.484 39.283z","M893.555 241.71c-3.529 0.075-6.762 1.284-9.363 3.277l0.038-0.028h-206.94c-8.454-0.088-15.788-4.8-19.602-11.724l-0.059-0.117v-11.109c-0.042-2.616-0.704-5.067-1.844-7.227l0.042 0.087c3.012-9.167 11.47-15.68 21.457-15.736l0.007-0h209.571c9.020-0.028 16.322-7.346 16.322-16.37s-7.302-16.343-16.319-16.37l-0.003-0h-209.571c-26.672 0.854-48.23 21.631-50.316 47.891l-0.012 0.182c-1.254 2.17-2.017 4.761-2.077 7.526l-0 0.017v291.428c-0.005 0.457-0.005 0.912 0 1.368 0.386 28.27 23.393 51.038 51.718 51.038 0.241 0 0.482-0.002 0.722-0.005l-0.036 0h209.534c9.831 0 16.37-9.831 23.063-16.37v-291.428c-0.024-9.010-7.321-16.308-16.329-16.331l-0.002-0zM680.541 536.347c-0.358 0.009-0.715 0.009-1.071 0-12.129-0.298-21.848-10.202-21.848-22.375 0-0.188 0.002-0.376 0.007-0.563l-0.001 0.028v-246.733c5.774 2.627 12.502 4.247 19.585 4.454l0.076 0.002h199.853v265.187z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-17"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":19,"id":46,"name":"video","prevSize":32,"code":59665},"setIdx":0,"setId":3,"iconIdx":47},{"icon":{"paths":["M870.555 712.916v-64.655c0.016-0.24 0.025-0.521 0.025-0.803s-0.009-0.563-0.027-0.841l0.002 0.038c-0.24-2.723-1.291-5.163-2.906-7.12l0.018 0.022v-367.961c0.015-0.24 0.024-0.521 0.024-0.803s-0.009-0.563-0.026-0.842l0.002 0.038c-0.436-6.978-6.202-12.473-13.252-12.473-0.282 0-0.562 0.009-0.84 0.026l0.038-0.002h-64.655c-7.743 0.026-14.009 6.308-14.009 14.054s6.267 14.029 14.007 14.054l0.002 0h53.425v348.396h-632.463v-348.235h53.425c7.748-0.018 14.023-6.304 14.023-14.054s-6.274-14.036-14.021-14.054l-0.002-0h-64.655c-0.24-0.015-0.52-0.024-0.802-0.024s-0.562 0.009-0.84 0.026l0.038-0.002c-6.978 0.435-12.473 6.201-12.473 13.25 0 0.283 0.009 0.563 0.026 0.841l-0.002-0.038v376.505c-0.015 0.24-0.024 0.521-0.024 0.803s0.009 0.563 0.026 0.842l-0.002-0.038v63.048c-0.015 0.24-0.024 0.521-0.024 0.803s0.009 0.563 0.026 0.842l-0.002-0.038c0.436 6.977 6.201 12.471 13.25 12.471 0.283 0 0.563-0.009 0.841-0.026l-0.038 0.002h275.336v59.007c-53.262 8.439-103.864 28.109-103.864 61.832-0.015 0.24-0.024 0.521-0.024 0.803s0.009 0.563 0.026 0.842l-0.002-0.038c0.436 6.977 6.201 12.471 13.25 12.471 0.283 0 0.563-0.009 0.842-0.026l-0.038 0.002h283.904c0.305 0.025 0.66 0.040 1.018 0.040 6.578 0 12.014-4.891 12.868-11.235l0.007-0.067c0-33.723-47.779-53.393-98.378-61.832v-61.798h275.594c0.1 0.003 0.218 0.005 0.337 0.005 6.255 0 11.325-5.071 11.325-11.325 0-0.971-0.122-1.913-0.352-2.812l0.017 0.078zM569.709 814.086c27.184 3.045 51.926 11.018 74.171 23.024l-1.076-0.531-233.302-0.032c23.498-13.345 51.462-21.564 81.268-22.455l0.264-0.006c5.616 0 11.23-8.439 11.23-14.053v-73.063h56.216v73.063c-0.034 0.354-0.054 0.766-0.054 1.182 0 6.571 4.882 12.003 11.217 12.864l0.067 0.007zM845.174 701.686h-266.762c-2.221-1.79-5.076-2.873-8.184-2.873-0.228 0-0.454 0.006-0.679 0.017l0.032-0.001h-81.502c-0.24-0.015-0.521-0.024-0.803-0.024s-0.563 0.009-0.842 0.026l0.038-0.002c-2.705 0.238-5.13 1.277-7.079 2.875l0.023-0.018h-266.671v-39.337h632.429z","M314.37 378.7c4.712 115.669 99.593 207.662 215.974 207.727l0.007 0 0.022 0.004 0.032-0.002c0.036 0 0.078 0 0.121 0 1.796 0 3.57-0.098 5.315-0.289l-0.216 0.019c118.705-2.993 213.791-99.933 213.791-219.081 0-120.995-98.056-219.087-219.037-219.146l-0.077-0c-4.706 0.075-8.832 2.494-11.268 6.139l-0.032 0.050c-111.395 6.007-200.035 95.531-204.619 206.746l-0.014 0.43c-2.037 2.308-3.281 5.359-3.281 8.7 0 3.342 1.244 6.393 3.295 8.716l-0.012-0.014zM352.226 439.282c-6.551-16.205-11.033-34.974-12.541-54.575l-0.040-0.648h72.397c-0.004 0.561-0.006 1.223-0.006 1.887 0 59.938 17.902 115.694 48.652 162.214l-0.683-1.099c-49.53-19.753-88.025-58.248-107.326-106.496l-0.453-1.282zM544.426 384.059h72.308c-3.71 83.401-34.048 154.237-72.308 169.911zM544.426 355.952v-172.831c41.552 15.789 70.216 87.169 72.591 172.831zM516.188 558.16c-39.977-13.263-72.003-87.445-75.252-174.101h75.252zM516.188 184.454v171.498h-75.259q0.119-3.192 0.283-6.355c5.077-83.253 36.847-151.284 74.976-165.143zM597.817 547.092c0.598-0.959 0.981-2.019 1.569-2.981 26.364-36.392 44.308-93.416 48.238-160.052h70.35c-5.598 74.315-53.178 136.264-118.878 162.581l-1.28 0.453zM705.595 300.695c6.557 16.216 11.041 34.997 12.546 54.611l0.040 0.646h-70.071c-1.846-66.44-19.794-124.223-46.693-161.405 47.803 20.16 84.878 57.876 103.726 104.868l0.453 1.28zM460.004 192.885c-1.389 2.223-2.312 4.667-3.641 6.92-14.527 21.84-25.813 47.296-32.404 74.583l-0.332 1.628c-0.433 1.565-0.792 3.134-1.201 4.705q-3.379 14.183-5.658 29.414c-1.609 9.996-2.635 20.024-3.275 30.167q-0.55 7.738-0.802 15.65h-72.845c5.585-74.329 53.169-136.293 118.878-162.614l1.28-0.453z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-18"],"grid":0},"attrs":[{},{}],"properties":{"order":20,"id":47,"name":"desktop","prevSize":32,"code":59666},"setIdx":0,"setId":3,"iconIdx":48},{"icon":{"paths":["M793.804 366.638c-17.171-43.992-59.031-74.676-108.113-75.105l-0.053-0c-6.001 0-15.020 3.018-21.022 3.018-23.937-76.749-94.104-131.595-177.167-132.171l-0.068-0c-0.117-0-0.254-0-0.392-0-95.979 0-174.749 73.682-182.831 167.567l-0.047 0.684h-12.003c-87.848 0.122-159.015 71.365-159.015 159.23s71.167 159.107 159.003 159.23l0.012 0h39.268c8.296 0 15.021-6.725 15.021-15.021s-6.725-15.021-15.021-15.021v0h-39.062c-71.307-0.055-129.091-57.873-129.091-129.188s57.784-129.133 129.086-129.188l0.005-0c3.19 0.152 6.197 0.647 9.075 1.45l-0.287-0.068c4.264 18.594 14.48 56.428 48.071 67.617h6.002c0.337 0.050 0.725 0.079 1.12 0.079 4.406 0 7.979-3.572 7.979-7.979 0-0.396-0.029-0.784-0.084-1.165l0.005 0.043c0.633-1.502 1.001-3.248 1.001-5.080 0-6.197-4.211-11.411-9.927-12.937l-0.094-0.021c-16.469-4.702-25.544-27.827-28.714-43.411 1.292-2.377 2.052-5.206 2.052-8.212 0-0.818-0.056-1.623-0.165-2.411l0.010 0.091c-0-0.065-0-0.142-0-0.219 0-84.548 68.54-153.087 153.087-153.087 70.733 0 130.261 47.971 147.827 113.153l0.246 1.071c-18.806 12.485-31.034 33.571-31.034 57.514 0 0.886 0.017 1.769 0.050 2.647l-0.004-0.127c0 6.002 9.020 12.003 15.021 12.003 8.985-3.018 15.021-9.020 12.003-15.021-2.984-24.041 24.041-36.044 24.041-36.044 2.466-0.964 4.525-2.515 6.073-4.486l0.023-0.031c6.496-1.728 13.953-2.72 21.643-2.72 38.994 0 72.027 25.521 83.307 60.771l0.171 0.619c2.984 3.018 6.002 9.020 12.003 9.020 50.31 12.107 87.113 56.72 87.113 109.929 0 0.38-0.002 0.76-0.006 1.139l0-0.058v0.137c-0.039 62.985-51.107 114.029-114.097 114.029-0.024 0-0.048-0-0.073-0l-54.079 0c-8.296 0-15.021 6.725-15.021 15.021s6.725 15.021 15.021 15.021v-0h54.082c80.666-0.551 146.322-64.063 150.3-143.817l0.014-0.357c0.005-0.439 0.008-0.959 0.008-1.479 0-64.351-42.674-118.735-101.266-136.398l-1.009-0.261z","M628.781 649.732c0.332-1.306 0.523-2.806 0.523-4.35s-0.191-3.043-0.55-4.476l0.027 0.126v-40.095c0.053-0.406 0.083-0.875 0.083-1.352 0-2.981-1.183-5.686-3.105-7.671l0.003 0.003-78.124-78.124c-2.61-1.392-5.639-2.444-8.841-2.993l-0.179-0.025h-30.215c-0.257-0.017-0.557-0.026-0.859-0.026s-0.602 0.010-0.9 0.028l0.041-0.002h-100.238c-0.257-0.017-0.557-0.026-0.859-0.026s-0.602 0.010-0.899 0.028l0.041-0.002c-7.458 0.466-13.33 6.629-13.33 14.163 0 0.302 0.009 0.602 0.028 0.9l-0.002-0.041v276.381c-0.017 0.257-0.026 0.557-0.026 0.859 0 7.836 6.352 14.188 14.188 14.188 0.302 0 0.602-0.009 0.9-0.028l-0.041 0.002h210.295c8.846 0 14.848-6.002 12.038-17.97zM523.425 540.82h9.192l68.932 68.931v18.178h-78.124zM418.451 787.158l3.156-0.035v-246.303h71.775v102.129c-0.017 0.257-0.026 0.557-0.026 0.859 0 7.836 6.352 14.188 14.188 14.188 0.302 0 0.602-0.009 0.9-0.028l-0.041 0.002h93.318v129.188z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-19"],"grid":0},"attrs":[{},{}],"properties":{"order":21,"id":48,"name":"document","prevSize":32,"code":59667},"setIdx":0,"setId":3,"iconIdx":49},{"icon":{"paths":["M818.248 226.721v-3.145c-0.004-0.091 0.042-0.167 0.036-0.258v-33.045c0-0.064-0.036-0.112-0.036-0.176v-2.808c-0.066-2.603-0.803-5.021-2.043-7.104l0.037 0.067c-4.17-11.689-15.106-19.921-27.977-20.008l-0.011-0h-33.045v-12.068c0.002-0.091 0.003-0.199 0.003-0.306 0-6.382-3.623-11.918-8.925-14.664l-0.092-0.043-24.030-6c-6.967-2.094-14.972-3.299-23.259-3.299-33.395 0-62.219 19.572-75.627 47.87l-0.217 0.508c-3.26 9.762-5.411 21.048-5.986 32.748l-0.012 0.298c0.286 11.919 2.46 23.239 6.233 33.799l-0.235-0.753c12.396 28.514 40.317 48.091 72.812 48.091 0.794 0 1.586-0.012 2.375-0.035l-0.116 0.003c0.691 0.056 1.495 0.088 2.307 0.088 8.516 0 16.212-3.512 21.718-9.167l0.007-0.007 24.030-5.998c5.394-2.79 9.017-8.326 9.017-14.709 0-0.108-0.001-0.216-0.003-0.323l0 0.016v-2.946h33.045c0.513 0.033 1.113 0.052 1.716 0.052s1.203-0.019 1.798-0.056l-0.081 0.004c0.438-0.028 0.788-0.277 1.219-0.324-5.714 107.898-67.482 200.171-156.515 248.748l-1.574 0.786-110.961 57.039-110.958-57.039c-90.842-48.961-152.763-141.286-158.097-248.508l-0.028-0.702h31.943v8.98c-0.002 0.091-0.003 0.199-0.003 0.307 0 6.382 3.623 11.918 8.925 14.664l0.092 0.043 24.030 6c6.009 1.986 12.926 3.132 20.11 3.132 1.379 0 2.748-0.042 4.106-0.125l-0.186 0.009c0.587 0.015 1.278 0.023 1.971 0.023 31.025 0 58.151-16.692 72.887-41.586l0.215-0.393c3.26-9.762 5.411-21.048 5.986-32.748l0.012-0.298c-0.286-11.919-2.46-23.239-6.233-33.799l0.235 0.754c-12.599-29.070-41.044-49.037-74.153-49.037-8.919 0-17.499 1.449-25.519 4.124l0.569-0.165-24.030 5.998c-5.394 2.789-9.017 8.326-9.017 14.708 0 0.107 0.001 0.214 0.003 0.321l-0-0.016v6.001h-33.011c-12.857 0.086-23.778 8.283-27.907 19.726l-0.066 0.208c-1.232 2.033-1.988 4.477-2.057 7.092l-0 0.019v51.043c-0.016 0.257-0.025 0.556-0.025 0.858s0.009 0.602 0.027 0.899l-0.002-0.041c0.017 0.286 0.178 0.516 0.212 0.798 0.926 123.444 70.423 230.444 172.248 284.885l1.748 0.853 108.082 58.216v49.936h-21.047c-0.257-0.017-0.556-0.027-0.858-0.027s-0.602 0.010-0.899 0.029l0.040-0.002c-7.454 0.466-13.323 6.625-13.323 14.155 0 0.302 0.009 0.602 0.028 0.899l-0.002-0.041v168.173c-0.016 0.257-0.025 0.556-0.025 0.858s0.009 0.602 0.027 0.899l-0.002-0.041c0.465 7.455 6.626 13.325 14.157 13.325 0.301 0 0.6-0.009 0.897-0.028l-0.041 0.002h21.048v39.009c-0.016 0.257-0.025 0.556-0.025 0.858s0.009 0.602 0.027 0.899l-0.002-0.041c0.466 7.454 6.625 13.323 14.155 13.323 0.302 0 0.602-0.009 0.899-0.028l-0.041 0.002c0.257 0.016 0.556 0.025 0.858 0.025s0.602-0.009 0.899-0.027l-0.041 0.002c7.455-0.465 13.325-6.626 13.325-14.157 0-0.301-0.009-0.6-0.028-0.897l0.002 0.041v-39.010h20.978c0.257 0.016 0.556 0.025 0.858 0.025s0.602-0.009 0.899-0.027l-0.041 0.002c7.454-0.467 13.323-6.627 13.323-14.157 0-0.302-0.009-0.602-0.028-0.899l0.002 0.041v-168.173c0.017-0.257 0.027-0.556 0.027-0.858s-0.010-0.602-0.029-0.899l0.002 0.040c-0.466-7.454-6.625-13.323-14.155-13.323-0.302 0-0.602 0.009-0.899 0.028l0.041-0.002h-20.978v-46.612l114.184-61.507c104.163-55.721 173.826-163.767 173.826-288.083 0-0.085-0-0.169-0-0.254l0 0.014v-0.074c-0.064-4.674-2.291-8.815-5.722-11.475l-0.034-0.025zM316.779 163.292l11.998-3.016c5.288-2.136 11.421-3.375 17.844-3.375 20.323 0 37.748 12.409 45.112 30.064l0.119 0.323c1.904 6.293 3 13.525 3 21.014s-1.096 14.721-3.136 21.545l0.136-0.531c-7.912 17.841-25.468 30.060-45.877 30.060-6.172 0-12.084-1.118-17.543-3.161l0.345 0.113-11.998-5.964v-87.071zM286.717 190.272v33.045h-33.012v-33.045zM541.959 802.91h-42.028v-138.146h42.028zM725.146 253.311l-11.996 3.016c-5.288 2.136-11.421 3.375-17.844 3.375-20.323 0-37.748-12.409-45.112-30.064l-0.119-0.323c-1.904-6.293-3-13.525-3-21.014s1.096-14.721 3.136-21.545l-0.136 0.531c8.893-17.919 27.062-30.020 48.058-30.027l0.001-0c5.677 1.282 10.693 3.339 15.243 6.091l-0.227-0.127 11.996 3.016zM755.209 193.288h33.012v33.045h-33.012z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-20"],"grid":0},"attrs":[{}],"properties":{"order":22,"id":49,"name":"stethoscope","prevSize":32,"code":59668},"setIdx":0,"setId":3,"iconIdx":50},{"icon":{"paths":["M726.524 847.858l-38.753-23.851c-18.090-12.37-29.808-32.904-29.808-56.176 0-0.155 0.001-0.31 0.002-0.465l-0 0.024v-86.698c35.513-49.521 56.789-111.346 56.789-178.14 0-0.145-0-0.29-0-0.436l0 0.023v-0.076c-0.037-8.202-6.695-14.837-14.902-14.837-8.23 0-14.902 6.672-14.902 14.902 0 0.004 0 0.008 0 0.012l-0-0.001c0.002 0.385 0.003 0.841 0.003 1.297 0 64.097-22.487 122.942-60.001 169.077l0.388-0.493c-24.138 28.797-53.996 51.957-87.919 67.897l-1.567 0.662c-9.87 5.626-21.687 8.942-34.279 8.942s-24.41-3.317-34.626-9.124l0.347 0.182c-35.488-16.602-65.346-39.762-89.159-68.161l-0.325-0.398c-37.146-45.915-59.633-105.022-59.633-169.38 0-1.229 0.008-2.456 0.025-3.681l-0.002 0.186v-0.076c-0.022-8.214-6.686-14.865-14.903-14.865-8.231 0-14.903 6.672-14.903 14.903 0 0.013 0 0.027 0 0.040l-0-0.002c-0.007 0.757-0.011 1.652-0.011 2.548 0 66.062 21.241 127.164 57.266 176.847l-0.604-0.875v89.761c0.001 0.132 0.001 0.288 0.001 0.444 0 23.269-11.717 43.802-29.573 56.020l-0.232 0.15-38.755 23.851c-4.671 2.785-7.75 7.811-7.75 13.556 0 2.67 0.665 5.184 1.838 7.386l-0.041-0.085c2.8 3.564 7.077 5.858 11.893 5.955l0.016 0c0.402 0.052 0.868 0.082 1.34 0.082 2.941 0 5.611-1.16 7.577-3.048l-0.004 0.004 38.755-23.851c26.63-17.384 44.136-46.817 44.74-80.376l0.001-0.090v-54.296c21.951 21.834 47.553 40.026 75.804 53.575l1.668 0.721c13.229 7.503 29.058 11.925 45.919 11.925 0.627 0 1.252-0.006 1.876-0.018l-0.093 0.001c18.233-0.050 35.688-3.313 51.851-9.253l-1.051 0.338c29.657-15.162 55.128-33.532 77.413-55.166l-0.077 0.075v52.063c0.605 33.649 18.111 63.083 44.367 80.238l0.375 0.23 38.755 23.851c1.967 1.904 4.652 3.077 7.61 3.077 0.471 0 0.935-0.030 1.391-0.087l-0.054 0.006c4.655-0.81 8.713-2.945 11.882-5.996l-0.007 0.007c0.875-1.994 1.384-4.318 1.384-6.761 0-5.808-2.878-10.944-7.285-14.061l-0.054-0.036z","M848.809 403.775c-6.963-10.467-17.335-18.19-29.506-21.627l-0.369-0.089v-106.526c-0.072-4.818-2.463-9.063-6.105-11.677l-0.044-0.030c0.002-0.101 0.003-0.22 0.003-0.34 0-6.304-3.487-11.794-8.637-14.647l-0.086-0.044-301.047-101.323h-8.947l-301.046 101.323c-5.356 2.906-8.931 8.487-8.931 14.903s3.575 11.997 8.842 14.859l0.089 0.044 77.472 26.075v93.145c0.21 13.555 8.706 25.074 20.637 29.73l0.221 0.076c12.006 6.279 25.934 11.412 40.563 14.686l1.149 0.216c49.92 14.733 107.321 23.414 166.685 23.849l0.239 0.001c2.022 0.025 4.409 0.039 6.8 0.039 59.206 0 116.373-8.729 170.284-24.97l-4.174 1.080c14.902-5.955 29.806-8.949 41.713-14.904 11.626-5.408 19.773-16.54 20.849-29.675l0.008-0.129v-96.134l53.657-18.059v98.457c-12.51 3.533-22.857 11.243-29.686 21.497l-0.12 0.192c-17.862 32.8-8.913 71.519 32.8 119.22 3.173 3.038 7.244 5.162 11.775 5.936l0.134 0.019c2.96 0 5.955-2.995 11.978-5.955 38.753-47.702 50.697-89.414 32.8-119.22zM708.698 400.815v0.141c-0.039 1.585-1.334 2.856-2.925 2.856-0.025 0-0.049-0-0.074-0.001l0.004 0c-14.902 2.96-26.811 8.913-41.713 11.909-47.771 14.187-102.659 22.351-159.454 22.351s-111.682-8.164-163.554-23.383l4.1 1.031c-15.614-2.419-29.647-6.573-42.815-12.338l1.1 0.429h-0.139c-1.585-0.039-2.856-1.333-2.856-2.924 0-0.025 0-0.050 0.001-0.075l-0 0.004v-83.461h7.793l185.906 62.57h8.839l0.109 0.036h8.949l190.773-62.606h5.955zM706.272 284.554h-15.507l-187.779 62.606-187.779-62.606h-15.44l-53.086-17.898 256.338-86.421 256.338 86.421zM804.032 490.162c-17.862-23.817-32.764-50.662-20.857-71.519 3.866-7.153 11.31-11.93 19.87-11.93 0.347 0 0.692 0.008 1.036 0.023l-0.049-0.002c8.568 0.965 15.946 5.394 20.802 11.832l0.055 0.076c11.942 20.857-2.96 47.668-20.857 71.519z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-21"],"grid":0},"attrs":[{},{}],"properties":{"order":23,"id":50,"name":"student","prevSize":32,"code":59669},"setIdx":0,"setId":3,"iconIdx":51},{"icon":{"paths":["M680.481 132.819h-322.442c-38.642 0.544-69.823 31.725-70.367 70.316l-0.001 0.052v601.203c0.543 38.595 31.648 69.747 70.172 70.367l0.059 0.001h322.578c0.601 0.019 1.307 0.030 2.016 0.030 37.843 0 68.521-30.678 68.521-68.521 0-1.697-0.062-3.38-0.183-5.046l0.013 0.223v-598.256c-0.545-38.642-31.726-69.822-70.316-70.367l-0.052-0.001zM724.502 804.39c-0.59 24.071-19.95 43.432-43.966 44.020l-0.056 0.001h-322.442c-24.072-0.59-43.432-19.95-44.022-43.966l-0.001-0.056v-598.223c0.59-24.072 19.951-43.433 43.968-44.020l0.055-0.001-0.136-2.98h322.578c24.072 0.589 43.432 19.95 44.020 43.966l0.001 0.055z","M639.609 203.187h-237.549c-24.071 0.59-43.432 19.95-44.020 43.966l-0.001 0.056v454.475c0.588 24.072 19.949 43.433 43.966 44.020l0.055 0.001h237.514c23.609-1.663 42.356-20.386 44.048-43.835l0.009-0.153v-454.508c-0.591-24.071-19.951-43.43-43.966-44.020l-0.056-0.001zM654.271 701.716c0.016 0.251 0.025 0.543 0.025 0.838s-0.009 0.588-0.027 0.878l0.002-0.040c-0.454 7.28-6.47 13.013-13.824 13.013-0.295 0-0.587-0.009-0.878-0.027l0.040 0.002h-237.549c-0.251 0.016-0.543 0.025-0.838 0.025s-0.588-0.009-0.878-0.027l0.040 0.002c-7.28-0.455-13.011-6.47-13.011-13.824 0-0.295 0.009-0.589 0.027-0.879l-0.002 0.040v-454.541c-0.017-0.251-0.026-0.543-0.026-0.838s0.010-0.587 0.028-0.878l-0.002 0.039c0.455-7.28 6.47-13.011 13.824-13.011 0.295 0 0.588 0.009 0.878 0.027l-0.040-0.002 237.549 0.033c0.251-0.016 0.543-0.025 0.838-0.025s0.588 0.009 0.878 0.027l-0.040-0.002c7.28 0.455 13.011 6.47 13.011 13.824 0 0.295-0.009 0.588-0.027 0.878l0.002-0.040z","M519.328 769.206c-14.569 0-26.379 11.81-26.379 26.379s11.81 26.379 26.379 26.379c14.569 0 26.379-11.81 26.379-26.379v0c-0.001-14.568-11.811-26.378-26.379-26.379l-0-0z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-22"],"grid":0},"attrs":[{},{},{}],"properties":{"order":24,"id":51,"name":"smartphone","prevSize":32,"code":59670},"setIdx":0,"setId":3,"iconIdx":52},{"icon":{"paths":["M860.402 204.509l-61.632-61.632c-10.246-8.744-23.518-14.216-38.055-14.668l-0.095-0.002c-0.134-0.001-0.292-0.002-0.451-0.002-14.556 0-27.809 5.576-37.741 14.708l0.040-0.036-50.268 50.27c-2.918-0.677-6.268-1.065-9.708-1.065-12.019 0-22.933 4.735-30.976 12.442l0.016-0.015c-8.046 7.109-13.152 17.385-13.352 28.857l-0 0.035c-10.808 0.759-20.44 5.256-27.732 12.192l0.019-0.018c-8.317 7.283-13.54 17.921-13.54 29.779 0 4.091 0.622 8.037 1.776 11.749l-0.075-0.28-311.532 311.532c-4.292 2.358-7.995 5.066-11.306 8.186l0.027-0.025c-0.948 1.452-1.636 3.164-1.953 5.003l-0.011 0.080-30.221 30.221c0 2.947-2.949 5.861-2.949 8.81l-23.48 137.899c-2.914 2.914 0 8.774 2.949 11.723 2.549 1.36 5.508 2.387 8.635 2.922l0.175 0.025 143.759-23.48c0.396 0.052 0.855 0.081 1.32 0.081 2.911 0 5.553-1.155 7.493-3.031l-0.003 0.003 356.488-356.49c2.070 0.555 4.584 1.027 7.153 1.319l0.248 0.023v-0.035c11.248-0.837 21.359-5.123 29.429-11.792l-0.088 0.071c8.208-7.254 13.357-17.807 13.357-29.563 0-0.059-0-0.117-0-0.176l0 0.009c10.544-1.556 19.937-5.563 27.878-11.423l-0.17 0.12q1.011-0.946 1.958-1.958c6.722-7.341 10.841-17.162 10.841-27.946 0-2.983-0.315-5.892-0.914-8.695l0.049 0.272 52.644-52.644c0.242-0.236 0.48-0.476 0.715-0.715 9.083-9.258 14.689-21.955 14.689-35.961 0-14.362-5.894-27.348-15.396-36.669l-0.008-0.008zM347.021 635.66c-1.262-11.644-6.744-21.813-14.862-29.107l-0.042-0.037c-5.517-5.285-12.172-9.431-19.556-12.030l-0.381-0.117 284.115-284.115 38.065 38.065zM238.638 706.637l55.159 55.159-67.221 12.063zM340.995 753.325l-12.381 2.221-81.505-81.505q-0.468-0.515-0.984-0.983c-0.368-0.254-0.8-0.515-1.246-0.752l-0.073-0.036 2.304-12.832 36.185-36.185c3.66-1.678 7.94-2.656 12.449-2.656 7.103 0 13.639 2.428 18.823 6.498l-0.066-0.050c4.229 5.122 6.793 11.753 6.793 18.984 0 2.633-0.34 5.187-0.979 7.62l0.047-0.208c-0.221 1.242-0.347 2.671-0.347 4.13 0 6.303 2.354 12.055 6.232 16.427l-0.022-0.026c3.586 4.143 8.853 6.749 14.728 6.749 2.072 0 4.068-0.324 5.941-0.924l-0.138 0.038c2.349-0.707 5.049-1.114 7.843-1.114 7.121 0 13.625 2.643 18.584 7.002l-0.031-0.027c3.996 5.103 6.408 11.614 6.408 18.688 0 4.943-1.178 9.612-3.268 13.74l0.080-0.174zM402.465 691.855c-1.809-11.604-7.046-21.75-14.629-29.622l0.016 0.017c-5.393-4.177-11.61-7.657-18.311-10.141l-0.485-0.157 285.795-283.141 35.329 35.329zM734.226 389.403c-1.938 1.874-4.581 3.029-7.494 3.029-0.464 0-0.92-0.029-1.368-0.086l0.053 0.006c-1.526-1.555-3.547-2.621-5.806-2.943l-0.054-0.006-108.592-108.592c-1.222-2.020-1.944-4.46-1.944-7.069 0-4.22 1.891-7.998 4.872-10.534l0.020-0.016c2.549-1.359 5.508-2.386 8.635-2.922l0.175-0.025v-0.035c2.914 0 2.914 2.949 5.861 2.982l105.645 105.645q0.068-0.003 0.137 0c1.561 0.037 2.811 1.311 2.811 2.877 0 0.025-0 0.049-0.001 0.074l0-0.004c1.221 2.020 1.944 4.46 1.944 7.069 0 4.22-1.891 7.998-4.872 10.534l-0.020 0.016zM775.29 351.286c-1.936 1.873-4.578 3.028-7.489 3.028-0.466 0-0.924-0.030-1.374-0.087l0.053 0.006c-2.914 0-2.914-2.947-5.861-2.947l-99.779-99.78c0-0.036 0-0.078 0-0.121 0-3.302-1.096-6.349-2.943-8.796l0.027 0.037h-0.139c-1.561-0.039-2.811-1.313-2.811-2.88 0-0.024 0-0.048 0.001-0.073l-0 0.004c-1.003-1.11-2.154-2.059-3.429-2.824l-0.068-0.038c-0.026-0.355-0.040-0.77-0.040-1.188 0-3.982 1.329-7.654 3.569-10.595l-0.031 0.043c2.549-1.36 5.508-2.387 8.635-2.922l0.175-0.025h5.863l2.947 2.947 102.696 105.645c0.045-0.002 0.091-0.002 0.139 0 1.561 0.038 2.811 1.312 2.811 2.878 0 0.024-0 0.048-0.001 0.072l0-0.004c1.221 2.020 1.943 4.459 1.943 7.068 0 4.221-1.891 7.999-4.873 10.535l-0.020 0.016zM834.008 260.211l-42.59 42.59-93.888-93.889 42.557-42.621c4.154-4.082 9.855-6.603 16.145-6.603s11.99 2.52 16.148 6.606l-0.003-0.003 61.632 61.63c4.082 4.154 6.603 9.855 6.603 16.145s-2.52 11.99-6.606 16.148l0.003-0.003z","M836.887 841.214h-628.003c-8.1 0.004-14.664 6.571-14.664 14.671 0 8.103 6.569 14.671 14.671 14.671 0.023 0 0.045-0 0.068-0l-0.004 0h628.005c8.075-0.037 14.607-6.591 14.607-14.671 0-8.103-6.569-14.671-14.671-14.671-0.004 0-0.007 0-0.011 0l0.001-0z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-23"],"grid":0},"attrs":[{},{}],"properties":{"order":25,"id":52,"name":"pencil","prevSize":32,"code":59671},"setIdx":0,"setId":3,"iconIdx":53},{"icon":{"paths":["M831.187 190.826h-622.87q-0.524-0.007-1.048-0.002c-24.39 0.26-44.061 20.092-44.061 44.519 0 0.162 0.001 0.323 0.003 0.484l-0-0.025v101.474c-0.020 0.271-0.031 0.587-0.031 0.906 0 0.285 0.009 0.567 0.026 0.848l-0.002-0.038c0.006 0.093 0.036 0.178 0.044 0.27-0.003 0.317-0.057 0.622-0.038 0.944v450.937q-0.008 0.59 0 1.179c0.332 24.334 20.136 43.932 44.517 43.932 0.207 0 0.414-0.001 0.621-0.004l-0.031 0h622.87q0.573 0.008 1.147-0.001c24.334-0.332 43.932-20.136 43.932-44.517 0-0.207-0.001-0.414-0.004-0.621l0 0.031v-450.938c0.016-0.241 0.024-0.522 0.024-0.806s-0.009-0.565-0.026-0.844l0.002 0.038c-0.011-0.184-0.068-0.352-0.087-0.534 0.029-0.265 0.104-0.516 0.119-0.784v-101.344q0.008-0.59 0-1.179c-0.333-24.333-20.136-43.931-44.517-43.931-0.207 0-0.415 0.001-0.621 0.004l0.031-0zM191.393 238.732c0.633-9.081 7.843-16.29 16.866-16.92l0.057-0.003h622.838c9.081 0.633 16.29 7.843 16.92 16.866l0.003 0.057v87.382h-656.684zM848.11 791.143c-0.633 9.081-7.843 16.291-16.866 16.92l-0.057 0.003h-622.87c-9.081-0.633-16.29-7.843-16.92-16.866l-0.003-0.057v-439.676h656.717z","M647.961 255.655c-9.346 0-16.923 7.577-16.923 16.923s7.577 16.923 16.923 16.923c9.346 0 16.923-7.577 16.923-16.923l0-0c-0.633-9.081-7.843-16.29-16.866-16.92l-0.057-0.003z","M712.79 255.655c-9.346 0-16.923 7.577-16.923 16.923s7.577 16.923 16.923 16.923c9.346 0 16.923-7.577 16.923-16.923l0-0c0.018-0.443 0.018-0.887 0-1.329-0.366-8.696-7.505-15.608-16.258-15.608-0.234 0-0.466 0.005-0.698 0.015l0.033-0.001z","M780.418 255.655c-9.346 0-16.923 7.577-16.923 16.923s7.577 16.923 16.923 16.923c9.346 0 16.923-7.577 16.923-16.923l0-0c-0.633-9.081-7.843-16.29-16.866-16.92l-0.057-0.003z","M371.755 743.238c0.010 0 0.021 0 0.033 0 31.113 0 56.335-25.222 56.335-56.335 0-26.117-17.772-48.083-41.882-54.464l-0.393-0.088v-41.325h118.364v41.325c-24.505 6.482-42.276 28.454-42.276 54.578 0 31.131 25.237 56.367 56.367 56.367s56.367-25.237 56.367-56.367c0-26.123-17.77-48.096-41.882-54.489l-0.393-0.089v-41.325h118.397v41.325c-24.381 6.519-42.043 28.411-42.043 54.427 0 31.067 25.184 56.251 56.251 56.251s56.251-25.184 56.251-56.251c0-25.066-16.395-46.302-39.046-53.571l-0.398-0.11v-56.162c0.016-0.241 0.024-0.522 0.024-0.805 0-7.351-5.959-13.311-13.311-13.311-0.283 0-0.565 0.009-0.844 0.026l0.038-0.002h-135.321v-42.406h62.030c0.241 0.015 0.522 0.024 0.805 0.024s0.565-0.009 0.844-0.026l-0.038 0.002c6.997-0.437 12.505-6.219 12.505-13.287 0-0.283-0.009-0.565-0.026-0.843l0.002 0.038v-76.089c0.016-0.241 0.024-0.522 0.024-0.805 0-7.351-5.959-13.311-13.311-13.311-0.283 0-0.565 0.009-0.844 0.026l0.038-0.002h-149.38c-0.241-0.016-0.522-0.024-0.805-0.024-7.352 0-13.311 5.96-13.311 13.311 0 0.283 0.009 0.564 0.026 0.843l-0.002-0.038v76.089c-0.016 0.241-0.024 0.522-0.024 0.805 0 7.351 5.959 13.311 13.311 13.311 0.283 0 0.565-0.009 0.844-0.026l-0.038 0.002h59.166v42.406h-129.625c-0.241-0.016-0.522-0.024-0.805-0.024-7.351 0-13.311 5.959-13.311 13.311 0 0.283 0.009 0.565 0.026 0.844l-0.002-0.038v54.699c-25.92 5.424-45.108 28.088-45.108 55.234 0 31.132 25.236 56.369 56.368 56.37l0 0zM546.417 686.735c0 0.021 0 0.046 0 0.070 0 15.54-12.578 28.143-28.109 28.183l-0.004 0c-15.122-1.054-27.129-13.061-28.178-28.088l-0.005-0.095c0.045-15.378 12.384-27.86 27.703-28.136l0.026-0c0.154-0.004 0.3 0.027 0.455 0.018 0.21 0.012 0.421-0.003 0.631 0 15.224 0.372 27.43 12.776 27.482 28.043l0 0.005zM692.998 686.735c0 0.021 0 0.046 0 0.070 0 15.541-12.578 28.144-28.11 28.183l-0.004 0c-15.122-1.055-27.129-13.061-28.178-28.088l-0.005-0.095c0.042-15.464 12.509-28.002 27.941-28.16l0.015-0c0.077-0.004 0.15 0.014 0.228 0.009l0.149-0.017c15.443 0.119 27.922 12.644 27.965 28.093l0 0.004zM459.137 444.348h121.196v50.737h-53.834c-2.268-1.667-5.115-2.668-8.196-2.668s-5.929 1.001-8.235 2.695l0.039-0.027h-50.97zM371.586 658.639l0.17 0.015v0.033c0-0 0-0 0.001-0 15.578 0 28.211 12.61 28.248 28.18l0 0.004c-1.090 15.115-13.119 27.1-28.156 28.114l-0.093 0.005c-15.122-1.054-27.129-13.061-28.178-28.088l-0.005-0.095c0.041-15.486 12.54-28.039 28.002-28.165l0.012-0z"],"attrs":[{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-24"],"grid":0},"attrs":[{},{},{},{},{}],"properties":{"order":26,"id":53,"name":"sitemap","prevSize":32,"code":59672},"setIdx":0,"setId":3,"iconIdx":54},{"icon":{"paths":["M810.104 803.157l-101.062-258.227c52.7-41.168 86.262-104.722 86.262-176.115 0-0.231-0-0.461-0.001-0.692l0 0.036c0.001-0.189 0.001-0.412 0.001-0.636 0-125.589-101.81-227.398-227.398-227.398s-227.398 101.81-227.398 227.398c0 72.368 33.805 136.84 86.485 178.487l0.477 0.364-102.89 262.903c-0.62 1.504-0.979 3.251-0.979 5.082 0 7.552 6.122 13.674 13.674 13.674 1.83 0 3.576-0.36 5.171-1.012l-0.091 0.033 97.701-44.442 41.431 97.701c0 5.913 5.915 8.888 11.828 8.888l0.035 0.033c6.015-1.189 11.138-4.383 14.765-8.842l0.036-0.046 58.951-147.375 56.456 147.375c2.75 5.319 8.209 8.891 14.503 8.891 0.106 0 0.211-0.001 0.316-0.003l-0.016 0c5.536-0.327 10.131-4.012 11.799-9.033l0.027-0.093 44.442-103.614 97.699 44.44c2.975 2.94 11.828 0 14.801-2.975 2.531-2.381 4.107-5.752 4.107-9.491 0-1.923-0.417-3.749-1.166-5.392l0.033 0.082zM369.052 368.089c0.001-109.502 88.77-198.271 198.273-198.271 0 0 0 0 0 0l0.171-0c109.502-0 198.271 88.769 198.271 198.271 0 0-0 0-0 0l0-0c-1.609 62.27-30.785 117.413-75.726 153.889l-0.38 0.298c-2.589 0.412-4.903 1.332-6.927 2.658l0.067-0.041c-21.075 14.874-45.86 26.153-72.604 32.306l-1.407 0.273c-12.458 2.823-26.764 4.441-41.449 4.441s-28.991-1.618-42.752-4.685l1.303 0.244c-0.581-0.081-1.252-0.127-1.934-0.127-1.746 0-3.422 0.303-4.977 0.86l0.103-0.032c-25.519-7.069-47.85-17.412-68.003-30.778l0.871 0.543c-50.331-34.429-82.932-91.571-82.932-156.328 0-1.238 0.012-2.473 0.036-3.705l-0.003 0.185zM493.314 835.907l-32.578-79.924q-4.444-8.888-8.888-8.888h-5.913v0.035c-2.375 0.271-4.442 1.416-5.903 3.1l-0.010 0.011-79.891 35.551 85.837-222.201c11.774 6.036 26.058 12.088 40.793 17.175l2.434 0.731q7.859 2.829 15.928 4.997c3.985 1.168 7.851 2.702 11.88 3.726 2.36 0.396 4.757 0.409 7.123 0.745 12.821 2.917 27.68 4.78 42.907 5.164l0.291 0.006c6.754-0.219 13.481-0.847 20.189-1.592zM691.654 747.13h-11.828c-5.913 2.973-5.913 5.913-8.886 8.888l-32.578 79.922-55.894-141.382 42.898-107.244c23.034-6.208 43.214-15.144 61.611-26.663l-0.943 0.551 85.545 221.445z","M511.091 442.167c-8.161 0.019-14.77 6.639-14.77 14.802s6.609 14.784 14.768 14.802l0.002 0h112.502c7.952-0.533 14.27-6.851 14.799-14.755l0.003-0.048c0.016-0.253 0.025-0.548 0.025-0.846s-0.009-0.593-0.027-0.886l0.002 0.040c-0.459-7.349-6.531-13.135-13.955-13.135-0.298 0-0.593 0.009-0.886 0.028l0.040-0.002h-41.467v-148.020h41.467c6.015 0 11.828-5.913 14.801-14.801 0.016-0.253 0.025-0.548 0.025-0.846s-0.009-0.593-0.027-0.886l0.002 0.040c-0.459-7.349-6.531-13.135-13.955-13.135-0.298 0-0.593 0.009-0.886 0.028l0.040-0.002h-55.586c-0.238-0.010-0.44-0.138-0.682-0.138s-0.444 0.127-0.682 0.138h-55.552c-0.253-0.017-0.548-0.027-0.846-0.027s-0.593 0.010-0.886 0.029l0.040-0.002c-7.349 0.459-13.135 6.531-13.135 13.955 0 0.298 0.009 0.593 0.028 0.886l-0.002-0.040c-0.017 0.253-0.027 0.548-0.027 0.846s0.010 0.593 0.029 0.886l-0.002-0.040c0.459 7.349 6.531 13.135 13.955 13.135 0.298 0 0.593-0.009 0.886-0.028l-0.040 0.002h41.431v148.020z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-25"],"grid":0},"attrs":[{},{}],"properties":{"order":27,"id":54,"name":"medal","prevSize":32,"code":59673},"setIdx":0,"setId":3,"iconIdx":55},{"icon":{"paths":["M459.552 308.28c-0.151-0.159-0.308-0.314-0.467-0.467-2.577-2.465-6.078-3.982-9.933-3.982-4.087 0-7.777 1.705-10.395 4.443l-0.005 0.005-83.058 83.231c-0.159 0.151-0.314 0.308-0.467 0.467-2.464 2.577-3.981 6.078-3.981 9.933 0 4.087 1.705 7.776 4.443 10.395l0.005 0.005 211.012 211.010c2.582 1.377 5.579 2.418 8.746 2.962l0.178 0.025c0.174 0.005 0.38 0.008 0.586 0.008 4.103 0 7.948-1.098 11.26-3.017l-0.108 0.058 83.231-83.231c0.159-0.153 0.316-0.308 0.467-0.467 2.465-2.577 3.982-6.078 3.982-9.933 0-4.087-1.705-7.777-4.443-10.395l-0.005-0.005zM572.678 590.647l-190.248-190.248 62.433-62.431 190.246 190.246z","M768.656 204.285c-30.081-31.169-72.226-50.524-118.891-50.524s-88.81 19.355-118.844 50.475l-0.047 0.049c-26.438 25.035-43.978 59.23-47.524 97.484l-0.045 0.607c-2.952 2.952 0 8.888 2.985 11.876l172.4 172.4c2.623 1.378 5.67 2.41 8.888 2.929l0.172 0.023-0.136 0.034c38.695-6.313 72.714-22.921 100.128-46.894l-0.233 0.2c1.27-0.508 2.739-0.836 4.276-0.91l0.031-0.001c0.159-0.151 0.314-0.308 0.467-0.467 2.069-2.247 3.42-5.184 3.669-8.43l0.003-0.048c25.711-29.375 41.394-68.093 41.394-110.475 0-46.151-18.596-87.959-48.704-118.339l0.012 0.012zM650.006 180.465c76.362 0.64 138.018 62.691 138.018 139.144 0 33.116-11.568 63.529-30.884 87.42l0.206-0.263-194.236-194.236c23.24-19.897 53.648-32.020 86.887-32.064l0.009-0zM513.3 296.404h-0.136c3.923-24.437 14.201-45.974 29.071-63.49l-0.154 0.186 194.605 194.603c-17.563 13.974-38.759 24.179-61.924 29.022l-0.972 0.17z","M424.030 771.936l-80.245 80.245c-13.156 12.423-30.948 20.059-50.523 20.059s-37.366-7.636-50.558-20.092l0.036 0.033c-12.422-13.156-20.058-30.946-20.058-50.521 0-19.567 7.63-37.352 20.077-50.541l-0.034 0.036 26.753 26.753c1.962 1.899 4.639 3.069 7.589 3.069 0.47 0 0.933-0.030 1.387-0.087l-0.054 0.006c3.198-0.224 5.734-2.773 5.938-5.956l0.001-0.019 216.982-166.461c3.030-3.164 5.148-7.224 5.92-11.742l0.019-0.133c2.952-5.937 0-8.888-2.985-11.876l-115.906-115.904c-2.812-1.93-6.289-3.082-10.035-3.082-0.648 0-1.289 0.035-1.919 0.102l0.078-0.007c-4.819 0.096-9.084 2.384-11.851 5.906l-0.025 0.033-166.461 216.983c-2.721 2.057-4.462 5.287-4.462 8.924s1.74 6.867 4.434 8.904l0.028 0.020 23.77 23.77c-17.919 18.404-28.969 43.572-28.969 71.321 0 27.757 11.056 52.931 29.005 71.358l-0.022-0.022c17.614 18.341 42.341 29.737 69.73 29.737 0.559 0 1.118-0.005 1.675-0.014l-0.084 0.001c27.882-0.118 53.091-11.468 71.354-29.756l0.001-0.001 80.245-80.245c4.74-4.153 10.989-6.687 17.83-6.687s13.091 2.534 17.861 6.714l-0.031-0.027c3.152 5.109 5.274 11.173 5.923 17.672l0.014 0.176c0.107 0.812 0.168 1.751 0.168 2.704 0 5.884-2.327 11.224-6.111 15.15l0.006-0.007-38.648 38.646c-2.373 2.605-3.827 6.084-3.827 9.902 0 8.132 6.592 14.725 14.725 14.725 3.818 0 7.297-1.453 9.914-3.837l-0.012 0.011 38.646-38.648c8.86-10.379 14.403-23.823 14.861-38.55l0.002-0.096c0.001-0.136 0.002-0.297 0.002-0.457 0-14.745-5.649-28.171-14.901-38.231l0.037 0.040c-9.994-9.66-23.625-15.612-38.645-15.612s-28.652 5.953-38.662 15.628l0.016-0.015zM376.494 504.465l95.106 95.106-193.2 148.615-20.674-20.674c-0.195-3.076-1.336-5.854-3.132-8.080l0.021 0.027c-2.424-2.627-5.785-4.358-9.55-4.658l-0.051-0.003-17.136-17.136z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-26"],"grid":0},"attrs":[{},{},{}],"properties":{"order":28,"id":55,"name":"microphone","prevSize":32,"code":59674},"setIdx":0,"setId":3,"iconIdx":56},{"icon":{"paths":["M543.952 399.854h-19.869c-0.064 0-0.117-0.036-0.181-0.036-0.062 0-0.115 0.036-0.177 0.036h-22.637q-0.643-0.003-1.286 0c-84.521 0.375-152.893 68.978-152.893 153.551 0 0.232 0.001 0.465 0.002 0.697l-0-0.036v168.488q-0.003 0.628 0 1.256c0.357 84.535 68.968 152.925 153.553 152.925 0.22 0 0.441-0 0.661-0.001l-0.034 0h42.863c85.37-1.024 154.181-70.469 154.181-155.985 0-0.374-0.001-0.747-0.004-1.12l0 0.057v-165.655q0.003-0.628 0-1.254c-0.356-84.535-68.967-152.925-153.551-152.925-0.221 0-0.442 0-0.663 0.001l0.034-0zM523.973 559.769v-0.008l0.046-0.012c12.249 0.875 21.965 10.614 22.8 22.794l0.004 0.076c0 0 0 0 0 0 0 12.62-10.23 22.85-22.85 22.85s-22.85-10.23-22.85-22.85c0-12.62 10.23-22.85 22.85-22.85h-0zM669.579 719.686c-0.629 69.126-56.499 124.995-125.565 125.624l-0.060 0h-42.864c-69.126-0.629-124.996-56.498-125.624-125.565l-0-0.060v-165.753c0.629-69.126 56.498-124.996 125.565-125.624l0.060-0 8.569 0.020v107.993c-21.595 6.36-37.090 26.005-37.090 49.269 0 28.315 22.954 51.268 51.268 51.268 0.047 0 0.094-0 0.141-0l-0.007 0h0.461c28.174-0.185 50.942-23.068 50.942-51.268 0-23.29-15.529-42.953-36.798-49.198l-0.363-0.091v-107.909l5.74 0.014c69.126 0.629 124.995 56.498 125.624 125.564l0 0.060z","M444.081 317.026q-0.504 0.459-0.964 0.964c-2.278 2.502-3.673 5.842-3.673 9.509 0 7.812 6.333 14.145 14.145 14.145 4.146 0 7.875-1.783 10.462-4.625l0.010-0.011c14.826-14.145 34.951-22.849 57.108-22.849s42.282 8.704 57.141 22.88l-0.033-0.031 2.87 2.868c1.883 1.824 4.454 2.949 7.287 2.949 0.453 0 0.9-0.029 1.338-0.085l-0.052 0.005c5.605 0 8.44-2.87 11.441-2.87 0.153-0.144 0.304-0.296 0.449-0.449 2.368-2.475 3.825-5.838 3.825-9.541 0-3.926-1.638-7.47-4.269-9.985l-0.005-0.005-2.868-2.87c-19.871-19.429-47.088-31.417-77.106-31.417s-57.235 11.988-77.126 31.437l0.020-0.020z","M623.878 294.177c1.884 1.823 4.455 2.947 7.289 2.947 0.453 0 0.899-0.029 1.336-0.084l-0.052 0.005c3.19-0.552 6.046-1.551 8.661-2.943l-0.155 0.075c0.153-0.147 0.304-0.296 0.449-0.449 2.368-2.475 3.825-5.839 3.825-9.542 0-3.927-1.638-7.471-4.269-9.986l-0.005-0.005-2.868-2.868q-1.265-1.292-2.554-2.554c-29.498-28.873-69.918-46.689-114.499-46.689-45.851 0-87.3 18.846-117.024 49.214l-0.028 0.029c-2.278 2.502-3.672 5.842-3.672 9.508 0 7.813 6.333 14.146 14.146 14.146 3.666 0 7.007-1.395 9.52-3.683l-0.011 0.010c25.244-25.149 60.067-40.697 98.522-40.697s73.278 15.548 98.526 40.701l-0.004-0.004z","M378.302 242.772c35.060-36.989 84.543-60.005 139.402-60.005 1.184 0 2.365 0.011 3.544 0.032l-0.177-0.003c55.84 0.399 106.265 23.252 142.761 59.966l0.010 0.010 5.703 5.705c1.884 1.823 4.455 2.947 7.289 2.947 0.453 0 0.899-0.029 1.336-0.084l-0.052 0.005c5.738 0 8.573 0 11.409-2.868 0.153-0.147 0.304-0.296 0.449-0.449 2.368-2.475 3.825-5.839 3.825-9.542 0-3.927-1.638-7.471-4.269-9.986l-0.005-0.005-5.703-5.703c-39.825-42.249-96.163-68.555-158.646-68.555-1.444 0-2.885 0.014-4.322 0.042l0.215-0.003c-63.626 0.771-121.024 26.806-162.752 68.517l0.001-0.001c-2.278 2.502-3.673 5.842-3.673 9.509 0 7.812 6.333 14.145 14.145 14.145 3.667 0 7.008-1.395 9.521-3.684l-0.011 0.010z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-27"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":29,"id":56,"name":"wireless","prevSize":32,"code":59675},"setIdx":0,"setId":3,"iconIdx":57},{"icon":{"paths":["M826.846 217.336c-12.441-13.768-30.362-22.383-50.295-22.383-0.671 0-1.339 0.010-2.005 0.029l0.098-0.002c-0.074-0-0.162-0-0.251-0-20.444 0-38.886 8.575-51.924 22.325l-0.030 0.032-216.247 216.219c-1.151 2.159-2.022 4.665-2.477 7.313l-0.021 0.149c-0.043 0.334-0.068 0.721-0.068 1.114 0 2.468 0.978 4.707 2.568 6.351l-0.002-0.003 8.723 8.723-146.901 146.902c-4.644-3.944-10.709-6.343-17.333-6.343-7.144 0-13.637 2.79-18.448 7.339l0.013-0.012-22.356 22.356c-4.482 5.198-7.212 12.018-7.212 19.475 0 5.187 1.321 10.066 3.645 14.318l-0.078-0.156-58.545 33.462c-2.468 0-4.966 4.964-4.966 7.462l-22.356 109.343c-2.468 2.468 0 7.432 2.498 9.93 1.582 0.186 3.024 0.564 4.377 1.114l-0.112-0.040c1.377 0.909 3.066 1.45 4.882 1.45 0.268 0 0.534-0.012 0.796-0.035l-0.034 0.002 0.019 0.005-0.028 0.058 109.343-12.426c2.498 0 4.966-2.468 7.462-4.966l39.549-65.955c2.303 0.757 4.958 1.226 7.712 1.296l0.035 0.001c0.621 0.071 1.342 0.111 2.071 0.111 6.234 0 11.779-2.949 15.316-7.528l0.033-0.045 22.356-22.356c4.627-5.283 7.449-12.248 7.449-19.872 0-3.799-0.701-7.434-1.98-10.784l0.070 0.207 148.519-148.519 4.964 4.966c1.64 1.587 3.878 2.565 6.344 2.565 0.394 0 0.782-0.025 1.163-0.073l-0.045 0.005c2.496 0 7.462 0 7.49-4.964l216.219-213.751c13.768-12.442 22.383-30.363 22.383-50.297 0-0.671-0.010-1.339-0.029-2.005l0.002 0.098c0-0.077 0-0.169 0-0.26 0-20.441-8.575-38.879-22.325-51.912l-0.032-0.030zM329.72 788.993l-64.433 9.762 52.092-52.094c0.295-0.267 0.567-0.539 0.825-0.824l0.009-0.010c1.993-2.18 3.215-5.095 3.215-8.296 0-6.799-5.512-12.311-12.311-12.311-3.615 0-6.867 1.558-9.119 4.040l-0.009 0.010-47.328 47.326 12.43-62.164 58.333-33.676 44.802 44.802zM399.231 714.432h-4.966l-66.983-67.098v-4.964l24.779-22.29 7.387 7.122c0.065 0.072 0.081 0.173 0.149 0.243l59.637 59.637c0.675 0.571 1.452 1.052 2.295 1.407l0.059 0.022v3.565zM426.695 659.761l-42.246-42.246 145.377-145.403 42.244 42.244zM809.426 306.905l-206.288 206.203-72.063-72.063 208.756-203.705q0.815-0.859 1.673-1.675c8.601-8.2 20.273-13.245 33.124-13.245 13.683 0 26.030 5.72 34.78 14.9l0.018 0.019c9.19 8.293 14.941 20.245 14.941 33.54 0 0.437-0.006 0.872-0.019 1.306l0.001-0.064c-0.133 13.655-5.822 25.956-14.911 34.771l-0.013 0.012z","M754.639 274.505l-106.761 106.961c-0.133 0.128-0.263 0.257-0.389 0.391-2.061 2.155-3.33 5.082-3.33 8.306 0 3.417 1.425 6.502 3.714 8.691l0.004 0.004c1.64 1.587 3.878 2.565 6.344 2.565 0.394 0 0.782-0.025 1.163-0.073l-0.045 0.005c2.468 0 4.966-2.582 9.93-2.582l106.761-106.877c1.986-2.178 3.203-5.088 3.203-8.283 0-6.799-5.512-12.311-12.311-12.311-3.195 0-6.105 1.217-8.293 3.212l0.010-0.009z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-29"],"grid":0},"attrs":[{},{}],"properties":{"order":31,"id":57,"name":"fountain","prevSize":32,"code":59677},"setIdx":0,"setId":3,"iconIdx":58},{"icon":{"paths":["M752.466 137.11c-2.004-1.341-4.47-2.14-7.122-2.14s-5.117 0.799-7.169 2.169l0.047-0.030c-14.241 5.689-344.67 150.971-401.539 356.050-5.255 17.93-8.278 38.529-8.278 59.834 0 50.583 17.042 97.185 45.697 134.379l-0.382-0.516c0.863 0.853 1.72 1.576 2.58 2.355-23.518 70.157-36.057 129.871-31.163 154.339 2.504 5.916 7.765 10.23 14.127 11.364l0.114 0.017h0.034c11.381-2.861 17.102-8.552 14.241-14.241-3.983-20.818 9.19-77.764 32.657-145.354 2.439 0.010 4.868 0.247 7.307 0.072l54.007 0.064c12.64-1.702 23.572-7.957 31.287-17.032l0.058-0.070c5.376-8.578 8.564-19.003 8.564-30.172 0-0.413-0.004-0.825-0.013-1.235l0.001 0.061 51.278 8.552c2.723 0.708 5.848 1.115 9.069 1.115 9.675 0 18.493-3.671 25.137-9.695l-0.031 0.028c20.69-18.145 38.573-38.747 53.408-61.518l0.697-1.141c4.351-6.812 6.936-15.119 6.936-24.030 0-6.791-1.501-13.231-4.189-19.006l0.116 0.278c-4.295-8.443-6.812-18.411-6.812-28.967 0-8.007 1.448-15.676 4.096-22.76l-0.147 0.449c3.982 7.216 11.542 12.022 20.225 12.022 1.916 0 3.776-0.234 5.556-0.675l-0.158 0.033c10.515-2.577 18.883-10.001 22.719-19.71l0.077-0.221c5.689-19.967 14.241-39.898 19.931-59.831 0.668-2.372 1.052-5.097 1.052-7.911 0-5.471-1.452-10.602-3.991-15.031l0.078 0.148-37.037-62.659h19.933c0.728 0.043 1.58 0.068 2.437 0.068 21.795 0 39.859-15.977 43.118-36.858l0.032-0.246c7.858-42.932 13.955-94.802 16.947-147.503l0.157-3.468c-0.092-4.617-2.284-8.704-5.658-11.357l-0.032-0.024zM706.845 296.632c-0.87 8.067-7.642 14.292-15.867 14.292-0.435 0-0.867-0.017-1.293-0.052l0.056 0.004-45.587-2.863c-0.441-0.061-0.951-0.095-1.469-0.095-4.229 0-7.92 2.307-9.882 5.731l-0.029 0.056c-1.34 2.004-2.138 4.469-2.138 7.121s0.798 5.117 2.168 7.168l-0.030-0.047 48.416 85.517c-5.689 19.933-14.241 39.866-19.931 56.968h-2.863l-11.381-17.102c-2.675-3.406-6.762-5.6-11.364-5.691l-0.015-0c-4.458 0.759-8.348 2.789-11.389 5.699l0.008-0.008c-11.549 15.186-18.501 34.415-18.501 55.267 0 15.166 3.678 29.473 10.19 42.078l-0.241-0.513c1.347 2.475 2.14 5.421 2.14 8.552s-0.792 6.077-2.187 8.648l0.048-0.096c-13.567 21.917-29.616 40.688-48.112 56.71l-0.304 0.258c-2.829 2.861-5.691 2.861-11.381 2.861l-71.211-11.381c-2.829-2.829-8.518 0.034-11.379 2.863-2.863 2.829-2.863 5.689-2.863 11.381l2.863 17.102c0.15 0.951 0.236 2.047 0.236 3.164 0 4.096-1.153 7.922-3.151 11.173l0.053-0.093c-2.677 3.405-6.764 5.597-11.366 5.689l-0.015 0c-14.257 0.935-28.539 1.032-42.821 0.745 45.545-121.9 120.225-266.534 190.931-302.754 0.359-0.181 0.709-0.376 1.052-0.584 4.249-2.62 7.039-7.248 7.039-12.529 0-8.102-6.568-14.67-14.67-14.67-2.835 0-5.481 0.804-7.725 2.196l0.063-0.036c-79.308 39.665-158.409 189.842-205.501 318.104-21.365-32.907-34.068-73.152-34.068-116.365 0-12.904 1.133-25.544 3.304-37.825l-0.19 1.3c45.553-165.214 290.528-296.254 364.6-330.428-2.861 25.656-5.689 71.211-14.241 122.488z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-30"],"grid":0},"attrs":[{}],"properties":{"order":32,"id":58,"name":"feather","prevSize":32,"code":59678},"setIdx":0,"setId":3,"iconIdx":59},{"icon":{"paths":["M193.912 789.641c0.519 0.057 1.121 0.089 1.73 0.089 3.52 0 6.787-1.083 9.487-2.933l-0.057 0.037 17.902-17.902c0.616 0.298 1.144 0.621 1.636 0.989l-0.026-0.019c92.578-38.443 171.515-92.294 237.325-159.11l0.088-0.090 134.646-134.646c0.844 0.164 1.591 0.407 2.296 0.728l-0.063-0.026 187.067-187.067c12.474-12.503 20.188-29.761 20.188-48.82 0-38.177-30.948-69.125-69.125-69.125-19.059 0-36.317 7.713-48.821 20.189l0.001-0.001-18.093 18.093-18.142-18.142 19.591-19.591q0.49-0.446 0.937-0.937c2.23-2.447 3.596-5.716 3.596-9.304 0-7.641-6.195-13.836-13.836-13.836-4.054 0-7.7 1.743-10.23 4.521l-0.010 0.011-234.639 234.637c-0.149 0.144-0.295 0.289-0.439 0.439-2.316 2.422-3.741 5.711-3.741 9.334 0 3.841 1.602 7.307 4.175 9.768l0.005 0.005c1.845 1.784 4.361 2.883 7.134 2.883 0.441 0 0.876-0.028 1.303-0.082l-0.051 0.005c0.518 0.057 1.119 0.089 1.727 0.089 3.521 0 6.789-1.083 9.49-2.933l-0.057 0.037 195.5-195.501 18.142 18.142-143.005 143.005c-2.541 0.569-4.734 1.808-6.455 3.52l0.001-0.001-136.848 136.848c-66.233 64.329-119.376 141.734-155.317 228.095l-1.669 4.524-21.727 21.727c-0.149 0.142-0.295 0.287-0.439 0.437-2.316 2.422-3.741 5.711-3.741 9.334 0 3.841 1.602 7.307 4.175 9.768l0.005 0.005c1.842 1.784 4.357 2.884 7.128 2.884 0.443 0 0.88-0.028 1.309-0.083l-0.051 0.005zM677.085 236.575l0.004-0.002c0.15-0.144 0.295-0.289 0.437-0.439l27.493-27.493c7.504-7.489 17.863-12.12 29.303-12.12 22.912 0 41.485 18.573 41.485 41.485 0 11.44-4.631 21.799-12.12 29.304l0.001-0.001-175.921 175.921-58.669-58.669zM383.719 529.813l125.721-125.721 58.667 58.669-125.722 125.722c-55.981 56.474-121.574 103.307-194.141 137.861l-4.18 1.792c36.675-76.626 83.465-142.171 139.65-198.317l0.004-0.004z","M791.649 825.926h-597.737c-7.699 0.018-13.933 6.263-13.933 13.965s6.234 13.947 13.931 13.965l0.002 0h597.739c5.579 0 11.158-5.579 13.965-13.965 0.015-0.239 0.024-0.517 0.024-0.798s-0.009-0.56-0.026-0.836l0.002 0.038c-0.433-6.933-6.163-12.392-13.167-12.392-0.281 0-0.561 0.009-0.838 0.026l0.038-0.002z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-31"],"grid":0},"attrs":[{},{}],"properties":{"order":33,"id":59,"name":"pen","prevSize":32,"code":59679},"setIdx":0,"setId":3,"iconIdx":60},{"icon":{"paths":["M880.822 234.254l-82.462-82.462q-0.211-0.221-0.431-0.431c-2.381-2.277-5.616-3.679-9.179-3.679-3.777 0-7.186 1.576-9.605 4.105l-0.005 0.005-56.395 56.26-61.747-61.747q-0.211-0.22-0.431-0.431c-2.381-2.277-5.616-3.679-9.179-3.679-3.777 0-7.186 1.576-9.605 4.106l-0.005 0.005-162.037 162.037q-0.221 0.211-0.431 0.431c-2.277 2.381-3.679 5.616-3.679 9.178 0 3.777 1.576 7.186 4.105 9.605l0.005 0.005c1.812 1.754 4.285 2.836 7.011 2.836 0.436 0 0.865-0.028 1.286-0.081l-0.050 0.005c4.452-0.089 8.393-2.203 10.95-5.456l0.023-0.031 151.032-151.095 31.621 31.621-401.946 401.947c-4.573 2.206-7.672 6.807-7.672 12.131 0 0.714 0.056 1.416 0.163 2.1l-0.010-0.076-47.893 167.612-24.663 24.663q-0.22 0.21-0.431 0.431c-2.277 2.381-3.679 5.616-3.679 9.179 0 3.777 1.575 7.186 4.105 9.605l0.005 0.005c1.813 1.754 4.286 2.835 7.012 2.835 0.435 0 0.864-0.028 1.285-0.081l-0.050 0.005c2.728 0 5.487-2.728 10.974-2.76l30.225-30.225q0.483-0.439 0.922-0.922c0.569-0.628 1.088-1.323 1.538-2.064l0.034-0.060 153.402-43.833c0.708 0.179 1.521 0.281 2.357 0.281 0.372 0 0.74-0.020 1.101-0.060l-0.045 0.004c2.727 0 8.341-2.76 10.974-2.76q0.22-0.211 0.431-0.431c1.538-1.626 2.669-3.655 3.217-5.911l0.018-0.090 411.147-408.223q0.221-0.211 0.431-0.431c2.277-2.381 3.679-5.616 3.679-9.179 0-3.777-1.576-7.186-4.106-9.605l-0.005-0.005-11.061-11.061 57.747-57.636c1.272-2.386 2.234-5.155 2.736-8.082l0.023-0.164c0.048-0.371 0.076-0.799 0.076-1.235 0-2.726-1.081-5.199-2.838-7.014l0.003 0.003zM292.729 645.946l90.238 90.238-128.473 36.386zM408.317 723.093l-103.005-103.005 394.158-396.871 104.346 104.377zM803.879 286.395l-63.178-63.178 46.686-46.718 63.178 63.21z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-32"],"grid":0},"attrs":[{}],"properties":{"order":34,"id":60,"name":"pentwo","prevSize":32,"code":59680},"setIdx":0,"setId":3,"iconIdx":61},{"icon":{"paths":["M868.587 270.862l-73.275-73.275c-0.697-1.32-1.54-2.453-2.528-3.439l-0-0c-0.656-0.488-1.398-0.938-2.182-1.316l-0.082-0.036-26.887-26.887c-8.777-8.135-20.569-13.125-33.526-13.125s-24.749 4.99-33.558 13.154l0.032-0.029-52.475 52.476c-0.156 0.15-0.308 0.302-0.458 0.458-0.296 0.403-0.591 0.865-0.857 1.344l-0.034 0.067c-0.65 0.384-1.21 0.779-1.736 1.214l0.022-0.018-384.674 384.672c-5.206 0.004-7.969 4.694-8.52 9.847-0.947 1.829-1.502 3.992-1.502 6.285 0 2.107 0.469 4.105 1.308 5.894l-0.036-0.085v10.102c-0.018 33.26-15.926 62.8-40.543 81.443l-0.255 0.185c-2.968 3.104-5.045 7.084-5.804 11.514l-0.019 0.131c-2.885 5.802-0.021 8.695 2.897 11.612l-55.339 55.339c-2.93 2.895-2.93 5.824-2.93 11.647 2.29 4.527 5.22 8.381 8.725 11.622l0.027 0.025 84.521 37.902h5.824c2.928 0 5.857-2.794 5.857 0l42.396-27.448 1.327 1.327c2.532 1.35 5.471 2.371 8.578 2.905l0.174 0.025 0.101 0.033c5.824 0 8.719-2.928 11.647-8.752 19.625-23.884 48.685-39.394 81.4-40.788l0.228-0.008h8.853c2.473 1.308 5.343 2.305 8.373 2.836l0.176 0.026c4.725-0.095 8.907-2.339 11.622-5.792l0.025-0.033 390.491-390.544c0.041-0.039 0.099-0.047 0.14-0.086l52.478-52.478c8.622-9.16 14.078-21.385 14.572-34.877l0.003-0.096c0.001-0.121 0.002-0.265 0.002-0.409 0-13.546-5.58-25.789-14.566-34.555l-0.010-0.010zM244.722 827.506l-58.3-26.221 37.817-37.885 46.645 46.645zM303.055 801.385l-69.98-69.947c22.153-18.76 37.101-45.434 40.457-75.606l0.047-0.523 105.896 105.896c-29.925 6.409-55.87 20.555-76.481 40.237l0.061-0.058zM416.662 754.765l-134.104-134.104 370.264-370.264 134.104 134.104zM851.118 320.409l-43.76 43.76-134.104-134.104 43.66-43.624c0.518-0.583 1.052-1.117 1.616-1.618l0.019-0.017c3.424-3.051 7.964-4.915 12.939-4.915 5.789 0 10.988 2.524 14.557 6.531l0.017 0.019 17.504 17.502-29.083 29.083c-0.156 0.15-0.308 0.302-0.458 0.458-2.417 2.527-3.905 5.961-3.905 9.741 0 4.009 1.673 7.627 4.358 10.194l0.005 0.005c1.925 1.862 4.551 3.010 7.445 3.010 0.461 0 0.915-0.029 1.36-0.086l-0.053 0.005c2.895 0 5.822-2.962 11.647-2.93l29.083-29.083 32.079 32.079-29.083 29.083c-0.156 0.15-0.31 0.302-0.458 0.458-2.417 2.527-3.905 5.961-3.905 9.741 0 4.009 1.673 7.627 4.358 10.194l0.005 0.005c1.923 1.861 4.547 3.008 7.438 3.008 0.462 0 0.918-0.029 1.365-0.086l-0.053 0.006c2.897 0 5.824-2.962 11.647-2.928l29.083-29.083 14.574 14.574c2.895 5.824 5.824 8.752 5.824 14.577-0.123 5.573-2.273 10.621-5.739 14.457l0.017-0.019z","M492.531 460.303c-55.405 55.372-104.953 131.176-75.804 160.325 5.876 5.432 13.764 8.764 22.43 8.764 0.315 0 0.629-0.004 0.942-0.013l-0.046 0.001c34.973 0 90.379-40.796 136.999-84.556 58.3-55.37 104.852-131.174 75.804-160.325-29.050-29.149-102.025 17.504-160.325 75.804zM635.353 402.003c5.824 8.752-11.68 58.267-75.804 122.424-64.122 64.157-113.67 81.626-122.422 75.804-5.824-8.752 11.68-58.302 75.804-122.424 55.37-55.405 102.023-75.804 116.6-75.804z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-33"],"grid":0},"attrs":[{},{}],"properties":{"order":35,"id":61,"name":"watercolor","prevSize":32,"code":59681},"setIdx":0,"setId":3,"iconIdx":62},{"icon":{"paths":["M626.809 132.562c-0.042-0-0.093-0-0.143-0-137.195 0-248.414 111.219-248.414 248.414 0 73.742 32.132 139.98 83.159 185.476l0.246 0.215-220.926 306.106c-3.007 4.109-4.811 9.263-4.811 14.838 0 13.965 11.321 25.287 25.287 25.287 8.424 0 15.886-4.119 20.481-10.454l0.051-0.073 220.898-306.068c35.635 20.92 78.485 33.275 124.221 33.275 137.247 0 248.508-111.261 248.508-248.508s-111.261-248.508-248.508-248.508c-0.017 0-0.034 0-0.051 0l0.002-0zM626.809 579.106c-0.001 0-0.002 0-0.004 0-109.344 0-197.985-88.641-197.985-197.985s88.641-197.985 197.985-197.985c109.344 0 197.985 88.641 197.985 197.985l-0 0c-0.128 109.292-88.69 197.855-197.969 197.985l-0.012 0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-34"],"grid":0},"attrs":[{}],"properties":{"order":36,"id":62,"name":"search","prevSize":32,"code":59682},"setIdx":0,"setId":3,"iconIdx":63},{"icon":{"paths":["M801.291 385.539c-17.622-45.147-60.582-76.638-110.953-77.078l-0.055-0c-6.158 0-15.415 3.096-21.576 3.096-24.566-78.766-96.576-135.054-181.822-135.645l-0.069-0c-0.119-0-0.261-0-0.402-0-98.502 0-179.343 75.619-187.638 171.972l-0.049 0.702h-12.742c-90.14 0.148-163.155 73.255-163.155 163.415 0 90.252 73.164 163.415 163.415 163.415 0.057 0 0.115-0 0.172-0l40.229 0c8.486-0.037 15.35-6.925 15.35-15.416 0-8.514-6.902-15.416-15.416-15.416-0.004 0-0.007 0-0.011 0l-40.274-0c-73.184-0.053-132.491-59.392-132.491-132.584 0-73.224 59.36-132.584 132.584-132.584 0.032 0 0.065 0 0.097 0l-0.005-0c1.067 0.112 2.010 0.269 2.932 0.477l-0.166-0.031c4.222 18.64 14.407 58.691 49.568 70.403h6.16c6.195 0 12.353-3.027 9.257-9.259 0.201-0.472 0.401-1.056 0.562-1.655l0.022-0.098c0.281-1.038 0.442-2.229 0.442-3.458 0-6.36-4.321-11.712-10.188-13.278l-0.096-0.022c-15.489-4.422-24.538-24.679-28.462-40.357 1.474-0.772 2.743-1.677 3.872-2.73l-0.010 0.009c3.096-3.062 3.096-6.158 3.096-12.319-0-0.147-0.001-0.321-0.001-0.496 0-86.586 70.192-156.778 156.778-156.778 71.35 0 131.568 47.663 150.551 112.886l0.276 1.108c-20.105 12.554-33.282 34.559-33.282 59.642 0 0.731 0.011 1.46 0.033 2.186l-0.003-0.106c0 6.158 9.257 12.319 15.415 12.319h0.002c9.22 0 15.415-9.257 12.317-15.417-3.012-24.279 23.662-36.528 24.52-36.917h3.286c8.156-3.329 17.601-5.535 27.478-6.148l0.256-0.013c39.545 1.106 72.555 27.841 83.083 64.133l0.156 0.629c3.062 3.096 6.158 9.257 12.319 9.257 51.632 12.425 89.403 58.211 89.403 112.818 0 0.39-0.002 0.781-0.006 1.17l0-0.060v0.141c-0.041 64.64-52.451 117.025-117.096 117.025-0.025 0-0.050-0-0.076-0l-55.577 0c-8.497 0.022-15.377 6.916-15.377 15.416 0 8.514 6.902 15.416 15.416 15.416 0.014 0 0.027-0 0.041-0l-0.002 0h55.503c82.184-3.606 148.551-66.766 157.158-147.204l0.063-0.725c0.006-0.485 0.009-1.057 0.009-1.63 0-65.992-43.728-121.77-103.789-139.941l-1.035-0.269z","M600.886 599.747v-32.352q0.036-1.842 0-3.683c-1.076-51.962-43.453-93.673-95.573-93.673-52.794 0-95.592 42.798-95.592 95.592 0 0.62 0.006 1.239 0.018 1.857l-0.001-0.092v31.702c-18.833 1.717-33.523 17.253-33.894 36.298l-0.001 0.037v113.928c0.277 20.317 16.674 36.714 36.965 36.991l0.026 0h181.893q1.415 0.055 2.834 0c19.044-0.783 34.186-16.411 34.186-35.575 0-0.498-0.010-0.993-0.030-1.486l0.002 0.071v-113.928c-0.402-17.923-13.486-32.674-30.612-35.653l-0.221-0.032zM503.787 504.177c0.453-0.011 0.987-0.018 1.523-0.018 35.231 0 63.891 28.132 64.743 63.158l0.002 0.079v31.046h-129.487v-31.046c0.839-34.572 28.647-62.381 63.14-63.218l0.079-0.002zM603.947 749.183c-0.23 3.305-2.854 5.929-6.137 6.159l-0.021 0.001h-181.893c-3.305-0.231-5.93-2.855-6.159-6.14l-0.001-0.021v-113.929c0.232-3.305 2.856-5.928 6.14-6.157l0.021-0.001h9.111c0.065 0 0.12 0.037 0.185 0.037 0.063 0 0.117-0.037 0.181-0.037h172.417c3.304 0.231 5.927 2.854 6.157 6.137l0.001 0.021z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-35"],"grid":0},"attrs":[{},{}],"properties":{"order":37,"id":63,"name":"security","prevSize":32,"code":59683},"setIdx":0,"setId":3,"iconIdx":64},{"icon":{"paths":["M527.496 604.396c-41.533-21.629-90.697-34.316-142.825-34.316-45.070 0-87.924 9.484-126.677 26.565l2.014-0.792v-358.534c13.422-6.419 29.47-12.481 46.069-17.239l2.264-0.555v114.688c0.834 5.057 4.058 9.215 8.451 11.329l0.091 0.040h5.684c2.227-0.351 4.162-1.404 5.616-2.921l0.003-0.003 45.539-36.997 45.539 36.997c2.859 5.717 8.543 5.717 14.228 2.858 5.684 0 8.543-5.684 8.543-11.369v-119.61c23.367 6.020 43.272 12.98 62.406 21.374l-2.606-1.019v213.171c0.023 6.73 4.718 12.356 11.010 13.807l0.096 0.019c2.411 1.967 5.523 3.159 8.913 3.159 7.816 0 14.153-6.336 14.153-14.153 0-0.014-0-0.028-0-0.042l0 0.002v-218.868c34.751-15.908 75.384-25.182 118.183-25.182 44.911 0 87.438 10.212 125.383 28.441l-1.74-0.753v213.57c-0.016 0.243-0.025 0.527-0.025 0.813 0 7.422 6.017 13.438 13.438 13.438 0.286 0 0.571-0.009 0.852-0.027l-0.039 0.002c0.253 0.017 0.549 0.027 0.847 0.027 7.422 0 13.438-6.017 13.438-13.438 0-0.287-0.009-0.572-0.027-0.854l0.002 0.039v-221.948c-0.834-5.057-4.058-9.215-8.451-11.329l-0.091-0.040c-41.8-21.491-91.21-34.088-143.563-34.088-50.336 0-97.953 11.646-140.302 32.39l1.884-0.833c-23.486-10.618-50.997-19.587-79.615-25.532l-2.624-0.456c-14.848-2.529-31.951-3.974-49.391-3.974-22.831 0-45.083 2.477-66.503 7.176l2.045-0.377c-0.654 0.333-1.189 0.644-1.706 0.98l0.071-0.043c-29.363 5.858-55.465 15.396-79.494 28.294l1.517-0.744c-5.684 2.825-8.543 5.684-8.543 11.368v386.988c0.092 4.612 2.282 8.695 5.653 11.344l0.032 0.024c2.002 1.338 4.465 2.136 7.114 2.136s5.111-0.798 7.161-2.166l-0.047 0.030c37.987-20.166 83.054-32.007 130.886-32.007s92.898 11.841 132.428 32.751l-1.543-0.744c0 2.858 2.826 2.858 5.684 2.858 5.397-1.265 10.157-3.269 14.464-5.934l-0.206 0.119c0.835-1.903 1.321-4.122 1.321-6.454 0-5.545-2.747-10.448-6.954-13.423l-0.051-0.035zM385.193 274.48c-1.969-2.605-5.061-4.271-8.542-4.271s-6.573 1.666-8.523 4.244l-0.019 0.027-31.313 25.596v-87.334c5.423-1.101 10.865-2.079 16.336-2.815 0.799-0.080 1.595-0.208 2.395-0.283 0.476-0.059 0.954-0.095 1.431-0.152 9.533-0.881 20.616-1.383 31.817-1.383 6.185 0 12.335 0.153 18.445 0.456l-0.86-0.034q5.080 0.411 10.147 1.035v90.51z","M524.605 692.781c-50.439-22.631-109.325-35.813-171.29-35.813-53.979 0-105.622 10.004-153.175 28.258l2.927-0.988v-310.169c-0.026-7.838-6.386-14.182-14.227-14.182s-14.201 6.344-14.227 14.179l-0 0.002v330.080c0.092 4.612 2.282 8.695 5.653 11.344l0.032 0.024c2.002 1.338 4.465 2.136 7.114 2.136s5.111-0.798 7.161-2.166l-0.047 0.030c2.859 0 162.215-73.994 318.712 0h5.684c4.607-0.084 8.689-2.262 11.344-5.62l0.024-0.031c0.67-1.56 1.059-3.376 1.059-5.282 0-5.001-2.679-9.376-6.681-11.769l-0.063-0.035z","M860.337 573.28c-0.689-24.619-20.811-44.314-45.533-44.314-7.54 0-14.652 1.832-20.916 5.075l0.254-0.12c-8.064-13.388-22.522-22.205-39.040-22.205-8.751 0-16.925 2.475-23.858 6.763l0.195-0.112c-8.351-10.916-21.384-17.887-36.044-17.887-5.125 0-10.051 0.852-14.644 2.422l0.319-0.095v-97.426c-0.684-24.618-20.803-44.313-45.523-44.313s-44.839 19.696-45.522 44.25l-0.001 0.063v159.17c-4.239-1.681-9.15-2.656-14.288-2.656-21.959 0-39.76 17.801-39.76 39.76 0 0.028 0 0.055 0 0.083l-0-0.004v93.905c0.574 97.196 79.212 175.834 176.353 176.409l0.055 0q1.023 0.006 2.045-0.001c80.667-0.635 145.816-66.175 145.816-146.931 0-0.394-0.002-0.788-0.005-1.181l0 0.060v-133.205c0.024-0.145 0.079-0.277 0.099-0.424zM831.784 723.994c-0.408 65.834-53.666 119.093-119.461 119.5l-0.039 0q-0.924 0.006-1.846 0c-80.752-0.524-146.013-66.107-146.013-146.933 0-0.324 0.001-0.649 0.003-0.973l-0 0.050v-93.905c-0-0.009-0-0.019-0-0.029 0-6.288 5.097-11.385 11.385-11.385s11.385 5.097 11.385 11.385c0 0.010-0 0.020-0 0.030l0-0.002v79.678c0.018 7.844 6.381 14.195 14.227 14.195s14.209-6.351 14.227-14.193l0-0.002v-67.856c1.775-2.243 2.847-5.113 2.847-8.233 0-0.269-0.008-0.536-0.024-0.8l0.002 0.037v-199.178c0.414-9.107 7.897-16.334 17.069-16.334s16.655 7.227 17.068 16.297l0.001 0.037v124.884c-1.649 4.3-2.672 9.271-2.824 14.461l-0.002 0.066v17.156c0.016 3.17 1.075 6.090 2.851 8.437l-0.026-0.035v31.383c0.018 7.844 6.381 14.195 14.227 14.195s14.209-6.351 14.227-14.193l0-0.002v-65.579c3.084-4.664 8.305-7.699 14.235-7.699 8.305 0 15.22 5.953 16.711 13.824l0.017 0.106c-1.445 4.047-2.341 8.719-2.474 13.581l-0.001 0.062v17.157c0.016 3.17 1.075 6.089 2.85 8.436l-0.026-0.035v20.114c-0.016 0.243-0.025 0.527-0.025 0.813 0 7.422 6.017 13.438 13.438 13.438 0.286 0 0.571-0.009 0.852-0.027l-0.039 0.002c7.643-0.511 13.716-6.584 14.224-14.181l0.002-0.046v-54.307c3.095-4.667 8.326-7.702 14.266-7.702 9.169 0 16.648 7.231 17.046 16.302l0.001 0.036v2.641c-1.668 4.323-2.703 9.323-2.857 14.543l-0.002 0.066v17.086c0.017 3.187 1.089 6.121 2.883 8.474l-0.025-0.034v2.765c-0 0.027-0 0.059-0 0.091 0 7.858 6.37 14.227 14.227 14.227s14.227-6.37 14.227-14.227c0-0.032-0-0.064-0-0.096l0 0.005v-38.412c3.089-4.671 8.319-7.709 14.258-7.709 9.411 0 17.040 7.629 17.040 17.040 0 0.278-0.007 0.555-0.020 0.831l0.001-0.039v1.903c-0.023 0.322-0.098 0.629-0.099 0.956z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-36"],"grid":0},"attrs":[{},{},{}],"properties":{"order":38,"id":64,"name":"consult","prevSize":32,"code":59684},"setIdx":0,"setId":3,"iconIdx":65},{"icon":{"paths":["M761.928 294.257c-4.943 0.024-9.325 2.402-12.085 6.070l-0.028 0.039h-446.352q-2.275 0.104-4.552 0c-20.34-0.959-37.406-13.995-44.256-32.057l-0.114-0.342v-22.669c-0.025-2.732-0.77-5.284-2.055-7.483l0.039 0.072c4.877-23.792 25.643-41.435 50.529-41.435 0.144 0 0.287 0.001 0.431 0.002l-0.022-0h452.398c8.427-0.019 15.25-6.854 15.25-15.283s-6.824-15.264-15.248-15.283l-0.002-0h-452.397c-38.85 1.697-70.355 31.041-75.402 68.76l-0.045 0.407c-2.505 2.699-4.042 6.326-4.042 10.313 0 0.003 0 0.006 0 0.009l-0-0v580.772c0.797 43.576 35.912 78.691 79.413 79.487l0.075 0.001h452.398c8.786-0.994 16.35-5.536 21.333-12.135l0.057-0.078v-583.919c-0.022-8.424-6.856-15.245-15.283-15.245-0.013 0-0.027 0-0.040 0l0.002-0zM306.498 878.102q-0.425 0.003-0.85 0c-28.278-0.241-51.108-23.22-51.108-51.531 0-0.149 0.001-0.299 0.002-0.448l-0 0.023v-521.012c13.053 11.502 30.066 18.786 48.759 19.582l0.162 0.005h443.22v553.381z","M575.529 465.485c-2.151-1.438-4.796-2.295-7.642-2.295s-5.491 0.857-7.692 2.327l0.051-0.032-134.967 73.344c-0.565-0.078-1.219-0.123-1.883-0.123-0.259 0-0.517 0.007-0.773 0.020l0.036-0.002h-67.24c-0.261-0.017-0.566-0.026-0.874-0.026s-0.612 0.009-0.915 0.028l0.041-0.002c-7.588 0.474-13.563 6.745-13.563 14.41 0 0.307 0.010 0.612 0.029 0.915l-0.002-0.041v91.772c-0.017 0.261-0.026 0.566-0.026 0.874 0 7.973 6.463 14.436 14.436 14.436 0.307 0 0.612-0.010 0.915-0.029l-0.041 0.002h67.24c0.261 0.017 0.566 0.026 0.874 0.026s0.613-0.010 0.915-0.028l-0.041 0.002c0.178-0.011 0.341-0.067 0.517-0.084l135.322 73.536c0 3.071 3.035 3.071 6.106 3.071 3.437-0.436 6.541-1.548 9.283-3.201l-0.106 0.059c3.655-2.872 6.007-7.258 6.106-12.196l0-0.016v-244.535c-0.099-4.955-2.452-9.341-6.072-12.187l-0.034-0.026zM410.412 630.497h-36.674v-61.134h36.674zM548.033 697.843l-110.055-61.134v-70.311l110.055-61.133z","M612.185 544.92c-3.729 2.819-6.114 7.246-6.114 12.23 0 3.461 1.15 6.653 3.088 9.216l-0.028-0.038c6.968 10.603 11.114 23.6 11.114 37.566 0 15.84-5.334 30.434-14.305 42.084l0.12-0.162-0.209 0.278c-1.819 2.465-2.912 5.563-2.912 8.916 0 4.99 2.42 9.416 6.15 12.166l0.041 0.029c2.017 1.952 4.769 3.155 7.803 3.155 0.484 0 0.962-0.031 1.43-0.090l-0.056 0.006c5.465-0.933 9.941-4.464 12.17-9.253l0.042-0.101c11.697-16.344 18.704-36.74 18.704-58.772 0-20.089-5.825-38.817-15.878-54.588l0.245 0.411c-2.819-3.729-7.246-6.113-12.23-6.113-3.461 0-6.653 1.15-9.216 3.088l0.038-0.028z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-37"],"grid":0},"attrs":[{},{},{}],"properties":{"order":39,"id":65,"name":"sound","prevSize":32,"code":59685},"setIdx":0,"setId":3,"iconIdx":66},{"icon":{"paths":["M799.264 383.714c-16.963-43.458-58.316-73.769-106.802-74.193l-0.052-0c-5.928 0-14.838 2.981-20.766 2.981-23.648-75.817-92.963-129.998-175.018-130.568l-0.067-0c-0.115-0-0.251-0-0.387-0-94.816 0-172.631 72.789-180.614 165.535l-0.047 0.675h-11.858c-86.874-0-157.299 70.425-157.299 157.299s70.425 157.299 157.299 157.299v0c8.196-0 14.839-6.644 14.839-14.839s-6.644-14.839-14.839-14.839h-0c-70.483 0-127.621-57.138-127.621-127.621s57.138-127.621 127.621-127.621v-0c2.050 0.134 3.96 0.454 5.798 0.947l-0.207-0.047c4.15 18.2 14.139 56.119 47.598 67.264h5.928c0.332 0.050 0.716 0.078 1.106 0.078 4.353 0 7.882-3.529 7.882-7.882 0-0.39-0.028-0.774-0.083-1.149l0.005 0.043c0.196-0.458 0.389-1.020 0.542-1.597l0.020-0.091c0.271-0.999 0.426-2.147 0.426-3.331 0-6.123-4.16-11.274-9.807-12.781l-0.092-0.021c-15.407-4.399-24.259-25.127-27.817-40.388 0.446-0.354 0.96-0.682 1.326-1.044 2.981-2.947 2.981-5.928 2.981-11.858-0-0.132-0.001-0.287-0.001-0.443 0-83.368 67.583-150.952 150.952-150.952 69.568 0 128.145 47.061 145.631 111.084l0.246 1.059c-19.846 11.988-32.911 33.442-32.911 57.949 0 0.704 0.011 1.406 0.032 2.105l-0.002-0.102c0 5.93 8.91 11.858 14.84 11.858 8.875-2.981 14.838-8.91 11.858-14.838-2.947-23.749 23.749-35.606 23.749-35.606 1.956-0.797 3.617-1.955 4.969-3.405l0.008-0.008c7.575-2.406 16.288-3.793 25.324-3.793 38.55 0 71.205 25.236 82.347 60.089l0.169 0.612c2.947 2.983 5.928 8.91 11.858 8.91 49.7 11.962 86.056 56.034 86.056 108.598 0 0.375-0.002 0.749-0.006 1.123l0-0.057v0.136c-0.039 62.221-50.488 112.647-112.715 112.647-0.024 0-0.047-0-0.071-0l-14.835 0c-0.010-0-0.021-0-0.033-0-8.195 0-14.838 6.643-14.838 14.838s6.643 14.838 14.838 14.838c0.012 0 0.023-0 0.035-0l-0.002 0h11.858c80.011-1.305 145.148-63.253 151.503-141.809l0.036-0.548c0.006-0.466 0.009-1.017 0.009-1.568 0-63.521-42.090-117.212-99.902-134.704l-0.997-0.259z","M686.279 751.673v-172.278c0.016-0.254 0.025-0.55 0.025-0.848s-0.009-0.595-0.027-0.889l0.002 0.040c-0.461-7.367-6.549-13.168-13.992-13.168-0.298 0-0.595 0.009-0.889 0.028l0.040-0.002h-139.478v-32.352h17.788c2.981 0 2.981-2.947 2.981-5.928l-35.606-65.285c0-2.981-5.928-2.981-5.928 0l-35.606 65.285v5.928h26.694v32.352h-142.458c-0.254-0.017-0.55-0.027-0.848-0.027s-0.595 0.010-0.888 0.029l0.040-0.002c-7.368 0.459-13.17 6.547-13.17 13.99 0 0.298 0.009 0.594 0.028 0.888l-0.002-0.040v178.204c-0.016 0.254-0.025 0.55-0.025 0.848s0.009 0.595 0.027 0.889l-0.002-0.040c0.025 0.427 0.253 0.774 0.316 1.19l-41.852 65.379c-1.396 2.088-2.228 4.657-2.228 7.419s0.832 5.331 2.258 7.468l-0.031-0.049c2.789 3.548 7.047 5.831 11.842 5.928l0.016 0h403.631c5.611-1.277 10.567-3.322 15.060-6.053l-0.222 0.125c1.421-2.081 2.268-4.651 2.268-7.419s-0.848-5.338-2.298-7.465l0.030 0.046zM374.663 594.372h127.619v29.677h-26.694v5.93l35.606 65.283c0 2.983 5.928 2.983 5.928 0l35.606-65.283c0-2.983 0-5.93-2.981-5.93h-17.788v-29.677h124.641v148.387h-281.938zM341.968 816.954l26.916-44.517h293.634l29.654 44.517z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-38"],"grid":0},"attrs":[{},{}],"properties":{"order":40,"id":66,"name":"files","prevSize":32,"code":59686},"setIdx":0,"setId":3,"iconIdx":67},{"icon":{"paths":["M801.797 405.539c-16.57-42.452-56.966-72.063-104.33-72.477l-0.051-0c-5.791 0-14.495 2.912-20.288 2.912-23.104-74.075-90.833-127.008-171.005-127.549l-0.063-0c-0.112-0-0.245-0-0.378-0-92.623 0-168.639 71.105-176.439 161.707l-0.046 0.66h-11.628c-84.855 0.013-153.638 68.805-153.638 153.661 0 84.865 68.796 153.661 153.661 153.661 0.008 0 0.016-0 0.025-0l43.519 0c8.704 0 20.288-5.792 20.288-14.495 0.016-0.248 0.024-0.537 0.024-0.828s-0.009-0.581-0.026-0.868l0.002 0.039c-0.451-7.198-6.399-12.866-13.671-12.866-0.291 0-0.579 0.009-0.865 0.027l0.039-0.002h-43.52c-68.812-0.054-124.575-55.85-124.575-124.669s55.762-124.615 124.569-124.669l0.005-0c2.015 0.131 3.891 0.446 5.697 0.931l-0.203-0.046c4.056 17.781 13.815 54.817 46.496 65.703h5.791c5.825 0 11.618-2.847 8.704-8.704 0.191-0.447 0.379-0.996 0.529-1.56l0.020-0.089c0.264-0.976 0.416-2.097 0.416-3.253 0-5.981-4.063-11.013-9.579-12.487l-0.090-0.021c-15.057-4.297-23.707-24.564-27.18-39.474 0.425-0.337 0.92-0.651 1.272-0.999 2.911-2.879 2.911-5.791 2.911-11.583-0-0.132-0.001-0.289-0.001-0.445 0-81.43 66.012-147.442 147.442-147.442 67.611 0 124.592 45.508 141.986 107.563l0.248 1.038c-17.571 12.024-28.951 31.976-28.951 54.587 0 0.706 0.011 1.41 0.033 2.111l-0.003-0.102c0 5.791 8.704 11.584 14.495 11.584 8.672 0 14.497-8.704 11.583-14.495-2.813-22.669 21.849-34.16 22.994-34.684h0.374q0.677-0.223 1.359-0.437c7.514-2.426 16.158-3.825 25.129-3.825 37.676 0 69.59 24.667 80.474 58.732l0.165 0.598c2.879 2.914 5.791 8.705 11.584 8.705 48.55 11.684 84.066 54.736 84.066 106.084 0 0.367-0.002 0.734-0.005 1.1l0-0.056v0.135c-0.038 60.782-49.32 110.040-110.107 110.040-0.024 0-0.047-0-0.071-0l-43.517 0c-0.010-0-0.021-0-0.032-0-8.005 0-14.495 6.49-14.495 14.495s6.49 14.495 14.495 14.495c0.011 0 0.023-0 0.034-0l-0.002 0h43.52c76.045-2.006 137.191-63.047 139.362-138.861l0.005-0.204c0.005-0.455 0.009-0.993 0.009-1.531 0-62.053-41.117-114.502-97.593-131.589l-0.973-0.253z","M644.921 654.778c5.793 0 8.672 0 11.584-5.791 1.364-2.040 2.176-4.549 2.176-7.248s-0.813-5.208-2.206-7.295l0.030 0.048-113.054-194.171c-2.911-8.703-17.406-8.703-23.199 0l-113.051 194.17c-1.364 2.040-2.177 4.549-2.177 7.248s0.813 5.208 2.207 7.295l-0.030-0.048c2.724 3.466 6.883 5.697 11.566 5.79l0.015 0h55.071v115.965h-55.143c-8.003 0.004-14.489 6.492-14.489 14.496 0 8.006 6.49 14.496 14.496 14.496 0.023 0 0.045-0 0.068-0l-0.003 0h69.566c0.248 0.016 0.537 0.025 0.828 0.025 7.563 0 13.693-6.131 13.693-13.693 0-0.291-0.009-0.58-0.027-0.866l0.002 0.039v-144.957c0.016-0.248 0.025-0.537 0.025-0.829 0-7.562-6.13-13.692-13.692-13.692-0.292 0-0.582 0.009-0.869 0.027l0.039-0.002h-43.52l87.042-150.648 87.040 150.648h-43.52c-0.248-0.016-0.537-0.026-0.828-0.026s-0.581 0.009-0.868 0.028l0.039-0.002c-7.197 0.45-12.863 6.397-12.863 13.667 0 0.291 0.009 0.581 0.027 0.868l-0.002-0.039v144.957c-0.016 0.248-0.026 0.537-0.026 0.829s0.009 0.581 0.028 0.868l-0.002-0.039c0.45 7.196 6.396 12.863 13.666 12.863 0.292 0 0.581-0.009 0.868-0.027l-0.039 0.002h66.759c8.002-0.005 14.488-6.493 14.488-14.496 0-8.006-6.49-14.496-14.496-14.496-0.023 0-0.045 0-0.068 0l0.003-0h-52.224v-115.965z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-39"],"grid":0},"attrs":[{},{}],"properties":{"order":41,"id":67,"name":"upload","prevSize":32,"code":59687},"setIdx":0,"setId":3,"iconIdx":68},{"icon":{"paths":["M502.783 138.143c-223.076-0-403.915 180.839-403.915 403.915s180.839 403.915 403.915 403.915c223.076 0 403.915-180.839 403.915-403.915v0c-0.261-222.97-180.944-403.653-403.889-403.914l-0.026-0zM502.783 902.622c-199.134 0-360.565-161.43-360.565-360.565s161.43-360.565 360.565-360.565c199.134 0 360.565 161.43 360.565 360.565l-0 0c-0.234 199.040-161.524 360.33-360.542 360.565l-0.023 0z","M637.397 409.355c-3.934-3.987-9.397-6.457-15.438-6.457-5.932 0-11.307 2.382-15.222 6.241l0.003-0.003-103.631 102.161-101.428-104.37c-3.939-4.026-9.427-6.523-15.499-6.523-11.971 0-21.675 9.704-21.675 21.675 0 5.854 2.321 11.166 6.092 15.066l-0.006-0.006 101.643 104.591-103.852 102.379c-3.976 3.932-6.438 9.387-6.438 15.417 0 11.973 9.706 21.678 21.678 21.678 5.921 0 11.288-2.374 15.201-6.222l-0.003 0.003 103.631-102.161 101.421 104.363c3.947 4.085 9.474 6.621 15.594 6.621 11.971 0 21.675-9.704 21.675-21.675 0-5.902-2.359-11.253-6.186-15.162l0.004 0.004-101.636-104.584 103.852-102.379c3.987-3.934 6.457-9.397 6.457-15.438 0-5.932-2.382-11.307-6.241-15.222l0.002 0.003z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-40"],"grid":0},"attrs":[{},{}],"properties":{"order":42,"id":68,"name":"close","prevSize":32,"code":59688},"setIdx":0,"setId":3,"iconIdx":69},{"icon":{"paths":["M896.148 552.765c-0.072-1.692-0.26-3.285-0.558-4.84l0.033 0.204-0.173-0.918c-0.454-2.080-1.037-3.888-1.771-5.617l0.077 0.205c-0.361-0.838-0.713-1.529-1.105-2.194l0.050 0.092-9.673 4.904 9.327-5.553c-0.477-0.976-0.947-1.792-1.466-2.573l0.051 0.082c-0.744-1.078-1.486-2.017-2.282-2.906l0.024 0.027c-0.517-0.687-1.042-1.294-1.604-1.865l-205.172-208.569c-5.676-5.783-13.575-9.368-22.311-9.368-17.26 0-31.252 13.992-31.252 31.252 0 8.551 3.434 16.3 8.999 21.943l152.995 155.538h-632.080c-17.262-0-31.256 13.994-31.256 31.256s13.994 31.256 31.256 31.256h635.618l-164.104 179.016c-5.095 5.543-8.218 12.969-8.218 21.125 0 17.264 13.996 31.26 31.26 31.26 9.109 0 17.308-3.896 23.022-10.113l0.020-0.022 212.054-231.34c0.563-0.622 1.103-1.299 1.599-2.007l0.045-0.067c0.575-0.72 1.132-1.453 1.637-2.23l0.018-0.028c0.51-0.802 1.051-1.77 1.542-2.767l0.084-0.189c0.345-0.626 0.718-1.41 1.052-2.215l0.062-0.169c0.358-0.896 0.732-2.046 1.042-3.222l0.051-0.228c0.192-0.589 0.391-1.36 0.55-2.144l0.025-0.149c0.198-1.046 0.341-2.286 0.397-3.548l0.002-0.057c0.1-0.645 0.16-1.392 0.166-2.153l0-0.006z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-41"],"grid":0},"attrs":[{}],"properties":{"order":43,"id":69,"name":"arrow","prevSize":32,"code":59689},"setIdx":0,"setId":3,"iconIdx":70},{"icon":{"paths":["M521.275 327.238c-0-0-0-0-0-0-48.272 0-87.404 39.132-87.404 87.404s39.132 87.404 87.404 87.404c48.272 0 87.404-39.132 87.404-87.404v0c0-48.272-39.132-87.404-87.404-87.404l-0-0zM521.275 477.394c-34.55-0.062-62.534-28.085-62.534-62.643 0-34.597 28.046-62.643 62.643-62.643s62.643 28.046 62.643 62.643c0 34.558-27.984 62.581-62.528 62.643l-0.006 0q-0.109 0-0.218 0z","M689.369 247.115c-43.622-43.264-103.695-69.999-170.012-69.999s-126.39 26.735-170.029 70.015l0.016-0.016c-84.134 84.047-94.226 242.071-22.494 337.322l192.179 246.54 192.179-245.973c72.277-95.904 61.64-253.82-21.796-337.845zM691.048 570.422l-171.451 216.853-172.584-216.853c-64.997-86.837-56.039-229.168 20.184-305.368 39.003-38.779 92.767-62.749 152.128-62.749s113.125 23.97 152.138 62.759l-0.010-0.010c75.634 75.633 85.159 218.531 19.617 305.368z"],"attrs":[{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-42"],"grid":0},"attrs":[{},{}],"properties":{"order":44,"id":70,"name":"mark","prevSize":32,"code":59690},"setIdx":0,"setId":3,"iconIdx":71},{"icon":{"paths":["M650.496 510.321h-77.875c-3.962-15.412-15.861-27.31-30.974-31.207l-0.299-0.065v-110.797c0-6.061-4.913-10.974-10.974-10.974s-10.974 4.913-10.974 10.974v-0 110.797c-19.084 4.985-32.94 22.070-32.94 42.392 0 24.161 19.587 43.748 43.748 43.748 20.322 0 37.407-13.856 42.324-32.636l0.068-0.305h77.896c0 0 0.001 0 0.001 0 6.061 0 10.974-4.913 10.974-10.974 0-6.047-4.891-10.951-10.932-10.974l-0.002-0h-0.041zM530.374 543.221c-0 0-0 0-0 0-12.122 0-21.948-9.826-21.948-21.948s9.826-21.948 21.948-21.948c12.122 0 21.948 9.826 21.948 21.948v-0c-0.024 12.116-9.834 21.933-21.944 21.969l-0.003 0z","M761.378 298.622l44.974 44.974c1.931 2.035 4.655 3.302 7.675 3.302 2.819 0 5.38-1.103 7.275-2.901l-0.005 0.004q0.208-0.197 0.405-0.405c16.251-16.136 26.31-38.489 26.31-63.192 0-49.177-39.866-89.043-89.043-89.043-24.582 0-46.837 9.961-62.949 26.066l0-0c-2.035 1.931-3.302 4.655-3.302 7.675 0 2.819 1.103 5.38 2.901 7.275l-0.004-0.005q0.197 0.208 0.405 0.405l49.922 49.943-18.649 18.649c-52.028-46.634-121.138-75.145-196.908-75.145s-144.879 28.512-197.187 75.391l0.279-0.246-18.67-18.649 49.922-49.922c2.035-1.931 3.302-4.655 3.302-7.675 0-2.819-1.103-5.38-2.901-7.275l0.004 0.005q-0.197-0.208-0.405-0.405c-16.070-16.057-38.264-25.987-62.777-25.987-49.053 0-88.819 39.766-88.819 88.819 0 24.508 9.926 46.697 25.977 62.767l-0.001-0.001c1.931 2.035 4.655 3.302 7.675 3.302 2.819 0 5.38-1.103 7.275-2.901l-0.005 0.004q0.208-0.197 0.405-0.405l44.995-44.974 18.099 18.1c-50.934 53.084-82.296 125.289-82.296 204.818 0 107.917 57.747 202.347 144.027 254.073l1.344 0.747-32.901 32.901c-2.035 1.931-3.302 4.655-3.302 7.675 0 2.819 1.103 5.38 2.901 7.275l-0.004-0.005q0.197 0.208 0.405 0.405c1.931 2.035 4.655 3.302 7.675 3.302 2.819 0 5.38-1.103 7.275-2.901l-0.005 0.004q0.208-0.197 0.405-0.405l37.849-37.849c37.762 19.026 82.303 30.167 129.446 30.167s91.684-11.141 131.134-30.934l-1.687 0.767 37.849 37.849c1.931 2.035 4.655 3.302 7.675 3.302 2.819 0 5.38-1.103 7.275-2.901l-0.005 0.004q0.208-0.197 0.405-0.405c2.035-1.931 3.302-4.655 3.302-7.675 0-2.819-1.103-5.38-2.901-7.275l0.004 0.005q-0.197-0.208-0.405-0.405l-32.901-32.901c87.562-52.215 145.3-146.434 145.3-254.139 0-79.63-31.561-151.888-82.856-204.948l0.080 0.083zM805.781 232.8c12.083 12.087 19.557 28.783 19.557 47.224 0 14.598-4.683 28.103-12.629 39.093l0.135-0.196-93.247-93.247c10.808-7.699 24.282-12.308 38.831-12.308 18.46 0 35.187 7.42 47.361 19.441l-0.007-0.007zM247.906 319.47c-7.815-10.785-12.5-24.281-12.5-38.872 0-18.462 7.502-35.172 19.624-47.247l0.002-0.002c12.171-11.987 28.888-19.389 47.334-19.389 14.529 0 27.985 4.592 38.997 12.404l-0.209-0.141zM530.374 794.46c-150.853-0-273.144-122.291-273.144-273.144s122.291-273.144 273.144-273.144c150.853 0 273.144 122.291 273.144 273.144 0 0-0 0-0 0.001l0-0c-0.024 150.844-122.301 273.12-273.142 273.144l-0.002 0z","M530.374 301.35c6.056-0.012 10.962-4.918 10.974-10.973l0-0.001v-10.974c0-0.006 0-0.013 0-0.020 0-6.061-4.913-10.974-10.974-10.974-6.054 0-10.962 4.902-10.974 10.953l-0 0.001v11.015c0.012 6.056 4.918 10.962 10.973 10.974l0.001 0z","M530.374 738.512c-6.056 0.012-10.962 4.918-10.974 10.973l-0 0.001v10.974c0 6.061 4.913 10.974 10.974 10.974s10.974-4.913 10.974-10.974v0-10.974c-0.012-6.056-4.918-10.962-10.973-10.974l-0.001-0z","M759.644 530.641h10.974c0 0 0.001 0 0.001 0 6.061 0 10.974-4.913 10.974-10.974 0-6.047-4.891-10.951-10.932-10.974l-0.002-0h-11.015c-6.056 0.012-10.962 4.918-10.974 10.973l-0 0.001c-0.005 0.122-0.008 0.266-0.008 0.41 0 5.695 4.503 10.338 10.142 10.564l0.020 0.001q0.409 0.016 0.819 0z","M300.555 509.242h-10.974c-6.061 0-10.974 4.913-10.974 10.974s4.913 10.974 10.974 10.974h10.974c6.056-0.012 10.962-4.918 10.974-10.973l0-0.001c0.005-0.122 0.008-0.266 0.008-0.41 0-5.695-4.503-10.338-10.142-10.564l-0.020-0.001q-0.409-0.016-0.819 0z","M692.743 341.947l-7.675 7.675c-2.035 1.931-3.302 4.655-3.302 7.675 0 2.819 1.103 5.38 2.901 7.275l-0.004-0.005q0.197 0.208 0.405 0.405c1.931 2.035 4.655 3.302 7.675 3.302 2.819 0 5.38-1.103 7.275-2.901l-0.005 0.004q0.208-0.197 0.405-0.405l7.675-7.675c2.035-1.931 3.302-4.655 3.302-7.675 0-2.819-1.103-5.38-2.901-7.275l0.004 0.005q-0.197-0.208-0.405-0.405c-2.040-1.788-4.73-2.879-7.675-2.879s-5.635 1.091-7.689 2.89l0.013-0.012z","M360.352 674.338l-7.676 7.675c-2.035 1.931-3.302 4.655-3.302 7.675 0 2.819 1.103 5.38 2.901 7.275l-0.004-0.005q0.197 0.208 0.405 0.405c1.931 2.035 4.655 3.302 7.675 3.302 2.819 0 5.38-1.103 7.275-2.901l-0.005 0.004q0.208-0.197 0.405-0.405l7.675-7.675c2.035-1.931 3.302-4.655 3.302-7.675 0-2.819-1.103-5.38-2.901-7.275l0.004 0.005q-0.197-0.208-0.405-0.405c-2.040-1.788-4.731-2.879-7.676-2.879s-5.635 1.091-7.688 2.89l0.013-0.012z","M700.418 674.338c-1.921-1.744-4.483-2.812-7.295-2.812-6.002 0-10.868 4.866-10.868 10.868 0 2.812 1.068 5.374 2.82 7.304l-0.008-0.009 7.675 7.675c1.931 2.035 4.655 3.302 7.675 3.302 2.819 0 5.38-1.103 7.275-2.901l-0.005 0.004q0.208-0.197 0.405-0.405c2.035-1.931 3.302-4.655 3.302-7.675 0-2.819-1.103-5.38-2.901-7.275l0.004 0.005q-0.197-0.208-0.405-0.405z","M368.027 341.947c-1.92-1.743-4.482-2.81-7.292-2.81-6.002 0-10.868 4.866-10.868 10.868 0 2.811 1.067 5.372 2.818 7.301l-0.008-0.009 7.676 7.675c1.931 2.035 4.655 3.302 7.675 3.302 2.819 0 5.38-1.103 7.275-2.901l-0.005 0.004q0.208-0.197 0.405-0.405c2.035-1.931 3.302-4.655 3.302-7.675 0-2.819-1.103-5.38-2.901-7.275l0.004 0.005q-0.197-0.208-0.405-0.405z"],"attrs":[{},{},{},{},{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-43"],"grid":0},"attrs":[{},{},{},{},{},{},{},{},{},{}],"properties":{"order":45,"id":71,"name":"time","prevSize":32,"code":59691},"setIdx":0,"setId":3,"iconIdx":72},{"icon":{"paths":["M829.881 669.314l-124.315-83.156c-5.635-3.734-12.554-5.957-19.992-5.957-11.541 0-21.832 5.352-28.526 13.71l-0.056 0.072-36.037 46.485c-2.847 3.714-7.285 6.085-12.277 6.085-2.784 0-5.396-0.737-7.651-2.028l0.076 0.040-6.781-3.647c-42.205-23.072-78.242-51.447-108.9-84.84l-0.275-0.303c-33.7-30.745-62.073-66.589-84.064-106.447l-1.079-2.134-3.647-6.781c-1.25-2.179-1.988-4.791-1.988-7.575 0-4.992 2.371-9.43 6.048-12.25l0.037-0.027 46.485-36.036c8.531-6.647 13.966-16.922 13.966-28.467 0-7.501-2.295-14.467-6.22-20.232l0.080 0.125-83.013-124.704c-6.525-9.782-17.515-16.139-29.99-16.139-6.867 0-13.285 1.926-18.741 5.268l0.157-0.089-52.242 31.263c-16.108 9.618-28.049 24.797-33.265 42.832l-0.129 0.519c-18.807 68.426-4.691 185.98 168.73 359.402 137.918 137.918 240.824 174.999 311.401 174.999 0.025 0 0.055 0 0.085 0 17.060 0 33.585-2.288 49.286-6.574l-1.31 0.305c18.559-5.355 33.739-17.31 43.165-33.099l0.186-0.336 31.345-52.242c3.353-5.288 5.344-11.728 5.344-18.632 0-12.249-6.264-23.035-15.764-29.328l-0.13-0.081zM823.099 707.44l-31.345 52.242c-6.864 11.699-17.882 20.334-30.982 23.946l-0.363 0.085c-63.202 17.23-172.91 3.135-339.55-163.506s-180.756-276.86-163.506-340.083c3.899-13.364 12.474-24.31 23.793-31.19l0.238-0.134 52.221-31.406c2.278-1.384 5.033-2.203 7.979-2.203 5.36 0 10.087 2.712 12.883 6.84l0.035 0.055 82.501 124.909c1.697 2.402 2.713 5.39 2.713 8.616 0 5.053-2.492 9.523-6.314 12.25l-0.046 0.031-46.464 36.057c-8.573 6.586-14.044 16.842-14.044 28.375 0 6.47 1.722 12.538 4.732 17.771l-0.092-0.173 3.647 6.781c24.077 43.829 53.671 81.247 88.478 113.054l0.333 0.3c32.108 35.14 69.525 64.734 111.122 87.682l2.232 1.129 6.781 3.647c5.059 2.918 11.127 4.64 17.597 4.64 11.533 0 21.789-5.471 28.313-13.959l0.062-0.084 36.078-46.464c2.991-3.652 7.5-5.965 12.55-5.965 3.083 0 5.965 0.862 8.418 2.359l-0.071-0.040 125.38 83.054c4.157 3.011 6.83 7.85 6.83 13.313 0 2.977-0.794 5.769-2.181 8.175l0.042-0.079z","M579.674 297.374c0.012-0 0.026-0 0.041-0 96.024 0 173.87 77.831 173.893 173.85l0 0.002v0.103c0.016 5.759 4.688 10.421 10.448 10.421s10.433-4.662 10.448-10.419l0-0.001c-0.198-107.527-87.306-194.642-194.811-194.851l-0.020-0c-5.77 0-10.448 4.678-10.448 10.448s4.678 10.448 10.448 10.448h-0z","M579.674 358.999c62.264 0.105 112.714 50.54 112.842 112.789l0 0.012c0.016 5.759 4.688 10.421 10.448 10.421s10.433-4.662 10.448-10.419l0-0.001c-0-73.545-59.62-133.165-133.165-133.165l-0 0c-5.766 0.012-10.437 4.683-10.448 10.447l-0 0.001c-0.004 0.099-0.006 0.216-0.006 0.333 0 5.178 4.105 9.398 9.239 9.581l0.017 0q0.312 0.011 0.625 0.001z","M579.653 420.132c0-0 0-0 0.001-0 28.287 0 51.217 22.931 51.217 51.217v0c0 5.77 4.678 10.448 10.448 10.448s10.448-4.678 10.448-10.448v0c0-0.073 0-0.16 0-0.246 0-39.311-31.798-71.195-71.076-71.335l-0.013-0q-0.246-0.001-0.492 0c-5.766 0.012-10.437 4.683-10.448 10.447l-0 0.001c-0.003 0.093-0.005 0.203-0.005 0.312 0 5.197 4.126 9.43 9.28 9.603l0.016 0q0.312 0.010 0.624 0z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-44"],"grid":0},"attrs":[{},{},{},{}],"properties":{"order":46,"id":72,"name":"phone","prevSize":32,"code":59692},"setIdx":0,"setId":3,"iconIdx":73},{"icon":{"paths":["M649.241 583.077c-0.016-0-0.036-0-0.056-0-31.522 0-59.568 14.883-77.494 38.006l-0.167 0.224-150.216-84.045c3.466-9.625 5.472-20.731 5.477-32.306l0-0.002c0-0.031 0-0.068 0-0.105 0-11.587-2.048-22.695-5.802-32.983l0.213 0.669 150.327-83.934c18.057 23.343 46.075 38.227 77.568 38.227 54.020 0 97.812-43.792 97.812-97.812s-43.792-97.812-97.812-97.812c-54.020 0-97.812 43.792-97.812 97.812 0 0.040 0 0.079 0 0.119l-0-0.006c-0 0.063-0 0.139-0 0.214 0 11.549 2.048 22.62 5.801 32.869l-0.213-0.664-150.215 83.934c-18.056-23.367-46.088-38.269-77.6-38.269-54.020 0-97.812 43.792-97.812 97.812s43.792 97.812 97.812 97.812c31.641 0 59.772-15.024 77.651-38.326l0.171-0.233 150.364 84.045c-3.55 9.719-5.602 20.94-5.602 32.641 0 54.061 43.825 97.886 97.886 97.886s97.886-43.825 97.886-97.886c0-54.061-43.825-97.886-97.886-97.886-0.099 0-0.198 0-0.297 0l0.015-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-45"],"grid":0},"attrs":[{}],"properties":{"order":47,"id":73,"name":"share","prevSize":32,"code":59693},"setIdx":0,"setId":3,"iconIdx":74},{"icon":{"paths":["M818.292 733.257l-149.696-149.696c26.18-35.835 41.888-80.765 41.888-129.365 0-1.127-0.008-2.253-0.025-3.376l0.002 0.17c0-0 0-0.001 0-0.001 0-124.364-100.817-225.18-225.18-225.18s-225.18 100.817-225.18 225.18c0 124.363 100.816 225.18 225.18 225.18l0 0q3.194 0.046 6.39 0c49.075-0.719 94.132-17.344 130.393-44.934l-0.542 0.396 158.713 158.715c4.185 4.033 9.887 6.518 16.169 6.518 1.009 0 2.003-0.064 2.978-0.188l-0.116 0.012c6.344 0 12.685-6.342 19.029-15.858 5.901-6.171 9.533-14.555 9.533-23.787s-3.632-17.615-9.545-23.8l0.012 0.013zM485.279 609.567c-87.58 0-158.578-70.998-158.578-158.578s70.998-158.578 158.578-158.578c87.58 0 158.578 70.998 158.578 158.578 0 0-0 0-0 0l0-0c-0 87.58-70.998 158.577-158.578 158.578l0-0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-46"],"grid":0},"attrs":[{}],"properties":{"order":48,"id":74,"name":"seeker","prevSize":32,"code":59694},"setIdx":0,"setId":3,"iconIdx":75},{"icon":{"paths":["M412.222 852.548h140.785v-336.336h100.808l11.448-114.917h-106.501v-66.030c0-25.867 5.755-37.13 31.622-37.13h71.723v-117.578h-112.071c-91.525-0.495-134.844 42.637-134.844 128.841v89.050h-66.153v114.917h63.183z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-47"],"grid":0},"attrs":[{}],"properties":{"order":49,"id":75,"name":"fb","prevSize":32,"code":59695},"setIdx":0,"setId":3,"iconIdx":76},{"icon":{"paths":["M223.983 711.025c56.722 37.402 126.284 59.691 201.048 59.757l0.017 0c1.010 0.010 2.204 0.015 3.399 0.015 205.724 0 372.72-165.809 374.643-371.078l0.001-0.183v-0.031c0-7.226 0-14.452-0.401-21.678 25.886-19.278 47.769-42.165 65.381-68.179l0.628-0.983c-21.647 9.426-46.923 17.072-73.234 21.72l-2.065 0.302c27.61-16.395 48.591-41.477 59.4-71.423l0.3-0.951c-24.408 14.829-52.929 25.818-83.371 31.261l-1.505 0.223c-23.724-27.056-58.358-44.045-96.961-44.045-0.187 0-0.374 0-0.561 0.001l0.029-0c-73.213 0.228-132.476 59.631-132.476 132.876 0 0.141 0 0.282 0.001 0.422l-0-0.022v0.001c0.009 10.727 1.305 21.148 3.741 31.121l-0.185-0.898c-110.257-6.878-207.132-58.972-273.177-137.78l-0.491-0.603c-11.51 19.069-18.32 42.097-18.32 66.716 0 45.554 23.316 85.663 58.665 109.043l0.487 0.302c-21.94-0.375-42.451-6.152-60.366-16.051l0.666 0.338c-0 0.055-0 0.12-0 0.186 0 64.527 45.407 118.449 106.012 131.556l0.887 0.161c-10.807 3.348-23.231 5.276-36.105 5.276-8.366 0-16.541-0.814-24.451-2.368l0.799 0.131c18.567 51.665 65.963 88.468 122.3 91.172l0.312 0.012c-45.177 34.564-102.467 55.383-164.62 55.383-10.719 0-21.293-0.619-31.689-1.824l1.266 0.119z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-48"],"grid":0},"attrs":[{}],"properties":{"order":50,"id":76,"name":"tw","prevSize":32,"code":59696},"setIdx":0,"setId":3,"iconIdx":77},{"icon":{"paths":["M643.506 419.313c16.809-1.267 31.339-10.040 40.381-22.939l0.115-0.174v20.183h34.572v-190.372h-34.572v144.082c-4.596 7.108-11.66 12.284-19.955 14.341l-0.228 0.048c-8.659 0-8.659-5.729-8.659-11.459v-144.147h-34.572v158.47c-0.859 2.369-1.355 5.104-1.355 7.954 0 10.393 6.6 19.245 15.837 22.593l0.167 0.053c2.461 0.867 5.298 1.367 8.252 1.367 0.006 0 0.011-0 0.017-0l-0.001 0z","M485.036 367.227c-0.335 2.075-0.526 4.468-0.526 6.905 0 22.733 16.644 41.578 38.411 45.015l0.258 0.034q0.46 0.070 0.921 0.132c1.957 0.314 4.213 0.493 6.511 0.493s4.554-0.179 6.755-0.525l-0.244 0.032c0.672 0.032 1.459 0.051 2.25 0.051 26.752 0 48.584-21.064 49.817-47.511l0.004-0.111 0.014-0.347v-96.423c0.001-0.136 0.002-0.296 0.002-0.456 0-28.354-22.856-51.369-51.149-51.628l-0.223-0.002h-0.716c-1.131-0.094-2.448-0.148-3.777-0.148-25.423 0-46.272 19.585-48.281 44.491l-0.011 0.171-0.016 0.214c-0.093 1.072-0.147 2.32-0.147 3.581s0.053 2.508 0.158 3.742l-0.011-0.161zM522.473 277.901c0-11.524 5.794-17.318 14.454-17.318 11.459 0 14.389 8.659 14.389 17.318v86.397c0 11.524-5.729 17.318-14.389 17.318-8.185-0.896-14.498-7.771-14.498-16.121 0-0.421 0.016-0.839 0.048-1.252l-0.003 0.055z","M401.7 416.188h40.431v-103.65l46.095-152.806h-40.431l-26.043 100.85-26.043-100.85h-40.106l46.095 152.806z","M764.995 459.353h-412.061c-44.345 0.859-80.069 36.582-80.926 80.846l-0.001 0.081v204.566c0.859 44.345 36.582 80.069 80.846 80.926l0.081 0.001h412.061c44.318-0.894 80.005-36.604 80.861-80.847l0.001-0.081v-204.566c0.018-0.63 0.028-1.372 0.028-2.116 0-42.753-34.029-77.559-76.479-78.81l-0.115-0.003zM407.429 761.97h-37.436v-207.495h-40.431v-34.572h115.369v34.572h-37.502zM539.986 761.97h-34.572v-20.183c-5.327 7.177-12.077 12.989-19.864 17.1l-0.32 0.154c-17.318 11.524-43.231 11.524-43.231-26.043v-149.746h34.572v138.287c0 8.594 2.865 11.459 8.594 11.459s14.454-8.594 20.183-14.389v-135.292h34.572zM669.614 724.533c0 23.048-8.594 40.431-31.642 40.431-13.142-0.421-24.633-7.122-31.62-17.187l-0.087-0.132v14.454h-34.572v-242.197h34.507v77.607c6.806-9.008 16.83-15.274 28.332-17.091l0.25-0.033c26.043 0 31.707 20.183 31.707 46.095v98.051zM793.317 675.508h-63.414v34.572c0 14.454 0 26.043 14.454 26.043s14.454-8.594 14.454-26.043v-11.524h34.311v14.454c0 34.572-14.454 54.755-49.025 54.755-0.215 0.003-0.469 0.005-0.723 0.005-26.564 0-48.155-21.298-48.627-47.749l-0.001-0.044c-0.003-0.215-0.005-0.469-0.005-0.724 0-2.201 0.144-4.368 0.423-6.492l-0.027 0.25v-80.928c-0.097-1.15-0.153-2.49-0.153-3.842 0-25.364 19.521-46.169 44.359-48.21l0.174-0.011 0.284-0.022c1.082-0.093 2.342-0.146 3.613-0.146s2.531 0.053 3.776 0.157l-0.163-0.011c1.014-0.079 2.195-0.124 3.387-0.124 24.302 0 44.217 18.779 46.026 42.618l0.009 0.155q0.033 0.453 0.058 0.907c0.14 1.318 0.219 2.847 0.219 4.395s-0.080 3.077-0.235 4.583l0.016-0.189v43.296z","M744.552 609.229c-11.459 0-14.389 8.594-14.389 20.183v17.318h28.777v-17.318c0-11.589-2.865-20.183-14.388-20.183z","M615.25 612.094c-3.039 0.325-5.435 2.699-5.791 5.699l-0.003 0.031v112.374c2.865 2.865 5.794 5.794 8.659 5.794 5.729 2.865 14.389 2.865 17.318-2.93 2.865-2.865 2.865-5.729 2.865-11.459v-92.191c0.148-0.96 0.233-2.068 0.233-3.195 0-4.155-1.152-8.041-3.153-11.357l0.055 0.099c-8.985-5.599-14.779-8.594-20.183-2.865z"],"attrs":[{},{},{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-49"],"grid":0},"attrs":[{},{},{},{},{},{}],"properties":{"order":51,"id":77,"name":"yt","prevSize":32,"code":59697},"setIdx":0,"setId":3,"iconIdx":78},{"icon":{"paths":["M513.067 247.239c10.828-0.328 23.564-0.514 36.344-0.514 33.491 0 66.683 1.282 99.529 3.8l-4.363-0.269c2.216-0.148 4.803-0.232 7.41-0.232 19.050 0 37.049 4.497 52.995 12.486l-0.683-0.31c15.164 5.289 28.144 13.45 38.871 23.91l-0.022-0.021c11.076 10.303 19.388 23.433 23.796 38.244l0.155 0.605c5.283 17.123 9.485 37.4 11.805 58.244l0.139 1.538c2.245 28.072 3.525 60.775 3.525 93.778 0 13.268-0.207 26.488-0.618 39.657l0.048-1.925c0.38 11.66 0.596 25.367 0.596 39.125 0 32.402-1.2 64.524-3.558 96.323l0.253-4.246c0.134 2.127 0.211 4.612 0.211 7.115 0 19.168-4.488 37.289-12.469 53.367l0.314-0.7c-5.355 15.131-13.529 28.082-23.973 38.812l0.023-0.024c-10.303 11.076-23.433 19.388-38.244 23.796l-0.605 0.155c-17.134 5.318-37.391 9.522-58.225 11.811l-1.496 0.133c-27.967 2.257-60.545 3.543-93.423 3.543-13.393 0-26.736-0.213-40.027-0.637l1.94 0.049c-11.133 0.351-24.224 0.551-37.363 0.551-33.154 0-66.012-1.273-98.525-3.772l4.316 0.267c-2.133 0.135-4.625 0.213-7.136 0.213-19.141 0-37.233-4.488-53.282-12.47l0.696 0.313c-15.164-5.348-28.139-13.545-38.87-24.031l0.020 0.019c-11.040-10.306-19.345-23.406-23.792-38.178l-0.158-0.61c-5.279-17.103-9.481-37.358-11.805-58.18l-0.14-1.541c-2.245-28.076-3.524-60.785-3.524-93.793 0-13.263 0.207-26.478 0.617-39.642l-0.048 1.925c-0.339-11.013-0.532-23.966-0.532-36.964 0-33.272 1.266-66.248 3.753-98.883l-0.265 4.337c-0.135-2.134-0.213-4.628-0.213-7.14 0-19.16 4.488-37.272 12.471-53.342l-0.314 0.699c5.355-15.152 13.529-28.123 23.975-38.875l-0.024 0.025c10.368-11.012 23.564-19.249 38.431-23.554l0.603-0.15c17.129-5.311 37.386-9.515 58.217-11.81l1.504-0.135c27.873-2.211 60.351-3.472 93.123-3.472 13.369 0 26.689 0.21 39.956 0.626l-1.939-0.048zM513.067 190.473c-11.382-0.351-24.768-0.551-38.201-0.551-33.898 0-67.499 1.273-100.757 3.773l4.431-0.268c-28.075 0.661-54.687 6.091-79.328 15.508l1.629-0.547c-23.774 6.362-44.062 18.908-59.708 35.813l-0.075 0.082c-16.19 15.787-29.303 34.642-38.413 55.636l-0.437 1.13c-9.483 21.782-15.001 47.157-15.001 73.82 0 1.364 0.014 2.725 0.043 4.082l-0.003-0.203v137.359c-0.351 11.382-0.551 24.768-0.551 38.201 0 33.898 1.273 67.499 3.773 100.757l-0.268-4.431c0.682 28.082 6.134 54.691 15.571 79.326l-0.548-1.627c19.172 42.908 52.769 76.506 94.497 95.204l1.18 0.473c21.77 9.484 47.133 15.002 73.785 15.002 1.376 0 2.749-0.015 4.119-0.044l-0.204 0.003c28.827 2.233 62.428 3.506 96.325 3.506 13.434 0 26.821-0.2 40.158-0.597l-1.956 0.046c11.373 0.351 24.75 0.55 38.175 0.55 33.885 0 67.473-1.273 100.718-3.773l-4.428 0.267c28.075-0.66 54.686-6.091 79.327-15.508l-1.628 0.547c65.776-28.84 110.89-93.384 110.89-168.465 0-1.748-0.024-3.491-0.073-5.228l0.006 0.256c2.387-29.603 3.747-64.088 3.747-98.89 0-12.51-0.176-24.979-0.525-37.405l0.041 1.829c0.352-11.318 0.552-24.63 0.552-37.989 0-33.973-1.296-67.644-3.84-100.965l0.272 4.427c-0.839-28.135-6.436-54.721-16.009-79.32l0.555 1.62c-19.109-42.874-52.618-76.463-94.254-95.204l-1.177-0.474c-21.771-9.484-47.133-15.002-73.785-15.002-1.376 0-2.749 0.015-4.119 0.044l0.205-0.003c-36.017-2.894-47.839-2.894-134.465-2.894z","M513.067 348.765c-92.376 0.105-167.22 75.014-167.22 167.404 0 92.455 74.949 167.404 167.404 167.404s167.404-74.949 167.404-167.404c0-0.022-0-0.043-0-0.065l0 0.003c-2.024-91.681-75.886-165.457-167.41-167.34l-0.178-0.003zM513.067 623.852c-59.035-0.262-106.79-48.18-106.79-107.251 0-59.234 48.018-107.252 107.252-107.252s107.252 48.018 107.252 107.252c0 59.071-47.756 106.989-106.765 107.251l-0.025 0h-0.923z","M725.478 339.591c-0 21.456-17.394 38.85-38.85 38.85s-38.85-17.394-38.85-38.85c0-21.456 17.394-38.85 38.85-38.85 0 0 0 0 0 0l0.061 0c21.264 0.44 38.383 17.58 38.788 38.811l0.001 0.038z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-50"],"grid":0},"attrs":[{},{},{}],"properties":{"order":52,"id":78,"name":"ig","prevSize":32,"code":59698},"setIdx":0,"setId":3,"iconIdx":79},{"icon":{"paths":["M233.012 417.12h126.428v409.056h-126.428v-409.056z","M293.145 362.987c40.426-2.464 72.279-35.852 72.279-76.679s-31.853-74.216-72.063-76.669l-0.216-0.011c-40.426 2.464-72.279 35.852-72.279 76.679s31.853 74.216 72.063 76.669l0.216 0.011z","M555.48 608.863c0-57.487 25.297-92.638 75.892-92.638 47.396 0 69.553 31.977 69.553 92.638v214.379h123.288v-259.051c0-108.686-60.074-163-145.445-163-0.665-0.012-1.449-0.018-2.235-0.018-49.876 0-93.53 26.641-117.508 66.468l-0.345 0.618v-54.313h-123.288v408.996h120.088z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-51"],"grid":0},"attrs":[{},{},{}],"properties":{"order":53,"id":79,"name":"in","prevSize":32,"code":59699},"setIdx":0,"setId":3,"iconIdx":80},{"icon":{"paths":["M834.665 672.068v0c-7.227-3.613-14.453-6.504-21.68-7.949v0c-33.965-11.562-63.594-33.242-84.55-62.871-10.84-15.898-20.957-31.797-29.629-49.14v0c-2.891-7.227-2.891-14.453 0-21.68v0c7.949-9.394 18.066-15.898 29.629-18.789v0c13.73-4.336 26.016-10.84 38.301-18.789v0c2.168-2.168 4.336-5.059 5.059-7.949v-13.73c-2.168-6.504-7.227-11.562-13.73-13.73v0c-7.227-5.059-16.621-5.781-24.57-2.891v0c-7.227 2.891-14.453 5.059-21.68 5.781v0c-7.949 2.891-16.621 2.891-24.57 0v-49.14c1.445-23.848 0.723-47.695-2.891-70.82v0c-7.949-39.746-31.797-75.156-65.039-98.281-24.57-16.621-52.031-26.738-81.66-29.629h-30.351c-39.746-0.723-79.492 12.285-111.289 35.41-23.848 18.066-42.637 42.637-54.199 70.82v0c-9.394 28.183-12.285 57.812-7.949 87.441v0c1.445 18.789 1.445 38.301 0 57.090v0c-8.672 1.445-18.066 1.445-27.461 0v0c-7.227-0.723-14.453-2.891-21.68-5.781v0c-7.949-2.168-15.898-0.723-21.68 5.781v0c-6.504 2.891-10.84 9.394-10.84 16.621v2.891c0 5.059 5.781 7.949 7.949 10.84s5.781 5.781 7.949 5.781v0c13.73 7.227 28.906 13.73 43.359 18.789v0c7.949 4.336 15.176 10.84 18.789 18.789 1.445 11.562-1.445 23.125-7.949 32.519v0c-15.898 30.351-37.578 56.367-65.039 76.601-15.176 10.117-31.797 17.344-49.14 21.68v0c-6.504 1.445-13.008 5.059-16.621 10.84v2.891c-2.168 4.336-0.723 10.117 2.891 13.73 2.891 2.891 5.059 5.059 7.949 5.059v0c14.453 7.227 30.351 12.285 46.25 16.621v0c9.394 1.445 18.789 3.613 27.461 7.949 0 2.891 1.445 5.781 2.891 7.949 2.168 9.394 4.336 18.789 7.949 27.461 0 2.891 2.891 5.059 5.781 5.059 3.613 1.445 7.227 1.445 10.84 0v0c23.125-6.504 46.972-7.227 70.82-2.891v0c24.57 8.672 46.972 20.234 67.929 35.41v0c16.621 10.84 34.687 17.344 54.199 19.512h46.25c12.285-0.723 24.57-4.336 35.41-10.84v0c24.57-13.73 46.25-29.629 67.929-41.191v0c8.672-2.168 18.066-3.613 27.461-2.891v0c18.789-0.723 38.301 0.723 57.090 2.891h2.891c2.168 0 4.336-1.445 5.781-2.891 2.891-2.891 2.891-2.891 2.891-5.781v0-2.891c2.168-10.84 5.781-20.957 10.84-29.629 2.891-2.168 7.227-2.891 10.84-2.891v0c15.898-2.891 31.074-7.227 46.25-13.73v0c7.227-2.891 14.453-7.227 18.789-13.73v0c13.73-7.949 10.84-15.898 5.781-21.68v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-52"],"grid":0},"attrs":[{}],"properties":{"order":54,"id":80,"name":"sc","prevSize":32,"code":59700},"setIdx":0,"setId":3,"iconIdx":81},{"icon":{"paths":["M866.948 284.489l-4.805-5.404-7.204-0.6c-1.618-0.137-3.502-0.215-5.404-0.215-12.69 0-24.567 3.48-34.729 9.538l0.311-0.172-1.905 1.143-420.005 420.008-196.059-196.027c-7.005-6.349-16.345-10.236-26.592-10.236-10.251 0-19.594 3.889-26.634 10.273l0.033-0.030-5.976 5.376v37.084l240.28 240.287h14.118c12.45 0 16.574-2.738 26.095-11.19l447.734-446.862c7.152-6.788 11.677-16.283 11.93-26.836l0.001-0.046c0-12.453-2.738-16.574-11.19-26.092z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["lasalle-53"],"grid":0},"attrs":[{}],"properties":{"order":55,"id":81,"name":"chk","prevSize":32,"code":59701},"setIdx":0,"setId":3,"iconIdx":82}],"height":1024,"metadata":{"name":"icomoon"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"icon-","metadata":{"fontFamily":"icomoon"},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon","height":32,"columns":16,"margin":16,"autoHost":false},"historySize":50,"showCodes":true,"gridSize":16,"quickUsageToken":{}}} \ No newline at end of file diff --git a/fonts/lasalle/lasalle.svg b/fonts/lasalle/lasalle.svg new file mode 100644 index 0000000..1dccb83 --- /dev/null +++ b/fonts/lasalle/lasalle.svg @@ -0,0 +1,93 @@ + + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/lasalle/lasalle.ttf b/fonts/lasalle/lasalle.ttf new file mode 100644 index 0000000..532f01d Binary files /dev/null and b/fonts/lasalle/lasalle.ttf differ diff --git a/fonts/lasalle/lasalle.woff b/fonts/lasalle/lasalle.woff new file mode 100644 index 0000000..7c05840 Binary files /dev/null and b/fonts/lasalle/lasalle.woff differ diff --git a/imagenes/LogoRed.png b/imagenes/LogoRed.png new file mode 100644 index 0000000..e9bfaf7 Binary files /dev/null and b/imagenes/LogoRed.png differ diff --git a/imagenes/asistencia.svg b/imagenes/asistencia.svg new file mode 100644 index 0000000..28ffb03 --- /dev/null +++ b/imagenes/asistencia.svg @@ -0,0 +1,452 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imagenes/atiempo.png b/imagenes/atiempo.png new file mode 100644 index 0000000..e2e97d7 Binary files /dev/null and b/imagenes/atiempo.png differ diff --git a/imagenes/aviso.svg b/imagenes/aviso.svg new file mode 100644 index 0000000..de2999b --- /dev/null +++ b/imagenes/aviso.svg @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imagenes/duplicada.svg b/imagenes/duplicada.svg new file mode 100644 index 0000000..ee66a67 --- /dev/null +++ b/imagenes/duplicada.svg @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imagenes/error.svg b/imagenes/error.svg new file mode 100644 index 0000000..46087aa --- /dev/null +++ b/imagenes/error.svg @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imagenes/favicon.ico b/imagenes/favicon.ico new file mode 100644 index 0000000..2968479 Binary files /dev/null and b/imagenes/favicon.ico differ diff --git a/imagenes/favicon.png b/imagenes/favicon.png new file mode 100644 index 0000000..bf11576 Binary files /dev/null and b/imagenes/favicon.png differ diff --git a/imagenes/fondo.webp b/imagenes/fondo.webp new file mode 100644 index 0000000..760108f Binary files /dev/null and b/imagenes/fondo.webp differ diff --git a/imagenes/fondochecador.jpg b/imagenes/fondochecador.jpg new file mode 100644 index 0000000..68ccba0 Binary files /dev/null and b/imagenes/fondochecador.jpg differ diff --git a/imagenes/fondochecador_color.jpg b/imagenes/fondochecador_color.jpg new file mode 100644 index 0000000..62f92d5 Binary files /dev/null and b/imagenes/fondochecador_color.jpg differ diff --git a/imagenes/fondochecador_old.jpg b/imagenes/fondochecador_old.jpg new file mode 100644 index 0000000..700127d Binary files /dev/null and b/imagenes/fondochecador_old.jpg differ diff --git a/imagenes/la-salle-logo-international-ia.png b/imagenes/la-salle-logo-international-ia.png new file mode 100644 index 0000000..ca90834 Binary files /dev/null and b/imagenes/la-salle-logo-international-ia.png differ diff --git a/imagenes/la-salle-logo-red-universidades.png b/imagenes/la-salle-logo-red-universidades.png new file mode 100644 index 0000000..e9bfaf7 Binary files /dev/null and b/imagenes/la-salle-logo-red-universidades.png differ diff --git a/imagenes/lasalle-blanco.svg b/imagenes/lasalle-blanco.svg new file mode 100644 index 0000000..4f4e52b --- /dev/null +++ b/imagenes/lasalle-blanco.svg @@ -0,0 +1,114 @@ + + + diff --git a/imagenes/lasalle-logo-blanco.png b/imagenes/lasalle-logo-blanco.png new file mode 100644 index 0000000..3a1321f Binary files /dev/null and b/imagenes/lasalle-logo-blanco.png differ diff --git a/imagenes/logo.png b/imagenes/logo.png new file mode 100644 index 0000000..9a619dc Binary files /dev/null and b/imagenes/logo.png differ diff --git a/imagenes/logo_lasalle.png b/imagenes/logo_lasalle.png new file mode 100644 index 0000000..c0be9a3 Binary files /dev/null and b/imagenes/logo_lasalle.png differ diff --git a/imagenes/no_clave.svg b/imagenes/no_clave.svg new file mode 100644 index 0000000..428615f --- /dev/null +++ b/imagenes/no_clave.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imagenes/no_horario.svg b/imagenes/no_horario.svg new file mode 100644 index 0000000..dc823f6 --- /dev/null +++ b/imagenes/no_horario.svg @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ? + ? + ? + + + + \ No newline at end of file diff --git a/imagenes/no_internet.svg b/imagenes/no_internet.svg new file mode 100644 index 0000000..7b510de --- /dev/null +++ b/imagenes/no_internet.svg @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imagenes/nored.png b/imagenes/nored.png new file mode 100644 index 0000000..0960bfc Binary files /dev/null and b/imagenes/nored.png differ diff --git a/imagenes/not-found.png b/imagenes/not-found.png new file mode 100644 index 0000000..ad09273 Binary files /dev/null and b/imagenes/not-found.png differ diff --git a/imagenes/registrar.svg b/imagenes/registrar.svg new file mode 100644 index 0000000..67a55dd --- /dev/null +++ b/imagenes/registrar.svg @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/imagenes/reloj.svg b/imagenes/reloj.svg new file mode 100644 index 0000000..05c628e --- /dev/null +++ b/imagenes/reloj.svg @@ -0,0 +1,537 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/imagenes/retardo.svg b/imagenes/retardo.svg new file mode 100644 index 0000000..fa795c5 --- /dev/null +++ b/imagenes/retardo.svg @@ -0,0 +1,881 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + + + + \ No newline at end of file diff --git a/imagenes/sinregistro.png b/imagenes/sinregistro.png new file mode 100644 index 0000000..c85b671 Binary files /dev/null and b/imagenes/sinregistro.png differ diff --git a/imagenes/tarde.png b/imagenes/tarde.png new file mode 100644 index 0000000..0309883 Binary files /dev/null and b/imagenes/tarde.png differ diff --git a/import/html_css_files.php b/import/html_css_files.php new file mode 100644 index 0000000..8eb65e2 --- /dev/null +++ b/import/html_css_files.php @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/import/html_footer.php b/import/html_footer.php new file mode 100644 index 0000000..10e2c30 --- /dev/null +++ b/import/html_footer.php @@ -0,0 +1,105 @@ +
+ +
\ No newline at end of file diff --git a/import/html_forms.php b/import/html_forms.php new file mode 100644 index 0000000..c2ccc79 --- /dev/null +++ b/import/html_forms.php @@ -0,0 +1,22 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/import/html_forms_asistencia.php b/import/html_forms_asistencia.php new file mode 100644 index 0000000..06ebe3b --- /dev/null +++ b/import/html_forms_asistencia.php @@ -0,0 +1,139 @@ + + + +
+
+ + where('id', $user->periodo)->getOne('fs_periodo'); + $carreras = $db + ->where('nivel', $periodo['nivel_id']) + ->where('facultad', $user->facultad['facultad_id']) + ->orderBy('carrera') + ->get('fs_carrera'); + + ?> +
+ +
+
+
Seleccionar todas las carreras
+ +
    +
  • Seleccionar todas las carreras
  • + +
  • + +
  • + +
+ +
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
No es una fecha válida.
+
+
+
+ +
+ +
No es una fecha válida o el rango es incorrecto.
+
+
+
+
+ + +
+ +
+ + \ No newline at end of file diff --git a/import/html_forms_justificacion.php b/import/html_forms_justificacion.php new file mode 100644 index 0000000..402556c --- /dev/null +++ b/import/html_forms_justificacion.php @@ -0,0 +1,111 @@ + + + +
+
+
+ Selecciona la fecha que deseas justificar. +
+
+ +
+ +
No es una fecha válida.
+
+
+ +
+ +
+ +
+ + + +
+
No es una hora válida.
+
+ +
+ + +
+ +
+ +
+ + + +
+
No es una hora válida.
+
+
+ +
+ +
+ +
No es una clave válida.
+
+
+ + +
+ +
+ +
No es un nombre válido.
+
+
+ +
+ + + +
+ +
+ +
+ + + \ No newline at end of file diff --git a/import/html_forms_vista.php b/import/html_forms_vista.php new file mode 100644 index 0000000..bd76f1b --- /dev/null +++ b/import/html_forms_vista.php @@ -0,0 +1,163 @@ +
+ $id, ':per' => $user->periodo]); +// materia por carrera +#print_r($carreras); +$materias = queryAll("SELECT DISTINCT * FROM FS_MATERIA WHERE CARRERA = COALESCE(:car, CARRERA) AND ID IN (SELECT distinct materia_id FROM HORARIO WHERE :id IN (SELECT HORARIO_ID FROM HORARIO_PROFESOR WHERE PROFESOR_ID = :id) AND PERIODO_ID = :per) ORDER BY NOMBRE", [":car" => empty($carrera) ? null : $carrera, ':id' => $id, ':per' => $user->periodo]); +#exit(); +$periodo = query("SELECT inicio, fin FROM FS_PERIODO WHERE ID = :per", [':per' => $user->periodo]); +?> + + +
+ + + + +
+
+ +
+
+
Todas las carreras
+ +
    + +
  • Todas las carreras
  • + +
  • " onclick="carreras()"> + +
  • + +
+ +
+
+
+ +
+ +
+
+
Todas las materias
+ +
    +
  • Todas las materias
  • + +
  • "> + +
  • + +
+ +
+
+
+ + +
+ +
+ +
No es una fecha válida.
+
+
+
+ +
+ +
No es una fecha válida o el rango es incorrecto.
+
+
+
+ + +
+ + +
+
+ + \ No newline at end of file diff --git a/import/html_header.php b/import/html_header.php new file mode 100644 index 0000000..8e0c24e --- /dev/null +++ b/import/html_header.php @@ -0,0 +1,139 @@ + + + +admin) { + $grupos = queryAll("SELECT * FROM GRUPO ORDER BY grupo_nombre"); + $paginas = queryAll("SELECT * FROM pagina ORDER BY pagina_ruta"); +} else { + $paginas = queryAll("SELECT * FROM PERMISO_VIEW WHERE id = :id ORDER BY pagina_ruta", array(":id" => $user->user['id'])); + $grupos = $db->query("SELECT * FROM GRUPO WHERE grupo_id IN (SELECT grupo_id FROM PERMISO_VIEW WHERE id = :id) ORDER BY grupo_nombre", array(":id" => $user->user['id'])); +} + +function html_header($title, $header = null) +{ + global $grupos, $paginas, $user; + ?> + +
+
+ +
+ +
+
+ +

+ +

+
+
+ diff --git a/import/html_header_index.php b/import/html_header_index.php new file mode 100644 index 0000000..1c0cbe5 --- /dev/null +++ b/import/html_header_index.php @@ -0,0 +1,34 @@ + + + +
+ +
+
+

+

+
+ +
+
+

+
+
+
+ + + + + + \ No newline at end of file diff --git a/import/html_scroll.php b/import/html_scroll.php new file mode 100644 index 0000000..c4721e5 --- /dev/null +++ b/import/html_scroll.php @@ -0,0 +1,42 @@ + + + + + + + \ No newline at end of file diff --git a/import/periodo.php b/import/periodo.php new file mode 100644 index 0000000..b2354a6 --- /dev/null +++ b/import/periodo.php @@ -0,0 +1,64 @@ + + +
+
+
+ array_merge( + $nivel, + ['periodos' => $db->where('nivel_id', $nivel['nivel_id'])->get('periodo_view')] + ), $db->get("nivel") + ); + + // collect facultad_id's with facultad from $periodos + ?> + +
+
+ +
+
+
Selecciona un periodo
+ +
    + +
  • + +
  • + query( + 'SELECT * FROM fs_periodo(NULL, :nivel, 4)', + [':nivel' => $nivel['nivel_id']] + ); + foreach ($periodos_rs as $per) { + ?> +
  • periodo == $per["periodo_id"]) { + echo 'class="selected"'; + } ?>> + +
  • + + +
+ +
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/include/.env b/include/.env new file mode 100644 index 0000000..d5d2c3a --- /dev/null +++ b/include/.env @@ -0,0 +1,6 @@ +DB_HOST=20.225.68.55 +DB_USER=postgres +DB_PASS=4ud1t0rf4lt4$ +DB_NAME=paad + +CHECADOR=https://checadores.lci.ulsa.mx/action_checador.php \ No newline at end of file diff --git a/include/bd_pdo.php b/include/bd_pdo.php new file mode 100644 index 0000000..032ed89 --- /dev/null +++ b/include/bd_pdo.php @@ -0,0 +1,63 @@ +load(); +use \SeinopSys\PostgresDb; + +# Connect to the database +try { + // Postgres + $pdo = new PDO("pgsql:host=" . $_ENV['DB_HOST'] . ";dbname=" . $_ENV['DB_NAME'], $_ENV['DB_USER'], $_ENV['DB_PASS']); + $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + + $db = new PostgresDb(); + $db->setConnection($pdo); +} catch (PDOException $e) { + echo "Error: " . $e->getMessage(); +} + +// check recursivelly if the array has only empty strings +function is_response_empty($array) +{ + foreach ($array as $value) { + if (is_array($value)) { + if (!is_response_empty($value)) { + return false; + } + } else { + if (!empty($value)) { + return false; + } + } + } + return true; +} + +// SQL function +function query(string $sql, array $params = null, bool $single = true) +{ + global $pdo; + try { + $stmt = $pdo->prepare($sql); + $stmt->execute($params); + $response = $single ? $stmt->fetch(PDO::FETCH_ASSOC) : $stmt->fetchAll(PDO::FETCH_ASSOC); + + return $response; + } catch (PDOException $e) { + echo "Error: " . $e->getMessage(); + return false; + } finally { + $stmt->closeCursor(); + $stmt = null; + } +} + +function queryAll(string $sql, array $params = null) +{ + return query($sql, $params, false); +} + +function toSQLArray(array $array): string +{ + return sprintf("{%s}", implode(", ", $array)); +} diff --git a/include/constantes.php b/include/constantes.php new file mode 100644 index 0000000..81a554e --- /dev/null +++ b/include/constantes.php @@ -0,0 +1,146 @@ +'', + "menos"=>'', + "editar"=>'', + "borrar"=>'', + "borrar2"=>'', + "cancelar"=>'', + "buscar"=>'', + "descargar"=>'', + "cargar"=>'', + "ver"=>'', + "cambiar"=>'', + "circulo"=>'', + "aceptar"=>'', + "alerta"=>'', + "calendario"=>'', + "ojo"=>'', + "profesor"=>'', + + "lista"=>'', + "lista_check"=>'', + "abajo"=>'', + "arriba"=>'', + "izquierda"=>'', + "derecha"=>'', +]; +$ICO_LG =[ + "mas"=>'', + "menos"=>'', + "editar"=>'', + "borrar"=>'', + "borrar2"=>'', + "cancelar"=>'', + "buscar"=>'', + "descargar"=>'', + "cargar"=>'', + "ver"=>'', + "cambiar"=>'', + "circulo"=>'', + "aceptar"=>'', + "alerta"=>'', + "calendario"=>'', + "ojo"=>'', + "profesor"=>'', + + "lista"=>'', + "lista_check"=>'', + "abajo"=>'', + "arriba"=>'', + + /* + "insert"=>'', + "update"=>'', + "delete"=>'', + "search"=>'', + "insert_box"=>'', + "update_box"=>'', + "delete_box"=>'', + "error"=>'', + "error_circle"=>'', + "ok"=>'', + "ok_circle"=>'', + "list"=>'', + "circulo"=>'', + "question_circle"=>'', + "info_circle"=>'', + "square_check"=>'', + "square_empty"=>'', + "eraser"=>'',*/ +]; + +$ICO_RND =[ + "right"=>' + + + ', + "left"=>' + + + ', + "error"=>' + + + ', + "error_circle"=>' + + + ', + "ok_circle"=>' + + + ', + "ok"=>' + + + ', + "close"=>' + + + ', + "next"=>' + + + ', + "back"=>' + + + ', +]; + +//Sistemas registrados +define("APSA", 1); +define("GEMA", 2); +define("CIDIT", 3); +define("CONSTANCIA", 5); +define("EXPOING", 7); + +define("MAX_ROWS", 30); + +define("HORA_INICIO", 6);//hora inicial de horario +define("HORA_FINAL", 22);//hora final de horario +define("FRACCION_HORA", 4);//fracciones en una hora + +define("DURACION_MIN", 60);//hora inicial de horario +define("DURACION_MAX", 360);//hora final de horario +define("DURACION_STEP", 15);//fracciones en una hora + +define("FACULTAD", "Facultad de Ingeniería"); +//define("NOMBRE_DIRECTOR", "Ing. Edmundo G. Barrera Monsiváis"); + +define("PE_INI", "PE_INI$"); +define("PE_INI_Y", "PE_INI_Y$"); +define("PE_FIN", "PE_FIN$"); +define("PE_FIN_Y", "PE_FIN_Y$"); + +define("PR_INI", "PR_INI$"); +define("PR_INI_Y", "PR_INI_Y$"); +define("PR_FIN", "PR_FIN$"); +define("PR_FIN_Y", "PR_FIN_Y$"); + +define("EX_INI", "EX_INI$"); +define("EX_INI_Y", "EX_INI_Y$"); +define("EX_FIN", "EX_FIN$"); +define("EX_FIN_Y", "EX_FIN_Y$"); +?> \ No newline at end of file diff --git a/include/fun_fecha.php b/include/fun_fecha.php new file mode 100644 index 0000000..baa85b3 --- /dev/null +++ b/include/fun_fecha.php @@ -0,0 +1,55 @@ +"enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"); + return $meses[intval($num)]; +} + +function diaNombre($num){ + $dias=array("domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"); + return $dias[intval($num)]; +} diff --git a/include/func_excel.php b/include/func_excel.php new file mode 100644 index 0000000..623510e --- /dev/null +++ b/include/func_excel.php @@ -0,0 +1,165 @@ + 1) { + $nombre .= $temp_nombre[1] . " "; + $grado = $temp_nombre[0] . "."; + array_shift($datos_nombre); + } else + $grado = strpos($datos_nombre[0], ".") !== false ? array_shift($datos_nombre) : null; + + $email = strpos($columna, "@") !== false ? array_pop($datos_nombre) : null; + $nombre .= implode(" ", $datos_nombre); + + return array( + "grado" => $grado, + "nombre" => trim($nombre), + "correo" => $email, + ); +} +### +function validar_columnas(object $sheet): void +{ + global $columnas; + $diff = array_diff(array_map(fn ($col) => trim($col), get_columns($sheet)), $columnas); + #array clean + if (!empty($diff)) { + $diff = array_filter($diff, fn ($col) => !empty($col)); + throw new Exception("Error en el formato del archivo: " . (empty($diff) ? "Columnas vacías" : "Columnas incorrectas: [" . implode(", ", $diff) . "]")); + } +} +### +function get_columns(object $sheet) +{ + global $columnas; + $columns = array(); + foreach ($sheet->getRowIterator(1, 1) as $row) + foreach ($row->getCellIterator() as $index => $cell) { + $columns[$index] = mb_strtoupper($cell->getValue() ?? ""); + if ($index == COLUMNA_MAXIMA) break; + } + return $columns; +} +### +function foreach_sheet(object $workbook, callable $callback = null): void +{ + + $sheets = $workbook->getSheetNames(); + // validate columns + foreach ($sheets as $sheet) { + $worksheet = $workbook->getSheetByName($sheet); + validar_columnas($worksheet); + foreach_register($worksheet, $callback, $sheet); + } +} +### +function foreach_register(object $worksheet, callable $callback = null, string $sheet): void +{ + foreach ($worksheet->getRowIterator(2) as $key => $row) { + $row_data = array(); + foreach ($row->getCellIterator() as $index => $cell) { + $row_data[] = str_replace(' ', '', $cell->getValue() ?? ""); + if ($index == COLUMNA_MAXIMA) break; + } + + if ($callback !== null) { + $callback($row_data, $key, $sheet); + } + } +} + +function horario(array &$row, int $fila, string $sheet): string +{ + global $cl, $db; + date_default_timezone_set('UTC'); + $horario_tostring = ""; + for ($i = HORARIO; $i < count($row) - 1; $i++) { + // echo $row[$i] . " $i\n"; + if (!empty(trim($row[$i] ?? ""))) { + $row[$i] = str_replace(array(" -", "- ", " - "), "-", $row[$i]); + $separar_por_espacios = EXPLODE(" ", trim(preg_replace('!\s+!', ' ', $row[$i]))); + foreach ($separar_por_espacios as $horario) { + $hora = // if string includes : then is string else is excel date + (strpos($horario, ":") === false) + ? \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($horario)->format('H:i') + : preg_replace('/[^0-9:]/', '', str_replace('.', ':', trim((strpos($horario, "-") !== false) ? explode("-", $horario)[0] : $horario))); + + if ( + $hora > "22:00" || $hora < "07:00" || explode(":", $hora)[1] % 15 !== 0 + ) { + throw new Exception("Error en el formato del archivo: Hora incorrecta [$hora] en la fila $fila, hoja $sheet."); + } + + $duración = end($row); + if ($duración <= 180 and $duración >= 30 and $duración % 15 == 0) + $bloques = $duración / 15; + else if ($duración <= 3 and $duración >= 0.5) + $bloques = $duración * 60 / 15; + else + throw new Exception("Error en el formato del archivo: Duración [$duración] incorrecta en la fila $fila, hoja $sheet."); + + $duraciónID = $db->where("duracion_bloques", $bloques)->get("duracion", 1, "duracion_id")[0]["duracion_id"]; + $horario_tostring .= ($i - 4) . ",$hora,$duraciónID;"; + } + } + } + + $row = array_combine($cl, array_intersect_key($row, array_keys($cl))); + $horario_tostring = substr($horario_tostring, 0, -1); + if (empty($horario_tostring)) + throw new Exception("Error en el formato del archivo: No se encontró horario en la fila $fila, hoja $sheet."); + + return $horario_tostring; +} + +function validar_registro(array $row, int $fila): void +{ + $tiene_horario = false; + for ($i = 0; $i < HORARIO - 1; $i++) + if (empty(trim($row[$i]))) + throw new Exception("Error faltan datos en la fila $fila de la hoja"); + + for ($i = HORARIO; $i < COLUMNA_MAXIMA; $i++) + if ($tiene_horario = !empty($row[$i])) + break; + + if (!$tiene_horario) + throw new Exception("Error en el formato del archivo: No se encontró horario en la fila $fila."); +} + + +function renglón_vacío(array $row) +{ + foreach ($row as $columna) + if (!empty($columna)) + return false; + + return true; +} diff --git a/include/func_string.php b/include/func_string.php new file mode 100644 index 0000000..7510b72 --- /dev/null +++ b/include/func_string.php @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/include/nusoap/changelog b/include/nusoap/changelog new file mode 100644 index 0000000..a9daba7 --- /dev/null +++ b/include/nusoap/changelog @@ -0,0 +1,648 @@ +2003-07-21, version 0.6.5 +- soap_transport_http: SOAPAction header is quoted again, fixes problem w/ Weblogic Server +- applied Jason Levitt patch for proper array serialization, fixes problem w/ Amazon shopping cart services +- fixed null value serialization +- applied patch from "BZC ToOn'S" - fixes wsdl serialization when no parameters +- applied John's patch, implementing compression for the server + +2003-07-22, version 0.6.5 +- soap_server: fixed bug causing charset encoding not to be passed to the parser +- soap_fault: added default encoding to the fault serialization +- soap_parser: changed the parser to pre-load the parent's result array when processing scalar values. This increases parsing speed. + +2003-07-23, version 0.6.5 +- soap_base: fix code that overwrites user-supplied attributes in serialize_val +- soap_base: use arrays-of-arrays rather than attempting multi-dimensional in serialize_val +- xmlschema: emit import statements and qualify all elements with prefix in serializeSchema (better interop with validation tools) +- soapclient: get xml character encoding from HTTP Content-Type header if provided, e.g. text/xml;charset="UTF-8" +- soapclient: use headers in call if provided (previously ignored this parameter) +- soap_server: in parse_request, if neither getallheaders nor $_SERVER are available, use $HTTP_SERVER_VARS to get SOAPAction and xml encoding + +2003-07-24, version 0.6.5 +- soap_transport_http: apply patch from Steven Brown "if the server closes connection prematurely, nusoap would spin trying to read data that isn't there" + +2003-07-25, version 0.6.5 +- wsdl: apply patch from Sven to workaround single schema limitation +- wsdl: apply a variant of the patch from Holger to handle empty values for array by serializing an array with 0 elements +- xmlschema: remove the redundant default namespace attribute on the schema element; everything in xsd is explicitly specified as being from xsd +- soap_transport_http: fix setCredentials and add TODO comments in sendHTTPS about what to change if this setCredentials stays + +2003-07-30, version 0.6.5 +- nusoap_base: change documentation of soap_defencoding to specify it is the encoding for outgoing messages +- nusoap_base: only change &, <, > to entities, not all HTML entities +- soap_transport_http: update the Content-Type header in sendRequest, since soap_defencoding could be changed after ctor is called +- soap_server: use soap_defencoding instead of charset_encoding +- soap_server: read encoding from _SERVER if available +- nusoap_base: do entity translation for string parameters with an xsd type specified (thanks David Derr) + +2003-07-31, version 0.6.5 +- soap_transport_http: add proxy authentication +- soap_transport_http: build payload the same way for http and https +- wsdl: add proxy authentication +- soapclient: add proxy authentication +- soapclient: allow proxy information in ctor, so that it can be used for wsdl + +2003-08-01, version 0.6.5 +- soap_transport_http: close a persistent connection that's at EOF +- soap_transport_http: prevent conflicts between setEncoding and usePersistentConnection +- soap_transport_http: fix use of $headers instead of $this->incoming_headers in getResponse +- soapclient: improve handling of persistent connections +- soapclient: force xml_encoding to upper case +- soap_server: let the Web server decide whether to close the connection (no Connection: close header) +- soap_server: force xml_encoding to upper case + +2003-08-04, version 0.6.5 +- soap_parser: use XML type information to pick a PHP data type; also decode base64 +- soap_server: read all HTTP headers when using _SERVER or HTTP_SERVER_VARS +- soap_server: add gzip encoding support for outgoing messages +- soap_transport_http: deflate is gzcompress/gzuncompress (cf. http://archive.develooper.com/libwww@perl.org/msg04650.html) +- soap_transport_http: clean use of persistentConnection so it's always a set boolean +- soapclient: add responseData member to access deflated/gunzipped payload + +2003-08-05, version 0.6.5 +- soap_server: look multiple places when setting debug_flag + +2003-08-07, version 0.6.5 +- nusoap_base: serialize specified type (e.g. ArrayOfString) even for simple array +- wsdl: only specify encodingStyle in the input/output soap bindings when it is not empty (thanks Guillaume) + +2003-08-15, version 0.6.5 +- soap_parser: fix parsing of elements with no XSD type specified +- soap_parser: use PHP string type for XSD long and unsignedLong types + +2003-08-16, version 0.6.5 +- soap_parser: fix code generating warning (thanks Torsten) + +2003-08-19, version 0.6.5 +- soap_parser: fix another line of code generating a warning (thanks Torsten) + +2003-08-22, version 0.6.5 +- soap_server: remove all '--' from debug_str; previous code changed '---' to '- --' +- wsdl, soapclient, soap_parser: patch submitted by Mark Spavin as described by + the following... +> Changes for the multiple/nested imports from the wsdl file. This builds an +> array of files not just the last one and also checks for relative paths to +> the parent. This will then get the imported files from the remote site +> instead of your local disk. Local wsdl files should still work (untested). +> +> Changes for multiple encoding sytles as previously posted + +2003-08-24, version 0.6.5 +- wsdl, soapclient: fix some PHP notices from previous update + +2003-08-26, version 0.6.5 +- wsdl: support multiple SOAP ports +- soapclient, soap_server: when no charset is specified, use UTF-8, even though HTTP specifies US-ASCII. +- soap_transport_http: do not prepend $host with 'ssl://' for https (is this required for older cURL versions?) + +2003-08-27, version 0.6.5 +- soap_server: support compressed request messages (thanks John Huong) +- soap_parser: deserialize Apache Vector as an array +- xmlschema: use $this->typemap in getPHPType (which is not used) +- soapclient, wsdl: check for WSDL errors after serializing parameters +- nusoap_base: add serialization of Apache Map (when not using WSDL) +- wsdl: add serialization of Apache Map (when using WSDL) +- wsdl: only change &, <, > to entities, not all HTML entities + +2003-08-28, version 0.6.5 +- soap_transport_http: disable cURL verification of peer and server (formerly the cURL default) +- soap_transport_http: mingle cURL code with straight http, so sendHTTP is no longer needed + +2003-08-29, version 0.6.6 +- soap_transport_http: add setContentType +- soapclient: call setContentType using new getHTTPContentType and getHTTPContentTypeCharset + +2003-09-05, version 0.6.6 +- wsdl: add some more code to handle null/nil values (but there's still a way to go) + +2003-10-21, version 0.6.6 +- soap_transport_http: only include port in Host header if it was specified in the URL +- soap_transport_http: add some code to use OpenSSL for PHP ssl:// scheme, but comment out since it's not ready +- soap_server: use $_SERVER['PHP_SELF'] if $GLOBALS['PHP_SELF'] is not set +- wsdl: add WSDL request and response and transport debug to debug +- wsdl: handle custom type extending xmlschema namespace (GLUE ... Thanks Matt) +- soap_parser: add param to docs +- soapclient: add getHTTPBody, getHTTPContentType, getHTTPContentTypeCharset (anticipating MIME subclass) + +2003-10-28, version 0.6.6 +- nusoap_base: add expandEntities method +- wsdl: use expandEntities +- soap_fault: use expandEntities +- soap_transport_http: Allow credentials to be included in URL, rather than requiring setCredentials +- soap_transport_http: Merge HTTP headers that span multiple lines +- soap_parser: Properly set errors in ctor +- soapclient: Pass headers to parseResponse and parse them in that method + +2003-10-30, version 0.6.6 +- xmlschema: Add some information for the related type to an element + +2003-12-09, version 0.6.6 +- nusoap_base: Add some namespace methods previously in xmlschema +- xmlschema: Improve parsing of complexType, element and simpleType +- xmlschema: Improve serialization +- xmlschema: Track imports +- xmlschema: Track elementFormDefault and form attributes +- wsdl: Support multiple (note that setting $server->wsdl->schemaTargetNamespace no longer does anything! Use configureWSDL instead.) +- wsdl: Use form attribute of element to control namespace specification +- wsdl: Support chained imports (A imports B which imports C) +- wsdl: Include port in endpoint address when serializing +- soap_server: Fix use of style (rpc|document) and use (encoded|literal) +- soap_server: Support _SERVER[CONTENT_TYPE] in addition to _SERVER[HTTP_CONTENT_TYPE] +- soap_server: Support wsdl with multiple +- soap_client: Remove a var_dump +- soap_client: Add style and use parameters to call method to support doc/lit without WSDL +- soap_transport_http: Check that $this->fp exists when doing persistent connections + +2003-12-17, version 0.6.6 +- soap_server: pass namespaces to xmlschema constructor +- wsdl: post-process after all imports +- wsdl: remove some debug, add some error handling +- xmlschema: allow enclosing namespaces to be specified in constructor +- xmlschema: improve handling of compositors and simple types + +2004-01-08, version 0.6.6 +- soap_server: when requested WSDL is in a file, return to client using passthru (thanks Ingo Fischer) +- soapclient: have proxy inherit more client state +- soapclient: allow timeout and response timeout to be specified in the constructor +- wsdl: allow timeout and response timeout to be specified in the constructor +- soap_transport_http: allow response timeout to be specified in send and sendHTTPS + +2004-01-28, version 0.6.6 +- wsdl: add namespace for array and scalar when form is qualified +- wsdl: fix a bug in which data type of complexType elements were ignored in serialization +- wsdl: enhance handling of URLs with file scheme +- wsdl: add addSimpleType +- xmlschema: add addSimpleType +- xmlschema: always set phpType elements +- soapclient: allow a wsdl instance to be specified in constructor +- soap_server: allow a wsdl instance to be specified in constructor (not tested!) +- soap_server: fix default SOAPAction created in register method +- soap_transport_http: accept chunking with LF separators in addition to CRLF. +- wsdlcache: added class +- nusoapmime: fix comments + +2004-02-23, version 0.6.6 +- soap_transport_http: don't try to unchunk cURL data, since cURL already does it +- soap_transport_http: append CVS revision to version in User-Agent +- wsdl: serialize boolean as true|false, not 1|0, to agree with XML Schema +- soap_server: always exit() after returning WSDL +- soap_server: use the WSDL URL scheme as the default endpoint URL scheme +- soap_server: append CVS revision to version in X-SOAP-Server +- nusoap_base: add (CVS) revision +- wsdlcache: synchronize using a per-WSDL lock file (Thanks Ingo) +- wsdlcache: add cache lifetime, after which cache contents are invalidated (Thanks Ingo) + +2004-03-15, version 0.6.6 +- nusoap_base: add isArraySimpleOrStruct method +- soap_server: improve WSDL URL scheme determination +- soap_server: only deflate/gzip payloads > 1024 bytes +- soap_server: fix parameter order in fault method (always used as faultcode, faultstring) +- soap_server: refactor parse_request into multiple functions (for sanity) +- soap_server: set the namespace on the Response element to the same as the request +- soap_server: name the return value element 'return' by default +- soap_server: added and documented data fields, so that service programmers can use them if desired +- soap_parser: standardize parsing error message +- soap_parser: fix document and responseHeaders so they are the correct XML text (as documented) +- soap_transport_http: fix read from persistent connection +- soapclient: clean up debugging for persistent connection +- wsdl: enforce correct naming of messages parts when an associative array is used for parameters +- wsdl: better serialization of null values +- wsdl: standardize parsing error message +- xmlschema: standardize parsing error message + +2004-03-24, version 0.6.7 +- soap_transport_http: add digest authentication (based on code by Kevin A. Miller) +- xmlschema: improve parsing of import elements +- wsdl: do schema imports even if there are no wsdl imports + +2004-04-12, version 0.6.7 +- wsdl: serialize multiple elements when maxOccurs="unbounded" and value is an array +- wsdl: serialize soapval values (used to force an XML type, e.g. when WSDL uses an abstract type) +- nusoapmime: do not require nusoap.php (it is now the programmer's responsibility) + +2004-04-21, version 0.6.7 +- soap_parser: parse repeated element name into an array (de-serializes doc/lit array into a PHP array when there is more than 1 array element) +- soap_server: do not wrap response in a response element for a document style service + +2004-04-30, version 0.6.7 +- soap_transport_http: allow digest auth params to be separated by "," as well as ", " +- soap_transport_http: re-initialize incoming headers for each response +- soap_server: add methodreturnisliteralxml property to allow service function to return XML as a string +- soapclient: improve rpc/literal support +- soapclient: allow XML string as call params in addition to array +- soapclient: support document style and literal encoding when not using WSDL + +2004-05-05, version 0.6.7 +- wsdl: serialize PHP objects for WSDL XML Schema complexTypes, in addition to associative arrays +- wsdl: fix WSDL generation when there is no encodingStyle +- soap_transport_http: suppress fsockopen warnings +- soap_transport_http: detect socket timeouts when reading (0 bytes returned) +- soap_transport_http: read chunked content "in-line" so it works on a persistent connection +- nusoap_base: serialize boolean as true|false, not 1|0, to agree with XML Schema +- nusoap_base: serialize array of struct differently than array of array + +2004-06-25, version 0.6.8 +- soap_server: prefer gzip to deflate, since IE does not like our deflate +- soap_server: move webDescription to the wsdl class +- soap_server: allow class and instance method calls for service (thanks Ingo Fischer and Roland Knall) +- wsdl: get webDescription from the soap_server class +- wsdl: allow compression from the server +- wsdl: fix serialization of soapval without a type +- wsdl: propagate debug value from query string to SOAP endpoint in programmatic WSDL generation +- nusoap_base: add anyType, anySimpleType for 2001 XML Schema +- nusoap_base: provide additional debug functions +- soap_transport_http: ignore Content-Length when chunked encoding is used +- soap_transport_http: remove ':' from username for Basic authentication (cf. RFC 2617) +- soap_transport_http: urldecode username and password taken from URL +- soap_transport_http: use raw inflate/deflate for IE/IIS compatibility, rather than having Zlib headers according to HTTP 1.1 spec +- soap_transport_http: attempt to handle the case when both the service application and Web server compress the response +- soapclient: when creating proxy methods, replace '.' in operation name with '__' in function name +- soapclient: initialize requestHeaders in proxy +- general: use new debug methods; never access debug_str directly + +2004-09-30, version 0.6.8 +- soapclient: do not allow getProxy call when WSDL is not used +- soapclient: use ISO-8859-1 as the charset if not specified in the Content-Type header +- soapclient: when an empty string is specified for the call namespace, do not put the method element in a namespace +- soapclient: let soap_transport_http check for SSL support +- soapclient: have proxy inherit soap_defencoding from the client from which it is generated +- soapclient: do not assume that 'ns1' is an unused namespace prefix; always generate namespace prefixes randomly +- soap_parser: compare any encoding in the XML declaration to the charset from the HTTP Content-Type header (thanks Ingo Fischer) +- soap_parser: improve parse repeated element name into an array (de-serializes doc/lit array into a PHP array when there is more than 1 array element) +- soap_server: use ISO-8859-1 as the charset if not specified in the Content-Type header +- soap_server: allow suppression of automatic UTF-8 decoding +- soap_server: fix a bug when call_user_func_array() is used +- soap_transport_http: correct digest authentication through a proxy +- wsdl: serialize SOAP-ENC types similarly to XSD types +- xmlschema: force unprefixed type into default namespace +- xmlschema: fix serialization of definition of simple types + +2004-10-01, version 0.6.8 +- soap_parser: handle default namespace attributes +- soap_server: add default_utf8 field +- soap_server: support literal encoding (with RPC style) +- soap_transport_http: parse HTTP status and generate error for 300, 302-307, 400, 401-417, 501-505 (thanks for the idea Ghislain) +- soap_transport_http: follow HTTP redirection (HTTP status 301 and Location header) (thanks for the idea Ghislain) +- xmlschema: allow any attributes to be specified in an element of a complexType, e.g., abstract, default, form, minOccurs, maxOccurs, nillable (thanks Jirka Pech for the original patch) + +2004-10-02, version 0.6.8 +- soapclient: read/write cookies (thanks Ingo) +- soap_server: change faultcode on non-resendable faults to Client +- soap_transport_http: read/write cookies (thanks Ingo) + +2004-10-05, version 0.6.8 +- wsdl: add addElement method +- wsdl: support the document style in the register method +- xmlschema: parse unnamed simpleTypes, rather than ignoring them +- xmlschema: include untyped elements when parsing a complexType +- xmlschema: add addElement method + +2004-10-14, version 0.6.8 +- soapclient: support client certificates +- soap_parser: deserialize attributes, prefixing names with "!" +- soap_server: notify the client with HTML when WSDL is requested but not supported by service +- soap_transport_http: support client certificates +- wsdl: support defaults for elements of a complexType +- wsdl: serialize elements from complexType extension base +- wsdl: serialize data (associative array elements) as attributes according to XML Schema +- xmlschema: record extension base if present for a complexType + +2004-12-15, version 0.6.8 +- nusoap_base: add 2000 XML Schema (rare, but used by Akamai) +- soap_parser: avoid deserializing more common attributes that are not data +- soap_parser: be lax when HTTP specifies ISO-8859-1 (the default) and XML specifies UTF-8 (the norm) +- soap_server: account for the fact that get_class_methods returns methods in all lower case (thanks Steve Haldane) +- soap_transport_http: parse digest info that includes '=' in the data (thanks Jinsuk Kim) +- wsdl: feably handle some cases for literal serialization of form="unqualified" elements +- wsdl: don't serialize the decimal portion of a PHP double when the XML type is long +- wsdl: fix serialization of attributes for complexType that is an extension +- wsdlcache: enhance diagnostics +- xmlschema: handle untyped elements +- xmlschema: handle WSDL for SOAP Array that uses the base attribute plus a sequence of element + +2005-01-22, version 0.6.8 +- wsdl: allow an element in one schema to have a type from another schema + +2005-01-24, version 0.6.8 +- xmlschema: correctly parse nested complexType definitions + +2005-02-14, version 0.6.8 +- nusoap_base: fix a bug in which attributes were sometimes not serialized with a value +- nusoap_base: improve serialization of null values (thanks Dominique Stender) +- soap_parser: parse null values by handling the nil attribute (thanks Dominique Stender) +- soap_server: set character encoding for a fault to be the same as for the server (thanks Mark Scott) +- soap_server: correctly check for null value returned from method when WSDL is used (without WSDL, cannot distinguish whether NULL or void return is desired) +- soapclient: for document style, call should always return an array rooted at the response part (all bets are off when there are multiple parts) +- xmlschema: save enumeration values parsed from WSDL + +2005-02-10, version 0.6.9 +- soapclient: only set SOAP headers when they are specified in call params (so setHeaders still works) + +2005-04-04, version 0.6.9 +- soap_server: use get_class instead of is_a (thanks Thomas Noel) +- soapclient: use get_class instead of is_a (thanks Thomas Noel) +- soapclient: add setEndpoint method +- soap_transport_http: fix client certificates (thanks Doug Anarino and Eryan Eriobowo) + +2005-04-29, version 0.6.9 +- nusoap_base: add global variable and methods for setting debug level +- nusoap_base: use xsd:anyType instead of xsd:ur-type to serialize arrays with multiple element types (thanks Ingo Fischer) +- nusoap_base: expand entities in attributes (thanks Gaetano Giunta) +- soapclient: call parent constructor +- soapval: call parent constructor +- soap_fault: call parent constructor +- soap_parser: call parent constructor +- soap_server: assume get_class_methods always returns lower case for PHP 4.x only +- soap_server: call parent constructor +- soap_transport_http: do nothing in setEncoding if gzdeflate is not present (thanks Franck Touanen for pointing this out) +- soap_transport_http: fix check for server request for digest authentication (thanks Mark Spavin) +- soap_transport_http: call parent constructor +- wsdl: fix documentation page popup of one method after another (thanks Owen) +- wsdl: call parent constructor +- wsdl: expand entities in attributes (thanks Gaetano Giunta) +- xmlschema: call parent constructor + +2005-06-03, version 0.6.9 +- nusoap_base: serialize empty arrays as having elements xsd:anyType[0] +- nusoap_base: add encodingStyle parameter to serializeEnvelope +- nusoap_base: serialize xsi:type with nil values +- nusoap_base: improve debug and comments +- soap_parser: correctly parse an empty array to an empty array, not an empty string +- soap_parser: improve debug and comments +- soap_server: specify encodingStyle for envelope when WSDL is used +- soapclient: factor out new getProxyClassCode method +- soapclient: specify encodingStyle for envelope +- soapclient: improve debug and comments +- wsdl: add namespace for Apache SOAP types if a variable of such type is serialized +- wsdl: serialize nil value for nillable elements when no value is provided +- wsdl: serialize xsi:type with nil values +- wsdl: copy attributes as well as elements to an element from its complexType +- wsdl: specify encodingStyle for operations +- wsdl: improve debug and comments +- xmlschema: improve debug and comments + +2005-06-03, version 0.7.0 +- nusoap_base: improve debug and comments +- nusoap_base: fix version, which should have been 0.7.0 since 2005-03-04 + +2005-06-06, version 0.7.1 +- nusoap_base: adjust numeric element names for serialization, instead of forcing them to 'soapVal' +- nusoapmime: add type=text/xml to multipart/related (thanks Emmanuel Cordonnier) +- soap_fault: fix serialization of detail +- soap_server: check required parameters for register method +- soap_server: when getallheaders is used, massage header names +- soap_server: use SOAPAction to determine operation when doc/lit service does not wrap parameters in an element with the method name (thanks Peter Hrastnik) +- soap_transport_http: correctly handle multiple HTTP/1.1 100 responses for https (thanks Jan Slabon) +- wsdl: fixed documentation for addComplexType (thanks Csintalan dm) +- wsdl: serialize array data when maxOccurs = 'unbounded' OR maxOccurs > 1 (thanks Dominique Schreckling) +- wsdl: when serializing a string == 'false' as a boolean, set the value to false +- wsdl: when serializing a complexType, require the PHP value supplied to be an array + +2005-07-01, version 0.7.1 +- nusoap_base: Allow SOAP headers to be supplied as an array like parameters +- soap_parser: de-serialize simpleContent that accompanies complexContent +- soap_server: append debug information when programmatically-defined WSDL is returned +- soap_transport_http: Add debug when an outgoing header is set +- soapclient: Allow SOAP headers to be supplied as an array like parameters +- xmlschema: serialize attributes more generally, rather than assuming they are for SOAP 1.1 Array +- wsdl: when serializing, look up types by namespace, not prefix (simple programmatic doc/lit WSDL now seems to work) +- wsdl: process namespace declarations first when parsing an element + +2005-07-27, version 0.7.1 +- nusoap_base: do not override supplied element name with class name when serializing an object in serialize_val +- nusoap_base: remove http://soapinterop.org/xsd (si) from namespaces array +- nusoapmime: add nusoapservermime class to implement MIME attachments on the server +- soap_fault: improve documentation +- soap_server: improve documentation +- soap_server: make consistent use of _SERVER and HTTP_SERVER_VARS +- soap_server: make all incoming HTTP header keys lower case +- soap_server: add hook functions to support subclassing for MIME attachments +- soap_transport_http: remove an unnecessary global statement +- soapclient: when creating a proxy, make $params within each function an associative array +- soapval: improve documentation +- wsdl: when serializing complexType elements, used typed serialization if there is either a type or a reference for the element +- wsdl: allow PHP objects to be serialized as SOAP structs in serializeType +- wsdl: for WSDL and XML Schema imports, don't forget to use the TCP port number (thanks Luca GIOPPO) +- wsdl: make consistent use of _SERVER and HTTP_SERVER_VARS +- xmlschema: improve documentation + +2005-07-31, version 0.7.2 +- nusoap_base: correctly serialize attributes in serialize_val (thanks Hidran Arias) +- soap_parser: when resolving references, do not assume that buildVal returns an array (thanks Akshell) +- soap_parser: removed decode_entities, which does not work (thanks Martin Sarsale) +- soap_server: fix a bug parsing headers from _SERVER and HTTP_SERVER_VARS (thanks Bert Catsburg) +- soap_server: parse all "headers" from HTTP_SERVER_VARS (not just HTTP_*) +- soap_server: use PHP_SELF instead of SCRIPT_NAME for WSDL endpoint +- soap_server: when generating a fault while debug_flag is true, put debug into faultdetail +- wsdl: add enumeration parameter to addSimpleType +- xmlschema: add enumeration parameter to addSimpleType + +2006-02-02, version 0.7.2 +- soapclient: initialize paramArrayStr to improve proxy generation +- soap_parser: handle PHP5 soapclient's incorrect transmission of WSDL-described SOAP encoded arrays. +- soap_server: don't assume _SERVER['HTTPS'] is set; try HTTP_SERVER_VARS['HTTPS'] if it is not +- soap_server: "flatten out" the parameter array to call_user_func_array (thanks Andr Mamitzsch) +- soap_server: make thrown exceptions conform to specs +- wsdl: use serialize_val to serialize an array when the XSD type is soapenc:Array (JBoss/Axis does this) +- wsdl: change formatting of serialized XML for the WSDL +- xmlschema: change formatting of namespaces when serializing XML for the schema + +2006-04-07, version 0.7.2 +- soap_server: if methodparams is not an array, call call_user_func_array with an empty array (thanks Eric Grossi) +- wsdl: distinguish parts with element specified from those with type specified by suffixing element names with ^ +- wsdl: do a case-insensitive match on schema URI when looking for type +- xmlschema: only get element (not type) when name has ^ suffix + +2006-05-16, version 0.7.2 +- soapclient: add getHeader to get parsed SOAP Header +- soap_parser: check status when receiving Header or Body element +- soap_parser: add soapheader +- soap_server: add requestHeader with parsed SOAP Header + +2006-06-15, version 0.7.2 +- wsdl: fix bug in addComplexType (thanks Maarten Meijer) +- soap_transport_http: change cURL message + +2007-03-19, version 0.7.2 +- soapclient: declare as nusoapclient, then also subclass soapclient if SOAP extension not loaded +- soapclientmime: declare as nusoapclientmime, then also subclass soapclientmime if SOAP extension not loaded + +2007-03-28, version 0.7.2 +- nusoap_base: fix serialization of a soapval when its value is a soapval +- soapval: fix serialization of a soapval when its value is a soapval +- soapval: add __toString (cf. http://article.gmane.org/gmane.comp.php.nusoap.general/2776) +- nusoapclient: use lazy retrieval of WSDL instead of always getting it in the constructor +- nusoapclient: fix getProxy that was broken in last revision +- wsdl: add ability to set authorization credentials and retrieve WSDL outside of constructor + +2007-04-05, version 0.7.2 +- nusoapclientmime: don't rely exclusively on Content-Disposition to distinguish the root part from attachment; also check Content-Type (thanks Ben Bosman) +- nusoapclientmime: obey RFC 2045 Section 5.1 (thanks Chris Butler) +- nusoapservermime: don't rely exclusively on Content-Disposition to distinguish the root part from attachment; also check Content-Type (thanks Ben Bosman) +- nusoapservermime: obey RFC 2045 Section 5.1 (thanks Chris Butler) +- nusoap_base: remove extra whitespace from some XML elements +- nusoap_base: allow SOAP headers to be specified as an associative array (thanks Unique) +- nusoap_base: implement __toString +- nusoap_base: improve doc accuracy and consistency (thanks Martin K?gler) +- iso8601_to_timestamp: avoid problem with negative hours after calculation, etc. (thanks Guntram Trebs) +- nusoapclient: support user-settable cURL options (thanks Ciprian Popovici) +- nusoapclient: call SOAP 1.2 binding operations if no SOAP 1.1 present (there is no reason to believe this will always work!) +- nusoapclient: improve doc accuracy and consistency (thanks Martin K?gler) +- soap_server: don't try to use eval to call function when any parameter is an object +- soap_server: don't print return value within debug string; returned objects would need __toString in PHP 5.2 +- soap_server: use URL scheme for WSDL access as the scheme in SOAPAction +- soap_server: strip port number from server name (some FastCGI implementations include port in server name) +- soap_transport_http: support user-settable cURL options (thanks Ciprian Popovici) +- soap_transport_http: use cURL for NTLM authentication +- soap_transport_http: make digest authentication work for GET as well as POST +- soap_transport_http: improve doc accuracy and consistency (thanks Martin K?gler) +- soapval: remove __toString +- wsdl: set operation style if necessary, but do not override one already provided (thanks Raffaele Capobianco) +- wsdl: check SOAP 1.2 binding operations if no SOAP 1.1 present +- wsdl: improve doc accuracy and consistency (thanks Martin K?gler) +- xmlschema: fix simpleType serialization +- xmlschema: improve doc accuracy and consistency (thanks Martin K?gler) + +2007-04-09, version 0.7.2 +- nusoapclient: set decode_utf8 when creating a proxy (thanks Dmitri Dmitrienko) +- nusoapclient: rename class to nusoap_client +- soap_fault: also provide a class named nusoap_fault +- soap_parser: also provide a class named nusoap_parser +- soap_server: also provide a class named nusoap_server +- soap_transport_http: skip HTTP responses 301 and 401 when using cURL +- soap_transport_http: don't force HTTP Connection header when using cURL +- soap_transport_http: don't set HTTP Host and Content-Length headers when using cURL +- soap_transport_http: support CURLOPT_SSLCERTPASSWD (thanks David Blanco) +- wsdl: support user-settable cURL options (thanks Ciprian Popovici) +- wsdl: serialize parameters for non-SOAP 1.1 binding operations (there is no reason to believe this will always work!) +- xmlschema: also provide a class named nusoap_xmlschema +- nusoapclientmime: rename class to nusoap_client_mime +- nusoapservermime: rename class to nusoap_server_mime + +2007-04-11, version 0.7.2 +- nusoap_client: enable cURL usage to be forced (thanks Giunta Gaetano) +- soap_transport_http: enable cURL proxy usage (thanks Giunta Gaetano) +- soap_transport_http: enable cURL usage to be forced (thanks Giunta Gaetano) +- soap_transport_http: use cURL's HTTP authentication options for basic, digest +- wsdl: enable cURL usage to be forced (thanks Giunta Gaetano) + +2007-04-12, version 0.7.2 +- nusoap_client: add debug +- nusoap_xmlschema: don't add elements of complexTypes to elements array (thanks Heiko Hund) +- soap_transport_http: set cURL connection timeout if supported +- soap_transport_http: add debug when setting cURL option +- soap_transport_http: fix digest authentication broken in previous revision +- wsdl: add debug +- wsdlcache: address some issues with non-existing cache-files and PHP Warnings which came in such cases (thanks Ingo Fischer) +- wsdlcache: change class name to nusoap_wsdlcache + +2007-04-13, version 0.7.2 +- wsdl: wrap parameters if unwrapped values are supplied and WSDL specifies Microsoft-style wrapping + +2007-04-16, version 0.7.2 +- nusoap_base: avoid warning in getDebugAsXMLComment +- nusoap_client: small debug change +- nusoap_client_mime: set responseData when the root part is found + +2007-04-17, version 0.7.2 +- soap_transport_http: improve detection of undefined cURL options (thanks Ingo Fischer) + +2007-05-28, version 0.7.2 +- soap_transport_http: support digest authentication opaque feature (cf. RFC 2617) (thanks Daniel Lacroix) +- soap_transport_http: check safe_mode and open_basedir before setting CURLOPT_FOLLOWLOCATION +- soap_transport_http: skip "HTTP/1.0 200 Connection established" header when cURL returns it (thanks Raimund Jacob) +- nusoap_client: improve handling when getProxy is called and WSDL is not being used +- nusoap_base: add comments about which specifications are used/implemented by NuSOAP +- nusoap_xmlschema: create names for unnamed types that are unique by scope within XML Schema + +2007-06-11, version 0.7.2 +- wsdl: wrap return value if unwrapped value is supplied and WSDL specifies Microsoft-style wrapping + +2007-06-22, version 0.7.2 +- nusoap_xmlschema: fix serialization of simpleType restriction (thanks Rizwan Tejpar) + +2007-07-30, version 0.7.2 +- nusoap_server: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) +- nusoap_client: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) + +2007-10-21, version 0.7.2 +- nusoap_server: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) +- nusoap_client: Per http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735, rpc/literal accessor elements should not be in a namespace (thanks Kostas Kalevras) + +2007-10-26, version 0.7.2 +- nusoap_server: Fix munging of _SERVER variables that start with HTTP_ (thanks Thomas Wieczorek) + +2007-10-30, version 0.7.2 +- nusoap_xmlschema: Serialize values for elementFormDefault, attributeFormDefault +- wsdl: Improve consistency between doc/lit schema auto-wrapping and client's parsed schema +- nusoap_server: Correct bug that placed encodingType in Envelope for doc/lit +- nusoap_server: Specify elementFormDefault for schema within doc/lit wsdl + +2007-10-31, version 0.7.2 +- wsdl: Fix typo in parametersMatchWrapped (thanks Sam Stepanyan) +- soap_transport_http: Fix three typos in setProxy (thanks Sam Stepanyan) +- nusoap_xmlschema: Fix typo in serializeTypeDef (thanks Sam Stepanyan) + +2007-11-06, version 1.0rc1 +- wsdl: Improve handling of return values from doc/lit methods +- nusoap_server: Handle case when method is not in a namespace + +2007-11-27, version 1.0rc1 +- nusoap_server: always try to invoke service for a POST +- nusoap_server: only return Location: for WSDL at http://... +- nusoap_base: change some syntax associated with globalDebugLevel + +2008-01-08, version 1.0rc1 +- nusoap_server: fix a typo where = was used instead of == (thanks J. (Johan) Bosma) + +2008-01-10, version 1.0rc1 +- nusoap_client: handle case where request or response has no content-type header (thanks Ingo Fischer) +- nusoap_server: handle case where request or response has no content-type header (thanks Ingo Fischer) +- wsdl: change CSS for .title in webDescription (thanks Marcus Uy) + +2008-01-25, version 1.0rc1 +- nusoap_xmlschema: when an element is of a complexType that is an extension, copy extensionBase from the type +- nusoap_xmlschema: do not apply elementFormDefault to globally defined elements + +2008-02-11, version 1.0rc1 +- wsdl: internally set form of wrapped parameter elements to unqualified (so server handles correctly) + +2008-03-03, version 1.0.rc1 +- nusoap_xmlschema: fix extension when base type has no explicit prefix +- nusoap_xmlschema: support XML Schema include +- wsdl: improve support for sequence by serializing inherited attributes and elements first + +2008-03-04, version 1.0.rc1 +- wsdl: allow WSDL port name to be specified in getOperations +- nusoap_client: allow WSDL port name to be specified in ctor + +2008-03-06, version 1.0rc1 +- wsdl: fix some port name variable references +- nusoap_base: change comments regarding preferred mode of support +- wsdl2nusoap: initial revision + +2008-03-14, version 1.0rc1 +- nusoap_base: fix timezone offset in timestamp_to_iso8601 (thanks Mario Trojan) + +2008-03-27, version 1.0rc1 +- nusoap_server: fix bug setting encodingStyle in serialize_return (thanks Luca Gobbo) + +2008-05-15, version 1.0rc1 +- nusoap_parser: handle case where Header or Body tags are used within SOAP messages (thanks Sergey Zhuravlev) + +2008-08-26, version 1.0rc1 +- wsdl: serialize simpleContent for complexType +- wsdl: avoid serializing complexType elements with no value and minOccurs = 0 regardless of nillability + +2010-04-26, version 0.9.5 +- nusoap_xmlschema: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- wsdl: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- soap_transport_http: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- soap_transport_http: remove call to deprecated function set_magic_quotes_runtime +- nusoap_server: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- nusoap_server: check that value is an object before calling get_class (thanks Pier-Luc Duchaine) +- nusoap_parser: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- nusoap_client: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- nusoap_client: do not assign the return value of new by reference (it is deprecated) (thanks Pier-Luc Duchaine) +- nusoap_base: replace regex function calls (ereg, eregi, split) with PCRE calls (preg_match, preg_split) (thanks Pier-Luc Duchaine) +- nusoapmime: do not assign the return value of new by reference (it is deprecated) diff --git a/include/nusoap/class.nusoap_base.php b/include/nusoap/class.nusoap_base.php new file mode 100644 index 0000000..26ce211 --- /dev/null +++ b/include/nusoap/class.nusoap_base.php @@ -0,0 +1,996 @@ + +* @author Scott Nichol +* @version $Id: class.nusoap_base.php,v 1.56 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class nusoap_base { + /** + * Identification for HTTP headers. + * + * @var string + * @access private + */ + var $title = 'NuSOAP'; + /** + * Version for HTTP headers. + * + * @var string + * @access private + */ + var $version = '0.9.5'; + /** + * CVS revision for HTTP headers. + * + * @var string + * @access private + */ + var $revision = '$Revision: 1.56 $'; + /** + * Current error string (manipulated by getError/setError) + * + * @var string + * @access private + */ + var $error_str = ''; + /** + * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) + * + * @var string + * @access private + */ + var $debug_str = ''; + /** + * toggles automatic encoding of special characters as entities + * (should always be true, I think) + * + * @var boolean + * @access private + */ + var $charencoding = true; + /** + * the debug level for this instance + * + * @var integer + * @access private + */ + var $debugLevel; + + /** + * set schema version + * + * @var string + * @access public + */ + var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + + /** + * charset encoding for outgoing messages + * + * @var string + * @access public + */ + var $soap_defencoding = 'ISO-8859-1'; + //var $soap_defencoding = 'UTF-8'; + + /** + * namespaces in an array of prefix => uri + * + * this is "seeded" by a set of constants, but it may be altered by code + * + * @var array + * @access public + */ + var $namespaces = array( + 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' + ); + + /** + * namespaces used in the current context, e.g. during serialization + * + * @var array + * @access private + */ + var $usedNamespaces = array(); + + /** + * XML Schema types in an array of uri => (array of xml type => php type) + * is this legacy yet? + * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. + * @var array + * @access public + */ + var $typemap = array( + 'http://www.w3.org/2001/XMLSchema' => array( + 'string'=>'string','boolean'=>'boolean','float'=>'double','double'=>'double','decimal'=>'double', + 'duration'=>'','dateTime'=>'string','time'=>'string','date'=>'string','gYearMonth'=>'', + 'gYear'=>'','gMonthDay'=>'','gDay'=>'','gMonth'=>'','hexBinary'=>'string','base64Binary'=>'string', + // abstract "any" types + 'anyType'=>'string','anySimpleType'=>'string', + // derived datatypes + 'normalizedString'=>'string','token'=>'string','language'=>'','NMTOKEN'=>'','NMTOKENS'=>'','Name'=>'','NCName'=>'','ID'=>'', + 'IDREF'=>'','IDREFS'=>'','ENTITY'=>'','ENTITIES'=>'','integer'=>'integer','nonPositiveInteger'=>'integer', + 'negativeInteger'=>'integer','long'=>'integer','int'=>'integer','short'=>'integer','byte'=>'integer','nonNegativeInteger'=>'integer', + 'unsignedLong'=>'','unsignedInt'=>'','unsignedShort'=>'','unsignedByte'=>'','positiveInteger'=>''), + 'http://www.w3.org/2000/10/XMLSchema' => array( + 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', + 'float'=>'double','dateTime'=>'string', + 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), + 'http://www.w3.org/1999/XMLSchema' => array( + 'i4'=>'','int'=>'integer','boolean'=>'boolean','string'=>'string','double'=>'double', + 'float'=>'double','dateTime'=>'string', + 'timeInstant'=>'string','base64Binary'=>'string','base64'=>'string','ur-type'=>'array'), + 'http://soapinterop.org/xsd' => array('SOAPStruct'=>'struct'), + 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64'=>'string','array'=>'array','Array'=>'array'), + 'http://xml.apache.org/xml-soap' => array('Map') + ); + + /** + * XML entities to convert + * + * @var array + * @access public + * @deprecated + * @see expandEntities + */ + var $xmlEntities = array('quot' => '"','amp' => '&', + 'lt' => '<','gt' => '>','apos' => "'"); + + /** + * constructor + * + * @access public + */ + function __construct() { + $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + } + + /** + * gets the global debug level, which applies to future instances + * + * @return integer Debug level 0-9, where 0 turns off + * @access public + */ + function getGlobalDebugLevel() { + return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + } + + /** + * sets the global debug level, which applies to future instances + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setGlobalDebugLevel($level) { + $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; + } + + /** + * gets the debug level for this instance + * + * @return int Debug level 0-9, where 0 turns off + * @access public + */ + function getDebugLevel() { + return $this->debugLevel; + } + + /** + * sets the debug level for this instance + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setDebugLevel($level) { + $this->debugLevel = $level; + } + + /** + * adds debug data to the instance debug string with formatting + * + * @param string $string debug data + * @access private + */ + function debug($string){ + if ($this->debugLevel > 0) { + $this->appendDebug($this->getmicrotime().' '.get_class($this).": $string\n"); + } + } + + /** + * adds debug data to the instance debug string without formatting + * + * @param string $string debug data + * @access public + */ + function appendDebug($string){ + if ($this->debugLevel > 0) { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str .= $string; + } + } + + /** + * clears the current debug data for this instance + * + * @access public + */ + function clearDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str = ''; + } + + /** + * gets the current debug data for this instance + * + * @return debug data + * @access public + */ + function &getDebug() { + // it would be nice to use a memory stream here to use + // memory more efficiently + return $this->debug_str; + } + + /** + * gets the current debug data for this instance as an XML comment + * this may change the contents of the debug data + * + * @return debug data as an XML comment + * @access public + */ + function &getDebugAsXMLComment() { + // it would be nice to use a memory stream here to use + // memory more efficiently + while (strpos($this->debug_str, '--')) { + $this->debug_str = str_replace('--', '- -', $this->debug_str); + } + $ret = ""; + return $ret; + } + + /** + * expands entities, e.g. changes '<' to '<'. + * + * @param string $val The string in which to expand entities. + * @access private + */ + function expandEntities($val) { + if ($this->charencoding) { + $val = str_replace('&', '&', $val); + $val = str_replace("'", ''', $val); + $val = str_replace('"', '"', $val); + $val = str_replace('<', '<', $val); + $val = str_replace('>', '>', $val); + } + return $val; + } + + /** + * returns error string if present + * + * @return mixed error string or false + * @access public + */ + function getError(){ + if($this->error_str != ''){ + return $this->error_str; + } + return false; + } + + /** + * sets error string + * + * @return boolean $string error string + * @access private + */ + function setError($str){ + $this->error_str = $str; + } + + /** + * detect if array is a simple array or a struct (associative array) + * + * @param mixed $val The PHP array + * @return string (arraySimple|arrayStruct) + * @access private + */ + function isArraySimpleOrStruct($val) { + $keyList = array_keys($val); + foreach ($keyList as $keyListValue) { + if (!is_int($keyListValue)) { + return 'arrayStruct'; + } + } + return 'arraySimple'; + } + + /** + * serializes PHP values in accordance w/ section 5. Type information is + * not serialized if $use == 'literal'. + * + * @param mixed $val The value to serialize + * @param string $name The name (local part) of the XML element + * @param string $type The XML schema type (local part) for the element + * @param string $name_ns The namespace for the name of the XML element + * @param string $type_ns The namespace for the type of the element + * @param array $attributes The attributes to serialize as name=>value pairs + * @param string $use The WSDL "use" (encoded|literal) + * @param boolean $soapval Whether this is called from soapval. + * @return string The serialized element, possibly with child elements + * @access public + */ + function serialize_val($val,$name=false,$type=false,$name_ns=false,$type_ns=false,$attributes=false,$use='encoded',$soapval=false) { + $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); + $this->appendDebug('value=' . $this->varDump($val)); + $this->appendDebug('attributes=' . $this->varDump($attributes)); + + if (is_object($val) && get_class($val) == 'soapval' && (! $soapval)) { + $this->debug("serialize_val: serialize soapval"); + $xml = $val->serialize($use); + $this->appendDebug($val->getDebug()); + $val->clearDebug(); + $this->debug("serialize_val of soapval returning $xml"); + return $xml; + } + // force valid name if necessary + if (is_numeric($name)) { + $name = '__numeric_' . $name; + } elseif (! $name) { + $name = 'noname'; + } + // if name has ns, add ns prefix to name + $xmlns = ''; + if($name_ns){ + $prefix = 'nu'.rand(1000,9999); + $name = $prefix.':'.$name; + $xmlns .= " xmlns:$prefix=\"$name_ns\""; + } + // if type is prefixed, create type prefix + if($type_ns != '' && $type_ns == $this->namespaces['xsd']){ + // need to fix this. shouldn't default to xsd if no ns specified + // w/o checking against typemap + $type_prefix = 'xsd'; + } elseif($type_ns){ + $type_prefix = 'ns'.rand(1000,9999); + $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; + } + // serialize attributes if present + $atts = ''; + if($attributes){ + foreach($attributes as $k => $v){ + $atts .= " $k=\"".$this->expandEntities($v).'"'; + } + } + // serialize null value + if (is_null($val)) { + $this->debug("serialize_val: serialize null"); + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$xmlns$atts/>"; + $this->debug("serialize_val returning $xml"); + return $xml; + } else { + if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; + $this->debug("serialize_val returning $xml"); + return $xml; + } + } + // serialize if an xsd built-in primitive type + if($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])){ + $this->debug("serialize_val: serialize xsd built-in primitive type"); + if (is_bool($val)) { + if ($type == 'boolean') { + $val = $val ? 'true' : 'false'; + } elseif (! $val) { + $val = 0; + } + } else if (is_string($val)) { + $val = $this->expandEntities($val); + } + if ($use == 'literal') { + $xml = "<$name$xmlns$atts>$val"; + $this->debug("serialize_val returning $xml"); + return $xml; + } else { + $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val"; + $this->debug("serialize_val returning $xml"); + return $xml; + } + } + // detect type and serialize + $xml = ''; + switch(true) { + case (is_bool($val) || $type == 'boolean'): + $this->debug("serialize_val: serialize boolean"); + if ($type == 'boolean') { + $val = $val ? 'true' : 'false'; + } elseif (! $val) { + $val = 0; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val"; + } + break; + case (is_int($val) || is_long($val) || $type == 'int'): + $this->debug("serialize_val: serialize int"); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val"; + } + break; + case (is_float($val)|| is_double($val) || $type == 'float'): + $this->debug("serialize_val: serialize float"); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val"; + } + break; + case (is_string($val) || $type == 'string'): + $this->debug("serialize_val: serialize string"); + $val = $this->expandEntities($val); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val"; + } + break; + case is_object($val): + $this->debug("serialize_val: serialize object"); + if (get_class($val) == 'soapval') { + $this->debug("serialize_val: serialize soapval object"); + $pXml = $val->serialize($use); + $this->appendDebug($val->getDebug()); + $val->clearDebug(); + } else { + if (! $name) { + $name = get_class($val); + $this->debug("In serialize_val, used class name $name as element name"); + } else { + $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); + } + foreach(get_object_vars($val) as $k => $v){ + $pXml = isset($pXml) ? $pXml.$this->serialize_val($v,$k,false,false,false,false,$use) : $this->serialize_val($v,$k,false,false,false,false,$use); + } + } + if(isset($type) && isset($type_prefix)){ + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$pXml"; + } else { + $xml .= "<$name$xmlns$type_str$atts>$pXml"; + } + break; + break; + case (is_array($val) || $type): + // detect if struct or array + $valueType = $this->isArraySimpleOrStruct($val); + if($valueType=='arraySimple' || preg_match('/^ArrayOf/',$type)){ + $this->debug("serialize_val: serialize array"); + $i = 0; + if(is_array($val) && count($val)> 0){ + foreach($val as $v){ + if(is_object($v) && get_class($v) == 'soapval'){ + $tt_ns = $v->type_ns; + $tt = $v->type; + } elseif (is_array($v)) { + $tt = $this->isArraySimpleOrStruct($v); + } else { + $tt = gettype($v); + } + $array_types[$tt] = 1; + // TODO: for literal, the name should be $name + $xml .= $this->serialize_val($v,'item',false,false,false,false,$use); + ++$i; + } + if(count($array_types) > 1){ + $array_typename = 'xsd:anyType'; + } elseif(isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { + if ($tt == 'integer') { + $tt = 'int'; + } + $array_typename = 'xsd:'.$tt; + } elseif(isset($tt) && $tt == 'arraySimple'){ + $array_typename = 'SOAP-ENC:Array'; + } elseif(isset($tt) && $tt == 'arrayStruct'){ + $array_typename = 'unnamed_struct_use_soapval'; + } else { + // if type is prefixed, create type prefix + if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']){ + $array_typename = 'xsd:' . $tt; + } elseif ($tt_ns) { + $tt_prefix = 'ns' . rand(1000, 9999); + $array_typename = "$tt_prefix:$tt"; + $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; + } else { + $array_typename = $tt; + } + } + $array_type = $i; + if ($use == 'literal') { + $type_str = ''; + } else if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"".$array_typename."[$array_type]\""; + } + // empty array + } else { + if ($use == 'literal') { + $type_str = ''; + } else if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; + } + } + // TODO: for array in literal, there is no wrapper here + $xml = "<$name$xmlns$type_str$atts>".$xml.""; + } else { + // got a struct + $this->debug("serialize_val: serialize struct"); + if(isset($type) && isset($type_prefix)){ + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>"; + } else { + $xml .= "<$name$xmlns$type_str$atts>"; + } + foreach($val as $k => $v){ + // Apache Map + if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { + $xml .= ''; + $xml .= $this->serialize_val($k,'key',false,false,false,false,$use); + $xml .= $this->serialize_val($v,'value',false,false,false,false,$use); + $xml .= ''; + } else { + $xml .= $this->serialize_val($v,$k,false,false,false,false,$use); + } + } + $xml .= ""; + } + break; + default: + $this->debug("serialize_val: serialize unknown"); + $xml .= 'not detected, got '.gettype($val).' for '.$val; + break; + } + $this->debug("serialize_val returning $xml"); + return $xml; + } + + /** + * serializes a message + * + * @param string $body the XML of the SOAP body + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array + * @param array $namespaces optional the namespaces used in generating the body and headers + * @param string $style optional (rpc|document) + * @param string $use optional (encoded|literal) + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @return string the message + * @access public + */ + function serializeEnvelope($body,$headers=false,$namespaces=array(),$style='rpc',$use='encoded',$encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'){ + // TODO: add an option to automatically run utf8_encode on $body and $headers + // if $this->soap_defencoding is UTF-8. Not doing this automatically allows + // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 + + $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); + $this->debug("headers:"); + $this->appendDebug($this->varDump($headers)); + $this->debug("namespaces:"); + $this->appendDebug($this->varDump($namespaces)); + + // serialize namespaces + $ns_string = ''; + foreach(array_merge($this->namespaces,$namespaces) as $k => $v){ + $ns_string .= " xmlns:$k=\"$v\""; + } + if($encodingStyle) { + $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; + } + + // serialize headers + if($headers){ + if (is_array($headers)) { + $xml = ''; + foreach ($headers as $k => $v) { + if (is_object($v) && get_class($v) == 'soapval') { + $xml .= $this->serialize_val($v, false, false, false, false, false, $use); + } else { + $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); + } + } + $headers = $xml; + $this->debug("In serializeEnvelope, serialized array of headers to $headers"); + } + $headers = "".$headers.""; + } + // serialize envelope + return + 'soap_defencoding .'"?'.">". + '". + $headers. + "". + $body. + "". + ""; + } + + /** + * formats a string to be inserted into an HTML stream + * + * @param string $str The string to format + * @return string The formatted string + * @access public + * @deprecated + */ + function formatDump($str){ + $str = htmlspecialchars($str); + return nl2br($str); + } + + /** + * contracts (changes namespace to prefix) a qualified name + * + * @param string $qname qname + * @return string contracted qname + * @access private + */ + function contractQname($qname){ + // get element namespace + //$this->xdebug("Contract $qname"); + if (strrpos($qname, ':')) { + // get unqualified name + $name = substr($qname, strrpos($qname, ':') + 1); + // get ns + $ns = substr($qname, 0, strrpos($qname, ':')); + $p = $this->getPrefixFromNamespace($ns); + if ($p) { + return $p . ':' . $name; + } + return $qname; + } else { + return $qname; + } + } + + /** + * expands (changes prefix to namespace) a qualified name + * + * @param string $qname qname + * @return string expanded qname + * @access private + */ + function expandQname($qname){ + // get element prefix + if(strpos($qname,':') && !preg_match('/^http:\/\//',$qname)){ + // get unqualified name + $name = substr(strstr($qname,':'),1); + // get ns prefix + $prefix = substr($qname,0,strpos($qname,':')); + if(isset($this->namespaces[$prefix])){ + return $this->namespaces[$prefix].':'.$name; + } else { + return $qname; + } + } else { + return $qname; + } + } + + /** + * returns the local part of a prefixed string + * returns the original string, if not prefixed + * + * @param string $str The prefixed string + * @return string The local part + * @access public + */ + function getLocalPart($str){ + if($sstr = strrchr($str,':')){ + // get unqualified name + return substr( $sstr, 1 ); + } else { + return $str; + } + } + + /** + * returns the prefix part of a prefixed string + * returns false, if not prefixed + * + * @param string $str The prefixed string + * @return mixed The prefix or false if there is no prefix + * @access public + */ + function getPrefix($str){ + if($pos = strrpos($str,':')){ + // get prefix + return substr($str,0,$pos); + } + return false; + } + + /** + * pass it a prefix, it returns a namespace + * + * @param string $prefix The prefix + * @return mixed The namespace, false if no namespace has the specified prefix + * @access public + */ + function getNamespaceFromPrefix($prefix){ + if (isset($this->namespaces[$prefix])) { + return $this->namespaces[$prefix]; + } + //$this->setError("No namespace registered for prefix '$prefix'"); + return false; + } + + /** + * returns the prefix for a given namespace (or prefix) + * or false if no prefixes registered for the given namespace + * + * @param string $ns The namespace + * @return mixed The prefix, false if the namespace has no prefixes + * @access public + */ + function getPrefixFromNamespace($ns) { + foreach ($this->namespaces as $p => $n) { + if ($ns == $n || $ns == $p) { + $this->usedNamespaces[$p] = $n; + return $p; + } + } + return false; + } + + /** + * returns the time in ODBC canonical form with microseconds + * + * @return string The time in ODBC canonical form with microseconds + * @access public + */ + function getmicrotime() { + if (function_exists('gettimeofday')) { + $tod = gettimeofday(); + $sec = $tod['sec']; + $usec = $tod['usec']; + } else { + $sec = time(); + $usec = 0; + } + return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); + } + + /** + * Returns a string with the output of var_dump + * + * @param mixed $data The variable to var_dump + * @return string The output of var_dump + * @access public + */ + function varDump($data) { + ob_start(); + var_dump($data); + $ret_val = ob_get_contents(); + ob_end_clean(); + return $ret_val; + } + + /** + * represents the object as a string + * + * @return string + * @access public + */ + function __toString() { + return $this->varDump($this); + } +} + +// XML Schema Datatype Helper Functions + +//xsd:dateTime helpers + +/** +* convert unix timestamp to ISO 8601 compliant date string +* +* @param int $timestamp Unix time stamp +* @param boolean $utc Whether the time stamp is UTC or local +* @return mixed ISO 8601 date string or false +* @access public +*/ +function timestamp_to_iso8601($timestamp,$utc=true){ + $datestr = date('Y-m-d\TH:i:sO',$timestamp); + $pos = strrpos($datestr, "+"); + if ($pos === FALSE) { + $pos = strrpos($datestr, "-"); + } + if ($pos !== FALSE) { + if (strlen($datestr) == $pos + 5) { + $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); + } + } + if($utc){ + $pattern = '/'. + '([0-9]{4})-'. // centuries & years CCYY- + '([0-9]{2})-'. // months MM- + '([0-9]{2})'. // days DD + 'T'. // separator T + '([0-9]{2}):'. // hours hh: + '([0-9]{2}):'. // minutes mm: + '([0-9]{2})(\.[0-9]*)?'. // seconds ss.ss... + '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's + '/'; + + if(preg_match($pattern,$datestr,$regs)){ + return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ',$regs[1],$regs[2],$regs[3],$regs[4],$regs[5],$regs[6]); + } + return false; + } else { + return $datestr; + } +} + +/** +* convert ISO 8601 compliant date string to unix timestamp +* +* @param string $datestr ISO 8601 compliant date string +* @return mixed Unix timestamp (int) or false +* @access public +*/ +function iso8601_to_timestamp($datestr){ + $pattern = '/'. + '([0-9]{4})-'. // centuries & years CCYY- + '([0-9]{2})-'. // months MM- + '([0-9]{2})'. // days DD + 'T'. // separator T + '([0-9]{2}):'. // hours hh: + '([0-9]{2}):'. // minutes mm: + '([0-9]{2})(\.[0-9]+)?'. // seconds ss.ss... + '(Z|[+\-][0-9]{2}:?[0-9]{2})?'. // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's + '/'; + if(preg_match($pattern,$datestr,$regs)){ + // not utc + if($regs[8] != 'Z'){ + $op = substr($regs[8],0,1); + $h = substr($regs[8],1,2); + $m = substr($regs[8],strlen($regs[8])-2,2); + if($op == '-'){ + $regs[4] = $regs[4] + $h; + $regs[5] = $regs[5] + $m; + } elseif($op == '+'){ + $regs[4] = $regs[4] - $h; + $regs[5] = $regs[5] - $m; + } + } + return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); + } else { + return false; + } +} + +/** +* sleeps some number of microseconds +* +* @param string $usec the number of microseconds to sleep +* @access public +* @deprecated +*/ +function usleepWindows($usec) +{ + $start = gettimeofday(); + + do + { + $stop = gettimeofday(); + $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + + $stop['usec'] - $start['usec']; + } + while ($timePassed < $usec); +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_fault.php b/include/nusoap/class.soap_fault.php new file mode 100644 index 0000000..b2889cc --- /dev/null +++ b/include/nusoap/class.soap_fault.php @@ -0,0 +1,90 @@ + +* @version $Id: class.soap_fault.php,v 1.14 2007/04/11 15:49:47 snichol Exp $ +* @access public +*/ +class nusoap_fault extends nusoap_base { + /** + * The fault code (client|server) + * @var string + * @access private + */ + var $faultcode; + /** + * The fault actor + * @var string + * @access private + */ + var $faultactor; + /** + * The fault string, a description of the fault + * @var string + * @access private + */ + var $faultstring; + /** + * The fault detail, typically a string or array of string + * @var mixed + * @access private + */ + var $faultdetail; + + /** + * constructor + * + * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) + * @param string $faultactor only used when msg routed between multiple actors + * @param string $faultstring human readable error message + * @param mixed $faultdetail detail, typically a string or array of string + */ + function __construct($faultcode,$faultactor='',$faultstring='',$faultdetail=''){ + parent::__construct(); + $this->faultcode = $faultcode; + $this->faultactor = $faultactor; + $this->faultstring = $faultstring; + $this->faultdetail = $faultdetail; + } + + /** + * serialize a fault + * + * @return string The serialization of the fault instance. + * @access public + */ + function serialize(){ + $ns_string = ''; + foreach($this->namespaces as $k => $v){ + $ns_string .= "\n xmlns:$k=\"$v\""; + } + $return_msg = + 'soap_defencoding.'"?>'. + '\n". + ''. + ''. + $this->serialize_val($this->faultcode, 'faultcode'). + $this->serialize_val($this->faultactor, 'faultactor'). + $this->serialize_val($this->faultstring, 'faultstring'). + $this->serialize_val($this->faultdetail, 'detail'). + ''. + ''. + ''; + return $return_msg; + } +} + +/** + * Backward compatibility + */ +class soap_fault extends nusoap_fault { +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_parser.php b/include/nusoap/class.soap_parser.php new file mode 100644 index 0000000..7bdbc42 --- /dev/null +++ b/include/nusoap/class.soap_parser.php @@ -0,0 +1,644 @@ + +* @author Scott Nichol +* @version $Id: class.soap_parser.php,v 1.42 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class nusoap_parser extends nusoap_base { + + var $xml = ''; + var $xml_encoding = ''; + var $method = ''; + var $root_struct = ''; + var $root_struct_name = ''; + var $root_struct_namespace = ''; + var $root_header = ''; + var $document = ''; // incoming SOAP body (text) + // determines where in the message we are (envelope,header,body,method) + var $status = ''; + var $position = 0; + var $depth = 0; + var $default_namespace = ''; + var $namespaces = array(); + var $message = array(); + var $parent = ''; + var $fault = false; + var $fault_code = ''; + var $fault_str = ''; + var $fault_detail = ''; + var $depth_array = array(); + var $debug_flag = true; + var $soapresponse = NULL; // parsed SOAP Body + var $soapheader = NULL; // parsed SOAP Header + var $responseHeaders = ''; // incoming SOAP headers (text) + var $body_position = 0; + // for multiref parsing: + // array of id => pos + var $ids = array(); + // array of id => hrefs => pos + var $multirefs = array(); + // toggle for auto-decoding element content + var $decode_utf8 = true; + + /** + * constructor that actually does the parsing + * + * @param string $xml SOAP message + * @param string $encoding character encoding scheme of message + * @param string $method method for which XML is parsed (unused?) + * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 + * @access public + */ + function __construct($xml,$encoding='UTF-8',$method='',$decode_utf8=true){ + parent::__construct(); + $this->xml = $xml; + $this->xml_encoding = $encoding; + $this->method = $method; + $this->decode_utf8 = $decode_utf8; + + // Check whether content has been read. + if(!empty($xml)){ + // Check XML encoding + $pos_xml = strpos($xml, '', $pos_xml + 2) - $pos_xml + 1); + if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { + $xml_encoding = $res[1]; + if (strtoupper($xml_encoding) != $encoding) { + $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; + $this->debug($err); + if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { + $this->setError($err); + return; + } + // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed + } else { + $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); + } + } else { + $this->debug('No encoding specified in XML declaration'); + } + } else { + $this->debug('No XML declaration'); + } + $this->debug('Entering nusoap_parser(), length='.strlen($xml).', encoding='.$encoding); + // Create an XML parser - why not xml_parser_create_ns? + $this->parser = xml_parser_create($this->xml_encoding); + // Set the options for parsing the XML data. + //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); + // Set the object for the parser. + xml_set_object($this->parser, $this); + // Set the element handlers for the parser. + xml_set_element_handler($this->parser, 'start_element','end_element'); + xml_set_character_data_handler($this->parser,'character_data'); + + // Parse the XML file. + if(!xml_parse($this->parser,$xml,true)){ + // Display an error message. + $err = sprintf('XML error parsing SOAP payload on line %d: %s', + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser))); + $this->debug($err); + $this->debug("XML payload:\n" . $xml); + $this->setError($err); + } else { + $this->debug('in nusoap_parser ctor, message:'); + $this->appendDebug($this->varDump($this->message)); + $this->debug('parsed successfully, found root struct: '.$this->root_struct.' of name '.$this->root_struct_name); + // get final value + $this->soapresponse = $this->message[$this->root_struct]['result']; + // get header value + if($this->root_header != '' && isset($this->message[$this->root_header]['result'])){ + $this->soapheader = $this->message[$this->root_header]['result']; + } + // resolve hrefs/ids + if(sizeof($this->multirefs) > 0){ + foreach($this->multirefs as $id => $hrefs){ + $this->debug('resolving multirefs for id: '.$id); + $idVal = $this->buildVal($this->ids[$id]); + if (is_array($idVal) && isset($idVal['!id'])) { + unset($idVal['!id']); + } + foreach($hrefs as $refPos => $ref){ + $this->debug('resolving href at pos '.$refPos); + $this->multirefs[$id][$refPos] = $idVal; + } + } + } + } + xml_parser_free($this->parser); + unset($this->parser); + } else { + $this->debug('xml was empty, didn\'t parse!'); + $this->setError('xml was empty, didn\'t parse!'); + } + } + + /** + * start-element handler + * + * @param resource $parser XML parser object + * @param string $name element name + * @param array $attrs associative array of attributes + * @access private + */ + function start_element($parser, $name, $attrs) { + // position in a total number of elements, starting from 0 + // update class level pos + $pos = $this->position++; + // and set mine + $this->message[$pos] = array('pos' => $pos,'children'=>'','cdata'=>''); + // depth = how many levels removed from root? + // set mine as current global depth and increment global depth value + $this->message[$pos]['depth'] = $this->depth++; + + // else add self as child to whoever the current parent is + if($pos != 0){ + $this->message[$this->parent]['children'] .= '|'.$pos; + } + // set my parent + $this->message[$pos]['parent'] = $this->parent; + // set self as current parent + $this->parent = $pos; + // set self as current value for this depth + $this->depth_array[$this->depth] = $pos; + // get element prefix + if(strpos($name,':')){ + // get ns prefix + $prefix = substr($name,0,strpos($name,':')); + // get unqualified name + $name = substr(strstr($name,':'),1); + } + // set status + if ($name == 'Envelope' && $this->status == '') { + $this->status = 'envelope'; + } elseif ($name == 'Header' && $this->status == 'envelope') { + $this->root_header = $pos; + $this->status = 'header'; + } elseif ($name == 'Body' && $this->status == 'envelope'){ + $this->status = 'body'; + $this->body_position = $pos; + // set method + } elseif($this->status == 'body' && $pos == ($this->body_position+1)) { + $this->status = 'method'; + $this->root_struct_name = $name; + $this->root_struct = $pos; + $this->message[$pos]['type'] = 'struct'; + $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); + } + // set my status + $this->message[$pos]['status'] = $this->status; + // set name + $this->message[$pos]['name'] = htmlspecialchars($name); + // set attrs + $this->message[$pos]['attrs'] = $attrs; + + // loop through atts, logging ns and type declarations + $attstr = ''; + foreach($attrs as $key => $value){ + $key_prefix = $this->getPrefix($key); + $key_localpart = $this->getLocalPart($key); + // if ns declarations, add to class level array of valid namespaces + if($key_prefix == 'xmlns'){ + if(preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/',$value)){ + $this->XMLSchemaVersion = $value; + $this->namespaces['xsd'] = $this->XMLSchemaVersion; + $this->namespaces['xsi'] = $this->XMLSchemaVersion.'-instance'; + } + $this->namespaces[$key_localpart] = $value; + // set method namespace + if($name == $this->root_struct_name){ + $this->methodNamespace = $value; + } + // if it's a type declaration, set type + } elseif($key_localpart == 'type'){ + if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { + // do nothing: already processed arrayType + } else { + $value_prefix = $this->getPrefix($value); + $value_localpart = $this->getLocalPart($value); + $this->message[$pos]['type'] = $value_localpart; + $this->message[$pos]['typePrefix'] = $value_prefix; + if(isset($this->namespaces[$value_prefix])){ + $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; + } else if(isset($attrs['xmlns:'.$value_prefix])) { + $this->message[$pos]['type_namespace'] = $attrs['xmlns:'.$value_prefix]; + } + // should do something here with the namespace of specified type? + } + } elseif($key_localpart == 'arrayType'){ + $this->message[$pos]['type'] = 'array'; + /* do arrayType ereg here + [1] arrayTypeValue ::= atype asize + [2] atype ::= QName rank* + [3] rank ::= '[' (',')* ']' + [4] asize ::= '[' length~ ']' + [5] length ::= nextDimension* Digit+ + [6] nextDimension ::= Digit+ ',' + */ + $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/'; + if(preg_match($expr,$value,$regs)){ + $this->message[$pos]['typePrefix'] = $regs[1]; + $this->message[$pos]['arrayTypePrefix'] = $regs[1]; + if (isset($this->namespaces[$regs[1]])) { + $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; + } else if (isset($attrs['xmlns:'.$regs[1]])) { + $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:'.$regs[1]]; + } + $this->message[$pos]['arrayType'] = $regs[2]; + $this->message[$pos]['arraySize'] = $regs[3]; + $this->message[$pos]['arrayCols'] = $regs[4]; + } + // specifies nil value (or not) + } elseif ($key_localpart == 'nil'){ + $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); + // some other attribute + } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { + $this->message[$pos]['xattrs']['!' . $key] = $value; + } + + if ($key == 'xmlns') { + $this->default_namespace = $value; + } + // log id + if($key == 'id'){ + $this->ids[$value] = $pos; + } + // root + if($key_localpart == 'root' && $value == 1){ + $this->status = 'method'; + $this->root_struct_name = $name; + $this->root_struct = $pos; + $this->debug("found root struct $this->root_struct_name, pos $pos"); + } + // for doclit + $attstr .= " $key=\"$value\""; + } + // get namespace - must be done after namespace atts are processed + if(isset($prefix)){ + $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; + $this->default_namespace = $this->namespaces[$prefix]; + } else { + $this->message[$pos]['namespace'] = $this->default_namespace; + } + if($this->status == 'header'){ + if ($this->root_header != $pos) { + $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; + } + } elseif($this->root_struct_name != ''){ + $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; + } + } + + /** + * end-element handler + * + * @param resource $parser XML parser object + * @param string $name element name + * @access private + */ + function end_element($parser, $name) { + // position of current element is equal to the last value left in depth_array for my depth + $pos = $this->depth_array[$this->depth--]; + + // get element prefix + if(strpos($name,':')){ + // get ns prefix + $prefix = substr($name,0,strpos($name,':')); + // get unqualified name + $name = substr(strstr($name,':'),1); + } + + // build to native type + if(isset($this->body_position) && $pos > $this->body_position){ + // deal w/ multirefs + if(isset($this->message[$pos]['attrs']['href'])){ + // get id + $id = substr($this->message[$pos]['attrs']['href'],1); + // add placeholder to href array + $this->multirefs[$id][$pos] = 'placeholder'; + // add set a reference to it as the result value + $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; + // build complexType values + } elseif($this->message[$pos]['children'] != ''){ + // if result has already been generated (struct/array) + if(!isset($this->message[$pos]['result'])){ + $this->message[$pos]['result'] = $this->buildVal($pos); + } + // build complexType values of attributes and possibly simpleContent + } elseif (isset($this->message[$pos]['xattrs'])) { + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + if (isset($this->message[$pos]['type'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; + } + } + } + $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; + // set value of simpleType (or nil complexType) + } else { + //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['type'])) { + $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['result'] = $this->message[$pos]['cdata']; + } + } + + /* add value to parent's result, if parent is struct/array + $parent = $this->message[$pos]['parent']; + if($this->message[$parent]['type'] != 'map'){ + if(strtolower($this->message[$parent]['type']) == 'array'){ + $this->message[$parent]['result'][] = $this->message[$pos]['result']; + } else { + $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; + } + } + */ + } + } + + // for doclit + if($this->status == 'header'){ + if ($this->root_header != $pos) { + $this->responseHeaders .= ""; + } + } elseif($pos >= $this->root_struct){ + $this->document .= ""; + } + // switch status + if ($pos == $this->root_struct){ + $this->status = 'body'; + $this->root_struct_namespace = $this->message[$pos]['namespace']; + } elseif ($pos == $this->root_header) { + $this->status = 'envelope'; + } elseif ($name == 'Body' && $this->status == 'body') { + $this->status = 'envelope'; + } elseif ($name == 'Header' && $this->status == 'header') { // will never happen + $this->status = 'envelope'; + } elseif ($name == 'Envelope' && $this->status == 'envelope') { + $this->status = ''; + } + // set parent back to my parent + $this->parent = $this->message[$pos]['parent']; + } + + /** + * element content handler + * + * @param resource $parser XML parser object + * @param string $data element content + * @access private + */ + function character_data($parser, $data){ + $pos = $this->depth_array[$this->depth]; + if ($this->xml_encoding=='UTF-8'){ + // TODO: add an option to disable this for folks who want + // raw UTF-8 that, e.g., might not map to iso-8859-1 + // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); + if($this->decode_utf8){ + $data = utf8_decode($data); + } + } + $this->message[$pos]['cdata'] .= $data; + // for doclit + if($this->status == 'header'){ + $this->responseHeaders .= $data; + } else { + $this->document .= $data; + } + } + + /** + * get the parsed message (SOAP Body) + * + * @return mixed + * @access public + * @deprecated use get_soapbody instead + */ + function get_response(){ + return $this->soapresponse; + } + + /** + * get the parsed SOAP Body (NULL if there was none) + * + * @return mixed + * @access public + */ + function get_soapbody(){ + return $this->soapresponse; + } + + /** + * get the parsed SOAP Header (NULL if there was none) + * + * @return mixed + * @access public + */ + function get_soapheader(){ + return $this->soapheader; + } + + /** + * get the unparsed SOAP Header + * + * @return string XML or empty if no Header + * @access public + */ + function getHeaders(){ + return $this->responseHeaders; + } + + /** + * decodes simple types into PHP variables + * + * @param string $value value to decode + * @param string $type XML type to decode + * @param string $typens XML type namespace to decode + * @return mixed PHP value + * @access private + */ + function decodeSimple($value, $type, $typens) { + // TODO: use the namespace! + if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { + return (string) $value; + } + if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { + return (int) $value; + } + if ($type == 'float' || $type == 'double' || $type == 'decimal') { + return (double) $value; + } + if ($type == 'boolean') { + if (strtolower($value) == 'false' || strtolower($value) == 'f') { + return false; + } + return (boolean) $value; + } + if ($type == 'base64' || $type == 'base64Binary') { + $this->debug('Decode base64 value'); + return base64_decode($value); + } + // obscure numeric types + if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' + || $type == 'nonNegativeInteger' || $type == 'positiveInteger' + || $type == 'unsignedInt' + || $type == 'unsignedShort' || $type == 'unsignedByte') { + return (int) $value; + } + // bogus: parser treats array with no elements as a simple type + if ($type == 'array') { + return array(); + } + // everything else + return (string) $value; + } + + /** + * builds response structures for compound values (arrays/structs) + * and scalars + * + * @param integer $pos position in node tree + * @return mixed PHP value + * @access private + */ + function buildVal($pos){ + if(!isset($this->message[$pos]['type'])){ + $this->message[$pos]['type'] = ''; + } + $this->debug('in buildVal() for '.$this->message[$pos]['name']."(pos $pos) of type ".$this->message[$pos]['type']); + // if there are children... + if($this->message[$pos]['children'] != ''){ + $this->debug('in buildVal, there are children'); + $children = explode('|',$this->message[$pos]['children']); + array_shift($children); // knock off empty + // md array + if(isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != ''){ + $r=0; // rowcount + $c=0; // colcount + foreach($children as $child_pos){ + $this->debug("in buildVal, got an MD array element: $r, $c"); + $params[$r][] = $this->message[$child_pos]['result']; + $c++; + if($c == $this->message[$pos]['arrayCols']){ + $c = 0; + $r++; + } + } + // array + } elseif($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array'){ + $this->debug('in buildVal, adding array '.$this->message[$pos]['name']); + foreach($children as $child_pos){ + $params[] = &$this->message[$child_pos]['result']; + } + // apache Map type: java hashtable + } elseif($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap'){ + $this->debug('in buildVal, Java Map '.$this->message[$pos]['name']); + foreach($children as $child_pos){ + $kv = explode("|",$this->message[$child_pos]['children']); + $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; + } + // generic compound type + //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { + } else { + // Apache Vector type: treat as an array + $this->debug('in buildVal, adding Java Vector or generic compound type '.$this->message[$pos]['name']); + if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { + $notstruct = 1; + } else { + $notstruct = 0; + } + // + foreach($children as $child_pos){ + if($notstruct){ + $params[] = &$this->message[$child_pos]['result']; + } else { + if (isset($params[$this->message[$child_pos]['name']])) { + // de-serialize repeated element name into an array + if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { + $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); + } + $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; + } else { + $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; + } + } + } + } + if (isset($this->message[$pos]['xattrs'])) { + $this->debug('in buildVal, handling attributes'); + foreach ($this->message[$pos]['xattrs'] as $n => $v) { + $params[$n] = $v; + } + } + // handle simpleContent + if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + $this->debug('in buildVal, handling simpleContent'); + if (isset($this->message[$pos]['type'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $params['!'] = $this->message[$pos]['cdata']; + } + } + } + $ret = is_array($params) ? $params : array(); + $this->debug('in buildVal, return:'); + $this->appendDebug($this->varDump($ret)); + return $ret; + } else { + $this->debug('in buildVal, no children, building scalar'); + $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; + if (isset($this->message[$pos]['type'])) { + $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + $this->debug("in buildVal, return: $ret"); + return $ret; + } + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + $this->debug("in buildVal, return: $ret"); + return $ret; + } + $ret = $this->message[$pos]['cdata']; + $this->debug("in buildVal, return: $ret"); + return $ret; + } + } +} + +/** + * Backward compatibility + */ +class soap_parser extends nusoap_parser { +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_server.php b/include/nusoap/class.soap_server.php new file mode 100644 index 0000000..8f11567 --- /dev/null +++ b/include/nusoap/class.soap_server.php @@ -0,0 +1,1127 @@ + +* @author Scott Nichol +* @version $Id: class.soap_server.php,v 1.63 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class nusoap_server extends nusoap_base { + /** + * HTTP headers of request + * @var array + * @access private + */ + var $headers = array(); + /** + * HTTP request + * @var string + * @access private + */ + var $request = ''; + /** + * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $requestHeaders = ''; + /** + * SOAP Headers from request (parsed) + * @var mixed + * @access public + */ + var $requestHeader = NULL; + /** + * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) + * @var string + * @access public + */ + var $document = ''; + /** + * SOAP payload for request (text) + * @var string + * @access public + */ + var $requestSOAP = ''; + /** + * requested method namespace URI + * @var string + * @access private + */ + var $methodURI = ''; + /** + * name of method requested + * @var string + * @access private + */ + var $methodname = ''; + /** + * method parameters from request + * @var array + * @access private + */ + var $methodparams = array(); + /** + * SOAP Action from request + * @var string + * @access private + */ + var $SOAPAction = ''; + /** + * character set encoding of incoming (request) messages + * @var string + * @access public + */ + var $xml_encoding = ''; + /** + * toggles whether the parser decodes element content w/ utf8_decode() + * @var boolean + * @access public + */ + var $decode_utf8 = true; + + /** + * HTTP headers of response + * @var array + * @access public + */ + var $outgoing_headers = array(); + /** + * HTTP response + * @var string + * @access private + */ + var $response = ''; + /** + * SOAP headers for response (text or array of soapval or associative array) + * @var mixed + * @access public + */ + var $responseHeaders = ''; + /** + * SOAP payload for response (text) + * @var string + * @access private + */ + var $responseSOAP = ''; + /** + * method return value to place in response + * @var mixed + * @access private + */ + var $methodreturn = false; + /** + * whether $methodreturn is a string of literal XML + * @var boolean + * @access public + */ + var $methodreturnisliteralxml = false; + /** + * SOAP fault for response (or false) + * @var mixed + * @access private + */ + var $fault = false; + /** + * text indication of result (for debugging) + * @var string + * @access private + */ + var $result = 'successful'; + + /** + * assoc array of operations => opData; operations are added by the register() + * method or by parsing an external WSDL definition + * @var array + * @access private + */ + var $operations = array(); + /** + * wsdl instance (if one) + * @var mixed + * @access private + */ + var $wsdl = false; + /** + * URL for WSDL (if one) + * @var mixed + * @access private + */ + var $externalWSDLURL = false; + /** + * whether to append debug to response as XML comment + * @var boolean + * @access public + */ + var $debug_flag = false; + + + /** + * constructor + * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. + * + * @param mixed $wsdl file path or URL (string), or wsdl instance (object) + * @access public + */ + function __construct($wsdl=false){ + parent::__construct(); + // turn on debugging? + global $debug; + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $this->debug("_SERVER is defined:"); + $this->appendDebug($this->varDump($_SERVER)); + } elseif (isset($HTTP_SERVER_VARS)) { + $this->debug("HTTP_SERVER_VARS is defined:"); + $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); + } else { + $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); + } + + if (isset($debug)) { + $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); + $this->debug_flag = $debug; + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = explode('&', $_SERVER['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); + $this->debug_flag = substr($v, 6); + } + } + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); + $this->debug_flag = substr($v, 6); + } + } + } + + // wsdl + if($wsdl){ + $this->debug("In nusoap_server, WSDL is specified"); + if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { + $this->wsdl = $wsdl; + $this->externalWSDLURL = $this->wsdl->wsdl; + $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); + } else { + $this->debug('Create wsdl from ' . $wsdl); + $this->wsdl = new wsdl($wsdl); + $this->externalWSDLURL = $wsdl; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($err = $this->wsdl->getError()){ + die('WSDL ERROR: '.$err); + } + } + } + + /** + * processes request and returns response + * + * @param string $data usually is the value of $HTTP_RAW_POST_DATA + * @access public + */ + function service($data){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER['REQUEST_METHOD'])) { + $rm = $_SERVER['REQUEST_METHOD']; + } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { + $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; + } else { + $rm = ''; + } + + if (isset($_SERVER['QUERY_STRING'])) { + $qs = $_SERVER['QUERY_STRING']; + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = $HTTP_SERVER_VARS['QUERY_STRING']; + } else { + $qs = ''; + } + $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); + + if ($rm == 'POST') { + $this->debug("In service, invoke the request"); + $this->parse_request($data); + if (! $this->fault) { + $this->invoke_method(); + } + if (! $this->fault) { + $this->serialize_return(); + } + $this->send_response(); + } elseif (preg_match('/wsdl/', $qs) ){ + $this->debug("In service, this is a request for WSDL"); + if ($this->externalWSDLURL){ + if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL + $this->debug("In service, re-direct for WSDL"); + header('Location: '.$this->externalWSDLURL); + } else { // assume file + $this->debug("In service, use file passthru for WSDL"); + header("Content-Type: text/xml\r\n"); + $pos = strpos($this->externalWSDLURL, "file://"); + if ($pos === false) { + $filename = $this->externalWSDLURL; + } else { + $filename = substr($this->externalWSDLURL, $pos + 7); + } + $fp = fopen($this->externalWSDLURL, 'r'); + fpassthru($fp); + } + } elseif ($this->wsdl) { + $this->debug("In service, serialize WSDL"); + header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); + print $this->wsdl->serialize($this->debug_flag); + if ($this->debug_flag) { + $this->debug('wsdl:'); + $this->appendDebug($this->varDump($this->wsdl)); + print $this->getDebugAsXMLComment(); + } + } else { + $this->debug("In service, there is no WSDL"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide WSDL"; + } + } elseif ($this->wsdl) { + $this->debug("In service, return Web description"); + print $this->wsdl->webDescription(); + } else { + $this->debug("In service, no Web description"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide a Web description"; + } + } + + /** + * parses HTTP request headers. + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * + * @access private + */ + function parse_http_headers() { + global $HTTP_SERVER_VARS; + + $this->request = ''; + $this->SOAPAction = ''; + if(function_exists('getallheaders')){ + $this->debug("In parse_http_headers, use getallheaders"); + $headers = getallheaders(); + foreach($headers as $k=>$v){ + $k = strtolower($k); + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + // get SOAPAction header + if(isset($this->headers['soapaction'])){ + $this->SOAPAction = str_replace('"','',$this->headers['soapaction']); + } + // get the character encoding of the incoming request + if(isset($this->headers['content-type']) && strpos($this->headers['content-type'],'=')){ + $enc = str_replace('"','',substr(strstr($this->headers["content-type"],'='),1)); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } elseif(isset($_SERVER) && is_array($_SERVER)){ + $this->debug("In parse_http_headers, use _SERVER"); + foreach ($_SERVER as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } else if ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } elseif (is_array($HTTP_SERVER_VARS)) { + $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); + foreach ($HTTP_SERVER_VARS as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); $k = strtolower($k); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } else if ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } else { + $this->debug("In parse_http_headers, HTTP headers not accessible"); + $this->setError("HTTP headers not accessible"); + } + } + + /** + * parses a request + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * request + * requestSOAP + * methodURI + * methodname + * methodparams + * requestHeaders + * document + * + * This sets the fault field on error + * + * @param string $data XML string + * @access private + */ + function parse_request($data='') { + $this->debug('entering parse_request()'); + $this->parse_http_headers(); + $this->debug('got character encoding: '.$this->xml_encoding); + // uncompress if necessary + if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { + $this->debug('got content encoding: ' . $this->headers['content-encoding']); + if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { + // if decoding works, use it. else assume data wasn't gzencoded + if (function_exists('gzuncompress')) { + if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { + $data = $degzdata; + } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { + $data = $degzdata; + } else { + $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); + return; + } + } else { + $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); + return; + } + } + } + $this->request .= "\r\n".$data; + $data = $this->parseRequest($this->headers, $data); + $this->requestSOAP = $data; + $this->debug('leaving parse_request'); + } + + /** + * invokes a PHP function for the requested SOAP method + * + * The following fields are set by this function (when successful) + * + * methodreturn + * + * Note that the PHP function that is called may also set the following + * fields to affect the response sent to the client + * + * responseHeaders + * outgoing_headers + * + * This sets the fault field on error + * + * @access private + */ + function invoke_method() { + $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); + + // + // if you are debugging in this area of the code, your service uses a class to implement methods, + // you use SOAP RPC, and the client is .NET, please be aware of the following... + // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the + // method name. that is fine for naming the .NET methods. it is not fine for properly constructing + // the XML request and reading the XML response. you need to add the RequestElementName and + // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe + // generates for the method. these parameters are used to specify the correct XML element names + // for .NET to use, i.e. the names with the '.' in them. + // + $orig_methodname = $this->methodname; + if ($this->wsdl) { + if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { + $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { + // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element + $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + $this->methodname = $this->opData['name']; + } else { + $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); + $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); + return; + } + } else { + $this->debug('in invoke_method, no WSDL to validate method'); + } + + // if a . is present in $this->methodname, we see if there is a class in scope, + // which could be referred to. We will also distinguish between two deliminators, + // to allow methods to be called a the class or an instance + if (strpos($this->methodname, '..') > 0) { + $delim = '..'; + } else if (strpos($this->methodname, '.') > 0) { + $delim = '.'; + } else { + $delim = ''; + } + $this->debug("in invoke_method, delim=$delim"); + + $class = ''; + $method = ''; + if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { + $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); + if (class_exists($try_class)) { + // get the class and method name + $class = $try_class; + $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); + $this->debug("in invoke_method, class=$class method=$method delim=$delim"); + } else { + $this->debug("in invoke_method, class=$try_class not found"); + } + } else { + $try_class = ''; + $this->debug("in invoke_method, no class to try"); + } + + // does method exist? + if ($class == '') { + if (!function_exists($this->methodname)) { + $this->debug("in invoke_method, function '$this->methodname' not found!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client',"method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); + return; + } + } else { + $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; + if (!in_array($method_to_compare, get_class_methods($class))) { + $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client',"method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); + return; + } + } + + // evaluate message, getting back parameters + // verify that request parameters match the method's signature + if(! $this->verify_method($this->methodname,$this->methodparams)){ + // debug + $this->debug('ERROR: request not verified against method signature'); + $this->result = 'fault: request failed validation against method signature'; + // return fault + $this->fault('SOAP-ENV:Client',"Operation '$this->methodname' not defined in service."); + return; + } + + // if there are parameters to pass + $this->debug('in invoke_method, params:'); + $this->appendDebug($this->varDump($this->methodparams)); + $this->debug("in invoke_method, calling '$this->methodname'"); + if (!function_exists('call_user_func_array')) { + if ($class == '') { + $this->debug('in invoke_method, calling function using eval()'); + $funcCall = "\$this->methodreturn = $this->methodname("; + } else { + if ($delim == '..') { + $this->debug('in invoke_method, calling class method using eval()'); + $funcCall = "\$this->methodreturn = ".$class."::".$method."("; + } else { + $this->debug('in invoke_method, calling instance method using eval()'); + // generate unique instance name + $instname = "\$inst_".time(); + $funcCall = $instname." = new ".$class."(); "; + $funcCall .= "\$this->methodreturn = ".$instname."->".$method."("; + } + } + if ($this->methodparams) { + foreach ($this->methodparams as $param) { + if (is_array($param) || is_object($param)) { + $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); + return; + } + $funcCall .= "\"$param\","; + } + $funcCall = substr($funcCall, 0, -1); + } + $funcCall .= ');'; + $this->debug('in invoke_method, function call: '.$funcCall); + @eval($funcCall); + } else { + if ($class == '') { + $this->debug('in invoke_method, calling function using call_user_func_array()'); + $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() + } elseif ($delim == '..') { + $this->debug('in invoke_method, calling class method using call_user_func_array()'); + $call_arg = array ($class, $method); + } else { + $this->debug('in invoke_method, calling instance method using call_user_func_array()'); + $instance = new $class (); + $call_arg = array(&$instance, $method); + } + if (is_array($this->methodparams)) { + $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); + } else { + $this->methodreturn = call_user_func_array($call_arg, array()); + } + } + $this->debug('in invoke_method, methodreturn:'); + $this->appendDebug($this->varDump($this->methodreturn)); + $this->debug("in invoke_method, called method $this->methodname, received data of type ".gettype($this->methodreturn)); + } + + /** + * serializes the return value from a PHP function into a full SOAP Envelope + * + * The following fields are set by this function (when successful) + * + * responseSOAP + * + * This sets the fault field on error + * + * @access private + */ + function serialize_return() { + $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); + // if fault + if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { + $this->debug('got a fault object from method'); + $this->fault = $this->methodreturn; + return; + } elseif ($this->methodreturnisliteralxml) { + $return_val = $this->methodreturn; + // returned value(s) + } else { + $this->debug('got a(n) '.gettype($this->methodreturn).' from method'); + $this->debug('serializing return value'); + if($this->wsdl){ + if (sizeof($this->opData['output']['parts']) > 1) { + $this->debug('more than one output part, so use the method return unchanged'); + $opParams = $this->methodreturn; + } elseif (sizeof($this->opData['output']['parts']) == 1) { + $this->debug('exactly one output part, so wrap the method return in a simple array'); + // TODO: verify that it is not already wrapped! + //foreach ($this->opData['output']['parts'] as $name => $type) { + // $this->debug('wrap in element named ' . $name); + //} + $opParams = array($this->methodreturn); + } + $return_val = $this->wsdl->serializeRPCParameters($this->methodname,'output',$opParams); + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if($errstr = $this->wsdl->getError()){ + $this->debug('got wsdl error: '.$errstr); + $this->fault('SOAP-ENV:Server', 'unable to serialize result'); + return; + } + } else { + if (isset($this->methodreturn)) { + $return_val = $this->serialize_val($this->methodreturn, 'return'); + } else { + $return_val = ''; + $this->debug('in absence of WSDL, assume void return for backward compatibility'); + } + } + } + $this->debug('return value:'); + $this->appendDebug($this->varDump($return_val)); + + $this->debug('serializing response'); + if ($this->wsdl) { + $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); + if ($this->opData['style'] == 'rpc') { + $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); + if ($this->opData['output']['use'] == 'literal') { + // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace + if ($this->methodURI) { + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } else { + $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; + } + } else { + if ($this->methodURI) { + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } else { + $payload = '<'.$this->methodname.'Response>'.$return_val.'methodname.'Response>'; + } + } + } else { + $this->debug('style is not rpc for serialization: assume document'); + $payload = $return_val; + } + } else { + $this->debug('do not have WSDL for serialization: assume rpc/encoded'); + $payload = 'methodname.'Response xmlns:ns1="'.$this->methodURI.'">'.$return_val.'methodname."Response>"; + } + $this->result = 'successful'; + if($this->wsdl){ + //if($this->debug_flag){ + $this->appendDebug($this->wsdl->getDebug()); + // } + if (isset($this->opData['output']['encodingStyle'])) { + $encodingStyle = $this->opData['output']['encodingStyle']; + } else { + $encodingStyle = ''; + } + // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. + $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders,$this->wsdl->usedNamespaces,$this->opData['style'],$this->opData['output']['use'],$encodingStyle); + } else { + $this->responseSOAP = $this->serializeEnvelope($payload,$this->responseHeaders); + } + $this->debug("Leaving serialize_return"); + } + + /** + * sends an HTTP response + * + * The following fields are set by this function (when successful) + * + * outgoing_headers + * response + * + * @access private + */ + function send_response() { + $this->debug('Enter send_response'); + if ($this->fault) { + $payload = $this->fault->serialize(); + $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; + $this->outgoing_headers[] = "Status: 500 Internal Server Error"; + } else { + $payload = $this->responseSOAP; + // Some combinations of PHP+Web server allow the Status + // to come through as a header. Since OK is the default + // just do nothing. + // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; + // $this->outgoing_headers[] = "Status: 200 OK"; + } + // add debug data if in debug mode + if(isset($this->debug_flag) && $this->debug_flag){ + $payload .= $this->getDebugAsXMLComment(); + } + $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (".$rev[1].")"; + // Let the Web server decide about this + //$this->outgoing_headers[] = "Connection: Close\r\n"; + $payload = $this->getHTTPBody($payload); + $type = $this->getHTTPContentType(); + $charset = $this->getHTTPContentTypeCharset(); + $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); + //begin code to compress payload - by John + // NOTE: there is no way to know whether the Web server will also compress + // this data. + if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { + if (strstr($this->headers['accept-encoding'], 'gzip')) { + if (function_exists('gzencode')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: gzip"; + $payload = gzencode($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { + // Note: MSIE requires gzdeflate output (no Zlib header and checksum), + // instead of gzcompress output, + // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) + if (function_exists('gzdeflate')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: deflate"; + $payload = gzdeflate($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } + } + //end code + $this->outgoing_headers[] = "Content-Length: ".strlen($payload); + reset($this->outgoing_headers); + foreach($this->outgoing_headers as $hdr){ + header($hdr, false); + } + print $payload; + $this->response = join("\r\n",$this->outgoing_headers)."\r\n\r\n".$payload; + } + + /** + * takes the value that was created by parsing the request + * and compares to the method's signature, if available. + * + * @param string $operation The operation to be invoked + * @param array $request The array of parameter values + * @return boolean Whether the operation was found + * @access private + */ + function verify_method($operation,$request){ + if(isset($this->wsdl) && is_object($this->wsdl)){ + if($this->wsdl->getOperationData($operation)){ + return true; + } + } elseif(isset($this->operations[$operation])){ + return true; + } + return false; + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Request not of type text/xml (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Request not of type text/xml'); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + // parse response, get soap parser obj + $parser = new nusoap_parser($data,$this->xml_encoding,'',$this->decode_utf8); + // parser debug + $this->debug("parser debug: \n".$parser->getDebug()); + // if fault occurred during message parsing + if($err = $parser->getError()){ + $this->result = 'fault: error in msg parsing: '.$err; + $this->fault('SOAP-ENV:Client',"error in msg parsing:\n".$err); + // else successfully parsed request into soapval object + } else { + // get/set methodname + $this->methodURI = $parser->root_struct_namespace; + $this->methodname = $parser->root_struct_name; + $this->debug('methodname: '.$this->methodname.' methodURI: '.$this->methodURI); + $this->debug('calling parser->get_soapbody()'); + $this->methodparams = $parser->get_soapbody(); + // get SOAP headers + $this->requestHeaders = $parser->getHeaders(); + // get SOAP Header + $this->requestHeader = $parser->get_soapheader(); + // add document for doclit support + $this->document = $parser->document; + } + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /** + * add a method to the dispatch map (this has been replaced by the register method) + * + * @param string $methodname + * @param string $in array of input values + * @param string $out array of output values + * @access public + * @deprecated + */ + function add_to_map($methodname,$in,$out){ + $this->operations[$methodname] = array('name' => $methodname,'in' => $in,'out' => $out); + } + + /** + * register a service function with the server + * + * @param string $name the name of the PHP function, class.method or class..method + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param mixed $namespace the element namespace for the method or false + * @param mixed $soapaction the soapaction for the method or false + * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param mixed $use optional (encoded|literal) or false + * @param string $documentation optional Description to include in WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function register($name,$in=array(),$out=array(),$namespace=false,$soapaction=false,$style=false,$use=false,$documentation='',$encodingStyle=''){ + global $HTTP_SERVER_VARS; + + if($this->externalWSDLURL){ + die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); + } + if (! $name) { + die('You must specify a name when you register an operation'); + } + if (!is_array($in)) { + die('You must provide an array for operation inputs'); + } + if (!is_array($out)) { + die('You must provide an array for operation outputs'); + } + if(false == $namespace) { + } + if(false == $soapaction) { + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; + } + if(false == $style) { + $style = "rpc"; + } + if(false == $use) { + $use = "encoded"; + } + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + $this->operations[$name] = array( + 'name' => $name, + 'in' => $in, + 'out' => $out, + 'namespace' => $namespace, + 'soapaction' => $soapaction, + 'style' => $style); + if($this->wsdl){ + $this->wsdl->addOperation($name,$in,$out,$namespace,$soapaction,$style,$use,$documentation,$encodingStyle); + } + return true; + } + + /** + * Specify a fault to be returned to the client. + * This also acts as a flag to the server that a fault has occured. + * + * @param string $faultcode + * @param string $faultstring + * @param string $faultactor + * @param string $faultdetail + * @access public + */ + function fault($faultcode,$faultstring,$faultactor='',$faultdetail=''){ + if ($faultdetail == '' && $this->debug_flag) { + $faultdetail = $this->getDebug(); + } + $this->fault = new nusoap_fault($faultcode,$faultactor,$faultstring,$faultdetail); + $this->fault->soap_defencoding = $this->soap_defencoding; + } + + /** + * Sets up wsdl object. + * Acts as a flag to enable internal WSDL generation + * + * @param string $serviceName, name of the service + * @param mixed $namespace optional 'tns' service namespace or false + * @param mixed $endpoint optional URL of service endpoint or false + * @param string $style optional (rpc|document) WSDL style (also specified by operation) + * @param string $transport optional SOAP transport + * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false + */ + function configureWSDL($serviceName,$namespace = false,$endpoint = false,$style='rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SERVER_PORT = $_SERVER['SERVER_PORT']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) + $colon = strpos($SERVER_NAME,":"); + if ($colon) { + $SERVER_NAME = substr($SERVER_NAME, 0, $colon); + } + if ($SERVER_PORT == 80) { + $SERVER_PORT = ''; + } else { + $SERVER_PORT = ':' . $SERVER_PORT; + } + if(false == $namespace) { + $namespace = "http://$SERVER_NAME/soap/$serviceName"; + } + + if(false == $endpoint) { + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; + } + + if(false == $schemaTargetNamespace) { + $schemaTargetNamespace = $namespace; + } + + $this->wsdl = new wsdl; + $this->wsdl->serviceName = $serviceName; + $this->wsdl->endpoint = $endpoint; + $this->wsdl->namespaces['tns'] = $namespace; + $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; + $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; + if ($schemaTargetNamespace != $namespace) { + $this->wsdl->namespaces['types'] = $schemaTargetNamespace; + } + $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); + if ($style == 'document') { + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; + } + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->bindings[$serviceName.'Binding'] = array( + 'name'=>$serviceName.'Binding', + 'style'=>$style, + 'transport'=>$transport, + 'portType'=>$serviceName.'PortType'); + $this->wsdl->ports[$serviceName.'Port'] = array( + 'binding'=>$serviceName.'Binding', + 'location'=>$endpoint, + 'bindingType'=>'http://schemas.xmlsoap.org/wsdl/soap/'); + } +} + +/** + * Backward compatibility + */ +class soap_server extends nusoap_server { +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_transport_http.php b/include/nusoap/class.soap_transport_http.php new file mode 100644 index 0000000..cb1c7da --- /dev/null +++ b/include/nusoap/class.soap_transport_http.php @@ -0,0 +1,1307 @@ + +* @author Scott Nichol +* @version $Id: class.soap_transport_http.php,v 1.68 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class soap_transport_http extends nusoap_base { + + var $url = ''; + var $uri = ''; + var $digest_uri = ''; + var $scheme = ''; + var $host = ''; + var $port = ''; + var $path = ''; + var $request_method = 'POST'; + var $protocol_version = '1.0'; + var $encoding = ''; + var $outgoing_headers = array(); + var $incoming_headers = array(); + var $incoming_cookies = array(); + var $outgoing_payload = ''; + var $incoming_payload = ''; + var $response_status_line; // HTTP response status line + var $useSOAPAction = true; + var $persistentConnection = false; + var $ch = false; // cURL handle + var $ch_options = array(); // cURL custom options + var $use_curl = false; // force cURL use + var $proxy = null; // proxy information (associative array) + var $username = ''; + var $password = ''; + var $authtype = ''; + var $digestRequest = array(); + var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) + // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' + // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' + // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' + // passphrase: SSL key password/passphrase + // certpassword: SSL certificate password + // verifypeer: default is 1 + // verifyhost: default is 1 + + /** + * constructor + * + * @param string $url The URL to which to connect + * @param array $curl_options User-specified cURL options + * @param boolean $use_curl Whether to try to force cURL use + * @access public + */ + function __construct($url, $curl_options = NULL, $use_curl = false){ + parent::__construct(); + $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); + $this->appendDebug($this->varDump($curl_options)); + $this->setURL($url); + if (is_array($curl_options)) { + $this->ch_options = $curl_options; + } + $this->use_curl = $use_curl; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->setHeader('User-Agent', $this->title.'/'.$this->version.' ('.$rev[1].')'); + } + + /** + * sets a cURL option + * + * @param mixed $option The cURL option (always integer?) + * @param mixed $value The cURL option value + * @access private + */ + function setCurlOption($option, $value) { + $this->debug("setCurlOption option=$option, value="); + $this->appendDebug($this->varDump($value)); + curl_setopt($this->ch, $option, $value); + } + + /** + * sets an HTTP header + * + * @param string $name The name of the header + * @param string $value The value of the header + * @access private + */ + function setHeader($name, $value) { + $this->outgoing_headers[$name] = $value; + $this->debug("set header $name: $value"); + } + + /** + * unsets an HTTP header + * + * @param string $name The name of the header + * @access private + */ + function unsetHeader($name) { + if (isset($this->outgoing_headers[$name])) { + $this->debug("unset header $name"); + unset($this->outgoing_headers[$name]); + } + } + + /** + * sets the URL to which to connect + * + * @param string $url The URL to which to connect + * @access private + */ + function setURL($url) { + $this->url = $url; + + $u = parse_url($url); + foreach($u as $k => $v){ + $this->debug("parsed URL $k = $v"); + $this->$k = $v; + } + + // add any GET params to path + if(isset($u['query']) && $u['query'] != ''){ + $this->path .= '?' . $u['query']; + } + + // set default port + if(!isset($u['port'])){ + if($u['scheme'] == 'https'){ + $this->port = 443; + } else { + $this->port = 80; + } + } + + $this->uri = $this->path; + $this->digest_uri = $this->uri; + + // build headers + if (!isset($u['port'])) { + $this->setHeader('Host', $this->host); + } else { + $this->setHeader('Host', $this->host.':'.$this->port); + } + + if (isset($u['user']) && $u['user'] != '') { + $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); + } + } + + /** + * gets the I/O method to use + * + * @return string I/O method to use (socket|curl|unknown) + * @access private + */ + function io_method() { + if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) + return 'curl'; + if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) + return 'socket'; + return 'unknown'; + } + + /** + * establish an HTTP connection + * + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @return boolean true if connected, false if not + * @access private + */ + function connect($connection_timeout=0,$response_timeout=30){ + // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like + // "regular" socket. + // TODO: disabled for now because OpenSSL must be *compiled* in (not just + // loaded), and until PHP5 stream_get_wrappers is not available. +// if ($this->scheme == 'https') { +// if (version_compare(phpversion(), '4.3.0') >= 0) { +// if (extension_loaded('openssl')) { +// $this->scheme = 'ssl'; +// $this->debug('Using SSL over OpenSSL'); +// } +// } +// } + $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); + if ($this->io_method() == 'socket') { + if (!is_array($this->proxy)) { + $host = $this->host; + $port = $this->port; + } else { + $host = $this->proxy['host']; + $port = $this->proxy['port']; + } + + // use persistent connection + if($this->persistentConnection && isset($this->fp) && is_resource($this->fp)){ + if (!feof($this->fp)) { + $this->debug('Re-use persistent connection'); + return true; + } + fclose($this->fp); + $this->debug('Closed persistent connection at EOF'); + } + + // munge host if using OpenSSL + if ($this->scheme == 'ssl') { + $host = 'ssl://' . $host; + } + $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); + + // open socket + if($connection_timeout > 0){ + $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str, $connection_timeout); + } else { + $this->fp = @fsockopen( $host, $this->port, $this->errno, $this->error_str); + } + + // test pointer + if(!$this->fp) { + $msg = 'Couldn\'t open socket connection to server ' . $this->url; + if ($this->errno) { + $msg .= ', Error ('.$this->errno.'): '.$this->error_str; + } else { + $msg .= ' prior to connect(). This is often a problem looking up the host name.'; + } + $this->debug($msg); + $this->setError($msg); + return false; + } + + // set response timeout + $this->debug('set response timeout to ' . $response_timeout); + socket_set_timeout( $this->fp, $response_timeout); + + $this->debug('socket connected'); + return true; + } else if ($this->io_method() == 'curl') { + if (!extension_loaded('curl')) { +// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); + $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.'); + return false; + } + // Avoid warnings when PHP does not have these options + if (defined('CURLOPT_CONNECTIONTIMEOUT')) + $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; + else + $CURLOPT_CONNECTIONTIMEOUT = 78; + if (defined('CURLOPT_HTTPAUTH')) + $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; + else + $CURLOPT_HTTPAUTH = 107; + if (defined('CURLOPT_PROXYAUTH')) + $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; + else + $CURLOPT_PROXYAUTH = 111; + if (defined('CURLAUTH_BASIC')) + $CURLAUTH_BASIC = CURLAUTH_BASIC; + else + $CURLAUTH_BASIC = 1; + if (defined('CURLAUTH_DIGEST')) + $CURLAUTH_DIGEST = CURLAUTH_DIGEST; + else + $CURLAUTH_DIGEST = 2; + if (defined('CURLAUTH_NTLM')) + $CURLAUTH_NTLM = CURLAUTH_NTLM; + else + $CURLAUTH_NTLM = 8; + + $this->debug('connect using cURL'); + // init CURL + $this->ch = curl_init(); + // set url + $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; + // add path + $hostURL .= $this->path; + $this->setCurlOption(CURLOPT_URL, $hostURL); + // follow location headers (re-directs) + if (ini_get('safe_mode') || ini_get('open_basedir')) { + $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); + $this->debug('safe_mode = '); + $this->appendDebug($this->varDump(ini_get('safe_mode'))); + $this->debug('open_basedir = '); + $this->appendDebug($this->varDump(ini_get('open_basedir'))); + } else { + $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); + } + // ask for headers in the response output + $this->setCurlOption(CURLOPT_HEADER, 1); + // ask for the response output as the return value + $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); + // encode + // We manage this ourselves through headers and encoding +// if(function_exists('gzuncompress')){ +// $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); +// } + // persistent connection + if ($this->persistentConnection) { + // I believe the following comment is now bogus, having applied to + // the code when it used CURLOPT_CUSTOMREQUEST to send the request. + // The way we send data, we cannot use persistent connections, since + // there will be some "junk" at the end of our request. + //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); + $this->persistentConnection = false; + $this->setHeader('Connection', 'close'); + } + // set timeouts + if ($connection_timeout != 0) { + $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); + } + if ($response_timeout != 0) { + $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); + } + + if ($this->scheme == 'https') { + $this->debug('set cURL SSL verify options'); + // recent versions of cURL turn on peer/host checking by default, + // while PHP binaries are not compiled with a default location for the + // CA cert bundle, so disable peer/host checking. + //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); + + // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) + if ($this->authtype == 'certificate') { + $this->debug('set cURL certificate options'); + if (isset($this->certRequest['cainfofile'])) { + $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); + } + if (isset($this->certRequest['verifypeer'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); + } else { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); + } + if (isset($this->certRequest['verifyhost'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); + } else { + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); + } + if (isset($this->certRequest['sslcertfile'])) { + $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); + } + if (isset($this->certRequest['sslkeyfile'])) { + $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); + } + if (isset($this->certRequest['passphrase'])) { + $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); + } + if (isset($this->certRequest['certpassword'])) { + $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); + } + } + } + if ($this->authtype && ($this->authtype != 'certificate')) { + if ($this->username) { + $this->debug('set cURL username/password'); + $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); + } + if ($this->authtype == 'basic') { + $this->debug('set cURL for Basic authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); + } + if ($this->authtype == 'digest') { + $this->debug('set cURL for digest authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); + } + if ($this->authtype == 'ntlm') { + $this->debug('set cURL for NTLM authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); + } + } + if (is_array($this->proxy)) { + $this->debug('set cURL proxy options'); + if ($this->proxy['port'] != '') { + $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'].':'.$this->proxy['port']); + } else { + $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); + } + if ($this->proxy['username'] || $this->proxy['password']) { + $this->debug('set cURL proxy authentication options'); + $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'].':'.$this->proxy['password']); + if ($this->proxy['authtype'] == 'basic') { + $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); + } + if ($this->proxy['authtype'] == 'ntlm') { + $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); + } + } + } + $this->debug('cURL connection set up'); + return true; + } else { + $this->setError('Unknown scheme ' . $this->scheme); + $this->debug('Unknown scheme ' . $this->scheme); + return false; + } + } + + /** + * sends the SOAP request and gets the SOAP response via HTTP[S] + * + * @param string $data message data + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @param array $cookies cookies to send + * @return string data + * @access public + */ + function send($data, $timeout=0, $response_timeout=30, $cookies=NULL) { + + $this->debug('entered send() with data of length: '.strlen($data)); + + $this->tryagain = true; + $tries = 0; + while ($this->tryagain) { + $this->tryagain = false; + if ($tries++ < 2) { + // make connnection + if (!$this->connect($timeout, $response_timeout)){ + return false; + } + + // send request + if (!$this->sendRequest($data, $cookies)){ + return false; + } + + // get response + $respdata = $this->getResponse(); + } else { + $this->setError("Too many tries to get an OK response ($this->response_status_line)"); + } + } + $this->debug('end of send()'); + return $respdata; + } + + + /** + * sends the SOAP request and gets the SOAP response via HTTPS using CURL + * + * @param string $data message data + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @param array $cookies cookies to send + * @return string data + * @access public + * @deprecated + */ + function sendHTTPS($data, $timeout=0, $response_timeout=30, $cookies) { + return $this->send($data, $timeout, $response_timeout, $cookies); + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $digestRequest (keys must be nonce, nc, realm, qop) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); + $this->appendDebug($this->varDump($digestRequest)); + $this->debug("certRequest="); + $this->appendDebug($this->varDump($certRequest)); + // cf. RFC 2617 + if ($authtype == 'basic') { + $this->setHeader('Authorization', 'Basic '.base64_encode(str_replace(':','',$username).':'.$password)); + } elseif ($authtype == 'digest') { + if (isset($digestRequest['nonce'])) { + $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; + + // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) + + // A1 = unq(username-value) ":" unq(realm-value) ":" passwd + $A1 = $username. ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; + + // H(A1) = MD5(A1) + $HA1 = md5($A1); + + // A2 = Method ":" digest-uri-value + $A2 = $this->request_method . ':' . $this->digest_uri; + + // H(A2) + $HA2 = md5($A2); + + // KD(secret, data) = H(concat(secret, ":", data)) + // if qop == auth: + // request-digest = <"> < KD ( H(A1), unq(nonce-value) + // ":" nc-value + // ":" unq(cnonce-value) + // ":" unq(qop-value) + // ":" H(A2) + // ) <"> + // if qop is missing, + // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> + + $unhashedDigest = ''; + $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; + $cnonce = $nonce; + if ($digestRequest['qop'] != '') { + $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; + } else { + $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; + } + + $hashedDigest = md5($unhashedDigest); + + $opaque = ''; + if (isset($digestRequest['opaque'])) { + $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; + } + + $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); + } + } elseif ($authtype == 'certificate') { + $this->certRequest = $certRequest; + $this->debug('Authorization header not set for certificate'); + } elseif ($authtype == 'ntlm') { + // do nothing + $this->debug('Authorization header not set for ntlm'); + } + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->digestRequest = $digestRequest; + } + + /** + * set the soapaction value + * + * @param string $soapaction + * @access public + */ + function setSOAPAction($soapaction) { + $this->setHeader('SOAPAction', '"' . $soapaction . '"'); + } + + /** + * use http encoding + * + * @param string $enc encoding style. supported values: gzip, deflate, or both + * @access public + */ + function setEncoding($enc='gzip, deflate') { + if (function_exists('gzdeflate')) { + $this->protocol_version = '1.1'; + $this->setHeader('Accept-Encoding', $enc); + if (!isset($this->outgoing_headers['Connection'])) { + $this->setHeader('Connection', 'close'); + $this->persistentConnection = false; + } + // deprecated as of PHP 5.3.0 + //set_magic_quotes_runtime(0); + $this->encoding = $enc; + } + } + + /** + * set proxy info here + * + * @param string $proxyhost use an empty string to remove proxy + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @param string $proxyauthtype (basic|ntlm) + * @access public + */ + function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') { + if ($proxyhost) { + $this->proxy = array( + 'host' => $proxyhost, + 'port' => $proxyport, + 'username' => $proxyusername, + 'password' => $proxypassword, + 'authtype' => $proxyauthtype + ); + if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { + $this->setHeader('Proxy-Authorization', ' Basic '.base64_encode($proxyusername.':'.$proxypassword)); + } + } else { + $this->debug('remove proxy'); + $proxy = null; + unsetHeader('Proxy-Authorization'); + } + } + + + /** + * Test if the given string starts with a header that is to be skipped. + * Skippable headers result from chunked transfer and proxy requests. + * + * @param string $data The string to check. + * @returns boolean Whether a skippable header was found. + * @access private + */ + function isSkippableCurlHeader(&$data) { + $skipHeaders = array( 'HTTP/1.1 100', + 'HTTP/1.0 301', + 'HTTP/1.1 301', + 'HTTP/1.0 302', + 'HTTP/1.1 302', + 'HTTP/1.0 401', + 'HTTP/1.1 401', + 'HTTP/1.0 200 Connection established'); + foreach ($skipHeaders as $hd) { + $prefix = substr($data, 0, strlen($hd)); + if ($prefix == $hd) return true; + } + + return false; + } + + /** + * decode a string that is encoded w/ "chunked' transfer encoding + * as defined in RFC2068 19.4.6 + * + * @param string $buffer + * @param string $lb + * @returns string + * @access public + * @deprecated + */ + function decodeChunked($buffer, $lb){ + // length := 0 + $length = 0; + $new = ''; + + // read chunk-size, chunk-extension (if any) and CRLF + // get the position of the linebreak + $chunkend = strpos($buffer, $lb); + if ($chunkend == FALSE) { + $this->debug('no linebreak found in decodeChunked'); + return $new; + } + $temp = substr($buffer,0,$chunkend); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend + strlen($lb); + // while (chunk-size > 0) { + while ($chunk_size > 0) { + $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); + $chunkend = strpos( $buffer, $lb, $chunkstart + $chunk_size); + + // Just in case we got a broken connection + if ($chunkend == FALSE) { + $chunk = substr($buffer,$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + $length += strlen($chunk); + break; + } + + // read chunk-data and CRLF + $chunk = substr($buffer,$chunkstart,$chunkend-$chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + // length := length + chunk-size + $length += strlen($chunk); + // read chunk-size and CRLF + $chunkstart = $chunkend + strlen($lb); + + $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); + if ($chunkend == FALSE) { + break; //Just in case we got a broken connection + } + $temp = substr($buffer,$chunkstart,$chunkend-$chunkstart); + $chunk_size = hexdec( trim($temp) ); + $chunkstart = $chunkend; + } + return $new; + } + + /** + * Writes the payload, including HTTP headers, to $this->outgoing_payload. + * + * @param string $data HTTP body + * @param string $cookie_str data for HTTP Cookie header + * @return void + * @access private + */ + function buildPayload($data, $cookie_str = '') { + // Note: for cURL connections, $this->outgoing_payload is ignored, + // as is the Content-Length header, but these are still created as + // debugging guides. + + // add content-length header + if ($this->request_method != 'GET') { + $this->setHeader('Content-Length', strlen($data)); + } + + // start building outgoing payload: + if ($this->proxy) { + $uri = $this->url; + } else { + $uri = $this->uri; + } + $req = "$this->request_method $uri HTTP/$this->protocol_version"; + $this->debug("HTTP request: $req"); + $this->outgoing_payload = "$req\r\n"; + + // loop thru headers, serializing + foreach($this->outgoing_headers as $k => $v){ + $hdr = $k.': '.$v; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // add any cookies + if ($cookie_str != '') { + $hdr = 'Cookie: '.$cookie_str; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // header/body separator + $this->outgoing_payload .= "\r\n"; + + // add data + $this->outgoing_payload .= $data; + } + + /** + * sends the SOAP request via HTTP[S] + * + * @param string $data message data + * @param array $cookies cookies to send + * @return boolean true if OK, false if problem + * @access private + */ + function sendRequest($data, $cookies = NULL) { + // build cookie string + $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); + + // build payload + $this->buildPayload($data, $cookie_str); + + if ($this->io_method() == 'socket') { + // send payload + if(!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { + $this->setError('couldn\'t write message data to socket'); + $this->debug('couldn\'t write message data to socket'); + return false; + } + $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); + return true; + } else if ($this->io_method() == 'curl') { + // set payload + // cURL does say this should only be the verb, and in fact it + // turns out that the URI and HTTP version are appended to this, which + // some servers refuse to work with (so we no longer use this method!) + //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); + $curl_headers = array(); + foreach($this->outgoing_headers as $k => $v){ + if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { + $this->debug("Skip cURL header $k: $v"); + } else { + $curl_headers[] = "$k: $v"; + } + } + if ($cookie_str != '') { + $curl_headers[] = 'Cookie: ' . $cookie_str; + } + $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); + $this->debug('set cURL HTTP headers'); + if ($this->request_method == "POST") { + $this->setCurlOption(CURLOPT_POST, 1); + $this->setCurlOption(CURLOPT_POSTFIELDS, $data); + $this->debug('set cURL POST data'); + } else { + } + // insert custom user-set cURL options + foreach ($this->ch_options as $key => $val) { + $this->setCurlOption($key, $val); + } + + $this->debug('set cURL payload'); + return true; + } + } + + /** + * gets the SOAP response via HTTP[S] + * + * @return string the response (also sets member variables like incoming_payload) + * @access private + */ + function getResponse(){ + $this->incoming_payload = ''; + + if ($this->io_method() == 'socket') { + // loop until headers have been retrieved + $data = ''; + while (!isset($lb)){ + + // We might EOF during header read. + if(feof($this->fp)) { + $this->incoming_payload = $data; + $this->debug('found no headers before EOF after length ' . strlen($data)); + $this->debug("received before EOF:\n" . $data); + $this->setError('server failed to send headers'); + return false; + } + + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read line of $tmplen bytes: " . trim($tmp)); + + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of headers timed out after length ' . strlen($data)); + $this->debug("read before timeout: " . $data); + $this->setError('socket read of headers timed out'); + return false; + } + + $data .= $tmp; + $pos = strpos($data,"\r\n\r\n"); + if($pos > 1){ + $lb = "\r\n"; + } else { + $pos = strpos($data,"\n\n"); + if($pos > 1){ + $lb = "\n"; + } + } + // remove 100 headers + if (isset($lb) && preg_match('/^HTTP\/1.1 100/',$data)) { + unset($lb); + $data = ''; + }// + } + // store header data + $this->incoming_payload .= $data; + $this->debug('found end of headers after length ' . strlen($data)); + // process headers + $header_data = trim(substr($data,0,$pos)); + $header_array = explode($lb,$header_data); + $this->incoming_headers = array(); + $this->incoming_cookies = array(); + foreach($header_array as $header_line){ + $arr = explode(':',$header_line, 2); + if(count($arr) > 1){ + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + + // loop until msg has been received + if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { + $content_length = 2147483647; // ignore any content-length header + $chunked = true; + $this->debug("want to read chunked content"); + } elseif (isset($this->incoming_headers['content-length'])) { + $content_length = $this->incoming_headers['content-length']; + $chunked = false; + $this->debug("want to read content of length $content_length"); + } else { + $content_length = 2147483647; + $chunked = false; + $this->debug("want to read content to EOF"); + } + $data = ''; + do { + if ($chunked) { + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read chunk line of $tmplen bytes"); + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of chunk length timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of chunk length timed out'); + return false; + } + $content_length = hexdec(trim($tmp)); + $this->debug("chunk length $content_length"); + } + $strlen = 0; + while (($strlen < $content_length) && (!feof($this->fp))) { + $readlen = min(8192, $content_length - $strlen); + $tmp = fread($this->fp, $readlen); + $tmplen = strlen($tmp); + $this->debug("read buffer of $tmplen bytes"); + if (($tmplen == 0) && (!feof($this->fp))) { + $this->incoming_payload = $data; + $this->debug('socket read of body timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of body timed out'); + return false; + } + $strlen += $tmplen; + $data .= $tmp; + } + if ($chunked && ($content_length > 0)) { + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read chunk terminator of $tmplen bytes"); + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of chunk terminator timed out'); + return false; + } + } + } while ($chunked && ($content_length > 0) && (!feof($this->fp))); + if (feof($this->fp)) { + $this->debug('read to EOF'); + } + $this->debug('read body of length ' . strlen($data)); + $this->incoming_payload .= $data; + $this->debug('received a total of '.strlen($this->incoming_payload).' bytes of data from server'); + + // close filepointer + if( + (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || + (! $this->persistentConnection) || feof($this->fp)){ + fclose($this->fp); + $this->fp = false; + $this->debug('closed socket'); + } + + // connection was closed unexpectedly + if($this->incoming_payload == ''){ + $this->setError('no response from server'); + return false; + } + + // decode transfer-encoding +// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ +// if(!$data = $this->decodeChunked($data, $lb)){ +// $this->setError('Decoding of chunked data failed'); +// return false; +// } + //print "
\nde-chunked:\n---------------\n$data\n\n---------------\n
"; + // set decoded payload +// $this->incoming_payload = $header_data.$lb.$lb.$data; +// } + + } else if ($this->io_method() == 'curl') { + // send and receive + $this->debug('send and receive with cURL'); + $this->incoming_payload = curl_exec($this->ch); + $data = $this->incoming_payload; + + $cErr = curl_error($this->ch); + if ($cErr != '') { + $err = 'cURL ERROR: '.curl_errno($this->ch).': '.$cErr.'
'; + // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE + foreach(curl_getinfo($this->ch) as $k => $v){ + $err .= "$k: $v
"; + } + $this->debug($err); + $this->setError($err); + curl_close($this->ch); + return false; + } else { + //echo '
';
+			//var_dump(curl_getinfo($this->ch));
+			//echo '
'; + } + // close curl + $this->debug('No cURL error, closing cURL'); + curl_close($this->ch); + + // try removing skippable headers + $savedata = $data; + while ($this->isSkippableCurlHeader($data)) { + $this->debug("Found HTTP header to skip"); + if ($pos = strpos($data,"\r\n\r\n")) { + $data = ltrim(substr($data,$pos)); + } elseif($pos = strpos($data,"\n\n") ) { + $data = ltrim(substr($data,$pos)); + } + } + + if ($data == '') { + // have nothing left; just remove 100 header(s) + $data = $savedata; + while (preg_match('/^HTTP\/1.1 100/',$data)) { + if ($pos = strpos($data,"\r\n\r\n")) { + $data = ltrim(substr($data,$pos)); + } elseif($pos = strpos($data,"\n\n") ) { + $data = ltrim(substr($data,$pos)); + } + } + } + + // separate content from HTTP headers + if ($pos = strpos($data,"\r\n\r\n")) { + $lb = "\r\n"; + } elseif( $pos = strpos($data,"\n\n")) { + $lb = "\n"; + } else { + $this->debug('no proper separation of headers and document'); + $this->setError('no proper separation of headers and document'); + return false; + } + $header_data = trim(substr($data,0,$pos)); + $header_array = explode($lb,$header_data); + $data = ltrim(substr($data,$pos)); + $this->debug('found proper separation of headers and document'); + $this->debug('cleaned data, stringlen: '.strlen($data)); + // clean headers + foreach ($header_array as $header_line) { + $arr = explode(':',$header_line,2); + if(count($arr) > 1){ + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } else if (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + } + + $this->response_status_line = $header_array[0]; + $arr = explode(' ', $this->response_status_line, 3); + $http_version = $arr[0]; + $http_status = intval($arr[1]); + $http_reason = count($arr) > 2 ? $arr[2] : ''; + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { + $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); + $this->setURL($this->incoming_headers['location']); + $this->tryagain = true; + return false; + } + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { + $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); + if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { + $this->debug('Server wants digest authentication'); + // remove "Digest " from our elements + $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); + + // parse elements into array + $digestElements = explode(',', $digestString); + foreach ($digestElements as $val) { + $tempElement = explode('=', trim($val), 2); + $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); + } + + // should have (at least) qop, realm, nonce + if (isset($digestRequest['nonce'])) { + $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); + $this->tryagain = true; + return false; + } + } + $this->debug('HTTP authentication failed'); + $this->setError('HTTP authentication failed'); + return false; + } + + if ( + ($http_status >= 300 && $http_status <= 307) || + ($http_status >= 400 && $http_status <= 417) || + ($http_status >= 501 && $http_status <= 505) + ) { + $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); + return false; + } + + // decode content-encoding + if(isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != ''){ + if(strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip'){ + // if decoding works, use it. else assume data wasn't gzencoded + if(function_exists('gzinflate')){ + //$timer->setMarker('starting decoding of gzip/deflated content'); + // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) + // this means there are no Zlib headers, although there should be + $this->debug('The gzinflate function exists'); + $datalen = strlen($data); + if ($this->incoming_headers['content-encoding'] == 'deflate') { + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The inflated payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to inflate the payload'); + $this->setError('Error using gzinflate to inflate the payload'); + } + } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { + if ($degzdata = @gzinflate(substr($data, 10))) { // do our best + $data = $degzdata; + $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate(substr($data, 10))) { + $data = $degzdata; + $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to un-gzip the payload'); + $this->setError('Error using gzinflate to un-gzip the payload'); + } + } + //$timer->setMarker('finished decoding of gzip/deflated content'); + //print "\nde-inflated:\n---------------\n$data\n-------------\n"; + // set decoded payload + $this->incoming_payload = $header_data.$lb.$lb.$data; + } else { + $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + } + } else { + $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + } + } else { + $this->debug('No Content-Encoding header'); + } + + if(strlen($data) == 0){ + $this->debug('no data after headers!'); + $this->setError('no data present after HTTP headers'); + return false; + } + + return $data; + } + + /** + * sets the content-type for the SOAP message to be sent + * + * @param string $type the content type, MIME style + * @param mixed $charset character set used for encoding (or false) + * @access public + */ + function setContentType($type, $charset = false) { + $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); + } + + /** + * specifies that an HTTP persistent connection should be used + * + * @return boolean whether the request was honored by this method. + * @access public + */ + function usePersistentConnection(){ + if (isset($this->outgoing_headers['Accept-Encoding'])) { + return false; + } + $this->protocol_version = '1.1'; + $this->persistentConnection = true; + $this->setHeader('Connection', 'Keep-Alive'); + return true; + } + + /** + * parse an incoming Cookie into it's parts + * + * @param string $cookie_str content of cookie + * @return array with data of that cookie + * @access private + */ + /* + * TODO: allow a Set-Cookie string to be parsed into multiple cookies + */ + function parseCookie($cookie_str) { + $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; + $data = preg_split('/;/', $cookie_str); + $value_str = $data[0]; + + $cookie_param = 'domain='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $domain = substr($cookie_str, $start + strlen($cookie_param)); + $domain = substr($domain, 0, strpos($domain, ';')); + } else { + $domain = ''; + } + + $cookie_param = 'expires='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $expires = substr($cookie_str, $start + strlen($cookie_param)); + $expires = substr($expires, 0, strpos($expires, ';')); + } else { + $expires = ''; + } + + $cookie_param = 'path='; + $start = strpos($cookie_str, $cookie_param); + if ( $start > 0 ) { + $path = substr($cookie_str, $start + strlen($cookie_param)); + $path = substr($path, 0, strpos($path, ';')); + } else { + $path = '/'; + } + + $cookie_param = ';secure;'; + if (strpos($cookie_str, $cookie_param) !== FALSE) { + $secure = true; + } else { + $secure = false; + } + + $sep_pos = strpos($value_str, '='); + + if ($sep_pos) { + $name = substr($value_str, 0, $sep_pos); + $value = substr($value_str, $sep_pos + 1); + $cookie= array( 'name' => $name, + 'value' => $value, + 'domain' => $domain, + 'path' => $path, + 'expires' => $expires, + 'secure' => $secure + ); + return $cookie; + } + return false; + } + + /** + * sort out cookies for the current request + * + * @param array $cookies array with all cookies + * @param boolean $secure is the send-content secure or not? + * @return string for Cookie-HTTP-Header + * @access private + */ + function getCookiesForRequest($cookies, $secure=false) { + $cookie_str = ''; + if ((! is_null($cookies)) && (is_array($cookies))) { + foreach ($cookies as $cookie) { + if (! is_array($cookie)) { + continue; + } + $this->debug("check cookie for validity: ".$cookie['name'].'='.$cookie['value']); + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) <= time()) { + $this->debug('cookie has expired'); + continue; + } + } + if ((isset($cookie['domain'])) && (! empty($cookie['domain']))) { + $domain = preg_quote($cookie['domain']); + if (! preg_match("'.*$domain$'i", $this->host)) { + $this->debug('cookie has different domain'); + continue; + } + } + if ((isset($cookie['path'])) && (! empty($cookie['path']))) { + $path = preg_quote($cookie['path']); + if (! preg_match("'^$path.*'i", $this->path)) { + $this->debug('cookie is for a different path'); + continue; + } + } + if ((! $secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { + $this->debug('cookie is secure, transport is not'); + continue; + } + $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; + $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); + } + } + return $cookie_str; + } +} + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soap_val.php b/include/nusoap/class.soap_val.php new file mode 100644 index 0000000..7d3023b --- /dev/null +++ b/include/nusoap/class.soap_val.php @@ -0,0 +1,107 @@ + +* @version $Id: class.soap_val.php,v 1.11 2007/04/06 13:56:32 snichol Exp $ +* @access public +*/ +class soapval extends nusoap_base { + /** + * The XML element name + * + * @var string + * @access private + */ + var $name; + /** + * The XML type name (string or false) + * + * @var mixed + * @access private + */ + var $type; + /** + * The PHP value + * + * @var mixed + * @access private + */ + var $value; + /** + * The XML element namespace (string or false) + * + * @var mixed + * @access private + */ + var $element_ns; + /** + * The XML type namespace (string or false) + * + * @var mixed + * @access private + */ + var $type_ns; + /** + * The XML element attributes (array or false) + * + * @var mixed + * @access private + */ + var $attributes; + + /** + * constructor + * + * @param string $name optional name + * @param mixed $type optional type name + * @param mixed $value optional value + * @param mixed $element_ns optional namespace of value + * @param mixed $type_ns optional namespace of type + * @param mixed $attributes associative array of attributes to add to element serialization + * @access public + */ + function __construct($name='soapval',$type=false,$value=-1,$element_ns=false,$type_ns=false,$attributes=false) { + parent::__construct(); + $this->name = $name; + $this->type = $type; + $this->value = $value; + $this->element_ns = $element_ns; + $this->type_ns = $type_ns; + $this->attributes = $attributes; + } + + /** + * return serialized value + * + * @param string $use The WSDL use value (encoded|literal) + * @return string XML data + * @access public + */ + function serialize($use='encoded') { + return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); + } + + /** + * decodes a soapval object into a PHP native type + * + * @return mixed + * @access public + */ + function decode(){ + return $this->value; + } +} + + + + +?> \ No newline at end of file diff --git a/include/nusoap/class.soapclient.php b/include/nusoap/class.soapclient.php new file mode 100644 index 0000000..7a9e5e7 --- /dev/null +++ b/include/nusoap/class.soapclient.php @@ -0,0 +1,991 @@ +call( string methodname [ ,array parameters] ); +* +* // bye bye client +* unset($soapclient); +* +* @author Dietrich Ayala +* @author Scott Nichol +* @version $Id: class.soapclient.php,v 1.69 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class nusoap_client extends nusoap_base { + + var $username = ''; // Username for HTTP authentication + var $password = ''; // Password for HTTP authentication + var $authtype = ''; // Type of HTTP authentication + var $certRequest = array(); // Certificate for HTTP SSL authentication + var $requestHeaders = false; // SOAP headers in request (text) + var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) + var $responseHeader = NULL; // SOAP Header from response (parsed) + var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) + var $endpoint; + var $forceEndpoint = ''; // overrides WSDL endpoint + var $proxyhost = ''; + var $proxyport = ''; + var $proxyusername = ''; + var $proxypassword = ''; + var $portName = ''; // port name to use in WSDL + var $xml_encoding = ''; // character set encoding of incoming (response) messages + var $http_encoding = false; + var $timeout = 0; // HTTP connection timeout + var $response_timeout = 30; // HTTP response timeout + var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error + var $persistentConnection = false; + var $defaultRpcParams = false; // This is no longer used + var $request = ''; // HTTP request + var $response = ''; // HTTP response + var $responseData = ''; // SOAP payload of response + var $cookies = array(); // Cookies from response or for request + var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() + var $operations = array(); // WSDL operations, empty for WSDL initialization error + var $curl_options = array(); // User-specified cURL options + var $bindingType = ''; // WSDL operation binding type + var $use_curl = false; // whether to always try to use cURL + + /* + * fault related variables + */ + /** + * @var fault + * @access public + */ + var $fault; + /** + * @var faultcode + * @access public + */ + var $faultcode; + /** + * @var faultstring + * @access public + */ + var $faultstring; + /** + * @var faultdetail + * @access public + */ + var $faultdetail; + + /** + * constructor + * + * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) + * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL + * @param string $proxyhost optional + * @param string $proxyport optional + * @param string $proxyusername optional + * @param string $proxypassword optional + * @param integer $timeout set the connection timeout + * @param integer $response_timeout set the response timeout + * @param string $portName optional portName in WSDL document + * @access public + */ + function __construct($endpoint,$wsdl = false,$proxyhost = false,$proxyport = false,$proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = ''){ + parent::__construct(); + $this->endpoint = $endpoint; + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + $this->timeout = $timeout; + $this->response_timeout = $response_timeout; + $this->portName = $portName; + + $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); + $this->appendDebug('endpoint=' . $this->varDump($endpoint)); + + // make values + if($wsdl){ + if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { + $this->wsdl = $endpoint; + $this->endpoint = $this->wsdl->wsdl; + $this->wsdlFile = $this->endpoint; + $this->debug('existing wsdl instance created from ' . $this->endpoint); + $this->checkWSDL(); + } else { + $this->wsdlFile = $this->endpoint; + $this->wsdl = null; + $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); + } + $this->endpointType = 'wsdl'; + } else { + $this->debug("instantiate SOAP with endpoint at $endpoint"); + $this->endpointType = 'soap'; + } + } + + /** + * calls method, returns PHP native type + * + * @param string $operation SOAP server URL or path + * @param mixed $params An array, associative or simple, of the parameters + * for the method call, or a string that is the XML + * for the call. For rpc style, this call will + * wrap the XML in a tag named after the method, as + * well as the SOAP Envelope and Body. For document + * style, this will only wrap with the Envelope and Body. + * IMPORTANT: when using an array with document style, + * in which case there + * is really one parameter, the root of the fragment + * used in the call, which encloses what programmers + * normally think of parameters. A parameter array + * *must* include the wrapper. + * @param string $namespace optional method namespace (WSDL can override) + * @param string $soapAction optional SOAPAction value (WSDL can override) + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array + * @param boolean $rpcParams optional (no longer used) + * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) + * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) + * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors + * @access public + */ + function call($operation,$params=array(),$namespace='http://tempuri.org',$soapAction='',$headers=false,$rpcParams=null,$style='rpc',$use='encoded'){ + $this->operation = $operation; + $this->fault = false; + $this->setError(''); + $this->request = ''; + $this->response = ''; + $this->responseData = ''; + $this->faultstring = ''; + $this->faultcode = ''; + $this->opData = array(); + + $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); + $this->appendDebug('params=' . $this->varDump($params)); + $this->appendDebug('headers=' . $this->varDump($headers)); + if ($headers) { + $this->requestHeaders = $headers; + } + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) + return false; + } + // serialize parameters + if($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)){ + // use WSDL for operation + $this->opData = $opData; + $this->debug("found operation"); + $this->appendDebug('opData=' . $this->varDump($opData)); + if (isset($opData['soapAction'])) { + $soapAction = $opData['soapAction']; + } + if (! $this->forceEndpoint) { + $this->endpoint = $opData['endpoint']; + } else { + $this->endpoint = $this->forceEndpoint; + } + $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; + $style = $opData['style']; + $use = $opData['input']['use']; + // add ns to ns array + if($namespace != '' && !isset($this->wsdl->namespaces[$namespace])){ + $nsPrefix = 'ns' . rand(1000, 9999); + $this->wsdl->namespaces[$nsPrefix] = $namespace; + } + $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); + // serialize payload + if (is_string($params)) { + $this->debug("serializing param string for WSDL operation $operation"); + $payload = $params; + } elseif (is_array($params)) { + $this->debug("serializing param array for WSDL operation $operation"); + $payload = $this->wsdl->serializeRPCParameters($operation,'input',$params,$this->bindingType); + } else { + $this->debug('params must be array or string'); + $this->setError('params must be array or string'); + return false; + } + $usedNamespaces = $this->wsdl->usedNamespaces; + if (isset($opData['input']['encodingStyle'])) { + $encodingStyle = $opData['input']['encodingStyle']; + } else { + $encodingStyle = ''; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if ($errstr = $this->wsdl->getError()) { + $this->debug('got wsdl error: '.$errstr); + $this->setError('wsdl error: '.$errstr); + return false; + } + } elseif($this->endpointType == 'wsdl') { + // operation not in WSDL + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->setError('operation '.$operation.' not present in WSDL.'); + $this->debug("operation '$operation' not present in WSDL."); + return false; + } else { + // no WSDL + //$this->namespaces['ns1'] = $namespace; + $nsPrefix = 'ns' . rand(1000, 9999); + // serialize + $payload = ''; + if (is_string($params)) { + $this->debug("serializing param string for operation $operation"); + $payload = $params; + } elseif (is_array($params)) { + $this->debug("serializing param array for operation $operation"); + foreach($params as $k => $v){ + $payload .= $this->serialize_val($v,$k,false,false,false,false,$use); + } + } else { + $this->debug('params must be array or string'); + $this->setError('params must be array or string'); + return false; + } + $usedNamespaces = array(); + if ($use == 'encoded') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } else { + $encodingStyle = ''; + } + } + // wrap RPC calls with method element + if ($style == 'rpc') { + if ($use == 'literal') { + $this->debug("wrapping RPC request with literal method element"); + if ($namespace) { + // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + ""; + } else { + $payload = "<$operation>" . $payload . ""; + } + } else { + $this->debug("wrapping RPC request with encoded method element"); + if ($namespace) { + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + ""; + } else { + $payload = "<$operation>" . + $payload . + ""; + } + } + } + // serialize envelope + $soapmsg = $this->serializeEnvelope($payload,$this->requestHeaders,$usedNamespaces,$style,$use,$encodingStyle); + $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); + $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); + // send + $return = $this->send($this->getHTTPBody($soapmsg),$soapAction,$this->timeout,$this->response_timeout); + if($errstr = $this->getError()){ + $this->debug('Error: '.$errstr); + return false; + } else { + $this->return = $return; + $this->debug('sent message successfully and got a(n) '.gettype($return)); + $this->appendDebug('return=' . $this->varDump($return)); + + // fault? + if(is_array($return) && isset($return['faultcode'])){ + $this->debug('got fault'); + $this->setError($return['faultcode'].': '.$return['faultstring']); + $this->fault = true; + foreach($return as $k => $v){ + $this->$k = $v; + $this->debug("$k = $v
"); + } + return $return; + } elseif ($style == 'document') { + // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), + // we are only going to return the first part here...sorry about that + return $return; + } else { + // array of return values + if(is_array($return)){ + // multiple 'out' parameters, which we return wrapped up + // in the array + if(sizeof($return) > 1){ + return $return; + } + // single 'out' parameter (normally the return value) + $return = array_shift($return); + $this->debug('return shifted value: '); + $this->appendDebug($this->varDump($return)); + return $return; + // nothing returned (ie, echoVoid) + } else { + return ""; + } + } + } + } + + /** + * check WSDL passed as an instance or pulled from an endpoint + * + * @access private + */ + function checkWSDL() { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('checkWSDL'); + // catch errors + if ($errstr = $this->wsdl->getError()) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('got wsdl error: '.$errstr); + $this->setError('wsdl error: '.$errstr); + } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->bindingType = 'soap'; + $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); + } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->bindingType = 'soap12'; + $this->debug('got '.count($this->operations).' operations from wsdl '.$this->wsdlFile.' for binding type '.$this->bindingType); + $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); + } else { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('getOperations returned false'); + $this->setError('no operations defined in the WSDL document!'); + } + } + + /** + * instantiate wsdl object and parse wsdl file + * + * @access public + */ + function loadWSDL() { + $this->debug('instantiating wsdl class with doc: '.$this->wsdlFile); + $this->wsdl = new wsdl('',$this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword,$this->timeout,$this->response_timeout,$this->curl_options,$this->use_curl); + $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); + $this->wsdl->fetchWSDL($this->wsdlFile); + $this->checkWSDL(); + } + + /** + * get available data pertaining to an operation + * + * @param string $operation operation name + * @return array array of data pertaining to the operation + * @access public + */ + function getOperationData($operation){ + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) + return false; + } + if(isset($this->operations[$operation])){ + return $this->operations[$operation]; + } + $this->debug("No data for operation: $operation"); + } + + /** + * send the SOAP message + * + * Note: if the operation has multiple return values + * the return value of this method will be an array + * of those values. + * + * @param string $msg a SOAPx4 soapmsg object + * @param string $soapaction SOAPAction value + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @return mixed native PHP types. + * @access private + */ + function send($msg, $soapaction = '', $timeout=0, $response_timeout=30) { + $this->checkCookies(); + // detect transport + switch(true){ + // http(s) + case preg_match('/^http/',$this->endpoint): + $this->debug('transporting via HTTP'); + if($this->persistentConnection == true && is_object($this->persistentConnection)){ + $http =& $this->persistentConnection; + } else { + $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); + if ($this->persistentConnection) { + $http->usePersistentConnection(); + } + } + $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); + $http->setSOAPAction($soapaction); + if($this->proxyhost && $this->proxyport){ + $http->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); + } + if($this->authtype != '') { + $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + if($this->http_encoding != ''){ + $http->setEncoding($this->http_encoding); + } + $this->debug('sending message, length='.strlen($msg)); + if(preg_match('/^http:/',$this->endpoint)){ + //if(strpos($this->endpoint,'http:')){ + $this->responseData = $http->send($msg,$timeout,$response_timeout,$this->cookies); + } elseif(preg_match('/^https/',$this->endpoint)){ + //} elseif(strpos($this->endpoint,'https:')){ + //if(phpversion() == '4.3.0-dev'){ + //$response = $http->send($msg,$timeout,$response_timeout); + //$this->request = $http->outgoing_payload; + //$this->response = $http->incoming_payload; + //} else + $this->responseData = $http->sendHTTPS($msg,$timeout,$response_timeout,$this->cookies); + } else { + $this->setError('no http/s in endpoint url'); + } + $this->request = $http->outgoing_payload; + $this->response = $http->incoming_payload; + $this->appendDebug($http->getDebug()); + $this->UpdateCookies($http->incoming_cookies); + + // save transport object if using persistent connections + if ($this->persistentConnection) { + $http->clearDebug(); + if (!is_object($this->persistentConnection)) { + $this->persistentConnection = $http; + } + } + + if($err = $http->getError()){ + $this->setError('HTTP Error: '.$err); + return false; + } elseif($this->getError()){ + return false; + } else { + $this->debug('got response, length='. strlen($this->responseData).' type='.$http->incoming_headers['content-type']); + return $this->parseResponse($http->incoming_headers, $this->responseData); + } + break; + default: + $this->setError('no transport found, or selected transport is not yet supported!'); + return false; + break; + } + } + + /** + * processes SOAP message returned from server + * + * @param array $headers The HTTP headers + * @param string $data unprocessed response data from server + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseResponse($headers, $data) { + $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Response not of type text/xml (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], 'text/xml')) { + $this->setError('Response not of type text/xml: ' . $headers['content-type']); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if(preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i',$enc)){ + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + $parser = new nusoap_parser($data,$this->xml_encoding,property_exists($this, 'operation') ? $this->operation : '',$this->decode_utf8); + // add parser debug data to our debug + $this->appendDebug($parser->getDebug()); + // if parse errors + if($errstr = $parser->getError()){ + $this->setError( $errstr); + // destroy the parser object + unset($parser); + return false; + } else { + // get SOAP headers + $this->responseHeaders = $parser->getHeaders(); + // get SOAP headers + $this->responseHeader = $parser->get_soapheader(); + // get decoded message + $return = $parser->get_soapbody(); + // add document for doclit support + $this->document = $parser->document; + // destroy the parser object + unset($parser); + // return decode message + return $return; + } + } + + /** + * sets user-specified cURL options + * + * @param mixed $option The cURL option (always integer?) + * @param mixed $value The cURL option value + * @access public + */ + function setCurlOption($option, $value) { + $this->debug("setCurlOption option=$option, value="); + $this->appendDebug($this->varDump($value)); + $this->curl_options[$option] = $value; + } + + /** + * sets the SOAP endpoint, which can override WSDL + * + * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override + * @access public + */ + function setEndpoint($endpoint) { + $this->debug("setEndpoint(\"$endpoint\")"); + $this->forceEndpoint = $endpoint; + } + + /** + * set the SOAP headers + * + * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers + * @access public + */ + function setHeaders($headers){ + $this->debug("setHeaders headers="); + $this->appendDebug($this->varDump($headers)); + $this->requestHeaders = $headers; + } + + /** + * get the SOAP response headers (namespace resolution incomplete) + * + * @return string + * @access public + */ + function getHeaders(){ + return $this->responseHeaders; + } + + /** + * get the SOAP response Header (parsed) + * + * @return mixed + * @access public + */ + function getHeader(){ + return $this->responseHeader; + } + + /** + * set proxy info here + * + * @param string $proxyhost + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @access public + */ + function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') { + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype certRequest="); + $this->appendDebug($this->varDump($certRequest)); + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + /** + * use HTTP encoding + * + * @param string $enc HTTP encoding + * @access public + */ + function setHTTPEncoding($enc='gzip, deflate'){ + $this->debug("setHTTPEncoding(\"$enc\")"); + $this->http_encoding = $enc; + } + + /** + * Set whether to try to use cURL connections if possible + * + * @param boolean $use Whether to try to use cURL + * @access public + */ + function setUseCURL($use) { + $this->debug("setUseCURL($use)"); + $this->use_curl = $use; + } + + /** + * use HTTP persistent connections if possible + * + * @access public + */ + function useHTTPPersistentConnection(){ + $this->debug("useHTTPPersistentConnection"); + $this->persistentConnection = true; + } + + /** + * gets the default RPC parameter setting. + * If true, default is that call params are like RPC even for document style. + * Each call() can override this value. + * + * This is no longer used. + * + * @return boolean + * @access public + * @deprecated + */ + function getDefaultRpcParams() { + return $this->defaultRpcParams; + } + + /** + * sets the default RPC parameter setting. + * If true, default is that call params are like RPC even for document style + * Each call() can override this value. + * + * This is no longer used. + * + * @param boolean $rpcParams + * @access public + * @deprecated + */ + function setDefaultRpcParams($rpcParams) { + $this->defaultRpcParams = $rpcParams; + } + + /** + * dynamically creates an instance of a proxy class, + * allowing user to directly call methods from wsdl + * + * @return object soap_proxy object + * @access public + */ + function getProxy() { + $r = rand(); + $evalStr = $this->_getProxyClassCode($r); + //$this->debug("proxy class: $evalStr"); + if ($this->getError()) { + $this->debug("Error from _getProxyClassCode, so return NULL"); + return null; + } + // eval the class + eval($evalStr); + // instantiate proxy object + eval("\$proxy = new nusoap_proxy_$r('');"); + // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice + $proxy->endpointType = 'wsdl'; + $proxy->wsdlFile = $this->wsdlFile; + $proxy->wsdl = $this->wsdl; + $proxy->operations = $this->operations; + $proxy->defaultRpcParams = $this->defaultRpcParams; + // transfer other state + $proxy->soap_defencoding = $this->soap_defencoding; + $proxy->username = $this->username; + $proxy->password = $this->password; + $proxy->authtype = $this->authtype; + $proxy->certRequest = $this->certRequest; + $proxy->requestHeaders = $this->requestHeaders; + $proxy->endpoint = $this->endpoint; + $proxy->forceEndpoint = $this->forceEndpoint; + $proxy->proxyhost = $this->proxyhost; + $proxy->proxyport = $this->proxyport; + $proxy->proxyusername = $this->proxyusername; + $proxy->proxypassword = $this->proxypassword; + $proxy->http_encoding = $this->http_encoding; + $proxy->timeout = $this->timeout; + $proxy->response_timeout = $this->response_timeout; + $proxy->persistentConnection = &$this->persistentConnection; + $proxy->decode_utf8 = $this->decode_utf8; + $proxy->curl_options = $this->curl_options; + $proxy->bindingType = $this->bindingType; + $proxy->use_curl = $this->use_curl; + return $proxy; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access private + */ + function _getProxyClassCode($r) { + $this->debug("in getProxy endpointType=$this->endpointType"); + $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); + if ($this->endpointType != 'wsdl') { + $evalStr = 'A proxy can only be created for a WSDL client'; + $this->setError($evalStr); + $evalStr = "echo \"$evalStr\";"; + return $evalStr; + } + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) { + return "echo \"" . $this->getError() . "\";"; + } + } + $evalStr = ''; + foreach ($this->operations as $operation => $opData) { + if ($operation != '') { + // create param string and param comment string + if (sizeof($opData['input']['parts']) > 0) { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = ''; + foreach ($opData['input']['parts'] as $name => $type) { + $paramStr .= "\$$name, "; + $paramArrayStr .= "'$name' => \$$name, "; + $paramCommentStr .= "$type \$$name, "; + } + $paramStr = substr($paramStr, 0, strlen($paramStr)-2); + $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr)-2); + $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr)-2); + } else { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = 'void'; + } + $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; + $evalStr .= "// $paramCommentStr + function " . str_replace('.', '__', $operation) . "($paramStr) { + \$params = array($paramArrayStr); + return \$this->call('$operation', \$params, '".$opData['namespace']."', '".(isset($opData['soapAction']) ? $opData['soapAction'] : '')."'); + } + "; + unset($paramStr); + unset($paramCommentStr); + } + } + $evalStr = 'class nusoap_proxy_'.$r.' extends nusoap_client { + '.$evalStr.' +}'; + return $evalStr; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access public + */ + function getProxyClassCode() { + $r = rand(); + return $this->_getProxyClassCode($r); + } + + /** + * gets the HTTP body for the current request. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current request. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current request. + * @access private + */ + function getHTTPContentType() { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current request. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current request. + * @access private + */ + function getHTTPContentTypeCharset() { + return $this->soap_defencoding; + } + + /* + * whether or not parser should decode utf8 element content + * + * @return always returns true + * @access public + */ + function decodeUTF8($bool){ + $this->decode_utf8 = $bool; + return true; + } + + /** + * adds a new Cookie into $this->cookies array + * + * @param string $name Cookie Name + * @param string $value Cookie Value + * @return boolean if cookie-set was successful returns true, else false + * @access public + */ + function setCookie($name, $value) { + if (strlen($name) == 0) { + return false; + } + $this->cookies[] = array('name' => $name, 'value' => $value); + return true; + } + + /** + * gets all Cookies + * + * @return array with all internal cookies + * @access public + */ + function getCookies() { + return $this->cookies; + } + + /** + * checks all Cookies and delete those which are expired + * + * @return boolean always return true + * @access private + */ + function checkCookies() { + if (sizeof($this->cookies) == 0) { + return true; + } + $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); + $curr_cookies = $this->cookies; + $this->cookies = array(); + foreach ($curr_cookies as $cookie) { + if (! is_array($cookie)) { + $this->debug('Remove cookie that is not an array'); + continue; + } + if ((isset($cookie['expires'])) && (! empty($cookie['expires']))) { + if (strtotime($cookie['expires']) > time()) { + $this->cookies[] = $cookie; + } else { + $this->debug('Remove expired cookie ' . $cookie['name']); + } + } else { + $this->cookies[] = $cookie; + } + } + $this->debug('checkCookie: '.sizeof($this->cookies).' cookies left in array'); + return true; + } + + /** + * updates the current cookies with a new set + * + * @param array $cookies new cookies with which to update current ones + * @return boolean always return true + * @access private + */ + function UpdateCookies($cookies) { + if (sizeof($this->cookies) == 0) { + // no existing cookies: take whatever is new + if (sizeof($cookies) > 0) { + $this->debug('Setting new cookie(s)'); + $this->cookies = $cookies; + } + return true; + } + if (sizeof($cookies) == 0) { + // no new cookies: keep what we've got + return true; + } + // merge + foreach ($cookies as $newCookie) { + if (!is_array($newCookie)) { + continue; + } + if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { + continue; + } + $newName = $newCookie['name']; + + $found = false; + for ($i = 0; $i < count($this->cookies); $i++) { + $cookie = $this->cookies[$i]; + if (!is_array($cookie)) { + continue; + } + if (!isset($cookie['name'])) { + continue; + } + if ($newName != $cookie['name']) { + continue; + } + $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; + $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; + if ($newDomain != $domain) { + continue; + } + $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; + $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; + if ($newPath != $path) { + continue; + } + $this->cookies[$i] = $newCookie; + $found = true; + $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); + break; + } + if (! $found) { + $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); + $this->cookies[] = $newCookie; + } + } + return true; + } +} + +if (!extension_loaded('soap')) { + /** + * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. + */ + class soapclient extends nusoap_client { + } +} +?> diff --git a/include/nusoap/class.wsdl.php b/include/nusoap/class.wsdl.php new file mode 100644 index 0000000..6f124e7 --- /dev/null +++ b/include/nusoap/class.wsdl.php @@ -0,0 +1,1939 @@ + +* @author Scott Nichol +* @version $Id: class.wsdl.php,v 1.76 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class wsdl extends nusoap_base { + // URL or filename of the root of this WSDL + var $wsdl; + // define internal arrays of bindings, ports, operations, messages, etc. + var $schemas = array(); + var $currentSchema; + var $message = array(); + var $complexTypes = array(); + var $messages = array(); + var $currentMessage; + var $currentOperation; + var $portTypes = array(); + var $currentPortType; + var $bindings = array(); + var $currentBinding; + var $ports = array(); + var $currentPort; + var $opData = array(); + var $status = ''; + var $documentation = false; + var $endpoint = ''; + // array of wsdl docs to import + var $import = array(); + // parser vars + var $parser; + var $position = 0; + var $depth = 0; + var $depth_array = array(); + // for getting wsdl + var $proxyhost = ''; + var $proxyport = ''; + var $proxyusername = ''; + var $proxypassword = ''; + var $timeout = 0; + var $response_timeout = 30; + var $curl_options = array(); // User-specified cURL options + var $use_curl = false; // whether to always try to use cURL + // for HTTP authentication + var $username = ''; // Username for HTTP authentication + var $password = ''; // Password for HTTP authentication + var $authtype = ''; // Type of HTTP authentication + var $certRequest = array(); // Certificate for HTTP SSL authentication + + /** + * constructor + * + * @param string $wsdl WSDL document URL + * @param string $proxyhost + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @param integer $timeout set the connection timeout + * @param integer $response_timeout set the response timeout + * @param array $curl_options user-specified cURL options + * @param boolean $use_curl try to use cURL + * @access public + */ + function __construct($wsdl = '',$proxyhost=false,$proxyport=false,$proxyusername=false,$proxypassword=false,$timeout=0,$response_timeout=30,$curl_options=null,$use_curl=false){ + parent::__construct(); + $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + $this->timeout = $timeout; + $this->response_timeout = $response_timeout; + if (is_array($curl_options)) + $this->curl_options = $curl_options; + $this->use_curl = $use_curl; + $this->fetchWSDL($wsdl); + } + + /** + * fetches the WSDL document and parses it + * + * @access public + */ + function fetchWSDL($wsdl) { + $this->debug("parse and process WSDL path=$wsdl"); + $this->wsdl = $wsdl; + // parse wsdl file + if ($this->wsdl != "") { + $this->parseWSDL($this->wsdl); + } + // imports + // TODO: handle imports more properly, grabbing them in-line and nesting them + $imported_urls = array(); + $imported = 1; + while ($imported > 0) { + $imported = 0; + // Schema imports + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! + foreach ($xs->imports as $ns2 => $list2) { + for ($ii = 0; $ii < count($list2); $ii++) { + if (! $list2[$ii]['loaded']) { + $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true; + $url = $list2[$ii]['location']; + if ($url != '') { + $urlparts = parse_url($url); + if (!isset($urlparts['host'])) { + $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' .$wsdlparts['port'] : '') . + substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; + } + if (! in_array($url, $imported_urls)) { + $this->parseWSDL($url); + $imported++; + $imported_urls[] = $url; + } + } else { + $this->debug("Unexpected scenario: empty URL for unloaded import"); + } + } + } + } + } + } + // WSDL imports + $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! + foreach ($this->import as $ns => $list) { + for ($ii = 0; $ii < count($list); $ii++) { + if (! $list[$ii]['loaded']) { + $this->import[$ns][$ii]['loaded'] = true; + $url = $list[$ii]['location']; + if ($url != '') { + $urlparts = parse_url($url); + if (!isset($urlparts['host'])) { + $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . + substr($wsdlparts['path'],0,strrpos($wsdlparts['path'],'/') + 1) .$urlparts['path']; + } + if (! in_array($url, $imported_urls)) { + $this->parseWSDL($url); + $imported++; + $imported_urls[] = $url; + } + } else { + $this->debug("Unexpected scenario: empty URL for unloaded import"); + } + } + } + } + } + // add new data to operation data + foreach($this->bindings as $binding => $bindingData) { + if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { + foreach($bindingData['operations'] as $operation => $data) { + $this->debug('post-parse data gathering for ' . $operation); + $this->bindings[$binding]['operations'][$operation]['input'] = + isset($this->bindings[$binding]['operations'][$operation]['input']) ? + array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[ $bindingData['portType'] ][$operation]['input']) : + $this->portTypes[ $bindingData['portType'] ][$operation]['input']; + $this->bindings[$binding]['operations'][$operation]['output'] = + isset($this->bindings[$binding]['operations'][$operation]['output']) ? + array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[ $bindingData['portType'] ][$operation]['output']) : + $this->portTypes[ $bindingData['portType'] ][$operation]['output']; + if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ])){ + $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['input']['message'] ]; + } + if(isset($this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ])){ + $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[ $this->bindings[$binding]['operations'][$operation]['output']['message'] ]; + } + // Set operation style if necessary, but do not override one already provided + if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { + $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; + } + $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; + $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[ $bindingData['portType'] ][$operation]['documentation']) ? $this->portTypes[ $bindingData['portType'] ][$operation]['documentation'] : ''; + $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; + } + } + } + } + + /** + * parses the wsdl document + * + * @param string $wsdl path or URL + * @access private + */ + function parseWSDL($wsdl = '') { + $this->debug("parse WSDL at path=$wsdl"); + + if ($wsdl == '') { + $this->debug('no wsdl passed to parseWSDL()!!'); + $this->setError('no wsdl passed to parseWSDL()!!'); + return false; + } + + // parse $wsdl for url format + $wsdl_props = parse_url($wsdl); + + if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { + $this->debug('getting WSDL http(s) URL ' . $wsdl); + // get wsdl + $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); + $tr->request_method = 'GET'; + $tr->useSOAPAction = false; + if($this->proxyhost && $this->proxyport){ + $tr->setProxy($this->proxyhost,$this->proxyport,$this->proxyusername,$this->proxypassword); + } + if ($this->authtype != '') { + $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + $tr->setEncoding('gzip, deflate'); + $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); + //$this->debug("WSDL request\n" . $tr->outgoing_payload); + //$this->debug("WSDL response\n" . $tr->incoming_payload); + $this->appendDebug($tr->getDebug()); + // catch errors + if($err = $tr->getError() ){ + $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: '.$err; + $this->debug($errstr); + $this->setError($errstr); + unset($tr); + return false; + } + unset($tr); + $this->debug("got WSDL URL"); + } else { + // $wsdl is not http(s), so treat it as a file URL or plain file path + if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { + $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; + } else { + $path = $wsdl; + } + $this->debug('getting WSDL file ' . $path); + if ($fp = @fopen($path, 'r')) { + $wsdl_string = ''; + while ($data = fread($fp, 32768)) { + $wsdl_string .= $data; + } + fclose($fp); + } else { + $errstr = "Bad path to WSDL file $path"; + $this->debug($errstr); + $this->setError($errstr); + return false; + } + } + $this->debug('Parse WSDL'); + // end new code added + // Create an XML parser. + $this->parser = xml_parser_create(); + // Set the options for parsing the XML data. + // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + // Set the object for the parser. + xml_set_object($this->parser, $this); + // Set the element handlers for the parser. + xml_set_element_handler($this->parser, 'start_element', 'end_element'); + xml_set_character_data_handler($this->parser, 'character_data'); + // Parse the XML file. + if (!xml_parse($this->parser, $wsdl_string, true)) { + // Display an error message. + $errstr = sprintf( + 'XML error parsing WSDL from %s on line %d: %s', + $wsdl, + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser)) + ); + $this->debug($errstr); + $this->debug("XML payload:\n" . $wsdl_string); + $this->setError($errstr); + return false; + } + // free the parser + xml_parser_free($this->parser); + unset($this->parser); + $this->debug('Parsing WSDL done'); + // catch wsdl parse errors + if($this->getError()){ + return false; + } + return true; + } + + /** + * start-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @param string $attrs associative array of attributes + * @access private + */ + function start_element($parser, $name, $attrs) + { + if ($this->status == 'schema') { + $this->currentSchema->schemaStartElement($parser, $name, $attrs); + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } elseif (preg_match('/schema$/', $name)) { + $this->debug('Parsing WSDL schema'); + // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); + $this->status = 'schema'; + $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); + $this->currentSchema->schemaStartElement($parser, $name, $attrs); + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } else { + // position in the total number of elements, starting from 0 + $pos = $this->position++; + $depth = $this->depth++; + // set self as current value for this depth + $this->depth_array[$depth] = $pos; + $this->message[$pos] = array('cdata' => ''); + // process attributes + if (count($attrs) > 0) { + // register namespace declarations + foreach($attrs as $k => $v) { + if (preg_match('/^xmlns/',$k)) { + if ($ns_prefix = substr(strrchr($k, ':'), 1)) { + $this->namespaces[$ns_prefix] = $v; + } else { + $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; + } + if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v . '-instance'; + } + } + } + // expand each attribute prefix to its namespace + foreach($attrs as $k => $v) { + $k = strpos($k, ':') ? $this->expandQname($k) : $k; + if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { + $v = strpos($v, ':') ? $this->expandQname($v) : $v; + } + $eAttrs[$k] = $v; + } + $attrs = $eAttrs; + } else { + $attrs = array(); + } + // get element prefix, namespace and name + if (preg_match('/:/', $name)) { + // get ns prefix + $prefix = substr($name, 0, strpos($name, ':')); + // get ns + $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; + // get unqualified name + $name = substr(strstr($name, ':'), 1); + } + // process attributes, expanding any prefixes to namespaces + // find status, register data + switch ($this->status) { + case 'message': + if ($name == 'part') { + if (isset($attrs['type'])) { + $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); + $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; + } + if (isset($attrs['element'])) { + $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); + $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; + } + } + break; + case 'portType': + switch ($name) { + case 'operation': + $this->currentPortOperation = $attrs['name']; + $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); + if (isset($attrs['parameterOrder'])) { + $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; + } + break; + case 'documentation': + $this->documentation = true; + break; + // merge input/output data + default: + $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; + $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; + break; + } + break; + case 'binding': + switch ($name) { + case 'binding': + // get ns prefix + if (isset($attrs['style'])) { + $this->bindings[$this->currentBinding]['prefix'] = $prefix; + } + $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); + break; + case 'header': + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; + break; + case 'operation': + if (isset($attrs['soapAction'])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; + } + if (isset($attrs['style'])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; + } + if (isset($attrs['name'])) { + $this->currentOperation = $attrs['name']; + $this->debug("current binding operation: $this->currentOperation"); + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; + } + break; + case 'input': + $this->opStatus = 'input'; + break; + case 'output': + $this->opStatus = 'output'; + break; + case 'body': + if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); + } else { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; + } + break; + } + break; + case 'service': + switch ($name) { + case 'port': + $this->currentPort = $attrs['name']; + $this->debug('current port: ' . $this->currentPort); + $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); + + break; + case 'address': + $this->ports[$this->currentPort]['location'] = $attrs['location']; + $this->ports[$this->currentPort]['bindingType'] = $namespace; + $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['bindingType'] = $namespace; + $this->bindings[ $this->ports[$this->currentPort]['binding'] ]['endpoint'] = $attrs['location']; + break; + } + break; + } + // set status + switch ($name) { + case 'import': + if (isset($attrs['location'])) { + $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); + $this->debug('parsing import ' . $attrs['namespace']. ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]).')'); + } else { + $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); + if (! $this->getPrefixFromNamespace($attrs['namespace'])) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; + } + $this->debug('parsing import ' . $attrs['namespace']. ' - [no location] (' . count($this->import[$attrs['namespace']]).')'); + } + break; + //wait for schema + //case 'types': + // $this->status = 'schema'; + // break; + case 'message': + $this->status = 'message'; + $this->messages[$attrs['name']] = array(); + $this->currentMessage = $attrs['name']; + break; + case 'portType': + $this->status = 'portType'; + $this->portTypes[$attrs['name']] = array(); + $this->currentPortType = $attrs['name']; + break; + case "binding": + if (isset($attrs['name'])) { + // get binding name + if (strpos($attrs['name'], ':')) { + $this->currentBinding = $this->getLocalPart($attrs['name']); + } else { + $this->currentBinding = $attrs['name']; + } + $this->status = 'binding'; + $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); + $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); + } + break; + case 'service': + $this->serviceName = $attrs['name']; + $this->status = 'service'; + $this->debug('current service: ' . $this->serviceName); + break; + case 'definitions': + foreach ($attrs as $name => $value) { + $this->wsdl_info[$name] = $value; + } + break; + } + } + } + + /** + * end-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @access private + */ + function end_element($parser, $name){ + // unset schema status + if (/*preg_match('/types$/', $name) ||*/ preg_match('/schema$/', $name)) { + $this->status = ""; + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; + $this->debug('Parsing WSDL schema done'); + } + if ($this->status == 'schema') { + $this->currentSchema->schemaEndElement($parser, $name); + } else { + // bring depth down a notch + $this->depth--; + } + // end documentation + if ($this->documentation) { + //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. + //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; + $this->documentation = false; + } + } + + /** + * element content handler + * + * @param string $parser XML parser object + * @param string $data element content + * @access private + */ + function character_data($parser, $data) + { + $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; + if (isset($this->message[$pos]['cdata'])) { + $this->message[$pos]['cdata'] .= $data; + } + if ($this->documentation) { + $this->documentation .= $data; + } + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) { + $this->debug("setCredentials username=$username authtype=$authtype certRequest="); + $this->appendDebug($this->varDump($certRequest)); + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + function getBindingData($binding) + { + if (is_array($this->bindings[$binding])) { + return $this->bindings[$binding]; + } + } + + /** + * returns an assoc array of operation names => operation data + * + * @param string $portName WSDL port name + * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) + * @return array + * @access public + */ + function getOperations($portName = '', $bindingType = 'soap') { + $ops = array(); + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } else { + $this->debug("getOperations bindingType $bindingType may not be supported"); + } + $this->debug("getOperations for port '$portName' bindingType $bindingType"); + // loop thru ports + foreach($this->ports as $port => $portData) { + $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); + if ($portName == '' || $port == $portName) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + $this->debug("getOperations found port $port bindingType $bindingType"); + //$this->debug("port data: " . $this->varDump($portData)); + //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); + // merge bindings + if (isset($this->bindings[ $portData['binding'] ]['operations'])) { + $ops = array_merge ($ops, $this->bindings[ $portData['binding'] ]['operations']); + } + } + } + } + if (count($ops) == 0) { + $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); + } + return $ops; + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $operation name of operation + * @param string $bindingType type of binding eg: soap, soap12 + * @return array + * @access public + */ + function getOperationData($operation, $bindingType = 'soap') + { + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } + // loop thru ports + foreach($this->ports as $port => $portData) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + // get binding + //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + foreach(array_keys($this->bindings[ $portData['binding'] ]['operations']) as $bOperation) { + // note that we could/should also check the namespace here + if ($operation == $bOperation) { + $opData = $this->bindings[ $portData['binding'] ]['operations'][$operation]; + return $opData; + } + } + } + } + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $soapAction soapAction for operation + * @param string $bindingType type of binding eg: soap, soap12 + * @return array + * @access public + */ + function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') { + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } + // loop thru ports + foreach($this->ports as $port => $portData) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + // loop through operations for the binding + foreach ($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + if ($opData['soapAction'] == $soapAction) { + return $opData; + } + } + } + } + } + + /** + * returns an array of information about a given type + * returns false if no type exists by the given name + * + * typeDef = array( + * 'elements' => array(), // refs to elements array + * 'restrictionBase' => '', + * 'phpType' => '', + * 'order' => '(sequence|all)', + * 'attrs' => array() // refs to attributes array + * ) + * + * @param string $type the type + * @param string $ns namespace (not prefix) of the type + * @return mixed + * @access public + * @see nusoap_xmlschema + */ + function getTypeDef($type, $ns) { + $this->debug("in getTypeDef: type=$type, ns=$ns"); + if ((! $ns) && isset($this->namespaces['tns'])) { + $ns = $this->namespaces['tns']; + $this->debug("in getTypeDef: type namespace forced to $ns"); + } + if (!isset($this->schemas[$ns])) { + foreach ($this->schemas as $ns0 => $schema0) { + if (strcasecmp($ns, $ns0) == 0) { + $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); + $ns = $ns0; + break; + } + } + } + if (isset($this->schemas[$ns])) { + $this->debug("in getTypeDef: have schema for namespace $ns"); + for ($i = 0; $i < count($this->schemas[$ns]); $i++) { + $xs = &$this->schemas[$ns][$i]; + $t = $xs->getTypeDef($type); + $this->appendDebug($xs->getDebug()); + $xs->clearDebug(); + if ($t) { + $this->debug("in getTypeDef: found type $type"); + if (!isset($t['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); + $ns = substr($t['type'], 0, strrpos($t['type'], ':')); + $etype = $this->getTypeDef($uqType, $ns); + if ($etype) { + $this->debug("found type for [element] $type:"); + $this->debug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $t['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $t['elements'] = $etype['elements']; + } + if (isset($etype['attrs'])) { + $t['attrs'] = $etype['attrs']; + } + } else { + $this->debug("did not find type for [element] $type"); + } + } + return $t; + } + } + $this->debug("in getTypeDef: did not find type $type"); + } else { + $this->debug("in getTypeDef: do not have schema for namespace $ns"); + } + return false; + } + + /** + * prints html description of services + * + * @access private + */ + function webDescription(){ + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $PHP_SELF = $_SERVER['PHP_SELF']; + } elseif (isset($HTTP_SERVER_VARS)) { + $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + + $b = ' + NuSOAP: '.$this->serviceName.' + + + + +
+

+
'.$this->serviceName.'
+ +
'; + return $b; + } + + /** + * serialize the parsed wsdl + * + * @param mixed $debug whether to put debug=1 in endpoint URL + * @return string serialization of WSDL + * @access public + */ + function serialize($debug = 0) + { + $xml = ''; + $xml .= "\nnamespaces as $k => $v) { + $xml .= " xmlns:$k=\"$v\""; + } + // 10.9.02 - add poulter fix for wsdl and tns declarations + if (isset($this->namespaces['wsdl'])) { + $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; + } + if (isset($this->namespaces['tns'])) { + $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; + } + $xml .= '>'; + // imports + if (sizeof($this->import) > 0) { + foreach($this->import as $ns => $list) { + foreach ($list as $ii) { + if ($ii['location'] != '') { + $xml .= ''; + } else { + $xml .= ''; + } + } + } + } + // types + if (count($this->schemas)>=1) { + $xml .= "\n\n"; + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $xml .= $xs->serializeSchema(); + } + } + $xml .= ''; + } + // messages + if (count($this->messages) >= 1) { + foreach($this->messages as $msgName => $msgParts) { + $xml .= "\n'; + if(is_array($msgParts)){ + foreach($msgParts as $partName => $partType) { + // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'
'; + if (strpos($partType, ':')) { + $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); + } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { + // print 'checking typemap: '.$this->XMLSchemaVersion.'
'; + $typePrefix = 'xsd'; + } else { + foreach($this->typemap as $ns => $types) { + if (isset($types[$partType])) { + $typePrefix = $this->getPrefixFromNamespace($ns); + } + } + if (!isset($typePrefix)) { + die("$partType has no namespace!"); + } + } + $ns = $this->getNamespaceFromPrefix($typePrefix); + $localPart = $this->getLocalPart($partType); + $typeDef = $this->getTypeDef($localPart, $ns); + if ($typeDef['typeClass'] == 'element') { + $elementortype = 'element'; + if (substr($localPart, -1) == '^') { + $localPart = substr($localPart, 0, -1); + } + } else { + $elementortype = 'type'; + } + $xml .= "\n" . ' '; + } + } + $xml .= '
'; + } + } + // bindings & porttypes + if (count($this->bindings) >= 1) { + $binding_xml = ''; + $portType_xml = ''; + foreach($this->bindings as $bindingName => $attrs) { + $binding_xml .= "\n'; + $binding_xml .= "\n" . ' '; + $portType_xml .= "\n'; + foreach($attrs['operations'] as $opName => $opParts) { + $binding_xml .= "\n" . ' '; + $binding_xml .= "\n" . ' '; + if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= "\n" . ' '; + if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= "\n" . ' '; + $binding_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' ' . htmlspecialchars($opParts['documentation']) . ''; + } + $portType_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' '; + } + $portType_xml .= "\n" . ''; + $binding_xml .= "\n" . ''; + } + $xml .= $portType_xml . $binding_xml; + } + // services + $xml .= "\nserviceName . '">'; + if (count($this->ports) >= 1) { + foreach($this->ports as $pName => $attrs) { + $xml .= "\n" . ' '; + $xml .= "\n" . ' '; + $xml .= "\n" . ' '; + } + } + $xml .= "\n" . ''; + return $xml . "\n"; + } + + /** + * determine whether a set of parameters are unwrapped + * when they are expect to be wrapped, Microsoft-style. + * + * @param string $type the type (element name) of the wrapper + * @param array $parameters the parameter values for the SOAP call + * @return boolean whether they parameters are unwrapped (and should be wrapped) + * @access private + */ + function parametersMatchWrapped($type, &$parameters) { + $this->debug("in parametersMatchWrapped type=$type, parameters="); + $this->appendDebug($this->varDump($parameters)); + + // split type into namespace:unqualified-type + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in parametersMatchWrapped: No namespace for type $type"); + $ns = ''; + $uqType = $type; + } + + // get the type information + if (!$typeDef = $this->getTypeDef($uqType, $ns)) { + $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); + return false; + } + $this->debug("in parametersMatchWrapped: found typeDef="); + $this->appendDebug($this->varDump($typeDef)); + if (substr($uqType, -1) == '^') { + $uqType = substr($uqType, 0, -1); + } + $phpType = $typeDef['phpType']; + $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); + $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); + + // we expect a complexType or element of complexType + if ($phpType != 'struct') { + $this->debug("in parametersMatchWrapped: not a struct"); + return false; + } + + // see whether the parameter names match the elements + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $elements = 0; + $matches = 0; + foreach ($typeDef['elements'] as $name => $attrs) { + if (isset($parameters[$name])) { + $this->debug("in parametersMatchWrapped: have parameter named $name"); + $matches++; + } else { + $this->debug("in parametersMatchWrapped: do not have parameter named $name"); + } + $elements++; + } + + $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); + if ($matches == 0) { + return false; + } + return true; + } + + // since there are no elements for the type, if the user passed no + // parameters, the parameters match wrapped. + $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); + return count($parameters) == 0; + } + + /** + * serialize PHP values according to a WSDL message definition + * contrary to the method name, this is not limited to RPC + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @param string $bindingType (soap|soap12) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + */ + function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') { + $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + if ($direction != 'input' && $direction != 'output') { + $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); + $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); + return false; + } + if (!$opData = $this->getOperationData($operation, $bindingType)) { + $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); + $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); + return false; + } + $this->debug('in serializeRPCParameters: opData:'); + $this->appendDebug($this->varDump($opData)); + + // Get encoding style for output and set to current + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { + $encodingStyle = $opData['output']['encodingStyle']; + $enc_style = $encodingStyle; + } + + // set input params + $xml = ''; + if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { + $parts = &$opData[$direction]['parts']; + $part_count = sizeof($parts); + $style = $opData['style']; + $use = $opData[$direction]['use']; + $this->debug("have $part_count part(s) to serialize using $style/$use"); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $parameter_count = count($parameters); + $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); + // check for Microsoft-style wrapped parameters + if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { + $this->debug('check whether the caller has wrapped the parameters'); + if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { + // TODO: consider checking here for double-wrapping, when + // service function wraps, then NuSOAP wraps again + $this->debug("change simple array to associative with 'parameters' element"); + $parameters['parameters'] = $parameters[0]; + unset($parameters[0]); + } + if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { + $this->debug('check whether caller\'s parameters match the wrapped ones'); + if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { + $this->debug('wrap the parameters for the caller'); + $parameters = array('parameters' => $parameters); + $parameter_count = 1; + } + } + } + foreach ($parts as $name => $type) { + $this->debug("serializing part $name of type $type"); + // Track encoding style + if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { + $encodingStyle = $opData[$direction]['encodingStyle']; + $enc_style = $encodingStyle; + } else { + $enc_style = false; + } + // NOTE: add error handling here + // if serializeType returns false, then catch global error and fault + if ($parametersArrayType == 'arraySimple') { + $p = array_shift($parameters); + $this->debug('calling serializeType w/indexed param'); + $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); + } elseif (isset($parameters[$name])) { + $this->debug('calling serializeType w/named param'); + $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); + } else { + // TODO: only send nillable + $this->debug('calling serializeType w/null param'); + $xml .= $this->serializeType($name, $type, null, $use, $enc_style); + } + } + } else { + $this->debug('no parameters passed.'); + } + } + $this->debug("serializeRPCParameters returning: $xml"); + return $xml; + } + + /** + * serialize a PHP value according to a WSDL message definition + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + * @deprecated + */ + function serializeParameters($operation, $direction, $parameters) + { + $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + if ($direction != 'input' && $direction != 'output') { + $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); + $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); + return false; + } + if (!$opData = $this->getOperationData($operation)) { + $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); + $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); + return false; + } + $this->debug('opData:'); + $this->appendDebug($this->varDump($opData)); + + // Get encoding style for output and set to current + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + if(($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { + $encodingStyle = $opData['output']['encodingStyle']; + $enc_style = $encodingStyle; + } + + // set input params + $xml = ''; + if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { + + $use = $opData[$direction]['use']; + $this->debug("use=$use"); + $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $this->debug('have ' . $parametersArrayType . ' parameters'); + foreach($opData[$direction]['parts'] as $name => $type) { + $this->debug('serializing part "'.$name.'" of type "'.$type.'"'); + // Track encoding style + if(isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { + $encodingStyle = $opData[$direction]['encodingStyle']; + $enc_style = $encodingStyle; + } else { + $enc_style = false; + } + // NOTE: add error handling here + // if serializeType returns false, then catch global error and fault + if ($parametersArrayType == 'arraySimple') { + $p = array_shift($parameters); + $this->debug('calling serializeType w/indexed param'); + $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); + } elseif (isset($parameters[$name])) { + $this->debug('calling serializeType w/named param'); + $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); + } else { + // TODO: only send nillable + $this->debug('calling serializeType w/null param'); + $xml .= $this->serializeType($name, $type, null, $use, $enc_style); + } + } + } else { + $this->debug('no parameters passed.'); + } + } + $this->debug("serializeParameters returning: $xml"); + return $xml; + } + + /** + * serializes a PHP value according a given type definition + * + * @param string $name name of value (part or element) + * @param string $type XML schema type of value (type or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @param boolean $unqualified a kludge for what should be XML namespace form handling + * @return string value serialized as an XML string + * @access private + */ + function serializeType($name, $type, $value, $use='encoded', $encodingStyle=false, $unqualified=false) + { + $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); + $this->appendDebug("value=" . $this->varDump($value)); + if($use == 'encoded' && $encodingStyle) { + $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; + } + + // if a soapval has been supplied, let its type override the WSDL + if (is_object($value) && get_class($value) == 'soapval') { + if ($value->type_ns) { + $type = $value->type_ns . ':' . $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } elseif ($value->type) { + $type = $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } else { + $forceType = false; + $this->debug("in serializeType: soapval does not override type"); + } + $attrs = $value->attributes; + $value = $value->value; + $this->debug("in serializeType: soapval overrides value to $value"); + if ($attrs) { + if (!is_array($value)) { + $value['!'] = $value; + } + foreach ($attrs as $n => $v) { + $value['!' . $n] = $v; + } + $this->debug("in serializeType: soapval provides attributes"); + } + } else { + $forceType = false; + } + + $xml = ''; + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); + } + + if($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/'){ + $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); + if ($unqualified && $use == 'literal') { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + // TODO: depends on nillable, which should be checked before calling this method + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if ($uqType == 'Array') { + // JBoss/Axis does this sometimes + return $this->serialize_val($value, $name, false, false, false, false, $use); + } + if ($uqType == 'boolean') { + if ((is_string($value) && $value == 'false') || (! $value)) { + $value = 'false'; + } else { + $value = 'true'; + } + } + if ($uqType == 'string' && gettype($value) == 'string') { + $value = $this->expandEntities($value); + } + if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { + $value = sprintf("%.0lf", $value); + } + // it's a scalar + // TODO: what about null/nil values? + // check type isn't a custom type extending xmlschema namespace + if (!$this->getTypeDef($uqType, $ns)) { + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; + } else { + $xml = "<$name$elementNS>$value"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); + } else if ($ns == 'http://xml.apache.org/xml-soap') { + $this->debug('in serializeType: appears to be Apache SOAP type'); + if ($uqType == 'Map') { + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + if (! $tt_prefix) { + $this->debug('in serializeType: Add namespace for Apache SOAP type'); + $tt_prefix = 'ns' . rand(1000, 9999); + $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; + // force this to be added to usedNamespaces + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + } + $contents = ''; + foreach($value as $k => $v) { + $this->debug("serializing map element: key $k, value $v"); + $contents .= ''; + $contents .= $this->serialize_val($k,'key',false,false,false,false,$use); + $contents .= $this->serialize_val($v,'value',false,false,false,false,$use); + $contents .= ''; + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents"; + } else { + $xml = "<$name>$contents"; + } + } else { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('in serializeType: Apache SOAP type, but only support Map'); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in serializeType: No namespace for type $type"); + $ns = ''; + $uqType = $type; + } + if(!$typeDef = $this->getTypeDef($uqType, $ns)){ + $this->setError("$type ($uqType) is not a supported type."); + $this->debug("in serializeType: $type ($uqType) is not a supported type."); + return false; + } else { + $this->debug("in serializeType: found typeDef"); + $this->appendDebug('typeDef=' . $this->varDump($typeDef)); + if (substr($uqType, -1) == '^') { + $uqType = substr($uqType, 0, -1); + } + } + if (!isset($typeDef['phpType'])) { + $this->setError("$type ($uqType) has no phpType."); + $this->debug("in serializeType: $type ($uqType) has no phpType."); + return false; + } + $phpType = $typeDef['phpType']; + $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '') ); + // if php type == struct, map value to the element names + if ($phpType == 'struct') { + if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { + $elementName = $uqType; + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + $elementNS = " xmlns=\"\""; + } + } else { + $elementName = $name; + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs and nillable + $xml = "<$elementName$elementNS/>"; + } else { + $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (is_object($value)) { + $value = get_object_vars($value); + } + if (is_array($value)) { + $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); + if ($use == 'literal') { + if ($forceType) { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; + } else { + $xml = "<$elementName$elementNS$elementAttrs>"; + } + } else { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; + } + + if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { + if (isset($value['!'])) { + $xml .= $value['!']; + $this->debug("in serializeType: serialized simpleContent for type $type"); + } else { + $this->debug("in serializeType: no simpleContent to serialize for type $type"); + } + } else { + // complexContent + $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); + } + $xml .= ""; + } else { + $this->debug("in serializeType: phpType is struct, but value is not an array"); + $this->setError("phpType is struct, but value is not an array: see debug output for details"); + $xml = ''; + } + } elseif ($phpType == 'array') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . + ":Array\" " . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . + ':arrayType="' . + $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . + ':' . + $this->getLocalPart($typeDef['arrayType'])."[0]\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (isset($typeDef['multidimensional'])) { + $nv = array(); + foreach($value as $v) { + $cols = ',' . sizeof($v); + $nv = array_merge($nv, $v); + } + $value = $nv; + } else { + $cols = ''; + } + if (is_array($value) && sizeof($value) >= 1) { + $rows = sizeof($value); + $contents = ''; + foreach($value as $k => $v) { + $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]"); + //if (strpos($typeDef['arrayType'], ':') ) { + if (!in_array($typeDef['arrayType'],$this->typemap['http://www.w3.org/2001/XMLSchema'])) { + $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); + } else { + $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); + } + } + } else { + $rows = 0; + $contents = null; + } + // TODO: for now, an empty value will be serialized as a zero element + // array. Revisit this when coding the handling of null/nil values. + if ($use == 'literal') { + $xml = "<$name$elementNS>" + .$contents + .""; + } else { + $xml = "<$name$elementNS xsi:type=\"".$this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/').':Array" '. + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') + .':arrayType="' + .$this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) + .":".$this->getLocalPart($typeDef['arrayType'])."[$rows$cols]\">" + .$contents + .""; + } + } elseif ($phpType == 'scalar') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; + } else { + $xml = "<$name$elementNS>$value"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; + } + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + + /** + * serializes the attributes for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) { + $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); + $xml = ''; + if (isset($typeDef['extensionBase'])) { + $nsx = $this->getPrefix($typeDef['extensionBase']); + $uqTypex = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($nsx)) { + $nsx = $this->getNamespaceFromPrefix($nsx); + } + if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { + $this->debug("serialize attributes for extension base $nsx:$uqTypex"); + $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); + } else { + $this->debug("extension base $nsx:$uqTypex is not a supported type"); + } + } + if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { + $this->debug("serialize attributes for XML Schema type $ns:$uqType"); + if (is_array($value)) { + $xvalue = $value; + } elseif (is_object($value)) { + $xvalue = get_object_vars($value); + } else { + $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); + $xvalue = array(); + } + foreach ($typeDef['attrs'] as $aName => $attrs) { + if (isset($xvalue['!' . $aName])) { + $xname = '!' . $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($xvalue[$aName])) { + $xname = $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($attrs['default'])) { + $xname = '!' . $aName; + $xvalue[$xname] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); + } else { + $xname = ''; + $this->debug("no value provided for attribute $aName"); + } + if ($xname) { + $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; + } + } + } else { + $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); + } + return $xml; + } + + /** + * serializes the elements for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use='encoded', $encodingStyle=false) { + $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); + $xml = ''; + if (isset($typeDef['extensionBase'])) { + $nsx = $this->getPrefix($typeDef['extensionBase']); + $uqTypex = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($nsx)) { + $nsx = $this->getNamespaceFromPrefix($nsx); + } + if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { + $this->debug("serialize elements for extension base $nsx:$uqTypex"); + $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); + } else { + $this->debug("extension base $nsx:$uqTypex is not a supported type"); + } + } + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); + if (is_array($value)) { + $xvalue = $value; + } elseif (is_object($value)) { + $xvalue = get_object_vars($value); + } else { + $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); + $xvalue = array(); + } + // toggle whether all elements are present - ideally should validate against schema + if (count($typeDef['elements']) != count($xvalue)){ + $optionals = true; + } + foreach ($typeDef['elements'] as $eName => $attrs) { + if (!isset($xvalue[$eName])) { + if (isset($attrs['default'])) { + $xvalue[$eName] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); + } + } + // if user took advantage of a minOccurs=0, then only serialize named parameters + if (isset($optionals) + && (!isset($xvalue[$eName])) + && ( (!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') + ){ + if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { + $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); + } + // do nothing + $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); + } else { + // get value + if (isset($xvalue[$eName])) { + $v = $xvalue[$eName]; + } else { + $v = null; + } + if (isset($attrs['form'])) { + $unqualified = ($attrs['form'] == 'unqualified'); + } else { + $unqualified = false; + } + if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { + $vv = $v; + foreach ($vv as $k => $v) { + if (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); + $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); + } + } + } else { + if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { + // do nothing + } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { + // TODO: serialize a nil correctly, but for now serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } elseif (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); + $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); + } + } + } + } + } else { + $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); + } + return $xml; + } + + /** + * adds an XML Schema complex type to the WSDL types + * + * @param string $name + * @param string $typeClass (complexType|simpleType|attribute) + * @param string $phpType currently supported are array and struct (php assoc array) + * @param string $compositor (all|sequence|choice) + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param array $elements e.g. array ( name => array(name=>'',type=>'') ) + * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) + * @param string $arrayType as namespace:name (xsd:string) + * @see nusoap_xmlschema + * @access public + */ + function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType='') { + if (count($elements) > 0) { + $eElements = array(); + foreach($elements as $n => $e){ + // expand each element + $ee = array(); + foreach ($e as $k => $v) { + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $ee[$k] = $v; + } + $eElements[$n] = $ee; + } + $elements = $eElements; + } + + if (count($attrs) > 0) { + foreach($attrs as $n => $a){ + // expand each attribute + foreach ($a as $k => $v) { + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $aa[$k] = $v; + } + $eAttrs[$n] = $aa; + } + $attrs = $eAttrs; + } + + $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; + $arrayType = strpos($arrayType,':') ? $this->expandQname($arrayType) : $arrayType; + + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addComplexType($name,$typeClass,$phpType,$compositor,$restrictionBase,$elements,$attrs,$arrayType); + } + + /** + * adds an XML Schema simple type to the WSDL types + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @see nusoap_xmlschema + * @access public + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $restrictionBase = strpos($restrictionBase,':') ? $this->expandQname($restrictionBase) : $restrictionBase; + + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); + } + + /** + * adds an element to the WSDL types + * + * @param array $attrs attributes that must include name and type + * @see nusoap_xmlschema + * @access public + */ + function addElement($attrs) { + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addElement($attrs); + } + + /** + * register an operation with the server + * + * @param string $name operation (method) name + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param string $namespace optional The namespace for the operation + * @param string $soapaction optional The soapaction for the operation + * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) + * @param string $documentation optional The description to include in the WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = ''){ + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + if ($style == 'document') { + $elements = array(); + foreach ($in as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); + } + $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); + $in = array('parameters' => 'tns:' . $name . '^'); + + $elements = array(); + foreach ($out as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); + } + $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); + $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); + } + + // get binding + $this->bindings[ $this->serviceName . 'Binding' ]['operations'][$name] = + array( + 'name' => $name, + 'binding' => $this->serviceName . 'Binding', + 'endpoint' => $this->endpoint, + 'soapAction' => $soapaction, + 'style' => $style, + 'input' => array( + 'use' => $use, + 'namespace' => $namespace, + 'encodingStyle' => $encodingStyle, + 'message' => $name . 'Request', + 'parts' => $in), + 'output' => array( + 'use' => $use, + 'namespace' => $namespace, + 'encodingStyle' => $encodingStyle, + 'message' => $name . 'Response', + 'parts' => $out), + 'namespace' => $namespace, + 'transport' => 'http://schemas.xmlsoap.org/soap/http', + 'documentation' => $documentation); + // add portTypes + // add messages + if($in) + { + foreach($in as $pName => $pType) + { + if(strpos($pType,':')) { + $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); + } + $this->messages[$name.'Request'][$pName] = $pType; + } + } else { + $this->messages[$name.'Request']= '0'; + } + if($out) + { + foreach($out as $pName => $pType) + { + if(strpos($pType,':')) { + $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)).":".$this->getLocalPart($pType); + } + $this->messages[$name.'Response'][$pName] = $pType; + } + } else { + $this->messages[$name.'Response']= '0'; + } + return true; + } +} + +?> \ No newline at end of file diff --git a/include/nusoap/class.wsdlcache.php b/include/nusoap/class.wsdlcache.php new file mode 100644 index 0000000..edc42e4 --- /dev/null +++ b/include/nusoap/class.wsdlcache.php @@ -0,0 +1,209 @@ + +* @author Ingo Fischer +* @version $Id: class.wsdlcache.php,v 1.7 2007/04/17 16:34:03 snichol Exp $ +* @access public +*/ +class nusoap_wsdlcache { + /** + * @var resource + * @access private + */ + var $fplock; + /** + * @var integer + * @access private + */ + var $cache_lifetime; + /** + * @var string + * @access private + */ + var $cache_dir; + /** + * @var string + * @access public + */ + var $debug_str = ''; + + /** + * constructor + * + * @param string $cache_dir directory for cache-files + * @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited + * @access public + */ + function __construct($cache_dir='.', $cache_lifetime=0) { + $this->fplock = array(); + $this->cache_dir = $cache_dir != '' ? $cache_dir : '.'; + $this->cache_lifetime = $cache_lifetime; + } + + /** + * creates the filename used to cache a wsdl instance + * + * @param string $wsdl The URL of the wsdl instance + * @return string The filename used to cache the instance + * @access private + */ + function createFilename($wsdl) { + return $this->cache_dir.'/wsdlcache-' . md5($wsdl); + } + + /** + * adds debug data to the class level debug string + * + * @param string $string debug data + * @access private + */ + function debug($string){ + $this->debug_str .= get_class($this).": $string\n"; + } + + /** + * gets a wsdl instance from the cache + * + * @param string $wsdl The URL of the wsdl instance + * @return object wsdl The cached wsdl instance, null if the instance is not in the cache + * @access public + */ + function get($wsdl) { + $filename = $this->createFilename($wsdl); + if ($this->obtainMutex($filename, "r")) { + // check for expired WSDL that must be removed from the cache + if ($this->cache_lifetime > 0) { + if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) { + unlink($filename); + $this->debug("Expired $wsdl ($filename) from cache"); + $this->releaseMutex($filename); + return null; + } + } + // see what there is to return + if (!file_exists($filename)) { + $this->debug("$wsdl ($filename) not in cache (1)"); + $this->releaseMutex($filename); + return null; + } + $fp = @fopen($filename, "r"); + if ($fp) { + $s = implode("", @file($filename)); + fclose($fp); + $this->debug("Got $wsdl ($filename) from cache"); + } else { + $s = null; + $this->debug("$wsdl ($filename) not in cache (2)"); + } + $this->releaseMutex($filename); + return (!is_null($s)) ? unserialize($s) : null; + } else { + $this->debug("Unable to obtain mutex for $filename in get"); + } + return null; + } + + /** + * obtains the local mutex + * + * @param string $filename The Filename of the Cache to lock + * @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode + * @return boolean Lock successfully obtained ?! + * @access private + */ + function obtainMutex($filename, $mode) { + if (isset($this->fplock[md5($filename)])) { + $this->debug("Lock for $filename already exists"); + return false; + } + $this->fplock[md5($filename)] = fopen($filename.".lock", "w"); + if ($mode == "r") { + return flock($this->fplock[md5($filename)], LOCK_SH); + } else { + return flock($this->fplock[md5($filename)], LOCK_EX); + } + } + + /** + * adds a wsdl instance to the cache + * + * @param object wsdl $wsdl_instance The wsdl instance to add + * @return boolean WSDL successfully cached + * @access public + */ + function put($wsdl_instance) { + $filename = $this->createFilename($wsdl_instance->wsdl); + $s = serialize($wsdl_instance); + if ($this->obtainMutex($filename, "w")) { + $fp = fopen($filename, "w"); + if (! $fp) { + $this->debug("Cannot write $wsdl_instance->wsdl ($filename) in cache"); + $this->releaseMutex($filename); + return false; + } + fputs($fp, $s); + fclose($fp); + $this->debug("Put $wsdl_instance->wsdl ($filename) in cache"); + $this->releaseMutex($filename); + return true; + } else { + $this->debug("Unable to obtain mutex for $filename in put"); + } + return false; + } + + /** + * releases the local mutex + * + * @param string $filename The Filename of the Cache to lock + * @return boolean Lock successfully released + * @access private + */ + function releaseMutex($filename) { + $ret = flock($this->fplock[md5($filename)], LOCK_UN); + fclose($this->fplock[md5($filename)]); + unset($this->fplock[md5($filename)]); + if (! $ret) { + $this->debug("Not able to release lock for $filename"); + } + return $ret; + } + + /** + * removes a wsdl instance from the cache + * + * @param string $wsdl The URL of the wsdl instance + * @return boolean Whether there was an instance to remove + * @access public + */ + function remove($wsdl) { + $filename = $this->createFilename($wsdl); + if (!file_exists($filename)) { + $this->debug("$wsdl ($filename) not in cache to be removed"); + return false; + } + // ignore errors obtaining mutex + $this->obtainMutex($filename, "w"); + $ret = unlink($filename); + $this->debug("Removed ($ret) $wsdl ($filename) from cache"); + $this->releaseMutex($filename); + return $ret; + } +} + +/** + * For backward compatibility + */ +class wsdlcache extends nusoap_wsdlcache { +} +?> diff --git a/include/nusoap/class.xmlschema.php b/include/nusoap/class.xmlschema.php new file mode 100644 index 0000000..72afc72 --- /dev/null +++ b/include/nusoap/class.xmlschema.php @@ -0,0 +1,974 @@ + +* @author Scott Nichol +* @version $Id: class.xmlschema.php,v 1.53 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class nusoap_xmlschema extends nusoap_base { + + // files + var $schema = ''; + var $xml = ''; + // namespaces + var $enclosingNamespaces; + // schema info + var $schemaInfo = array(); + var $schemaTargetNamespace = ''; + // types, elements, attributes defined by the schema + var $attributes = array(); + var $complexTypes = array(); + var $complexTypeStack = array(); + var $currentComplexType = null; + var $elements = array(); + var $elementStack = array(); + var $currentElement = null; + var $simpleTypes = array(); + var $simpleTypeStack = array(); + var $currentSimpleType = null; + // imports + var $imports = array(); + // parser vars + var $parser; + var $position = 0; + var $depth = 0; + var $depth_array = array(); + var $message = array(); + var $defaultNamespace = array(); + + /** + * constructor + * + * @param string $schema schema document URI + * @param string $xml xml document URI + * @param string $namespaces namespaces defined in enclosing XML + * @access public + */ + function __construct($schema='',$xml='',$namespaces=array()){ + parent::__construct(); + $this->debug('nusoap_xmlschema class instantiated, inside constructor'); + // files + $this->schema = $schema; + $this->xml = $xml; + + // namespaces + $this->enclosingNamespaces = $namespaces; + $this->namespaces = array_merge($this->namespaces, $namespaces); + + // parse schema file + if($schema != ''){ + $this->debug('initial schema file: '.$schema); + $this->parseFile($schema, 'schema'); + } + + // parse xml file + if($xml != ''){ + $this->debug('initial xml file: '.$xml); + $this->parseFile($xml, 'xml'); + } + + } + + /** + * parse an XML file + * + * @param string $xml path/URL to XML file + * @param string $type (schema | xml) + * @return boolean + * @access public + */ + function parseFile($xml,$type){ + // parse xml file + if($xml != ""){ + $xmlStr = @join("",@file($xml)); + if($xmlStr == ""){ + $msg = 'Error reading XML from '.$xml; + $this->setError($msg); + $this->debug($msg); + return false; + } else { + $this->debug("parsing $xml"); + $this->parseString($xmlStr,$type); + $this->debug("done parsing $xml"); + return true; + } + } + return false; + } + + /** + * parse an XML string + * + * @param string $xml path or URL + * @param string $type (schema|xml) + * @access private + */ + function parseString($xml,$type){ + // parse xml string + if($xml != ""){ + + // Create an XML parser. + $this->parser = xml_parser_create(); + // Set the options for parsing the XML data. + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + + // Set the object for the parser. + xml_set_object($this->parser, $this); + + // Set the element handlers for the parser. + if($type == "schema"){ + xml_set_element_handler($this->parser, 'schemaStartElement','schemaEndElement'); + xml_set_character_data_handler($this->parser,'schemaCharacterData'); + } elseif($type == "xml"){ + xml_set_element_handler($this->parser, 'xmlStartElement','xmlEndElement'); + xml_set_character_data_handler($this->parser,'xmlCharacterData'); + } + + // Parse the XML file. + if(!xml_parse($this->parser,$xml,true)){ + // Display an error message. + $errstr = sprintf('XML error parsing XML schema on line %d: %s', + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser)) + ); + $this->debug($errstr); + $this->debug("XML payload:\n" . $xml); + $this->setError($errstr); + } + + xml_parser_free($this->parser); + unset($this->parser); + } else{ + $this->debug('no xml passed to parseString()!!'); + $this->setError('no xml passed to parseString()!!'); + } + } + + /** + * gets a type name for an unnamed type + * + * @param string Element name + * @return string A type name for an unnamed type + * @access private + */ + function CreateTypeName($ename) { + $scope = ''; + for ($i = 0; $i < count($this->complexTypeStack); $i++) { + $scope .= $this->complexTypeStack[$i] . '_'; + } + return $scope . $ename . '_ContainedType'; + } + + /** + * start-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @param string $attrs associative array of attributes + * @access private + */ + function schemaStartElement($parser, $name, $attrs) { + + // position in the total number of elements, starting from 0 + $pos = $this->position++; + $depth = $this->depth++; + // set self as current value for this depth + $this->depth_array[$depth] = $pos; + $this->message[$pos] = array('cdata' => ''); + if ($depth > 0) { + $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; + } else { + $this->defaultNamespace[$pos] = false; + } + + // get element prefix + if($prefix = $this->getPrefix($name)){ + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + + // loop thru attributes, expanding, and registering namespace declarations + if(count($attrs) > 0){ + foreach($attrs as $k => $v){ + // if ns declarations, add to class level array of valid namespaces + if(preg_match('/^xmlns/',$k)){ + //$this->xdebug("$k: $v"); + //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); + if($ns_prefix = substr(strrchr($k,':'),1)){ + //$this->xdebug("Add namespace[$ns_prefix] = $v"); + $this->namespaces[$ns_prefix] = $v; + } else { + $this->defaultNamespace[$pos] = $v; + if (! $this->getPrefixFromNamespace($v)) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $v; + } + } + if($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema'){ + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v.'-instance'; + } + } + } + foreach($attrs as $k => $v){ + // expand each attribute + $k = strpos($k,':') ? $this->expandQname($k) : $k; + $v = strpos($v,':') ? $this->expandQname($v) : $v; + $eAttrs[$k] = $v; + } + $attrs = $eAttrs; + } else { + $attrs = array(); + } + // find status, register data + switch($name){ + case 'all': // (optional) compositor content for a complexType + case 'choice': + case 'group': + case 'sequence': + //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); + $this->complexTypes[$this->currentComplexType]['compositor'] = $name; + //if($name == 'all' || $name == 'sequence'){ + // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + //} + break; + case 'attribute': // complexType attribute + //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); + $this->xdebug("parsing attribute:"); + $this->appendDebug($this->varDump($attrs)); + if (!isset($attrs['form'])) { + // TODO: handle globals + $attrs['form'] = $this->schemaInfo['attributeFormDefault']; + } + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + if (!strpos($v, ':')) { + // no namespace in arrayType attribute value... + if ($this->defaultNamespace[$pos]) { + // ...so use the default + $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } + } + } + if(isset($attrs['name'])){ + $this->attributes[$attrs['name']] = $attrs; + $aname = $attrs['name']; + } elseif(isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'){ + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } else { + $aname = ''; + } + } elseif(isset($attrs['ref'])){ + $aname = $attrs['ref']; + $this->attributes[$attrs['ref']] = $attrs; + } + + if($this->currentComplexType){ // This should *always* be + $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; + } + // arrayType attribute + if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType'){ + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + $prefix = $this->getPrefix($aname); + if(isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])){ + $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } else { + $v = ''; + } + if(strpos($v,'[,]')){ + $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; + } + $v = substr($v,0,strpos($v,'[')); // clip the [] + if(!strpos($v,':') && isset($this->typemap[$this->XMLSchemaVersion][$v])){ + $v = $this->XMLSchemaVersion.':'.$v; + } + $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; + } + break; + case 'complexContent': // (optional) content for a complexType + $this->xdebug("do nothing for element $name"); + break; + case 'complexType': + array_push($this->complexTypeStack, $this->currentComplexType); + if(isset($attrs['name'])){ + // TODO: what is the scope of named complexTypes that appear + // nested within other c complexTypes? + $this->xdebug('processing named complexType '.$attrs['name']); + //$this->currentElement = false; + $this->currentComplexType = $attrs['name']; + $this->complexTypes[$this->currentComplexType] = $attrs; + $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; + // This is for constructs like + // + // + // + // + // + if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } else { + $name = $this->CreateTypeName($this->currentElement); + $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); + $this->currentComplexType = $name; + //$this->currentElement = false; + $this->complexTypes[$this->currentComplexType] = $attrs; + $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; + // This is for constructs like + // + // + // + // + // + if(isset($attrs['base']) && preg_match('/:Array$/',$attrs['base'])){ + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } + $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false'; + break; + case 'element': + array_push($this->elementStack, $this->currentElement); + if (!isset($attrs['form'])) { + if ($this->currentComplexType) { + $attrs['form'] = $this->schemaInfo['elementFormDefault']; + } else { + // global + $attrs['form'] = 'qualified'; + } + } + if(isset($attrs['type'])){ + $this->xdebug("processing typed element ".$attrs['name']." of type ".$attrs['type']); + if (! $this->getPrefix($attrs['type'])) { + if ($this->defaultNamespace[$pos]) { + $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; + $this->xdebug('used default namespace to make type ' . $attrs['type']); + } + } + // This is for constructs like + // + // + // + // + // + if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { + $this->xdebug('arrayType for unusual array is ' . $attrs['type']); + $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; + } + $this->currentElement = $attrs['name']; + $ename = $attrs['name']; + } elseif(isset($attrs['ref'])){ + $this->xdebug("processing element as ref to ".$attrs['ref']); + $this->currentElement = "ref to ".$attrs['ref']; + $ename = $this->getLocalPart($attrs['ref']); + } else { + $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); + $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); + $this->currentElement = $attrs['name']; + $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; + $ename = $attrs['name']; + } + if (isset($ename) && $this->currentComplexType) { + $this->xdebug("add element $ename to complexType $this->currentComplexType"); + $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; + } elseif (!isset($attrs['ref'])) { + $this->xdebug("add element $ename to elements array"); + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + } + break; + case 'enumeration': // restriction value list member + $this->xdebug('enumeration ' . $attrs['value']); + if ($this->currentSimpleType) { + $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; + } elseif ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; + } + break; + case 'extension': // simpleContent or complexContent type extension + $this->xdebug('extension ' . $attrs['base']); + if ($this->currentComplexType) { + $ns = $this->getPrefix($attrs['base']); + if ($ns == '') { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base']; + } else { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; + } + } else { + $this->xdebug('no current complexType to set extensionBase'); + } + break; + case 'import': + if (isset($attrs['schemaLocation'])) { + $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); + $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); + } else { + $this->xdebug('import namespace ' . $attrs['namespace']); + $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); + if (! $this->getPrefixFromNamespace($attrs['namespace'])) { + $this->namespaces['ns'.(count($this->namespaces)+1)] = $attrs['namespace']; + } + } + break; + case 'include': + if (isset($attrs['schemaLocation'])) { + $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']); + $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); + } else { + $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute'); + } + break; + case 'list': // simpleType value list + $this->xdebug("do nothing for element $name"); + break; + case 'restriction': // simpleType, simpleContent or complexContent value restriction + $this->xdebug('restriction ' . $attrs['base']); + if($this->currentSimpleType){ + $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; + } elseif($this->currentComplexType){ + $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; + if(strstr($attrs['base'],':') == ':Array'){ + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } + } + break; + case 'schema': + $this->schemaInfo = $attrs; + $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); + if (isset($attrs['targetNamespace'])) { + $this->schemaTargetNamespace = $attrs['targetNamespace']; + } + if (!isset($attrs['elementFormDefault'])) { + $this->schemaInfo['elementFormDefault'] = 'unqualified'; + } + if (!isset($attrs['attributeFormDefault'])) { + $this->schemaInfo['attributeFormDefault'] = 'unqualified'; + } + break; + case 'simpleContent': // (optional) content for a complexType + if ($this->currentComplexType) { // This should *always* be + $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true'; + } else { + $this->xdebug("do nothing for element $name because there is no current complexType"); + } + break; + case 'simpleType': + array_push($this->simpleTypeStack, $this->currentSimpleType); + if(isset($attrs['name'])){ + $this->xdebug("processing simpleType for name " . $attrs['name']); + $this->currentSimpleType = $attrs['name']; + $this->simpleTypes[ $attrs['name'] ] = $attrs; + $this->simpleTypes[ $attrs['name'] ]['typeClass'] = 'simpleType'; + $this->simpleTypes[ $attrs['name'] ]['phpType'] = 'scalar'; + } else { + $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); + $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); + $this->currentSimpleType = $name; + //$this->currentElement = false; + $this->simpleTypes[$this->currentSimpleType] = $attrs; + $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; + } + break; + case 'union': // simpleType type list + $this->xdebug("do nothing for element $name"); + break; + default: + $this->xdebug("do not have any logic to process element $name"); + } + } + + /** + * end-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @access private + */ + function schemaEndElement($parser, $name) { + // bring depth down a notch + $this->depth--; + // position of current element is equal to the last value left in depth_array for my depth + if(isset($this->depth_array[$this->depth])){ + $pos = $this->depth_array[$this->depth]; + } + // get element prefix + if ($prefix = $this->getPrefix($name)){ + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + // move on... + if($name == 'complexType'){ + $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); + $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType])); + $this->currentComplexType = array_pop($this->complexTypeStack); + //$this->currentElement = false; + } + if($name == 'element'){ + $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); + $this->currentElement = array_pop($this->elementStack); + } + if($name == 'simpleType'){ + $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); + $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType])); + $this->currentSimpleType = array_pop($this->simpleTypeStack); + } + } + + /** + * element content handler + * + * @param string $parser XML parser object + * @param string $data element content + * @access private + */ + function schemaCharacterData($parser, $data){ + $pos = $this->depth_array[$this->depth - 1]; + $this->message[$pos]['cdata'] .= $data; + } + + /** + * serialize the schema + * + * @access public + */ + function serializeSchema(){ + + $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); + $xml = ''; + // imports + if (sizeof($this->imports) > 0) { + foreach($this->imports as $ns => $list) { + foreach ($list as $ii) { + if ($ii['location'] != '') { + $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; + } else { + $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; + } + } + } + } + // complex types + foreach($this->complexTypes as $typeName => $attrs){ + $contentStr = ''; + // serialize child elements + if(isset($attrs['elements']) && (count($attrs['elements']) > 0)){ + foreach($attrs['elements'] as $element => $eParts){ + if(isset($eParts['ref'])){ + $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; + } else { + $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; + foreach ($eParts as $aName => $aValue) { + // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable + if ($aName != 'name' && $aName != 'type') { + $contentStr .= " $aName=\"$aValue\""; + } + } + $contentStr .= "/>\n"; + } + } + // compositor wraps elements + if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { + $contentStr = " <$schemaPrefix:$attrs[compositor]>\n".$contentStr." \n"; + } + } + // attributes + if(isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)){ + foreach($attrs['attrs'] as $attr => $aParts){ + $contentStr .= " <$schemaPrefix:attribute"; + foreach ($aParts as $a => $v) { + if ($a == 'ref' || $a == 'type') { + $contentStr .= " $a=\"".$this->contractQName($v).'"'; + } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { + $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; + $contentStr .= ' wsdl:arrayType="'.$this->contractQName($v).'"'; + } else { + $contentStr .= " $a=\"$v\""; + } + } + $contentStr .= "/>\n"; + } + } + // if restriction + if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != ''){ + $contentStr = " <$schemaPrefix:restriction base=\"".$this->contractQName($attrs['restrictionBase'])."\">\n".$contentStr." \n"; + // complex or simple content + if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)){ + $contentStr = " <$schemaPrefix:complexContent>\n".$contentStr." \n"; + } + } + // finalize complex type + if($contentStr != ''){ + $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n".$contentStr." \n"; + } else { + $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; + } + $xml .= $contentStr; + } + // simple types + if(isset($this->simpleTypes) && count($this->simpleTypes) > 0){ + foreach($this->simpleTypes as $typeName => $eParts){ + $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"".$this->contractQName($eParts['type'])."\">\n"; + if (isset($eParts['enumeration'])) { + foreach ($eParts['enumeration'] as $e) { + $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; + } + } + $xml .= " \n "; + } + } + // elements + if(isset($this->elements) && count($this->elements) > 0){ + foreach($this->elements as $element => $eParts){ + $xml .= " <$schemaPrefix:element name=\"$element\" type=\"".$this->contractQName($eParts['type'])."\"/>\n"; + } + } + // attributes + if(isset($this->attributes) && count($this->attributes) > 0){ + foreach($this->attributes as $attr => $aParts){ + $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"".$this->contractQName($aParts['type'])."\"\n/>"; + } + } + // finish 'er up + $attr = ''; + foreach ($this->schemaInfo as $k => $v) { + if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { + $attr .= " $k=\"$v\""; + } + } + $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; + foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { + $el .= " xmlns:$nsp=\"$ns\""; + } + $xml = $el . ">\n".$xml."\n"; + return $xml; + } + + /** + * adds debug data to the clas level debug string + * + * @param string $string debug data + * @access private + */ + function xdebug($string){ + $this->debug('<' . $this->schemaTargetNamespace . '> '.$string); + } + + /** + * get the PHP type of a user defined type in the schema + * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays + * returns false if no type exists, or not w/ the given namespace + * else returns a string that is either a native php type, or 'struct' + * + * @param string $type name of defined type + * @param string $ns namespace of type + * @return mixed + * @access public + * @deprecated + */ + function getPHPType($type,$ns){ + if(isset($this->typemap[$ns][$type])){ + //print "found type '$type' and ns $ns in typemap
"; + return $this->typemap[$ns][$type]; + } elseif(isset($this->complexTypes[$type])){ + //print "getting type '$type' and ns $ns from complexTypes array
"; + return $this->complexTypes[$type]['phpType']; + } + return false; + } + + /** + * returns an associative array of information about a given type + * returns false if no type exists by the given name + * + * For a complexType typeDef = array( + * 'restrictionBase' => '', + * 'phpType' => '', + * 'compositor' => '(sequence|all)', + * 'elements' => array(), // refs to elements array + * 'attrs' => array() // refs to attributes array + * ... and so on (see addComplexType) + * ) + * + * For simpleType or element, the array has different keys. + * + * @param string $type + * @return mixed + * @access public + * @see addComplexType + * @see addSimpleType + * @see addElement + */ + function getTypeDef($type){ + //$this->debug("in getTypeDef for type $type"); + if (substr($type, -1) == '^') { + $is_element = 1; + $type = substr($type, 0, -1); + } else { + $is_element = 0; + } + + if((! $is_element) && isset($this->complexTypes[$type])){ + $this->xdebug("in getTypeDef, found complexType $type"); + return $this->complexTypes[$type]; + } elseif((! $is_element) && isset($this->simpleTypes[$type])){ + $this->xdebug("in getTypeDef, found simpleType $type"); + if (!isset($this->simpleTypes[$type]['phpType'])) { + // get info for type to tack onto the simple type + // TODO: can this ever really apply (i.e. what is a simpleType really?) + $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); + $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); + $etype = $this->getTypeDef($uqType); + if ($etype) { + $this->xdebug("in getTypeDef, found type for simpleType $type:"); + $this->xdebug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $this->simpleTypes[$type]['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $this->simpleTypes[$type]['elements'] = $etype['elements']; + } + } + } + return $this->simpleTypes[$type]; + } elseif(isset($this->elements[$type])){ + $this->xdebug("in getTypeDef, found element $type"); + if (!isset($this->elements[$type]['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); + $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); + $etype = $this->getTypeDef($uqType); + if ($etype) { + $this->xdebug("in getTypeDef, found type for element $type:"); + $this->xdebug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $this->elements[$type]['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $this->elements[$type]['elements'] = $etype['elements']; + } + if (isset($etype['extensionBase'])) { + $this->elements[$type]['extensionBase'] = $etype['extensionBase']; + } + } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { + $this->xdebug("in getTypeDef, element $type is an XSD type"); + $this->elements[$type]['phpType'] = 'scalar'; + } + } + return $this->elements[$type]; + } elseif(isset($this->attributes[$type])){ + $this->xdebug("in getTypeDef, found attribute $type"); + return $this->attributes[$type]; + } elseif (preg_match('/_ContainedType$/', $type)) { + $this->xdebug("in getTypeDef, have an untyped element $type"); + $typeDef['typeClass'] = 'simpleType'; + $typeDef['phpType'] = 'scalar'; + $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; + return $typeDef; + } + $this->xdebug("in getTypeDef, did not find $type"); + return false; + } + + /** + * returns a sample serialization of a given type, or false if no type by the given name + * + * @param string $type name of type + * @return mixed + * @access public + * @deprecated + */ + function serializeTypeDef($type){ + //print "in sTD() for type $type
"; + if($typeDef = $this->getTypeDef($type)){ + $str .= '<'.$type; + if(is_array($typeDef['attrs'])){ + foreach($typeDef['attrs'] as $attName => $data){ + $str .= " $attName=\"{type = ".$data['type']."}\""; + } + } + $str .= " xmlns=\"".$this->schema['targetNamespace']."\""; + if(count($typeDef['elements']) > 0){ + $str .= ">"; + foreach($typeDef['elements'] as $element => $eData){ + $str .= $this->serializeTypeDef($element); + } + $str .= ""; + } elseif($typeDef['typeClass'] == 'element') { + $str .= ">"; + } else { + $str .= "/>"; + } + return $str; + } + return false; + } + + /** + * returns HTML form elements that allow a user + * to enter values for creating an instance of the given type. + * + * @param string $name name for type instance + * @param string $type name of type + * @return string + * @access public + * @deprecated + */ + function typeToForm($name,$type){ + // get typedef + if($typeDef = $this->getTypeDef($type)){ + // if struct + if($typeDef['phpType'] == 'struct'){ + $buffer .= ''; + foreach($typeDef['elements'] as $child => $childDef){ + $buffer .= " + + "; + } + $buffer .= '
$childDef[name] (type: ".$this->getLocalPart($childDef['type'])."):
'; + // if array + } elseif($typeDef['phpType'] == 'array'){ + $buffer .= ''; + for($i=0;$i < 3; $i++){ + $buffer .= " + + "; + } + $buffer .= '
array item (type: $typeDef[arrayType]):
'; + // if scalar + } else { + $buffer .= ""; + } + } else { + $buffer .= ""; + } + return $buffer; + } + + /** + * adds a complex type to the schema + * + * example: array + * + * addType( + * 'ArrayOfstring', + * 'complexType', + * 'array', + * '', + * 'SOAP-ENC:Array', + * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), + * 'xsd:string' + * ); + * + * example: PHP associative array ( SOAP Struct ) + * + * addType( + * 'SOAPStruct', + * 'complexType', + * 'struct', + * 'all', + * array('myVar'=> array('name'=>'myVar','type'=>'string') + * ); + * + * @param name + * @param typeClass (complexType|simpleType|attribute) + * @param phpType: currently supported are array and struct (php assoc array) + * @param compositor (all|sequence|choice) + * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param elements = array ( name = array(name=>'',type=>'') ) + * @param attrs = array( + * array( + * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", + * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" + * ) + * ) + * @param arrayType: namespace:name (http://www.w3.org/2001/XMLSchema:string) + * @access public + * @see getTypeDef + */ + function addComplexType($name,$typeClass='complexType',$phpType='array',$compositor='',$restrictionBase='',$elements=array(),$attrs=array(),$arrayType=''){ + $this->complexTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'compositor'=> $compositor, + 'restrictionBase' => $restrictionBase, + 'elements' => $elements, + 'attrs' => $attrs, + 'arrayType' => $arrayType + ); + + $this->xdebug("addComplexType $name:"); + $this->appendDebug($this->varDump($this->complexTypes[$name])); + } + + /** + * adds a simple type to the schema + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @access public + * @see nusoap_xmlschema + * @see getTypeDef + */ + function addSimpleType($name, $restrictionBase='', $typeClass='simpleType', $phpType='scalar', $enumeration=array()) { + $this->simpleTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'type' => $restrictionBase, + 'enumeration' => $enumeration + ); + + $this->xdebug("addSimpleType $name:"); + $this->appendDebug($this->varDump($this->simpleTypes[$name])); + } + + /** + * adds an element to the schema + * + * @param array $attrs attributes that must include name and type + * @see nusoap_xmlschema + * @access public + */ + function addElement($attrs) { + if (! $this->getPrefix($attrs['type'])) { + $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; + } + $this->elements[ $attrs['name'] ] = $attrs; + $this->elements[ $attrs['name'] ]['typeClass'] = 'element'; + + $this->xdebug("addElement " . $attrs['name']); + $this->appendDebug($this->varDump($this->elements[ $attrs['name'] ])); + } +} + +/** + * Backward compatibility + */ +class XMLSchema extends nusoap_xmlschema { +} + + +?> \ No newline at end of file diff --git a/include/nusoap/nusoap.php b/include/nusoap/nusoap.php new file mode 100644 index 0000000..b64cfc7 --- /dev/null +++ b/include/nusoap/nusoap.php @@ -0,0 +1,8574 @@ + + * @author Scott Nichol + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class nusoap_base +{ + /** + * Identification for HTTP headers. + * + * @var string + * @access private + */ + var $title = 'NuSOAP'; + /** + * Version for HTTP headers. + * + * @var string + * @access private + */ + var $version = '0.9.5'; + /** + * CVS revision for HTTP headers. + * + * @var string + * @access private + */ + var $revision = '$Revision: 1.123 $'; + /** + * Current error string (manipulated by getError/setError) + * + * @var string + * @access private + */ + var $error_str = ''; + /** + * Current debug string (manipulated by debug/appendDebug/clearDebug/getDebug/getDebugAsXMLComment) + * + * @var string + * @access private + */ + var $debug_str = ''; + /** + * toggles automatic encoding of special characters as entities + * (should always be true, I think) + * + * @var boolean + * @access private + */ + var $charencoding = true; + /** + * the debug level for this instance + * + * @var integer + * @access private + */ + var $debugLevel; + + /** + * set schema version + * + * @var string + * @access public + */ + var $XMLSchemaVersion = 'http://www.w3.org/2001/XMLSchema'; + + /** + * charset encoding for outgoing messages + * + * @var string + * @access public + */ + var $soap_defencoding = 'ISO-8859-1'; + //var $soap_defencoding = 'UTF-8'; + + /** + * namespaces in an array of prefix => uri + * + * this is "seeded" by a set of constants, but it may be altered by code + * + * @var array + * @access public + */ + var $namespaces = array( + 'SOAP-ENV' => 'http://schemas.xmlsoap.org/soap/envelope/', + 'xsd' => 'http://www.w3.org/2001/XMLSchema', + 'xsi' => 'http://www.w3.org/2001/XMLSchema-instance', + 'SOAP-ENC' => 'http://schemas.xmlsoap.org/soap/encoding/' + ); + + /** + * namespaces used in the current context, e.g. during serialization + * + * @var array + * @access private + */ + var $usedNamespaces = array(); + + /** + * XML Schema types in an array of uri => (array of xml type => php type) + * is this legacy yet? + * no, this is used by the nusoap_xmlschema class to verify type => namespace mappings. + * + * @var array + * @access public + */ + var $typemap = array( + 'http://www.w3.org/2001/XMLSchema' => array( + 'string' => 'string', 'boolean' => 'boolean', 'float' => 'double', 'double' => 'double', 'decimal' => 'double', + 'duration' => '', 'dateTime' => 'string', 'time' => 'string', 'date' => 'string', 'gYearMonth' => '', + 'gYear' => '', 'gMonthDay' => '', 'gDay' => '', 'gMonth' => '', 'hexBinary' => 'string', 'base64Binary' => 'string', + // abstract "any" types + 'anyType' => 'string', 'anySimpleType' => 'string', + // derived datatypes + 'normalizedString' => 'string', 'token' => 'string', 'language' => '', 'NMTOKEN' => '', 'NMTOKENS' => '', 'Name' => '', 'NCName' => '', 'ID' => '', + 'IDREF' => '', 'IDREFS' => '', 'ENTITY' => '', 'ENTITIES' => '', 'integer' => 'integer', 'nonPositiveInteger' => 'integer', + 'negativeInteger' => 'integer', 'long' => 'integer', 'int' => 'integer', 'short' => 'integer', 'byte' => 'integer', 'nonNegativeInteger' => 'integer', + 'unsignedLong' => '', 'unsignedInt' => '', 'unsignedShort' => '', 'unsignedByte' => '', 'positiveInteger' => ''), + 'http://www.w3.org/2000/10/XMLSchema' => array( + 'i4' => '', 'int' => 'integer', 'boolean' => 'boolean', 'string' => 'string', 'double' => 'double', + 'float' => 'double', 'dateTime' => 'string', + 'timeInstant' => 'string', 'base64Binary' => 'string', 'base64' => 'string', 'ur-type' => 'array'), + 'http://www.w3.org/1999/XMLSchema' => array( + 'i4' => '', 'int' => 'integer', 'boolean' => 'boolean', 'string' => 'string', 'double' => 'double', + 'float' => 'double', 'dateTime' => 'string', + 'timeInstant' => 'string', 'base64Binary' => 'string', 'base64' => 'string', 'ur-type' => 'array'), + 'http://soapinterop.org/xsd' => array('SOAPStruct' => 'struct'), + 'http://schemas.xmlsoap.org/soap/encoding/' => array('base64' => 'string', 'array' => 'array', 'Array' => 'array'), + 'http://xml.apache.org/xml-soap' => array('Map') + ); + + /** + * XML entities to convert + * + * @var array + * @access public + * @deprecated + * @see expandEntities + */ + var $xmlEntities = array('quot' => '"', 'amp' => '&', + 'lt' => '<', 'gt' => '>', 'apos' => "'"); + + /** + * HTTP Content-type to be used for SOAP calls and responses + * + * @var string + */ + var $contentType = "text/xml"; + + + /** + * constructor + * + * @access public + */ + function __construct() + { + $this->debugLevel = $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + } + + /** + * gets the global debug level, which applies to future instances + * + * @return integer Debug level 0-9, where 0 turns off + * @access public + */ + function getGlobalDebugLevel() + { + return $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel']; + } + + /** + * sets the global debug level, which applies to future instances + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setGlobalDebugLevel($level) + { + $GLOBALS['_transient']['static']['nusoap_base']['globalDebugLevel'] = $level; + } + + /** + * gets the debug level for this instance + * + * @return int Debug level 0-9, where 0 turns off + * @access public + */ + function getDebugLevel() + { + return $this->debugLevel; + } + + /** + * sets the debug level for this instance + * + * @param int $level Debug level 0-9, where 0 turns off + * @access public + */ + function setDebugLevel($level) + { + $this->debugLevel = $level; + } + + /** + * adds debug data to the instance debug string with formatting + * + * @param string $string debug data + * @access private + */ + function debug($string) + { + if ($this->debugLevel > 0) { + $this->appendDebug($this->getmicrotime() . ' ' . get_class($this) . ": $string\n"); + } + } + + /** + * adds debug data to the instance debug string without formatting + * + * @param string $string debug data + * @access public + */ + function appendDebug($string) + { + if ($this->debugLevel > 0) { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str .= $string; + } + } + + /** + * clears the current debug data for this instance + * + * @access public + */ + function clearDebug() + { + // it would be nice to use a memory stream here to use + // memory more efficiently + $this->debug_str = ''; + } + + /** + * gets the current debug data for this instance + * + * @return debug data + * @access public + */ + function &getDebug() + { + // it would be nice to use a memory stream here to use + // memory more efficiently + return $this->debug_str; + } + + /** + * gets the current debug data for this instance as an XML comment + * this may change the contents of the debug data + * + * @return debug data as an XML comment + * @access public + */ + function &getDebugAsXMLComment() + { + // it would be nice to use a memory stream here to use + // memory more efficiently + while (strpos($this->debug_str, '--')) { + $this->debug_str = str_replace('--', '- -', $this->debug_str); + } + $ret = ""; + return $ret; + } + + /** + * expands entities, e.g. changes '<' to '<'. + * + * @param string $val The string in which to expand entities. + * @access private + */ + function expandEntities($val) + { + if ($this->charencoding) { + $val = str_replace('&', '&', $val); + $val = str_replace("'", ''', $val); + $val = str_replace('"', '"', $val); + $val = str_replace('<', '<', $val); + $val = str_replace('>', '>', $val); + } + return $val; + } + + /** + * returns error string if present + * + * @return mixed error string or false + * @access public + */ + function getError() + { + if ($this->error_str != '') { + return $this->error_str; + } + return false; + } + + /** + * sets error string + * + * @return boolean $string error string + * @access private + */ + function setError($str) + { + $this->error_str = $str; + } + + /** + * detect if array is a simple array or a struct (associative array) + * + * @param mixed $val The PHP array + * @return string (arraySimple|arrayStruct) + * @access private + */ + function isArraySimpleOrStruct($val) + { + $keyList = array_keys($val); + foreach ($keyList as $keyListValue) { + if (!is_int($keyListValue)) { + return 'arrayStruct'; + } + } + return 'arraySimple'; + } + + /** + * serializes PHP values in accordance w/ section 5. Type information is + * not serialized if $use == 'literal'. + * + * @param mixed $val The value to serialize + * @param string $name The name (local part) of the XML element + * @param string $type The XML schema type (local part) for the element + * @param string $name_ns The namespace for the name of the XML element + * @param string $type_ns The namespace for the type of the element + * @param array $attributes The attributes to serialize as name=>value pairs + * @param string $use The WSDL "use" (encoded|literal) + * @param boolean $soapval Whether this is called from soapval. + * @return string The serialized element, possibly with child elements + * @access public + */ + function serialize_val($val, $name = false, $type = false, $name_ns = false, $type_ns = false, $attributes = false, $use = 'encoded', $soapval = false) + { + $this->debug("in serialize_val: name=$name, type=$type, name_ns=$name_ns, type_ns=$type_ns, use=$use, soapval=$soapval"); + $this->appendDebug('value=' . $this->varDump($val)); + $this->appendDebug('attributes=' . $this->varDump($attributes)); + + if (is_object($val) && get_class($val) == 'soapval' && (!$soapval)) { + $this->debug("serialize_val: serialize soapval"); + $xml = $val->serialize($use); + $this->appendDebug($val->getDebug()); + $val->clearDebug(); + $this->debug("serialize_val of soapval returning $xml"); + return $xml; + } + // force valid name if necessary + if (is_numeric($name)) { + $name = '__numeric_' . $name; + } elseif (!$name) { + $name = 'noname'; + } + // if name has ns, add ns prefix to name + $xmlns = ''; + if ($name_ns) { + $prefix = 'nu' . rand(1000, 9999); + $name = $prefix . ':' . $name; + $xmlns .= " xmlns:$prefix=\"$name_ns\""; + } + // if type is prefixed, create type prefix + if ($type_ns != '' && $type_ns == $this->namespaces['xsd']) { + // need to fix this. shouldn't default to xsd if no ns specified + // w/o checking against typemap + $type_prefix = 'xsd'; + } elseif ($type_ns) { + $type_prefix = 'ns' . rand(1000, 9999); + $xmlns .= " xmlns:$type_prefix=\"$type_ns\""; + } + // serialize attributes if present + $atts = ''; + if ($attributes) { + foreach ($attributes as $k => $v) { + $atts .= " $k=\"" . $this->expandEntities($v) . '"'; + } + } + // serialize null value + if (is_null($val)) { + $this->debug("serialize_val: serialize null"); + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$xmlns$atts/>"; + $this->debug("serialize_val returning $xml"); + return $xml; + } else { + if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + $xml = "<$name$xmlns$type_str$atts xsi:nil=\"true\"/>"; + $this->debug("serialize_val returning $xml"); + return $xml; + } + } + // serialize if an xsd built-in primitive type + if ($type != '' && isset($this->typemap[$this->XMLSchemaVersion][$type])) { + $this->debug("serialize_val: serialize xsd built-in primitive type"); + if (is_bool($val)) { + if ($type == 'boolean') { + $val = $val ? 'true' : 'false'; + } elseif (!$val) { + $val = 0; + } + } elseif (is_string($val)) { + $val = $this->expandEntities($val); + } + if ($use == 'literal') { + $xml = "<$name$xmlns$atts>$val"; + $this->debug("serialize_val returning $xml"); + return $xml; + } else { + $xml = "<$name$xmlns xsi:type=\"xsd:$type\"$atts>$val"; + $this->debug("serialize_val returning $xml"); + return $xml; + } + } + // detect type and serialize + $xml = ''; + switch (true) { + case (is_bool($val) || $type == 'boolean'): + $this->debug("serialize_val: serialize boolean"); + if ($type == 'boolean') { + $val = $val ? 'true' : 'false'; + } elseif (!$val) { + $val = 0; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:boolean\"$atts>$val"; + } + break; + case (is_int($val) || is_long($val) || $type == 'int'): + $this->debug("serialize_val: serialize int"); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:int\"$atts>$val"; + } + break; + case (is_float($val) || is_double($val) || $type == 'float'): + $this->debug("serialize_val: serialize float"); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:float\"$atts>$val"; + } + break; + case (is_string($val) || $type == 'string'): + $this->debug("serialize_val: serialize string"); + $val = $this->expandEntities($val); + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$val"; + } else { + $xml .= "<$name$xmlns xsi:type=\"xsd:string\"$atts>$val"; + } + break; + case is_object($val): + $this->debug("serialize_val: serialize object"); + if (get_class($val) == 'soapval') { + $this->debug("serialize_val: serialize soapval object"); + $pXml = $val->serialize($use); + $this->appendDebug($val->getDebug()); + $val->clearDebug(); + } else { + if (!$name) { + $name = get_class($val); + $this->debug("In serialize_val, used class name $name as element name"); + } else { + $this->debug("In serialize_val, do not override name $name for element name for class " . get_class($val)); + } + foreach (get_object_vars($val) as $k => $v) { + $pXml = isset($pXml) ? $pXml . $this->serialize_val($v, $k, false, false, false, false, $use) : $this->serialize_val($v, $k, false, false, false, false, $use); + } + } + if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>$pXml"; + } else { + $xml .= "<$name$xmlns$type_str$atts>$pXml"; + } + break; + break; + case (is_array($val) || $type): + // detect if struct or array + $valueType = $this->isArraySimpleOrStruct($val); + if ($valueType == 'arraySimple' || preg_match('/^ArrayOf/', $type)) { + $this->debug("serialize_val: serialize array"); + $i = 0; + if (is_array($val) && count($val) > 0) { + foreach ($val as $v) { + if (is_object($v) && get_class($v) == 'soapval') { + $tt_ns = $v->type_ns; + $tt = $v->type; + } elseif (is_array($v)) { + $tt = $this->isArraySimpleOrStruct($v); + } else { + $tt = gettype($v); + } + $array_types[$tt] = 1; + // TODO: for literal, the name should be $name + $xml .= $this->serialize_val($v, 'item', false, false, false, false, $use); + ++$i; + } + if (count($array_types) > 1) { + $array_typename = 'xsd:anyType'; + } elseif (isset($tt) && isset($this->typemap[$this->XMLSchemaVersion][$tt])) { + if ($tt == 'integer') { + $tt = 'int'; + } + $array_typename = 'xsd:' . $tt; + } elseif (isset($tt) && $tt == 'arraySimple') { + $array_typename = 'SOAP-ENC:Array'; + } elseif (isset($tt) && $tt == 'arrayStruct') { + $array_typename = 'unnamed_struct_use_soapval'; + } else { + // if type is prefixed, create type prefix + if ($tt_ns != '' && $tt_ns == $this->namespaces['xsd']) { + $array_typename = 'xsd:' . $tt; + } elseif ($tt_ns) { + $tt_prefix = 'ns' . rand(1000, 9999); + $array_typename = "$tt_prefix:$tt"; + $xmlns .= " xmlns:$tt_prefix=\"$tt_ns\""; + } else { + $array_typename = $tt; + } + } + $array_type = $i; + if ($use == 'literal') { + $type_str = ''; + } elseif (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"" . $array_typename . "[$array_type]\""; + } + // empty array + } else { + if ($use == 'literal') { + $type_str = ''; + } elseif (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = " xsi:type=\"SOAP-ENC:Array\" SOAP-ENC:arrayType=\"xsd:anyType[0]\""; + } + } + // TODO: for array in literal, there is no wrapper here + $xml = "<$name$xmlns$type_str$atts>" . $xml . ""; + } else { + // got a struct + $this->debug("serialize_val: serialize struct"); + if (isset($type) && isset($type_prefix)) { + $type_str = " xsi:type=\"$type_prefix:$type\""; + } else { + $type_str = ''; + } + if ($use == 'literal') { + $xml .= "<$name$xmlns$atts>"; + } else { + $xml .= "<$name$xmlns$type_str$atts>"; + } + foreach ($val as $k => $v) { + // Apache Map + if ($type == 'Map' && $type_ns == 'http://xml.apache.org/xml-soap') { + $xml .= ''; + $xml .= $this->serialize_val($k, 'key', false, false, false, false, $use); + $xml .= $this->serialize_val($v, 'value', false, false, false, false, $use); + $xml .= ''; + } else { + $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); + } + } + $xml .= ""; + } + break; + default: + $this->debug("serialize_val: serialize unknown"); + $xml .= 'not detected, got ' . gettype($val) . ' for ' . $val; + break; + } + $this->debug("serialize_val returning $xml"); + return $xml; + } + + /** + * serializes a message + * + * @param string $body the XML of the SOAP body + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array + * @param array $namespaces optional the namespaces used in generating the body and headers + * @param string $style optional (rpc|document) + * @param string $use optional (encoded|literal) + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @return string the message + * @access public + */ + function serializeEnvelope($body, $headers = false, $namespaces = array(), $style = 'rpc', $use = 'encoded', $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/') + { + // TODO: add an option to automatically run utf8_encode on $body and $headers + // if $this->soap_defencoding is UTF-8. Not doing this automatically allows + // one to send arbitrary UTF-8 characters, not just characters that map to ISO-8859-1 + + $this->debug("In serializeEnvelope length=" . strlen($body) . " body (max 1000 characters)=" . substr($body, 0, 1000) . " style=$style use=$use encodingStyle=$encodingStyle"); + $this->debug("headers:"); + $this->appendDebug($this->varDump($headers)); + $this->debug("namespaces:"); + $this->appendDebug($this->varDump($namespaces)); + + // serialize namespaces + $ns_string = ''; + foreach (array_merge($this->namespaces, $namespaces) as $k => $v) { + $ns_string .= " xmlns:$k=\"$v\""; + } + if ($encodingStyle) { + $ns_string = " SOAP-ENV:encodingStyle=\"$encodingStyle\"$ns_string"; + } + + // serialize headers + if ($headers) { + if (is_array($headers)) { + $xml = ''; + foreach ($headers as $k => $v) { + if (is_object($v) && get_class($v) == 'soapval') { + $xml .= $this->serialize_val($v, false, false, false, false, false, $use); + } else { + $xml .= $this->serialize_val($v, $k, false, false, false, false, $use); + } + } + $headers = $xml; + $this->debug("In serializeEnvelope, serialized array of headers to $headers"); + } + $headers = "" . $headers . ""; + } + // serialize envelope + return + 'soap_defencoding . '"?' . ">" . + '" . + $headers . + "" . + $body . + "" . + ""; + } + + /** + * formats a string to be inserted into an HTML stream + * + * @param string $str The string to format + * @return string The formatted string + * @access public + * @deprecated + */ + function formatDump($str) + { + $str = htmlspecialchars($str); + return nl2br($str); + } + + /** + * contracts (changes namespace to prefix) a qualified name + * + * @param string $qname qname + * @return string contracted qname + * @access private + */ + function contractQname($qname) + { + // get element namespace + //$this->xdebug("Contract $qname"); + if (strrpos($qname, ':')) { + // get unqualified name + $name = substr($qname, strrpos($qname, ':') + 1); + // get ns + $ns = substr($qname, 0, strrpos($qname, ':')); + $p = $this->getPrefixFromNamespace($ns); + if ($p) { + return $p . ':' . $name; + } + return $qname; + } else { + return $qname; + } + } + + /** + * expands (changes prefix to namespace) a qualified name + * + * @param string $qname qname + * @return string expanded qname + * @access private + */ + function expandQname($qname) + { + // get element prefix + if (strpos($qname, ':') && !preg_match('/^http:\/\//', $qname)) { + // get unqualified name + $name = substr(strstr($qname, ':'), 1); + // get ns prefix + $prefix = substr($qname, 0, strpos($qname, ':')); + if (isset($this->namespaces[$prefix])) { + return $this->namespaces[$prefix] . ':' . $name; + } else { + return $qname; + } + } else { + return $qname; + } + } + + /** + * returns the local part of a prefixed string + * returns the original string, if not prefixed + * + * @param string $str The prefixed string + * @return string The local part + * @access public + */ + function getLocalPart($str) + { + if ($sstr = strrchr($str, ':')) { + // get unqualified name + return substr($sstr, 1); + } else { + return $str; + } + } + + /** + * returns the prefix part of a prefixed string + * returns false, if not prefixed + * + * @param string $str The prefixed string + * @return mixed The prefix or false if there is no prefix + * @access public + */ + function getPrefix($str) + { + if ($pos = strrpos($str, ':')) { + // get prefix + return substr($str, 0, $pos); + } + return false; + } + + /** + * pass it a prefix, it returns a namespace + * + * @param string $prefix The prefix + * @return mixed The namespace, false if no namespace has the specified prefix + * @access public + */ + function getNamespaceFromPrefix($prefix) + { + if (isset($this->namespaces[$prefix])) { + return $this->namespaces[$prefix]; + } + //$this->setError("No namespace registered for prefix '$prefix'"); + return false; + } + + /** + * returns the prefix for a given namespace (or prefix) + * or false if no prefixes registered for the given namespace + * + * @param string $ns The namespace + * @return mixed The prefix, false if the namespace has no prefixes + * @access public + */ + function getPrefixFromNamespace($ns) + { + foreach ($this->namespaces as $p => $n) { + if ($ns == $n || $ns == $p) { + $this->usedNamespaces[$p] = $n; + return $p; + } + } + return false; + } + + /** + * returns the time in ODBC canonical form with microseconds + * + * @return string The time in ODBC canonical form with microseconds + * @access public + */ + function getmicrotime() + { + if (function_exists('gettimeofday')) { + $tod = gettimeofday(); + $sec = $tod['sec']; + $usec = $tod['usec']; + } else { + $sec = time(); + $usec = 0; + } + return strftime('%Y-%m-%d %H:%M:%S', $sec) . '.' . sprintf('%06d', $usec); + } + + /** + * Returns a string with the output of var_dump + * + * @param mixed $data The variable to var_dump + * @return string The output of var_dump + * @access public + */ + function varDump($data) + { + ob_start(); + var_dump($data); + $ret_val = ob_get_contents(); + ob_end_clean(); + return $ret_val; + } + + /** + * represents the object as a string + * + * @return string + * @access public + */ + function __toString() + { + return $this->varDump($this); + } +} + +// XML Schema Datatype Helper Functions + +//xsd:dateTime helpers + +/** + * convert unix timestamp to ISO 8601 compliant date string + * + * @param int $timestamp Unix time stamp + * @param boolean $utc Whether the time stamp is UTC or local + * @return mixed ISO 8601 date string or false + * @access public + */ +function timestamp_to_iso8601($timestamp, $utc = true) +{ + $datestr = date('Y-m-d\TH:i:sO', $timestamp); + $pos = strrpos($datestr, "+"); + if ($pos === false) { + $pos = strrpos($datestr, "-"); + } + if ($pos !== false) { + if (strlen($datestr) == $pos + 5) { + $datestr = substr($datestr, 0, $pos + 3) . ':' . substr($datestr, -2); + } + } + if ($utc) { + $pattern = '/' . + '([0-9]{4})-' . // centuries & years CCYY- + '([0-9]{2})-' . // months MM- + '([0-9]{2})' . // days DD + 'T' . // separator T + '([0-9]{2}):' . // hours hh: + '([0-9]{2}):' . // minutes mm: + '([0-9]{2})(\.[0-9]*)?' . // seconds ss.ss... + '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's + '/'; + + if (preg_match($pattern, $datestr, $regs)) { + return sprintf('%04d-%02d-%02dT%02d:%02d:%02dZ', $regs[1], $regs[2], $regs[3], $regs[4], $regs[5], $regs[6]); + } + return false; + } else { + return $datestr; + } +} + +/** + * convert ISO 8601 compliant date string to unix timestamp + * + * @param string $datestr ISO 8601 compliant date string + * @return mixed Unix timestamp (int) or false + * @access public + */ +function iso8601_to_timestamp($datestr) +{ + $pattern = '/' . + '([0-9]{4})-' . // centuries & years CCYY- + '([0-9]{2})-' . // months MM- + '([0-9]{2})' . // days DD + 'T' . // separator T + '([0-9]{2}):' . // hours hh: + '([0-9]{2}):' . // minutes mm: + '([0-9]{2})(\.[0-9]+)?' . // seconds ss.ss... + '(Z|[+\-][0-9]{2}:?[0-9]{2})?' . // Z to indicate UTC, -/+HH:MM:SS.SS... for local tz's + '/'; + if (preg_match($pattern, $datestr, $regs)) { + // not utc + if ($regs[8] != 'Z') { + $op = substr($regs[8], 0, 1); + $h = substr($regs[8], 1, 2); + $m = substr($regs[8], strlen($regs[8]) - 2, 2); + if ($op == '-') { + $regs[4] = $regs[4] + $h; + $regs[5] = $regs[5] + $m; + } elseif ($op == '+') { + $regs[4] = $regs[4] - $h; + $regs[5] = $regs[5] - $m; + } + } + return gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +// return strtotime("$regs[1]-$regs[2]-$regs[3] $regs[4]:$regs[5]:$regs[6]Z"); + } else { + return false; + } +} + +/** + * sleeps some number of microseconds + * + * @param string $usec the number of microseconds to sleep + * @access public + * @deprecated + */ +function usleepWindows($usec) +{ + $start = gettimeofday(); + + do { + $stop = gettimeofday(); + $timePassed = 1000000 * ($stop['sec'] - $start['sec']) + + $stop['usec'] - $start['usec']; + } while ($timePassed < $usec); +} + + +/** + * Contains information for a SOAP fault. + * Mainly used for returning faults from deployed functions + * in a server instance. + * + * @author Dietrich Ayala + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class nusoap_fault extends nusoap_base +{ + /** + * The fault code (client|server) + * + * @var string + * @access private + */ + var $faultcode; + /** + * The fault actor + * + * @var string + * @access private + */ + var $faultactor; + /** + * The fault string, a description of the fault + * + * @var string + * @access private + */ + var $faultstring; + /** + * The fault detail, typically a string or array of string + * + * @var mixed + * @access private + */ + var $faultdetail; + + /** + * constructor + * + * @param string $faultcode (SOAP-ENV:Client | SOAP-ENV:Server) + * @param string $faultactor only used when msg routed between multiple actors + * @param string $faultstring human readable error message + * @param mixed $faultdetail detail, typically a string or array of string + */ + function __construct($faultcode, $faultactor = '', $faultstring = '', $faultdetail = '') + { + parent::__construct(); + $this->faultcode = $faultcode; + $this->faultactor = $faultactor; + $this->faultstring = $faultstring; + $this->faultdetail = $faultdetail; + } + + /** + * serialize a fault + * + * @return string The serialization of the fault instance. + * @access public + */ + function serialize() + { + $ns_string = ''; + foreach ($this->namespaces as $k => $v) { + $ns_string .= "\n xmlns:$k=\"$v\""; + } + $return_msg = + 'soap_defencoding . '"?>' . + '\n" . + '' . + '' . + $this->serialize_val($this->faultcode, 'faultcode') . + $this->serialize_val($this->faultactor, 'faultactor') . + $this->serialize_val($this->faultstring, 'faultstring') . + $this->serialize_val($this->faultdetail, 'detail') . + '' . + '' . + ''; + return $return_msg; + } +} + + +/** + * Backward compatibility + */ +class soap_fault extends nusoap_fault +{ +} + + +/** + * parses an XML Schema, allows access to it's data, other utility methods. + * imperfect, no validation... yet, but quite functional. + * + * @author Dietrich Ayala + * @author Scott Nichol + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class nusoap_xmlschema extends nusoap_base +{ + + // files + var $schema = ''; + var $xml = ''; + // namespaces + var $enclosingNamespaces; + // schema info + var $schemaInfo = array(); + var $schemaTargetNamespace = ''; + // types, elements, attributes defined by the schema + var $attributes = array(); + var $complexTypes = array(); + var $complexTypeStack = array(); + var $currentComplexType = null; + var $elements = array(); + var $elementStack = array(); + var $currentElement = null; + var $simpleTypes = array(); + var $simpleTypeStack = array(); + var $currentSimpleType = null; + // imports + var $imports = array(); + // parser vars + var $parser; + var $position = 0; + var $depth = 0; + var $depth_array = array(); + var $message = array(); + var $defaultNamespace = array(); + + /** + * constructor + * + * @param string $schema schema document URI + * @param string $xml xml document URI + * @param string $namespaces namespaces defined in enclosing XML + * @access public + */ + function __construct($schema = '', $xml = '', $namespaces = array()) + { + parent::__construct(); + $this->debug('nusoap_xmlschema class instantiated, inside constructor'); + // files + $this->schema = $schema; + $this->xml = $xml; + + // namespaces + $this->enclosingNamespaces = $namespaces; + $this->namespaces = array_merge($this->namespaces, $namespaces); + + // parse schema file + if ($schema != '') { + $this->debug('initial schema file: ' . $schema); + $this->parseFile($schema, 'schema'); + } + + // parse xml file + if ($xml != '') { + $this->debug('initial xml file: ' . $xml); + $this->parseFile($xml, 'xml'); + } + + } + + /** + * parse an XML file + * + * @param string $xml path/URL to XML file + * @param string $type (schema | xml) + * @return boolean + * @access public + */ + function parseFile($xml, $type) + { + // parse xml file + if ($xml != "") { + $xmlStr = @join("", @file($xml)); + if ($xmlStr == "") { + $msg = 'Error reading XML from ' . $xml; + $this->setError($msg); + $this->debug($msg); + return false; + } else { + $this->debug("parsing $xml"); + $this->parseString($xmlStr, $type); + $this->debug("done parsing $xml"); + return true; + } + } + return false; + } + + /** + * parse an XML string + * + * @param string $xml path or URL + * @param string $type (schema|xml) + * @access private + */ + function parseString($xml, $type) + { + // parse xml string + if ($xml != "") { + + // Create an XML parser. + $this->parser = xml_parser_create(); + // Set the options for parsing the XML data. + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + + // Set the object for the parser. + xml_set_object($this->parser, $this); + + // Set the element handlers for the parser. + if ($type == "schema") { + xml_set_element_handler($this->parser, 'schemaStartElement', 'schemaEndElement'); + xml_set_character_data_handler($this->parser, 'schemaCharacterData'); + } elseif ($type == "xml") { + xml_set_element_handler($this->parser, 'xmlStartElement', 'xmlEndElement'); + xml_set_character_data_handler($this->parser, 'xmlCharacterData'); + } + + // Parse the XML file. + if (!xml_parse($this->parser, $xml, true)) { + // Display an error message. + $errstr = sprintf('XML error parsing XML schema on line %d: %s', + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser)) + ); + $this->debug($errstr); + $this->debug("XML payload:\n" . $xml); + $this->setError($errstr); + } + + xml_parser_free($this->parser); + unset($this->parser); + } else { + $this->debug('no xml passed to parseString()!!'); + $this->setError('no xml passed to parseString()!!'); + } + } + + /** + * gets a type name for an unnamed type + * + * @param string Element name + * @return string A type name for an unnamed type + * @access private + */ + function CreateTypeName($ename) + { + $scope = ''; + for ($i = 0; $i < count($this->complexTypeStack); $i++) { + $scope .= $this->complexTypeStack[$i] . '_'; + } + return $scope . $ename . '_ContainedType'; + } + + /** + * start-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @param string $attrs associative array of attributes + * @access private + */ + function schemaStartElement($parser, $name, $attrs) + { + + // position in the total number of elements, starting from 0 + $pos = $this->position++; + $depth = $this->depth++; + // set self as current value for this depth + $this->depth_array[$depth] = $pos; + $this->message[$pos] = array('cdata' => ''); + if ($depth > 0) { + $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]]; + } else { + $this->defaultNamespace[$pos] = false; + } + + // get element prefix + if ($prefix = $this->getPrefix($name)) { + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + + // loop thru attributes, expanding, and registering namespace declarations + if (count($attrs) > 0) { + foreach ($attrs as $k => $v) { + // if ns declarations, add to class level array of valid namespaces + if (preg_match('/^xmlns/', $k)) { + //$this->xdebug("$k: $v"); + //$this->xdebug('ns_prefix: '.$this->getPrefix($k)); + if ($ns_prefix = substr(strrchr($k, ':'), 1)) { + //$this->xdebug("Add namespace[$ns_prefix] = $v"); + $this->namespaces[$ns_prefix] = $v; + } else { + $this->defaultNamespace[$pos] = $v; + if (!$this->getPrefixFromNamespace($v)) { + $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; + } + } + if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v . '-instance'; + } + } + } + foreach ($attrs as $k => $v) { + // expand each attribute + $k = strpos($k, ':') ? $this->expandQname($k) : $k; + $v = strpos($v, ':') ? $this->expandQname($v) : $v; + $eAttrs[$k] = $v; + } + $attrs = $eAttrs; + } else { + $attrs = array(); + } + // find status, register data + switch ($name) { + case 'all': // (optional) compositor content for a complexType + case 'choice': + case 'group': + case 'sequence': + //$this->xdebug("compositor $name for currentComplexType: $this->currentComplexType and currentElement: $this->currentElement"); + $this->complexTypes[$this->currentComplexType]['compositor'] = $name; + //if($name == 'all' || $name == 'sequence'){ + // $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + //} + break; + case 'attribute': // complexType attribute + //$this->xdebug("parsing attribute $attrs[name] $attrs[ref] of value: ".$attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']); + $this->xdebug("parsing attribute:"); + $this->appendDebug($this->varDump($attrs)); + if (!isset($attrs['form'])) { + // TODO: handle globals + $attrs['form'] = $this->schemaInfo['attributeFormDefault']; + } + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + if (!strpos($v, ':')) { + // no namespace in arrayType attribute value... + if ($this->defaultNamespace[$pos]) { + // ...so use the default + $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } + } + } + if (isset($attrs['name'])) { + $this->attributes[$attrs['name']] = $attrs; + $aname = $attrs['name']; + } elseif (isset($attrs['ref']) && $attrs['ref'] == 'http://schemas.xmlsoap.org/soap/encoding/:arrayType') { + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } else { + $aname = ''; + } + } elseif (isset($attrs['ref'])) { + $aname = $attrs['ref']; + $this->attributes[$attrs['ref']] = $attrs; + } + + if ($this->currentComplexType) { // This should *always* be + $this->complexTypes[$this->currentComplexType]['attrs'][$aname] = $attrs; + } + // arrayType attribute + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']) || $this->getLocalPart($aname) == 'arrayType') { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + $prefix = $this->getPrefix($aname); + if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) { + $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType']; + } else { + $v = ''; + } + if (strpos($v, '[,]')) { + $this->complexTypes[$this->currentComplexType]['multidimensional'] = true; + } + $v = substr($v, 0, strpos($v, '[')); // clip the [] + if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) { + $v = $this->XMLSchemaVersion . ':' . $v; + } + $this->complexTypes[$this->currentComplexType]['arrayType'] = $v; + } + break; + case 'complexContent': // (optional) content for a complexType + $this->xdebug("do nothing for element $name"); + break; + case 'complexType': + array_push($this->complexTypeStack, $this->currentComplexType); + if (isset($attrs['name'])) { + // TODO: what is the scope of named complexTypes that appear + // nested within other c complexTypes? + $this->xdebug('processing named complexType ' . $attrs['name']); + //$this->currentElement = false; + $this->currentComplexType = $attrs['name']; + $this->complexTypes[$this->currentComplexType] = $attrs; + $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; + // This is for constructs like + // + // + // + // + // + if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) { + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } else { + $name = $this->CreateTypeName($this->currentElement); + $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name); + $this->currentComplexType = $name; + //$this->currentElement = false; + $this->complexTypes[$this->currentComplexType] = $attrs; + $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType'; + // This is for constructs like + // + // + // + // + // + if (isset($attrs['base']) && preg_match('/:Array$/', $attrs['base'])) { + $this->xdebug('complexType is unusual array'); + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } else { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct'; + } + } + $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false'; + break; + case 'element': + array_push($this->elementStack, $this->currentElement); + if (!isset($attrs['form'])) { + if ($this->currentComplexType) { + $attrs['form'] = $this->schemaInfo['elementFormDefault']; + } else { + // global + $attrs['form'] = 'qualified'; + } + } + if (isset($attrs['type'])) { + $this->xdebug("processing typed element " . $attrs['name'] . " of type " . $attrs['type']); + if (!$this->getPrefix($attrs['type'])) { + if ($this->defaultNamespace[$pos]) { + $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type']; + $this->xdebug('used default namespace to make type ' . $attrs['type']); + } + } + // This is for constructs like + // + // + // + // + // + if ($this->currentComplexType && $this->complexTypes[$this->currentComplexType]['phpType'] == 'array') { + $this->xdebug('arrayType for unusual array is ' . $attrs['type']); + $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type']; + } + $this->currentElement = $attrs['name']; + $ename = $attrs['name']; + } elseif (isset($attrs['ref'])) { + $this->xdebug("processing element as ref to " . $attrs['ref']); + $this->currentElement = "ref to " . $attrs['ref']; + $ename = $this->getLocalPart($attrs['ref']); + } else { + $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']); + $this->xdebug("processing untyped element " . $attrs['name'] . ' type ' . $type); + $this->currentElement = $attrs['name']; + $attrs['type'] = $this->schemaTargetNamespace . ':' . $type; + $ename = $attrs['name']; + } + if (isset($ename) && $this->currentComplexType) { + $this->xdebug("add element $ename to complexType $this->currentComplexType"); + $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs; + } elseif (!isset($attrs['ref'])) { + $this->xdebug("add element $ename to elements array"); + $this->elements[$attrs['name']] = $attrs; + $this->elements[$attrs['name']]['typeClass'] = 'element'; + } + break; + case 'enumeration': // restriction value list member + $this->xdebug('enumeration ' . $attrs['value']); + if ($this->currentSimpleType) { + $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value']; + } elseif ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value']; + } + break; + case 'extension': // simpleContent or complexContent type extension + $this->xdebug('extension ' . $attrs['base']); + if ($this->currentComplexType) { + $ns = $this->getPrefix($attrs['base']); + if ($ns == '') { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base']; + } else { + $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base']; + } + } else { + $this->xdebug('no current complexType to set extensionBase'); + } + break; + case 'import': + if (isset($attrs['schemaLocation'])) { + $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']); + $this->imports[$attrs['namespace']][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); + } else { + $this->xdebug('import namespace ' . $attrs['namespace']); + $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true); + if (!$this->getPrefixFromNamespace($attrs['namespace'])) { + $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace']; + } + } + break; + case 'include': + if (isset($attrs['schemaLocation'])) { + $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']); + $this->imports[$this->schemaTargetNamespace][] = array('location' => $attrs['schemaLocation'], 'loaded' => false); + } else { + $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute'); + } + break; + case 'list': // simpleType value list + $this->xdebug("do nothing for element $name"); + break; + case 'restriction': // simpleType, simpleContent or complexContent value restriction + $this->xdebug('restriction ' . $attrs['base']); + if ($this->currentSimpleType) { + $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base']; + } elseif ($this->currentComplexType) { + $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base']; + if (strstr($attrs['base'], ':') == ':Array') { + $this->complexTypes[$this->currentComplexType]['phpType'] = 'array'; + } + } + break; + case 'schema': + $this->schemaInfo = $attrs; + $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix); + if (isset($attrs['targetNamespace'])) { + $this->schemaTargetNamespace = $attrs['targetNamespace']; + } + if (!isset($attrs['elementFormDefault'])) { + $this->schemaInfo['elementFormDefault'] = 'unqualified'; + } + if (!isset($attrs['attributeFormDefault'])) { + $this->schemaInfo['attributeFormDefault'] = 'unqualified'; + } + break; + case 'simpleContent': // (optional) content for a complexType + if ($this->currentComplexType) { // This should *always* be + $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true'; + } else { + $this->xdebug("do nothing for element $name because there is no current complexType"); + } + break; + case 'simpleType': + array_push($this->simpleTypeStack, $this->currentSimpleType); + if (isset($attrs['name'])) { + $this->xdebug("processing simpleType for name " . $attrs['name']); + $this->currentSimpleType = $attrs['name']; + $this->simpleTypes[$attrs['name']] = $attrs; + $this->simpleTypes[$attrs['name']]['typeClass'] = 'simpleType'; + $this->simpleTypes[$attrs['name']]['phpType'] = 'scalar'; + } else { + $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement); + $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name); + $this->currentSimpleType = $name; + //$this->currentElement = false; + $this->simpleTypes[$this->currentSimpleType] = $attrs; + $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar'; + } + break; + case 'union': // simpleType type list + $this->xdebug("do nothing for element $name"); + break; + default: + $this->xdebug("do not have any logic to process element $name"); + } + } + + /** + * end-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @access private + */ + function schemaEndElement($parser, $name) + { + // bring depth down a notch + $this->depth--; + // position of current element is equal to the last value left in depth_array for my depth + if (isset($this->depth_array[$this->depth])) { + $pos = $this->depth_array[$this->depth]; + } + // get element prefix + if ($prefix = $this->getPrefix($name)) { + // get unqualified name + $name = $this->getLocalPart($name); + } else { + $prefix = ''; + } + // move on... + if ($name == 'complexType') { + $this->xdebug('done processing complexType ' . ($this->currentComplexType ? $this->currentComplexType : '(unknown)')); + $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType])); + $this->currentComplexType = array_pop($this->complexTypeStack); + //$this->currentElement = false; + } + if ($name == 'element') { + $this->xdebug('done processing element ' . ($this->currentElement ? $this->currentElement : '(unknown)')); + $this->currentElement = array_pop($this->elementStack); + } + if ($name == 'simpleType') { + $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ? $this->currentSimpleType : '(unknown)')); + $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType])); + $this->currentSimpleType = array_pop($this->simpleTypeStack); + } + } + + /** + * element content handler + * + * @param string $parser XML parser object + * @param string $data element content + * @access private + */ + function schemaCharacterData($parser, $data) + { + $pos = $this->depth_array[$this->depth - 1]; + $this->message[$pos]['cdata'] .= $data; + } + + /** + * serialize the schema + * + * @access public + */ + function serializeSchema() + { + + $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion); + $xml = ''; + // imports + if (sizeof($this->imports) > 0) { + foreach ($this->imports as $ns => $list) { + foreach ($list as $ii) { + if ($ii['location'] != '') { + $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n"; + } else { + $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n"; + } + } + } + } + // complex types + foreach ($this->complexTypes as $typeName => $attrs) { + $contentStr = ''; + // serialize child elements + if (isset($attrs['elements']) && (count($attrs['elements']) > 0)) { + foreach ($attrs['elements'] as $element => $eParts) { + if (isset($eParts['ref'])) { + $contentStr .= " <$schemaPrefix:element ref=\"$element\"/>\n"; + } else { + $contentStr .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\""; + foreach ($eParts as $aName => $aValue) { + // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable + if ($aName != 'name' && $aName != 'type') { + $contentStr .= " $aName=\"$aValue\""; + } + } + $contentStr .= "/>\n"; + } + } + // compositor wraps elements + if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) { + $contentStr = " <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . " \n"; + } + } + // attributes + if (isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)) { + foreach ($attrs['attrs'] as $attr => $aParts) { + $contentStr .= " <$schemaPrefix:attribute"; + foreach ($aParts as $a => $v) { + if ($a == 'ref' || $a == 'type') { + $contentStr .= " $a=\"" . $this->contractQName($v) . '"'; + } elseif ($a == 'http://schemas.xmlsoap.org/wsdl/:arrayType') { + $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl']; + $contentStr .= ' wsdl:arrayType="' . $this->contractQName($v) . '"'; + } else { + $contentStr .= " $a=\"$v\""; + } + } + $contentStr .= "/>\n"; + } + } + // if restriction + if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != '') { + $contentStr = " <$schemaPrefix:restriction base=\"" . $this->contractQName($attrs['restrictionBase']) . "\">\n" . $contentStr . " \n"; + // complex or simple content + if ((isset($attrs['elements']) && count($attrs['elements']) > 0) || (isset($attrs['attrs']) && count($attrs['attrs']) > 0)) { + $contentStr = " <$schemaPrefix:complexContent>\n" . $contentStr . " \n"; + } + } + // finalize complex type + if ($contentStr != '') { + $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " \n"; + } else { + $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n"; + } + $xml .= $contentStr; + } + // simple types + if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) { + foreach ($this->simpleTypes as $typeName => $eParts) { + $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n <$schemaPrefix:restriction base=\"" . $this->contractQName($eParts['type']) . "\">\n"; + if (isset($eParts['enumeration'])) { + foreach ($eParts['enumeration'] as $e) { + $xml .= " <$schemaPrefix:enumeration value=\"$e\"/>\n"; + } + } + $xml .= " \n "; + } + } + // elements + if (isset($this->elements) && count($this->elements) > 0) { + foreach ($this->elements as $element => $eParts) { + $xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQName($eParts['type']) . "\"/>\n"; + } + } + // attributes + if (isset($this->attributes) && count($this->attributes) > 0) { + foreach ($this->attributes as $attr => $aParts) { + $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQName($aParts['type']) . "\"\n/>"; + } + } + // finish 'er up + $attr = ''; + foreach ($this->schemaInfo as $k => $v) { + if ($k == 'elementFormDefault' || $k == 'attributeFormDefault') { + $attr .= " $k=\"$v\""; + } + } + $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n"; + foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) { + $el .= " xmlns:$nsp=\"$ns\""; + } + $xml = $el . ">\n" . $xml . "\n"; + return $xml; + } + + /** + * adds debug data to the clas level debug string + * + * @param string $string debug data + * @access private + */ + function xdebug($string) + { + $this->debug('<' . $this->schemaTargetNamespace . '> ' . $string); + } + + /** + * get the PHP type of a user defined type in the schema + * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays + * returns false if no type exists, or not w/ the given namespace + * else returns a string that is either a native php type, or 'struct' + * + * @param string $type name of defined type + * @param string $ns namespace of type + * @return mixed + * @access public + * @deprecated + */ + function getPHPType($type, $ns) + { + if (isset($this->typemap[$ns][$type])) { + //print "found type '$type' and ns $ns in typemap
"; + return $this->typemap[$ns][$type]; + } elseif (isset($this->complexTypes[$type])) { + //print "getting type '$type' and ns $ns from complexTypes array
"; + return $this->complexTypes[$type]['phpType']; + } + return false; + } + + /** + * returns an associative array of information about a given type + * returns false if no type exists by the given name + * + * For a complexType typeDef = array( + * 'restrictionBase' => '', + * 'phpType' => '', + * 'compositor' => '(sequence|all)', + * 'elements' => array(), // refs to elements array + * 'attrs' => array() // refs to attributes array + * ... and so on (see addComplexType) + * ) + * + * For simpleType or element, the array has different keys. + * + * @param string $type + * @return mixed + * @access public + * @see addComplexType + * @see addSimpleType + * @see addElement + */ + function getTypeDef($type) + { + //$this->debug("in getTypeDef for type $type"); + if (substr($type, -1) == '^') { + $is_element = 1; + $type = substr($type, 0, -1); + } else { + $is_element = 0; + } + + if ((!$is_element) && isset($this->complexTypes[$type])) { + $this->xdebug("in getTypeDef, found complexType $type"); + return $this->complexTypes[$type]; + } elseif ((!$is_element) && isset($this->simpleTypes[$type])) { + $this->xdebug("in getTypeDef, found simpleType $type"); + if (!isset($this->simpleTypes[$type]['phpType'])) { + // get info for type to tack onto the simple type + // TODO: can this ever really apply (i.e. what is a simpleType really?) + $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1); + $ns = substr($this->simpleTypes[$type]['type'], 0, strrpos($this->simpleTypes[$type]['type'], ':')); + $etype = $this->getTypeDef($uqType); + if ($etype) { + $this->xdebug("in getTypeDef, found type for simpleType $type:"); + $this->xdebug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $this->simpleTypes[$type]['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $this->simpleTypes[$type]['elements'] = $etype['elements']; + } + } + } + return $this->simpleTypes[$type]; + } elseif (isset($this->elements[$type])) { + $this->xdebug("in getTypeDef, found element $type"); + if (!isset($this->elements[$type]['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1); + $ns = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':')); + $etype = $this->getTypeDef($uqType); + if ($etype) { + $this->xdebug("in getTypeDef, found type for element $type:"); + $this->xdebug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $this->elements[$type]['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $this->elements[$type]['elements'] = $etype['elements']; + } + if (isset($etype['extensionBase'])) { + $this->elements[$type]['extensionBase'] = $etype['extensionBase']; + } + } elseif ($ns == 'http://www.w3.org/2001/XMLSchema') { + $this->xdebug("in getTypeDef, element $type is an XSD type"); + $this->elements[$type]['phpType'] = 'scalar'; + } + } + return $this->elements[$type]; + } elseif (isset($this->attributes[$type])) { + $this->xdebug("in getTypeDef, found attribute $type"); + return $this->attributes[$type]; + } elseif (preg_match('/_ContainedType$/', $type)) { + $this->xdebug("in getTypeDef, have an untyped element $type"); + $typeDef['typeClass'] = 'simpleType'; + $typeDef['phpType'] = 'scalar'; + $typeDef['type'] = 'http://www.w3.org/2001/XMLSchema:string'; + return $typeDef; + } + $this->xdebug("in getTypeDef, did not find $type"); + return false; + } + + /** + * returns a sample serialization of a given type, or false if no type by the given name + * + * @param string $type name of type + * @return mixed + * @access public + * @deprecated + */ + function serializeTypeDef($type) + { + $str = ''; + //print "in sTD() for type $type
"; + if ($typeDef = $this->getTypeDef($type)) { + $str .= '<' . $type; + if (is_array($typeDef['attrs'])) { + foreach ($typeDef['attrs'] as $attName => $data) { + $str .= " $attName=\"{type = " . $data['type'] . "}\""; + } + } + $str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\""; + if (count($typeDef['elements']) > 0) { + $str .= ">"; + foreach ($typeDef['elements'] as $element => $eData) { + $str .= $this->serializeTypeDef($element); + } + $str .= ""; + } elseif ($typeDef['typeClass'] == 'element') { + $str .= ">"; + } else { + $str .= "/>"; + } + return $str; + } + return false; + } + + /** + * returns HTML form elements that allow a user + * to enter values for creating an instance of the given type. + * + * @param string $name name for type instance + * @param string $type name of type + * @return string + * @access public + * @deprecated + */ + function typeToForm($name, $type) + { + $buffer = ''; + // get typedef + if ($typeDef = $this->getTypeDef($type)) { + // if struct + if ($typeDef['phpType'] == 'struct') { + $buffer .= ''; + foreach ($typeDef['elements'] as $child => $childDef) { + $buffer .= " + + "; + } + $buffer .= '
$childDef[name] (type: " . $this->getLocalPart($childDef['type']) . "):
'; + // if array + } elseif ($typeDef['phpType'] == 'array') { + $buffer .= ''; + for ($i = 0; $i < 3; $i++) { + $buffer .= " + + "; + } + $buffer .= '
array item (type: $typeDef[arrayType]):
'; + // if scalar + } else { + $buffer .= ""; + } + } else { + $buffer .= ""; + } + return $buffer; + } + + /** + * adds a complex type to the schema + * + * example: array + * + * addType( + * 'ArrayOfstring', + * 'complexType', + * 'array', + * '', + * 'SOAP-ENC:Array', + * array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'), + * 'xsd:string' + * ); + * + * example: PHP associative array ( SOAP Struct ) + * + * addType( + * 'SOAPStruct', + * 'complexType', + * 'struct', + * 'all', + * array('myVar'=> array('name'=>'myVar','type'=>'string') + * ); + * + * @param name + * @param typeClass (complexType|simpleType|attribute) + * @param phpType : currently supported are array and struct (php assoc array) + * @param compositor (all|sequence|choice) + * @param restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param elements = array ( name = array(name=>'',type=>'') ) + * @param attrs = array( + * array( + * 'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType", + * "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]" + * ) + * ) + * @param arrayType : namespace:name (http://www.w3.org/2001/XMLSchema:string) + * @access public + * @see getTypeDef + */ + function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '') + { + $this->complexTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'compositor' => $compositor, + 'restrictionBase' => $restrictionBase, + 'elements' => $elements, + 'attrs' => $attrs, + 'arrayType' => $arrayType + ); + + $this->xdebug("addComplexType $name:"); + $this->appendDebug($this->varDump($this->complexTypes[$name])); + } + + /** + * adds a simple type to the schema + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @access public + * @see nusoap_xmlschema + * @see getTypeDef + */ + function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array()) + { + $this->simpleTypes[$name] = array( + 'name' => $name, + 'typeClass' => $typeClass, + 'phpType' => $phpType, + 'type' => $restrictionBase, + 'enumeration' => $enumeration + ); + + $this->xdebug("addSimpleType $name:"); + $this->appendDebug($this->varDump($this->simpleTypes[$name])); + } + + /** + * adds an element to the schema + * + * @param array $attrs attributes that must include name and type + * @see nusoap_xmlschema + * @access public + */ + function addElement($attrs) + { + if (!$this->getPrefix($attrs['type'])) { + $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type']; + } + $this->elements[$attrs['name']] = $attrs; + $this->elements[$attrs['name']]['typeClass'] = 'element'; + + $this->xdebug("addElement " . $attrs['name']); + $this->appendDebug($this->varDump($this->elements[$attrs['name']])); + } +} + +/** + * Backward compatibility + */ +class XMLSchema extends nusoap_xmlschema +{ +} + + +/** + * For creating serializable abstractions of native PHP types. This class + * allows element name/namespace, XSD type, and XML attributes to be + * associated with a value. This is extremely useful when WSDL is not + * used, but is also useful when WSDL is used with polymorphic types, including + * xsd:anyType and user-defined types. + * + * @author Dietrich Ayala + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class soapval extends nusoap_base +{ + /** + * The XML element name + * + * @var string + * @access private + */ + var $name; + /** + * The XML type name (string or false) + * + * @var mixed + * @access private + */ + var $type; + /** + * The PHP value + * + * @var mixed + * @access private + */ + var $value; + /** + * The XML element namespace (string or false) + * + * @var mixed + * @access private + */ + var $element_ns; + /** + * The XML type namespace (string or false) + * + * @var mixed + * @access private + */ + var $type_ns; + /** + * The XML element attributes (array or false) + * + * @var mixed + * @access private + */ + var $attributes; + + /** + * constructor + * + * @param string $name optional name + * @param mixed $type optional type name + * @param mixed $value optional value + * @param mixed $element_ns optional namespace of value + * @param mixed $type_ns optional namespace of type + * @param mixed $attributes associative array of attributes to add to element serialization + * @access public + */ + function __construct($name = 'soapval', $type = false, $value = -1, $element_ns = false, $type_ns = false, $attributes = false) + { + parent::__construct(); + $this->name = $name; + $this->type = $type; + $this->value = $value; + $this->element_ns = $element_ns; + $this->type_ns = $type_ns; + $this->attributes = $attributes; + } + + /** + * return serialized value + * + * @param string $use The WSDL use value (encoded|literal) + * @return string XML data + * @access public + */ + function serialize($use = 'encoded') + { + return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true); + } + + /** + * decodes a soapval object into a PHP native type + * + * @return mixed + * @access public + */ + function decode() + { + return $this->value; + } +} + + +/** + * transport class for sending/receiving data via HTTP and HTTPS + * NOTE: PHP must be compiled with the CURL extension for HTTPS support + * + * @author Dietrich Ayala + * @author Scott Nichol + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class soap_transport_http extends nusoap_base +{ + + var $url = ''; + var $uri = ''; + var $digest_uri = ''; + var $scheme = ''; + var $host = ''; + var $port = ''; + var $path = ''; + var $request_method = 'POST'; + var $protocol_version = '1.0'; + var $encoding = ''; + var $outgoing_headers = array(); + var $incoming_headers = array(); + var $incoming_cookies = array(); + var $outgoing_payload = ''; + var $incoming_payload = ''; + var $response_status_line; // HTTP response status line + var $useSOAPAction = true; + var $persistentConnection = false; + var $ch = false; // cURL handle + var $ch_options = array(); // cURL custom options + var $use_curl = false; // force cURL use + var $proxy = null; // proxy information (associative array) + var $username = ''; + var $password = ''; + var $authtype = ''; + var $digestRequest = array(); + var $certRequest = array(); // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional) + // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem' + // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem' + // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem' + // passphrase: SSL key password/passphrase + // certpassword: SSL certificate password + // verifypeer: default is 1 + // verifyhost: default is 1 + + /** + * constructor + * + * @param string $url The URL to which to connect + * @param array $curl_options User-specified cURL options + * @param boolean $use_curl Whether to try to force cURL use + * @access public + */ + function __construct($url, $curl_options = null, $use_curl = false) + { + parent::__construct(); + $this->debug("ctor url=$url use_curl=$use_curl curl_options:"); + $this->appendDebug($this->varDump($curl_options)); + $this->setURL($url); + if (is_array($curl_options)) { + $this->ch_options = $curl_options; + } + $this->use_curl = $use_curl; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->setHeader('User-Agent', $this->title . '/' . $this->version . ' (' . $rev[1] . ')'); + } + + /** + * sets a cURL option + * + * @param mixed $option The cURL option (always integer?) + * @param mixed $value The cURL option value + * @access private + */ + function setCurlOption($option, $value) + { + $this->debug("setCurlOption option=$option, value="); + $this->appendDebug($this->varDump($value)); + curl_setopt($this->ch, $option, $value); + } + + /** + * sets an HTTP header + * + * @param string $name The name of the header + * @param string $value The value of the header + * @access private + */ + function setHeader($name, $value) + { + $this->outgoing_headers[$name] = $value; + $this->debug("set header $name: $value"); + } + + /** + * unsets an HTTP header + * + * @param string $name The name of the header + * @access private + */ + function unsetHeader($name) + { + if (isset($this->outgoing_headers[$name])) { + $this->debug("unset header $name"); + unset($this->outgoing_headers[$name]); + } + } + + /** + * sets the URL to which to connect + * + * @param string $url The URL to which to connect + * @access private + */ + function setURL($url) + { + $this->url = $url; + + $u = parse_url($url); + foreach ($u as $k => $v) { + $this->debug("parsed URL $k = $v"); + $this->$k = $v; + } + + // add any GET params to path + if (isset($u['query']) && $u['query'] != '') { + $this->path .= '?' . $u['query']; + } + + // set default port + if (!isset($u['port'])) { + if ($u['scheme'] == 'https') { + $this->port = 443; + } else { + $this->port = 80; + } + } + + $this->uri = $this->path; + $this->digest_uri = $this->uri; + + // build headers + if (!isset($u['port'])) { + $this->setHeader('Host', $this->host); + } else { + $this->setHeader('Host', $this->host . ':' . $this->port); + } + + if (isset($u['user']) && $u['user'] != '') { + $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : ''); + } + } + + /** + * gets the I/O method to use + * + * @return string I/O method to use (socket|curl|unknown) + * @access private + */ + function io_method() + { + if ($this->use_curl || ($this->scheme == 'https') || ($this->scheme == 'http' && $this->authtype == 'ntlm') || ($this->scheme == 'http' && is_array($this->proxy) && $this->proxy['authtype'] == 'ntlm')) { + return 'curl'; + } + if (($this->scheme == 'http' || $this->scheme == 'ssl') && $this->authtype != 'ntlm' && (!is_array($this->proxy) || $this->proxy['authtype'] != 'ntlm')) { + return 'socket'; + } + return 'unknown'; + } + + /** + * establish an HTTP connection + * + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @return boolean true if connected, false if not + * @access private + */ + function connect($connection_timeout = 0, $response_timeout = 30) + { + // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like + // "regular" socket. + // TODO: disabled for now because OpenSSL must be *compiled* in (not just + // loaded), and until PHP5 stream_get_wrappers is not available. +// if ($this->scheme == 'https') { +// if (version_compare(phpversion(), '4.3.0') >= 0) { +// if (extension_loaded('openssl')) { +// $this->scheme = 'ssl'; +// $this->debug('Using SSL over OpenSSL'); +// } +// } +// } + $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port"); + if ($this->io_method() == 'socket') { + if (!is_array($this->proxy)) { + $host = $this->host; + $port = $this->port; + } else { + $host = $this->proxy['host']; + $port = $this->proxy['port']; + } + + // use persistent connection + if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) { + if (!feof($this->fp)) { + $this->debug('Re-use persistent connection'); + return true; + } + fclose($this->fp); + $this->debug('Closed persistent connection at EOF'); + } + + // munge host if using OpenSSL + if ($this->scheme == 'ssl') { + $host = 'ssl://' . $host; + } + $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout); + + // open socket + if ($connection_timeout > 0) { + $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str, $connection_timeout); + } else { + $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str); + } + + // test pointer + if (!$this->fp) { + $msg = 'Couldn\'t open socket connection to server ' . $this->url; + if ($this->errno) { + $msg .= ', Error (' . $this->errno . '): ' . $this->error_str; + } else { + $msg .= ' prior to connect(). This is often a problem looking up the host name.'; + } + $this->debug($msg); + $this->setError($msg); + return false; + } + + // set response timeout + $this->debug('set response timeout to ' . $response_timeout); + socket_set_timeout($this->fp, $response_timeout); + + $this->debug('socket connected'); + return true; + } elseif ($this->io_method() == 'curl') { + if (!extension_loaded('curl')) { +// $this->setError('cURL Extension, or OpenSSL extension w/ PHP version >= 4.3 is required for HTTPS'); + $this->setError('The PHP cURL Extension is required for HTTPS or NLTM. You will need to re-build or update your PHP to include cURL or change php.ini to load the PHP cURL extension.'); + return false; + } + // Avoid warnings when PHP does not have these options + if (defined('CURLOPT_CONNECTIONTIMEOUT')) { + $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT; + } else { + $CURLOPT_CONNECTIONTIMEOUT = 78; + } + if (defined('CURLOPT_HTTPAUTH')) { + $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH; + } else { + $CURLOPT_HTTPAUTH = 107; + } + if (defined('CURLOPT_PROXYAUTH')) { + $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH; + } else { + $CURLOPT_PROXYAUTH = 111; + } + if (defined('CURLAUTH_BASIC')) { + $CURLAUTH_BASIC = CURLAUTH_BASIC; + } else { + $CURLAUTH_BASIC = 1; + } + if (defined('CURLAUTH_DIGEST')) { + $CURLAUTH_DIGEST = CURLAUTH_DIGEST; + } else { + $CURLAUTH_DIGEST = 2; + } + if (defined('CURLAUTH_NTLM')) { + $CURLAUTH_NTLM = CURLAUTH_NTLM; + } else { + $CURLAUTH_NTLM = 8; + } + + $this->debug('connect using cURL'); + // init CURL + $this->ch = curl_init(); + // set url + $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host"; + // add path + $hostURL .= $this->path; + $this->setCurlOption(CURLOPT_URL, $hostURL); + // follow location headers (re-directs) + if (ini_get('safe_mode') || ini_get('open_basedir')) { + $this->debug('safe_mode or open_basedir set, so do not set CURLOPT_FOLLOWLOCATION'); + $this->debug('safe_mode = '); + $this->appendDebug($this->varDump(ini_get('safe_mode'))); + $this->debug('open_basedir = '); + $this->appendDebug($this->varDump(ini_get('open_basedir'))); + } else { + $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1); + } + // ask for headers in the response output + $this->setCurlOption(CURLOPT_HEADER, 1); + // ask for the response output as the return value + $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1); + // encode + // We manage this ourselves through headers and encoding +// if(function_exists('gzuncompress')){ +// $this->setCurlOption(CURLOPT_ENCODING, 'deflate'); +// } + // persistent connection + if ($this->persistentConnection) { + // I believe the following comment is now bogus, having applied to + // the code when it used CURLOPT_CUSTOMREQUEST to send the request. + // The way we send data, we cannot use persistent connections, since + // there will be some "junk" at the end of our request. + //$this->setCurlOption(CURL_HTTP_VERSION_1_1, true); + $this->persistentConnection = false; + $this->setHeader('Connection', 'close'); + } + // set timeouts + if ($connection_timeout != 0) { + $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout); + } + if ($response_timeout != 0) { + $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout); + } + + if ($this->scheme == 'https') { + $this->debug('set cURL SSL verify options'); + // recent versions of cURL turn on peer/host checking by default, + // while PHP binaries are not compiled with a default location for the + // CA cert bundle, so disable peer/host checking. + //$this->setCurlOption(CURLOPT_CAINFO, 'f:\php-4.3.2-win32\extensions\curl-ca-bundle.crt'); + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0); + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0); + + // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo) + if ($this->authtype == 'certificate') { + $this->debug('set cURL certificate options'); + if (isset($this->certRequest['cainfofile'])) { + $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']); + } + if (isset($this->certRequest['verifypeer'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']); + } else { + $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1); + } + if (isset($this->certRequest['verifyhost'])) { + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']); + } else { + $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1); + } + if (isset($this->certRequest['sslcertfile'])) { + $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']); + } + if (isset($this->certRequest['sslkeyfile'])) { + $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']); + } + if (isset($this->certRequest['passphrase'])) { + $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']); + } + if (isset($this->certRequest['certpassword'])) { + $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']); + } + } + } + if ($this->authtype && ($this->authtype != 'certificate')) { + if ($this->username) { + $this->debug('set cURL username/password'); + $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password"); + } + if ($this->authtype == 'basic') { + $this->debug('set cURL for Basic authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC); + } + if ($this->authtype == 'digest') { + $this->debug('set cURL for digest authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST); + } + if ($this->authtype == 'ntlm') { + $this->debug('set cURL for NTLM authentication'); + $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM); + } + } + if (is_array($this->proxy)) { + $this->debug('set cURL proxy options'); + if ($this->proxy['port'] != '') { + $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port']); + } else { + $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']); + } + if ($this->proxy['username'] || $this->proxy['password']) { + $this->debug('set cURL proxy authentication options'); + $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password']); + if ($this->proxy['authtype'] == 'basic') { + $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC); + } + if ($this->proxy['authtype'] == 'ntlm') { + $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM); + } + } + } + $this->debug('cURL connection set up'); + return true; + } else { + $this->setError('Unknown scheme ' . $this->scheme); + $this->debug('Unknown scheme ' . $this->scheme); + return false; + } + } + + /** + * sends the SOAP request and gets the SOAP response via HTTP[S] + * + * @param string $data message data + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @param array $cookies cookies to send + * @return string data + * @access public + */ + function send($data, $timeout = 0, $response_timeout = 30, $cookies = null) + { + + $this->debug('entered send() with data of length: ' . strlen($data)); + + $this->tryagain = true; + $tries = 0; + while ($this->tryagain) { + $this->tryagain = false; + if ($tries++ < 2) { + // make connnection + if (!$this->connect($timeout, $response_timeout)) { + return false; + } + + // send request + if (!$this->sendRequest($data, $cookies)) { + return false; + } + + // get response + $respdata = $this->getResponse(); + } else { + $this->setError("Too many tries to get an OK response ($this->response_status_line)"); + } + } + $this->debug('end of send()'); + return $respdata; + } + + + /** + * sends the SOAP request and gets the SOAP response via HTTPS using CURL + * + * @param string $data message data + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @param array $cookies cookies to send + * @return string data + * @access public + * @deprecated + */ + function sendHTTPS($data, $timeout = 0, $response_timeout = 30, $cookies = null) + { + return $this->send($data, $timeout, $response_timeout, $cookies); + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $digestRequest (keys must be nonce, nc, realm, qop) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $digestRequest = array(), $certRequest = array()) + { + $this->debug("setCredentials username=$username authtype=$authtype digestRequest="); + $this->appendDebug($this->varDump($digestRequest)); + $this->debug("certRequest="); + $this->appendDebug($this->varDump($certRequest)); + // cf. RFC 2617 + if ($authtype == 'basic') { + $this->setHeader('Authorization', 'Basic ' . base64_encode(str_replace(':', '', $username) . ':' . $password)); + } elseif ($authtype == 'digest') { + if (isset($digestRequest['nonce'])) { + $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1; + + // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html) + + // A1 = unq(username-value) ":" unq(realm-value) ":" passwd + $A1 = $username . ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password; + + // H(A1) = MD5(A1) + $HA1 = md5($A1); + + // A2 = Method ":" digest-uri-value + $A2 = $this->request_method . ':' . $this->digest_uri; + + // H(A2) + $HA2 = md5($A2); + + // KD(secret, data) = H(concat(secret, ":", data)) + // if qop == auth: + // request-digest = <"> < KD ( H(A1), unq(nonce-value) + // ":" nc-value + // ":" unq(cnonce-value) + // ":" unq(qop-value) + // ":" H(A2) + // ) <"> + // if qop is missing, + // request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <"> + + $unhashedDigest = ''; + $nonce = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : ''; + $cnonce = $nonce; + if ($digestRequest['qop'] != '') { + $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf("%08d", $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2; + } else { + $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2; + } + + $hashedDigest = md5($unhashedDigest); + + $opaque = ''; + if (isset($digestRequest['opaque'])) { + $opaque = ', opaque="' . $digestRequest['opaque'] . '"'; + } + + $this->setHeader('Authorization', 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf("%08x", $digestRequest['nc']) . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"'); + } + } elseif ($authtype == 'certificate') { + $this->certRequest = $certRequest; + $this->debug('Authorization header not set for certificate'); + } elseif ($authtype == 'ntlm') { + // do nothing + $this->debug('Authorization header not set for ntlm'); + } + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->digestRequest = $digestRequest; + } + + /** + * set the soapaction value + * + * @param string $soapaction + * @access public + */ + function setSOAPAction($soapaction) + { + $this->setHeader('SOAPAction', '"' . $soapaction . '"'); + } + + /** + * use http encoding + * + * @param string $enc encoding style. supported values: gzip, deflate, or both + * @access public + */ + function setEncoding($enc = 'gzip, deflate') + { + if (function_exists('gzdeflate')) { + $this->protocol_version = '1.1'; + $this->setHeader('Accept-Encoding', $enc); + if (!isset($this->outgoing_headers['Connection'])) { + $this->setHeader('Connection', 'close'); + $this->persistentConnection = false; + } + // deprecated as of PHP 5.3.0 + //set_magic_quotes_runtime(0); + $this->encoding = $enc; + } + } + + /** + * set proxy info here + * + * @param string $proxyhost use an empty string to remove proxy + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @param string $proxyauthtype (basic|ntlm) + * @access public + */ + function setProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '', $proxyauthtype = 'basic') + { + if ($proxyhost) { + $this->proxy = array( + 'host' => $proxyhost, + 'port' => $proxyport, + 'username' => $proxyusername, + 'password' => $proxypassword, + 'authtype' => $proxyauthtype + ); + if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') { + $this->setHeader('Proxy-Authorization', ' Basic ' . base64_encode($proxyusername . ':' . $proxypassword)); + } + } else { + $this->debug('remove proxy'); + $proxy = null; + unsetHeader('Proxy-Authorization'); + } + } + + + /** + * Test if the given string starts with a header that is to be skipped. + * Skippable headers result from chunked transfer and proxy requests. + * + * @param string $data The string to check. + * @returns boolean Whether a skippable header was found. + * @access private + */ + function isSkippableCurlHeader(&$data) + { + $skipHeaders = array('HTTP/1.1 100', + 'HTTP/1.0 301', + 'HTTP/1.1 301', + 'HTTP/1.0 302', + 'HTTP/1.1 302', + 'HTTP/1.0 401', + 'HTTP/1.1 401', + 'HTTP/1.0 200 Connection established'); + foreach ($skipHeaders as $hd) { + $prefix = substr($data, 0, strlen($hd)); + if ($prefix == $hd) { + return true; + } + } + + return false; + } + + /** + * decode a string that is encoded w/ "chunked' transfer encoding + * as defined in RFC2068 19.4.6 + * + * @param string $buffer + * @param string $lb + * @returns string + * @access public + * @deprecated + */ + function decodeChunked($buffer, $lb) + { + // length := 0 + $length = 0; + $new = ''; + + // read chunk-size, chunk-extension (if any) and CRLF + // get the position of the linebreak + $chunkend = strpos($buffer, $lb); + if ($chunkend == false) { + $this->debug('no linebreak found in decodeChunked'); + return $new; + } + $temp = substr($buffer, 0, $chunkend); + $chunk_size = hexdec(trim($temp)); + $chunkstart = $chunkend + strlen($lb); + // while (chunk-size > 0) { + while ($chunk_size > 0) { + $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size"); + $chunkend = strpos($buffer, $lb, $chunkstart + $chunk_size); + + // Just in case we got a broken connection + if ($chunkend == false) { + $chunk = substr($buffer, $chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + $length += strlen($chunk); + break; + } + + // read chunk-data and CRLF + $chunk = substr($buffer, $chunkstart, $chunkend - $chunkstart); + // append chunk-data to entity-body + $new .= $chunk; + // length := length + chunk-size + $length += strlen($chunk); + // read chunk-size and CRLF + $chunkstart = $chunkend + strlen($lb); + + $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb); + if ($chunkend == false) { + break; //Just in case we got a broken connection + } + $temp = substr($buffer, $chunkstart, $chunkend - $chunkstart); + $chunk_size = hexdec(trim($temp)); + $chunkstart = $chunkend; + } + return $new; + } + + /** + * Writes the payload, including HTTP headers, to $this->outgoing_payload. + * + * @param string $data HTTP body + * @param string $cookie_str data for HTTP Cookie header + * @return void + * @access private + */ + function buildPayload($data, $cookie_str = '') + { + // Note: for cURL connections, $this->outgoing_payload is ignored, + // as is the Content-Length header, but these are still created as + // debugging guides. + + // add content-length header + if ($this->request_method != 'GET') { + $this->setHeader('Content-Length', strlen($data)); + } + + // start building outgoing payload: + if ($this->proxy) { + $uri = $this->url; + } else { + $uri = $this->uri; + } + $req = "$this->request_method $uri HTTP/$this->protocol_version"; + $this->debug("HTTP request: $req"); + $this->outgoing_payload = "$req\r\n"; + + // loop thru headers, serializing + foreach ($this->outgoing_headers as $k => $v) { + $hdr = $k . ': ' . $v; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // add any cookies + if ($cookie_str != '') { + $hdr = 'Cookie: ' . $cookie_str; + $this->debug("HTTP header: $hdr"); + $this->outgoing_payload .= "$hdr\r\n"; + } + + // header/body separator + $this->outgoing_payload .= "\r\n"; + + // add data + $this->outgoing_payload .= $data; + } + + /** + * sends the SOAP request via HTTP[S] + * + * @param string $data message data + * @param array $cookies cookies to send + * @return boolean true if OK, false if problem + * @access private + */ + function sendRequest($data, $cookies = null) + { + // build cookie string + $cookie_str = $this->getCookiesForRequest($cookies, (($this->scheme == 'ssl') || ($this->scheme == 'https'))); + + // build payload + $this->buildPayload($data, $cookie_str); + + if ($this->io_method() == 'socket') { + // send payload + if (!fputs($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) { + $this->setError('couldn\'t write message data to socket'); + $this->debug('couldn\'t write message data to socket'); + return false; + } + $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload)); + return true; + } elseif ($this->io_method() == 'curl') { + // set payload + // cURL does say this should only be the verb, and in fact it + // turns out that the URI and HTTP version are appended to this, which + // some servers refuse to work with (so we no longer use this method!) + //$this->setCurlOption(CURLOPT_CUSTOMREQUEST, $this->outgoing_payload); + $curl_headers = array(); + foreach ($this->outgoing_headers as $k => $v) { + if ($k == 'Connection' || $k == 'Content-Length' || $k == 'Host' || $k == 'Authorization' || $k == 'Proxy-Authorization') { + $this->debug("Skip cURL header $k: $v"); + } else { + $curl_headers[] = "$k: $v"; + } + } + if ($cookie_str != '') { + $curl_headers[] = 'Cookie: ' . $cookie_str; + } + $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers); + $this->debug('set cURL HTTP headers'); + if ($this->request_method == "POST") { + $this->setCurlOption(CURLOPT_POST, 1); + $this->setCurlOption(CURLOPT_POSTFIELDS, $data); + $this->debug('set cURL POST data'); + } else { + } + // insert custom user-set cURL options + foreach ($this->ch_options as $key => $val) { + $this->setCurlOption($key, $val); + } + + $this->debug('set cURL payload'); + return true; + } + } + + /** + * gets the SOAP response via HTTP[S] + * + * @return string the response (also sets member variables like incoming_payload) + * @access private + */ + function getResponse() + { + $this->incoming_payload = ''; + + if ($this->io_method() == 'socket') { + // loop until headers have been retrieved + $data = ''; + while (!isset($lb)) { + + // We might EOF during header read. + if (feof($this->fp)) { + $this->incoming_payload = $data; + $this->debug('found no headers before EOF after length ' . strlen($data)); + $this->debug("received before EOF:\n" . $data); + $this->setError('server failed to send headers'); + return false; + } + + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read line of $tmplen bytes: " . trim($tmp)); + + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of headers timed out after length ' . strlen($data)); + $this->debug("read before timeout: " . $data); + $this->setError('socket read of headers timed out'); + return false; + } + + $data .= $tmp; + $pos = strpos($data, "\r\n\r\n"); + if ($pos > 1) { + $lb = "\r\n"; + } else { + $pos = strpos($data, "\n\n"); + if ($pos > 1) { + $lb = "\n"; + } + } + // remove 100 headers + if (isset($lb) && preg_match('/^HTTP\/1.1 100/', $data)) { + unset($lb); + $data = ''; + }// + } + // store header data + $this->incoming_payload .= $data; + $this->debug('found end of headers after length ' . strlen($data)); + // process headers + $header_data = trim(substr($data, 0, $pos)); + $header_array = explode($lb, $header_data); + $this->incoming_headers = array(); + $this->incoming_cookies = array(); + foreach ($header_array as $header_line) { + $arr = explode(':', $header_line, 2); + if (count($arr) > 1) { + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } elseif (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + + // loop until msg has been received + if (isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked') { + $content_length = 2147483647; // ignore any content-length header + $chunked = true; + $this->debug("want to read chunked content"); + } elseif (isset($this->incoming_headers['content-length'])) { + $content_length = $this->incoming_headers['content-length']; + $chunked = false; + $this->debug("want to read content of length $content_length"); + } else { + $content_length = 2147483647; + $chunked = false; + $this->debug("want to read content to EOF"); + } + $data = ''; + do { + if ($chunked) { + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read chunk line of $tmplen bytes"); + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of chunk length timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of chunk length timed out'); + return false; + } + $content_length = hexdec(trim($tmp)); + $this->debug("chunk length $content_length"); + } + $strlen = 0; + while (($strlen < $content_length) && (!feof($this->fp))) { + $readlen = min(8192, $content_length - $strlen); + $tmp = fread($this->fp, $readlen); + $tmplen = strlen($tmp); + $this->debug("read buffer of $tmplen bytes"); + if (($tmplen == 0) && (!feof($this->fp))) { + $this->incoming_payload = $data; + $this->debug('socket read of body timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of body timed out'); + return false; + } + $strlen += $tmplen; + $data .= $tmp; + } + if ($chunked && ($content_length > 0)) { + $tmp = fgets($this->fp, 256); + $tmplen = strlen($tmp); + $this->debug("read chunk terminator of $tmplen bytes"); + if ($tmplen == 0) { + $this->incoming_payload = $data; + $this->debug('socket read of chunk terminator timed out after length ' . strlen($data)); + $this->debug("read before timeout:\n" . $data); + $this->setError('socket read of chunk terminator timed out'); + return false; + } + } + } while ($chunked && ($content_length > 0) && (!feof($this->fp))); + if (feof($this->fp)) { + $this->debug('read to EOF'); + } + $this->debug('read body of length ' . strlen($data)); + $this->incoming_payload .= $data; + $this->debug('received a total of ' . strlen($this->incoming_payload) . ' bytes of data from server'); + + // close filepointer + if ( + (isset($this->incoming_headers['connection']) && strtolower($this->incoming_headers['connection']) == 'close') || + (!$this->persistentConnection) || feof($this->fp) + ) { + fclose($this->fp); + $this->fp = false; + $this->debug('closed socket'); + } + + // connection was closed unexpectedly + if ($this->incoming_payload == '') { + $this->setError('no response from server'); + return false; + } + + // decode transfer-encoding +// if(isset($this->incoming_headers['transfer-encoding']) && strtolower($this->incoming_headers['transfer-encoding']) == 'chunked'){ +// if(!$data = $this->decodeChunked($data, $lb)){ +// $this->setError('Decoding of chunked data failed'); +// return false; +// } + //print "
\nde-chunked:\n---------------\n$data\n\n---------------\n
"; + // set decoded payload +// $this->incoming_payload = $header_data.$lb.$lb.$data; +// } + + } elseif ($this->io_method() == 'curl') { + // send and receive + $this->debug('send and receive with cURL'); + $this->incoming_payload = curl_exec($this->ch); + $data = $this->incoming_payload; + + $cErr = curl_error($this->ch); + if ($cErr != '') { + $err = 'cURL ERROR: ' . curl_errno($this->ch) . ': ' . $cErr . '
'; + // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE + foreach (curl_getinfo($this->ch) as $k => $v) { + if (is_array($v)) { + $this->debug("$k: " . json_encode($v)); + } else { + $this->debug("$k: $v
"); + } + } + $this->debug($err); + $this->setError($err); + curl_close($this->ch); + return false; + } else { + //echo '
';
+                //var_dump(curl_getinfo($this->ch));
+                //echo '
'; + } + // close curl + $this->debug('No cURL error, closing cURL'); + curl_close($this->ch); + + // try removing skippable headers + $savedata = $data; + while ($this->isSkippableCurlHeader($data)) { + $this->debug("Found HTTP header to skip"); + if ($pos = strpos($data, "\r\n\r\n")) { + $data = ltrim(substr($data, $pos)); + } elseif ($pos = strpos($data, "\n\n")) { + $data = ltrim(substr($data, $pos)); + } + } + + if ($data == '') { + // have nothing left; just remove 100 header(s) + $data = $savedata; + while (preg_match('/^HTTP\/1.1 100/', $data)) { + if ($pos = strpos($data, "\r\n\r\n")) { + $data = ltrim(substr($data, $pos)); + } elseif ($pos = strpos($data, "\n\n")) { + $data = ltrim(substr($data, $pos)); + } + } + } + + // separate content from HTTP headers + if ($pos = strpos($data, "\r\n\r\n")) { + $lb = "\r\n"; + } elseif ($pos = strpos($data, "\n\n")) { + $lb = "\n"; + } else { + $this->debug('no proper separation of headers and document'); + $this->setError('no proper separation of headers and document'); + return false; + } + $header_data = trim(substr($data, 0, $pos)); + $header_array = explode($lb, $header_data); + $data = ltrim(substr($data, $pos)); + $this->debug('found proper separation of headers and document'); + $this->debug('cleaned data, stringlen: ' . strlen($data)); + // clean headers + foreach ($header_array as $header_line) { + $arr = explode(':', $header_line, 2); + if (count($arr) > 1) { + $header_name = strtolower(trim($arr[0])); + $this->incoming_headers[$header_name] = trim($arr[1]); + if ($header_name == 'set-cookie') { + // TODO: allow multiple cookies from parseCookie + $cookie = $this->parseCookie(trim($arr[1])); + if ($cookie) { + $this->incoming_cookies[] = $cookie; + $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']); + } else { + $this->debug('did not find cookie in ' . trim($arr[1])); + } + } + } elseif (isset($header_name)) { + // append continuation line to previous header + $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line; + } + } + } + + $this->response_status_line = $header_array[0]; + $arr = explode(' ', $this->response_status_line, 3); + $http_version = $arr[0]; + $http_status = intval($arr[1]); + $http_reason = count($arr) > 2 ? $arr[2] : ''; + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) { + $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']); + $this->setURL($this->incoming_headers['location']); + $this->tryagain = true; + return false; + } + + // see if we need to resend the request with http digest authentication + if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) { + $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']); + if (strstr($this->incoming_headers['www-authenticate'], "Digest ")) { + $this->debug('Server wants digest authentication'); + // remove "Digest " from our elements + $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']); + + // parse elements into array + $digestElements = explode(',', $digestString); + foreach ($digestElements as $val) { + $tempElement = explode('=', trim($val), 2); + $digestRequest[$tempElement[0]] = str_replace("\"", '', $tempElement[1]); + } + + // should have (at least) qop, realm, nonce + if (isset($digestRequest['nonce'])) { + $this->setCredentials($this->username, $this->password, 'digest', $digestRequest); + $this->tryagain = true; + return false; + } + } + $this->debug('HTTP authentication failed'); + $this->setError('HTTP authentication failed'); + return false; + } + + if ( + ($http_status >= 300 && $http_status <= 307) || + ($http_status >= 400 && $http_status <= 417) || + ($http_status >= 501 && $http_status <= 505) + ) { + $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)"); + return false; + } + + // decode content-encoding + if (isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != '') { + if (strtolower($this->incoming_headers['content-encoding']) == 'deflate' || strtolower($this->incoming_headers['content-encoding']) == 'gzip') { + // if decoding works, use it. else assume data wasn't gzencoded + if (function_exists('gzinflate')) { + //$timer->setMarker('starting decoding of gzip/deflated content'); + // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress) + // this means there are no Zlib headers, although there should be + $this->debug('The gzinflate function exists'); + $datalen = strlen($data); + if ($this->incoming_headers['content-encoding'] == 'deflate') { + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The inflated payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate($data)) { + $data = $degzdata; + $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to inflate the payload'); + $this->setError('Error using gzinflate to inflate the payload'); + } + } elseif ($this->incoming_headers['content-encoding'] == 'gzip') { + if ($degzdata = @gzinflate(substr($data, 10))) { // do our best + $data = $degzdata; + $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes'); + if (strlen($data) < $datalen) { + // test for the case that the payload has been compressed twice + $this->debug('The un-gzipped payload is smaller than the gzipped one; try again'); + if ($degzdata = @gzinflate(substr($data, 10))) { + $data = $degzdata; + $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes'); + } + } + } else { + $this->debug('Error using gzinflate to un-gzip the payload'); + $this->setError('Error using gzinflate to un-gzip the payload'); + } + } + //$timer->setMarker('finished decoding of gzip/deflated content'); + //print "\nde-inflated:\n---------------\n$data\n-------------\n"; + // set decoded payload + $this->incoming_payload = $header_data . $lb . $lb . $data; + } else { + $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.'); + } + } else { + $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']); + } + } else { + $this->debug('No Content-Encoding header'); + } + + if (strlen($data) == 0) { + $this->debug('no data after headers!'); + $this->setError('no data present after HTTP headers'); + return false; + } + + return $data; + } + + /** + * sets the content-type for the SOAP message to be sent + * + * @param string $type the content type, MIME style + * @param mixed $charset character set used for encoding (or false) + * @access public + */ + function setContentType($type, $charset = false) + { + $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : '')); + } + + /** + * specifies that an HTTP persistent connection should be used + * + * @return boolean whether the request was honored by this method. + * @access public + */ + function usePersistentConnection() + { + if (isset($this->outgoing_headers['Accept-Encoding'])) { + return false; + } + $this->protocol_version = '1.1'; + $this->persistentConnection = true; + $this->setHeader('Connection', 'Keep-Alive'); + return true; + } + + /** + * parse an incoming Cookie into it's parts + * + * @param string $cookie_str content of cookie + * @return array with data of that cookie + * @access private + */ + /* + * TODO: allow a Set-Cookie string to be parsed into multiple cookies + */ + function parseCookie($cookie_str) + { + $cookie_str = str_replace('; ', ';', $cookie_str) . ';'; + $data = preg_split('/;/', $cookie_str); + $value_str = $data[0]; + + $cookie_param = 'domain='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $domain = substr($cookie_str, $start + strlen($cookie_param)); + $domain = substr($domain, 0, strpos($domain, ';')); + } else { + $domain = ''; + } + + $cookie_param = 'expires='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $expires = substr($cookie_str, $start + strlen($cookie_param)); + $expires = substr($expires, 0, strpos($expires, ';')); + } else { + $expires = ''; + } + + $cookie_param = 'path='; + $start = strpos($cookie_str, $cookie_param); + if ($start > 0) { + $path = substr($cookie_str, $start + strlen($cookie_param)); + $path = substr($path, 0, strpos($path, ';')); + } else { + $path = '/'; + } + + $cookie_param = ';secure;'; + if (strpos($cookie_str, $cookie_param) !== false) { + $secure = true; + } else { + $secure = false; + } + + $sep_pos = strpos($value_str, '='); + + if ($sep_pos) { + $name = substr($value_str, 0, $sep_pos); + $value = substr($value_str, $sep_pos + 1); + $cookie = array('name' => $name, + 'value' => $value, + 'domain' => $domain, + 'path' => $path, + 'expires' => $expires, + 'secure' => $secure + ); + return $cookie; + } + return false; + } + + /** + * sort out cookies for the current request + * + * @param array $cookies array with all cookies + * @param boolean $secure is the send-content secure or not? + * @return string for Cookie-HTTP-Header + * @access private + */ + function getCookiesForRequest($cookies, $secure = false) + { + $cookie_str = ''; + if ((!is_null($cookies)) && (is_array($cookies))) { + foreach ($cookies as $cookie) { + if (!is_array($cookie)) { + continue; + } + $this->debug("check cookie for validity: " . $cookie['name'] . '=' . $cookie['value']); + if ((isset($cookie['expires'])) && (!empty($cookie['expires']))) { + if (strtotime($cookie['expires']) <= time()) { + $this->debug('cookie has expired'); + continue; + } + } + if ((isset($cookie['domain'])) && (!empty($cookie['domain']))) { + $domain = preg_quote($cookie['domain']); + if (!preg_match("'.*$domain$'i", $this->host)) { + $this->debug('cookie has different domain'); + continue; + } + } + if ((isset($cookie['path'])) && (!empty($cookie['path']))) { + $path = preg_quote($cookie['path']); + if (!preg_match("'^$path.*'i", $this->path)) { + $this->debug('cookie is for a different path'); + continue; + } + } + if ((!$secure) && (isset($cookie['secure'])) && ($cookie['secure'])) { + $this->debug('cookie is secure, transport is not'); + continue; + } + $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; '; + $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']); + } + } + return $cookie_str; + } +} + + +/** + * + * nusoap_server allows the user to create a SOAP server + * that is capable of receiving messages and returning responses + * + * @author Dietrich Ayala + * @author Scott Nichol + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class nusoap_server extends nusoap_base +{ + /** + * HTTP headers of request + * + * @var array + * @access private + */ + var $headers = array(); + /** + * HTTP request + * + * @var string + * @access private + */ + var $request = ''; + /** + * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text) + * + * @var string + * @access public + */ + var $requestHeaders = ''; + /** + * SOAP Headers from request (parsed) + * + * @var mixed + * @access public + */ + var $requestHeader = null; + /** + * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text) + * + * @var string + * @access public + */ + var $document = ''; + /** + * SOAP payload for request (text) + * + * @var string + * @access public + */ + var $requestSOAP = ''; + /** + * requested method namespace URI + * + * @var string + * @access private + */ + var $methodURI = ''; + /** + * name of method requested + * + * @var string + * @access private + */ + var $methodname = ''; + /** + * method parameters from request + * + * @var array + * @access private + */ + var $methodparams = array(); + /** + * SOAP Action from request + * + * @var string + * @access private + */ + var $SOAPAction = ''; + /** + * character set encoding of incoming (request) messages + * + * @var string + * @access public + */ + var $xml_encoding = ''; + /** + * toggles whether the parser decodes element content w/ utf8_decode() + * + * @var boolean + * @access public + */ + var $decode_utf8 = true; + + /** + * HTTP headers of response + * + * @var array + * @access public + */ + var $outgoing_headers = array(); + /** + * HTTP response + * + * @var string + * @access private + */ + var $response = ''; + /** + * SOAP headers for response (text or array of soapval or associative array) + * + * @var mixed + * @access public + */ + var $responseHeaders = ''; + /** + * SOAP payload for response (text) + * + * @var string + * @access private + */ + var $responseSOAP = ''; + /** + * method return value to place in response + * + * @var mixed + * @access private + */ + var $methodreturn = false; + /** + * whether $methodreturn is a string of literal XML + * + * @var boolean + * @access public + */ + var $methodreturnisliteralxml = false; + /** + * SOAP fault for response (or false) + * + * @var mixed + * @access private + */ + var $fault = false; + /** + * text indication of result (for debugging) + * + * @var string + * @access private + */ + var $result = 'successful'; + + /** + * assoc array of operations => opData; operations are added by the register() + * method or by parsing an external WSDL definition + * + * @var array + * @access private + */ + var $operations = array(); + /** + * wsdl instance (if one) + * + * @var mixed + * @access private + */ + var $wsdl = false; + /** + * URL for WSDL (if one) + * + * @var mixed + * @access private + */ + var $externalWSDLURL = false; + /** + * whether to append debug to response as XML comment + * + * @var boolean + * @access public + */ + var $debug_flag = false; + + + /** + * constructor + * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to. + * + * @param mixed $wsdl file path or URL (string), or wsdl instance (object) + * @access public + */ + function __construct($wsdl = false) + { + parent::__construct(); + // turn on debugging? + global $debug; + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $this->debug("_SERVER is defined:"); + $this->appendDebug($this->varDump($_SERVER)); + } elseif (isset($HTTP_SERVER_VARS)) { + $this->debug("HTTP_SERVER_VARS is defined:"); + $this->appendDebug($this->varDump($HTTP_SERVER_VARS)); + } else { + $this->debug("Neither _SERVER nor HTTP_SERVER_VARS is defined."); + } + + if (isset($debug)) { + $this->debug("In nusoap_server, set debug_flag=$debug based on global flag"); + $this->debug_flag = $debug; + } elseif (isset($_SERVER['QUERY_STRING'])) { + $qs = explode('&', $_SERVER['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #1"); + $this->debug_flag = substr($v, 6); + } + } + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']); + foreach ($qs as $v) { + if (substr($v, 0, 6) == 'debug=') { + $this->debug("In nusoap_server, set debug_flag=" . substr($v, 6) . " based on query string #2"); + $this->debug_flag = substr($v, 6); + } + } + } + + // wsdl + if ($wsdl) { + $this->debug("In nusoap_server, WSDL is specified"); + if (is_object($wsdl) && (get_class($wsdl) == 'wsdl')) { + $this->wsdl = $wsdl; + $this->externalWSDLURL = $this->wsdl->wsdl; + $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL); + } else { + $this->debug('Create wsdl from ' . $wsdl); + $this->wsdl = new wsdl($wsdl); + $this->externalWSDLURL = $wsdl; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if ($err = $this->wsdl->getError()) { + die('WSDL ERROR: ' . $err); + } + } + } + + /** + * processes request and returns response + * + * @param string $data usually is the value of $HTTP_RAW_POST_DATA + * @access public + */ + function service($data) + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER['REQUEST_METHOD'])) { + $rm = $_SERVER['REQUEST_METHOD']; + } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) { + $rm = $HTTP_SERVER_VARS['REQUEST_METHOD']; + } else { + $rm = ''; + } + + if (isset($_SERVER['QUERY_STRING'])) { + $qs = $_SERVER['QUERY_STRING']; + } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) { + $qs = $HTTP_SERVER_VARS['QUERY_STRING']; + } else { + $qs = ''; + } + $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data)); + + if ($rm == 'POST') { + $this->debug("In service, invoke the request"); + $this->parse_request($data); + if (!$this->fault) { + $this->invoke_method(); + } + if (!$this->fault) { + $this->serialize_return(); + } + $this->send_response(); + } elseif (preg_match('/wsdl/', $qs)) { + $this->debug("In service, this is a request for WSDL"); + if ($this->externalWSDLURL) { + if (strpos($this->externalWSDLURL, "http://") !== false) { // assume URL + $this->debug("In service, re-direct for WSDL"); + header('Location: ' . $this->externalWSDLURL); + } else { // assume file + $this->debug("In service, use file passthru for WSDL"); + header("Content-Type: text/xml\r\n"); + $pos = strpos($this->externalWSDLURL, "file://"); + if ($pos === false) { + $filename = $this->externalWSDLURL; + } else { + $filename = substr($this->externalWSDLURL, $pos + 7); + } + $fp = fopen($this->externalWSDLURL, 'r'); + fpassthru($fp); + } + } elseif ($this->wsdl) { + $this->debug("In service, serialize WSDL"); + header("Content-Type: text/xml; charset=ISO-8859-1\r\n"); + print $this->wsdl->serialize($this->debug_flag); + if ($this->debug_flag) { + $this->debug('wsdl:'); + $this->appendDebug($this->varDump($this->wsdl)); + print $this->getDebugAsXMLComment(); + } + } else { + $this->debug("In service, there is no WSDL"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide WSDL"; + } + } elseif ($this->wsdl) { + $this->debug("In service, return Web description"); + print $this->wsdl->webDescription(); + } else { + $this->debug("In service, no Web description"); + header("Content-Type: text/html; charset=ISO-8859-1\r\n"); + print "This service does not provide a Web description"; + } + } + + /** + * parses HTTP request headers. + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * + * @access private + */ + function parse_http_headers() + { + global $HTTP_SERVER_VARS; + + $this->request = ''; + $this->SOAPAction = ''; + if (function_exists('getallheaders')) { + $this->debug("In parse_http_headers, use getallheaders"); + $headers = getallheaders(); + foreach ($headers as $k => $v) { + $k = strtolower($k); + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + // get SOAPAction header + if (isset($this->headers['soapaction'])) { + $this->SOAPAction = str_replace('"', '', $this->headers['soapaction']); + } + // get the character encoding of the incoming request + if (isset($this->headers['content-type']) && strpos($this->headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($this->headers["content-type"], '='), 1)); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } elseif (isset($_SERVER) && is_array($_SERVER)) { + $this->debug("In parse_http_headers, use _SERVER"); + foreach ($_SERVER as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } elseif ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + if (is_array($v)) { + $this->request .= "$k: " . json_encode($v) . "\r\n"; + $this->debug("$k: " . json_encode($v)); + } else { + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } + } elseif (is_array($HTTP_SERVER_VARS)) { + $this->debug("In parse_http_headers, use HTTP_SERVER_VARS"); + foreach ($HTTP_SERVER_VARS as $k => $v) { + if (substr($k, 0, 5) == 'HTTP_') { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5)))); + $k = strtolower(substr($k, 5)); + } else { + $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k))); + $k = strtolower($k); + } + if ($k == 'soapaction') { + // get SOAPAction header + $k = 'SOAPAction'; + $v = str_replace('"', '', $v); + $v = str_replace('\\', '', $v); + $this->SOAPAction = $v; + } elseif ($k == 'content-type') { + // get the character encoding of the incoming request + if (strpos($v, '=')) { + $enc = substr(strstr($v, '='), 1); + $enc = str_replace('"', '', $enc); + $enc = str_replace('\\', '', $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + } + $this->headers[$k] = $v; + $this->request .= "$k: $v\r\n"; + $this->debug("$k: $v"); + } + } else { + $this->debug("In parse_http_headers, HTTP headers not accessible"); + $this->setError("HTTP headers not accessible"); + } + } + + /** + * parses a request + * + * The following fields are set by this function (when successful) + * + * headers + * request + * xml_encoding + * SOAPAction + * request + * requestSOAP + * methodURI + * methodname + * methodparams + * requestHeaders + * document + * + * This sets the fault field on error + * + * @param string $data XML string + * @access private + */ + function parse_request($data = '') + { + $this->debug('entering parse_request()'); + $this->parse_http_headers(); + $this->debug('got character encoding: ' . $this->xml_encoding); + // uncompress if necessary + if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') { + $this->debug('got content encoding: ' . $this->headers['content-encoding']); + if ($this->headers['content-encoding'] == 'deflate' || $this->headers['content-encoding'] == 'gzip') { + // if decoding works, use it. else assume data wasn't gzencoded + if (function_exists('gzuncompress')) { + if ($this->headers['content-encoding'] == 'deflate' && $degzdata = @gzuncompress($data)) { + $data = $degzdata; + } elseif ($this->headers['content-encoding'] == 'gzip' && $degzdata = gzinflate(substr($data, 10))) { + $data = $degzdata; + } else { + $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data'); + return; + } + } else { + $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data'); + return; + } + } + } + $this->request .= "\r\n" . $data; + $data = $this->parseRequest($this->headers, $data); + $this->requestSOAP = $data; + $this->debug('leaving parse_request'); + } + + /** + * invokes a PHP function for the requested SOAP method + * + * The following fields are set by this function (when successful) + * + * methodreturn + * + * Note that the PHP function that is called may also set the following + * fields to affect the response sent to the client + * + * responseHeaders + * outgoing_headers + * + * This sets the fault field on error + * + * @access private + */ + function invoke_method() + { + $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction); + + // + // if you are debugging in this area of the code, your service uses a class to implement methods, + // you use SOAP RPC, and the client is .NET, please be aware of the following... + // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the + // method name. that is fine for naming the .NET methods. it is not fine for properly constructing + // the XML request and reading the XML response. you need to add the RequestElementName and + // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe + // generates for the method. these parameters are used to specify the correct XML element names + // for .NET to use, i.e. the names with the '.' in them. + // + $orig_methodname = $this->methodname; + if ($this->wsdl) { + if ($this->opData = $this->wsdl->getOperationData($this->methodname)) { + $this->debug('in invoke_method, found WSDL operation=' . $this->methodname); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) { + // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element + $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']); + $this->appendDebug('opData=' . $this->varDump($this->opData)); + $this->methodname = $this->opData['name']; + } else { + $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname); + $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service"); + return; + } + } else { + $this->debug('in invoke_method, no WSDL to validate method'); + } + + // if a . is present in $this->methodname, we see if there is a class in scope, + // which could be referred to. We will also distinguish between two deliminators, + // to allow methods to be called a the class or an instance + if (strpos($this->methodname, '..') > 0) { + $delim = '..'; + } elseif (strpos($this->methodname, '.') > 0) { + $delim = '.'; + } else { + $delim = ''; + } + $this->debug("in invoke_method, delim=$delim"); + + $class = ''; + $method = ''; + if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) { + $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim)); + if (class_exists($try_class)) { + // get the class and method name + $class = $try_class; + $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim)); + $this->debug("in invoke_method, class=$class method=$method delim=$delim"); + } else { + $this->debug("in invoke_method, class=$try_class not found"); + } + } elseif (strlen($delim) > 0 && substr_count($this->methodname, $delim) > 1) { + $split = explode($delim, $this->methodname); + $method = array_pop($split); + $class = implode('\\', $split); + } else { + $try_class = ''; + $this->debug("in invoke_method, no class to try"); + } + + // does method exist? + if ($class == '') { + if (!function_exists($this->methodname)) { + $this->debug("in invoke_method, function '$this->methodname' not found!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client', "method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')"); + return; + } + } else { + $method_to_compare = (substr(phpversion(), 0, 2) == '4.') ? strtolower($method) : $method; + if (!in_array($method_to_compare, get_class_methods($class))) { + $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!"); + $this->result = 'fault: method not found'; + $this->fault('SOAP-ENV:Client', "method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')"); + return; + } + } + + // evaluate message, getting back parameters + // verify that request parameters match the method's signature + if (!$this->verify_method($this->methodname, $this->methodparams)) { + // debug + $this->debug('ERROR: request not verified against method signature'); + $this->result = 'fault: request failed validation against method signature'; + // return fault + $this->fault('SOAP-ENV:Client', "Operation '$this->methodname' not defined in service."); + return; + } + + // if there are parameters to pass + $this->debug('in invoke_method, params:'); + $this->appendDebug($this->varDump($this->methodparams)); + $this->debug("in invoke_method, calling '$this->methodname'"); + if (!function_exists('call_user_func_array')) { + if ($class == '') { + $this->debug('in invoke_method, calling function using eval()'); + $funcCall = "\$this->methodreturn = $this->methodname("; + } else { + if ($delim == '..') { + $this->debug('in invoke_method, calling class method using eval()'); + $funcCall = "\$this->methodreturn = " . $class . "::" . $method . "("; + } else { + $this->debug('in invoke_method, calling instance method using eval()'); + // generate unique instance name + $instname = "\$inst_" . time(); + $funcCall = $instname . " = new " . $class . "(); "; + $funcCall .= "\$this->methodreturn = " . $instname . "->" . $method . "("; + } + } + if ($this->methodparams) { + foreach ($this->methodparams as $param) { + if (is_array($param) || is_object($param)) { + $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available'); + return; + } + $funcCall .= "\"$param\","; + } + $funcCall = substr($funcCall, 0, -1); + } + $funcCall .= ');'; + $this->debug('in invoke_method, function call: ' . $funcCall); + @eval($funcCall); + } else { + if ($class == '') { + $this->debug('in invoke_method, calling function using call_user_func_array()'); + $call_arg = "$this->methodname"; // straight assignment changes $this->methodname to lower case after call_user_func_array() + } elseif ($delim == '..') { + $this->debug('in invoke_method, calling class method using call_user_func_array()'); + $call_arg = array($class, $method); + } else { + $this->debug('in invoke_method, calling instance method using call_user_func_array()'); + $instance = new $class (); + $call_arg = array(&$instance, $method); + } + if (is_array($this->methodparams)) { + $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams)); + } else { + $this->methodreturn = call_user_func_array($call_arg, array()); + } + } + $this->debug('in invoke_method, methodreturn:'); + $this->appendDebug($this->varDump($this->methodreturn)); + $this->debug("in invoke_method, called method $this->methodname, received data of type " . gettype($this->methodreturn)); + } + + /** + * serializes the return value from a PHP function into a full SOAP Envelope + * + * The following fields are set by this function (when successful) + * + * responseSOAP + * + * This sets the fault field on error + * + * @access private + */ + function serialize_return() + { + $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); + // if fault + if (isset($this->methodreturn) && is_object($this->methodreturn) && ((get_class($this->methodreturn) == 'soap_fault') || (get_class($this->methodreturn) == 'nusoap_fault'))) { + $this->debug('got a fault object from method'); + $this->fault = $this->methodreturn; + return; + } elseif ($this->methodreturnisliteralxml) { + $return_val = $this->methodreturn; + // returned value(s) + } else { + $this->debug('got a(n) ' . gettype($this->methodreturn) . ' from method'); + $this->debug('serializing return value'); + if ($this->wsdl) { + if (sizeof($this->opData['output']['parts']) > 1) { + $this->debug('more than one output part, so use the method return unchanged'); + $opParams = $this->methodreturn; + } elseif (sizeof($this->opData['output']['parts']) == 1) { + $this->debug('exactly one output part, so wrap the method return in a simple array'); + // TODO: verify that it is not already wrapped! + //foreach ($this->opData['output']['parts'] as $name => $type) { + // $this->debug('wrap in element named ' . $name); + //} + $opParams = array($this->methodreturn); + } + $opParams = isset($opParams) ? $opParams : []; + $return_val = $this->wsdl->serializeRPCParameters($this->methodname, 'output', $opParams); + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if ($errstr = $this->wsdl->getError()) { + $this->debug('got wsdl error: ' . $errstr); + $this->fault('SOAP-ENV:Server', 'unable to serialize result'); + return; + } + } else { + if (isset($this->methodreturn)) { + $return_val = $this->serialize_val($this->methodreturn, 'return'); + } else { + $return_val = ''; + $this->debug('in absence of WSDL, assume void return for backward compatibility'); + } + } + } + $this->debug('return value:'); + $this->appendDebug($this->varDump($return_val)); + + $this->debug('serializing response'); + if ($this->wsdl) { + $this->debug('have WSDL for serialization: style is ' . $this->opData['style']); + if ($this->opData['style'] == 'rpc') { + $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']); + if ($this->opData['output']['use'] == 'literal') { + // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace + if ($this->methodURI) { + $payload = 'methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . 'methodname . "Response>"; + } else { + $payload = '<' . $this->methodname . 'Response>' . $return_val . 'methodname . 'Response>'; + } + } else { + if ($this->methodURI) { + $payload = 'methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . 'methodname . "Response>"; + } else { + $payload = '<' . $this->methodname . 'Response>' . $return_val . 'methodname . 'Response>'; + } + } + } else { + $this->debug('style is not rpc for serialization: assume document'); + $payload = $return_val; + } + } else { + $this->debug('do not have WSDL for serialization: assume rpc/encoded'); + $payload = 'methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . 'methodname . "Response>"; + } + $this->result = 'successful'; + if ($this->wsdl) { + //if($this->debug_flag){ + $this->appendDebug($this->wsdl->getDebug()); + // } + if (isset($this->opData['output']['encodingStyle'])) { + $encodingStyle = $this->opData['output']['encodingStyle']; + } else { + $encodingStyle = ''; + } + // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces. + $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle); + } else { + $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders); + } + $this->debug("Leaving serialize_return"); + } + + /** + * sends an HTTP response + * + * The following fields are set by this function (when successful) + * + * outgoing_headers + * response + * + * @access private + */ + function send_response() + { + $this->debug('Enter send_response'); + if ($this->fault) { + $payload = $this->fault->serialize(); + $this->outgoing_headers[] = "HTTP/1.0 500 Internal Server Error"; + $this->outgoing_headers[] = "Status: 500 Internal Server Error"; + } else { + $payload = $this->responseSOAP; + // Some combinations of PHP+Web server allow the Status + // to come through as a header. Since OK is the default + // just do nothing. + // $this->outgoing_headers[] = "HTTP/1.0 200 OK"; + // $this->outgoing_headers[] = "Status: 200 OK"; + } + // add debug data if in debug mode + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= $this->getDebugAsXMLComment(); + } + $this->outgoing_headers[] = "Server: $this->title Server v$this->version"; + preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev); + $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ")"; + // Let the Web server decide about this + //$this->outgoing_headers[] = "Connection: Close\r\n"; + $payload = $this->getHTTPBody($payload); + $type = $this->getHTTPContentType(); + $charset = $this->getHTTPContentTypeCharset(); + $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : ''); + //begin code to compress payload - by John + // NOTE: there is no way to know whether the Web server will also compress + // this data. + if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) { + if (strstr($this->headers['accept-encoding'], 'gzip')) { + if (function_exists('gzencode')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: gzip"; + $payload = gzencode($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } elseif (strstr($this->headers['accept-encoding'], 'deflate')) { + // Note: MSIE requires gzdeflate output (no Zlib header and checksum), + // instead of gzcompress output, + // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5) + if (function_exists('gzdeflate')) { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + $this->outgoing_headers[] = "Content-Encoding: deflate"; + $payload = gzdeflate($payload); + } else { + if (isset($this->debug_flag) && $this->debug_flag) { + $payload .= ""; + } + } + } + } + //end code + $this->outgoing_headers[] = "Content-Length: " . strlen($payload); + reset($this->outgoing_headers); + foreach ($this->outgoing_headers as $hdr) { + header($hdr, false); + } + print $payload; + $this->response = join("\r\n", $this->outgoing_headers) . "\r\n\r\n" . $payload; + } + + /** + * takes the value that was created by parsing the request + * and compares to the method's signature, if available. + * + * @param string $operation The operation to be invoked + * @param array $request The array of parameter values + * @return boolean Whether the operation was found + * @access private + */ + function verify_method($operation, $request) + { + if (isset($this->wsdl) && is_object($this->wsdl)) { + if ($this->wsdl->getOperationData($operation)) { + return true; + } + } elseif (isset($this->operations[$operation])) { + return true; + } + return false; + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) + { + $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Request not of type '.$this->contentType.' (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], $this->contentType)) { + $this->setError('Request not of type '.$this->contentType.': ' . $headers['content-type']); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + // parse response, get soap parser obj + $parser = new nusoap_parser($data, $this->xml_encoding, '', $this->decode_utf8); + // parser debug + $this->debug("parser debug: \n" . $parser->getDebug()); + // if fault occurred during message parsing + if ($err = $parser->getError()) { + $this->result = 'fault: error in msg parsing: ' . $err; + $this->fault('SOAP-ENV:Client', "error in msg parsing:\n" . $err); + // else successfully parsed request into soapval object + } else { + // get/set methodname + $this->methodURI = $parser->root_struct_namespace; + $this->methodname = $parser->root_struct_name; + $this->debug('methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI); + $this->debug('calling parser->get_soapbody()'); + $this->methodparams = $parser->get_soapbody(); + // get SOAP headers + $this->requestHeaders = $parser->getHeaders(); + // get SOAP Header + $this->requestHeader = $parser->get_soapheader(); + // add document for doclit support + $this->document = $parser->document; + } + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) + { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() + { + return 'text/xml'; + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() + { + return $this->soap_defencoding; + } + + /** + * add a method to the dispatch map (this has been replaced by the register method) + * + * @param string $methodname + * @param string $in array of input values + * @param string $out array of output values + * @access public + * @deprecated + */ + function add_to_map($methodname, $in, $out) + { + $this->operations[$methodname] = array('name' => $methodname, 'in' => $in, 'out' => $out); + } + + /** + * register a service function with the server + * + * @param string $name the name of the PHP function, class.method or class..method + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param mixed $namespace the element namespace for the method or false + * @param mixed $soapaction the soapaction for the method or false + * @param mixed $style optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param mixed $use optional (encoded|literal) or false + * @param string $documentation optional Description to include in WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function register($name, $in = array(), $out = array(), $namespace = false, $soapaction = false, $style = false, $use = false, $documentation = '', $encodingStyle = '') + { + global $HTTP_SERVER_VARS; + + if ($this->externalWSDLURL) { + die('You cannot bind to an external WSDL file, and register methods outside of it! Please choose either WSDL or no WSDL.'); + } + if (!$name) { + die('You must specify a name when you register an operation'); + } + if (!is_array($in)) { + die('You must provide an array for operation inputs'); + } + if (!is_array($out)) { + die('You must provide an array for operation outputs'); + } + if (false == $namespace) { + } + if (false == $soapaction) { + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $soapaction = "$SCHEME://$SERVER_NAME$SCRIPT_NAME/$name"; + } + if (false == $style) { + $style = "rpc"; + } + if (false == $use) { + $use = "encoded"; + } + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + $this->operations[$name] = array( + 'name' => $name, + 'in' => $in, + 'out' => $out, + 'namespace' => $namespace, + 'soapaction' => $soapaction, + 'style' => $style); + if ($this->wsdl) { + $this->wsdl->addOperation($name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle); + } + return true; + } + + /** + * Specify a fault to be returned to the client. + * This also acts as a flag to the server that a fault has occured. + * + * @param string $faultcode + * @param string $faultstring + * @param string $faultactor + * @param string $faultdetail + * @access public + */ + function fault($faultcode, $faultstring, $faultactor = '', $faultdetail = '') + { + if ($faultdetail == '' && $this->debug_flag) { + $faultdetail = $this->getDebug(); + } + $this->fault = new nusoap_fault($faultcode, $faultactor, $faultstring, $faultdetail); + $this->fault->soap_defencoding = $this->soap_defencoding; + } + + /** + * Sets up wsdl object. + * Acts as a flag to enable internal WSDL generation + * + * @param string $serviceName , name of the service + * @param mixed $namespace optional 'tns' service namespace or false + * @param mixed $endpoint optional URL of service endpoint or false + * @param string $style optional (rpc|document) WSDL style (also specified by operation) + * @param string $transport optional SOAP transport + * @param mixed $schemaTargetNamespace optional 'types' targetNamespace for service schema or false + */ + function configureWSDL($serviceName, $namespace = false, $endpoint = false, $style = 'rpc', $transport = 'http://schemas.xmlsoap.org/soap/http', $schemaTargetNamespace = false) + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $SERVER_NAME = $_SERVER['SERVER_NAME']; + $SERVER_PORT = $_SERVER['SERVER_PORT']; + $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']; + $HTTPS = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'); + } elseif (isset($HTTP_SERVER_VARS)) { + $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME']; + $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT']; + $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME']; + $HTTPS = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off'; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI) + $colon = strpos($SERVER_NAME, ":"); + if ($colon) { + $SERVER_NAME = substr($SERVER_NAME, 0, $colon); + } + if ($SERVER_PORT == 80) { + $SERVER_PORT = ''; + } else { + $SERVER_PORT = ':' . $SERVER_PORT; + } + if (false == $namespace) { + $namespace = "http://$SERVER_NAME/soap/$serviceName"; + } + + if (false == $endpoint) { + if ($HTTPS == '1' || $HTTPS == 'on') { + $SCHEME = 'https'; + } else { + $SCHEME = 'http'; + } + $endpoint = "$SCHEME://$SERVER_NAME$SERVER_PORT$SCRIPT_NAME"; + } + + if (false == $schemaTargetNamespace) { + $schemaTargetNamespace = $namespace; + } + + $this->wsdl = new wsdl; + $this->wsdl->serviceName = $serviceName; + $this->wsdl->endpoint = $endpoint; + $this->wsdl->namespaces['tns'] = $namespace; + $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/'; + $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/'; + if ($schemaTargetNamespace != $namespace) { + $this->wsdl->namespaces['types'] = $schemaTargetNamespace; + } + $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces); + if ($style == 'document') { + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified'; + } + $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace = $schemaTargetNamespace; + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0] = array('location' => '', 'loaded' => true); + $this->wsdl->bindings[$serviceName . 'Binding'] = array( + 'name' => $serviceName . 'Binding', + 'style' => $style, + 'transport' => $transport, + 'portType' => $serviceName . 'PortType'); + $this->wsdl->ports[$serviceName . 'Port'] = array( + 'binding' => $serviceName . 'Binding', + 'location' => $endpoint, + 'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/'); + } +} + +/** + * Backward compatibility + */ +class soap_server extends nusoap_server +{ +} + + +/** + * parses a WSDL file, allows access to it's data, other utility methods. + * also builds WSDL structures programmatically. + * + * @author Dietrich Ayala + * @author Scott Nichol + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class wsdl extends nusoap_base +{ + // URL or filename of the root of this WSDL + var $wsdl; + // define internal arrays of bindings, ports, operations, messages, etc. + var $schemas = array(); + var $currentSchema; + var $message = array(); + var $complexTypes = array(); + var $messages = array(); + var $currentMessage; + var $currentOperation; + var $portTypes = array(); + var $currentPortType; + var $bindings = array(); + var $currentBinding; + var $ports = array(); + var $currentPort; + var $opData = array(); + var $status = ''; + var $documentation = false; + var $endpoint = ''; + // array of wsdl docs to import + var $import = array(); + // parser vars + var $parser; + var $position = 0; + var $depth = 0; + var $depth_array = array(); + // for getting wsdl + var $proxyhost = ''; + var $proxyport = ''; + var $proxyusername = ''; + var $proxypassword = ''; + var $timeout = 0; + var $response_timeout = 30; + var $curl_options = array(); // User-specified cURL options + var $use_curl = false; // whether to always try to use cURL + // for HTTP authentication + var $username = ''; // Username for HTTP authentication + var $password = ''; // Password for HTTP authentication + var $authtype = ''; // Type of HTTP authentication + var $certRequest = array(); // Certificate for HTTP SSL authentication + + /** + * constructor + * + * @param string $wsdl WSDL document URL + * @param string $proxyhost + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @param integer $timeout set the connection timeout + * @param integer $response_timeout set the response timeout + * @param array $curl_options user-specified cURL options + * @param boolean $use_curl try to use cURL + * @access public + */ + function __construct($wsdl = '', $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $curl_options = null, $use_curl = false) + { + parent::__construct(); + $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + $this->timeout = $timeout; + $this->response_timeout = $response_timeout; + if (is_array($curl_options)) { + $this->curl_options = $curl_options; + } + $this->use_curl = $use_curl; + $this->fetchWSDL($wsdl); + } + + /** + * fetches the WSDL document and parses it + * + * @access public + */ + function fetchWSDL($wsdl) + { + $this->debug("parse and process WSDL path=$wsdl"); + $this->wsdl = $wsdl; + // parse wsdl file + if ($this->wsdl != "") { + $this->parseWSDL($this->wsdl); + } + // imports + // TODO: handle imports more properly, grabbing them in-line and nesting them + $imported_urls = array(); + $imported = 1; + while ($imported > 0) { + $imported = 0; + // Schema imports + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! + foreach ($xs->imports as $ns2 => $list2) { + for ($ii = 0; $ii < count($list2); $ii++) { + if (!$list2[$ii]['loaded']) { + $this->schemas[$ns][$ns2]->imports[$ns2][$ii]['loaded'] = true; + $url = $list2[$ii]['location']; + if ($url != '') { + $urlparts = parse_url($url); + if (!isset($urlparts['host'])) { + $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . + substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path']; + } + if (!in_array($url, $imported_urls)) { + $this->parseWSDL($url); + $imported++; + $imported_urls[] = $url; + } + } else { + $this->debug("Unexpected scenario: empty URL for unloaded import"); + } + } + } + } + } + } + // WSDL imports + $wsdlparts = parse_url($this->wsdl); // this is bogusly simple! + foreach ($this->import as $ns => $list) { + for ($ii = 0; $ii < count($list); $ii++) { + if (!$list[$ii]['loaded']) { + $this->import[$ns][$ii]['loaded'] = true; + $url = $list[$ii]['location']; + if ($url != '') { + $urlparts = parse_url($url); + if (!isset($urlparts['host'])) { + $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . + substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path']; + } + if (!in_array($url, $imported_urls)) { + $this->parseWSDL($url); + $imported++; + $imported_urls[] = $url; + } + } else { + $this->debug("Unexpected scenario: empty URL for unloaded import"); + } + } + } + } + } + // add new data to operation data + foreach ($this->bindings as $binding => $bindingData) { + if (isset($bindingData['operations']) && is_array($bindingData['operations'])) { + foreach ($bindingData['operations'] as $operation => $data) { + $this->debug('post-parse data gathering for ' . $operation); + $this->bindings[$binding]['operations'][$operation]['input'] = + isset($this->bindings[$binding]['operations'][$operation]['input']) ? + array_merge($this->bindings[$binding]['operations'][$operation]['input'], $this->portTypes[$bindingData['portType']][$operation]['input']) : + $this->portTypes[$bindingData['portType']][$operation]['input']; + $this->bindings[$binding]['operations'][$operation]['output'] = + isset($this->bindings[$binding]['operations'][$operation]['output']) ? + array_merge($this->bindings[$binding]['operations'][$operation]['output'], $this->portTypes[$bindingData['portType']][$operation]['output']) : + $this->portTypes[$bindingData['portType']][$operation]['output']; + if (isset($this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']])) { + $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']]; + } + if (isset($this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']])) { + $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']]; + } + // Set operation style if necessary, but do not override one already provided + if (isset($bindingData['style']) && !isset($this->bindings[$binding]['operations'][$operation]['style'])) { + $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style']; + } + $this->bindings[$binding]['operations'][$operation]['transport'] = isset($bindingData['transport']) ? $bindingData['transport'] : ''; + $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[$bindingData['portType']][$operation]['documentation']) ? $this->portTypes[$bindingData['portType']][$operation]['documentation'] : ''; + $this->bindings[$binding]['operations'][$operation]['endpoint'] = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : ''; + } + } + } + } + + /** + * parses the wsdl document + * + * @param string $wsdl path or URL + * @access private + */ + function parseWSDL($wsdl = '') + { + $this->debug("parse WSDL at path=$wsdl"); + + if ($wsdl == '') { + $this->debug('no wsdl passed to parseWSDL()!!'); + $this->setError('no wsdl passed to parseWSDL()!!'); + return false; + } + + // parse $wsdl for url format + $wsdl_props = parse_url($wsdl); + + if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'http' || $wsdl_props['scheme'] == 'https')) { + $this->debug('getting WSDL http(s) URL ' . $wsdl); + // get wsdl + $tr = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl); + $tr->request_method = 'GET'; + $tr->useSOAPAction = false; + if ($this->proxyhost && $this->proxyport) { + $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword); + } + if ($this->authtype != '') { + $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + $tr->setEncoding('gzip, deflate'); + $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout); + //$this->debug("WSDL request\n" . $tr->outgoing_payload); + //$this->debug("WSDL response\n" . $tr->incoming_payload); + $this->appendDebug($tr->getDebug()); + // catch errors + if ($err = $tr->getError()) { + $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: ' . $err; + $this->debug($errstr); + $this->setError($errstr); + unset($tr); + return false; + } + unset($tr); + $this->debug("got WSDL URL"); + } else { + // $wsdl is not http(s), so treat it as a file URL or plain file path + if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] == 'file') && isset($wsdl_props['path'])) { + $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path']; + } else { + $path = $wsdl; + } + $this->debug('getting WSDL file ' . $path); + if ($fp = @fopen($path, 'r')) { + $wsdl_string = ''; + while ($data = fread($fp, 32768)) { + $wsdl_string .= $data; + } + fclose($fp); + } else { + $errstr = "Bad path to WSDL file $path"; + $this->debug($errstr); + $this->setError($errstr); + return false; + } + } + $this->debug('Parse WSDL'); + // end new code added + // Create an XML parser. + $this->parser = xml_parser_create(); + // Set the options for parsing the XML data. + // xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + // Set the object for the parser. + xml_set_object($this->parser, $this); + // Set the element handlers for the parser. + xml_set_element_handler($this->parser, 'start_element', 'end_element'); + xml_set_character_data_handler($this->parser, 'character_data'); + // Parse the XML file. + if (!xml_parse($this->parser, $wsdl_string, true)) { + // Display an error message. + $errstr = sprintf( + 'XML error parsing WSDL from %s on line %d: %s', + $wsdl, + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser)) + ); + $this->debug($errstr); + $this->debug("XML payload:\n" . $wsdl_string); + $this->setError($errstr); + xml_parser_free($this->parser); + unset($this->parser); + return false; + } + // free the parser + xml_parser_free($this->parser); + unset($this->parser); + $this->debug('Parsing WSDL done'); + // catch wsdl parse errors + if ($this->getError()) { + return false; + } + return true; + } + + /** + * start-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @param string $attrs associative array of attributes + * @access private + */ + function start_element($parser, $name, $attrs) + { + if ($this->status == 'schema') { + $this->currentSchema->schemaStartElement($parser, $name, $attrs); + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } elseif (preg_match('/schema$/', $name)) { + $this->debug('Parsing WSDL schema'); + // $this->debug("startElement for $name ($attrs[name]). status = $this->status (".$this->getLocalPart($name).")"); + $this->status = 'schema'; + $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces); + $this->currentSchema->schemaStartElement($parser, $name, $attrs); + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + } else { + // position in the total number of elements, starting from 0 + $pos = $this->position++; + $depth = $this->depth++; + // set self as current value for this depth + $this->depth_array[$depth] = $pos; + $this->message[$pos] = array('cdata' => ''); + // process attributes + if (count($attrs) > 0) { + // register namespace declarations + foreach ($attrs as $k => $v) { + if (preg_match('/^xmlns/', $k)) { + if ($ns_prefix = substr(strrchr($k, ':'), 1)) { + $this->namespaces[$ns_prefix] = $v; + } else { + $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v; + } + if ($v == 'http://www.w3.org/2001/XMLSchema' || $v == 'http://www.w3.org/1999/XMLSchema' || $v == 'http://www.w3.org/2000/10/XMLSchema') { + $this->XMLSchemaVersion = $v; + $this->namespaces['xsi'] = $v . '-instance'; + } + } + } + // expand each attribute prefix to its namespace + foreach ($attrs as $k => $v) { + $k = strpos($k, ':') ? $this->expandQname($k) : $k; + if ($k != 'location' && $k != 'soapAction' && $k != 'namespace') { + $v = strpos($v, ':') ? $this->expandQname($v) : $v; + } + $eAttrs[$k] = $v; + } + $attrs = $eAttrs; + } else { + $attrs = array(); + } + // Set default prefix and namespace + // to prevent error Undefined variable $prefix and $namespace if (preg_match('/:/', $name)) return 0 or FALSE + $prefix = ''; + $namespace = ''; + // get element prefix, namespace and name + if (preg_match('/:/', $name)) { + // get ns prefix + $prefix = substr($name, 0, strpos($name, ':')); + // get ns + $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : ''; + // get unqualified name + $name = substr(strstr($name, ':'), 1); + } + // process attributes, expanding any prefixes to namespaces + // find status, register data + switch ($this->status) { + case 'message': + if ($name == 'part') { + if (isset($attrs['type'])) { + $this->debug("msg " . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs)); + $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type']; + } + if (isset($attrs['element'])) { + $this->debug("msg " . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs)); + $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^'; + } + } + break; + case 'portType': + switch ($name) { + case 'operation': + $this->currentPortOperation = $attrs['name']; + $this->debug("portType $this->currentPortType operation: $this->currentPortOperation"); + if (isset($attrs['parameterOrder'])) { + $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder']; + } + break; + case 'documentation': + $this->documentation = true; + break; + // merge input/output data + default: + $m = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : ''; + $this->portTypes[$this->currentPortType][$this->currentPortOperation][$name]['message'] = $m; + break; + } + break; + case 'binding': + switch ($name) { + case 'binding': + // get ns prefix + if (isset($attrs['style'])) { + $this->bindings[$this->currentBinding]['prefix'] = $prefix; + } + $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs); + break; + case 'header': + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus]['headers'][] = $attrs; + break; + case 'operation': + if (isset($attrs['soapAction'])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction']; + } + if (isset($attrs['style'])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style']; + } + if (isset($attrs['name'])) { + $this->currentOperation = $attrs['name']; + $this->debug("current binding operation: $this->currentOperation"); + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name'] = $attrs['name']; + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding'] = $this->currentBinding; + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : ''; + } + break; + case 'input': + $this->opStatus = 'input'; + break; + case 'output': + $this->opStatus = 'output'; + break; + case 'body': + if (isset($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus])) { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = array_merge($this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus], $attrs); + } else { + $this->bindings[$this->currentBinding]['operations'][$this->currentOperation][$this->opStatus] = $attrs; + } + break; + } + break; + case 'service': + switch ($name) { + case 'port': + $this->currentPort = $attrs['name']; + $this->debug('current port: ' . $this->currentPort); + $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']); + + break; + case 'address': + $this->ports[$this->currentPort]['location'] = $attrs['location']; + $this->ports[$this->currentPort]['bindingType'] = $namespace; + $this->bindings[$this->ports[$this->currentPort]['binding']]['bindingType'] = $namespace; + $this->bindings[$this->ports[$this->currentPort]['binding']]['endpoint'] = $attrs['location']; + break; + } + break; + } + // set status + switch ($name) { + case 'import': + if (isset($attrs['location'])) { + $this->import[$attrs['namespace']][] = array('location' => $attrs['location'], 'loaded' => false); + $this->debug('parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]) . ')'); + } else { + $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true); + if (!$this->getPrefixFromNamespace($attrs['namespace'])) { + $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace']; + } + $this->debug('parsing import ' . $attrs['namespace'] . ' - [no location] (' . count($this->import[$attrs['namespace']]) . ')'); + } + break; + //wait for schema + //case 'types': + // $this->status = 'schema'; + // break; + case 'message': + $this->status = 'message'; + $this->messages[$attrs['name']] = array(); + $this->currentMessage = $attrs['name']; + break; + case 'portType': + $this->status = 'portType'; + $this->portTypes[$attrs['name']] = array(); + $this->currentPortType = $attrs['name']; + break; + case "binding": + if (isset($attrs['name'])) { + // get binding name + if (strpos($attrs['name'], ':')) { + $this->currentBinding = $this->getLocalPart($attrs['name']); + } else { + $this->currentBinding = $attrs['name']; + } + $this->status = 'binding'; + $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']); + $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']); + } + break; + case 'service': + $this->serviceName = $attrs['name']; + $this->status = 'service'; + $this->debug('current service: ' . $this->serviceName); + break; + case 'definitions': + foreach ($attrs as $name => $value) { + $this->wsdl_info[$name] = $value; + } + break; + } + } + } + + /** + * end-element handler + * + * @param string $parser XML parser object + * @param string $name element name + * @access private + */ + function end_element($parser, $name) + { + // unset schema status + if (/*preg_match('/types$/', $name) ||*/ + preg_match('/schema$/', $name) + ) { + $this->status = ""; + $this->appendDebug($this->currentSchema->getDebug()); + $this->currentSchema->clearDebug(); + $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema; + $this->debug('Parsing WSDL schema done'); + } + if ($this->status == 'schema') { + $this->currentSchema->schemaEndElement($parser, $name); + } else { + // bring depth down a notch + $this->depth--; + } + // end documentation + if ($this->documentation) { + //TODO: track the node to which documentation should be assigned; it can be a part, message, etc. + //$this->portTypes[$this->currentPortType][$this->currentPortOperation]['documentation'] = $this->documentation; + $this->documentation = false; + } + } + + /** + * element content handler + * + * @param string $parser XML parser object + * @param string $data element content + * @access private + */ + function character_data($parser, $data) + { + $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0; + if (isset($this->message[$pos]['cdata'])) { + $this->message[$pos]['cdata'] .= $data; + } + if ($this->documentation) { + $this->documentation .= $data; + } + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) + { + $this->debug("setCredentials username=$username authtype=$authtype certRequest="); + $this->appendDebug($this->varDump($certRequest)); + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + function getBindingData($binding) + { + if (is_array($this->bindings[$binding])) { + return $this->bindings[$binding]; + } + } + + /** + * returns an assoc array of operation names => operation data + * + * @param string $portName WSDL port name + * @param string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported) + * @return array + * @access public + */ + function getOperations($portName = '', $bindingType = 'soap') + { + $ops = array(); + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } else { + $this->debug("getOperations bindingType $bindingType may not be supported"); + } + $this->debug("getOperations for port '$portName' bindingType $bindingType"); + // loop thru ports + foreach ($this->ports as $port => $portData) { + $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']); + if ($portName == '' || $port == $portName) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + $this->debug("getOperations found port $port bindingType $bindingType"); + //$this->debug("port data: " . $this->varDump($portData)); + //$this->debug("bindings: " . $this->varDump($this->bindings[ $portData['binding'] ])); + // merge bindings + if (isset($this->bindings[$portData['binding']]['operations'])) { + $ops = array_merge($ops, $this->bindings[$portData['binding']]['operations']); + } + } + } + } + if (count($ops) == 0) { + $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType"); + } + return $ops; + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $operation name of operation + * @param string $bindingType type of binding eg: soap, soap12 + * @return array + * @access public + */ + function getOperationData($operation, $bindingType = 'soap') + { + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } + // loop thru ports + foreach ($this->ports as $port => $portData) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + // get binding + //foreach($this->bindings[ $portData['binding'] ]['operations'] as $bOperation => $opData) { + foreach (array_keys($this->bindings[$portData['binding']]['operations']) as $bOperation) { + // note that we could/should also check the namespace here + if ($operation == $bOperation) { + $opData = $this->bindings[$portData['binding']]['operations'][$operation]; + return $opData; + } + } + } + } + } + + /** + * returns an associative array of data necessary for calling an operation + * + * @param string $soapAction soapAction for operation + * @param string $bindingType type of binding eg: soap, soap12 + * @return array + * @access public + */ + function getOperationDataForSoapAction($soapAction, $bindingType = 'soap') + { + if ($bindingType == 'soap') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/'; + } elseif ($bindingType == 'soap12') { + $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/'; + } + // loop thru ports + foreach ($this->ports as $port => $portData) { + // binding type of port matches parameter + if ($portData['bindingType'] == $bindingType) { + // loop through operations for the binding + foreach ($this->bindings[$portData['binding']]['operations'] as $bOperation => $opData) { + if ($opData['soapAction'] == $soapAction) { + return $opData; + } + } + } + } + } + + /** + * returns an array of information about a given type + * returns false if no type exists by the given name + * + * typeDef = array( + * 'elements' => array(), // refs to elements array + * 'restrictionBase' => '', + * 'phpType' => '', + * 'order' => '(sequence|all)', + * 'attrs' => array() // refs to attributes array + * ) + * + * @param string $type the type + * @param string $ns namespace (not prefix) of the type + * @return mixed + * @access public + * @see nusoap_xmlschema + */ + function getTypeDef($type, $ns) + { + $this->debug("in getTypeDef: type=$type, ns=$ns"); + if ((!$ns) && isset($this->namespaces['tns'])) { + $ns = $this->namespaces['tns']; + $this->debug("in getTypeDef: type namespace forced to $ns"); + } + if (!isset($this->schemas[$ns])) { + foreach ($this->schemas as $ns0 => $schema0) { + if (strcasecmp($ns, $ns0) == 0) { + $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0"); + $ns = $ns0; + break; + } + } + } + if (isset($this->schemas[$ns])) { + $this->debug("in getTypeDef: have schema for namespace $ns"); + for ($i = 0; $i < count($this->schemas[$ns]); $i++) { + $xs = &$this->schemas[$ns][$i]; + $t = $xs->getTypeDef($type); + $this->appendDebug($xs->getDebug()); + $xs->clearDebug(); + if ($t) { + $this->debug("in getTypeDef: found type $type"); + if (!isset($t['phpType'])) { + // get info for type to tack onto the element + $uqType = substr($t['type'], strrpos($t['type'], ':') + 1); + $ns = substr($t['type'], 0, strrpos($t['type'], ':')); + $etype = $this->getTypeDef($uqType, $ns); + if ($etype) { + $this->debug("found type for [element] $type:"); + $this->debug($this->varDump($etype)); + if (isset($etype['phpType'])) { + $t['phpType'] = $etype['phpType']; + } + if (isset($etype['elements'])) { + $t['elements'] = $etype['elements']; + } + if (isset($etype['attrs'])) { + $t['attrs'] = $etype['attrs']; + } + } else { + $this->debug("did not find type for [element] $type"); + } + } + return $t; + } + } + $this->debug("in getTypeDef: did not find type $type"); + } else { + $this->debug("in getTypeDef: do not have schema for namespace $ns"); + } + return false; + } + + /** + * prints html description of services + * + * @access private + */ + function webDescription() + { + global $HTTP_SERVER_VARS; + + if (isset($_SERVER)) { + $PHP_SELF = $_SERVER['PHP_SELF']; + } elseif (isset($HTTP_SERVER_VARS)) { + $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF']; + } else { + $this->setError("Neither _SERVER nor HTTP_SERVER_VARS is available"); + } + + $b = ' + NuSOAP: ' . $this->serviceName . ' + + + + +
+

+
' . $this->serviceName . '
+ +
'; + return $b; + } + + /** + * serialize the parsed wsdl + * + * @param mixed $debug whether to put debug=1 in endpoint URL + * @return string serialization of WSDL + * @access public + */ + function serialize($debug = 0) + { + $xml = ''; + $xml .= "\nnamespaces as $k => $v) { + $xml .= " xmlns:$k=\"$v\""; + } + // 10.9.02 - add poulter fix for wsdl and tns declarations + if (isset($this->namespaces['wsdl'])) { + $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\""; + } + if (isset($this->namespaces['tns'])) { + $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\""; + } + $xml .= '>'; + // imports + if (sizeof($this->import) > 0) { + foreach ($this->import as $ns => $list) { + foreach ($list as $ii) { + if ($ii['location'] != '') { + $xml .= ''; + } else { + $xml .= ''; + } + } + } + } + // types + if (count($this->schemas) >= 1) { + $xml .= "\n\n"; + foreach ($this->schemas as $ns => $list) { + foreach ($list as $xs) { + $xml .= $xs->serializeSchema(); + } + } + $xml .= ''; + } + // messages + if (count($this->messages) >= 1) { + foreach ($this->messages as $msgName => $msgParts) { + $xml .= "\n'; + if (is_array($msgParts)) { + foreach ($msgParts as $partName => $partType) { + // print 'serializing '.$partType.', sv: '.$this->XMLSchemaVersion.'
'; + if (strpos($partType, ':')) { + $typePrefix = $this->getPrefixFromNamespace($this->getPrefix($partType)); + } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) { + // print 'checking typemap: '.$this->XMLSchemaVersion.'
'; + $typePrefix = 'xsd'; + } else { + foreach ($this->typemap as $ns => $types) { + if (isset($types[$partType])) { + $typePrefix = $this->getPrefixFromNamespace($ns); + } + } + if (!isset($typePrefix)) { + die("$partType has no namespace!"); + } + } + $ns = $this->getNamespaceFromPrefix($typePrefix); + $localPart = $this->getLocalPart($partType); + $typeDef = $this->getTypeDef($localPart, $ns); + if ($typeDef['typeClass'] == 'element') { + $elementortype = 'element'; + if (substr($localPart, -1) == '^') { + $localPart = substr($localPart, 0, -1); + } + } else { + $elementortype = 'type'; + } + $xml .= "\n" . ' '; + } + } + $xml .= '
'; + } + } + // bindings & porttypes + if (count($this->bindings) >= 1) { + $binding_xml = ''; + $portType_xml = ''; + foreach ($this->bindings as $bindingName => $attrs) { + $binding_xml .= "\n'; + $binding_xml .= "\n" . ' '; + $portType_xml .= "\n'; + foreach ($attrs['operations'] as $opName => $opParts) { + $binding_xml .= "\n" . ' '; + $binding_xml .= "\n" . ' '; + if (isset($opParts['input']['encodingStyle']) && $opParts['input']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= "\n" . ' '; + if (isset($opParts['output']['encodingStyle']) && $opParts['output']['encodingStyle'] != '') { + $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"'; + } else { + $enc_style = ''; + } + $binding_xml .= "\n" . ' '; + $binding_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' ' . htmlspecialchars($opParts['documentation']) . ''; + } + $portType_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' '; + $portType_xml .= "\n" . ' '; + } + $portType_xml .= "\n" . ''; + $binding_xml .= "\n" . ''; + } + $xml .= $portType_xml . $binding_xml; + } + // services + $xml .= "\nserviceName . '">'; + if (count($this->ports) >= 1) { + foreach ($this->ports as $pName => $attrs) { + $xml .= "\n" . ' '; + $xml .= "\n" . ' '; + $xml .= "\n" . ' '; + } + } + $xml .= "\n" . ''; + return $xml . "\n"; + } + + /** + * determine whether a set of parameters are unwrapped + * when they are expect to be wrapped, Microsoft-style. + * + * @param string $type the type (element name) of the wrapper + * @param array $parameters the parameter values for the SOAP call + * @return boolean whether they parameters are unwrapped (and should be wrapped) + * @access private + */ + function parametersMatchWrapped($type, &$parameters) + { + $this->debug("in parametersMatchWrapped type=$type, parameters="); + $this->appendDebug($this->varDump($parameters)); + + // split type into namespace:unqualified-type + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns"); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in parametersMatchWrapped: No namespace for type $type"); + $ns = ''; + $uqType = $type; + } + + // get the type information + if (!$typeDef = $this->getTypeDef($uqType, $ns)) { + $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type."); + return false; + } + $this->debug("in parametersMatchWrapped: found typeDef="); + $this->appendDebug($this->varDump($typeDef)); + if (substr($uqType, -1) == '^') { + $uqType = substr($uqType, 0, -1); + } + $phpType = $typeDef['phpType']; + $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''); + $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType"); + + // we expect a complexType or element of complexType + if ($phpType != 'struct') { + $this->debug("in parametersMatchWrapped: not a struct"); + return false; + } + + // see whether the parameter names match the elements + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $elements = 0; + $matches = 0; + foreach ($typeDef['elements'] as $name => $attrs) { + if (isset($parameters[$name])) { + $this->debug("in parametersMatchWrapped: have parameter named $name"); + $matches++; + } else { + $this->debug("in parametersMatchWrapped: do not have parameter named $name"); + } + $elements++; + } + + $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names"); + if ($matches == 0) { + return false; + } + return true; + } + + // since there are no elements for the type, if the user passed no + // parameters, the parameters match wrapped. + $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType"); + return count($parameters) == 0; + } + + /** + * serialize PHP values according to a WSDL message definition + * contrary to the method name, this is not limited to RPC + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @param string $bindingType (soap|soap12) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + */ + function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap') + { + $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + if ($direction != 'input' && $direction != 'output') { + $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); + $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); + return false; + } + if (!$opData = $this->getOperationData($operation, $bindingType)) { + $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); + $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType); + return false; + } + $this->debug('in serializeRPCParameters: opData:'); + $this->appendDebug($this->varDump($opData)); + + // Get encoding style for output and set to current + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { + $encodingStyle = $opData['output']['encodingStyle']; + $enc_style = $encodingStyle; + } + + // set input params + $xml = ''; + if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { + $parts = &$opData[$direction]['parts']; + $part_count = sizeof($parts); + $style = $opData['style']; + $use = $opData[$direction]['use']; + $this->debug("have $part_count part(s) to serialize using $style/$use"); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $parameter_count = count($parameters); + $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize"); + // check for Microsoft-style wrapped parameters + if ($style == 'document' && $use == 'literal' && $part_count == 1 && isset($parts['parameters'])) { + $this->debug('check whether the caller has wrapped the parameters'); + if ($direction == 'output' && $parametersArrayType == 'arraySimple' && $parameter_count == 1) { + // TODO: consider checking here for double-wrapping, when + // service function wraps, then NuSOAP wraps again + $this->debug("change simple array to associative with 'parameters' element"); + $parameters['parameters'] = $parameters[0]; + unset($parameters[0]); + } + if (($parametersArrayType == 'arrayStruct' || $parameter_count == 0) && !isset($parameters['parameters'])) { + $this->debug('check whether caller\'s parameters match the wrapped ones'); + if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) { + $this->debug('wrap the parameters for the caller'); + $parameters = array('parameters' => $parameters); + $parameter_count = 1; + } + } + } + foreach ($parts as $name => $type) { + $this->debug("serializing part $name of type $type"); + // Track encoding style + if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { + $encodingStyle = $opData[$direction]['encodingStyle']; + $enc_style = $encodingStyle; + } else { + $enc_style = false; + } + // NOTE: add error handling here + // if serializeType returns false, then catch global error and fault + if ($parametersArrayType == 'arraySimple') { + $p = array_shift($parameters); + $this->debug('calling serializeType w/indexed param'); + $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); + } elseif (isset($parameters[$name])) { + $this->debug('calling serializeType w/named param'); + $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); + } else { + // TODO: only send nillable + $this->debug('calling serializeType w/null param'); + $xml .= $this->serializeType($name, $type, null, $use, $enc_style); + } + } + } else { + $this->debug('no parameters passed.'); + } + } + $this->debug("serializeRPCParameters returning: $xml"); + return $xml; + } + + /** + * serialize a PHP value according to a WSDL message definition + * + * TODO + * - multi-ref serialization + * - validate PHP values against type definitions, return errors if invalid + * + * @param string $operation operation name + * @param string $direction (input|output) + * @param mixed $parameters parameter value(s) + * @return mixed parameters serialized as XML or false on error (e.g. operation not found) + * @access public + * @deprecated + */ + function serializeParameters($operation, $direction, $parameters) + { + $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion"); + $this->appendDebug('parameters=' . $this->varDump($parameters)); + + if ($direction != 'input' && $direction != 'output') { + $this->debug('The value of the \$direction argument needs to be either "input" or "output"'); + $this->setError('The value of the \$direction argument needs to be either "input" or "output"'); + return false; + } + if (!$opData = $this->getOperationData($operation)) { + $this->debug('Unable to retrieve WSDL data for operation: ' . $operation); + $this->setError('Unable to retrieve WSDL data for operation: ' . $operation); + return false; + } + $this->debug('opData:'); + $this->appendDebug($this->varDump($opData)); + + // Get encoding style for output and set to current + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + if (($direction == 'input') && isset($opData['output']['encodingStyle']) && ($opData['output']['encodingStyle'] != $encodingStyle)) { + $encodingStyle = $opData['output']['encodingStyle']; + $enc_style = $encodingStyle; + } + + // set input params + $xml = ''; + if (isset($opData[$direction]['parts']) && sizeof($opData[$direction]['parts']) > 0) { + + $use = $opData[$direction]['use']; + $this->debug("use=$use"); + $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)'); + if (is_array($parameters)) { + $parametersArrayType = $this->isArraySimpleOrStruct($parameters); + $this->debug('have ' . $parametersArrayType . ' parameters'); + foreach ($opData[$direction]['parts'] as $name => $type) { + $this->debug('serializing part "' . $name . '" of type "' . $type . '"'); + // Track encoding style + if (isset($opData[$direction]['encodingStyle']) && $encodingStyle != $opData[$direction]['encodingStyle']) { + $encodingStyle = $opData[$direction]['encodingStyle']; + $enc_style = $encodingStyle; + } else { + $enc_style = false; + } + // NOTE: add error handling here + // if serializeType returns false, then catch global error and fault + if ($parametersArrayType == 'arraySimple') { + $p = array_shift($parameters); + $this->debug('calling serializeType w/indexed param'); + $xml .= $this->serializeType($name, $type, $p, $use, $enc_style); + } elseif (isset($parameters[$name])) { + $this->debug('calling serializeType w/named param'); + $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style); + } else { + // TODO: only send nillable + $this->debug('calling serializeType w/null param'); + $xml .= $this->serializeType($name, $type, null, $use, $enc_style); + } + } + } else { + $this->debug('no parameters passed.'); + } + } + $this->debug("serializeParameters returning: $xml"); + return $xml; + } + + /** + * serializes a PHP value according a given type definition + * + * @param string $name name of value (part or element) + * @param string $type XML schema type of value (type or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @param boolean $unqualified a kludge for what should be XML namespace form handling + * @return string value serialized as an XML string + * @access private + */ + function serializeType($name, $type, $value, $use = 'encoded', $encodingStyle = false, $unqualified = false) + { + $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? "unqualified" : "qualified")); + $this->appendDebug("value=" . $this->varDump($value)); + if ($use == 'encoded' && $encodingStyle) { + $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"'; + } + + // if a soapval has been supplied, let its type override the WSDL + if (is_object($value) && get_class($value) == 'soapval') { + if ($value->type_ns) { + $type = $value->type_ns . ':' . $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } elseif ($value->type) { + $type = $value->type; + $forceType = true; + $this->debug("in serializeType: soapval overrides type to $type"); + } else { + $forceType = false; + $this->debug("in serializeType: soapval does not override type"); + } + $attrs = $value->attributes; + $value = $value->value; + $this->debug("in serializeType: soapval overrides value to $value"); + if ($attrs) { + if (!is_array($value)) { + $value['!'] = $value; + } + foreach ($attrs as $n => $v) { + $value['!' . $n] = $v; + } + $this->debug("in serializeType: soapval provides attributes"); + } + } else { + $forceType = false; + } + + $xml = ''; + if (strpos($type, ':')) { + $uqType = substr($type, strrpos($type, ':') + 1); + $ns = substr($type, 0, strrpos($type, ':')); + $this->debug("in serializeType: got a prefixed type: $uqType, $ns"); + if ($this->getNamespaceFromPrefix($ns)) { + $ns = $this->getNamespaceFromPrefix($ns); + $this->debug("in serializeType: expanded prefixed type: $uqType, $ns"); + } + + if ($ns == $this->XMLSchemaVersion || $ns == 'http://schemas.xmlsoap.org/soap/encoding/') { + $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type'); + if ($unqualified && $use == 'literal') { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + // TODO: depends on nillable, which should be checked before calling this method + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if ($uqType == 'Array') { + // JBoss/Axis does this sometimes + return $this->serialize_val($value, $name, false, false, false, false, $use); + } + if ($uqType == 'boolean') { + if ((is_string($value) && $value == 'false') || (!$value)) { + $value = 'false'; + } else { + $value = 'true'; + } + } + if ($uqType == 'string' && gettype($value) == 'string') { + $value = $this->expandEntities($value); + } + if (($uqType == 'long' || $uqType == 'unsignedLong') && gettype($value) == 'double') { + $value = sprintf("%.0lf", $value); + } + // it's a scalar + // TODO: what about null/nil values? + // check type isn't a custom type extending xmlschema namespace + if (!$this->getTypeDef($uqType, $ns)) { + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; + } else { + $xml = "<$name$elementNS>$value"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)'); + } elseif ($ns == 'http://xml.apache.org/xml-soap') { + $this->debug('in serializeType: appears to be Apache SOAP type'); + if ($uqType == 'Map') { + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + if (!$tt_prefix) { + $this->debug('in serializeType: Add namespace for Apache SOAP type'); + $tt_prefix = 'ns' . rand(1000, 9999); + $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap'; + // force this to be added to usedNamespaces + $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap'); + } + $contents = ''; + foreach ($value as $k => $v) { + $this->debug("serializing map element: key $k, value $v"); + $contents .= ''; + $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use); + $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use); + $contents .= ''; + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents"; + } else { + $xml = "<$name>$contents"; + } + } else { + $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + $this->debug('in serializeType: Apache SOAP type, but only support Map'); + } + } else { + // TODO: should the type be compared to types in XSD, and the namespace + // set to XSD if the type matches? + $this->debug("in serializeType: No namespace for type $type"); + $ns = ''; + $uqType = $type; + } + if (!$typeDef = $this->getTypeDef($uqType, $ns)) { + $this->setError("$type ($uqType) is not a supported type."); + $this->debug("in serializeType: $type ($uqType) is not a supported type."); + return false; + } else { + $this->debug("in serializeType: found typeDef"); + $this->appendDebug('typeDef=' . $this->varDump($typeDef)); + if (substr($uqType, -1) == '^') { + $uqType = substr($uqType, 0, -1); + } + } + if (!isset($typeDef['phpType'])) { + $this->setError("$type ($uqType) has no phpType."); + $this->debug("in serializeType: $type ($uqType) has no phpType."); + return false; + } + $phpType = $typeDef['phpType']; + $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '')); + // if php type == struct, map value to the element names + if ($phpType == 'struct') { + if (isset($typeDef['typeClass']) && $typeDef['typeClass'] == 'element') { + $elementName = $uqType; + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + $elementNS = " xmlns=\"\""; + } + } else { + $elementName = $name; + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs and nillable + $xml = "<$elementName$elementNS/>"; + } else { + $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (is_object($value)) { + $value = get_object_vars($value); + } + if (is_array($value)) { + $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType); + if ($use == 'literal') { + if ($forceType) { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">"; + } else { + $xml = "<$elementName$elementNS$elementAttrs>"; + } + } else { + $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>"; + } + + if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] == 'true') { + if (isset($value['!'])) { + $xml .= $value['!']; + $this->debug("in serializeType: serialized simpleContent for type $type"); + } else { + $this->debug("in serializeType: no simpleContent to serialize for type $type"); + } + } else { + // complexContent + $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle); + } + $xml .= ""; + } else { + $this->debug("in serializeType: phpType is struct, but value is not an array"); + $this->setError("phpType is struct, but value is not an array: see debug output for details"); + $xml = ''; + } + } elseif ($phpType == 'array') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if (is_null($value)) { + if ($use == 'literal') { + // TODO: depends on minOccurs + $xml = "<$name$elementNS/>"; + } else { + $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . + ":Array\" " . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . + ':arrayType="' . + $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . + ':' . + $this->getLocalPart($typeDef['arrayType']) . "[0]\"/>"; + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + if (isset($typeDef['multidimensional'])) { + $nv = array(); + foreach ($value as $v) { + $cols = ',' . sizeof($v); + $nv = array_merge($nv, $v); + } + $value = $nv; + } else { + $cols = ''; + } + if (is_array($value) && sizeof($value) >= 1) { + $rows = sizeof($value); + $contents = ''; + foreach ($value as $k => $v) { + $this->debug("serializing array element: $k, " . (is_array($v) ? "array" : $v) . " of type: $typeDef[arrayType]"); + //if (strpos($typeDef['arrayType'], ':') ) { + if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) { + $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use); + } else { + $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use); + } + } + } else { + $rows = 0; + $contents = null; + } + // TODO: for now, an empty value will be serialized as a zero element + // array. Revisit this when coding the handling of null/nil values. + if ($use == 'literal') { + $xml = "<$name$elementNS>" + . $contents + . ""; + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':Array" ' . + $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') + . ':arrayType="' + . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) + . ":" . $this->getLocalPart($typeDef['arrayType']) . "[$rows$cols]\">" + . $contents + . ""; + } + } elseif ($phpType == 'scalar') { + if (isset($typeDef['form']) && ($typeDef['form'] == 'qualified')) { + $elementNS = " xmlns=\"$ns\""; + } else { + if ($unqualified) { + $elementNS = " xmlns=\"\""; + } else { + $elementNS = ''; + } + } + if ($use == 'literal') { + if ($forceType) { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value"; + } else { + $xml = "<$name$elementNS>$value"; + } + } else { + $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value"; + } + } + $this->debug("in serializeType: returning: $xml"); + return $xml; + } + + /** + * serializes the attributes for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType) + { + $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType"); + $xml = ''; + if (isset($typeDef['extensionBase'])) { + $nsx = $this->getPrefix($typeDef['extensionBase']); + $uqTypex = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($nsx)) { + $nsx = $this->getNamespaceFromPrefix($nsx); + } + if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { + $this->debug("serialize attributes for extension base $nsx:$uqTypex"); + $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex); + } else { + $this->debug("extension base $nsx:$uqTypex is not a supported type"); + } + } + if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) { + $this->debug("serialize attributes for XML Schema type $ns:$uqType"); + if (is_array($value)) { + $xvalue = $value; + } elseif (is_object($value)) { + $xvalue = get_object_vars($value); + } else { + $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); + $xvalue = array(); + } + foreach ($typeDef['attrs'] as $aName => $attrs) { + if (isset($xvalue['!' . $aName])) { + $xname = '!' . $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($xvalue[$aName])) { + $xname = $aName; + $this->debug("value provided for attribute $aName with key $xname"); + } elseif (isset($attrs['default'])) { + $xname = '!' . $aName; + $xvalue[$xname] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName); + } else { + $xname = ''; + $this->debug("no value provided for attribute $aName"); + } + if ($xname) { + $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\""; + } + } + } else { + $this->debug("no attributes to serialize for XML Schema type $ns:$uqType"); + } + return $xml; + } + + /** + * serializes the elements for a complexType + * + * @param array $typeDef our internal representation of an XML schema type (or element) + * @param mixed $value a native PHP value (parameter value) + * @param string $ns the namespace of the type + * @param string $uqType the local part of the type + * @param string $use use for part (encoded|literal) + * @param string $encodingStyle SOAP encoding style for the value (if different than the enclosing style) + * @return string value serialized as an XML string + * @access private + */ + function serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use = 'encoded', $encodingStyle = false) + { + $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType"); + $xml = ''; + if (isset($typeDef['extensionBase'])) { + $nsx = $this->getPrefix($typeDef['extensionBase']); + $uqTypex = $this->getLocalPart($typeDef['extensionBase']); + if ($this->getNamespaceFromPrefix($nsx)) { + $nsx = $this->getNamespaceFromPrefix($nsx); + } + if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) { + $this->debug("serialize elements for extension base $nsx:$uqTypex"); + $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle); + } else { + $this->debug("extension base $nsx:$uqTypex is not a supported type"); + } + } + if (isset($typeDef['elements']) && is_array($typeDef['elements'])) { + $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType"); + if (is_array($value)) { + $xvalue = $value; + } elseif (is_object($value)) { + $xvalue = get_object_vars($value); + } else { + $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType"); + $xvalue = array(); + } + // toggle whether all elements are present - ideally should validate against schema + if (count($typeDef['elements']) != count($xvalue)) { + $optionals = true; + } + foreach ($typeDef['elements'] as $eName => $attrs) { + if (!isset($xvalue[$eName])) { + if (isset($attrs['default'])) { + $xvalue[$eName] = $attrs['default']; + $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName); + } + } + // if user took advantage of a minOccurs=0, then only serialize named parameters + if (isset($optionals) + && (!isset($xvalue[$eName])) + && ((!isset($attrs['nillable'])) || $attrs['nillable'] != 'true') + ) { + if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') { + $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']); + } + // do nothing + $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing"); + } else { + // get value + if (isset($xvalue[$eName])) { + $v = $xvalue[$eName]; + } else { + $v = null; + } + if (isset($attrs['form'])) { + $unqualified = ($attrs['form'] == 'unqualified'); + } else { + $unqualified = false; + } + if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] == 'unbounded' || $attrs['maxOccurs'] > 1) && isset($v) && is_array($v) && $this->isArraySimpleOrStruct($v) == 'arraySimple') { + $vv = $v; + foreach ($vv as $k => $v) { + if (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); + $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); + } + } + } else { + if (is_null($v) && isset($attrs['minOccurs']) && $attrs['minOccurs'] == '0') { + // do nothing + } elseif (is_null($v) && isset($attrs['nillable']) && $attrs['nillable'] == 'true') { + // TODO: serialize a nil correctly, but for now serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } elseif (isset($attrs['type']) || isset($attrs['ref'])) { + // serialize schema-defined type + $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified); + } else { + // serialize generic type (can this ever really happen?) + $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use"); + $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use); + } + } + } + } + } else { + $this->debug("no elements to serialize for XML Schema type $ns:$uqType"); + } + return $xml; + } + + /** + * adds an XML Schema complex type to the WSDL types + * + * @param string $name + * @param string $typeClass (complexType|simpleType|attribute) + * @param string $phpType currently supported are array and struct (php assoc array) + * @param string $compositor (all|sequence|choice) + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param array $elements e.g. array ( name => array(name=>'',type=>'') ) + * @param array $attrs e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]')) + * @param string $arrayType as namespace:name (xsd:string) + * @see nusoap_xmlschema + * @access public + */ + function addComplexType($name, $typeClass = 'complexType', $phpType = 'array', $compositor = '', $restrictionBase = '', $elements = array(), $attrs = array(), $arrayType = '') + { + if (count($elements) > 0) { + $eElements = array(); + foreach ($elements as $n => $e) { + // expand each element + $ee = array(); + foreach ($e as $k => $v) { + $k = strpos($k, ':') ? $this->expandQname($k) : $k; + $v = strpos($v, ':') ? $this->expandQname($v) : $v; + $ee[$k] = $v; + } + $eElements[$n] = $ee; + } + $elements = $eElements; + } + + if (count($attrs) > 0) { + foreach ($attrs as $n => $a) { + // expand each attribute + foreach ($a as $k => $v) { + $k = strpos($k, ':') ? $this->expandQname($k) : $k; + $v = strpos($v, ':') ? $this->expandQname($v) : $v; + $aa[$k] = $v; + } + $eAttrs[$n] = $aa; + } + $attrs = $eAttrs; + } + + $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase; + $arrayType = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType; + + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType); + } + + /** + * adds an XML Schema simple type to the WSDL types + * + * @param string $name + * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array) + * @param string $typeClass (should always be simpleType) + * @param string $phpType (should always be scalar) + * @param array $enumeration array of values + * @see nusoap_xmlschema + * @access public + */ + function addSimpleType($name, $restrictionBase = '', $typeClass = 'simpleType', $phpType = 'scalar', $enumeration = array()) + { + $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase; + + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration); + } + + /** + * adds an element to the WSDL types + * + * @param array $attrs attributes that must include name and type + * @see nusoap_xmlschema + * @access public + */ + function addElement($attrs) + { + $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns']; + $this->schemas[$typens][0]->addElement($attrs); + } + + /** + * register an operation with the server + * + * @param string $name operation (method) name + * @param array $in assoc array of input values: key = param name, value = param type + * @param array $out assoc array of output values: key = param name, value = param type + * @param string $namespace optional The namespace for the operation + * @param string $soapaction optional The soapaction for the operation + * @param string $style (rpc|document) optional The style for the operation Note: when 'document' is specified, parameter and return wrappers are created for you automatically + * @param string $use (encoded|literal) optional The use for the parameters (cannot mix right now) + * @param string $documentation optional The description to include in the WSDL + * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded) + * @access public + */ + function addOperation($name, $in = false, $out = false, $namespace = false, $soapaction = false, $style = 'rpc', $use = 'encoded', $documentation = '', $encodingStyle = '') + { + if ($use == 'encoded' && $encodingStyle == '') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } + + if ($style == 'document') { + $elements = array(); + foreach ($in as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); + } + $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name, 'type' => $name . 'RequestType')); + $in = array('parameters' => 'tns:' . $name . '^'); + + $elements = array(); + foreach ($out as $n => $t) { + $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified'); + } + $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements); + $this->addElement(array('name' => $name . 'Response', 'type' => $name . 'ResponseType', 'form' => 'qualified')); + $out = array('parameters' => 'tns:' . $name . 'Response' . '^'); + } + + // get binding + $this->bindings[$this->serviceName . 'Binding']['operations'][$name] = + array( + 'name' => $name, + 'binding' => $this->serviceName . 'Binding', + 'endpoint' => $this->endpoint, + 'soapAction' => $soapaction, + 'style' => $style, + 'input' => array( + 'use' => $use, + 'namespace' => $namespace, + 'encodingStyle' => $encodingStyle, + 'message' => $name . 'Request', + 'parts' => $in), + 'output' => array( + 'use' => $use, + 'namespace' => $namespace, + 'encodingStyle' => $encodingStyle, + 'message' => $name . 'Response', + 'parts' => $out), + 'namespace' => $namespace, + 'transport' => 'http://schemas.xmlsoap.org/soap/http', + 'documentation' => $documentation); + // add portTypes + // add messages + if ($in) { + foreach ($in as $pName => $pType) { + if (strpos($pType, ':')) { + $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType); + } + $this->messages[$name . 'Request'][$pName] = $pType; + } + } else { + $this->messages[$name . 'Request'] = '0'; + } + if ($out) { + foreach ($out as $pName => $pType) { + if (strpos($pType, ':')) { + $pType = $this->getNamespaceFromPrefix($this->getPrefix($pType)) . ":" . $this->getLocalPart($pType); + } + $this->messages[$name . 'Response'][$pName] = $pType; + } + } else { + $this->messages[$name . 'Response'] = '0'; + } + return true; + } +} + + +/** + * + * nusoap_parser class parses SOAP XML messages into native PHP values + * + * @author Dietrich Ayala + * @author Scott Nichol + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class nusoap_parser extends nusoap_base +{ + + var $xml = ''; + var $xml_encoding = ''; + var $method = ''; + var $root_struct = ''; + var $root_struct_name = ''; + var $root_struct_namespace = ''; + var $root_header = ''; + var $document = ''; // incoming SOAP body (text) + // determines where in the message we are (envelope,header,body,method) + var $status = ''; + var $position = 0; + var $depth = 0; + var $default_namespace = ''; + var $namespaces = array(); + var $message = array(); + var $parent = ''; + var $fault = false; + var $fault_code = ''; + var $fault_str = ''; + var $fault_detail = ''; + var $depth_array = array(); + var $debug_flag = true; + var $soapresponse = null; // parsed SOAP Body + var $soapheader = null; // parsed SOAP Header + var $responseHeaders = ''; // incoming SOAP headers (text) + var $body_position = 0; + // for multiref parsing: + // array of id => pos + var $ids = array(); + // array of id => hrefs => pos + var $multirefs = array(); + // toggle for auto-decoding element content + var $decode_utf8 = true; + + /** + * constructor that actually does the parsing + * + * @param string $xml SOAP message + * @param string $encoding character encoding scheme of message + * @param string $method method for which XML is parsed (unused?) + * @param string $decode_utf8 whether to decode UTF-8 to ISO-8859-1 + * @access public + */ + function __construct($xml, $encoding = 'UTF-8', $method = '', $decode_utf8 = true) + { + parent::__construct(); + $this->xml = $xml; + $this->xml_encoding = $encoding; + $this->method = $method; + $this->decode_utf8 = $decode_utf8; + + // Check whether content has been read. + if (!empty($xml)) { + // Check XML encoding + $pos_xml = strpos($xml, '', $pos_xml + 2) - $pos_xml + 1); + if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) { + $xml_encoding = $res[1]; + if (strtoupper($xml_encoding) != $encoding) { + $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'"; + $this->debug($err); + if ($encoding != 'ISO-8859-1' || strtoupper($xml_encoding) != 'UTF-8') { + $this->setError($err); + return; + } + // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed + } else { + $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration'); + } + } else { + $this->debug('No encoding specified in XML declaration'); + } + } else { + $this->debug('No XML declaration'); + } + $this->debug('Entering nusoap_parser(), length=' . strlen($xml) . ', encoding=' . $encoding); + // Create an XML parser - why not xml_parser_create_ns? + $this->parser = xml_parser_create($this->xml_encoding); + // Set the options for parsing the XML data. + //xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); + xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0); + xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding); + // Set the object for the parser. + xml_set_object($this->parser, $this); + // Set the element handlers for the parser. + xml_set_element_handler($this->parser, 'start_element', 'end_element'); + xml_set_character_data_handler($this->parser, 'character_data'); + + // Parse the XML file. + if (!xml_parse($this->parser, $xml, true)) { + // Display an error message. + $err = sprintf('XML error parsing SOAP payload on line %d: %s', + xml_get_current_line_number($this->parser), + xml_error_string(xml_get_error_code($this->parser))); + $this->debug($err); + $this->debug("XML payload:\n" . $xml); + $this->setError($err); + } else { + $this->debug('in nusoap_parser ctor, message:'); + $this->appendDebug($this->varDump($this->message)); + $this->debug('parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name); + // get final value + $this->soapresponse = $this->message[$this->root_struct]['result']; + // get header value + if ($this->root_header != '' && isset($this->message[$this->root_header]['result'])) { + $this->soapheader = $this->message[$this->root_header]['result']; + } + // resolve hrefs/ids + if (sizeof($this->multirefs) > 0) { + foreach ($this->multirefs as $id => $hrefs) { + $this->debug('resolving multirefs for id: ' . $id); + $idVal = $this->buildVal($this->ids[$id]); + if (is_array($idVal) && isset($idVal['!id'])) { + unset($idVal['!id']); + } + foreach ($hrefs as $refPos => $ref) { + $this->debug('resolving href at pos ' . $refPos); + $this->multirefs[$id][$refPos] = $idVal; + } + } + } + } + xml_parser_free($this->parser); + unset($this->parser); + } else { + $this->debug('xml was empty, didn\'t parse!'); + $this->setError('xml was empty, didn\'t parse!'); + } + } + + /** + * start-element handler + * + * @param resource $parser XML parser object + * @param string $name element name + * @param array $attrs associative array of attributes + * @access private + */ + function start_element($parser, $name, $attrs) + { + // position in a total number of elements, starting from 0 + // update class level pos + $pos = $this->position++; + // and set mine + $this->message[$pos] = array('pos' => $pos, 'children' => '', 'cdata' => ''); + // depth = how many levels removed from root? + // set mine as current global depth and increment global depth value + $this->message[$pos]['depth'] = $this->depth++; + + // else add self as child to whoever the current parent is + if ($pos != 0) { + $this->message[$this->parent]['children'] .= '|' . $pos; + } + // set my parent + $this->message[$pos]['parent'] = $this->parent; + // set self as current parent + $this->parent = $pos; + // set self as current value for this depth + $this->depth_array[$this->depth] = $pos; + // get element prefix + if (strpos($name, ':')) { + // get ns prefix + $prefix = substr($name, 0, strpos($name, ':')); + // get unqualified name + $name = substr(strstr($name, ':'), 1); + } + // set status + if ($name == 'Envelope' && $this->status == '') { + $this->status = 'envelope'; + } elseif ($name == 'Header' && $this->status == 'envelope') { + $this->root_header = $pos; + $this->status = 'header'; + } elseif ($name == 'Body' && $this->status == 'envelope') { + $this->status = 'body'; + $this->body_position = $pos; + // set method + } elseif ($this->status == 'body' && $pos == ($this->body_position + 1)) { + $this->status = 'method'; + $this->root_struct_name = $name; + $this->root_struct = $pos; + $this->message[$pos]['type'] = 'struct'; + $this->debug("found root struct $this->root_struct_name, pos $this->root_struct"); + } + // set my status + $this->message[$pos]['status'] = $this->status; + // set name + $this->message[$pos]['name'] = htmlspecialchars($name); + // set attrs + $this->message[$pos]['attrs'] = $attrs; + + // loop through atts, logging ns and type declarations + $attstr = ''; + foreach ($attrs as $key => $value) { + $key_prefix = $this->getPrefix($key); + $key_localpart = $this->getLocalPart($key); + // if ns declarations, add to class level array of valid namespaces + if ($key_prefix == 'xmlns') { + if (preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value)) { + $this->XMLSchemaVersion = $value; + $this->namespaces['xsd'] = $this->XMLSchemaVersion; + $this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance'; + } + $this->namespaces[$key_localpart] = $value; + // set method namespace + if ($name == $this->root_struct_name) { + $this->methodNamespace = $value; + } + // if it's a type declaration, set type + } elseif ($key_localpart == 'type') { + if (isset($this->message[$pos]['type']) && $this->message[$pos]['type'] == 'array') { + // do nothing: already processed arrayType + } else { + $value_prefix = $this->getPrefix($value); + $value_localpart = $this->getLocalPart($value); + $this->message[$pos]['type'] = $value_localpart; + $this->message[$pos]['typePrefix'] = $value_prefix; + if (isset($this->namespaces[$value_prefix])) { + $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix]; + } elseif (isset($attrs['xmlns:' . $value_prefix])) { + $this->message[$pos]['type_namespace'] = $attrs['xmlns:' . $value_prefix]; + } + // should do something here with the namespace of specified type? + } + } elseif ($key_localpart == 'arrayType') { + $this->message[$pos]['type'] = 'array'; + /* do arrayType ereg here + [1] arrayTypeValue ::= atype asize + [2] atype ::= QName rank* + [3] rank ::= '[' (',')* ']' + [4] asize ::= '[' length~ ']' + [5] length ::= nextDimension* Digit+ + [6] nextDimension ::= Digit+ ',' + */ + $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/'; + if (preg_match($expr, $value, $regs)) { + $this->message[$pos]['typePrefix'] = $regs[1]; + $this->message[$pos]['arrayTypePrefix'] = $regs[1]; + if (isset($this->namespaces[$regs[1]])) { + $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]]; + } elseif (isset($attrs['xmlns:' . $regs[1]])) { + $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:' . $regs[1]]; + } + $this->message[$pos]['arrayType'] = $regs[2]; + $this->message[$pos]['arraySize'] = $regs[3]; + $this->message[$pos]['arrayCols'] = $regs[4]; + } + // specifies nil value (or not) + } elseif ($key_localpart == 'nil') { + $this->message[$pos]['nil'] = ($value == 'true' || $value == '1'); + // some other attribute + } elseif ($key != 'href' && $key != 'xmlns' && $key_localpart != 'encodingStyle' && $key_localpart != 'root') { + $this->message[$pos]['xattrs']['!' . $key] = $value; + } + + if ($key == 'xmlns') { + $this->default_namespace = $value; + } + // log id + if ($key == 'id') { + $this->ids[$value] = $pos; + } + // root + if ($key_localpart == 'root' && $value == 1) { + $this->status = 'method'; + $this->root_struct_name = $name; + $this->root_struct = $pos; + $this->debug("found root struct $this->root_struct_name, pos $pos"); + } + // for doclit + $attstr .= " $key=\"$value\""; + } + // get namespace - must be done after namespace atts are processed + if (isset($prefix)) { + $this->message[$pos]['namespace'] = $this->namespaces[$prefix]; + $this->default_namespace = $this->namespaces[$prefix]; + } else { + $this->message[$pos]['namespace'] = $this->default_namespace; + } + if ($this->status == 'header') { + if ($this->root_header != $pos) { + $this->responseHeaders .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; + } + } elseif ($this->root_struct_name != '') { + $this->document .= "<" . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>"; + } + } + + /** + * end-element handler + * + * @param resource $parser XML parser object + * @param string $name element name + * @access private + */ + function end_element($parser, $name) + { + // position of current element is equal to the last value left in depth_array for my depth + $pos = $this->depth_array[$this->depth--]; + + // get element prefix + if (strpos($name, ':')) { + // get ns prefix + $prefix = substr($name, 0, strpos($name, ':')); + // get unqualified name + $name = substr(strstr($name, ':'), 1); + } + + // build to native type + if (isset($this->body_position) && $pos > $this->body_position) { + // deal w/ multirefs + if (isset($this->message[$pos]['attrs']['href'])) { + // get id + $id = substr($this->message[$pos]['attrs']['href'], 1); + // add placeholder to href array + $this->multirefs[$id][$pos] = 'placeholder'; + // add set a reference to it as the result value + $this->message[$pos]['result'] =& $this->multirefs[$id][$pos]; + // build complexType values + } elseif ($this->message[$pos]['children'] != '') { + // if result has already been generated (struct/array) + if (!isset($this->message[$pos]['result'])) { + $this->message[$pos]['result'] = $this->buildVal($pos); + } + // build complexType values of attributes and possibly simpleContent + } elseif (isset($this->message[$pos]['xattrs'])) { + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + if (isset($this->message[$pos]['type'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata']; + } + } + } + $this->message[$pos]['result'] = $this->message[$pos]['xattrs']; + // set value of simpleType (or nil complexType) + } else { + //$this->debug('adding data for scalar value '.$this->message[$pos]['name'].' of value '.$this->message[$pos]['cdata']); + if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) { + $this->message[$pos]['xattrs']['!'] = null; + } elseif (isset($this->message[$pos]['type'])) { + $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $this->message[$pos]['result'] = $this->message[$pos]['cdata']; + } + } + + /* add value to parent's result, if parent is struct/array + $parent = $this->message[$pos]['parent']; + if($this->message[$parent]['type'] != 'map'){ + if(strtolower($this->message[$parent]['type']) == 'array'){ + $this->message[$parent]['result'][] = $this->message[$pos]['result']; + } else { + $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result']; + } + } + */ + } + } + + // for doclit + if ($this->status == 'header') { + if ($this->root_header != $pos) { + $this->responseHeaders .= ""; + } + } elseif ($pos >= $this->root_struct) { + $this->document .= ""; + } + // switch status + if ($pos == $this->root_struct) { + $this->status = 'body'; + $this->root_struct_namespace = $this->message[$pos]['namespace']; + } elseif ($pos == $this->root_header) { + $this->status = 'envelope'; + } elseif ($name == 'Body' && $this->status == 'body') { + $this->status = 'envelope'; + } elseif ($name == 'Header' && $this->status == 'header') { // will never happen + $this->status = 'envelope'; + } elseif ($name == 'Envelope' && $this->status == 'envelope') { + $this->status = ''; + } + // set parent back to my parent + $this->parent = $this->message[$pos]['parent']; + } + + /** + * element content handler + * + * @param resource $parser XML parser object + * @param string $data element content + * @access private + */ + function character_data($parser, $data) + { + $pos = $this->depth_array[$this->depth]; + if ($this->xml_encoding == 'UTF-8') { + // TODO: add an option to disable this for folks who want + // raw UTF-8 that, e.g., might not map to iso-8859-1 + // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1"); + if ($this->decode_utf8) { + $data = utf8_decode($data); + } + } + $this->message[$pos]['cdata'] .= $data; + // for doclit + if ($this->status == 'header') { + $this->responseHeaders .= $data; + } else { + $this->document .= $data; + } + } + + /** + * get the parsed message (SOAP Body) + * + * @return mixed + * @access public + * @deprecated use get_soapbody instead + */ + function get_response() + { + return $this->soapresponse; + } + + /** + * get the parsed SOAP Body (null if there was none) + * + * @return mixed + * @access public + */ + function get_soapbody() + { + return $this->soapresponse; + } + + /** + * get the parsed SOAP Header (null if there was none) + * + * @return mixed + * @access public + */ + function get_soapheader() + { + return $this->soapheader; + } + + /** + * get the unparsed SOAP Header + * + * @return string XML or empty if no Header + * @access public + */ + function getHeaders() + { + return $this->responseHeaders; + } + + /** + * decodes simple types into PHP variables + * + * @param string $value value to decode + * @param string $type XML type to decode + * @param string $typens XML type namespace to decode + * @return mixed PHP value + * @access private + */ + function decodeSimple($value, $type, $typens) + { + // TODO: use the namespace! + if ((!isset($type)) || $type == 'string' || $type == 'long' || $type == 'unsignedLong') { + return (string) $value; + } + if ($type == 'int' || $type == 'integer' || $type == 'short' || $type == 'byte') { + return (int) $value; + } + if ($type == 'float' || $type == 'double' || $type == 'decimal') { + return (double) $value; + } + if ($type == 'boolean') { + if (strtolower($value) == 'false' || strtolower($value) == 'f') { + return false; + } + return (boolean) $value; + } + if ($type == 'base64' || $type == 'base64Binary') { + $this->debug('Decode base64 value'); + return base64_decode($value); + } + // obscure numeric types + if ($type == 'nonPositiveInteger' || $type == 'negativeInteger' + || $type == 'nonNegativeInteger' || $type == 'positiveInteger' + || $type == 'unsignedInt' + || $type == 'unsignedShort' || $type == 'unsignedByte' + ) { + return (int) $value; + } + // bogus: parser treats array with no elements as a simple type + if ($type == 'array') { + return array(); + } + // everything else + return (string) $value; + } + + /** + * builds response structures for compound values (arrays/structs) + * and scalars + * + * @param integer $pos position in node tree + * @return mixed PHP value + * @access private + */ + function buildVal($pos) + { + if (!isset($this->message[$pos]['type'])) { + $this->message[$pos]['type'] = ''; + } + $this->debug('in buildVal() for ' . $this->message[$pos]['name'] . "(pos $pos) of type " . $this->message[$pos]['type']); + // if there are children... + if ($this->message[$pos]['children'] != '') { + $params = []; + $this->debug('in buildVal, there are children'); + $children = explode('|', $this->message[$pos]['children']); + array_shift($children); // knock off empty + // md array + if (isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != '') { + $r = 0; // rowcount + $c = 0; // colcount + foreach ($children as $child_pos) { + $this->debug("in buildVal, got an MD array element: $r, $c"); + $params[$r][] = $this->message[$child_pos]['result']; + $c++; + if ($c == $this->message[$pos]['arrayCols']) { + $c = 0; + $r++; + } + } + // array + } elseif ($this->message[$pos]['type'] == 'array' || $this->message[$pos]['type'] == 'Array') { + $this->debug('in buildVal, adding array ' . $this->message[$pos]['name']); + foreach ($children as $child_pos) { + $params[] = &$this->message[$child_pos]['result']; + } + // apache Map type: java hashtable + } elseif ($this->message[$pos]['type'] == 'Map' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { + $this->debug('in buildVal, Java Map ' . $this->message[$pos]['name']); + foreach ($children as $child_pos) { + $kv = explode("|", $this->message[$child_pos]['children']); + $params[$this->message[$kv[1]]['result']] = &$this->message[$kv[2]]['result']; + } + // generic compound type + //} elseif($this->message[$pos]['type'] == 'SOAPStruct' || $this->message[$pos]['type'] == 'struct') { + } else { + // Apache Vector type: treat as an array + $this->debug('in buildVal, adding Java Vector or generic compound type ' . $this->message[$pos]['name']); + if ($this->message[$pos]['type'] == 'Vector' && $this->message[$pos]['type_namespace'] == 'http://xml.apache.org/xml-soap') { + $notstruct = 1; + } else { + $notstruct = 0; + } + // + foreach ($children as $child_pos) { + if ($notstruct) { + $params[] = &$this->message[$child_pos]['result']; + } else { + if (isset($params[$this->message[$child_pos]['name']])) { + // de-serialize repeated element name into an array + if ((!is_array($params[$this->message[$child_pos]['name']])) || (!isset($params[$this->message[$child_pos]['name']][0]))) { + $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]); + } + $params[$this->message[$child_pos]['name']][] = &$this->message[$child_pos]['result']; + } else { + $params[$this->message[$child_pos]['name']] = &$this->message[$child_pos]['result']; + } + } + } + } + if (isset($this->message[$pos]['xattrs'])) { + $this->debug('in buildVal, handling attributes'); + foreach ($this->message[$pos]['xattrs'] as $n => $v) { + $params[$n] = $v; + } + } + // handle simpleContent + if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') { + $this->debug('in buildVal, handling simpleContent'); + if (isset($this->message[$pos]['type'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + } else { + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + } else { + $params['!'] = $this->message[$pos]['cdata']; + } + } + } + $ret = is_array($params) ? $params : array(); + $this->debug('in buildVal, return:'); + $this->appendDebug($this->varDump($ret)); + return $ret; + } else { + $this->debug('in buildVal, no children, building scalar'); + $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : ''; + if (isset($this->message[$pos]['type'])) { + $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : ''); + $this->debug("in buildVal, return: $ret"); + return $ret; + } + $parent = $this->message[$pos]['parent']; + if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] == 'array') && isset($this->message[$parent]['arrayType'])) { + $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : ''); + $this->debug("in buildVal, return: $ret"); + return $ret; + } + $ret = $this->message[$pos]['cdata']; + $this->debug("in buildVal, return: $ret"); + return $ret; + } + } +} + + +/** + * Backward compatibility + */ +class soap_parser extends nusoap_parser +{ +} + + +/** + * + * [nu]soapclient higher level class for easy usage. + * + * usage: + * + * // instantiate client with server info + * $soapclient = new nusoap_client( string path [ ,mixed wsdl] ); + * + * // call method, get results + * echo $soapclient->call( string methodname [ ,array parameters] ); + * + * // bye bye client + * unset($soapclient); + * + * @author Dietrich Ayala + * @author Scott Nichol + * @version $Id: nusoap.php,v 1.123 2010/04/26 20:15:08 snichol Exp $ + * @access public + */ +class nusoap_client extends nusoap_base +{ + + var $username = ''; // Username for HTTP authentication + var $password = ''; // Password for HTTP authentication + var $authtype = ''; // Type of HTTP authentication + var $certRequest = array(); // Certificate for HTTP SSL authentication + var $requestHeaders = false; // SOAP headers in request (text) + var $responseHeaders = ''; // SOAP headers from response (incomplete namespace resolution) (text) + var $responseHeader = null; // SOAP Header from response (parsed) + var $document = ''; // SOAP body response portion (incomplete namespace resolution) (text) + var $endpoint; + var $forceEndpoint = ''; // overrides WSDL endpoint + var $proxyhost = ''; + var $proxyport = ''; + var $proxyusername = ''; + var $proxypassword = ''; + var $portName = ''; // port name to use in WSDL + var $xml_encoding = ''; // character set encoding of incoming (response) messages + var $http_encoding = false; + var $timeout = 0; // HTTP connection timeout + var $response_timeout = 30; // HTTP response timeout + var $endpointType = ''; // soap|wsdl, empty for WSDL initialization error + var $persistentConnection = false; + var $defaultRpcParams = false; // This is no longer used + var $request = ''; // HTTP request + var $response = ''; // HTTP response + var $responseData = ''; // SOAP payload of response + var $cookies = array(); // Cookies from response or for request + var $decode_utf8 = true; // toggles whether the parser decodes element content w/ utf8_decode() + var $operations = array(); // WSDL operations, empty for WSDL initialization error + var $curl_options = array(); // User-specified cURL options + var $bindingType = ''; // WSDL operation binding type + var $use_curl = false; // whether to always try to use cURL + + /* + * fault related variables + */ + /** + * @var fault + * @access public + */ + var $fault; + /** + * @var faultcode + * @access public + */ + var $faultcode; + /** + * @var faultstring + * @access public + */ + var $faultstring; + /** + * @var faultdetail + * @access public + */ + var $faultdetail; + + /** + * constructor + * + * @param mixed $endpoint SOAP server or WSDL URL (string), or wsdl instance (object) + * @param mixed $wsdl optional, set to 'wsdl' or true if using WSDL + * @param string $proxyhost optional + * @param string $proxyport optional + * @param string $proxyusername optional + * @param string $proxypassword optional + * @param integer $timeout set the connection timeout + * @param integer $response_timeout set the response timeout + * @param string $portName optional portName in WSDL document + * @access public + */ + function __construct($endpoint, $wsdl = false, $proxyhost = false, $proxyport = false, $proxyusername = false, $proxypassword = false, $timeout = 0, $response_timeout = 30, $portName = '') + { + parent::__construct(); + $this->endpoint = $endpoint; + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + $this->timeout = $timeout; + $this->response_timeout = $response_timeout; + $this->portName = $portName; + + $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout"); + $this->appendDebug('endpoint=' . $this->varDump($endpoint)); + + // make values + if ($wsdl) { + if (is_object($endpoint) && (get_class($endpoint) == 'wsdl')) { + $this->wsdl = $endpoint; + $this->endpoint = $this->wsdl->wsdl; + $this->wsdlFile = $this->endpoint; + $this->debug('existing wsdl instance created from ' . $this->endpoint); + $this->checkWSDL(); + } else { + $this->wsdlFile = $this->endpoint; + $this->wsdl = null; + $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint); + } + $this->endpointType = 'wsdl'; + } else { + $this->debug("instantiate SOAP with endpoint at $endpoint"); + $this->endpointType = 'soap'; + } + } + + /** + * calls method, returns PHP native type + * + * @param string $operation SOAP server URL or path + * @param mixed $params An array, associative or simple, of the parameters + * for the method call, or a string that is the XML + * for the call. For rpc style, this call will + * wrap the XML in a tag named after the method, as + * well as the SOAP Envelope and Body. For document + * style, this will only wrap with the Envelope and Body. + * IMPORTANT: when using an array with document style, + * in which case there + * is really one parameter, the root of the fragment + * used in the call, which encloses what programmers + * normally think of parameters. A parameter array + * *must* include the wrapper. + * @param string $namespace optional method namespace (WSDL can override) + * @param string $soapAction optional SOAPAction value (WSDL can override) + * @param mixed $headers optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array + * @param boolean $rpcParams optional (no longer used) + * @param string $style optional (rpc|document) the style to use when serializing parameters (WSDL can override) + * @param string $use optional (encoded|literal) the use when serializing parameters (WSDL can override) + * @return mixed response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors + * @access public + */ + function call($operation, $params = array(), $namespace = 'http://tempuri.org', $soapAction = '', $headers = false, $rpcParams = null, $style = 'rpc', $use = 'encoded') + { + $this->operation = $operation; + $this->fault = false; + $this->setError(''); + $this->request = ''; + $this->response = ''; + $this->responseData = ''; + $this->faultstring = ''; + $this->faultcode = ''; + $this->opData = array(); + + $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType"); + $this->appendDebug('params=' . $this->varDump($params)); + $this->appendDebug('headers=' . $this->varDump($headers)); + if ($headers) { + $this->requestHeaders = $headers; + } + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) { + return false; + } + } + // serialize parameters + if ($this->endpointType == 'wsdl' && $opData = $this->getOperationData($operation)) { + // use WSDL for operation + $this->opData = $opData; + $this->debug("found operation"); + $this->appendDebug('opData=' . $this->varDump($opData)); + if (isset($opData['soapAction'])) { + $soapAction = $opData['soapAction']; + } + if (!$this->forceEndpoint) { + $this->endpoint = $opData['endpoint']; + } else { + $this->endpoint = $this->forceEndpoint; + } + $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace; + $style = $opData['style']; + $use = $opData['input']['use']; + // add ns to ns array + if ($namespace != '' && !isset($this->wsdl->namespaces[$namespace])) { + $nsPrefix = 'ns' . rand(1000, 9999); + $this->wsdl->namespaces[$nsPrefix] = $namespace; + } + $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace); + // serialize payload + if (is_string($params)) { + $this->debug("serializing param string for WSDL operation $operation"); + $payload = $params; + } elseif (is_array($params)) { + $this->debug("serializing param array for WSDL operation $operation"); + $payload = $this->wsdl->serializeRPCParameters($operation, 'input', $params, $this->bindingType); + } else { + $this->debug('params must be array or string'); + $this->setError('params must be array or string'); + return false; + } + $usedNamespaces = $this->wsdl->usedNamespaces; + if (isset($opData['input']['encodingStyle'])) { + $encodingStyle = $opData['input']['encodingStyle']; + } else { + $encodingStyle = ''; + } + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + if ($errstr = $this->wsdl->getError()) { + $this->debug('got wsdl error: ' . $errstr); + $this->setError('wsdl error: ' . $errstr); + return false; + } + } elseif ($this->endpointType == 'wsdl') { + // operation not in WSDL + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->setError('operation ' . $operation . ' not present in WSDL.'); + $this->debug("operation '$operation' not present in WSDL."); + return false; + } else { + // no WSDL + //$this->namespaces['ns1'] = $namespace; + $nsPrefix = 'ns' . rand(1000, 9999); + // serialize + $payload = ''; + if (is_string($params)) { + $this->debug("serializing param string for operation $operation"); + $payload = $params; + } elseif (is_array($params)) { + $this->debug("serializing param array for operation $operation"); + foreach ($params as $k => $v) { + $payload .= $this->serialize_val($v, $k, false, false, false, false, $use); + } + } else { + $this->debug('params must be array or string'); + $this->setError('params must be array or string'); + return false; + } + $usedNamespaces = array(); + if ($use == 'encoded') { + $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/'; + } else { + $encodingStyle = ''; + } + } + // wrap RPC calls with method element + if ($style == 'rpc') { + if ($use == 'literal') { + $this->debug("wrapping RPC request with literal method element"); + if ($namespace) { + // http://www.ws-i.org/Profiles/BasicProfile-1.1-2004-08-24.html R2735 says rpc/literal accessor elements should not be in a namespace + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + ""; + } else { + $payload = "<$operation>" . $payload . ""; + } + } else { + $this->debug("wrapping RPC request with encoded method element"); + if ($namespace) { + $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . + $payload . + ""; + } else { + $payload = "<$operation>" . + $payload . + ""; + } + } + } + // serialize envelope + $soapmsg = $this->serializeEnvelope($payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle); + $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle"); + $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000)); + // send + $return = $this->send($this->getHTTPBody($soapmsg), $soapAction, $this->timeout, $this->response_timeout); + if ($errstr = $this->getError()) { + $this->debug('Error: ' . $errstr); + return false; + } else { + $this->return = $return; + $this->debug('sent message successfully and got a(n) ' . gettype($return)); + $this->appendDebug('return=' . $this->varDump($return)); + + // fault? + if (is_array($return) && isset($return['faultcode'])) { + $this->debug('got fault'); + $this->setError($return['faultcode'] . ': ' . $return['faultstring']); + $this->fault = true; + foreach ($return as $k => $v) { + $this->$k = $v; + if (is_array($v)) { + $this->debug("$k = " . json_encode($v)); + } else { + $this->debug("$k = $v
"); + } + } + return $return; + } elseif ($style == 'document') { + // NOTE: if the response is defined to have multiple parts (i.e. unwrapped), + // we are only going to return the first part here...sorry about that + return $return; + } else { + // array of return values + if (is_array($return)) { + // multiple 'out' parameters, which we return wrapped up + // in the array + if (sizeof($return) > 1) { + return $return; + } + // single 'out' parameter (normally the return value) + $return = array_shift($return); + $this->debug('return shifted value: '); + $this->appendDebug($this->varDump($return)); + return $return; + // nothing returned (ie, echoVoid) + } else { + return ""; + } + } + } + } + + /** + * check WSDL passed as an instance or pulled from an endpoint + * + * @access private + */ + function checkWSDL() + { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('checkWSDL'); + // catch errors + if ($errstr = $this->wsdl->getError()) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('got wsdl error: ' . $errstr); + $this->setError('wsdl error: ' . $errstr); + } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->bindingType = 'soap'; + $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType); + } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->bindingType = 'soap12'; + $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType); + $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************'); + } else { + $this->appendDebug($this->wsdl->getDebug()); + $this->wsdl->clearDebug(); + $this->debug('getOperations returned false'); + $this->setError('no operations defined in the WSDL document!'); + } + } + + /** + * instantiate wsdl object and parse wsdl file + * + * @access public + */ + function loadWSDL() + { + $this->debug('instantiating wsdl class with doc: ' . $this->wsdlFile); + $this->wsdl = new wsdl('', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl); + $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest); + $this->wsdl->fetchWSDL($this->wsdlFile); + $this->checkWSDL(); + } + + /** + * get available data pertaining to an operation + * + * @param string $operation operation name + * @return array array of data pertaining to the operation + * @access public + */ + function getOperationData($operation) + { + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) { + return false; + } + } + if (isset($this->operations[$operation])) { + return $this->operations[$operation]; + } + $this->debug("No data for operation: $operation"); + } + + /** + * send the SOAP message + * + * Note: if the operation has multiple return values + * the return value of this method will be an array + * of those values. + * + * @param string $msg a SOAPx4 soapmsg object + * @param string $soapaction SOAPAction value + * @param integer $timeout set connection timeout in seconds + * @param integer $response_timeout set response timeout in seconds + * @return mixed native PHP types. + * @access private + */ + function send($msg, $soapaction = '', $timeout = 0, $response_timeout = 30) + { + $this->checkCookies(); + // detect transport + switch (true) { + // http(s) + case preg_match('/^http/', $this->endpoint): + $this->debug('transporting via HTTP'); + if ($this->persistentConnection == true && is_object($this->persistentConnection)) { + $http =& $this->persistentConnection; + } else { + $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl); + if ($this->persistentConnection) { + $http->usePersistentConnection(); + } + } + $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset()); + $http->setSOAPAction($soapaction); + if ($this->proxyhost && $this->proxyport) { + $http->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword); + } + if ($this->authtype != '') { + $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest); + } + if ($this->http_encoding != '') { + $http->setEncoding($this->http_encoding); + } + $this->debug('sending message, length=' . strlen($msg)); + if (preg_match('/^http:/', $this->endpoint)) { + //if(strpos($this->endpoint,'http:')){ + $this->responseData = $http->send($msg, $timeout, $response_timeout, $this->cookies); + } elseif (preg_match('/^https/', $this->endpoint)) { + //} elseif(strpos($this->endpoint,'https:')){ + //if(phpversion() == '4.3.0-dev'){ + //$response = $http->send($msg,$timeout,$response_timeout); + //$this->request = $http->outgoing_payload; + //$this->response = $http->incoming_payload; + //} else + $this->responseData = $http->sendHTTPS($msg, $timeout, $response_timeout, $this->cookies); + } else { + $this->setError('no http/s in endpoint url'); + } + $this->request = $http->outgoing_payload; + $this->response = $http->incoming_payload; + $this->appendDebug($http->getDebug()); + $this->UpdateCookies($http->incoming_cookies); + + // save transport object if using persistent connections + if ($this->persistentConnection) { + $http->clearDebug(); + if (!is_object($this->persistentConnection)) { + $this->persistentConnection = $http; + } + } + + if ($err = $http->getError()) { + $this->setError('HTTP Error: ' . $err); + return false; + } elseif ($this->getError()) { + return false; + } else { + $this->debug('got response, length=' . strlen($this->responseData) . ' type=' . $http->incoming_headers['content-type']); + return $this->parseResponse($http->incoming_headers, $this->responseData); + } + break; + default: + $this->setError('no transport found, or selected transport is not yet supported!'); + return false; + break; + } + } + + /** + * processes SOAP message returned from server + * + * @param array $headers The HTTP headers + * @param string $data unprocessed response data from server + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseResponse($headers, $data) + { + $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:'); + $this->appendDebug($this->varDump($headers)); + if (!isset($headers['content-type'])) { + $this->setError('Response not of type '.$this->contentType.' (no content-type header)'); + return false; + } + if (!strstr($headers['content-type'], $this->contentType)) { + $this->setError('Response not of type '.$this->contentType.': ' . $headers['content-type']); + return false; + } + if (strpos($headers['content-type'], '=')) { + $enc = str_replace('"', '', substr(strstr($headers["content-type"], '='), 1)); + $this->debug('Got response encoding: ' . $enc); + if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) { + $this->xml_encoding = strtoupper($enc); + } else { + $this->xml_encoding = 'US-ASCII'; + } + } else { + // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1 + $this->xml_encoding = 'ISO-8859-1'; + } + $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser'); + $parser = new nusoap_parser($data, $this->xml_encoding, $this->operations, $this->decode_utf8); + // add parser debug data to our debug + $this->appendDebug($parser->getDebug()); + // if parse errors + if ($errstr = $parser->getError()) { + $this->setError($errstr); + // destroy the parser object + unset($parser); + return false; + } else { + // get SOAP headers + $this->responseHeaders = $parser->getHeaders(); + // get SOAP headers + $this->responseHeader = $parser->get_soapheader(); + // get decoded message + $return = $parser->get_soapbody(); + // add document for doclit support + $this->document = $parser->document; + // destroy the parser object + unset($parser); + // return decode message + return $return; + } + } + + /** + * sets user-specified cURL options + * + * @param mixed $option The cURL option (always integer?) + * @param mixed $value The cURL option value + * @access public + */ + function setCurlOption($option, $value) + { + $this->debug("setCurlOption option=$option, value="); + $this->appendDebug($this->varDump($value)); + $this->curl_options[$option] = $value; + } + + /** + * sets the SOAP endpoint, which can override WSDL + * + * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override + * @access public + */ + function setEndpoint($endpoint) + { + $this->debug("setEndpoint(\"$endpoint\")"); + $this->forceEndpoint = $endpoint; + } + + /** + * set the SOAP headers + * + * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers + * @access public + */ + function setHeaders($headers) + { + $this->debug("setHeaders headers="); + $this->appendDebug($this->varDump($headers)); + $this->requestHeaders = $headers; + } + + /** + * get the SOAP response headers (namespace resolution incomplete) + * + * @return string + * @access public + */ + function getHeaders() + { + return $this->responseHeaders; + } + + /** + * get the SOAP response Header (parsed) + * + * @return mixed + * @access public + */ + function getHeader() + { + return $this->responseHeader; + } + + /** + * set proxy info here + * + * @param string $proxyhost + * @param string $proxyport + * @param string $proxyusername + * @param string $proxypassword + * @access public + */ + function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '') + { + $this->proxyhost = $proxyhost; + $this->proxyport = $proxyport; + $this->proxyusername = $proxyusername; + $this->proxypassword = $proxypassword; + } + + /** + * if authenticating, set user credentials here + * + * @param string $username + * @param string $password + * @param string $authtype (basic|digest|certificate|ntlm) + * @param array $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs) + * @access public + */ + function setCredentials($username, $password, $authtype = 'basic', $certRequest = array()) + { + $this->debug("setCredentials username=$username authtype=$authtype certRequest="); + $this->appendDebug($this->varDump($certRequest)); + $this->username = $username; + $this->password = $password; + $this->authtype = $authtype; + $this->certRequest = $certRequest; + } + + /** + * use HTTP encoding + * + * @param string $enc HTTP encoding + * @access public + */ + function setHTTPEncoding($enc = 'gzip, deflate') + { + $this->debug("setHTTPEncoding(\"$enc\")"); + $this->http_encoding = $enc; + } + + /** + * Set whether to try to use cURL connections if possible + * + * @param boolean $use Whether to try to use cURL + * @access public + */ + function setUseCURL($use) + { + $this->debug("setUseCURL($use)"); + $this->use_curl = $use; + } + + /** + * use HTTP persistent connections if possible + * + * @access public + */ + function useHTTPPersistentConnection() + { + $this->debug("useHTTPPersistentConnection"); + $this->persistentConnection = true; + } + + /** + * gets the default RPC parameter setting. + * If true, default is that call params are like RPC even for document style. + * Each call() can override this value. + * + * This is no longer used. + * + * @return boolean + * @access public + * @deprecated + */ + function getDefaultRpcParams() + { + return $this->defaultRpcParams; + } + + /** + * sets the default RPC parameter setting. + * If true, default is that call params are like RPC even for document style + * Each call() can override this value. + * + * This is no longer used. + * + * @param boolean $rpcParams + * @access public + * @deprecated + */ + function setDefaultRpcParams($rpcParams) + { + $this->defaultRpcParams = $rpcParams; + } + + /** + * dynamically creates an instance of a proxy class, + * allowing user to directly call methods from wsdl + * + * @return object soap_proxy object + * @access public + */ + function getProxy() + { + $r = rand(); + $evalStr = $this->_getProxyClassCode($r); + //$this->debug("proxy class: $evalStr"); + if ($this->getError()) { + $this->debug("Error from _getProxyClassCode, so return null"); + return null; + } + // eval the class + eval($evalStr); + // instantiate proxy object + eval("\$proxy = new nusoap_proxy_$r('');"); + // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice + $proxy->endpointType = 'wsdl'; + $proxy->wsdlFile = $this->wsdlFile; + $proxy->wsdl = $this->wsdl; + $proxy->operations = $this->operations; + $proxy->defaultRpcParams = $this->defaultRpcParams; + // transfer other state + $proxy->soap_defencoding = $this->soap_defencoding; + $proxy->username = $this->username; + $proxy->password = $this->password; + $proxy->authtype = $this->authtype; + $proxy->certRequest = $this->certRequest; + $proxy->requestHeaders = $this->requestHeaders; + $proxy->endpoint = $this->endpoint; + $proxy->forceEndpoint = $this->forceEndpoint; + $proxy->proxyhost = $this->proxyhost; + $proxy->proxyport = $this->proxyport; + $proxy->proxyusername = $this->proxyusername; + $proxy->proxypassword = $this->proxypassword; + $proxy->http_encoding = $this->http_encoding; + $proxy->timeout = $this->timeout; + $proxy->response_timeout = $this->response_timeout; + $proxy->persistentConnection = &$this->persistentConnection; + $proxy->decode_utf8 = $this->decode_utf8; + $proxy->curl_options = $this->curl_options; + $proxy->bindingType = $this->bindingType; + $proxy->use_curl = $this->use_curl; + return $proxy; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access private + */ + function _getProxyClassCode($r) + { + $this->debug("in getProxy endpointType=$this->endpointType"); + $this->appendDebug("wsdl=" . $this->varDump($this->wsdl)); + if ($this->endpointType != 'wsdl') { + $evalStr = 'A proxy can only be created for a WSDL client'; + $this->setError($evalStr); + $evalStr = "echo \"$evalStr\";"; + return $evalStr; + } + if ($this->endpointType == 'wsdl' && is_null($this->wsdl)) { + $this->loadWSDL(); + if ($this->getError()) { + return "echo \"" . $this->getError() . "\";"; + } + } + $evalStr = ''; + foreach ($this->operations as $operation => $opData) { + if ($operation != '') { + // create param string and param comment string + if (sizeof($opData['input']['parts']) > 0) { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = ''; + foreach ($opData['input']['parts'] as $name => $type) { + $paramStr .= "\$$name, "; + $paramArrayStr .= "'$name' => \$$name, "; + $paramCommentStr .= "$type \$$name, "; + } + $paramStr = substr($paramStr, 0, strlen($paramStr) - 2); + $paramArrayStr = substr($paramArrayStr, 0, strlen($paramArrayStr) - 2); + $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr) - 2); + } else { + $paramStr = ''; + $paramArrayStr = ''; + $paramCommentStr = 'void'; + } + $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace']; + $evalStr .= "// $paramCommentStr + function " . str_replace('.', '__', $operation) . "($paramStr) { + \$params = array($paramArrayStr); + return \$this->call('$operation', \$params, '" . $opData['namespace'] . "', '" . (isset($opData['soapAction']) ? $opData['soapAction'] : '') . "'); + } + "; + unset($paramStr); + unset($paramCommentStr); + } + } + $evalStr = 'class nusoap_proxy_' . $r . ' extends nusoap_client { + ' . $evalStr . ' +}'; + return $evalStr; + } + + /** + * dynamically creates proxy class code + * + * @return string PHP/NuSOAP code for the proxy class + * @access public + */ + function getProxyClassCode() + { + $r = rand(); + return $this->_getProxyClassCode($r); + } + + /** + * gets the HTTP body for the current request. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) + { + return $soapmsg; + } + + /** + * gets the HTTP content type for the current request. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current request. + * @access private + */ + function getHTTPContentType() + { + return $this->contentType; + } + + /** + * allows you to change the HTTP ContentType of the request. + * + * @param string $contentTypeNew + * @return void + */ + function setHTTPContentType($contentTypeNew = "text/xml"){ + $this->contentType = $contentTypeNew; + } + + /** + * gets the HTTP content type charset for the current request. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current request. + * @access private + */ + function getHTTPContentTypeCharset() + { + return $this->soap_defencoding; + } + + /* + * whether or not parser should decode utf8 element content + * + * @return always returns true + * @access public + */ + function decodeUTF8($bool) + { + $this->decode_utf8 = $bool; + return true; + } + + /** + * adds a new Cookie into $this->cookies array + * + * @param string $name Cookie Name + * @param string $value Cookie Value + * @return boolean if cookie-set was successful returns true, else false + * @access public + */ + function setCookie($name, $value) + { + if (strlen($name) == 0) { + return false; + } + $this->cookies[] = array('name' => $name, 'value' => $value); + return true; + } + + /** + * gets all Cookies + * + * @return array with all internal cookies + * @access public + */ + function getCookies() + { + return $this->cookies; + } + + /** + * checks all Cookies and delete those which are expired + * + * @return boolean always return true + * @access private + */ + function checkCookies() + { + if (sizeof($this->cookies) == 0) { + return true; + } + $this->debug('checkCookie: check ' . sizeof($this->cookies) . ' cookies'); + $curr_cookies = $this->cookies; + $this->cookies = array(); + foreach ($curr_cookies as $cookie) { + if (!is_array($cookie)) { + $this->debug('Remove cookie that is not an array'); + continue; + } + if ((isset($cookie['expires'])) && (!empty($cookie['expires']))) { + if (strtotime($cookie['expires']) > time()) { + $this->cookies[] = $cookie; + } else { + $this->debug('Remove expired cookie ' . $cookie['name']); + } + } else { + $this->cookies[] = $cookie; + } + } + $this->debug('checkCookie: ' . sizeof($this->cookies) . ' cookies left in array'); + return true; + } + + /** + * updates the current cookies with a new set + * + * @param array $cookies new cookies with which to update current ones + * @return boolean always return true + * @access private + */ + function UpdateCookies($cookies) + { + if (sizeof($this->cookies) == 0) { + // no existing cookies: take whatever is new + if (sizeof($cookies) > 0) { + $this->debug('Setting new cookie(s)'); + $this->cookies = $cookies; + } + return true; + } + if (sizeof($cookies) == 0) { + // no new cookies: keep what we've got + return true; + } + // merge + foreach ($cookies as $newCookie) { + if (!is_array($newCookie)) { + continue; + } + if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) { + continue; + } + $newName = $newCookie['name']; + + $found = false; + for ($i = 0; $i < count($this->cookies); $i++) { + $cookie = $this->cookies[$i]; + if (!is_array($cookie)) { + continue; + } + if (!isset($cookie['name'])) { + continue; + } + if ($newName != $cookie['name']) { + continue; + } + $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN'; + $domain = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN'; + if ($newDomain != $domain) { + continue; + } + $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH'; + $path = isset($cookie['path']) ? $cookie['path'] : 'NOPATH'; + if ($newPath != $path) { + continue; + } + $this->cookies[$i] = $newCookie; + $found = true; + $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']); + break; + } + if (!$found) { + $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']); + $this->cookies[] = $newCookie; + } + } + return true; + } +} + + +if (!extension_loaded('soap')) { + /** + * For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded. + */ + class soapclient extends nusoap_client + { + } +} + +/** + * caches instances of the wsdl class + * + * @author Scott Nichol + * @author Ingo Fischer + * @version $Id: class.wsdlcache.php,v 1.7 2007/04/17 16:34:03 snichol Exp $ + * @access public + */ +class nusoap_wsdlcache { + /** + * @var resource + * @access private + */ + var $fplock; + /** + * @var integer + * @access private + */ + var $cache_lifetime; + /** + * @var string + * @access private + */ + var $cache_dir; + /** + * @var string + * @access public + */ + var $debug_str = ''; + + /** + * constructor + * + * @param string $cache_dir directory for cache-files + * @param integer $cache_lifetime lifetime for caching-files in seconds or 0 for unlimited + * @access public + */ + function __construct($cache_dir='.', $cache_lifetime=0) { + $this->fplock = array(); + $this->cache_dir = $cache_dir != '' ? $cache_dir : '.'; + $this->cache_lifetime = $cache_lifetime; + } + + /** + * creates the filename used to cache a wsdl instance + * + * @param string $wsdl The URL of the wsdl instance + * @return string The filename used to cache the instance + * @access private + */ + function createFilename($wsdl) { + return $this->cache_dir.'/wsdlcache-' . md5($wsdl); + } + + /** + * adds debug data to the class level debug string + * + * @param string $string debug data + * @access private + */ + function debug($string){ + $this->debug_str .= get_class($this).": $string\n"; + } + + /** + * gets a wsdl instance from the cache + * + * @param string $wsdl The URL of the wsdl instance + * @return object wsdl The cached wsdl instance, null if the instance is not in the cache + * @access public + */ + function get($wsdl) { + $filename = $this->createFilename($wsdl); + if ($this->obtainMutex($filename, "r")) { + // check for expired WSDL that must be removed from the cache + if ($this->cache_lifetime > 0) { + if (file_exists($filename) && (time() - filemtime($filename) > $this->cache_lifetime)) { + unlink($filename); + $this->debug("Expired $wsdl ($filename) from cache"); + $this->releaseMutex($filename); + return null; + } + } + // see what there is to return + if (!file_exists($filename)) { + $this->debug("$wsdl ($filename) not in cache (1)"); + $this->releaseMutex($filename); + return null; + } + $fp = @fopen($filename, "r"); + if ($fp) { + $s = implode("", @file($filename)); + fclose($fp); + $this->debug("Got $wsdl ($filename) from cache"); + } else { + $s = null; + $this->debug("$wsdl ($filename) not in cache (2)"); + } + $this->releaseMutex($filename); + return (!is_null($s)) ? unserialize($s) : null; + } else { + $this->debug("Unable to obtain mutex for $filename in get"); + } + return null; + } + + /** + * obtains the local mutex + * + * @param string $filename The Filename of the Cache to lock + * @param string $mode The open-mode ("r" or "w") or the file - affects lock-mode + * @return boolean Lock successfully obtained ?! + * @access private + */ + function obtainMutex($filename, $mode) { + if (isset($this->fplock[md5($filename)])) { + $this->debug("Lock for $filename already exists"); + return false; + } + $this->fplock[md5($filename)] = fopen($filename.".lock", "w"); + if ($mode == "r") { + return flock($this->fplock[md5($filename)], LOCK_SH); + } else { + return flock($this->fplock[md5($filename)], LOCK_EX); + } + } + + /** + * adds a wsdl instance to the cache + * + * @param object wsdl $wsdl_instance The wsdl instance to add + * @return boolean WSDL successfully cached + * @access public + */ + function put($wsdl_instance) { + $filename = $this->createFilename($wsdl_instance->wsdl); + $s = serialize($wsdl_instance); + if ($this->obtainMutex($filename, "w")) { + $fp = fopen($filename, "w"); + if (! $fp) { + $this->debug("Cannot write $wsdl_instance->wsdl ($filename) in cache"); + $this->releaseMutex($filename); + return false; + } + fputs($fp, $s); + fclose($fp); + $this->debug("Put $wsdl_instance->wsdl ($filename) in cache"); + $this->releaseMutex($filename); + return true; + } else { + $this->debug("Unable to obtain mutex for $filename in put"); + } + return false; + } + + /** + * releases the local mutex + * + * @param string $filename The Filename of the Cache to lock + * @return boolean Lock successfully released + * @access private + */ + function releaseMutex($filename) { + $ret = flock($this->fplock[md5($filename)], LOCK_UN); + fclose($this->fplock[md5($filename)]); + unset($this->fplock[md5($filename)]); + if (! $ret) { + $this->debug("Not able to release lock for $filename"); + } + return $ret; + } + + /** + * removes a wsdl instance from the cache + * + * @param string $wsdl The URL of the wsdl instance + * @return boolean Whether there was an instance to remove + * @access public + */ + function remove($wsdl) { + $filename = $this->createFilename($wsdl); + if (!file_exists($filename)) { + $this->debug("$wsdl ($filename) not in cache to be removed"); + return false; + } + // ignore errors obtaining mutex + $this->obtainMutex($filename, "w"); + $ret = unlink($filename); + $this->debug("Removed ($ret) $wsdl ($filename) from cache"); + $this->releaseMutex($filename); + return $ret; + } +} + +/** + * For backward compatibility + */ +class wsdlcache extends nusoap_wsdlcache { +} diff --git a/include/nusoap/nusoapmime.php b/include/nusoap/nusoapmime.php new file mode 100644 index 0000000..cdb1afc --- /dev/null +++ b/include/nusoap/nusoapmime.php @@ -0,0 +1,501 @@ + +* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list +* @version $Id: nusoapmime.php,v 1.13 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class nusoap_client_mime extends nusoap_client { + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $requestAttachments = array(); + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $responseAttachments; + /** + * @var string + * @access private + */ + var $mimeContentType; + + /** + * adds a MIME attachment to the current request. + * + * If the $data parameter contains an empty string, this method will read + * the contents of the file named by the $filename parameter. + * + * If the $cid parameter is false, this method will generate the cid. + * + * @param string $data The data of the attachment + * @param string $filename The filename of the attachment (default is empty string) + * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) + * @param string $cid The content-id (cid) of the attachment (default is false) + * @return string The content-id (cid) of the attachment + * @access public + */ + function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { + if (! $cid) { + $cid = md5(uniqid(time())); + } + + $info['data'] = $data; + $info['filename'] = $filename; + $info['contenttype'] = $contenttype; + $info['cid'] = $cid; + + $this->requestAttachments[] = $info; + + return $cid; + } + + /** + * clears the MIME attachments for the current request. + * + * @access public + */ + function clearAttachments() { + $this->requestAttachments = array(); + } + + /** + * gets the MIME attachments from the current response. + * + * Each array element in the return is an associative array with keys + * data, filename, contenttype, cid. These keys correspond to the parameters + * for addAttachment. + * + * @return array The attachments. + * @access public + */ + function getAttachments() { + return $this->responseAttachments; + } + + /** + * gets the HTTP body for the current request. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + if (count($this->requestAttachments) > 0) { + $params['content_type'] = 'multipart/related; type="text/xml"'; + $mimeMessage = new Mail_mimePart('', $params); + unset($params); + + $params['content_type'] = 'text/xml'; + $params['encoding'] = '8bit'; + $params['charset'] = $this->soap_defencoding; + $mimeMessage->addSubpart($soapmsg, $params); + + foreach ($this->requestAttachments as $att) { + unset($params); + + $params['content_type'] = $att['contenttype']; + $params['encoding'] = 'base64'; + $params['disposition'] = 'attachment'; + $params['dfilename'] = $att['filename']; + $params['cid'] = $att['cid']; + + if ($att['data'] == '' && $att['filename'] <> '') { + if ($fd = fopen($att['filename'], 'rb')) { + $data = fread($fd, filesize($att['filename'])); + fclose($fd); + } else { + $data = ''; + } + $mimeMessage->addSubpart($data, $params); + } else { + $mimeMessage->addSubpart($att['data'], $params); + } + } + + $output = $mimeMessage->encode(); + $mimeHeaders = $output['headers']; + + foreach ($mimeHeaders as $k => $v) { + $this->debug("MIME header $k: $v"); + if (strtolower($k) == 'content-type') { + // PHP header() seems to strip leading whitespace starting + // the second line, so force everything to one line + $this->mimeContentType = str_replace("\r\n", " ", $v); + } + } + + return $output['body']; + } + + return parent::getHTTPBody($soapmsg); + } + + /** + * gets the HTTP content type for the current request. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current request. + * @access private + */ + function getHTTPContentType() { + if (count($this->requestAttachments) > 0) { + return $this->mimeContentType; + } + return parent::getHTTPContentType(); + } + + /** + * gets the HTTP content type charset for the current request. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current request. + * @access private + */ + function getHTTPContentTypeCharset() { + if (count($this->requestAttachments) > 0) { + return false; + } + return parent::getHTTPContentTypeCharset(); + } + + /** + * processes SOAP message returned from server + * + * @param array $headers The HTTP headers + * @param string $data unprocessed response data from server + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseResponse($headers, $data) { + $this->debug('Entering parseResponse() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); + $this->responseAttachments = array(); + if (strstr($headers['content-type'], 'multipart/related')) { + $this->debug('Decode multipart/related'); + $input = ''; + foreach ($headers as $k => $v) { + $input .= "$k: $v\r\n"; + } + $params['input'] = $input . "\r\n" . $data; + $params['include_bodies'] = true; + $params['decode_bodies'] = true; + $params['decode_headers'] = true; + + $structure = Mail_mimeDecode::decode($params); + + foreach ($structure->parts as $part) { + if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { + $this->debug('Have root part of type ' . $part->headers['content-type']); + $root = $part->body; + $return = parent::parseResponse($part->headers, $part->body); + } else { + $this->debug('Have an attachment of type ' . $part->headers['content-type']); + $info['data'] = $part->body; + $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; + $info['contenttype'] = $part->headers['content-type']; + $info['cid'] = $part->headers['content-id']; + $this->responseAttachments[] = $info; + } + } + + if (isset($return)) { + $this->responseData = $root; + return $return; + } + + $this->setError('No root part found in multipart/related content'); + return ''; + } + $this->debug('Not multipart/related'); + return parent::parseResponse($headers, $data); + } +} + +/* + * For backwards compatiblity, define soapclientmime unless the PHP SOAP extension is loaded. + */ +if (!extension_loaded('soap')) { + class soapclientmime extends nusoap_client_mime { + } +} + +/** +* nusoap_server_mime server supporting MIME attachments defined at +* http://www.w3.org/TR/SOAP-attachments. It depends on the PEAR Mail_MIME library. +* +* @author Scott Nichol +* @author Thanks to Guillaume and Henning Reich for posting great attachment code to the mail list +* @version $Id: nusoapmime.php,v 1.13 2010/04/26 20:15:08 snichol Exp $ +* @access public +*/ +class nusoap_server_mime extends nusoap_server { + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $requestAttachments = array(); + /** + * @var array Each array element in the return is an associative array with keys + * data, filename, contenttype, cid + * @access private + */ + var $responseAttachments; + /** + * @var string + * @access private + */ + var $mimeContentType; + + /** + * adds a MIME attachment to the current response. + * + * If the $data parameter contains an empty string, this method will read + * the contents of the file named by the $filename parameter. + * + * If the $cid parameter is false, this method will generate the cid. + * + * @param string $data The data of the attachment + * @param string $filename The filename of the attachment (default is empty string) + * @param string $contenttype The MIME Content-Type of the attachment (default is application/octet-stream) + * @param string $cid The content-id (cid) of the attachment (default is false) + * @return string The content-id (cid) of the attachment + * @access public + */ + function addAttachment($data, $filename = '', $contenttype = 'application/octet-stream', $cid = false) { + if (! $cid) { + $cid = md5(uniqid(time())); + } + + $info['data'] = $data; + $info['filename'] = $filename; + $info['contenttype'] = $contenttype; + $info['cid'] = $cid; + + $this->responseAttachments[] = $info; + + return $cid; + } + + /** + * clears the MIME attachments for the current response. + * + * @access public + */ + function clearAttachments() { + $this->responseAttachments = array(); + } + + /** + * gets the MIME attachments from the current request. + * + * Each array element in the return is an associative array with keys + * data, filename, contenttype, cid. These keys correspond to the parameters + * for addAttachment. + * + * @return array The attachments. + * @access public + */ + function getAttachments() { + return $this->requestAttachments; + } + + /** + * gets the HTTP body for the current response. + * + * @param string $soapmsg The SOAP payload + * @return string The HTTP body, which includes the SOAP payload + * @access private + */ + function getHTTPBody($soapmsg) { + if (count($this->responseAttachments) > 0) { + $params['content_type'] = 'multipart/related; type="text/xml"'; + $mimeMessage = new Mail_mimePart('', $params); + unset($params); + + $params['content_type'] = 'text/xml'; + $params['encoding'] = '8bit'; + $params['charset'] = $this->soap_defencoding; + $mimeMessage->addSubpart($soapmsg, $params); + + foreach ($this->responseAttachments as $att) { + unset($params); + + $params['content_type'] = $att['contenttype']; + $params['encoding'] = 'base64'; + $params['disposition'] = 'attachment'; + $params['dfilename'] = $att['filename']; + $params['cid'] = $att['cid']; + + if ($att['data'] == '' && $att['filename'] <> '') { + if ($fd = fopen($att['filename'], 'rb')) { + $data = fread($fd, filesize($att['filename'])); + fclose($fd); + } else { + $data = ''; + } + $mimeMessage->addSubpart($data, $params); + } else { + $mimeMessage->addSubpart($att['data'], $params); + } + } + + $output = $mimeMessage->encode(); + $mimeHeaders = $output['headers']; + + foreach ($mimeHeaders as $k => $v) { + $this->debug("MIME header $k: $v"); + if (strtolower($k) == 'content-type') { + // PHP header() seems to strip leading whitespace starting + // the second line, so force everything to one line + $this->mimeContentType = str_replace("\r\n", " ", $v); + } + } + + return $output['body']; + } + + return parent::getHTTPBody($soapmsg); + } + + /** + * gets the HTTP content type for the current response. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type for the current response. + * @access private + */ + function getHTTPContentType() { + if (count($this->responseAttachments) > 0) { + return $this->mimeContentType; + } + return parent::getHTTPContentType(); + } + + /** + * gets the HTTP content type charset for the current response. + * returns false for non-text content types. + * + * Note: getHTTPBody must be called before this. + * + * @return string the HTTP content type charset for the current response. + * @access private + */ + function getHTTPContentTypeCharset() { + if (count($this->responseAttachments) > 0) { + return false; + } + return parent::getHTTPContentTypeCharset(); + } + + /** + * processes SOAP message received from client + * + * @param array $headers The HTTP headers + * @param string $data unprocessed request data from client + * @return mixed value of the message, decoded into a PHP type + * @access private + */ + function parseRequest($headers, $data) { + $this->debug('Entering parseRequest() for payload of length ' . strlen($data) . ' and type of ' . $headers['content-type']); + $this->requestAttachments = array(); + if (strstr($headers['content-type'], 'multipart/related')) { + $this->debug('Decode multipart/related'); + $input = ''; + foreach ($headers as $k => $v) { + $input .= "$k: $v\r\n"; + } + $params['input'] = $input . "\r\n" . $data; + $params['include_bodies'] = true; + $params['decode_bodies'] = true; + $params['decode_headers'] = true; + + $structure = Mail_mimeDecode::decode($params); + + foreach ($structure->parts as $part) { + if (!isset($part->disposition) && (strstr($part->headers['content-type'], 'text/xml'))) { + $this->debug('Have root part of type ' . $part->headers['content-type']); + $return = parent::parseRequest($part->headers, $part->body); + } else { + $this->debug('Have an attachment of type ' . $part->headers['content-type']); + $info['data'] = $part->body; + $info['filename'] = isset($part->d_parameters['filename']) ? $part->d_parameters['filename'] : ''; + $info['contenttype'] = $part->headers['content-type']; + $info['cid'] = $part->headers['content-id']; + $this->requestAttachments[] = $info; + } + } + + if (isset($return)) { + return $return; + } + + $this->setError('No root part found in multipart/related content'); + return; + } + $this->debug('Not multipart/related'); + return parent::parseRequest($headers, $data); + } +} + +/* + * For backwards compatiblity + */ +class nusoapservermime extends nusoap_server_mime { +} + +?> diff --git a/include/phpmailer/PHPMailerAutoload.php b/include/phpmailer/PHPMailerAutoload.php new file mode 100644 index 0000000..60f9ad7 --- /dev/null +++ b/include/phpmailer/PHPMailerAutoload.php @@ -0,0 +1,50 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2014 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. + */ + +/** + * PHPMailer SPL autoloader. + * @param string $classname The name of the class to load + */ +function PHPMailerAutoload($classname) +{ + //Can't use __DIR__ as it's only in PHP 5.3+ + $filename = dirname(__FILE__).DIRECTORY_SEPARATOR.'class.'.strtolower($classname).'.php'; + if (is_readable($filename)) { + require $filename; + } +} + +if (version_compare(PHP_VERSION, '5.1.2', '>=')) { + //SPL autoloading was introduced in PHP 5.1.2 + if (version_compare(PHP_VERSION, '5.3.0', '>=')) { + spl_autoload_register('PHPMailerAutoload', true, true); + } else { + spl_autoload_register('PHPMailerAutoload'); + } +} else { + /** + * Fall back to traditional autoload for old PHP versions + * @param string $classname The name of the class to load + */ + spl_autoload_register($classname); + /*function __autoload($classname) + { + PHPMailerAutoload($classname); + }*/ +} diff --git a/include/phpmailer/class.phpmailer.php b/include/phpmailer/class.phpmailer.php new file mode 100644 index 0000000..3cda98d --- /dev/null +++ b/include/phpmailer/class.phpmailer.php @@ -0,0 +1,3884 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2012 - 2014 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. + */ + +/** + * PHPMailer - PHP email creation and transport class. + * @package PHPMailer + * @author Marcus Bointon (Synchro/coolbru) + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + */ +class PHPMailer +{ + /** + * The PHPMailer Version number. + * @var string + */ + public $Version = '5.2.14'; + + /** + * Email priority. + * Options: null (default), 1 = High, 3 = Normal, 5 = low. + * When null, the header is not set at all. + * @var integer + */ + public $Priority = null; + + /** + * The character set of the message. + * @var string + */ + public $CharSet = 'iso-8859-1'; + + /** + * The MIME Content-type of the message. + * @var string + */ + public $ContentType = 'text/plain'; + + /** + * The message encoding. + * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable". + * @var string + */ + public $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 Sender email (Return-Path) of the message. + * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. + * @var string + */ + public $Sender = ''; + + /** + * The Return-Path of the message. + * If empty, it will be set to either From or Sender. + * @var string + * @deprecated Email senders should never set a return-path header; + * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything. + * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference + */ + public $ReturnPath = ''; + + /** + * 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 events, use the bundled extras/EasyPeasyICS.php class or iCalcreator + * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/ + * @link http://kigkonsult.se/iCalcreator/ + * @var string + */ + public $Ical = ''; + + /** + * The complete compiled MIME message body. + * @access protected + * @var string + */ + protected $MIMEBody = ''; + + /** + * The complete compiled MIME message headers. + * @var string + * @access protected + */ + protected $MIMEHeader = ''; + + /** + * Extra headers that createHeader() doesn't fold in. + * @var string + * @access protected + */ + 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. + * @var integer + */ + 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 boolean + */ + public $UseSendmailOptions = true; + + /** + * Path to PHPMailer plugins. + * Useful if the SMTP class is not in the PHP include path. + * @var string + * @deprecated Should not be needed now there is an autoloader. + */ + public $PluginDir = ''; + + /** + * 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'. + * @var string + */ + public $Hostname = ''; + + /** + * An ID to be used in the Message-ID header. + * If empty, a unique id will be generated. + * @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 integer + * @TODO Why is this needed when the SMTP class takes care of it? + */ + public $Port = 25; + + /** + * The SMTP HELO of the message. + * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find + * one with the same method described above for $Hostname. + * @var string + * @see PHPMailer::$Hostname + */ + public $Helo = ''; + + /** + * What kind of encryption to use on the SMTP connection. + * Options: '', 'ssl' or 'tls' + * @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 boolean + */ + public $SMTPAutoTLS = true; + + /** + * Whether to use SMTP authentication. + * Uses the Username and Password properties. + * @var boolean + * @see PHPMailer::$Username + * @see PHPMailer::$Password + */ + public $SMTPAuth = false; + + /** + * Options array passed to stream_context_create when connecting via SMTP. + * @var array + */ + public $SMTPOptions = array(); + + /** + * SMTP username. + * @var string + */ + public $Username = ''; + + /** + * SMTP password. + * @var string + */ + public $Password = ''; + + /** + * SMTP auth type. + * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5 + * @var string + */ + public $AuthType = ''; + + /** + * SMTP realm. + * Used for NTLM auth + * @var string + */ + public $Realm = ''; + + /** + * SMTP workstation. + * Used for NTLM auth + * @var string + */ + public $Workstation = ''; + + /** + * The SMTP server timeout in seconds. + * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 + * @var integer + */ + public $Timeout = 300; + + /** + * SMTP class debug output mode. + * Debug output level. + * Options: + * * `0` No output + * * `1` Commands + * * `2` Data and commands + * * `3` As 2 plus connection status + * * `4` Low-level data output + * @var integer + * @see SMTP::$do_debug + */ + 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 + * + * Alternatively, you can provide a callable expecting two params: a message string and the debug level: + * + * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * + * @var string|callable + * @see SMTP::$Debugoutput + */ + 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 boolean + */ + public $SMTPKeepAlive = false; + + /** + * Whether to split multiple to addresses into multiple messages + * or send them all in one message. + * @var boolean + */ + public $SingleTo = false; + + /** + * Storage for addresses when SingleTo is enabled. + * @var array + * @TODO This should really not be public + */ + public $SingleToArray = array(); + + /** + * Whether to generate VERP addresses on send. + * Only applicable when sending via SMTP. + * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path + * @link http://www.postfix.org/VERP_README.html Postfix VERP info + * @var boolean + */ + public $do_verp = false; + + /** + * Whether to allow sending messages with an empty body. + * @var boolean + */ + public $AllowEmpty = false; + + /** + * The default line ending. + * @note The default remains "\n". We force CRLF where we know + * it must be used via self::CRLF. + * @var string + */ + public $LE = "\n"; + + /** + * 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 private key file path. + * @var string + */ + public $DKIM_private = ''; + + /** + * 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: + * boolean $result result of the send action + * string $to email address of the recipient + * string $cc cc email addresses + * string $bcc bcc email addresses + * string $subject the subject + * string $body the email body + * string $from email address of sender + * @var string + */ + public $action_function = ''; + + /** + * What to put in the X-Mailer header. + * Options: An empty string for PHPMailer default, whitespace for none, or a string to use + * @var string + */ + public $XMailer = ''; + + /** + * An instance of the SMTP sender class. + * @var SMTP + * @access protected + */ + protected $smtp = null; + + /** + * The array of 'to' names and addresses. + * @var array + * @access protected + */ + protected $to = array(); + + /** + * The array of 'cc' names and addresses. + * @var array + * @access protected + */ + protected $cc = array(); + + /** + * The array of 'bcc' names and addresses. + * @var array + * @access protected + */ + protected $bcc = array(); + + /** + * The array of reply-to names and addresses. + * @var array + * @access protected + */ + protected $ReplyTo = array(); + + /** + * An array of all kinds of addresses. + * Includes all of $to, $cc, $bcc + * @var array + * @access protected + * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc + */ + protected $all_recipients = array(); + + /** + * 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. + * @var array + * @access protected + * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc + * @see PHPMailer::$all_recipients + */ + protected $RecipientsQueue = array(); + + /** + * 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. + * @var array + * @access protected + * @see PHPMailer::$ReplyTo + */ + protected $ReplyToQueue = array(); + + /** + * The array of attachments. + * @var array + * @access protected + */ + protected $attachment = array(); + + /** + * The array of custom headers. + * @var array + * @access protected + */ + protected $CustomHeader = array(); + + /** + * The most recent Message-ID (including angular brackets). + * @var string + * @access protected + */ + protected $lastMessageID = ''; + + /** + * The message's MIME type. + * @var string + * @access protected + */ + protected $message_type = ''; + + /** + * The array of MIME boundary strings. + * @var array + * @access protected + */ + protected $boundary = array(); + + /** + * The array of available languages. + * @var array + * @access protected + */ + protected $language = array(); + + /** + * The number of errors encountered. + * @var integer + * @access protected + */ + protected $error_count = 0; + + /** + * The S/MIME certificate file path. + * @var string + * @access protected + */ + protected $sign_cert_file = ''; + + /** + * The S/MIME key file path. + * @var string + * @access protected + */ + protected $sign_key_file = ''; + + /** + * The optional S/MIME extra certificates ("CA Chain") file path. + * @var string + * @access protected + */ + protected $sign_extracerts_file = ''; + + /** + * The S/MIME password for the key. + * Used only if the key is encrypted. + * @var string + * @access protected + */ + protected $sign_key_pass = ''; + + /** + * Whether to throw exceptions for errors. + * @var boolean + * @access protected + */ + protected $exceptions = false; + + /** + * Unique ID used for message ID and boundaries. + * @var string + * @access protected + */ + protected $uniqueid = ''; + + /** + * Error severity: message only, continue processing. + */ + const STOP_MESSAGE = 0; + + /** + * Error severity: message, likely ok to continue processing. + */ + const STOP_CONTINUE = 1; + + /** + * Error severity: message, plus full stop, critical error reached. + */ + const STOP_CRITICAL = 2; + + /** + * SMTP RFC standard line ending. + */ + const CRLF = "\r\n"; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1 + * @var integer + */ + const MAX_LINE_LENGTH = 998; + + /** + * Constructor. + * @param boolean $exceptions Should we throw external exceptions? + */ + public function __construct($exceptions = false) + { + $this->exceptions = (boolean)$exceptions; + } + + /** + * Destructor. + */ + public function __destruct() + { + //Close any open SMTP connection nicely + if ($this->Mailer == 'smtp') { + $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 $params Params + * @access private + * @return boolean + */ + 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)); + } + if (ini_get('safe_mode') || !($this->UseSendmailOptions)) { + $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; + } + //Avoid clash with built-in function names + if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { + 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|\n)/ms', "\n", $str); + echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( + "\n", + "\n \t ", + trim($str) + ) . "\n"; + } + } + + /** + * Sets message type to HTML or plain. + * @param boolean $isHtml True for HTML mode. + * @return void + */ + public function isHTML($isHtml = true) + { + if ($isHtml) { + $this->ContentType = 'text/html'; + } else { + $this->ContentType = 'text/plain'; + } + } + + /** + * Send messages using SMTP. + * @return void + */ + public function isSMTP() + { + $this->Mailer = 'smtp'; + } + + /** + * Send messages using PHP's mail() function. + * @return void + */ + public function isMail() + { + $this->Mailer = 'mail'; + } + + /** + * Send messages using $Sendmail. + * @return void + */ + public function isSendmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (!stristr($ini_sendmail_path, 'sendmail')) { + $this->Sendmail = '/usr/sbin/sendmail'; + } else { + $this->Sendmail = $ini_sendmail_path; + } + $this->Mailer = 'sendmail'; + } + + /** + * Send messages using qmail. + * @return void + */ + public function isQmail() + { + $ini_sendmail_path = ini_get('sendmail_path'); + + if (!stristr($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 + * @return boolean 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. + * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer. + * @param string $address The email address to send to + * @param string $name + * @return boolean 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. + * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer. + * @param string $address The email address to send to + * @param string $name + * @return boolean 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 + * @return boolean 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 phpmailerException + * @return boolean true on success, false if address already used or invalid in some way + * @access protected + */ + protected function addOrEnqueueAnAddress($kind, $address, $name) + { + $address = trim($address); + $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim + if (($pos = strrpos($address, '@')) === false) { + // At-sign is misssing. + $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + $params = array($kind, $address, $name); + // Enqueue addresses with IDN until we know the PHPMailer::$CharSet. + if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) { + if ($kind != 'Reply-To') { + if (!array_key_exists($address, $this->RecipientsQueue)) { + $this->RecipientsQueue[$address] = $params; + return true; + } + } else { + if (!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(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 phpmailerException + * @return boolean true on success, false if address already used or invalid in some way + * @access protected + */ + protected function addAnAddress($kind, $address, $name = '') + { + if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) { + $error_message = $this->lang('Invalid recipient kind: ') . $kind; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + if (!$this->validateAddress($address)) { + $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + if ($kind != 'Reply-To') { + if (!array_key_exists(strtolower($address), $this->all_recipients)) { + array_push($this->$kind, array($address, $name)); + $this->all_recipients[strtolower($address)] = true; + return true; + } + } else { + if (!array_key_exists(strtolower($address), $this->ReplyTo)) { + $this->ReplyTo[strtolower($address)] = array($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. + * @param string $addrstr The address list string + * @param bool $useimap Whether to use the IMAP extension to parse the list + * @return array + * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation + */ + public function parseAddresses($addrstr, $useimap = true) + { + $addresses = array(); + if ($useimap and 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 ($address->host != '.SYNTAX-ERROR.') { + if ($this->validateAddress($address->mailbox . '@' . $address->host)) { + $addresses[] = array( + '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 ($this->validateAddress($address)) { + $addresses[] = array( + 'name' => '', + 'address' => $address + ); + } + } else { + list($name, $email) = explode('<', $address); + $email = trim(str_replace('>', '', $email)); + if ($this->validateAddress($email)) { + $addresses[] = array( + 'name' => trim(str_replace(array('"', "'"), '', $name)), + 'address' => $email + ); + } + } + } + } + return $addresses; + } + + /** + * Set the From and FromName properties. + * @param string $address + * @param string $name + * @param boolean $auto Whether to also set the Sender address, defaults to true + * @throws phpmailerException + * @return boolean + */ + 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(). + if (($pos = strrpos($address, '@')) === false or + (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and + !$this->validateAddress($address)) { + $error_message = $this->lang('invalid_address') . " (setFrom) $address"; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + $this->From = $address; + $this->FromName = $name; + if ($auto) { + if (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. + * @param string $address The email address to check + * @param string $patternselect A selector for the validation pattern to use : + * * `auto` Pick best pattern automatically; + * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14; + * * `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. + * @return boolean + * @static + * @access public + */ + public static function validateAddress($address, $patternselect = 'auto') + { + //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321 + if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) { + return false; + } + if (!$patternselect or $patternselect == 'auto') { + //Check this constant first so it works when extension_loaded() is disabled by safe mode + //Constant was added in PHP 5.2.4 + if (defined('PCRE_VERSION')) { + //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2 + if (version_compare(PCRE_VERSION, '8.0.3') >= 0) { + $patternselect = 'pcre8'; + } else { + $patternselect = 'pcre'; + } + } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) { + //Fall back to older PCRE + $patternselect = 'pcre'; + } else { + //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension + if (version_compare(PHP_VERSION, '5.2.0') >= 0) { + $patternselect = 'php'; + } else { + $patternselect = 'noregex'; + } + } + } + switch ($patternselect) { + case 'pcre8': + /** + * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains. + * @link 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 (boolean)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 'pcre': + //An older regex that doesn't need a recent PCRE + return (boolean)preg_match( + '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' . + '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' . + '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' . + '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' . + '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' . + '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' . + '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' . + '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' . + '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' . + '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', + $address + ); + case 'html5': + /** + * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements. + * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email) + */ + return (boolean)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 'noregex': + //No PCRE! Do something _very_ approximate! + //Check the address is 3 chars or longer and contains an @ that's not the first or last char + return (strlen($address) >= 3 + and strpos($address, '@') >= 1 + and strpos($address, '@') != strlen($address) - 1); + case 'php': + default: + return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL); + } + } + + /** + * 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 function idnSupported() + { + // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2. + return function_exists('idn_to_ascii') and 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 has 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. + if ($this->idnSupported() and + !empty($this->CharSet) and + ($pos = strrpos($address, '@')) !== false) { + $domain = substr($address, ++$pos); + // Verify CharSet string is a valid one, and domain properly encoded in this CharSet. + if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) { + $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet); + if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ? + idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) : + idn_to_ascii($domain)) !== false) { + return substr($address, 0, $pos) . $punycode; + } + } + } + return $address; + } + + /** + * Create a message and send it. + * Uses the sending method specified by $Mailer. + * @throws phpmailerException + * @return boolean 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 (phpmailerException $exc) { + $this->mailHeader = ''; + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + return false; + } + } + + /** + * Prepare a message for sending. + * @throws phpmailerException + * @return boolean + */ + public function preSend() + { + 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(array($this, 'addAnAddress'), $params); + } + if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { + throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL); + } + + // Validate From, Sender, and ConfirmReadingTo addresses + foreach (array('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 (!$this->validateAddress($this->$address_kind)) { + $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind; + $this->setError($error_message); + $this->edebug($error_message); + if ($this->exceptions) { + throw new phpmailerException($error_message); + } + return false; + } + } + + // Set whether the message is multipart/alternative + if ($this->alternativeExists()) { + $this->ContentType = 'multipart/alternative'; + } + + $this->setMessageType(); + // Refuse to send an empty message unless we are specifically allowing it + if (!$this->AllowEmpty and empty($this->Body)) { + throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL); + } + + // 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 ($this->Mailer == 'mail') { + 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(trim($this->Subject))) + ); + } + + // Sign with DKIM if enabled + if (!empty($this->DKIM_domain) + && !empty($this->DKIM_private) + && !empty($this->DKIM_selector) + && 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 ") . self::CRLF . + str_replace("\r\n", "\n", $header_dkim) . self::CRLF; + } + return true; + } catch (phpmailerException $exc) { + $this->setError($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + return false; + } + } + + /** + * Actually send a message. + * Send the email via the selected mechanism + * @throws phpmailerException + * @return boolean + */ + 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 (phpmailerException $exc) { + $this->setError($exc->getMessage()); + $this->edebug($exc->getMessage()); + if ($this->exceptions) { + throw $exc; + } + } + return false; + } + + /** + * Send mail using the $Sendmail program. + * @param string $header The message headers + * @param string $body The message body + * @see PHPMailer::$Sendmail + * @throws phpmailerException + * @access protected + * @return boolean + */ + protected function sendmailSend($header, $body) + { + if ($this->Sender != '') { + if ($this->Mailer == 'qmail') { + $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + } else { + $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); + } + } else { + if ($this->Mailer == 'qmail') { + $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail)); + } else { + $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail)); + } + } + if ($this->SingleTo) { + foreach ($this->SingleToArray as $toAddr) { + if (!@$mail = popen($sendmail, 'w')) { + throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fputs($mail, 'To: ' . $toAddr . "\n"); + fputs($mail, $header); + fputs($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result == 0), + array($toAddr), + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From + ); + if ($result != 0) { + throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + } else { + if (!@$mail = popen($sendmail, 'w')) { + throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + fputs($mail, $header); + fputs($mail, $body); + $result = pclose($mail); + $this->doCallback( + ($result == 0), + $this->to, + $this->cc, + $this->bcc, + $this->Subject, + $body, + $this->From + ); + if ($result != 0) { + throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL); + } + } + return true; + } + + /** + * Send mail using the PHP mail() function. + * @param string $header The message headers + * @param string $body The message body + * @link http://www.php.net/manual/en/book.mail.php + * @throws phpmailerException + * @access protected + * @return boolean + */ + protected function mailSend($header, $body) + { + $toArr = array(); + foreach ($this->to as $toaddr) { + $toArr[] = $this->addrFormat($toaddr); + } + $to = implode(', ', $toArr); + + if (empty($this->Sender)) { + $params = ' '; + } else { + $params = sprintf('-f%s', $this->Sender); + } + if ($this->Sender != '' and !ini_get('safe_mode')) { + $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, array($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 phpmailerException($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 + * @return SMTP + */ + public function getSMTPInstance() + { + if (!is_object($this->smtp)) { + $this->smtp = new SMTP; + } + return $this->smtp; + } + + /** + * Send mail via SMTP. + * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. + * Uses the PHPMailerSMTP class by default. + * @see PHPMailer::getSMTPInstance() to use a different class. + * @param string $header The message headers + * @param string $body The message body + * @throws phpmailerException + * @uses SMTP + * @access protected + * @return boolean + */ + protected function smtpSend($header, $body) + { + $bad_rcpt = array(); + if (!$this->smtpConnect($this->SMTPOptions)) { + throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL); + } + 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 phpmailerException($this->ErrorInfo, self::STOP_CRITICAL); + } + + // Attempt to send to all recipients + foreach (array($this->to, $this->cc, $this->bcc) as $togroup) { + foreach ($togroup as $to) { + if (!$this->smtp->recipient($to[0])) { + $error = $this->smtp->getError(); + $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']); + $isSent = false; + } else { + $isSent = true; + } + $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From); + } + } + + // Only send the DATA command if we have viable recipients + if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) { + throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL); + } + if ($this->SMTPKeepAlive) { + $this->smtp->reset(); + } else { + $this->smtp->quit(); + $this->smtp->close(); + } + //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 phpmailerException( + $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() + * @uses SMTP + * @access public + * @throws phpmailerException + * @return boolean + */ + public function smtpConnect($options = array()) + { + if (is_null($this->smtp)) { + $this->smtp = $this->getSMTPInstance(); + } + + // 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 = array(); + if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) { + // Not a valid host entry + continue; + } + // $hostinfo[2]: optional ssl or tls prefix + // $hostinfo[3]: the hostname + // $hostinfo[4]: 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 + $prefix = ''; + $secure = $this->SMTPSecure; + $tls = ($this->SMTPSecure == 'tls'); + if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) { + $prefix = 'ssl://'; + $tls = false; // Can't have SSL and TLS at the same time + $secure = 'ssl'; + } elseif ($hostinfo[2] == 'tls') { + $tls = true; + // tls doesn't use a prefix + $secure = 'tls'; + } + //Do we need the OpenSSL extension? + $sslext = defined('OPENSSL_ALGO_SHA1'); + if ('tls' === $secure or 'ssl' === $secure) { + //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled + if (!$sslext) { + throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL); + } + } + $host = $hostinfo[3]; + $port = $this->Port; + $tport = (integer)$hostinfo[4]; + if ($tport > 0 and $tport < 65536) { + $port = $tport; + } + 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 and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) { + $tls = true; + } + if ($tls) { + if (!$this->smtp->startTLS()) { + throw new phpmailerException($this->lang('connect_host')); + } + // We must resend HELO after tls negotiation + $this->smtp->hello($hello); + } + if ($this->SMTPAuth) { + if (!$this->smtp->authenticate( + $this->Username, + $this->Password, + $this->AuthType, + $this->Realm, + $this->Workstation + ) + ) { + throw new phpmailerException($this->lang('authenticate')); + } + } + return true; + } catch (phpmailerException $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 and !is_null($lastexception)) { + throw $lastexception; + } + return false; + } + + /** + * Close the active SMTP session if one exists. + * @return void + */ + public function smtpClose() + { + if ($this->smtp !== null) { + if ($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 boolean + * @access public + */ + public function setLanguage($langcode = 'en', $lang_path = '') + { + // Define full set of translatable strings in English + $PHPMAILER_LANG = array( + '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: ', + '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(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR; + } + $foundlang = true; + $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php'; + // There is no English translation file + if ($langcode != 'en') { + // Make sure language file path is readable + if (!is_readable($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 (boolean)$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. + * @access public + * @param string $type + * @param array $addr An array of recipient, + * where each recipient is a 2-element indexed array with element 0 containing an address + * and element 1 containing a name, like: + * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User')) + * @return string + */ + public function addrAppend($type, $addr) + { + $addresses = array(); + foreach ($addr as $address) { + $addresses[] = $this->addrFormat($address); + } + return $type . ': ' . implode(', ', $addresses) . $this->LE; + } + + /** + * Format an address for use in a message header. + * @access public + * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name + * like array('joe@example.com', 'Joe User') + * @return string + */ + public function addrFormat($addr) + { + if (empty($addr[1])) { // No name provided + return $this->secureHeader($addr[0]); + } else { + 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 integer $length The line length to wrap to + * @param boolean $qp_mode Whether to run in Quoted-Printable mode + * @access public + * @return string + */ + public function wrapText($message, $length, $qp_mode = false) + { + if ($qp_mode) { + $soft_break = sprintf(' =%s', $this->LE); + } else { + $soft_break = $this->LE; + } + // If utf-8 encoding is used, we will need to make sure we don't + // split multibyte characters when we wrap + $is_utf8 = (strtolower($this->CharSet) == 'utf-8'); + $lelen = strlen($this->LE); + $crlflen = strlen(self::CRLF); + + $message = $this->fixEOL($message); + //Remove a trailing line break + if (substr($message, -$lelen) == $this->LE) { + $message = substr($message, 0, -$lelen); + } + + //Split message into lines + $lines = explode($this->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 and (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', self::CRLF); + } else { + $message .= $buf . $soft_break; + } + $buf = ''; + } + while (strlen($word) > 0) { + 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 = substr($word, $len); + + if (strlen($word) > 0) { + $message .= $part . sprintf('=%s', self::CRLF); + } else { + $buf = $part; + } + } + } else { + $buf_o = $buf; + if (!$firstword) { + $buf .= ' '; + } + $buf .= $word; + + if (strlen($buf) > $length and $buf_o != '') { + $message .= $buf_o . $soft_break; + $buf = $word; + } + } + $firstword = false; + } + $message .= $buf . self::CRLF; + } + + return $message; + } + + /** + * Find the last character boundary prior to $maxLength in a utf-8 + * quoted-printable encoded string. + * Original written by Colin Brown. + * @access public + * @param string $encodedText utf-8 QP text + * @param integer $maxLength Find the last character boundary prior to this length + * @return integer + */ + 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 = $maxLength - ($lookBack - $encodedCharPos); + } + $foundSplitPos = true; + } elseif ($dec >= 192) { + // First byte of a multi byte character + // Reduce maxLength to split at start of character + $maxLength = $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. + * @access public + * @return void + */ + 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. + * @access public + * @return string The assembled headers + */ + public function createHeader() + { + $result = ''; + + if ($this->MessageDate == '') { + $this->MessageDate = self::rfcDate(); + } + $result .= $this->headerLine('Date', $this->MessageDate); + + // To be created automatically by mail() + if ($this->SingleTo) { + if ($this->Mailer != 'mail') { + foreach ($this->to as $toaddr) { + $this->SingleToArray[] = $this->addrFormat($toaddr); + } + } + } else { + if (count($this->to) > 0) { + if ($this->Mailer != 'mail') { + $result .= $this->addrAppend('To', $this->to); + } + } elseif (count($this->cc) == 0) { + $result .= $this->headerLine('To', 'undisclosed-recipients:;'); + } + } + + $result .= $this->addrAppend('From', array(array(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 (( + $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail' + ) + and 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 ($this->Mailer != 'mail') { + $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject))); + } + + if ('' != $this->MessageID and 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 (!is_null($this->Priority)) { + $result .= $this->headerLine('X-Priority', $this->Priority); + } + if ($this->XMailer == '') { + $result .= $this->headerLine( + 'X-Mailer', + 'PHPMailer ' . $this->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. + * @access public + * @return string + */ + public function getMailMIME() + { + $result = ''; + $ismultipart = true; + switch ($this->message_type) { + case 'inline': + $result .= $this->headerLine('Content-Type', 'multipart/related;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + case 'attach': + case 'inline_attach': + case 'alt_attach': + case 'alt_inline_attach': + $result .= $this->headerLine('Content-Type', 'multipart/mixed;'); + $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"'); + break; + case 'alt': + case 'alt_inline': + $result .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $result .= $this->textLine("\tboundary=\"" . $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 ($this->Encoding != '7bit') { + // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE + if ($ismultipart) { + if ($this->Encoding == '8bit') { + $result .= $this->headerLine('Content-Transfer-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 ($this->Mailer != 'mail') { + $result .= $this->LE; + } + + return $result; + } + + /** + * Returns the whole MIME message. + * Includes complete headers and body. + * Only valid post preSend(). + * @see PHPMailer::preSend() + * @access public + * @return string + */ + public function getSentMIMEMessage() + { + return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody; + } + + /** + * Assemble the message body. + * Returns an empty string on failure. + * @access public + * @throws phpmailerException + * @return string The assembled message body + */ + public function createBody() + { + $body = ''; + //Create unique IDs and preset boundaries + $this->uniqueid = md5(uniqid(time())); + $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() . $this->LE; + } + + $this->setWordWrap(); + + $bodyEncoding = $this->Encoding; + $bodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) { + $bodyEncoding = '7bit'; + $bodyCharSet = 'us-ascii'; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding + if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) { + $this->Encoding = 'quoted-printable'; + $bodyEncoding = 'quoted-printable'; + } + + $altBodyEncoding = $this->Encoding; + $altBodyCharSet = $this->CharSet; + //Can we do a 7-bit downgrade? + if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) { + $altBodyEncoding = '7bit'; + $altBodyCharSet = 'us-ascii'; + } + //If lines are too long, and we're not already using an encoding that will shorten them, + //change to quoted-printable transfer encoding + if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) { + $altBodyEncoding = 'quoted-printable'; + } + //Use this as a preamble in all multipart message types + $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE; + switch ($this->message_type) { + case 'inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->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 .= $this->LE . $this->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', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= $this->LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + case 'alt': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + if (!empty($this->Ical)) { + $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', ''); + $body .= $this->encodeString($this->Ical, $this->Encoding); + $body .= $this->LE . $this->LE; + } + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_inline': + $body .= $mimepre; + $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->attachAll('inline', $this->boundary[2]); + $body .= $this->LE; + $body .= $this->endBoundary($this->boundary[1]); + break; + case 'alt_attach': + $body .= $mimepre; + $body .= $this->textLine('--' . $this->boundary[1]); + $body .= $this->headerLine('Content-Type', 'multipart/alternative;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->endBoundary($this->boundary[2]); + $body .= $this->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', 'multipart/alternative;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding); + $body .= $this->encodeString($this->AltBody, $altBodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->textLine('--' . $this->boundary[2]); + $body .= $this->headerLine('Content-Type', 'multipart/related;'); + $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"'); + $body .= $this->LE; + $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding); + $body .= $this->encodeString($this->Body, $bodyEncoding); + $body .= $this->LE . $this->LE; + $body .= $this->attachAll('inline', $this->boundary[3]); + $body .= $this->LE; + $body .= $this->endBoundary($this->boundary[2]); + $body .= $this->LE; + $body .= $this->attachAll('attachment', $this->boundary[1]); + break; + default: + // catch case 'plain' and case '' + $body .= $this->encodeString($this->Body, $bodyEncoding); + break; + } + + if ($this->isError()) { + $body = ''; + } elseif ($this->sign_key_file) { + try { + if (!defined('PKCS7_TEXT')) { + throw new phpmailerException($this->lang('extension_missing') . 'openssl'); + } + // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1 + $file = tempnam(sys_get_temp_dir(), 'mail'); + if (false === file_put_contents($file, $body)) { + throw new phpmailerException($this->lang('signing') . ' Could not write temp file'); + } + $signed = tempnam(sys_get_temp_dir(), 'signed'); + //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), + array('file://' . realpath($this->sign_key_file), $this->sign_key_pass), + null + ); + } else { + $sign = @openssl_pkcs7_sign( + $file, + $signed, + 'file://' . realpath($this->sign_cert_file), + array('file://' . realpath($this->sign_key_file), $this->sign_key_pass), + null, + PKCS7_DETACHED, + $this->sign_extracerts_file + ); + } + if ($sign) { + @unlink($file); + $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] . $this->LE . $this->LE; + $body = $parts[1]; + } else { + @unlink($file); + @unlink($signed); + throw new phpmailerException($this->lang('signing') . openssl_error_string()); + } + } catch (phpmailerException $exc) { + $body = ''; + if ($this->exceptions) { + throw $exc; + } + } + } + return $body; + } + + /** + * Return the start of a message boundary. + * @access protected + * @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 .= $this->LE; + // RFC1341 part 5 says 7bit is assumed if not specified + if ($encoding != '7bit') { + $result .= $this->headerLine('Content-Transfer-Encoding', $encoding); + } + $result .= $this->LE; + + return $result; + } + + /** + * Return the end of a message boundary. + * @access protected + * @param string $boundary + * @return string + */ + protected function endBoundary($boundary) + { + return $this->LE . '--' . $boundary . '--' . $this->LE; + } + + /** + * Set the message type. + * PHPMailer only supports some preset message types, + * not arbitrary MIME structures. + * @access protected + * @return void + */ + protected function setMessageType() + { + $type = array(); + if ($this->alternativeExists()) { + $type[] = 'alt'; + } + if ($this->inlineImageExists()) { + $type[] = 'inline'; + } + if ($this->attachmentExists()) { + $type[] = 'attach'; + } + $this->message_type = implode('_', $type); + if ($this->message_type == '') { + $this->message_type = 'plain'; + } + } + + /** + * Format a header line. + * @access public + * @param string $name + * @param string $value + * @return string + */ + public function headerLine($name, $value) + { + return $name . ': ' . $value . $this->LE; + } + + /** + * Return a formatted mail line. + * @access public + * @param string $value + * @return string + */ + public function textLine($value) + { + return $value . $this->LE; + } + + /** + * Add an attachment from a path on the filesystem. + * Returns false if the file could not be found or read. + * @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 phpmailerException + * @return boolean + */ + public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment') + { + try { + if (!@is_file($path)) { + throw new phpmailerException($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 = self::filenameToType($path); + } + + $filename = basename($path); + if ($name == '') { + $name = $filename; + } + + $this->attachment[] = array( + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => 0 + ); + + } catch (phpmailerException $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. + * @access protected + * @param string $disposition_type + * @param string $boundary + * @return string + */ + protected function attachAll($disposition_type, $boundary) + { + // Return text of body + $mime = array(); + $cidUniq = array(); + $incl = array(); + + // 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 = md5(serialize($attachment)); + if (in_array($inclhash, $incl)) { + continue; + } + $incl[] = $inclhash; + $name = $attachment[2]; + $encoding = $attachment[3]; + $type = $attachment[4]; + $disposition = $attachment[6]; + $cid = $attachment[7]; + if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) { + continue; + } + $cidUniq[$cid] = true; + + $mime[] = sprintf('--%s%s', $boundary, $this->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)), + $this->LE + ); + } else { + $mime[] = sprintf( + 'Content-Type: %s%s', + $type, + $this->LE + ); + } + // RFC1341 part 5 says 7bit is assumed if not specified + if ($encoding != '7bit') { + $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE); + } + + if ($disposition == 'inline') { + $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->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, + $this->LE . $this->LE + ); + } else { + if (!empty($encoded_name)) { + $mime[] = sprintf( + 'Content-Disposition: %s; filename=%s%s', + $disposition, + $encoded_name, + $this->LE . $this->LE + ); + } else { + $mime[] = sprintf( + 'Content-Disposition: %s%s', + $disposition, + $this->LE . $this->LE + ); + } + } + } else { + $mime[] = $this->LE; + } + + // Encode as string attachment + if ($bString) { + $mime[] = $this->encodeString($string, $encoding); + if ($this->isError()) { + return ''; + } + $mime[] = $this->LE . $this->LE; + } else { + $mime[] = $this->encodeFile($path, $encoding); + if ($this->isError()) { + return ''; + } + $mime[] = $this->LE . $this->LE; + } + } + } + + $mime[] = sprintf('--%s--%s', $boundary, $this->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' + * @throws phpmailerException + * @access protected + * @return string + */ + protected function encodeFile($path, $encoding = 'base64') + { + try { + if (!is_readable($path)) { + throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE); + } + $magic_quotes = get_magic_quotes_runtime(); + if ($magic_quotes) { + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + set_magic_quotes_runtime(false); + } else { + //Doesn't exist in PHP 5.4, but we don't need to check because + //get_magic_quotes_runtime always returns false in 5.4+ + //so it will never get here + ini_set('magic_quotes_runtime', false); + } + } + $file_buffer = file_get_contents($path); + $file_buffer = $this->encodeString($file_buffer, $encoding); + if ($magic_quotes) { + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + set_magic_quotes_runtime($magic_quotes); + } else { + ini_set('magic_quotes_runtime', $magic_quotes); + } + } + 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' + * @access public + * @return string + */ + public function encodeString($str, $encoding = 'base64') + { + $encoded = ''; + switch (strtolower($encoding)) { + case 'base64': + $encoded = chunk_split(base64_encode($str), 76, $this->LE); + break; + case '7bit': + case '8bit': + $encoded = $this->fixEOL($str); + // Make sure it ends with a line break + if (substr($encoded, -(strlen($this->LE))) != $this->LE) { + $encoded .= $this->LE; + } + break; + case 'binary': + $encoded = $str; + break; + case 'quoted-printable': + $encoded = $this->encodeQP($str); + break; + default: + $this->setError($this->lang('encoding') . $encoding); + break; + } + return $encoded; + } + + /** + * Encode a header string optimally. + * Picks shortest of Q, B, quoted-printable or none. + * @access public + * @param string $str + * @param string $position + * @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); + } else { + 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); + // Intentional fall-through + case 'text': + default: + $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + break; + } + + //There are no chars that need encoding + if ($matchcount == 0) { + return ($str); + } + + $maxlen = 75 - 7 - strlen($this->CharSet); + // Try to select the encoding which should produce the shortest output + if ($matchcount > strlen($str) / 3) { + // More than a third of the content will need encoding, so B encoding will be most efficient + $encoding = 'B'; + if (function_exists('mb_strlen') && $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")); + } + } else { + $encoding = 'Q'; + $encoded = $this->encodeQ($str, $position); + $encoded = $this->wrapText($encoded, $maxlen, true); + $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded)); + } + + $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded); + $encoded = trim(str_replace("\n", $this->LE, $encoded)); + + return $encoded; + } + + /** + * Check if a string contains multi-byte characters. + * @access public + * @param string $str multi-byte text to wrap encode + * @return boolean + */ + public function hasMultiBytes($str) + { + if (function_exists('mb_strlen')) { + return (strlen($str) > mb_strlen($str, $this->CharSet)); + } else { // 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 boolean + */ + public function has8bitChars($text) + { + return (boolean)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 + * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283 + * @access public + * @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 ($linebreak === null) { + $linebreak = $this->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); + + 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 + $encoded = substr($encoded, 0, -strlen($linebreak)); + return $encoded; + } + + /** + * Encode a string in quoted-printable format. + * According to RFC2045 section 6.7. + * @access public + * @param string $string The text to encode + * @param integer $line_max Number of chars allowed on a line before wrapping + * @return string + * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment + */ + public function encodeQP($string, $line_max = 76) + { + // Use native function if it's available (>= PHP5.3) + if (function_exists('quoted_printable_encode')) { + return quoted_printable_encode($string); + } + // Fall back to a pure PHP implementation + $string = str_replace( + array('%20', '%0D%0A.', '%0D%0A', '%'), + array(' ', "\r\n=2E", "\r\n", '='), + rawurlencode($string) + ); + return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string); + } + + /** + * Backward compatibility wrapper for an old QP encoding function that was removed. + * @see PHPMailer::encodeQP() + * @access public + * @param string $string + * @param integer $line_max + * @param boolean $space_conv + * @return string + * @deprecated Use encodeQP instead. + */ + public function encodeQPphp( + $string, + $line_max = 76, + /** @noinspection PhpUnusedParameterInspection */ $space_conv = false + ) { + return $this->encodeQP($string, $line_max); + } + + /** + * Encode a string using Q encoding. + * @link http://tools.ietf.org/html/rfc2047 + * @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 + * @access public + * @return string + */ + public function encodeQ($str, $position = 'text') + { + // There should not be any EOL in the string + $pattern = ''; + $encoded = str_replace(array("\r", "\n"), '', $str); + switch (strtolower($position)) { + case 'phrase': + // RFC 2047 section 5.3 + $pattern = '^A-Za-z0-9!*+\/ -'; + break; + /** @noinspection PhpMissingBreakStatementInspection */ + case 'comment': + // RFC 2047 section 5.2 + $pattern = '\(\)"'; + // intentional fall-through + // for this reason we build the $pattern without including delimiters and [] + 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 = array(); + 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]); + 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 every spaces to _ (more readable than =20) + 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 + * @return void + */ + public function addStringAttachment( + $string, + $filename, + $encoding = 'base64', + $type = '', + $disposition = 'attachment' + ) { + // If a MIME type is not specified, try to work it out from the file name + if ($type == '') { + $type = self::filenameToType($filename); + } + // Append to $attachment array + $this->attachment[] = array( + 0 => $string, + 1 => $filename, + 2 => basename($filename), + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => 0 + ); + } + + /** + * 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. + * @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 + * @return boolean True on successfully adding an attachment + */ + public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline') + { + if (!@is_file($path)) { + $this->setError($this->lang('file_access') . $path); + return false; + } + + // If a MIME type is not specified, try to work it out from the file name + if ($type == '') { + $type = self::filenameToType($path); + } + + $filename = basename($path); + if ($name == '') { + $name = $filename; + } + + // Append to $attachment array + $this->attachment[] = array( + 0 => $path, + 1 => $filename, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => false, // isStringAttachment + 6 => $disposition, + 7 => $cid + ); + return true; + } + + /** + * Add an embedded stringified attachment. + * This can include images, sounds, and just about any other document type. + * Be sure to set the $type to an image type for images: + * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'. + * @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 + * @param string $encoding File encoding (see $Encoding). + * @param string $type MIME type. + * @param string $disposition Disposition to use + * @return boolean True on successfully adding an attachment + */ + public function addStringEmbeddedImage( + $string, + $cid, + $name = '', + $encoding = 'base64', + $type = '', + $disposition = 'inline' + ) { + // If a MIME type is not specified, try to work it out from the name + if ($type == '' and !empty($name)) { + $type = self::filenameToType($name); + } + + // Append to $attachment array + $this->attachment[] = array( + 0 => $string, + 1 => $name, + 2 => $name, + 3 => $encoding, + 4 => $type, + 5 => true, // isStringAttachment + 6 => $disposition, + 7 => $cid + ); + return true; + } + + /** + * Check if an inline attachment is present. + * @access public + * @return boolean + */ + public function inlineImageExists() + { + foreach ($this->attachment as $attachment) { + if ($attachment[6] == 'inline') { + return true; + } + } + return false; + } + + /** + * Check if an attachment (non-inline) is present. + * @return boolean + */ + public function attachmentExists() + { + foreach ($this->attachment as $attachment) { + if ($attachment[6] == 'attachment') { + return true; + } + } + return false; + } + + /** + * Check if this message has an alternative body set. + * @return boolean + */ + public function alternativeExists() + { + return !empty($this->AltBody); + } + + /** + * Clear queued addresses of given kind. + * @access protected + * @param string $kind 'to', 'cc', or 'bcc' + * @return void + */ + public function clearQueuedAddresses($kind) + { + $RecipientsQueue = $this->RecipientsQueue; + foreach ($RecipientsQueue as $address => $params) { + if ($params[0] == $kind) { + unset($this->RecipientsQueue[$address]); + } + } + } + + /** + * Clear all To recipients. + * @return void + */ + public function clearAddresses() + { + foreach ($this->to as $to) { + unset($this->all_recipients[strtolower($to[0])]); + } + $this->to = array(); + $this->clearQueuedAddresses('to'); + } + + /** + * Clear all CC recipients. + * @return void + */ + public function clearCCs() + { + foreach ($this->cc as $cc) { + unset($this->all_recipients[strtolower($cc[0])]); + } + $this->cc = array(); + $this->clearQueuedAddresses('cc'); + } + + /** + * Clear all BCC recipients. + * @return void + */ + public function clearBCCs() + { + foreach ($this->bcc as $bcc) { + unset($this->all_recipients[strtolower($bcc[0])]); + } + $this->bcc = array(); + $this->clearQueuedAddresses('bcc'); + } + + /** + * Clear all ReplyTo recipients. + * @return void + */ + public function clearReplyTos() + { + $this->ReplyTo = array(); + $this->ReplyToQueue = array(); + } + + /** + * Clear all recipient types. + * @return void + */ + public function clearAllRecipients() + { + $this->to = array(); + $this->cc = array(); + $this->bcc = array(); + $this->all_recipients = array(); + $this->RecipientsQueue = array(); + } + + /** + * Clear all filesystem, string, and binary attachments. + * @return void + */ + public function clearAttachments() + { + $this->attachment = array(); + } + + /** + * Clear all custom headers. + * @return void + */ + public function clearCustomHeaders() + { + $this->CustomHeader = array(); + } + + /** + * Add an error message to the error container. + * @access protected + * @param string $msg + * @return void + */ + protected function setError($msg) + { + $this->error_count++; + if ($this->Mailer == 'smtp' and !is_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. + * @access public + * @return string + * @static + */ + 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. + * @access protected + * @return string + */ + protected function serverHostname() + { + $result = 'localhost.localdomain'; + if (!empty($this->Hostname)) { + $result = $this->Hostname; + } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) { + $result = $_SERVER['SERVER_NAME']; + } elseif (function_exists('gethostname') && gethostname() !== false) { + $result = gethostname(); + } elseif (php_uname('n') !== false) { + $result = php_uname('n'); + } + return $result; + } + + /** + * Get an error message in the current language. + * @access protected + * @param string $key + * @return string + */ + protected function lang($key) + { + if (count($this->language) < 1) { + $this->setLanguage('en'); // set the default language + } + + if (array_key_exists($key, $this->language)) { + if ($key == 'smtp_connect_failed') { + //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]; + } else { + //Return the key as a fallback + return $key; + } + } + + /** + * Check if an error occurred. + * @access public + * @return boolean True if an error did occur. + */ + public function isError() + { + return ($this->error_count > 0); + } + + /** + * Ensure consistent line endings in a string. + * Changes every end of line from CRLF, CR or LF to $this->LE. + * @access public + * @param string $str String to fixEOL + * @return string + */ + public function fixEOL($str) + { + // Normalise to \n + $nstr = str_replace(array("\r\n", "\r"), "\n", $str); + // Now convert LE as needed + if ($this->LE !== "\n") { + $nstr = str_replace("\n", $this->LE, $nstr); + } + return $nstr; + } + + /** + * Add a custom header. + * $name value can be overloaded to contain + * both header name and value (name:value) + * @access public + * @param string $name Custom header name + * @param string $value Header value + * @return void + */ + public function addCustomHeader($name, $value = null) + { + if ($value === null) { + // Value passed in as name:value + $this->CustomHeader[] = explode(':', $name, 2); + } else { + $this->CustomHeader[] = array($name, $value); + } + } + + /** + * Returns all custom headers. + * @return array + */ + public function getCustomHeaders() + { + return $this->CustomHeader; + } + + /** + * Create a message from an HTML string. + * Automatically makes modifications for inline images and backgrounds + * and creates a plain-text version by converting the HTML. + * Overwrites any existing values in $this->Body and $this->AltBody + * @access public + * @param string $message HTML message string + * @param string $basedir baseline directory for path + * @param boolean|callable $advanced Whether to use the internal HTML to text converter + * or your own custom converter @see PHPMailer::html2text() + * @return string $message + */ + public function msgHTML($message, $basedir = '', $advanced = false) + { + preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images); + if (array_key_exists(2, $images)) { + foreach ($images[2] as $imgindex => $url) { + // Convert data URIs into embedded images + if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) { + $data = substr($url, strpos($url, ',')); + if ($match[2]) { + $data = base64_decode($data); + } else { + $data = rawurldecode($data); + } + $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 + if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) { + $message = str_replace( + $images[0][$imgindex], + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + } + } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[A-z]+://#', $url)) { + // Do not change urls for absolute images (thanks to corvuscorax) + // Do not change urls that are already inline images + $filename = basename($url); + $directory = dirname($url); + if ($directory == '.') { + $directory = ''; + } + $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 + if (strlen($basedir) > 1 && substr($basedir, -1) != '/') { + $basedir .= '/'; + } + if (strlen($directory) > 1 && substr($directory, -1) != '/') { + $directory .= '/'; + } + if ($this->addEmbeddedImage( + $basedir . $directory . $filename, + $cid, + $filename, + 'base64', + self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION)) + ) + ) { + $message = preg_replace( + '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui', + $images[1][$imgindex] . '="cid:' . $cid . '"', + $message + ); + } + } + } + } + $this->isHTML(true); + // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better + $this->Body = $this->normalizeBreaks($message); + $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced)); + if (!$this->alternativeExists()) { + $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . + self::CRLF . self::CRLF; + } + 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 been removed for license reasons in #232 + * Example usage: + * + * // 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 boolean|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 call_user_func($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 + * @access public + * @return string MIME type of file. + * @static + */ + public static function _mime_types($ext = '') + { + $mimes = array( + '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', + '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', + 'bmp' => 'image/bmp', + 'gif' => 'image/gif', + 'jpeg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'png' => 'image/png', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + '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', + 'xml' => 'text/xml', + 'xsl' => 'text/xml', + 'mpeg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mov' => 'video/quicktime', + 'qt' => 'video/quicktime', + 'rv' => 'video/vnd.rn-realvideo', + 'avi' => 'video/x-msvideo', + 'movie' => 'video/x-sgi-movie' + ); + if (array_key_exists(strtolower($ext), $mimes)) { + return $mimes[strtolower($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 + * @static + */ + 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); + } + $pathinfo = self::mb_pathinfo($filename); + return self::_mime_types($pathinfo['extension']); + } + + /** + * Multi-byte-safe pathinfo replacement. + * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe. + * Works similarly to the one in PHP >= 5.2.0 + * @link 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 integer|string $options Either a PATHINFO_* constant, + * or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2 + * @return string|array + * @static + */ + public static function mb_pathinfo($path, $options = null) + { + $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => ''); + $pathinfo = array(); + if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $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', 'tls');` + * is the same as: + * `$mail->SMTPSecure = 'tls';` + * @access public + * @param string $name The property name to set + * @param mixed $value The value to set the property to + * @return boolean + * @TODO Should this not be using the __set() magic function? + */ + public function set($name, $value = '') + { + if (property_exists($this, $name)) { + $this->$name = $value; + return true; + } else { + $this->setError($this->lang('variable_set') . $name); + return false; + } + } + + /** + * Strip newlines to prevent header injection. + * @access public + * @param string $str + * @return string + */ + public function secureHeader($str) + { + return trim(str_replace(array("\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 CRLF + * @return string + * @access public + * @static + */ + public static function normalizeBreaks($text, $breaktype = "\r\n") + { + return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text); + } + + /** + * Set the public and private key files and password for S/MIME signing. + * @access public + * @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. + * @access public + * @param string $txt + * @return string + */ + public function DKIM_QP($txt) + { + $line = ''; + for ($i = 0; $i < strlen($txt); $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. + * @access public + * @param string $signHeader + * @throws phpmailerException + * @return string + */ + public function DKIM_Sign($signHeader) + { + if (!defined('PKCS7_TEXT')) { + if ($this->exceptions) { + throw new phpmailerException($this->lang('extension_missing') . 'openssl'); + } + return ''; + } + $privKeyStr = file_get_contents($this->DKIM_private); + if ($this->DKIM_passphrase != '') { + $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase); + } else { + $privKey = $privKeyStr; + } + if (openssl_sign($signHeader, $signature, $privKey)) { + return base64_encode($signature); + } + return ''; + } + + /** + * Generate a DKIM canonicalization header. + * @access public + * @param string $signHeader Header + * @return string + */ + public function DKIM_HeaderC($signHeader) + { + $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader); + $lines = explode("\r\n", $signHeader); + foreach ($lines as $key => $line) { + list($heading, $value) = explode(':', $line, 2); + $heading = strtolower($heading); + $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces + $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value + } + $signHeader = implode("\r\n", $lines); + return $signHeader; + } + + /** + * Generate a DKIM canonicalization body. + * @access public + * @param string $body Message Body + * @return string + */ + public function DKIM_BodyC($body) + { + if ($body == '') { + return "\r\n"; + } + // stabilize line endings + $body = str_replace("\r\n", "\n", $body); + $body = str_replace("\n", "\r\n", $body); + // END stabilize line endings + while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") { + $body = substr($body, 0, strlen($body) - 2); + } + return $body; + } + + /** + * Create the DKIM header and body in a new message header. + * @access public + * @param string $headers_line Header lines + * @param string $subject Subject + * @param string $body Body + * @return string + */ + public function DKIM_Add($headers_line, $subject, $body) + { + $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms + $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body + $DKIMquery = 'dns/txt'; // Query method + $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone) + $subject_header = "Subject: $subject"; + $headers = explode($this->LE, $headers_line); + $from_header = ''; + $to_header = ''; + $current = ''; + foreach ($headers as $header) { + if (strpos($header, 'From:') === 0) { + $from_header = $header; + $current = 'from_header'; + } elseif (strpos($header, 'To:') === 0) { + $to_header = $header; + $current = 'to_header'; + } else { + if (!empty($$current) && strpos($header, ' =?') === 0) { + $$current .= $header; + } else { + $current = ''; + } + } + } + $from = str_replace('|', '=7C', $this->DKIM_QP($from_header)); + $to = str_replace('|', '=7C', $this->DKIM_QP($to_header)); + $subject = str_replace( + '|', + '=7C', + $this->DKIM_QP($subject_header) + ); // Copied header fields (dkim-quoted-printable) + $body = $this->DKIM_BodyC($body); + $DKIMlen = strlen($body); // Length of body + $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body + if ('' == $this->DKIM_identity) { + $ident = ''; + } else { + $ident = ' i=' . $this->DKIM_identity . ';'; + } + $dkimhdrs = 'DKIM-Signature: v=1; a=' . + $DKIMsignatureType . '; q=' . + $DKIMquery . '; l=' . + $DKIMlen . '; s=' . + $this->DKIM_selector . + ";\r\n" . + "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" . + "\th=From:To:Subject;\r\n" . + "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" . + "\tz=$from\r\n" . + "\t|$to\r\n" . + "\t|$subject;\r\n" . + "\tbh=" . $DKIMb64 . ";\r\n" . + "\tb="; + $toSign = $this->DKIM_HeaderC( + $from_header . "\r\n" . + $to_header . "\r\n" . + $subject_header . "\r\n" . + $dkimhdrs + ); + $signed = $this->DKIM_Sign($toSign); + return $dkimhdrs . $signed . "\r\n"; + } + + /** + * Detect if a string contains a line longer than the maximum line length allowed. + * @param string $str + * @return boolean + * @static + */ + public static function hasLineLongerThanMax($str) + { + //+2 to include CRLF line break for a 1000 total + return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str); + } + + /** + * Allows for public read access to 'to' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getToAddresses() + { + return $this->to; + } + + /** + * Allows for public read access to 'cc' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getCcAddresses() + { + return $this->cc; + } + + /** + * Allows for public read access to 'bcc' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getBccAddresses() + { + return $this->bcc; + } + + /** + * Allows for public read access to 'ReplyTo' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getReplyToAddresses() + { + return $this->ReplyTo; + } + + /** + * Allows for public read access to 'all_recipients' property. + * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included. + * @access public + * @return array + */ + public function getAllRecipientAddresses() + { + return $this->all_recipients; + } + + /** + * Perform a callback. + * @param boolean $isSent + * @param array $to + * @param array $cc + * @param array $bcc + * @param string $subject + * @param string $body + * @param string $from + */ + protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from) + { + if (!empty($this->action_function) && is_callable($this->action_function)) { + $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from); + call_user_func_array($this->action_function, $params); + } + } +} + +/** + * PHPMailer exception handler + * @package PHPMailer + */ +class phpmailerException extends Exception +{ + /** + * Prettify error message output + * @return string + */ + public function errorMessage() + { + $errorMsg = '' . $this->getMessage() . "
\n"; + return $errorMsg; + } +} diff --git a/include/phpmailer/class.smtp.php b/include/phpmailer/class.smtp.php new file mode 100644 index 0000000..2e32e2f --- /dev/null +++ b/include/phpmailer/class.smtp.php @@ -0,0 +1,1181 @@ + + * @author Jim Jagielski (jimjag) + * @author Andy Prevost (codeworxtech) + * @author Brent R. Matzelle (original founder) + * @copyright 2014 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. + */ + +/** + * PHPMailer RFC821 SMTP email transport class. + * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. + * @package PHPMailer + * @author Chris Ryan + * @author Marcus Bointon + */ +class SMTP +{ + /** + * The PHPMailer SMTP version number. + * @var string + */ + const VERSION = '5.2.14'; + + /** + * SMTP line break constant. + * @var string + */ + const CRLF = "\r\n"; + + /** + * The SMTP port to use if one is not specified. + * @var integer + */ + const DEFAULT_SMTP_PORT = 25; + + /** + * The maximum line length allowed by RFC 2822 section 2.1.1 + * @var integer + */ + const MAX_LINE_LENGTH = 998; + + /** + * Debug level for no output + */ + const DEBUG_OFF = 0; + + /** + * Debug level to show client -> server messages + */ + const DEBUG_CLIENT = 1; + + /** + * Debug level to show client -> server and server -> client messages + */ + const DEBUG_SERVER = 2; + + /** + * Debug level to show connection status, client -> server and server -> client messages + */ + const DEBUG_CONNECTION = 3; + + /** + * Debug level to show all messages + */ + const DEBUG_LOWLEVEL = 4; + + /** + * The PHPMailer SMTP Version number. + * @var string + * @deprecated Use the `VERSION` constant instead + * @see SMTP::VERSION + */ + public $Version = '5.2.14'; + + /** + * SMTP server port number. + * @var integer + * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead + * @see SMTP::DEFAULT_SMTP_PORT + */ + public $SMTP_PORT = 25; + + /** + * SMTP reply line ending. + * @var string + * @deprecated Use the `CRLF` constant instead + * @see SMTP::CRLF + */ + public $CRLF = "\r\n"; + + /** + * 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 integer + */ + 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: + * + * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; + * + * @var string|callable + */ + public $Debugoutput = 'echo'; + + /** + * Whether to use VERP. + * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path + * @link http://www.postfix.org/VERP_README.html Info on VERP + * @var boolean + */ + 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. + * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2 + * @var integer + */ + 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 integer + */ + public $Timelimit = 300; + + /** + * The socket for the server connection. + * @var resource + */ + protected $smtp_conn; + + /** + * Error information, if any, for the last SMTP command. + * @var array + */ + protected $error = array( + '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 = null; + + /** + * 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 = null; + + /** + * The most recent reply received from the server. + * @var string + */ + protected $last_reply = ''; + + /** + * Output debugging info via a user-selected method. + * @see SMTP::$Debugoutput + * @see SMTP::$do_debug + * @param string $str Debug string to output + * @param integer $level The debug level of this message; see DEBUG_* constants + * @return void + */ + protected function edebug($str, $level = 0) + { + if ($level > $this->do_debug) { + return; + } + //Avoid clash with built-in function names + if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) { + call_user_func($this->Debugoutput, $str, $this->do_debug); + 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|\n)/ms', "\n", $str); + echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( + "\n", + "\n \t ", + trim($str) + )."\n"; + } + } + + /** + * Connect to an SMTP server. + * @param string $host SMTP server IP or host name + * @param integer $port The port number to connect to + * @param integer $timeout How long to wait for the connection to open + * @param array $options An array of options for stream_context_create() + * @access public + * @return boolean + */ + public function connect($host, $port = null, $timeout = 30, $options = array()) + { + static $streamok; + //This is enabled by default since 5.0.0 but some providers disable it + //Check this once and cache the result + if (is_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_SMTP_PORT; + } + // Connect to the SMTP server + $this->edebug( + "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true), + self::DEBUG_CONNECTION + ); + $errno = 0; + $errstr = ''; + if ($streamok) { + $socket_context = stream_context_create($options); + //Suppress errors; connection failures are handled at a higher level + $this->smtp_conn = @stream_socket_client( + $host . ":" . $port, + $errno, + $errstr, + $timeout, + STREAM_CLIENT_CONNECT, + $socket_context + ); + } 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 + ); + $this->smtp_conn = fsockopen( + $host, + $port, + $errno, + $errstr, + $timeout + ); + } + // Verify we connected properly + if (!is_resource($this->smtp_conn)) { + $this->setError( + 'Failed to connect to server', + $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 (substr(PHP_OS, 0, 3) != 'WIN') { + $max = ini_get('max_execution_time'); + // Don't bother if unlimited + if ($max != 0 && $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. + * @access public + * @return boolean + */ + public function startTLS() + { + if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { + return false; + } + // Begin encrypted connection + if (!stream_socket_enable_crypto( + $this->smtp_conn, + true, + STREAM_CRYPTO_METHOD_TLS_CLIENT + )) { + return false; + } + return true; + } + + /** + * 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 (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2) + * @param string $realm The auth realm for NTLM + * @param string $workstation The auth workstation for NTLM + * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth) + * @return bool True if successfully authenticated.* @access public + */ + public function authenticate( + $username, + $password, + $authtype = null, + $realm = '', + $workstation = '', + $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. Let's 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; + } + + self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL); + self::edebug( + 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']), + self::DEBUG_LOWLEVEL + ); + + if (empty($authtype)) { + foreach (array('LOGIN', 'CRAM-MD5', 'NTLM', 'PLAIN', 'XOAUTH2') as $method) { + if (in_array($method, $this->server_caps['AUTH'])) { + $authtype = $method; + break; + } + } + if (empty($authtype)) { + $this->setError('No supported authentication methods found'); + return false; + } + self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL); + } + + if (!in_array($authtype, $this->server_caps['AUTH'])) { + $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 'XOAUTH2': + //If the OAuth Instance is not set. Can be a case when PHPMailer is used + //instead of PHPMailerOAuth + if (is_null($OAuth)) { + return false; + } + $oauth = $OAuth->getOauth64(); + + // Start authentication + if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) { + return false; + } + break; + case 'NTLM': + /* + * ntlm_sasl_client.php + * Bundled with Permission + * + * How to telnet in windows: + * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx + * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication + */ + require_once 'extras/ntlm_sasl_client.php'; + $temp = new stdClass; + $ntlm_client = new ntlm_sasl_client_class; + //Check that functions are available + if (!$ntlm_client->Initialize($temp)) { + $this->setError($temp->error); + $this->edebug( + 'You need to enable some modules in your php.ini file: ' + . $this->error['error'], + self::DEBUG_CLIENT + ); + return false; + } + //msg1 + $msg1 = $ntlm_client->TypeMsg1($realm, $workstation); //msg1 + + if (!$this->sendCommand( + 'AUTH NTLM', + 'AUTH NTLM ' . base64_encode($msg1), + 334 + ) + ) { + return false; + } + //Though 0 based, there is a white space after the 3 digit number + //msg2 + $challenge = substr($this->last_reply, 3); + $challenge = base64_decode($challenge); + $ntlm_res = $ntlm_client->NTLMResponse( + substr($challenge, 24, 8), + $password + ); + //msg3 + $msg3 = $ntlm_client->TypeMsg3( + $ntlm_res, + $username, + $realm, + $workstation + ); + // send encoded username + return $this->sendCommand('Username', base64_encode($msg3), 235); + 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); + 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 + * @access protected + * @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. + * @access public + * @return boolean 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() + * @access public + * @return void + */ + 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 and additional . + * Implements rfc 821: DATA + * @param string $msg_data Message data to send + * @access public + * @return boolean + */ + 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 CRLF) + * 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(array("\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 = array(); + if ($in_headers and $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) and $line_out[0] == '.') { + $line_out = '.' . $line_out; + } + $this->client_send($line_out . self::CRLF); + } + } + + //Message data has been sent, complete the command + //Increase timelimit for end of DATA command + $savetimelimit = $this->Timelimit; + $this->Timelimit = $this->Timelimit * 2; + $result = $this->sendCommand('DATA END', '.', 250); + //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 + * @access public + * @return boolean + */ + public function hello($host = '') + { + //Try extended hello first (RFC 2821) + return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); + } + + /** + * Send an SMTP HELO or EHLO command. + * Low-level implementation used by hello() + * @see hello() + * @param string $hello The HELO string + * @param string $host The hostname to say we are + * @access protected + * @return boolean + */ + 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. + * @access protected + * @param string $type - 'HELO' or 'EHLO' + */ + protected function parseHelloFields($type) + { + $this->server_caps = array(); + $lines = explode("\n", $this->last_reply); + + 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 = array(); + } + 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 + * @access public + * @return boolean + */ + 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 boolean $close_on_error Should the connection close if an error occurs? + * @access public + * @return boolean + */ + public function quit($close_on_error = true) + { + $noerror = $this->sendCommand('QUIT', 'QUIT', 221); + $err = $this->error; //Save any error + if ($noerror or $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 + * @access public + * @return boolean + */ + public function recipient($address) + { + return $this->sendCommand( + 'RCPT TO', + 'RCPT TO:<' . $address . '>', + array(250, 251) + ); + } + + /** + * Send an SMTP RSET command. + * Abort any transaction that is currently in progress. + * Implements rfc 821: RSET + * @access public + * @return boolean 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 integer|array $expect One or more expected integer success codes + * @access protected + * @return boolean 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 or strpos($commandstring, "\r") !== false) { + $this->setError("Command '$command' contained line breaks"); + return false; + } + $this->client_send($commandstring . self::CRLF); + + $this->last_reply = $this->get_lines(); + // Fetch SMTP code and possible error code explanation + $matches = array(); + if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) { + $code = $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 = 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)) { + $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 + * @access public + * @return boolean + */ + public function sendAndMail($from) + { + return $this->sendCommand('SAML', "SAML FROM:$from", 250); + } + + /** + * Send an SMTP VRFY command. + * @param string $name The name to verify + * @access public + * @return boolean + */ + public function verify($name) + { + return $this->sendCommand('VRFY', "VRFY $name", array(250, 251)); + } + + /** + * Send an SMTP NOOP command. + * Used to keep keep-alives alive, doesn't actually do anything + * @access public + * @return boolean + */ + 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 + * @access public + * @return boolean + */ + 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 + * @access public + * @return integer|boolean The number of bytes sent to the server or false on error + */ + public function client_send($data) + { + $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT); + return fwrite($this->smtp_conn, $data); + } + + /** + * Get the latest error. + * @access public + * @return array + */ + public function getError() + { + return $this->error; + } + + /** + * Get SMTP extensions available on the server + * @access public + * @return array|null + */ + public function getServerExtList() + { + return $this->server_caps; + } + + /** + * A multipurpose method + * The method works in three ways, dependent on argument value and current state + * 1. HELO/EHLO was not sent - returns null and set up $this->error + * 2. HELO was sent + * $name = 'HELO': returns server name + * $name = 'EHLO': returns boolean false + * $name = any string: returns null and set up $this->error + * 3. EHLO was sent + * $name = 'HELO'|'EHLO': returns server name + * $name = any string: if extension $name exists, returns boolean True + * or its options. Otherwise returns boolean False + * In other words, one can use this method to detect 3 conditions: + * - null returned: handshake was not or we don't know about ext (refer to $this->error) + * - false returned: the requested feature exactly not exists + * - positive value returned: the requested feature exists + * @param string $name Name of SMTP extension or 'HELO'|'EHLO' + * @return mixed + */ + public function getServerExt($name) + { + if (!$this->server_caps) { + $this->setError('No HELO/EHLO was sent'); + return null; + } + + // the tight logic knot ;) + if (!array_key_exists($name, $this->server_caps)) { + if ($name == 'HELO') { + return $this->server_caps['EHLO']; + } + if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) { + return false; + } + $this->setError('HELO handshake was used. Client knows nothing about server extensions'); + return null; + } + + return $this->server_caps[$name]; + } + + /** + * Get the last reply from the server. + * @access public + * @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. + * @access protected + * @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; + } + while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { + $str = @fgets($this->smtp_conn, 515); + $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL); + $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL); + $data .= $str; + // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen + if ((isset($str[3]) and $str[3] == ' ')) { + 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 and 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 boolean $enabled + */ + public function setVerp($enabled = false) + { + $this->do_verp = $enabled; + } + + /** + * Get VERP address generation mode. + * @return boolean + */ + 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 = array( + '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 integer $level + */ + public function setDebugLevel($level = 0) + { + $this->do_debug = $level; + } + + /** + * Get debug output level. + * @return integer + */ + public function getDebugLevel() + { + return $this->do_debug; + } + + /** + * Set SMTP timeout. + * @param integer $timeout + */ + public function setTimeout($timeout = 0) + { + $this->Timeout = $timeout; + } + + /** + * Get SMTP timeout. + * @return integer + */ + public function getTimeout() + { + return $this->Timeout; + } +} diff --git a/include/util.php b/include/util.php new file mode 100644 index 0000000..1aceb86 --- /dev/null +++ b/include/util.php @@ -0,0 +1,127 @@ +"ene", "feb", "mar", "abr", "may", "jun", "jul", "ago", "sep", "oct", "nov", "dic"); + $fechaTxt = trim($fechaTxt); + if(substr($fechaTxt,2,1) == "/" && substr($fechaTxt,5,1) == "/"){// dd/mm/aaaa + $fechaArr = explode("/", $fechaTxt); + return $meses[intval($fechaArr[1])].", ".$fechaArr[2]; + } + if(substr($fechaTxt,4,1) == "-" && substr($fechaTxt,7,1) == "-"){// aaaa-mm-dd + $fechaArr = explode("-", $fechaTxt); + return $meses[intval($fechaArr[1])].", ".$fechaArr[0]; + } + return ""; +} + + +function fechaMes($fechaTxt){ + $fechaTxt = trim($fechaTxt); + if(substr($fechaTxt,2,1) == "/" && substr($fechaTxt,5,1) == "/"){// dd/mm/aaaa + $fechaArr = explode("/", $fechaTxt); + return intval(mesNombre($fechaArr[1])." ".$fechaArr[2]); + } + if(substr($fechaTxt,4,1) == "-" && substr($fechaTxt,7,1) == "-"){// aaaa-mm-dd + $fechaArr = explode("-", $fechaTxt); + return intval(mesNombre($fechaArr[2])." ".$fechaArr[1]); + } + return ""; +} + +function mesNombre($num){ + $meses=array(1=>"enero", "febrero", "marzo", "abril", "mayo", "junio", "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"); + return $meses[intval($num)]; +} + +function diaNombre($num){ + $dias=array("domingo", "lunes", "martes", "miércoles", "jueves", "viernes", "sábado"); + return $dias[intval($num)]; +} + +function horaMin($arr, $campo = "Horario_hora"){ + $min = ""; + foreach($arr as $horario){ + if($min == "" || date('H:i', strtotime($horario[$campo])) < date('H:i', strtotime($min))){ + $min = $horario[$campo]; + } + } + return date('H:i', strtotime($min)); +} + +function horaMax($arr, $campo = "Horario_hora_final"){ + $max = ""; + foreach($arr as $horario){ + if($max == "" || date('H:i', strtotime($horario[$campo])) > date('H:i', strtotime($max))){ + $max = $horario[$campo]; + } + } + return date('H:i', strtotime($max)); +} +function duracionMinutos($fechahora_i, $fechahora_f){ + return round((strtotime($fechahora_f) - strtotime($fechahora_i)) / 60,2); +} + +function validaPassword($pass){ + $expr = '/^\S*(?=\S{5,})(?=\S*[a-zA-Z])(?=\S*[\d])(?=\S*[\W])\S*$/'; + return preg_match($expr, $pass); +} \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..23e3138 --- /dev/null +++ b/index.php @@ -0,0 +1,73 @@ + + + + + + + .: Acceso Asistencia Profesores :. + + + + + + + + + + + +
+
+
+
+

Iniciar sesión

+
+
+
+
+
+

Utiliza tu usuario y contraseña institucionales

+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+ +

¡ERROR!

+ +

+ +

+
+
+
+ + + + + + + + + + diff --git a/js/auditoría.js b/js/auditoría.js new file mode 100644 index 0000000..4fe8ae3 --- /dev/null +++ b/js/auditoría.js @@ -0,0 +1,160 @@ +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; +const store = reactive({ + loading: false, + current: { + comentario: '', + clase_vista: null, + empty: '', + }, + facultades: { + data: [], + async fetch() { + this.data = []; + const res = await fetch('action/action_facultad.php'); + this.data = await res.json(); + }, + }, + filters: { + facultad_id: null, + fecha: null, + fecha_inicio: null, + fecha_fin: null, + profesor: null, + estados: [], + switchFecha: false, + switchFechas() { + $(function () { + store.filters.fecha_inicio = store.filters.fecha_fin = store.filters.fecha = null; + $("#fecha, #fecha_inicio, #fecha_fin").datepicker({ + minDate: -3, + maxDate: new Date(), + dateFormat: "yy-mm-dd", + showAnim: "slide", + }); + const fecha = $("#fecha"), inicio = $("#fecha_inicio"), fin = $("#fecha_fin"); + inicio.on("change", function () { + store.filters.fecha_inicio = inicio.val(); + fin.datepicker("option", "minDate", inicio.val()); + }); + fin.on("change", function () { + store.filters.fecha_fin = fin.val(); + inicio.datepicker("option", "maxDate", fin.val()); + }); + fecha.on("change", function () { + store.filters.fecha = fecha.val(); + }); + }); + } + }, + estados: { + data: [], + async fetch() { + this.data = []; + const res = await fetch('action/action_estado_supervisor.php'); + this.data = await res.json(); + }, + getEstado(id) { + return this.data.find((estado) => estado.estado_supervisor_id === id); + }, + printEstados() { + if (store.filters.estados.length > 0) + document.querySelector('#estados').innerHTML = store.filters.estados.map((estado) => ` + ${store.estados.getEstado(estado).nombre} + `).join(''); + else + document.querySelector('#estados').innerHTML = `Todos los registros`; + } + }, + toggle(arr, element) { + const newArray = arr.includes(element) ? arr.filter((item) => item !== element) : [...arr, element]; + // if all are selected, then unselect all + if (newArray.length === this.estados.data.length) + return []; + return newArray; + }, +}); +createApp({ + store, + get clase_vista() { + return store.current.clase_vista; + }, + registros: { + data: [], + async fetch() { + this.loading = true; + this.data = []; + const res = await fetch('action/action_auditoria.php'); + this.data = await res.json(); + this.loading = false; + }, + invertir() { + this.data = this.data.reverse(); + }, + mostrarComentario(registro_id) { + const registro = this.data.find((registro) => registro.registro_id === registro_id); + store.current.comentario = registro.comentario; + $('#ver-comentario').modal('show'); + }, + get relevant() { + /* + facultad_id: null, + fecha: null, + fecha_inicio: null, + fecha_fin: null, + profesor: null, + asistencia: null, + estado_id: null, + if one of the filters is null, then it is not relevant + + */ + const filters = Object.keys(store.filters).filter((filtro) => store.filters[filtro] || store.filters[filtro]?.length > 0); + return this.data.filter((registro) => { + return filters.every((filtro) => { + switch (filtro) { + case 'fecha': + return registro.registro_fecha_ideal === store.filters[filtro]; + case 'fecha_inicio': + return registro.registro_fecha_ideal >= store.filters[filtro]; + case 'fecha_fin': + return registro.registro_fecha_ideal <= store.filters[filtro]; + case 'profesor': + const textoFiltro = store.filters[filtro].toLowerCase(); + if (/^\([^)]+\)\s[\s\S]+$/.test(textoFiltro)) { + const clave = registro.profesor_clave.toLowerCase(); + const filtroClave = textoFiltro.match(/\((.*?)\)/)?.[1]; + console.log(clave, filtroClave); + return clave.includes(filtroClave); + } + else { + const nombre = registro.profesor_nombre.toLowerCase(); + return nombre.includes(textoFiltro); + } + case 'facultad_id': + return registro.facultad_id === store.filters[filtro]; + case 'estados': + if (store.filters[filtro].length === 0) + return true; + return store.filters[filtro].includes(registro.estado_supervisor_id); + default: + return true; + } + }); + }); + }, + }, + get profesores() { + return this.registros.data.map((registro) => ({ + profesor_id: registro.profesor_id, + profesor_nombre: registro.profesor_nombre, + profesor_correo: registro.profesor_correo, + profesor_clave: registro.profesor_clave, + profesor_grado: registro.profesor_grado, + })).sort((a, b) => a.profesor_nombre.localeCompare(b.profesor_nombre)); + }, + async mounted() { + await this.registros.fetch(); + await store.facultades.fetch(); + await store.estados.fetch(); + store.filters.switchFechas(); + } +}).mount('#app'); diff --git a/js/barra.js b/js/barra.js new file mode 100644 index 0000000..44b7e69 --- /dev/null +++ b/js/barra.js @@ -0,0 +1,41 @@ +function barra(profesor, retardos) { + profesor.faltas = profesor.total - profesor.asistencias - profesor.retardos - profesor.justificaciones; + if (profesor.total != 0) + var porcentajes = { + "asistencias": profesor.asistencias / profesor.total * 100, + "retardos": profesor.retardos / profesor.total * 100, + "justificaciones": profesor.justificaciones / profesor.total * 100, + "faltas": 100 * profesor.faltas / profesor.total + } + else + var porcentajes = { + "asistencias": 0, + "retardos": 0, + "justificaciones": 0, + "faltas": 0 + } + var html = ` +
+
+
+
+
+ + ${retardos ? `
` : ``} +
+
+
+
+
+ + +
+ Asistencias: ${profesor.asistencias} + ${retardos ? `Retardos: ${profesor.retardos}` : `` } + Justificaciones: ${profesor.justificaciones} + Faltas: ${profesor.faltas} +
+ +`; + return html; +} \ No newline at end of file diff --git a/js/bootstrap/bootstrap.bundle.min.js b/js/bootstrap/bootstrap.bundle.min.js new file mode 100644 index 0000000..72a46cf --- /dev/null +++ b/js/bootstrap/bootstrap.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v4.1.3 (https://getbootstrap.com/) + * Copyright 2011-2018 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("jquery")):"function"==typeof define&&define.amd?define(["exports","jquery"],t):t(e.bootstrap={},e.jQuery)}(this,function(e,t){"use strict";function i(e,t){for(var n=0;nthis._items.length-1||e<0))if(this._isSliding)k(this._element).one(q.SLID,function(){return t.to(e)});else{if(n===e)return this.pause(),void this.cycle();var i=n=i.clientWidth&&n>=i.clientHeight}),u=0l[e]&&!i.escapeWithReference&&(n=Math.min(u[t],l[e]-("right"===e?u.width:u.height))),Ve({},t,n)}};return c.forEach(function(e){var t=-1!==["left","top"].indexOf(e)?"primary":"secondary";u=ze({},u,f[t](e))}),e.offsets.popper=u,e},priority:["left","right","top","bottom"],padding:5,boundariesElement:"scrollParent"},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,n=t.popper,i=t.reference,r=e.placement.split("-")[0],o=Math.floor,s=-1!==["top","bottom"].indexOf(r),a=s?"right":"bottom",l=s?"left":"top",c=s?"width":"height";return n[a]o(i[a])&&(e.offsets.popper[l]=o(i[a])),e}},arrow:{order:500,enabled:!0,fn:function(e,t){var n;if(!pt(e.instance.modifiers,"arrow","keepTogether"))return e;var i=t.element;if("string"==typeof i){if(!(i=e.instance.popper.querySelector(i)))return e}else if(!e.instance.popper.contains(i))return console.warn("WARNING: `arrow.element` must be child of its popper element!"),e;var r=e.placement.split("-")[0],o=e.offsets,s=o.popper,a=o.reference,l=-1!==["left","right"].indexOf(r),c=l?"height":"width",u=l?"Top":"Left",f=u.toLowerCase(),h=l?"left":"top",d=l?"bottom":"right",p=nt(i)[c];a[d]-ps[d]&&(e.offsets.popper[f]+=a[f]+p-s[d]),e.offsets.popper=Ge(e.offsets.popper);var m=a[f]+a[c]/2-p/2,g=Pe(e.instance.popper),_=parseFloat(g["margin"+u],10),v=parseFloat(g["border"+u+"Width"],10),y=m-e.offsets.popper[f]-_-v;return y=Math.max(Math.min(s[c]-p,y),0),e.arrowElement=i,e.offsets.arrow=(Ve(n={},f,Math.round(y)),Ve(n,h,""),n),e},element:"[x-arrow]"},flip:{order:600,enabled:!0,fn:function(p,m){if(at(p.instance.modifiers,"inner"))return p;if(p.flipped&&p.placement===p.originalPlacement)return p;var g=$e(p.instance.popper,p.instance.reference,m.padding,m.boundariesElement,p.positionFixed),_=p.placement.split("-")[0],v=it(_),y=p.placement.split("-")[1]||"",E=[];switch(m.behavior){case vt:E=[_,v];break;case yt:E=_t(_);break;case Et:E=_t(_,!0);break;default:E=m.behavior}return E.forEach(function(e,t){if(_!==e||E.length===t+1)return p;_=p.placement.split("-")[0],v=it(_);var n,i=p.offsets.popper,r=p.offsets.reference,o=Math.floor,s="left"===_&&o(i.right)>o(r.left)||"right"===_&&o(i.left)o(r.top)||"bottom"===_&&o(i.top)o(g.right),c=o(i.top)o(g.bottom),f="left"===_&&a||"right"===_&&l||"top"===_&&c||"bottom"===_&&u,h=-1!==["top","bottom"].indexOf(_),d=!!m.flipVariations&&(h&&"start"===y&&a||h&&"end"===y&&l||!h&&"start"===y&&c||!h&&"end"===y&&u);(s||f||d)&&(p.flipped=!0,(s||f)&&(_=E[t+1]),d&&(y="end"===(n=y)?"start":"start"===n?"end":n),p.placement=_+(y?"-"+y:""),p.offsets.popper=ze({},p.offsets.popper,rt(p.instance.popper,p.offsets.reference,p.placement)),p=st(p.instance.modifiers,p,"flip"))}),p},behavior:"flip",padding:5,boundariesElement:"viewport"},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,n=t.split("-")[0],i=e.offsets,r=i.popper,o=i.reference,s=-1!==["left","right"].indexOf(n),a=-1===["top","left"].indexOf(n);return r[s?"left":"top"]=o[n]-(a?r[s?"width":"height"]:0),e.placement=it(t),e.offsets.popper=Ge(r),e}},hide:{order:800,enabled:!0,fn:function(e){if(!pt(e.instance.modifiers,"hide","preventOverflow"))return e;var t=e.offsets.reference,n=ot(e.instance.modifiers,function(e){return"preventOverflow"===e.name}).boundaries;if(t.bottomn.right||t.top>n.bottom||t.rightdocument.documentElement.clientHeight;!this._isBodyOverflowing&&e&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!e&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},e._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},e._checkScrollbar=function(){var e=document.body.getBoundingClientRect();this._isBodyOverflowing=e.left+e.right
',trigger:"hover focus",title:"",delay:0,html:!(An={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"}),selector:!(Dn={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)"}),placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},Nn="out",kn={HIDE:"hide"+wn,HIDDEN:"hidden"+wn,SHOW:(On="show")+wn,SHOWN:"shown"+wn,INSERTED:"inserted"+wn,CLICK:"click"+wn,FOCUSIN:"focusin"+wn,FOCUSOUT:"focusout"+wn,MOUSEENTER:"mouseenter"+wn,MOUSELEAVE:"mouseleave"+wn},xn="fade",Pn="show",Ln=".tooltip-inner",jn=".arrow",Hn="hover",Mn="focus",Fn="click",Wn="manual",Rn=function(){function i(e,t){if("undefined"==typeof Ct)throw new TypeError("Bootstrap tooltips require Popper.js (https://popper.js.org)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=e,this.config=this._getConfig(t),this.tip=null,this._setListeners()}var e=i.prototype;return e.enable=function(){this._isEnabled=!0},e.disable=function(){this._isEnabled=!1},e.toggleEnabled=function(){this._isEnabled=!this._isEnabled},e.toggle=function(e){if(this._isEnabled)if(e){var t=this.constructor.DATA_KEY,n=yn(e.currentTarget).data(t);n||(n=new this.constructor(e.currentTarget,this._getDelegateConfig()),yn(e.currentTarget).data(t,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(yn(this.getTipElement()).hasClass(Pn))return void this._leave(null,this);this._enter(null,this)}},e.dispose=function(){clearTimeout(this._timeout),yn.removeData(this.element,this.constructor.DATA_KEY),yn(this.element).off(this.constructor.EVENT_KEY),yn(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&yn(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},e.show=function(){var t=this;if("none"===yn(this.element).css("display"))throw new Error("Please use show on visible elements");var e=yn.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){yn(this.element).trigger(e);var n=yn.contains(this.element.ownerDocument.documentElement,this.element);if(e.isDefaultPrevented()||!n)return;var i=this.getTipElement(),r=we.getUID(this.constructor.NAME);i.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&yn(i).addClass(xn);var o="function"==typeof this.config.placement?this.config.placement.call(this,i,this.element):this.config.placement,s=this._getAttachment(o);this.addAttachmentClass(s);var a=!1===this.config.container?document.body:yn(document).find(this.config.container);yn(i).data(this.constructor.DATA_KEY,this),yn.contains(this.element.ownerDocument.documentElement,this.tip)||yn(i).appendTo(a),yn(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new Ct(this.element,i,{placement:s,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:jn},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(e){e.originalPlacement!==e.placement&&t._handlePopperPlacementChange(e)},onUpdate:function(e){t._handlePopperPlacementChange(e)}}),yn(i).addClass(Pn),"ontouchstart"in document.documentElement&&yn(document.body).children().on("mouseover",null,yn.noop);var l=function(){t.config.animation&&t._fixTransition();var e=t._hoverState;t._hoverState=null,yn(t.element).trigger(t.constructor.Event.SHOWN),e===Nn&&t._leave(null,t)};if(yn(this.tip).hasClass(xn)){var c=we.getTransitionDurationFromElement(this.tip);yn(this.tip).one(we.TRANSITION_END,l).emulateTransitionEnd(c)}else l()}},e.hide=function(e){var t=this,n=this.getTipElement(),i=yn.Event(this.constructor.Event.HIDE),r=function(){t._hoverState!==On&&n.parentNode&&n.parentNode.removeChild(n),t._cleanTipClass(),t.element.removeAttribute("aria-describedby"),yn(t.element).trigger(t.constructor.Event.HIDDEN),null!==t._popper&&t._popper.destroy(),e&&e()};if(yn(this.element).trigger(i),!i.isDefaultPrevented()){if(yn(n).removeClass(Pn),"ontouchstart"in document.documentElement&&yn(document.body).children().off("mouseover",null,yn.noop),this._activeTrigger[Fn]=!1,this._activeTrigger[Mn]=!1,this._activeTrigger[Hn]=!1,yn(this.tip).hasClass(xn)){var o=we.getTransitionDurationFromElement(n);yn(n).one(we.TRANSITION_END,r).emulateTransitionEnd(o)}else r();this._hoverState=""}},e.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},e.isWithContent=function(){return Boolean(this.getTitle())},e.addAttachmentClass=function(e){yn(this.getTipElement()).addClass(Tn+"-"+e)},e.getTipElement=function(){return this.tip=this.tip||yn(this.config.template)[0],this.tip},e.setContent=function(){var e=this.getTipElement();this.setElementContent(yn(e.querySelectorAll(Ln)),this.getTitle()),yn(e).removeClass(xn+" "+Pn)},e.setElementContent=function(e,t){var n=this.config.html;"object"==typeof t&&(t.nodeType||t.jquery)?n?yn(t).parent().is(e)||e.empty().append(t):e.text(yn(t).text()):e[n?"html":"text"](t)},e.getTitle=function(){var e=this.element.getAttribute("data-original-title");return e||(e="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),e},e._getAttachment=function(e){return An[e.toUpperCase()]},e._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(e){if("click"===e)yn(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(e){return i.toggle(e)});else if(e!==Wn){var t=e===Hn?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=e===Hn?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;yn(i.element).on(t,i.config.selector,function(e){return i._enter(e)}).on(n,i.config.selector,function(e){return i._leave(e)})}yn(i.element).closest(".modal").on("hide.bs.modal",function(){return i.hide()})}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},e._fixTitle=function(){var e=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==e)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},e._enter=function(e,t){var n=this.constructor.DATA_KEY;(t=t||yn(e.currentTarget).data(n))||(t=new this.constructor(e.currentTarget,this._getDelegateConfig()),yn(e.currentTarget).data(n,t)),e&&(t._activeTrigger["focusin"===e.type?Mn:Hn]=!0),yn(t.getTipElement()).hasClass(Pn)||t._hoverState===On?t._hoverState=On:(clearTimeout(t._timeout),t._hoverState=On,t.config.delay&&t.config.delay.show?t._timeout=setTimeout(function(){t._hoverState===On&&t.show()},t.config.delay.show):t.show())},e._leave=function(e,t){var n=this.constructor.DATA_KEY;(t=t||yn(e.currentTarget).data(n))||(t=new this.constructor(e.currentTarget,this._getDelegateConfig()),yn(e.currentTarget).data(n,t)),e&&(t._activeTrigger["focusout"===e.type?Mn:Hn]=!1),t._isWithActiveTrigger()||(clearTimeout(t._timeout),t._hoverState=Nn,t.config.delay&&t.config.delay.hide?t._timeout=setTimeout(function(){t._hoverState===Nn&&t.hide()},t.config.delay.hide):t.hide())},e._isWithActiveTrigger=function(){for(var e in this._activeTrigger)if(this._activeTrigger[e])return!0;return!1},e._getConfig=function(e){return"number"==typeof(e=l({},this.constructor.Default,yn(this.element).data(),"object"==typeof e&&e?e:{})).delay&&(e.delay={show:e.delay,hide:e.delay}),"number"==typeof e.title&&(e.title=e.title.toString()),"number"==typeof e.content&&(e.content=e.content.toString()),we.typeCheckConfig(En,e,this.constructor.DefaultType),e},e._getDelegateConfig=function(){var e={};if(this.config)for(var t in this.config)this.constructor.Default[t]!==this.config[t]&&(e[t]=this.config[t]);return e},e._cleanTipClass=function(){var e=yn(this.getTipElement()),t=e.attr("class").match(Sn);null!==t&&t.length&&e.removeClass(t.join(""))},e._handlePopperPlacementChange=function(e){var t=e.instance;this.tip=t.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(e.placement))},e._fixTransition=function(){var e=this.getTipElement(),t=this.config.animation;null===e.getAttribute("x-placement")&&(yn(e).removeClass(xn),this.config.animation=!1,this.hide(),this.show(),this.config.animation=t)},i._jQueryInterface=function(n){return this.each(function(){var e=yn(this).data(bn),t="object"==typeof n&&n;if((e||!/dispose|hide/.test(n))&&(e||(e=new i(this,t),yn(this).data(bn,e)),"string"==typeof n)){if("undefined"==typeof e[n])throw new TypeError('No method named "'+n+'"');e[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.1.3"}},{key:"Default",get:function(){return In}},{key:"NAME",get:function(){return En}},{key:"DATA_KEY",get:function(){return bn}},{key:"Event",get:function(){return kn}},{key:"EVENT_KEY",get:function(){return wn}},{key:"DefaultType",get:function(){return Dn}}]),i}(),yn.fn[En]=Rn._jQueryInterface,yn.fn[En].Constructor=Rn,yn.fn[En].noConflict=function(){return yn.fn[En]=Cn,Rn._jQueryInterface},Rn),Qi=(Bn="popover",Kn="."+(qn="bs.popover"),Qn=(Un=t).fn[Bn],Yn="bs-popover",Vn=new RegExp("(^|\\s)"+Yn+"\\S+","g"),zn=l({},Ki.Default,{placement:"right",trigger:"click",content:"",template:''}),Gn=l({},Ki.DefaultType,{content:"(string|element|function)"}),Jn="fade",Xn=".popover-header",$n=".popover-body",ei={HIDE:"hide"+Kn,HIDDEN:"hidden"+Kn,SHOW:(Zn="show")+Kn,SHOWN:"shown"+Kn,INSERTED:"inserted"+Kn,CLICK:"click"+Kn,FOCUSIN:"focusin"+Kn,FOCUSOUT:"focusout"+Kn,MOUSEENTER:"mouseenter"+Kn,MOUSELEAVE:"mouseleave"+Kn},ti=function(e){var t,n;function i(){return e.apply(this,arguments)||this}n=e,(t=i).prototype=Object.create(n.prototype),(t.prototype.constructor=t).__proto__=n;var r=i.prototype;return r.isWithContent=function(){return this.getTitle()||this._getContent()},r.addAttachmentClass=function(e){Un(this.getTipElement()).addClass(Yn+"-"+e)},r.getTipElement=function(){return this.tip=this.tip||Un(this.config.template)[0],this.tip},r.setContent=function(){var e=Un(this.getTipElement());this.setElementContent(e.find(Xn),this.getTitle());var t=this._getContent();"function"==typeof t&&(t=t.call(this.element)),this.setElementContent(e.find($n),t),e.removeClass(Jn+" "+Zn)},r._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},r._cleanTipClass=function(){var e=Un(this.getTipElement()),t=e.attr("class").match(Vn);null!==t&&0=this._offsets[r]&&("undefined"==typeof this._offsets[r+1]||ethis._items.length-1||t<0))if(this._isSliding)P(this._element).one(Q.SLID,function(){return e.to(t)});else{if(n===t)return this.pause(),void this.cycle();var i=ndocument.documentElement.clientHeight;!this._isBodyOverflowing&&t&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!t&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},t._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},t._checkScrollbar=function(){var t=document.body.getBoundingClientRect();this._isBodyOverflowing=t.left+t.right
',trigger:"hover focus",title:"",delay:0,html:!(Ie={AUTO:"auto",TOP:"top",RIGHT:"right",BOTTOM:"bottom",LEFT:"left"}),selector:!(Se={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(number|string)",container:"(string|element|boolean)",fallbackPlacement:"(string|array)",boundary:"(string|element)"}),placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent"},we="out",Ne={HIDE:"hide"+Ee,HIDDEN:"hidden"+Ee,SHOW:(De="show")+Ee,SHOWN:"shown"+Ee,INSERTED:"inserted"+Ee,CLICK:"click"+Ee,FOCUSIN:"focusin"+Ee,FOCUSOUT:"focusout"+Ee,MOUSEENTER:"mouseenter"+Ee,MOUSELEAVE:"mouseleave"+Ee},Oe="fade",ke="show",Pe=".tooltip-inner",je=".arrow",He="hover",Le="focus",Re="click",xe="manual",We=function(){function i(t,e){if("undefined"==typeof h)throw new TypeError("Bootstrap 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=pe(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),pe(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(pe(this.getTipElement()).hasClass(ke))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),pe.removeData(this.element,this.constructor.DATA_KEY),pe(this.element).off(this.constructor.EVENT_KEY),pe(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&pe(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"===pe(this.element).css("display"))throw new Error("Please use show on visible elements");var t=pe.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){pe(this.element).trigger(t);var n=pe.contains(this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!n)return;var i=this.getTipElement(),r=Fn.getUID(this.constructor.NAME);i.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&pe(i).addClass(Oe);var o="function"==typeof this.config.placement?this.config.placement.call(this,i,this.element):this.config.placement,s=this._getAttachment(o);this.addAttachmentClass(s);var a=!1===this.config.container?document.body:pe(document).find(this.config.container);pe(i).data(this.constructor.DATA_KEY,this),pe.contains(this.element.ownerDocument.documentElement,this.tip)||pe(i).appendTo(a),pe(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new h(this.element,i,{placement:s,modifiers:{offset:{offset:this.config.offset},flip:{behavior:this.config.fallbackPlacement},arrow:{element:je},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){e._handlePopperPlacementChange(t)}}),pe(i).addClass(ke),"ontouchstart"in document.documentElement&&pe(document.body).children().on("mouseover",null,pe.noop);var l=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,pe(e.element).trigger(e.constructor.Event.SHOWN),t===we&&e._leave(null,e)};if(pe(this.tip).hasClass(Oe)){var c=Fn.getTransitionDurationFromElement(this.tip);pe(this.tip).one(Fn.TRANSITION_END,l).emulateTransitionEnd(c)}else l()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=pe.Event(this.constructor.Event.HIDE),r=function(){e._hoverState!==De&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),pe(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(pe(this.element).trigger(i),!i.isDefaultPrevented()){if(pe(n).removeClass(ke),"ontouchstart"in document.documentElement&&pe(document.body).children().off("mouseover",null,pe.noop),this._activeTrigger[Re]=!1,this._activeTrigger[Le]=!1,this._activeTrigger[He]=!1,pe(this.tip).hasClass(Oe)){var o=Fn.getTransitionDurationFromElement(n);pe(n).one(Fn.TRANSITION_END,r).emulateTransitionEnd(o)}else r();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){pe(this.getTipElement()).addClass(Te+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||pe(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(pe(t.querySelectorAll(Pe)),this.getTitle()),pe(t).removeClass(Oe+" "+ke)},t.setElementContent=function(t,e){var n=this.config.html;"object"==typeof e&&(e.nodeType||e.jquery)?n?pe(e).parent().is(t)||t.empty().append(e):t.text(pe(e).text()):t[n?"html":"text"](e)},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._getAttachment=function(t){return Ie[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)pe(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==xe){var e=t===He?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===He?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;pe(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}pe(i.element).closest(".modal").on("hide.bs.modal",function(){return 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||pe(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),pe(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Le:He]=!0),pe(e.getTipElement()).hasClass(ke)||e._hoverState===De?e._hoverState=De:(clearTimeout(e._timeout),e._hoverState=De,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===De&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||pe(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),pe(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Le:He]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=we,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===we&&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){return"number"==typeof(t=l({},this.constructor.Default,pe(this.element).data(),"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()),Fn.typeCheckConfig(ve,t,this.constructor.DefaultType),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=pe(this.getTipElement()),e=t.attr("class").match(be);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")&&(pe(t).removeClass(Oe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=pe(this).data(ye),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),pe(this).data(ye,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.1.3"}},{key:"Default",get:function(){return Ae}},{key:"NAME",get:function(){return ve}},{key:"DATA_KEY",get:function(){return ye}},{key:"Event",get:function(){return Ne}},{key:"EVENT_KEY",get:function(){return Ee}},{key:"DefaultType",get:function(){return Se}}]),i}(),pe.fn[ve]=We._jQueryInterface,pe.fn[ve].Constructor=We,pe.fn[ve].noConflict=function(){return pe.fn[ve]=Ce,We._jQueryInterface},We),Jn=(qe="popover",Ke="."+(Fe="bs.popover"),Me=(Ue=e).fn[qe],Qe="bs-popover",Be=new RegExp("(^|\\s)"+Qe+"\\S+","g"),Ve=l({},zn.Default,{placement:"right",trigger:"click",content:"",template:''}),Ye=l({},zn.DefaultType,{content:"(string|element|function)"}),ze="fade",Ze=".popover-header",Ge=".popover-body",$e={HIDE:"hide"+Ke,HIDDEN:"hidden"+Ke,SHOW:(Je="show")+Ke,SHOWN:"shown"+Ke,INSERTED:"inserted"+Ke,CLICK:"click"+Ke,FOCUSIN:"focusin"+Ke,FOCUSOUT:"focusout"+Ke,MOUSEENTER:"mouseenter"+Ke,MOUSELEAVE:"mouseleave"+Ke},Xe=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 r=i.prototype;return r.isWithContent=function(){return this.getTitle()||this._getContent()},r.addAttachmentClass=function(t){Ue(this.getTipElement()).addClass(Qe+"-"+t)},r.getTipElement=function(){return this.tip=this.tip||Ue(this.config.template)[0],this.tip},r.setContent=function(){var t=Ue(this.getTipElement());this.setElementContent(t.find(Ze),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(Ge),e),t.removeClass(ze+" "+Je)},r._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},r._cleanTipClass=function(){var t=Ue(this.getTipElement()),e=t.attr("class").match(Be);null!==e&&0=this._offsets[r]&&("undefined"==typeof this._offsets[r+1]||t {\n called = true\n })\n\n setTimeout(() => {\n if (!called) {\n Util.triggerTransitionEnd(this)\n }\n }, duration)\n\n return this\n}\n\nfunction setTransitionEndSupport() {\n $.fn.emulateTransitionEnd = transitionEndEmulator\n $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent()\n}\n\n/**\n * --------------------------------------------------------------------------\n * Public Util Api\n * --------------------------------------------------------------------------\n */\n\nconst Util = {\n TRANSITION_END: 'bsTransitionEnd',\n\n getUID(prefix) {\n do {\n // eslint-disable-next-line no-bitwise\n prefix += ~~(Math.random() * MAX_UID) // \"~~\" acts like a faster Math.floor() here\n } while (document.getElementById(prefix))\n return prefix\n },\n\n getSelectorFromElement(element) {\n let selector = element.getAttribute('data-target')\n\n if (!selector || selector === '#') {\n const hrefAttr = element.getAttribute('href')\n selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''\n }\n\n try {\n return document.querySelector(selector) ? selector : null\n } catch (err) {\n return null\n }\n },\n\n getTransitionDurationFromElement(element) {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let transitionDuration = $(element).css('transition-duration')\n let transitionDelay = $(element).css('transition-delay')\n\n const floatTransitionDuration = parseFloat(transitionDuration)\n const floatTransitionDelay = parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n },\n\n reflow(element) {\n return element.offsetHeight\n },\n\n triggerTransitionEnd(element) {\n $(element).trigger(TRANSITION_END)\n },\n\n // TODO: Remove in v5\n supportsTransitionEnd() {\n return Boolean(TRANSITION_END)\n },\n\n isElement(obj) {\n return (obj[0] || obj).nodeType\n },\n\n typeCheckConfig(componentName, config, configTypes) {\n for (const property in configTypes) {\n if (Object.prototype.hasOwnProperty.call(configTypes, property)) {\n const expectedTypes = configTypes[property]\n const value = config[property]\n const valueType = value && Util.isElement(value)\n ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new Error(\n `${componentName.toUpperCase()}: ` +\n `Option \"${property}\" provided type \"${valueType}\" ` +\n `but expected type \"${expectedTypes}\".`)\n }\n }\n }\n },\n\n findShadowRoot(element) {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return Util.findShadowRoot(element.parentNode)\n },\n\n jQueryDetection() {\n if (typeof $ === 'undefined') {\n throw new TypeError('Bootstrap\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\'s JavaScript.')\n }\n\n const version = $.fn.jquery.split(' ')[0].split('.')\n const minMajor = 1\n const ltMajor = 2\n const minMinor = 9\n const minPatch = 1\n const maxMajor = 4\n\n if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {\n throw new Error('Bootstrap\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0')\n }\n }\n}\n\nUtil.jQueryDetection()\nsetTransitionEndSupport()\n\nexport default Util\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport $ from 'jquery'\nimport Util from './util'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'alert'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\n\nconst SELECTOR_DISMISS = '[data-dismiss=\"alert\"]'\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_ALERT = 'alert'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Alert {\n constructor(element) {\n this._element = element\n }\n\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n // Public\n\n close(element) {\n let rootElement = this._element\n if (element) {\n rootElement = this._getRootElement(element)\n }\n\n const customEvent = this._triggerCloseEvent(rootElement)\n\n if (customEvent.isDefaultPrevented()) {\n return\n }\n\n this._removeElement(rootElement)\n }\n\n dispose() {\n $.removeData(this._element, DATA_KEY)\n this._element = null\n }\n\n // Private\n\n _getRootElement(element) {\n const selector = Util.getSelectorFromElement(element)\n let parent = false\n\n if (selector) {\n parent = document.querySelector(selector)\n }\n\n if (!parent) {\n parent = $(element).closest(`.${CLASS_NAME_ALERT}`)[0]\n }\n\n return parent\n }\n\n _triggerCloseEvent(element) {\n const closeEvent = $.Event(EVENT_CLOSE)\n\n $(element).trigger(closeEvent)\n return closeEvent\n }\n\n _removeElement(element) {\n $(element).removeClass(CLASS_NAME_SHOW)\n\n if (!$(element).hasClass(CLASS_NAME_FADE)) {\n this._destroyElement(element)\n return\n }\n\n const transitionDuration = Util.getTransitionDurationFromElement(element)\n\n $(element)\n .one(Util.TRANSITION_END, (event) => this._destroyElement(element, event))\n .emulateTransitionEnd(transitionDuration)\n }\n\n _destroyElement(element) {\n $(element)\n .detach()\n .trigger(EVENT_CLOSED)\n .remove()\n }\n\n // Static\n\n static _jQueryInterface(config) {\n return this.each(function () {\n const $element = $(this)\n let data = $element.data(DATA_KEY)\n\n if (!data) {\n data = new Alert(this)\n $element.data(DATA_KEY, data)\n }\n\n if (config === 'close') {\n data[config](this)\n }\n })\n }\n\n static _handleDismiss(alertInstance) {\n return function (event) {\n if (event) {\n event.preventDefault()\n }\n\n alertInstance.close(this)\n }\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n$(document).on(\n EVENT_CLICK_DATA_API,\n SELECTOR_DISMISS,\n Alert._handleDismiss(new Alert())\n)\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Alert._jQueryInterface\n$.fn[NAME].Constructor = Alert\n$.fn[NAME].noConflict = () => {\n $.fn[NAME] = JQUERY_NO_CONFLICT\n return Alert._jQueryInterface\n}\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport $ from 'jquery'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'button'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_BUTTON = 'btn'\nconst CLASS_NAME_FOCUS = 'focus'\n\nconst SELECTOR_DATA_TOGGLE_CARROT = '[data-toggle^=\"button\"]'\nconst SELECTOR_DATA_TOGGLES = '[data-toggle=\"buttons\"]'\nconst SELECTOR_DATA_TOGGLE = '[data-toggle=\"button\"]'\nconst SELECTOR_DATA_TOGGLES_BUTTONS = '[data-toggle=\"buttons\"] .btn'\nconst SELECTOR_INPUT = 'input:not([type=\"hidden\"])'\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_BUTTON = '.btn'\n\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_FOCUS_BLUR_DATA_API = `focus${EVENT_KEY}${DATA_API_KEY} ` +\n `blur${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Button {\n constructor(element) {\n this._element = element\n }\n\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n // Public\n\n toggle() {\n let triggerChangeEvent = true\n let addAriaPressed = true\n const rootElement = $(this._element).closest(\n SELECTOR_DATA_TOGGLES\n )[0]\n\n if (rootElement) {\n const input = this._element.querySelector(SELECTOR_INPUT)\n\n if (input) {\n if (input.type === 'radio') {\n if (input.checked &&\n this._element.classList.contains(CLASS_NAME_ACTIVE)) {\n triggerChangeEvent = false\n } else {\n const activeElement = rootElement.querySelector(SELECTOR_ACTIVE)\n\n if (activeElement) {\n $(activeElement).removeClass(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n if (triggerChangeEvent) {\n // if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input\n if (input.type === 'checkbox' || input.type === 'radio') {\n input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE)\n }\n $(input).trigger('change')\n }\n\n input.focus()\n addAriaPressed = false\n }\n }\n\n if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) {\n if (addAriaPressed) {\n this._element.setAttribute('aria-pressed',\n !this._element.classList.contains(CLASS_NAME_ACTIVE))\n }\n\n if (triggerChangeEvent) {\n $(this._element).toggleClass(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n dispose() {\n $.removeData(this._element, DATA_KEY)\n this._element = null\n }\n\n // Static\n\n static _jQueryInterface(config) {\n return this.each(function () {\n let data = $(this).data(DATA_KEY)\n\n if (!data) {\n data = new Button(this)\n $(this).data(DATA_KEY, data)\n }\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n$(document)\n .on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, (event) => {\n let button = event.target\n const initialButton = button\n\n if (!$(button).hasClass(CLASS_NAME_BUTTON)) {\n button = $(button).closest(SELECTOR_BUTTON)[0]\n }\n\n if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) {\n event.preventDefault() // work around Firefox bug #1540995\n } else {\n const inputBtn = button.querySelector(SELECTOR_INPUT)\n\n if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) {\n event.preventDefault() // work around Firefox bug #1540995\n return\n }\n\n if (initialButton.tagName === 'LABEL' && inputBtn && inputBtn.type === 'checkbox') {\n event.preventDefault() // work around event sent to label and input\n }\n Button._jQueryInterface.call($(button), 'toggle')\n }\n })\n .on(EVENT_FOCUS_BLUR_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, (event) => {\n const button = $(event.target).closest(SELECTOR_BUTTON)[0]\n $(button).toggleClass(CLASS_NAME_FOCUS, /^focus(in)?$/.test(event.type))\n })\n\n$(window).on(EVENT_LOAD_DATA_API, () => {\n // ensure correct active class is set to match the controls' actual values/states\n\n // find all checkboxes/readio buttons inside data-toggle groups\n let buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLES_BUTTONS))\n for (let i = 0, len = buttons.length; i < len; i++) {\n const button = buttons[i]\n const input = button.querySelector(SELECTOR_INPUT)\n if (input.checked || input.hasAttribute('checked')) {\n button.classList.add(CLASS_NAME_ACTIVE)\n } else {\n button.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // find all button toggles\n buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE))\n for (let i = 0, len = buttons.length; i < len; i++) {\n const button = buttons[i]\n if (button.getAttribute('aria-pressed') === 'true') {\n button.classList.add(CLASS_NAME_ACTIVE)\n } else {\n button.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Button._jQueryInterface\n$.fn[NAME].Constructor = Button\n$.fn[NAME].noConflict = () => {\n $.fn[NAME] = JQUERY_NO_CONFLICT\n return Button._jQueryInterface\n}\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport $ from 'jquery'\nimport Util from './util'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'carousel'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\nconst ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key\nconst ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n interval : 5000,\n keyboard : true,\n slide : false,\n pause : 'hover',\n wrap : true,\n touch : true\n}\n\nconst DefaultType = {\n interval : '(number|boolean)',\n keyboard : 'boolean',\n slide : '(boolean|string)',\n pause : '(string|boolean)',\n wrap : 'boolean',\n touch : 'boolean'\n}\n\nconst DIRECTION_NEXT = 'next'\nconst DIRECTION_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_RIGHT = 'carousel-item-right'\nconst CLASS_NAME_LEFT = 'carousel-item-left'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ACTIVE_ITEM = '.active.carousel-item'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-slide], [data-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-ride=\"carousel\"]'\n\nconst PointerType = {\n TOUCH : 'touch',\n PEN : 'pen'\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\nclass Carousel {\n constructor(element, config) {\n this._items = null\n this._interval = null\n this._activeElement = null\n this._isPaused = false\n this._isSliding = false\n this.touchTimeout = null\n this.touchStartX = 0\n this.touchDeltaX = 0\n\n this._config = this._getConfig(config)\n this._element = element\n this._indicatorsElement = this._element.querySelector(SELECTOR_INDICATORS)\n this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent)\n\n this._addEventListeners()\n }\n\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n static get Default() {\n return Default\n }\n\n // Public\n\n next() {\n if (!this._isSliding) {\n this._slide(DIRECTION_NEXT)\n }\n }\n\n nextWhenVisible() {\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden &&\n ($(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden')) {\n this.next()\n }\n }\n\n prev() {\n if (!this._isSliding) {\n this._slide(DIRECTION_PREV)\n }\n }\n\n pause(event) {\n if (!event) {\n this._isPaused = true\n }\n\n if (this._element.querySelector(SELECTOR_NEXT_PREV)) {\n Util.triggerTransitionEnd(this._element)\n this.cycle(true)\n }\n\n clearInterval(this._interval)\n this._interval = null\n }\n\n cycle(event) {\n if (!event) {\n this._isPaused = false\n }\n\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n\n if (this._config.interval && !this._isPaused) {\n this._interval = setInterval(\n (document.visibilityState ? this.nextWhenVisible : this.next).bind(this),\n this._config.interval\n )\n }\n }\n\n to(index) {\n this._activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM)\n\n const activeIndex = this._getItemIndex(this._activeElement)\n\n if (index > this._items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n $(this._element).one(EVENT_SLID, () => this.to(index))\n return\n }\n\n if (activeIndex === index) {\n this.pause()\n this.cycle()\n return\n }\n\n const direction = index > activeIndex\n ? DIRECTION_NEXT\n : DIRECTION_PREV\n\n this._slide(direction, this._items[index])\n }\n\n dispose() {\n $(this._element).off(EVENT_KEY)\n $.removeData(this._element, DATA_KEY)\n\n this._items = null\n this._config = null\n this._element = null\n this._interval = null\n this._isPaused = null\n this._isSliding = null\n this._activeElement = null\n this._indicatorsElement = null\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...config\n }\n Util.typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _handleSwipe() {\n const absDeltax = Math.abs(this.touchDeltaX)\n\n if (absDeltax <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltax / this.touchDeltaX\n\n this.touchDeltaX = 0\n\n // swipe left\n if (direction > 0) {\n this.prev()\n }\n\n // swipe right\n if (direction < 0) {\n this.next()\n }\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n $(this._element).on(EVENT_KEYDOWN, (event) => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n $(this._element)\n .on(EVENT_MOUSEENTER, (event) => this.pause(event))\n .on(EVENT_MOUSELEAVE, (event) => this.cycle(event))\n }\n\n if (this._config.touch) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n if (!this._touchSupported) {\n return\n }\n\n const start = (event) => {\n if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n this.touchStartX = event.originalEvent.clientX\n } else if (!this._pointerEvent) {\n this.touchStartX = event.originalEvent.touches[0].clientX\n }\n }\n\n const move = (event) => {\n // ensure swiping with one touch and not pinching\n if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {\n this.touchDeltaX = 0\n } else {\n this.touchDeltaX = event.originalEvent.touches[0].clientX - this.touchStartX\n }\n }\n\n const end = (event) => {\n if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n this.touchDeltaX = event.originalEvent.clientX - this.touchStartX\n }\n\n this._handleSwipe()\n if (this._config.pause === 'hover') {\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n this.touchTimeout = setTimeout((event) => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n }\n\n $(this._element.querySelectorAll(SELECTOR_ITEM_IMG))\n .on(EVENT_DRAG_START, (e) => e.preventDefault())\n\n if (this._pointerEvent) {\n $(this._element).on(EVENT_POINTERDOWN, (event) => start(event))\n $(this._element).on(EVENT_POINTERUP, (event) => end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n $(this._element).on(EVENT_TOUCHSTART, (event) => start(event))\n $(this._element).on(EVENT_TOUCHMOVE, (event) => move(event))\n $(this._element).on(EVENT_TOUCHEND, (event) => end(event))\n }\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n switch (event.which) {\n case ARROW_LEFT_KEYCODE:\n event.preventDefault()\n this.prev()\n break\n case ARROW_RIGHT_KEYCODE:\n event.preventDefault()\n this.next()\n break\n default:\n }\n }\n\n _getItemIndex(element) {\n this._items = element && element.parentNode\n ? [].slice.call(element.parentNode.querySelectorAll(SELECTOR_ITEM))\n : []\n return this._items.indexOf(element)\n }\n\n _getItemByDirection(direction, activeElement) {\n const isNextDirection = direction === DIRECTION_NEXT\n const isPrevDirection = direction === DIRECTION_PREV\n const activeIndex = this._getItemIndex(activeElement)\n const lastItemIndex = this._items.length - 1\n const isGoingToWrap = isPrevDirection && activeIndex === 0 ||\n isNextDirection && activeIndex === lastItemIndex\n\n if (isGoingToWrap && !this._config.wrap) {\n return activeElement\n }\n\n const delta = direction === DIRECTION_PREV ? -1 : 1\n const itemIndex = (activeIndex + delta) % this._items.length\n\n return itemIndex === -1\n ? this._items[this._items.length - 1] : this._items[itemIndex]\n }\n\n _triggerSlideEvent(relatedTarget, eventDirectionName) {\n const targetIndex = this._getItemIndex(relatedTarget)\n const fromIndex = this._getItemIndex(this._element.querySelector(SELECTOR_ACTIVE_ITEM))\n const slideEvent = $.Event(EVENT_SLIDE, {\n relatedTarget,\n direction: eventDirectionName,\n from: fromIndex,\n to: targetIndex\n })\n\n $(this._element).trigger(slideEvent)\n\n return slideEvent\n }\n\n _setActiveIndicatorElement(element) {\n if (this._indicatorsElement) {\n const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(SELECTOR_ACTIVE))\n $(indicators).removeClass(CLASS_NAME_ACTIVE)\n\n const nextIndicator = this._indicatorsElement.children[\n this._getItemIndex(element)\n ]\n\n if (nextIndicator) {\n $(nextIndicator).addClass(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _slide(direction, element) {\n const activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM)\n const activeElementIndex = this._getItemIndex(activeElement)\n const nextElement = element || activeElement &&\n this._getItemByDirection(direction, activeElement)\n const nextElementIndex = this._getItemIndex(nextElement)\n const isCycling = Boolean(this._interval)\n\n let directionalClassName\n let orderClassName\n let eventDirectionName\n\n if (direction === DIRECTION_NEXT) {\n directionalClassName = CLASS_NAME_LEFT\n orderClassName = CLASS_NAME_NEXT\n eventDirectionName = DIRECTION_LEFT\n } else {\n directionalClassName = CLASS_NAME_RIGHT\n orderClassName = CLASS_NAME_PREV\n eventDirectionName = DIRECTION_RIGHT\n }\n\n if (nextElement && $(nextElement).hasClass(CLASS_NAME_ACTIVE)) {\n this._isSliding = false\n return\n }\n\n const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)\n if (slideEvent.isDefaultPrevented()) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n return\n }\n\n this._isSliding = true\n\n if (isCycling) {\n this.pause()\n }\n\n this._setActiveIndicatorElement(nextElement)\n\n const slidEvent = $.Event(EVENT_SLID, {\n relatedTarget: nextElement,\n direction: eventDirectionName,\n from: activeElementIndex,\n to: nextElementIndex\n })\n\n if ($(this._element).hasClass(CLASS_NAME_SLIDE)) {\n $(nextElement).addClass(orderClassName)\n\n Util.reflow(nextElement)\n\n $(activeElement).addClass(directionalClassName)\n $(nextElement).addClass(directionalClassName)\n\n const nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10)\n if (nextElementInterval) {\n this._config.defaultInterval = this._config.defaultInterval || this._config.interval\n this._config.interval = nextElementInterval\n } else {\n this._config.interval = this._config.defaultInterval || this._config.interval\n }\n\n const transitionDuration = Util.getTransitionDurationFromElement(activeElement)\n\n $(activeElement)\n .one(Util.TRANSITION_END, () => {\n $(nextElement)\n .removeClass(`${directionalClassName} ${orderClassName}`)\n .addClass(CLASS_NAME_ACTIVE)\n\n $(activeElement).removeClass(`${CLASS_NAME_ACTIVE} ${orderClassName} ${directionalClassName}`)\n\n this._isSliding = false\n\n setTimeout(() => $(this._element).trigger(slidEvent), 0)\n })\n .emulateTransitionEnd(transitionDuration)\n } else {\n $(activeElement).removeClass(CLASS_NAME_ACTIVE)\n $(nextElement).addClass(CLASS_NAME_ACTIVE)\n\n this._isSliding = false\n $(this._element).trigger(slidEvent)\n }\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n // Static\n\n static _jQueryInterface(config) {\n return this.each(function () {\n let data = $(this).data(DATA_KEY)\n let _config = {\n ...Default,\n ...$(this).data()\n }\n\n if (typeof config === 'object') {\n _config = {\n ..._config,\n ...config\n }\n }\n\n const action = typeof config === 'string' ? config : _config.slide\n\n if (!data) {\n data = new Carousel(this, _config)\n $(this).data(DATA_KEY, data)\n }\n\n if (typeof config === 'number') {\n data.to(config)\n } else if (typeof action === 'string') {\n if (typeof data[action] === 'undefined') {\n throw new TypeError(`No method named \"${action}\"`)\n }\n data[action]()\n } else if (_config.interval && _config.ride) {\n data.pause()\n data.cycle()\n }\n })\n }\n\n static _dataApiClickHandler(event) {\n const selector = Util.getSelectorFromElement(this)\n\n if (!selector) {\n return\n }\n\n const target = $(selector)[0]\n\n if (!target || !$(target).hasClass(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n const config = {\n ...$(target).data(),\n ...$(this).data()\n }\n const slideIndex = this.getAttribute('data-slide-to')\n\n if (slideIndex) {\n config.interval = false\n }\n\n Carousel._jQueryInterface.call($(target), config)\n\n if (slideIndex) {\n $(target).data(DATA_KEY).to(slideIndex)\n }\n\n event.preventDefault()\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel._dataApiClickHandler)\n\n$(window).on(EVENT_LOAD_DATA_API, () => {\n const carousels = [].slice.call(document.querySelectorAll(SELECTOR_DATA_RIDE))\n for (let i = 0, len = carousels.length; i < len; i++) {\n const $carousel = $(carousels[i])\n Carousel._jQueryInterface.call($carousel, $carousel.data())\n }\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Carousel._jQueryInterface\n$.fn[NAME].Constructor = Carousel\n$.fn[NAME].noConflict = () => {\n $.fn[NAME] = JQUERY_NO_CONFLICT\n return Carousel._jQueryInterface\n}\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport $ from 'jquery'\nimport Util from './util'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'collapse'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\n\nconst Default = {\n toggle : true,\n parent : ''\n}\n\nconst DefaultType = {\n toggle : 'boolean',\n parent : '(string|element)'\n}\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\n\nconst DIMENSION_WIDTH = 'width'\nconst DIMENSION_HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.show, .collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-toggle=\"collapse\"]'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Collapse {\n constructor(element, config) {\n this._isTransitioning = false\n this._element = element\n this._config = this._getConfig(config)\n this._triggerArray = [].slice.call(document.querySelectorAll(\n `[data-toggle=\"collapse\"][href=\"#${element.id}\"],` +\n `[data-toggle=\"collapse\"][data-target=\"#${element.id}\"]`\n ))\n\n const toggleList = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE))\n for (let i = 0, len = toggleList.length; i < len; i++) {\n const elem = toggleList[i]\n const selector = Util.getSelectorFromElement(elem)\n const filterElement = [].slice.call(document.querySelectorAll(selector))\n .filter((foundElem) => foundElem === element)\n\n if (selector !== null && filterElement.length > 0) {\n this._selector = selector\n this._triggerArray.push(elem)\n }\n }\n\n this._parent = this._config.parent ? this._getParent() : null\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._element, this._triggerArray)\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n static get Default() {\n return Default\n }\n\n // Public\n\n toggle() {\n if ($(this._element).hasClass(CLASS_NAME_SHOW)) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning ||\n $(this._element).hasClass(CLASS_NAME_SHOW)) {\n return\n }\n\n let actives\n let activesData\n\n if (this._parent) {\n actives = [].slice.call(this._parent.querySelectorAll(SELECTOR_ACTIVES))\n .filter((elem) => {\n if (typeof this._config.parent === 'string') {\n return elem.getAttribute('data-parent') === this._config.parent\n }\n\n return elem.classList.contains(CLASS_NAME_COLLAPSE)\n })\n\n if (actives.length === 0) {\n actives = null\n }\n }\n\n if (actives) {\n activesData = $(actives).not(this._selector).data(DATA_KEY)\n if (activesData && activesData._isTransitioning) {\n return\n }\n }\n\n const startEvent = $.Event(EVENT_SHOW)\n $(this._element).trigger(startEvent)\n if (startEvent.isDefaultPrevented()) {\n return\n }\n\n if (actives) {\n Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide')\n if (!activesData) {\n $(actives).data(DATA_KEY, null)\n }\n }\n\n const dimension = this._getDimension()\n\n $(this._element)\n .removeClass(CLASS_NAME_COLLAPSE)\n .addClass(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n if (this._triggerArray.length) {\n $(this._triggerArray)\n .removeClass(CLASS_NAME_COLLAPSED)\n .attr('aria-expanded', true)\n }\n\n this.setTransitioning(true)\n\n const complete = () => {\n $(this._element)\n .removeClass(CLASS_NAME_COLLAPSING)\n .addClass(`${CLASS_NAME_COLLAPSE} ${CLASS_NAME_SHOW}`)\n\n this._element.style[dimension] = ''\n\n this.setTransitioning(false)\n\n $(this._element).trigger(EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n const transitionDuration = Util.getTransitionDurationFromElement(this._element)\n\n $(this._element)\n .one(Util.TRANSITION_END, complete)\n .emulateTransitionEnd(transitionDuration)\n\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning ||\n !$(this._element).hasClass(CLASS_NAME_SHOW)) {\n return\n }\n\n const startEvent = $.Event(EVENT_HIDE)\n $(this._element).trigger(startEvent)\n if (startEvent.isDefaultPrevented()) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n Util.reflow(this._element)\n\n $(this._element)\n .addClass(CLASS_NAME_COLLAPSING)\n .removeClass(`${CLASS_NAME_COLLAPSE} ${CLASS_NAME_SHOW}`)\n\n const triggerArrayLength = this._triggerArray.length\n if (triggerArrayLength > 0) {\n for (let i = 0; i < triggerArrayLength; i++) {\n const trigger = this._triggerArray[i]\n const selector = Util.getSelectorFromElement(trigger)\n\n if (selector !== null) {\n const $elem = $([].slice.call(document.querySelectorAll(selector)))\n if (!$elem.hasClass(CLASS_NAME_SHOW)) {\n $(trigger).addClass(CLASS_NAME_COLLAPSED)\n .attr('aria-expanded', false)\n }\n }\n }\n }\n\n this.setTransitioning(true)\n\n const complete = () => {\n this.setTransitioning(false)\n $(this._element)\n .removeClass(CLASS_NAME_COLLAPSING)\n .addClass(CLASS_NAME_COLLAPSE)\n .trigger(EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n const transitionDuration = Util.getTransitionDurationFromElement(this._element)\n\n $(this._element)\n .one(Util.TRANSITION_END, complete)\n .emulateTransitionEnd(transitionDuration)\n }\n\n setTransitioning(isTransitioning) {\n this._isTransitioning = isTransitioning\n }\n\n dispose() {\n $.removeData(this._element, DATA_KEY)\n\n this._config = null\n this._parent = null\n this._element = null\n this._triggerArray = null\n this._isTransitioning = null\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...config\n }\n config.toggle = Boolean(config.toggle) // Coerce string values\n Util.typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _getDimension() {\n const hasWidth = $(this._element).hasClass(DIMENSION_WIDTH)\n return hasWidth ? DIMENSION_WIDTH : DIMENSION_HEIGHT\n }\n\n _getParent() {\n let parent\n\n if (Util.isElement(this._config.parent)) {\n parent = this._config.parent\n\n // It's a jQuery object\n if (typeof this._config.parent.jquery !== 'undefined') {\n parent = this._config.parent[0]\n }\n } else {\n parent = document.querySelector(this._config.parent)\n }\n\n const selector = `[data-toggle=\"collapse\"][data-parent=\"${this._config.parent}\"]`\n const children = [].slice.call(parent.querySelectorAll(selector))\n\n $(children).each((i, element) => {\n this._addAriaAndCollapsedClass(\n Collapse._getTargetFromElement(element),\n [element]\n )\n })\n\n return parent\n }\n\n _addAriaAndCollapsedClass(element, triggerArray) {\n const isOpen = $(element).hasClass(CLASS_NAME_SHOW)\n\n if (triggerArray.length) {\n $(triggerArray)\n .toggleClass(CLASS_NAME_COLLAPSED, !isOpen)\n .attr('aria-expanded', isOpen)\n }\n }\n\n // Static\n\n static _getTargetFromElement(element) {\n const selector = Util.getSelectorFromElement(element)\n return selector ? document.querySelector(selector) : null\n }\n\n static _jQueryInterface(config) {\n return this.each(function () {\n const $this = $(this)\n let data = $this.data(DATA_KEY)\n const _config = {\n ...Default,\n ...$this.data(),\n ...typeof config === 'object' && config ? config : {}\n }\n\n if (!data && _config.toggle && typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n if (!data) {\n data = new Collapse(this, _config)\n $this.data(DATA_KEY, data)\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for elements (which change the URL) not inside the collapsible element\n if (event.currentTarget.tagName === 'A') {\n event.preventDefault()\n }\n\n const $trigger = $(this)\n const selector = Util.getSelectorFromElement(this)\n const selectors = [].slice.call(document.querySelectorAll(selector))\n\n $(selectors).each(function () {\n const $target = $(this)\n const data = $target.data(DATA_KEY)\n const config = data ? 'toggle' : $trigger.data()\n Collapse._jQueryInterface.call($target, config)\n })\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Collapse._jQueryInterface\n$.fn[NAME].Constructor = Collapse\n$.fn[NAME].noConflict = () => {\n $.fn[NAME] = JQUERY_NO_CONFLICT\n return Collapse._jQueryInterface\n}\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport $ from 'jquery'\nimport Popper from 'popper.js'\nimport Util from './util'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'dropdown'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\nconst ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key\nconst SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key\nconst TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key\nconst ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key\nconst ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key\nconst RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse)\nconst REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`)\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DISABLED = 'disabled'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPRIGHT = 'dropright'\nconst CLASS_NAME_DROPLEFT = 'dropleft'\nconst CLASS_NAME_MENURIGHT = 'dropdown-menu-right'\nconst CLASS_NAME_POSITION_STATIC = 'position-static'\n\nconst SELECTOR_DATA_TOGGLE = '[data-toggle=\"dropdown\"]'\nconst SELECTOR_FORM_CHILD = '.dropdown form'\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = 'top-start'\nconst PLACEMENT_TOPEND = 'top-end'\nconst PLACEMENT_BOTTOM = 'bottom-start'\nconst PLACEMENT_BOTTOMEND = 'bottom-end'\nconst PLACEMENT_RIGHT = 'right-start'\nconst PLACEMENT_LEFT = 'left-start'\n\nconst Default = {\n offset : 0,\n flip : true,\n boundary : 'scrollParent',\n reference : 'toggle',\n display : 'dynamic',\n popperConfig : null\n}\n\nconst DefaultType = {\n offset : '(number|string|function)',\n flip : 'boolean',\n boundary : '(string|element)',\n reference : '(string|element)',\n display : 'string',\n popperConfig : '(null|object)'\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Dropdown {\n constructor(element, config) {\n this._element = element\n this._popper = null\n this._config = this._getConfig(config)\n this._menu = this._getMenuElement()\n this._inNavbar = this._detectNavbar()\n\n this._addEventListeners()\n }\n\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Public\n\n toggle() {\n if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED)) {\n return\n }\n\n const isActive = $(this._menu).hasClass(CLASS_NAME_SHOW)\n\n Dropdown._clearMenus()\n\n if (isActive) {\n return\n }\n\n this.show(true)\n }\n\n show(usePopper = false) {\n if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || $(this._menu).hasClass(CLASS_NAME_SHOW)) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n const showEvent = $.Event(EVENT_SHOW, relatedTarget)\n const parent = Dropdown._getParentFromElement(this._element)\n\n $(parent).trigger(showEvent)\n\n if (showEvent.isDefaultPrevented()) {\n return\n }\n\n // Disable totally Popper.js for Dropdown in Navbar\n if (!this._inNavbar && usePopper) {\n /**\n * Check for Popper dependency\n * Popper - https://popper.js.org\n */\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper.js (https://popper.js.org/)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = parent\n } else if (Util.isElement(this._config.reference)) {\n referenceElement = this._config.reference\n\n // Check if it's jQuery element\n if (typeof this._config.reference.jquery !== 'undefined') {\n referenceElement = this._config.reference[0]\n }\n }\n\n // If boundary is not `scrollParent`, then set position to `static`\n // to allow the menu to \"escape\" the scroll parent's boundaries\n // https://github.com/twbs/bootstrap/issues/24251\n if (this._config.boundary !== 'scrollParent') {\n $(parent).addClass(CLASS_NAME_POSITION_STATIC)\n }\n this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig())\n }\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement &&\n $(parent).closest(SELECTOR_NAVBAR_NAV).length === 0) {\n $(document.body).children().on('mouseover', null, $.noop)\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n $(this._menu).toggleClass(CLASS_NAME_SHOW)\n $(parent)\n .toggleClass(CLASS_NAME_SHOW)\n .trigger($.Event(EVENT_SHOWN, relatedTarget))\n }\n\n hide() {\n if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || !$(this._menu).hasClass(CLASS_NAME_SHOW)) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n const hideEvent = $.Event(EVENT_HIDE, relatedTarget)\n const parent = Dropdown._getParentFromElement(this._element)\n\n $(parent).trigger(hideEvent)\n\n if (hideEvent.isDefaultPrevented()) {\n return\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n $(this._menu).toggleClass(CLASS_NAME_SHOW)\n $(parent)\n .toggleClass(CLASS_NAME_SHOW)\n .trigger($.Event(EVENT_HIDDEN, relatedTarget))\n }\n\n dispose() {\n $.removeData(this._element, DATA_KEY)\n $(this._element).off(EVENT_KEY)\n this._element = null\n this._menu = null\n if (this._popper !== null) {\n this._popper.destroy()\n this._popper = null\n }\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper !== null) {\n this._popper.scheduleUpdate()\n }\n }\n\n // Private\n\n _addEventListeners() {\n $(this._element).on(EVENT_CLICK, (event) => {\n event.preventDefault()\n event.stopPropagation()\n this.toggle()\n })\n }\n\n _getConfig(config) {\n config = {\n ...this.constructor.Default,\n ...$(this._element).data(),\n ...config\n }\n\n Util.typeCheckConfig(\n NAME,\n config,\n this.constructor.DefaultType\n )\n\n return config\n }\n\n _getMenuElement() {\n if (!this._menu) {\n const parent = Dropdown._getParentFromElement(this._element)\n\n if (parent) {\n this._menu = parent.querySelector(SELECTOR_MENU)\n }\n }\n return this._menu\n }\n\n _getPlacement() {\n const $parentDropdown = $(this._element.parentNode)\n let placement = PLACEMENT_BOTTOM\n\n // Handle dropup\n if ($parentDropdown.hasClass(CLASS_NAME_DROPUP)) {\n placement = $(this._menu).hasClass(CLASS_NAME_MENURIGHT)\n ? PLACEMENT_TOPEND\n : PLACEMENT_TOP\n } else if ($parentDropdown.hasClass(CLASS_NAME_DROPRIGHT)) {\n placement = PLACEMENT_RIGHT\n } else if ($parentDropdown.hasClass(CLASS_NAME_DROPLEFT)) {\n placement = PLACEMENT_LEFT\n } else if ($(this._menu).hasClass(CLASS_NAME_MENURIGHT)) {\n placement = PLACEMENT_BOTTOMEND\n }\n return placement\n }\n\n _detectNavbar() {\n return $(this._element).closest('.navbar').length > 0\n }\n\n _getOffset() {\n const offset = {}\n\n if (typeof this._config.offset === 'function') {\n offset.fn = (data) => {\n data.offsets = {\n ...data.offsets,\n ...this._config.offset(data.offsets, this._element) || {}\n }\n\n return data\n }\n } else {\n offset.offset = this._config.offset\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const popperConfig = {\n placement: this._getPlacement(),\n modifiers: {\n offset: this._getOffset(),\n flip: {\n enabled: this._config.flip\n },\n preventOverflow: {\n boundariesElement: this._config.boundary\n }\n }\n }\n\n // Disable Popper.js if we have a static display\n if (this._config.display === 'static') {\n popperConfig.modifiers.applyStyle = {\n enabled: false\n }\n }\n\n return {\n ...popperConfig,\n ...this._config.popperConfig\n }\n }\n\n // Static\n\n static _jQueryInterface(config) {\n return this.each(function () {\n let data = $(this).data(DATA_KEY)\n const _config = typeof config === 'object' ? config : null\n\n if (!data) {\n data = new Dropdown(this, _config)\n $(this).data(DATA_KEY, data)\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n data[config]()\n }\n })\n }\n\n static _clearMenus(event) {\n if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH ||\n event.type === 'keyup' && event.which !== TAB_KEYCODE)) {\n return\n }\n\n const toggles = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE))\n\n for (let i = 0, len = toggles.length; i < len; i++) {\n const parent = Dropdown._getParentFromElement(toggles[i])\n const context = $(toggles[i]).data(DATA_KEY)\n const relatedTarget = {\n relatedTarget: toggles[i]\n }\n\n if (event && event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n if (!context) {\n continue\n }\n\n const dropdownMenu = context._menu\n if (!$(parent).hasClass(CLASS_NAME_SHOW)) {\n continue\n }\n\n if (event && (event.type === 'click' &&\n /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) &&\n $.contains(parent, event.target)) {\n continue\n }\n\n const hideEvent = $.Event(EVENT_HIDE, relatedTarget)\n $(parent).trigger(hideEvent)\n if (hideEvent.isDefaultPrevented()) {\n continue\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n $(document.body).children().off('mouseover', null, $.noop)\n }\n\n toggles[i].setAttribute('aria-expanded', 'false')\n\n if (context._popper) {\n context._popper.destroy()\n }\n\n $(dropdownMenu).removeClass(CLASS_NAME_SHOW)\n $(parent)\n .removeClass(CLASS_NAME_SHOW)\n .trigger($.Event(EVENT_HIDDEN, relatedTarget))\n }\n }\n\n static _getParentFromElement(element) {\n let parent\n const selector = Util.getSelectorFromElement(element)\n\n if (selector) {\n parent = document.querySelector(selector)\n }\n\n return parent || element.parentNode\n }\n\n // eslint-disable-next-line complexity\n static _dataApiKeydownHandler(event) {\n // If not input/textarea:\n // - And not a key in REGEXP_KEYDOWN => not a dropdown command\n // If input/textarea:\n // - If space key => not a dropdown command\n // - If key is other than escape\n // - If key is not up or down => not a dropdown command\n // - If trigger inside the menu => not a dropdown command\n if (/input|textarea/i.test(event.target.tagName)\n ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE &&\n (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE ||\n $(event.target).closest(SELECTOR_MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {\n return\n }\n\n if (this.disabled || $(this).hasClass(CLASS_NAME_DISABLED)) {\n return\n }\n\n const parent = Dropdown._getParentFromElement(this)\n const isActive = $(parent).hasClass(CLASS_NAME_SHOW)\n\n if (!isActive && event.which === ESCAPE_KEYCODE) {\n return\n }\n\n event.preventDefault()\n event.stopPropagation()\n\n if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {\n if (event.which === ESCAPE_KEYCODE) {\n $(parent.querySelector(SELECTOR_DATA_TOGGLE)).trigger('focus')\n }\n\n $(this).trigger('click')\n return\n }\n\n const items = [].slice.call(parent.querySelectorAll(SELECTOR_VISIBLE_ITEMS))\n .filter((item) => $(item).is(':visible'))\n\n if (items.length === 0) {\n return\n }\n\n let index = items.indexOf(event.target)\n\n if (event.which === ARROW_UP_KEYCODE && index > 0) { // Up\n index--\n }\n\n if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { // Down\n index++\n }\n\n if (index < 0) {\n index = 0\n }\n\n items[index].focus()\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n$(document)\n .on(EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown._dataApiKeydownHandler)\n .on(EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown._dataApiKeydownHandler)\n .on(`${EVENT_CLICK_DATA_API} ${EVENT_KEYUP_DATA_API}`, Dropdown._clearMenus)\n .on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n event.stopPropagation()\n Dropdown._jQueryInterface.call($(this), 'toggle')\n })\n .on(EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, (e) => {\n e.stopPropagation()\n })\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Dropdown._jQueryInterface\n$.fn[NAME].Constructor = Dropdown\n$.fn[NAME].noConflict = () => {\n $.fn[NAME] = JQUERY_NO_CONFLICT\n return Dropdown._jQueryInterface\n}\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport $ from 'jquery'\nimport Util from './util'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'modal'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\nconst ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key\n\nconst Default = {\n backdrop : true,\n keyboard : true,\n focus : true,\n show : true\n}\n\nconst DefaultType = {\n backdrop : '(boolean|string)',\n keyboard : 'boolean',\n focus : 'boolean',\n show : 'boolean'\n}\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SCROLLABLE = 'modal-dialog-scrollable'\nconst CLASS_NAME_SCROLLBAR_MEASURER = 'modal-scrollbar-measure'\nconst CLASS_NAME_BACKDROP = 'modal-backdrop'\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-toggle=\"modal\"]'\nconst SELECTOR_DATA_DISMISS = '[data-dismiss=\"modal\"]'\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Modal {\n constructor(element, config) {\n this._config = this._getConfig(config)\n this._element = element\n this._dialog = element.querySelector(SELECTOR_DIALOG)\n this._backdrop = null\n this._isShown = false\n this._isBodyOverflowing = false\n this._ignoreBackdropClick = false\n this._isTransitioning = false\n this._scrollbarWidth = 0\n }\n\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n static get Default() {\n return Default\n }\n\n // Public\n\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n if ($(this._element).hasClass(CLASS_NAME_FADE)) {\n this._isTransitioning = true\n }\n\n const showEvent = $.Event(EVENT_SHOW, {\n relatedTarget\n })\n\n $(this._element).trigger(showEvent)\n\n if (this._isShown || showEvent.isDefaultPrevented()) {\n return\n }\n\n this._isShown = true\n\n this._checkScrollbar()\n this._setScrollbar()\n\n this._adjustDialog()\n\n this._setEscapeEvent()\n this._setResizeEvent()\n\n $(this._element).on(\n EVENT_CLICK_DISMISS,\n SELECTOR_DATA_DISMISS,\n (event) => this.hide(event)\n )\n\n $(this._dialog).on(EVENT_MOUSEDOWN_DISMISS, () => {\n $(this._element).one(EVENT_MOUSEUP_DISMISS, (event) => {\n if ($(event.target).is(this._element)) {\n this._ignoreBackdropClick = true\n }\n })\n })\n\n this._showBackdrop(() => this._showElement(relatedTarget))\n }\n\n hide(event) {\n if (event) {\n event.preventDefault()\n }\n\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = $.Event(EVENT_HIDE)\n\n $(this._element).trigger(hideEvent)\n\n if (!this._isShown || hideEvent.isDefaultPrevented()) {\n return\n }\n\n this._isShown = false\n const transition = $(this._element).hasClass(CLASS_NAME_FADE)\n\n if (transition) {\n this._isTransitioning = true\n }\n\n this._setEscapeEvent()\n this._setResizeEvent()\n\n $(document).off(EVENT_FOCUSIN)\n\n $(this._element).removeClass(CLASS_NAME_SHOW)\n\n $(this._element).off(EVENT_CLICK_DISMISS)\n $(this._dialog).off(EVENT_MOUSEDOWN_DISMISS)\n\n if (transition) {\n const transitionDuration = Util.getTransitionDurationFromElement(this._element)\n\n $(this._element)\n .one(Util.TRANSITION_END, (event) => this._hideModal(event))\n .emulateTransitionEnd(transitionDuration)\n } else {\n this._hideModal()\n }\n }\n\n dispose() {\n [window, this._element, this._dialog]\n .forEach((htmlElement) => $(htmlElement).off(EVENT_KEY))\n\n /**\n * `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`\n * Do not move `document` in `htmlElements` array\n * It will remove `EVENT_CLICK_DATA_API` event that should remain\n */\n $(document).off(EVENT_FOCUSIN)\n\n $.removeData(this._element, DATA_KEY)\n\n this._config = null\n this._element = null\n this._dialog = null\n this._backdrop = null\n this._isShown = null\n this._isBodyOverflowing = null\n this._ignoreBackdropClick = null\n this._isTransitioning = null\n this._scrollbarWidth = null\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...config\n }\n Util.typeCheckConfig(NAME, config, DefaultType)\n return config\n }\n\n _triggerBackdropTransition() {\n if (this._config.backdrop === 'static') {\n const hideEventPrevented = $.Event(EVENT_HIDE_PREVENTED)\n\n $(this._element).trigger(hideEventPrevented)\n if (hideEventPrevented.defaultPrevented) {\n return\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n\n const modalTransitionDuration = Util.getTransitionDurationFromElement(this._element)\n\n $(this._element).one(Util.TRANSITION_END, () => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n })\n .emulateTransitionEnd(modalTransitionDuration)\n this._element.focus()\n } else {\n this.hide()\n }\n }\n\n _showElement(relatedTarget) {\n const transition = $(this._element).hasClass(CLASS_NAME_FADE)\n const modalBody = this._dialog ? this._dialog.querySelector(SELECTOR_MODAL_BODY) : null\n\n if (!this._element.parentNode ||\n this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n // Don't move modal's DOM position\n document.body.appendChild(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n\n if ($(this._dialog).hasClass(CLASS_NAME_SCROLLABLE) && modalBody) {\n modalBody.scrollTop = 0\n } else {\n this._element.scrollTop = 0\n }\n\n if (transition) {\n Util.reflow(this._element)\n }\n\n $(this._element).addClass(CLASS_NAME_SHOW)\n\n if (this._config.focus) {\n this._enforceFocus()\n }\n\n const shownEvent = $.Event(EVENT_SHOWN, {\n relatedTarget\n })\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._element.focus()\n }\n this._isTransitioning = false\n $(this._element).trigger(shownEvent)\n }\n\n if (transition) {\n const transitionDuration = Util.getTransitionDurationFromElement(this._dialog)\n\n $(this._dialog)\n .one(Util.TRANSITION_END, transitionComplete)\n .emulateTransitionEnd(transitionDuration)\n } else {\n transitionComplete()\n }\n }\n\n _enforceFocus() {\n $(document)\n .off(EVENT_FOCUSIN) // Guard against infinite focus loop\n .on(EVENT_FOCUSIN, (event) => {\n if (document !== event.target &&\n this._element !== event.target &&\n $(this._element).has(event.target).length === 0) {\n this._element.focus()\n }\n })\n }\n\n _setEscapeEvent() {\n if (this._isShown) {\n $(this._element).on(EVENT_KEYDOWN_DISMISS, (event) => {\n if (this._config.keyboard && event.which === ESCAPE_KEYCODE) {\n event.preventDefault()\n this.hide()\n } else if (!this._config.keyboard && event.which === ESCAPE_KEYCODE) {\n this._triggerBackdropTransition()\n }\n })\n } else if (!this._isShown) {\n $(this._element).off(EVENT_KEYDOWN_DISMISS)\n }\n }\n\n _setResizeEvent() {\n if (this._isShown) {\n $(window).on(EVENT_RESIZE, (event) => this.handleUpdate(event))\n } else {\n $(window).off(EVENT_RESIZE)\n }\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._isTransitioning = false\n this._showBackdrop(() => {\n $(document.body).removeClass(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._resetScrollbar()\n $(this._element).trigger(EVENT_HIDDEN)\n })\n }\n\n _removeBackdrop() {\n if (this._backdrop) {\n $(this._backdrop).remove()\n this._backdrop = null\n }\n }\n\n _showBackdrop(callback) {\n const animate = $(this._element).hasClass(CLASS_NAME_FADE)\n ? CLASS_NAME_FADE : ''\n\n if (this._isShown && this._config.backdrop) {\n this._backdrop = document.createElement('div')\n this._backdrop.className = CLASS_NAME_BACKDROP\n\n if (animate) {\n this._backdrop.classList.add(animate)\n }\n\n $(this._backdrop).appendTo(document.body)\n\n $(this._element).on(EVENT_CLICK_DISMISS, (event) => {\n if (this._ignoreBackdropClick) {\n this._ignoreBackdropClick = false\n return\n }\n if (event.target !== event.currentTarget) {\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n if (animate) {\n Util.reflow(this._backdrop)\n }\n\n $(this._backdrop).addClass(CLASS_NAME_SHOW)\n\n if (!callback) {\n return\n }\n\n if (!animate) {\n callback()\n return\n }\n\n const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)\n\n $(this._backdrop)\n .one(Util.TRANSITION_END, callback)\n .emulateTransitionEnd(backdropTransitionDuration)\n } else if (!this._isShown && this._backdrop) {\n $(this._backdrop).removeClass(CLASS_NAME_SHOW)\n\n const callbackRemove = () => {\n this._removeBackdrop()\n if (callback) {\n callback()\n }\n }\n\n if ($(this._element).hasClass(CLASS_NAME_FADE)) {\n const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)\n\n $(this._backdrop)\n .one(Util.TRANSITION_END, callbackRemove)\n .emulateTransitionEnd(backdropTransitionDuration)\n } else {\n callbackRemove()\n }\n } else if (callback) {\n callback()\n }\n }\n\n // ----------------------------------------------------------------------\n // the following methods are used to handle overflowing modals\n // todo (fat): these should probably be refactored out of modal.js\n // ----------------------------------------------------------------------\n\n _adjustDialog() {\n const isModalOverflowing =\n this._element.scrollHeight > document.documentElement.clientHeight\n\n if (!this._isBodyOverflowing && isModalOverflowing) {\n this._element.style.paddingLeft = `${this._scrollbarWidth}px`\n }\n\n if (this._isBodyOverflowing && !isModalOverflowing) {\n this._element.style.paddingRight = `${this._scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n _checkScrollbar() {\n const rect = document.body.getBoundingClientRect()\n this._isBodyOverflowing = Math.round(rect.left + rect.right) < window.innerWidth\n this._scrollbarWidth = this._getScrollbarWidth()\n }\n\n _setScrollbar() {\n if (this._isBodyOverflowing) {\n // Note: DOMNode.style.paddingRight returns the actual value or '' if not set\n // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set\n const fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT))\n const stickyContent = [].slice.call(document.querySelectorAll(SELECTOR_STICKY_CONTENT))\n\n // Adjust fixed content padding\n $(fixedContent).each((index, element) => {\n const actualPadding = element.style.paddingRight\n const calculatedPadding = $(element).css('padding-right')\n $(element)\n .data('padding-right', actualPadding)\n .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`)\n })\n\n // Adjust sticky content margin\n $(stickyContent).each((index, element) => {\n const actualMargin = element.style.marginRight\n const calculatedMargin = $(element).css('margin-right')\n $(element)\n .data('margin-right', actualMargin)\n .css('margin-right', `${parseFloat(calculatedMargin) - this._scrollbarWidth}px`)\n })\n\n // Adjust body padding\n const actualPadding = document.body.style.paddingRight\n const calculatedPadding = $(document.body).css('padding-right')\n $(document.body)\n .data('padding-right', actualPadding)\n .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`)\n }\n\n $(document.body).addClass(CLASS_NAME_OPEN)\n }\n\n _resetScrollbar() {\n // Restore fixed content padding\n const fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT))\n $(fixedContent).each((index, element) => {\n const padding = $(element).data('padding-right')\n $(element).removeData('padding-right')\n element.style.paddingRight = padding ? padding : ''\n })\n\n // Restore sticky content\n const elements = [].slice.call(document.querySelectorAll(`${SELECTOR_STICKY_CONTENT}`))\n $(elements).each((index, element) => {\n const margin = $(element).data('margin-right')\n if (typeof margin !== 'undefined') {\n $(element).css('margin-right', margin).removeData('margin-right')\n }\n })\n\n // Restore body padding\n const padding = $(document.body).data('padding-right')\n $(document.body).removeData('padding-right')\n document.body.style.paddingRight = padding ? padding : ''\n }\n\n _getScrollbarWidth() { // thx d.walsh\n const scrollDiv = document.createElement('div')\n scrollDiv.className = CLASS_NAME_SCROLLBAR_MEASURER\n document.body.appendChild(scrollDiv)\n const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth\n document.body.removeChild(scrollDiv)\n return scrollbarWidth\n }\n\n // Static\n\n static _jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n let data = $(this).data(DATA_KEY)\n const _config = {\n ...Default,\n ...$(this).data(),\n ...typeof config === 'object' && config ? config : {}\n }\n\n if (!data) {\n data = new Modal(this, _config)\n $(this).data(DATA_KEY, data)\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n data[config](relatedTarget)\n } else if (_config.show) {\n data.show(relatedTarget)\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n let target\n const selector = Util.getSelectorFromElement(this)\n\n if (selector) {\n target = document.querySelector(selector)\n }\n\n const config = $(target).data(DATA_KEY)\n ? 'toggle' : {\n ...$(target).data(),\n ...$(this).data()\n }\n\n if (this.tagName === 'A' || this.tagName === 'AREA') {\n event.preventDefault()\n }\n\n const $target = $(target).one(EVENT_SHOW, (showEvent) => {\n if (showEvent.isDefaultPrevented()) {\n // Only register focus restorer if modal will actually get shown\n return\n }\n\n $target.one(EVENT_HIDDEN, () => {\n if ($(this).is(':visible')) {\n this.focus()\n }\n })\n })\n\n Modal._jQueryInterface.call($(target), config, this)\n})\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Modal._jQueryInterface\n$.fn[NAME].Constructor = Modal\n$.fn[NAME].noConflict = () => {\n $.fn[NAME] = JQUERY_NO_CONFLICT\n return Modal._jQueryInterface\n}\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): tools/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst uriAttrs = [\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n]\n\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultWhitelist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n div: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n\n/**\n * A pattern that recognizes a commonly useful subset of URLs that are safe.\n *\n * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\n */\nconst SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/gi\n\n/**\n * A pattern that matches safe data URLs. Only matches image, video and audio types.\n *\n * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\n */\nconst DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[\\d+/a-z]+=*$/i\n\nfunction allowedAttribute(attr, allowedAttributeList) {\n const attrName = attr.nodeName.toLowerCase()\n\n if (allowedAttributeList.indexOf(attrName) !== -1) {\n if (uriAttrs.indexOf(attrName) !== -1) {\n return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))\n }\n\n return true\n }\n\n const regExp = allowedAttributeList.filter((attrRegex) => attrRegex instanceof RegExp)\n\n // Check if a regular expression validates the attribute.\n for (let i = 0, len = regExp.length; i < len; i++) {\n if (attrName.match(regExp[i])) {\n return true\n }\n }\n\n return false\n}\n\nexport function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {\n if (unsafeHtml.length === 0) {\n return unsafeHtml\n }\n\n if (sanitizeFn && typeof sanitizeFn === 'function') {\n return sanitizeFn(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const whitelistKeys = Object.keys(whiteList)\n const elements = [].slice.call(createdDocument.body.querySelectorAll('*'))\n\n for (let i = 0, len = elements.length; i < len; i++) {\n const el = elements[i]\n const elName = el.nodeName.toLowerCase()\n\n if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {\n el.parentNode.removeChild(el)\n\n continue\n }\n\n const attributeList = [].slice.call(el.attributes)\n const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])\n\n attributeList.forEach((attr) => {\n if (!allowedAttribute(attr, whitelistedAttributes)) {\n el.removeAttribute(attr.nodeName)\n }\n })\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport {\n DefaultWhitelist,\n sanitizeHtml\n} from './tools/sanitizer'\nimport $ from 'jquery'\nimport Popper from 'popper.js'\nimport Util from './util'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'tooltip'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.tooltip'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\nconst CLASS_PREFIX = 'bs-tooltip'\nconst BSCLS_PREFIX_REGEX = new RegExp(`(^|\\\\s)${CLASS_PREFIX}\\\\S+`, 'g')\nconst DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']\n\nconst DefaultType = {\n animation : 'boolean',\n template : 'string',\n title : '(string|element|function)',\n trigger : 'string',\n delay : '(number|object)',\n html : 'boolean',\n selector : '(string|boolean)',\n placement : '(string|function)',\n offset : '(number|string|function)',\n container : '(string|element|boolean)',\n fallbackPlacement : '(string|array)',\n boundary : '(string|element)',\n sanitize : 'boolean',\n sanitizeFn : '(null|function)',\n whiteList : 'object',\n popperConfig : '(null|object)'\n}\n\nconst AttachmentMap = {\n AUTO : 'auto',\n TOP : 'top',\n RIGHT : 'right',\n BOTTOM : 'bottom',\n LEFT : 'left'\n}\n\nconst Default = {\n animation : true,\n template : '
' +\n '
' +\n '
',\n trigger : 'hover focus',\n title : '',\n delay : 0,\n html : false,\n selector : false,\n placement : 'top',\n offset : 0,\n container : false,\n fallbackPlacement : 'flip',\n boundary : 'scrollParent',\n sanitize : true,\n sanitizeFn : null,\n whiteList : DefaultWhitelist,\n popperConfig : null\n}\n\nconst HOVER_STATE_SHOW = 'show'\nconst HOVER_STATE_OUT = 'out'\n\nconst Event = {\n HIDE : `hide${EVENT_KEY}`,\n HIDDEN : `hidden${EVENT_KEY}`,\n SHOW : `show${EVENT_KEY}`,\n SHOWN : `shown${EVENT_KEY}`,\n INSERTED : `inserted${EVENT_KEY}`,\n CLICK : `click${EVENT_KEY}`,\n FOCUSIN : `focusin${EVENT_KEY}`,\n FOCUSOUT : `focusout${EVENT_KEY}`,\n MOUSEENTER : `mouseenter${EVENT_KEY}`,\n MOUSELEAVE : `mouseleave${EVENT_KEY}`\n}\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_ARROW = '.arrow'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Tooltip {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper.js (https://popper.js.org/)')\n }\n\n // private\n this._isEnabled = true\n this._timeout = 0\n this._hoverState = ''\n this._activeTrigger = {}\n this._popper = null\n\n // Protected\n this.element = element\n this.config = this._getConfig(config)\n this.tip = null\n\n this._setListeners()\n }\n\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n static get DATA_KEY() {\n return DATA_KEY\n }\n\n static get Event() {\n return Event\n }\n\n static get EVENT_KEY() {\n return EVENT_KEY\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Public\n\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle(event) {\n if (!this._isEnabled) {\n return\n }\n\n if (event) {\n const dataKey = this.constructor.DATA_KEY\n let context = $(event.currentTarget).data(dataKey)\n\n if (!context) {\n context = new this.constructor(\n event.currentTarget,\n this._getDelegateConfig()\n )\n $(event.currentTarget).data(dataKey, context)\n }\n\n context._activeTrigger.click = !context._activeTrigger.click\n\n if (context._isWithActiveTrigger()) {\n context._enter(null, context)\n } else {\n context._leave(null, context)\n }\n } else {\n if ($(this.getTipElement()).hasClass(CLASS_NAME_SHOW)) {\n this._leave(null, this)\n return\n }\n\n this._enter(null, this)\n }\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n $.removeData(this.element, this.constructor.DATA_KEY)\n\n $(this.element).off(this.constructor.EVENT_KEY)\n $(this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler)\n\n if (this.tip) {\n $(this.tip).remove()\n }\n\n this._isEnabled = null\n this._timeout = null\n this._hoverState = null\n this._activeTrigger = null\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._popper = null\n this.element = null\n this.config = null\n this.tip = null\n }\n\n show() {\n if ($(this.element).css('display') === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n const showEvent = $.Event(this.constructor.Event.SHOW)\n if (this.isWithContent() && this._isEnabled) {\n $(this.element).trigger(showEvent)\n\n const shadowRoot = Util.findShadowRoot(this.element)\n const isInTheDom = $.contains(\n shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement,\n this.element\n )\n\n if (showEvent.isDefaultPrevented() || !isInTheDom) {\n return\n }\n\n const tip = this.getTipElement()\n const tipId = Util.getUID(this.constructor.NAME)\n\n tip.setAttribute('id', tipId)\n this.element.setAttribute('aria-describedby', tipId)\n\n this.setContent()\n\n if (this.config.animation) {\n $(tip).addClass(CLASS_NAME_FADE)\n }\n\n const placement = typeof this.config.placement === 'function'\n ? this.config.placement.call(this, tip, this.element)\n : this.config.placement\n\n const attachment = this._getAttachment(placement)\n this.addAttachmentClass(attachment)\n\n const container = this._getContainer()\n $(tip).data(this.constructor.DATA_KEY, this)\n\n if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {\n $(tip).appendTo(container)\n }\n\n $(this.element).trigger(this.constructor.Event.INSERTED)\n\n this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment))\n\n $(tip).addClass(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n $(document.body).children().on('mouseover', null, $.noop)\n }\n\n const complete = () => {\n if (this.config.animation) {\n this._fixTransition()\n }\n const prevHoverState = this._hoverState\n this._hoverState = null\n\n $(this.element).trigger(this.constructor.Event.SHOWN)\n\n if (prevHoverState === HOVER_STATE_OUT) {\n this._leave(null, this)\n }\n }\n\n if ($(this.tip).hasClass(CLASS_NAME_FADE)) {\n const transitionDuration = Util.getTransitionDurationFromElement(this.tip)\n\n $(this.tip)\n .one(Util.TRANSITION_END, complete)\n .emulateTransitionEnd(transitionDuration)\n } else {\n complete()\n }\n }\n }\n\n hide(callback) {\n const tip = this.getTipElement()\n const hideEvent = $.Event(this.constructor.Event.HIDE)\n const complete = () => {\n if (this._hoverState !== HOVER_STATE_SHOW && tip.parentNode) {\n tip.parentNode.removeChild(tip)\n }\n\n this._cleanTipClass()\n this.element.removeAttribute('aria-describedby')\n $(this.element).trigger(this.constructor.Event.HIDDEN)\n if (this._popper !== null) {\n this._popper.destroy()\n }\n\n if (callback) {\n callback()\n }\n }\n\n $(this.element).trigger(hideEvent)\n\n if (hideEvent.isDefaultPrevented()) {\n return\n }\n\n $(tip).removeClass(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n $(document.body).children().off('mouseover', null, $.noop)\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n\n if ($(this.tip).hasClass(CLASS_NAME_FADE)) {\n const transitionDuration = Util.getTransitionDurationFromElement(tip)\n\n $(tip)\n .one(Util.TRANSITION_END, complete)\n .emulateTransitionEnd(transitionDuration)\n } else {\n complete()\n }\n\n this._hoverState = ''\n }\n\n update() {\n if (this._popper !== null) {\n this._popper.scheduleUpdate()\n }\n }\n\n // Protected\n\n isWithContent() {\n return Boolean(this.getTitle())\n }\n\n addAttachmentClass(attachment) {\n $(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`)\n }\n\n getTipElement() {\n this.tip = this.tip || $(this.config.template)[0]\n return this.tip\n }\n\n setContent() {\n const tip = this.getTipElement()\n this.setElementContent($(tip.querySelectorAll(SELECTOR_TOOLTIP_INNER)), this.getTitle())\n $(tip).removeClass(`${CLASS_NAME_FADE} ${CLASS_NAME_SHOW}`)\n }\n\n setElementContent($element, content) {\n if (typeof content === 'object' && (content.nodeType || content.jquery)) {\n // Content is a DOM node or a jQuery\n if (this.config.html) {\n if (!$(content).parent().is($element)) {\n $element.empty().append(content)\n }\n } else {\n $element.text($(content).text())\n }\n\n return\n }\n\n if (this.config.html) {\n if (this.config.sanitize) {\n content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn)\n }\n\n $element.html(content)\n } else {\n $element.text(content)\n }\n }\n\n getTitle() {\n let title = this.element.getAttribute('data-original-title')\n\n if (!title) {\n title = typeof this.config.title === 'function'\n ? this.config.title.call(this.element)\n : this.config.title\n }\n\n return title\n }\n\n // Private\n\n _getPopperConfig(attachment) {\n const defaultBsConfig = {\n placement: attachment,\n modifiers: {\n offset: this._getOffset(),\n flip: {\n behavior: this.config.fallbackPlacement\n },\n arrow: {\n element: SELECTOR_ARROW\n },\n preventOverflow: {\n boundariesElement: this.config.boundary\n }\n },\n onCreate: (data) => {\n if (data.originalPlacement !== data.placement) {\n this._handlePopperPlacementChange(data)\n }\n },\n onUpdate: (data) => this._handlePopperPlacementChange(data)\n }\n\n return {\n ...defaultBsConfig,\n ...this.config.popperConfig\n }\n }\n\n _getOffset() {\n const offset = {}\n\n if (typeof this.config.offset === 'function') {\n offset.fn = (data) => {\n data.offsets = {\n ...data.offsets,\n ...this.config.offset(data.offsets, this.element) || {}\n }\n\n return data\n }\n } else {\n offset.offset = this.config.offset\n }\n\n return offset\n }\n\n _getContainer() {\n if (this.config.container === false) {\n return document.body\n }\n\n if (Util.isElement(this.config.container)) {\n return $(this.config.container)\n }\n\n return $(document).find(this.config.container)\n }\n\n _getAttachment(placement) {\n return AttachmentMap[placement.toUpperCase()]\n }\n\n _setListeners() {\n const triggers = this.config.trigger.split(' ')\n\n triggers.forEach((trigger) => {\n if (trigger === 'click') {\n $(this.element).on(\n this.constructor.Event.CLICK,\n this.config.selector,\n (event) => this.toggle(event)\n )\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER\n ? this.constructor.Event.MOUSEENTER\n : this.constructor.Event.FOCUSIN\n const eventOut = trigger === TRIGGER_HOVER\n ? this.constructor.Event.MOUSELEAVE\n : this.constructor.Event.FOCUSOUT\n\n $(this.element)\n .on(eventIn, this.config.selector, (event) => this._enter(event))\n .on(eventOut, this.config.selector, (event) => this._leave(event))\n }\n })\n\n this._hideModalHandler = () => {\n if (this.element) {\n this.hide()\n }\n }\n\n $(this.element).closest('.modal').on('hide.bs.modal', this._hideModalHandler)\n\n if (this.config.selector) {\n this.config = {\n ...this.config,\n trigger: 'manual',\n selector: ''\n }\n } else {\n this._fixTitle()\n }\n }\n\n _fixTitle() {\n const titleType = typeof this.element.getAttribute('data-original-title')\n\n if (this.element.getAttribute('title') || titleType !== 'string') {\n this.element.setAttribute(\n 'data-original-title',\n this.element.getAttribute('title') || ''\n )\n\n this.element.setAttribute('title', '')\n }\n }\n\n _enter(event, context) {\n const dataKey = this.constructor.DATA_KEY\n context = context || $(event.currentTarget).data(dataKey)\n\n if (!context) {\n context = new this.constructor(\n event.currentTarget,\n this._getDelegateConfig()\n )\n $(event.currentTarget).data(dataKey, context)\n }\n\n if (event) {\n context._activeTrigger[\n event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER\n ] = true\n }\n\n if ($(context.getTipElement()).hasClass(CLASS_NAME_SHOW) || context._hoverState === HOVER_STATE_SHOW) {\n context._hoverState = HOVER_STATE_SHOW\n return\n }\n\n clearTimeout(context._timeout)\n\n context._hoverState = HOVER_STATE_SHOW\n\n if (!context.config.delay || !context.config.delay.show) {\n context.show()\n return\n }\n\n context._timeout = setTimeout(() => {\n if (context._hoverState === HOVER_STATE_SHOW) {\n context.show()\n }\n }, context.config.delay.show)\n }\n\n _leave(event, context) {\n const dataKey = this.constructor.DATA_KEY\n context = context || $(event.currentTarget).data(dataKey)\n\n if (!context) {\n context = new this.constructor(\n event.currentTarget,\n this._getDelegateConfig()\n )\n $(event.currentTarget).data(dataKey, context)\n }\n\n if (event) {\n context._activeTrigger[\n event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER\n ] = false\n }\n\n if (context._isWithActiveTrigger()) {\n return\n }\n\n clearTimeout(context._timeout)\n\n context._hoverState = HOVER_STATE_OUT\n\n if (!context.config.delay || !context.config.delay.hide) {\n context.hide()\n return\n }\n\n context._timeout = setTimeout(() => {\n if (context._hoverState === HOVER_STATE_OUT) {\n context.hide()\n }\n }, context.config.delay.hide)\n }\n\n _isWithActiveTrigger() {\n for (const trigger in this._activeTrigger) {\n if (this._activeTrigger[trigger]) {\n return true\n }\n }\n\n return false\n }\n\n _getConfig(config) {\n const dataAttributes = $(this.element).data()\n\n Object.keys(dataAttributes)\n .forEach((dataAttr) => {\n if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {\n delete dataAttributes[dataAttr]\n }\n })\n\n config = {\n ...this.constructor.Default,\n ...dataAttributes,\n ...typeof config === 'object' && config ? config : {}\n }\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n Util.typeCheckConfig(\n NAME,\n config,\n this.constructor.DefaultType\n )\n\n if (config.sanitize) {\n config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn)\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n if (this.config) {\n for (const key in this.config) {\n if (this.constructor.Default[key] !== this.config[key]) {\n config[key] = this.config[key]\n }\n }\n }\n\n return config\n }\n\n _cleanTipClass() {\n const $tip = $(this.getTipElement())\n const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX)\n if (tabClass !== null && tabClass.length) {\n $tip.removeClass(tabClass.join(''))\n }\n }\n\n _handlePopperPlacementChange(popperData) {\n this.tip = popperData.instance.popper\n this._cleanTipClass()\n this.addAttachmentClass(this._getAttachment(popperData.placement))\n }\n\n _fixTransition() {\n const tip = this.getTipElement()\n const initConfigAnimation = this.config.animation\n\n if (tip.getAttribute('x-placement') !== null) {\n return\n }\n\n $(tip).removeClass(CLASS_NAME_FADE)\n this.config.animation = false\n this.hide()\n this.show()\n this.config.animation = initConfigAnimation\n }\n\n // Static\n\n static _jQueryInterface(config) {\n return this.each(function () {\n let data = $(this).data(DATA_KEY)\n const _config = typeof config === 'object' && config\n\n if (!data && /dispose|hide/.test(config)) {\n return\n }\n\n if (!data) {\n data = new Tooltip(this, _config)\n $(this).data(DATA_KEY, data)\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Tooltip._jQueryInterface\n$.fn[NAME].Constructor = Tooltip\n$.fn[NAME].noConflict = () => {\n $.fn[NAME] = JQUERY_NO_CONFLICT\n return Tooltip._jQueryInterface\n}\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport $ from 'jquery'\nimport Tooltip from './tooltip'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'popover'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.popover'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\nconst CLASS_PREFIX = 'bs-popover'\nconst BSCLS_PREFIX_REGEX = new RegExp(`(^|\\\\s)${CLASS_PREFIX}\\\\S+`, 'g')\n\nconst Default = {\n ...Tooltip.Default,\n placement : 'right',\n trigger : 'click',\n content : '',\n template : '
' +\n '
' +\n '

' +\n '
'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content : '(string|element|function)'\n}\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Event = {\n HIDE : `hide${EVENT_KEY}`,\n HIDDEN : `hidden${EVENT_KEY}`,\n SHOW : `show${EVENT_KEY}`,\n SHOWN : `shown${EVENT_KEY}`,\n INSERTED : `inserted${EVENT_KEY}`,\n CLICK : `click${EVENT_KEY}`,\n FOCUSIN : `focusin${EVENT_KEY}`,\n FOCUSOUT : `focusout${EVENT_KEY}`,\n MOUSEENTER : `mouseenter${EVENT_KEY}`,\n MOUSELEAVE : `mouseleave${EVENT_KEY}`\n}\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass Popover extends Tooltip {\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n static get Default() {\n return Default\n }\n\n static get NAME() {\n return NAME\n }\n\n static get DATA_KEY() {\n return DATA_KEY\n }\n\n static get Event() {\n return Event\n }\n\n static get EVENT_KEY() {\n return EVENT_KEY\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n // Overrides\n\n isWithContent() {\n return this.getTitle() || this._getContent()\n }\n\n addAttachmentClass(attachment) {\n $(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`)\n }\n\n getTipElement() {\n this.tip = this.tip || $(this.config.template)[0]\n return this.tip\n }\n\n setContent() {\n const $tip = $(this.getTipElement())\n\n // We use append for html objects to maintain js events\n this.setElementContent($tip.find(SELECTOR_TITLE), this.getTitle())\n let content = this._getContent()\n if (typeof content === 'function') {\n content = content.call(this.element)\n }\n this.setElementContent($tip.find(SELECTOR_CONTENT), content)\n\n $tip.removeClass(`${CLASS_NAME_FADE} ${CLASS_NAME_SHOW}`)\n }\n\n // Private\n\n _getContent() {\n return this.element.getAttribute('data-content') ||\n this.config.content\n }\n\n _cleanTipClass() {\n const $tip = $(this.getTipElement())\n const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX)\n if (tabClass !== null && tabClass.length > 0) {\n $tip.removeClass(tabClass.join(''))\n }\n }\n\n // Static\n\n static _jQueryInterface(config) {\n return this.each(function () {\n let data = $(this).data(DATA_KEY)\n const _config = typeof config === 'object' ? config : null\n\n if (!data && /dispose|hide/.test(config)) {\n return\n }\n\n if (!data) {\n data = new Popover(this, _config)\n $(this).data(DATA_KEY, data)\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n data[config]()\n }\n })\n }\n}\n\n/**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n$.fn[NAME] = Popover._jQueryInterface\n$.fn[NAME].Constructor = Popover\n$.fn[NAME].noConflict = () => {\n $.fn[NAME] = JQUERY_NO_CONFLICT\n return Popover._jQueryInterface\n}\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.0): scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport $ from 'jquery'\nimport Util from './util'\n\n/**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\nconst NAME = 'scrollspy'\nconst VERSION = '4.5.0'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst JQUERY_NO_CONFLICT = $.fn[NAME]\n\nconst Default = {\n offset : 10,\n method : 'auto',\n target : ''\n}\n\nconst DefaultType = {\n offset : 'number',\n method : 'string',\n target : '(string|element)'\n}\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_SCROLL = `scroll${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-spy=\"scroll\"]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_ITEMS = '.dropdown-item'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst METHOD_OFFSET = 'offset'\nconst METHOD_POSITION = 'position'\n\n/**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\nclass ScrollSpy {\n constructor(element, config) {\n this._element = element\n this._scrollElement = element.tagName === 'BODY' ? window : element\n this._config = this._getConfig(config)\n this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS},` +\n `${this._config.target} ${SELECTOR_LIST_ITEMS},` +\n `${this._config.target} ${SELECTOR_DROPDOWN_ITEMS}`\n this._offsets = []\n this._targets = []\n this._activeTarget = null\n this._scrollHeight = 0\n\n $(this._scrollElement).on(EVENT_SCROLL, (event) => this._process(event))\n\n this.refresh()\n this._process()\n }\n\n // Getters\n\n static get VERSION() {\n return VERSION\n }\n\n static get Default() {\n return Default\n }\n\n // Public\n\n refresh() {\n const autoMethod = this._scrollElement === this._scrollElement.window\n ? METHOD_OFFSET : METHOD_POSITION\n\n const offsetMethod = this._config.method === 'auto'\n ? autoMethod : this._config.method\n\n const offsetBase = offsetMethod === METHOD_POSITION\n ? this._getScrollTop() : 0\n\n this._offsets = []\n this._targets = []\n\n this._scrollHeight = this._getScrollHeight()\n\n const targets = [].slice.call(document.querySelectorAll(this._selector))\n\n targets\n .map((element) => {\n let target\n const targetSelector = Util.getSelectorFromElement(element)\n\n if (targetSelector) {\n target = document.querySelector(targetSelector)\n }\n\n if (target) {\n const targetBCR = target.getBoundingClientRect()\n if (targetBCR.width || targetBCR.height) {\n // TODO (fat): remove sketch reliance on jQuery position/offset\n return [\n $(target)[offsetMethod]().top + offsetBase,\n targetSelector\n ]\n }\n }\n return null\n })\n .filter((item) => item)\n .sort((a, b) => a[0] - b[0])\n .forEach((item) => {\n this._offsets.push(item[0])\n this._targets.push(item[1])\n })\n }\n\n dispose() {\n $.removeData(this._element, DATA_KEY)\n $(this._scrollElement).off(EVENT_KEY)\n\n this._element = null\n this._scrollElement = null\n this._config = null\n this._selector = null\n this._offsets = null\n this._targets = null\n this._activeTarget = null\n this._scrollHeight = null\n }\n\n // Private\n\n _getConfig(config) {\n config = {\n ...Default,\n ...typeof config === 'object' && config ? config : {}\n }\n\n if (typeof config.target !== 'string' && Util.isElement(config.target)) {\n let id = $(config.target).attr('id')\n if (!id) {\n id = Util.getUID(NAME)\n $(config.target).attr('id', id)\n }\n config.target = `#${id}`\n }\n\n Util.typeCheckConfig(NAME, config, DefaultType)\n\n return config\n }\n\n _getScrollTop() {\n return this._scrollElement === window\n ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop\n }\n\n _getScrollHeight() {\n return this._scrollElement.scrollHeight || Math.max(\n document.body.scrollHeight,\n document.documentElement.scrollHeight\n )\n }\n\n _getOffsetHeight() {\n return this._scrollElement === window\n ? window.innerHeight : this._scrollElement.getBoundingClientRect().height\n }\n\n _process() {\n const scrollTop = this._getScrollTop() + this._config.offset\n const scrollHeight = this._getScrollHeight()\n const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight()\n\n if (this._scrollHeight !== scrollHeight) {\n this.refresh()\n }\n\n if (scrollTop >= maxScroll) {\n const target = this._targets[this._targets.length - 1]\n\n if (this._activeTarget !== target) {\n this._activate(target)\n }\n return\n }\n\n if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n this._activeTarget = null\n this._clear()\n return\n }\n\n for (let i = this._offsets.length; i--;) {\n const isActiveTarget = this._activeTarget !== this._targets[i] &&\n scrollTop >= this._offsets[i] &&\n (typeof this._offsets[i + 1] === 'undefined' ||\n scrollTop < this._offsets[i + 1])\n\n if (isActiveTarget) {\n this._activate(this._targets[i])\n }\n }\n }\n\n _activate(target) {\n this._activeTarget = target\n\n this._clear()\n\n const queries = this._selector\n .split(',')\n .map((selector) => `${selector}[data-target=\"${target}\"],${selector}[href=\"${target}\"]`)\n\n const $link = $([].slice.call(document.querySelectorAll(queries.join(','))))\n\n if ($link.hasClass(CLASS_NAME_DROPDOWN_ITEM)) {\n $link.closest(SELECTOR_DROPDOWN)\n .find(SELECTOR_DROPDOWN_TOGGLE)\n .addClass(CLASS_NAME_ACTIVE)\n $link.addClass(CLASS_NAME_ACTIVE)\n } else {\n // Set triggered link as active\n $link.addClass(CLASS_NAME_ACTIVE)\n // Set triggered links parents as active\n // With both