diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b3828c2..34f2454 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,26 +1,26 @@ -name: Deploy Pruebas - -on: - push: - branches: - - master - -jobs: - deploy: - runs-on: ubuntu-latest - environment: - name: pruebasPAAD - steps: - - name: Checkout code - uses: actions/checkout@v2 - - - name: Deploy to Server - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.SERVER_IP }} - username: ${{ secrets.SERVER_USER }} - key: ${{ secrets.SSH_PRIVATE_KEY }} - script: | - cd /usr/share/nginx/html/paad/ - git fetch --all +name: Deploy Pruebas + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-latest + environment: + name: pruebasPAAD + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Deploy to Server + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.SERVER_IP }} + username: ${{ secrets.SERVER_USER }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + script: | + cd /usr/share/nginx/html/paad/ + git fetch --all git reset --hard origin/master \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2dd6ce4..3e92d13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,17 @@ -composer.phar -/vendor/ - -/temp/ -/template/ -/node_modules/ -/include/nusoap/ -/fonts/ -/imagenes/ -/concept/ -/backup/ -/.vscode/ -/log/ - -/include/.env -*/.env -log/asistencias_2023_08.log +composer.phar +/vendor/ + +/temp/ +/template/ +/node_modules/ +/include/nusoap/ +/fonts/ +/imagenes/ +/concept/ +/backup/ +/.vscode/ +/log/ + +/include/.env +*/.env +log/asistencias_2023_08.log diff --git a/README.md b/README.md index a5be8e3..3cde9f5 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,13 @@ -# Checador de Profesor de la Universidad La Salle 馃帗 - -![Imagen Institucional de La Salle](https://paad.lci.ulsa.mx/imagenes/logo_lasalle.png) - -## Descripci贸n - -Herramienta dise帽ada para el registro y control de asistencia de profesores en la Universidad La Salle. Asegura que los profesores realicen el registro de su entrada y salida y proporciona herramientas de auditor铆a para supervisores. - -## Caracter铆sticas - -- Registro de entrada de profesores. -- Base de datos segura con informaci贸n del profesor. -- Herramientas de auditor铆a para supervisores. +# Checador de Profesor de la Universidad La Salle 馃帗 + +![Imagen Institucional de La Salle](https://paad.lci.ulsa.mx/imagenes/logo_lasalle.png) + +## Descripci贸n + +Herramienta dise帽ada para el registro y control de asistencia de profesores en la Universidad La Salle. Asegura que los profesores realicen el registro de su entrada y salida y proporciona herramientas de auditor铆a para supervisores. + +## Caracter铆sticas + +- Registro de entrada de profesores. +- Base de datos segura con informaci贸n del profesor. +- Herramientas de auditor铆a para supervisores. diff --git a/action/action_avisos.php b/action/action_avisos.php index 18c03ff..e0ac346 100644 --- a/action/action_avisos.php +++ b/action/action_avisos.php @@ -1,52 +1,52 @@ - 'unauthorized'])); -} -$user = unserialize($_SESSION['user']); - -// check method -try { - if ($_SERVER['REQUEST_METHOD'] === 'GET') { - $data = $db->query( - 'SELECT * FROM AVISO', - [ - ':facultad_id' => $user->facultad['facultad_id'], - ':fecha_inicio' => $_GET['fecha'] ?? $_GET['fecha_inicio'] ?? null, - ':fecha_fin' => $_GET['fecha'] ?? $_GET['fecha_fin'] ?? null, - ] - ); - - $last_query = [ - 'query' => $db->getLastQuery(), - ]; - - echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); - } else { - http_response_code(405); - echo json_encode(['error' => 'method not allowed']); - exit; - } -} catch (PDOException $th) { - http_response_code(500); - echo json_encode([ - 'error' => $th->getMessage(), - 'query' => $db->getLastQuery(), - ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR); - exit; -} catch (Exception $th) { - http_response_code(500); - echo json_encode([ - 'error' => $th->getMessage(), - ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); - exit; + 'unauthorized'])); +} +$user = unserialize($_SESSION['user']); + +// check method +try { + if ($_SERVER['REQUEST_METHOD'] === 'GET') { + $data = $db->query( + 'SELECT * FROM AVISO', + [ + ':facultad_id' => $user->facultad['facultad_id'], + ':fecha_inicio' => $_GET['fecha'] ?? $_GET['fecha_inicio'] ?? null, + ':fecha_fin' => $_GET['fecha'] ?? $_GET['fecha_fin'] ?? null, + ] + ); + + $last_query = [ + 'query' => $db->getLastQuery(), + ]; + + echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + } else { + http_response_code(405); + echo json_encode(['error' => 'method not allowed']); + exit; + } +} catch (PDOException $th) { + http_response_code(500); + echo json_encode([ + 'error' => $th->getMessage(), + 'query' => $db->getLastQuery(), + ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR); + exit; +} catch (Exception $th) { + http_response_code(500); + echo json_encode([ + 'error' => $th->getMessage(), + ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + exit; } \ No newline at end of file diff --git a/action/action_login.php b/action/action_login.php index f0dc374..b3ce913 100644 --- a/action/action_login.php +++ b/action/action_login.php @@ -36,7 +36,7 @@ if (is_array($user)) { } else { $_SESSION['user'] = serialize($user); - header("Location: " . (isset($_SESSION['ruta']) ? $_SESSION['ruta'] : "../main.php")); + header("Location: " . ($_SESSION['ruta'] ?? "../main.php")); } exit; \ No newline at end of file diff --git a/action/action_puestos_excel.php b/action/action_puestos_excel.php index 50d6a74..ad6046f 100644 --- a/action/action_puestos_excel.php +++ b/action/action_puestos_excel.php @@ -1,81 +1,81 @@ - 'unauthorized'])); -} -$user = unserialize($_SESSION['user']); - -$facultad_id = $user->facultad["facultad_id"]; - -use PhpOffice\PhpSpreadsheet\Spreadsheet; -use PhpOffice\PhpSpreadsheet\IOFactory; - -// Create the Spreadsheet -$spreadsheet = new Spreadsheet(); - -// Get data for each 'puesto' -$puestos = $db->orderBy('nombre')->where('facultad_id', $facultad_id)->get('puesto', columns: ['nombre', 'puesto_id']); - -$sheetIndex = 0; // To track and switch between sheets - -foreach ($puestos as $puesto) { - // Create a new worksheet for each 'puesto' - if ($sheetIndex == 0) { - // Use the first default sheet - $sheet = $spreadsheet->getActiveSheet(); - $sheet->setTitle(substr($puesto['nombre'], 0, 31)); // Name the first sheet - } else { - $sheet = $spreadsheet->createSheet(); // Create new sheet - $sheet->setTitle(substr($puesto['nombre'], 0, 31)); // Set sheet title to puesto name - } - - // Get associated materias for current puesto - $materias = $db - ->join('materia m', 'm.materia_id = pm.materia_id') - ->orderBy('materia_nombre') - ->where('puesto_id', $puesto['puesto_id']) - ->get('puesto_materia pm', columns: ['clave_materia', 'materia_nombre']); - - $sheet->setCellValue('A1', $puesto['nombre']); - - // Add header row for each 'materia' table - $sheet->setCellValue('A2', 'Clave Materia'); - $sheet->setCellValue('B2', 'Materia Nombre'); - - // Set some styling for headers - $sheet->getStyle('A2:B2')->getFont()->setBold(true); - $sheet->getStyle('A2:B2')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); - - // Start populating from the second row - $row = 2; - - // Populate the sheet with materias data - foreach ($materias as $materia) { - $sheet->setCellValue("A$row", $materia['clave_materia']); - $sheet->setCellValue("B$row", $materia['materia_nombre']); - $row++; - } - - // Auto-size columns - foreach (range('A', 'B') as $column) { - $sheet->getColumnDimension($column)->setAutoSize(true); - } - - // Move to the next sheet index - $sheetIndex++; -} - -// Set the first sheet as active when the Excel file is opened -$spreadsheet->setActiveSheetIndex(0); - -// Output the file for download -header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); -header('Content-Disposition: attachment;filename="materias_por_puesto.xlsx"'); -header('Cache-Control: max-age=0'); - -$writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); -$writer->save('php://output'); + 'unauthorized'])); +} +$user = unserialize($_SESSION['user']); + +$facultad_id = $user->facultad["facultad_id"]; + +use PhpOffice\PhpSpreadsheet\Spreadsheet; +use PhpOffice\PhpSpreadsheet\IOFactory; + +// Create the Spreadsheet +$spreadsheet = new Spreadsheet(); + +// Get data for each 'puesto' +$puestos = $db->orderBy('nombre')->where('facultad_id', $facultad_id)->get('puesto', columns: ['nombre', 'puesto_id']); + +$sheetIndex = 0; // To track and switch between sheets + +foreach ($puestos as $puesto) { + // Create a new worksheet for each 'puesto' + if ($sheetIndex == 0) { + // Use the first default sheet + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setTitle(substr($puesto['nombre'], 0, 31)); // Name the first sheet + } else { + $sheet = $spreadsheet->createSheet(); // Create new sheet + $sheet->setTitle(substr($puesto['nombre'], 0, 31)); // Set sheet title to puesto name + } + + // Get associated materias for current puesto + $materias = $db + ->join('materia m', 'm.materia_id = pm.materia_id') + ->orderBy('materia_nombre') + ->where('puesto_id', $puesto['puesto_id']) + ->get('puesto_materia pm', columns: ['clave_materia', 'materia_nombre']); + + $sheet->setCellValue('A1', $puesto['nombre']); + + // Add header row for each 'materia' table + $sheet->setCellValue('A2', 'Clave Materia'); + $sheet->setCellValue('B2', 'Materia Nombre'); + + // Set some styling for headers + $sheet->getStyle('A2:B2')->getFont()->setBold(true); + $sheet->getStyle('A2:B2')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER); + + // Start populating from the second row + $row = 2; + + // Populate the sheet with materias data + foreach ($materias as $materia) { + $sheet->setCellValue("A$row", $materia['clave_materia']); + $sheet->setCellValue("B$row", $materia['materia_nombre']); + $row++; + } + + // Auto-size columns + foreach (range('A', 'B') as $column) { + $sheet->getColumnDimension($column)->setAutoSize(true); + } + + // Move to the next sheet index + $sheetIndex++; +} + +// Set the first sheet as active when the Excel file is opened +$spreadsheet->setActiveSheetIndex(0); + +// Output the file for download +header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); +header('Content-Disposition: attachment;filename="materias_por_puesto.xlsx"'); +header('Cache-Control: max-age=0'); + +$writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); +$writer->save('php://output'); diff --git a/action/action_usuarios_delete.php b/action/action_usuarios_delete.php index 77e33ba..e29ae09 100644 --- a/action/action_usuarios_delete.php +++ b/action/action_usuarios_delete.php @@ -1,15 +1,15 @@ -querySingle("UPDATE usuario SET estado_baja = TRUE WHERE usuario_id = ?", [$_GET['id']]); - header("Location: ../usuarios.php", true, 307); -} catch (PDOException $e) { - header("Location: ../usuarios.php?error=2"); - exit; -} +querySingle("UPDATE usuario SET estado_baja = TRUE WHERE usuario_id = ?", [$_GET['id']]); + header("Location: ../usuarios.php", true, 307); +} catch (PDOException $e) { + header("Location: ../usuarios.php?error=2"); + exit; +} diff --git a/action/asignacion_delete.php b/action/asignacion_delete.php index 5605d9d..8618965 100644 --- a/action/asignacion_delete.php +++ b/action/asignacion_delete.php @@ -1,33 +1,33 @@ -user["id"]; - - try{ - $db->query('SELECT * from fd_asignacion_solicitud(:id, :creador)', [":id"=> $id, ":creador"=>$creador]); - $return["ok"] = "La solicitud se borr贸 correctamente"; - - }catch(Exception $e){ - $return["error"] = "Ocurri贸 un error al borrar la solicitud de sal贸n."; - } - - -} -echo json_encode($return); -?> +user["id"]; + + try{ + $db->query('SELECT * from fd_asignacion_solicitud(:id, :creador)', [":id"=> $id, ":creador"=>$creador]); + $return["ok"] = "La solicitud se borr贸 correctamente"; + + }catch(Exception $e){ + $return["error"] = "Ocurri贸 un error al borrar la solicitud de sal贸n."; + } + + +} +echo json_encode($return); +?> diff --git a/action/asignacion_insert.php b/action/asignacion_insert.php index 3a3a593..4f58cd6 100644 --- a/action/asignacion_insert.php +++ b/action/asignacion_insert.php @@ -1,186 +1,186 @@ -access(); - -$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//Id reposicion -$fecha = trim(htmlspecialchars($_POST["fecha_inicial"], ENT_QUOTES, "UTF-8"));//limpia texto -$hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad -if(isset($_POST["salon"]) && $_POST["salon"] != "") - $salon = filter_input(INPUT_POST, "salon", FILTER_SANITIZE_NUMBER_INT);//limpia texto - -if(empty($_POST["prof"])) - $prof = $user["id"]; -else - $prof = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto -//if(isset($_POST["salon"]) && $_POST["salon"] != "") -//$salon = trim(filter_input(INPUT_POST, "salon", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto -$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto - -$aula_rs = $db->querySingle("select tipoaula_nombre, tipoaula_supervisor from tipoaula where tipoaula_id = :id", [":id"=>$aula]); - - -$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); -$duracion_tiempo = $duracion_rs["duracion_interval"]; - -//-- Obtiene datos de horario regular de clase - -$hora = $hora_ini.":".$min_ini.":00"; -$fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; -$fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; -$dia_new = date('w', strtotime($fecha_new)); - -//Datos de dependencia de usuario -$fac_rs = $db->querySingle("SELECT facultad_nombre, clave_dependencia from facultad where facultad_id = :id_fac",[':id_fac' => $user->facultad["facultad_id"]] ); - -$salon_desc = "Pendiente"; -if(!empty($salon)){ - $salon_rs = $db->querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon', - [':id_salon' => $salon] - ); - if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){ - $salon_desc = "Pendiente"; - }else{ - $salon_json = json_decode($salon_rs["salon_array"], true); - if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ - unset($salon_json[0]); - } - $salon_desc = join(" / ",$salon_json); - } -} - -//Obtiene correos -$correos_rs = $db->query('SELECT coor.usuario_correo as coordinador_correo - from reposicion_solicitud rs - inner join profesor p on rs.profesor_id =p.profesor_id - inner join usuario u on u.usuario_id = rs.usuario_id - inner join horario_view hv on hv.horario_id = rs.horario_id - inner join usuario coor on hv.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord - where hv.facultad_id = :id_fac', - [':rol_coord' => COORDINADOR, ':id_fac' => $user->facultad["facultad_id"]] - ); -$coord_correos=[]; -foreach($correos_rs as $correo){ - if( count($coord_correos)==0 && $correo["coordinador_correo"]!=""){ - if(!isset($coord_correos["correo"]) || !in_array($correo["coordinador_correo"], $coord_correos["correo"])){ - array_push($coord_correos, $correo["coordinador_correo"]); - } - } -} - -$correosSup_rs = $db->querySingle("SELECT DISTINCT sup.usuario_correo as coordinador_correo - FROM horario_supervisor hs - inner join usuario sup on sup.usuario_id =hs.usuario_id - where :id_fac = ANY(hs.facultad_id_array) - and sup.usuario_correo is not null and sup.usuario_correo != ''", - [':id_fac' => $user->facultad["facultad_id"]] ); - - -// Valida que grupo no tenga clases -/*$result = validaConflictoHoras($pdo, $gpo, $dia_new, $hora, $materia, "-", $fecha_new, $fecha_fin_new, $duracion); -if($result != ""){//error - //echo $result; - header("Location:".$pag."?error=7"); - exit(); -} -*/ -//Valida que profesor no este en 2 reposiciones al mismo tiempo en la fecha nueva - -$traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)', - [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo] -)["traslape_profesor_reposicion"]; -if($traslape){ - //print_r($_POST); - //echo "SELECT * from traslape_profesor_reposicion($prof,'".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."' , '$hora', $duracion)"; - - header("Location:".$pag."?error=9"); - exit(); -} - -try{ - $edo = 1; - if(!$user->jefe_carrera) - $edo = 2; - - //echo "SELECT * from fi_asignacion_solicitud( $fecha_new, $hora, $prof, $edo, $comentario, $alumnos, $aula, $duracion_tiempo, ".$user->user["id"].")"; exit(); - $db->query('SELECT * from fi_asignacion_solicitud(:f_nueva, :hora_nueva, :prof, :edo, :desc, :alumnos, :aula, :duracion, :usr)', - [':f_nueva' => $fecha_new, ':hora_nueva' => $hora, - ':prof' => $prof, ':edo'=>$edo, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"] - ] - ); -}catch(Exception $e){ - echo $e->getMessage(); - //header("Location: ".$pag."?error=1"); - exit(); -} - -$asunto = ""; -$texto = ""; -$to = ""; -switch($edo){ - case 1://Correo a coordinador - if( count($coord_correos) > 0 ){ - $to = join(",", $coord_correos); - } - $asunto = "Solicitud de salon nueva"; - $texto = "

Se cre贸 una solicitud de asignaci贸n de sal贸n nueva.

"; - $texto .= "

Se solicita un espacio de tipo ".mb_strtoupper($aula_rs["tipoaula_nombre"])." para el d铆a ".$fecha." a las ".$hora." hrs. "; - $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; - break; - case 2://Correo a supervisor - $asunto = "Solicitud de salon nueva - ".$fac_rs["clave_dependencia"]." ".$fac_rs["facultad_nombre"]; - //crear plantilla - $texto = "

Se cre贸 una solicitud de asignaci贸n de sal贸n nueva para: ".$fac_rs["clave_dependencia"]." ".$fac_rs["facultad_nombre"].".

"; - $texto .= "

Para el d铆a ".$fecha." a las ".$hora." hrs. "; - if(!$aula_rs["tipoaula_supervisor"]){ - $texto .= " en el sal贸n: ".$salon_desc."

"; - }else{ - $texto .= " en un sal贸n de tipo: ".mb_strtoupper($aula_rs["tipoaula_nombre"])."

"; - } - $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; - $to = join(",", $correosSup_rs); - break; -} - -/* -$log = new LogActividad(); -$desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."] Alumnos[".$alumnos."]"; -$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ - - - -if($to!= "" && ENVIO_CORREOS){ - //crear plantilla - $texto = ' - La Salle - '.$texto.' - '; - - require_once('../include/phpmailer/PHPMailerAutoload.php'); - if($_ENV['DB_NAME'] == "paad_pruebas"){ - $asunto = "PRUEBAS-".$asunto; - Mailer::enviarCorreo("alejandro.lara@lasalle.mx", $asunto, $texto, true); - }else{ - Mailer::enviarCorreo($to, $asunto, $texto, true); - } -} - -header("Location: ".$pag."?ok=0"); -?> +access(); + +$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//Id reposicion +$fecha = trim(htmlspecialchars($_POST["fecha_inicial"], ENT_QUOTES, "UTF-8"));//limpia texto +$hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad +if(isset($_POST["salon"]) && $_POST["salon"] != "") + $salon = filter_input(INPUT_POST, "salon", FILTER_SANITIZE_NUMBER_INT);//limpia texto + +if(empty($_POST["prof"])) + $prof = $user["id"]; +else + $prof = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto +//if(isset($_POST["salon"]) && $_POST["salon"] != "") +//$salon = trim(filter_input(INPUT_POST, "salon", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto +$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto + +$aula_rs = $db->querySingle("select tipoaula_nombre, tipoaula_supervisor from tipoaula where tipoaula_id = :id", [":id"=>$aula]); + + +$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); +$duracion_tiempo = $duracion_rs["duracion_interval"]; + +//-- Obtiene datos de horario regular de clase + +$hora = $hora_ini.":".$min_ini.":00"; +$fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; +$fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; +$dia_new = date('w', strtotime($fecha_new)); + +//Datos de dependencia de usuario +$fac_rs = $db->querySingle("SELECT facultad_nombre, clave_dependencia from facultad where facultad_id = :id_fac",[':id_fac' => $user->facultad["facultad_id"]] ); + +$salon_desc = "Pendiente"; +if(!empty($salon)){ + $salon_rs = $db->querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon', + [':id_salon' => $salon] + ); + if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){ + $salon_desc = "Pendiente"; + }else{ + $salon_json = json_decode($salon_rs["salon_array"], true); + if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ + unset($salon_json[0]); + } + $salon_desc = join(" / ",$salon_json); + } +} + +//Obtiene correos +$correos_rs = $db->query('SELECT coor.usuario_correo as coordinador_correo + from reposicion_solicitud rs + inner join profesor p on rs.profesor_id =p.profesor_id + inner join usuario u on u.usuario_id = rs.usuario_id + inner join horario_view hv on hv.horario_id = rs.horario_id + inner join usuario coor on hv.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord + where hv.facultad_id = :id_fac', + [':rol_coord' => COORDINADOR, ':id_fac' => $user->facultad["facultad_id"]] + ); +$coord_correos=[]; +foreach($correos_rs as $correo){ + if( count($coord_correos)==0 && $correo["coordinador_correo"]!=""){ + if(!isset($coord_correos["correo"]) || !in_array($correo["coordinador_correo"], $coord_correos["correo"])){ + array_push($coord_correos, $correo["coordinador_correo"]); + } + } +} + +$correosSup_rs = $db->querySingle("SELECT DISTINCT sup.usuario_correo as coordinador_correo + FROM horario_supervisor hs + inner join usuario sup on sup.usuario_id =hs.usuario_id + where :id_fac = ANY(hs.facultad_id_array) + and sup.usuario_correo is not null and sup.usuario_correo != ''", + [':id_fac' => $user->facultad["facultad_id"]] ); + + +// Valida que grupo no tenga clases +/*$result = validaConflictoHoras($pdo, $gpo, $dia_new, $hora, $materia, "-", $fecha_new, $fecha_fin_new, $duracion); +if($result != ""){//error + //echo $result; + header("Location:".$pag."?error=7"); + exit(); +} +*/ +//Valida que profesor no este en 2 reposiciones al mismo tiempo en la fecha nueva + +$traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)', + [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo] +)["traslape_profesor_reposicion"]; +if($traslape){ + //print_r($_POST); + //echo "SELECT * from traslape_profesor_reposicion($prof,'".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."' , '$hora', $duracion)"; + + header("Location:".$pag."?error=9"); + exit(); +} + +try{ + $edo = 1; + if(!$user->jefe_carrera) + $edo = 2; + + //echo "SELECT * from fi_asignacion_solicitud( $fecha_new, $hora, $prof, $edo, $comentario, $alumnos, $aula, $duracion_tiempo, ".$user->user["id"].")"; exit(); + $db->query('SELECT * from fi_asignacion_solicitud(:f_nueva, :hora_nueva, :prof, :edo, :desc, :alumnos, :aula, :duracion, :usr)', + [':f_nueva' => $fecha_new, ':hora_nueva' => $hora, + ':prof' => $prof, ':edo'=>$edo, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"] + ] + ); +}catch(Exception $e){ + echo $e->getMessage(); + //header("Location: ".$pag."?error=1"); + exit(); +} + +$asunto = ""; +$texto = ""; +$to = ""; +switch($edo){ + case 1://Correo a coordinador + if( count($coord_correos) > 0 ){ + $to = join(",", $coord_correos); + } + $asunto = "Solicitud de salon nueva"; + $texto = "

Se cre贸 una solicitud de asignaci贸n de sal贸n nueva.

"; + $texto .= "

Se solicita un espacio de tipo ".mb_strtoupper($aula_rs["tipoaula_nombre"])." para el d铆a ".$fecha." a las ".$hora." hrs. "; + $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; + break; + case 2://Correo a supervisor + $asunto = "Solicitud de salon nueva - ".$fac_rs["clave_dependencia"]." ".$fac_rs["facultad_nombre"]; + //crear plantilla + $texto = "

Se cre贸 una solicitud de asignaci贸n de sal贸n nueva para: ".$fac_rs["clave_dependencia"]." ".$fac_rs["facultad_nombre"].".

"; + $texto .= "

Para el d铆a ".$fecha." a las ".$hora." hrs. "; + if(!$aula_rs["tipoaula_supervisor"]){ + $texto .= " en el sal贸n: ".$salon_desc."

"; + }else{ + $texto .= " en un sal贸n de tipo: ".mb_strtoupper($aula_rs["tipoaula_nombre"])."

"; + } + $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; + $to = join(",", $correosSup_rs); + break; +} + +/* +$log = new LogActividad(); +$desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."] Alumnos[".$alumnos."]"; +$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ + + + +if($to!= "" && ENVIO_CORREOS){ + //crear plantilla + $texto = ' + La Salle + '.$texto.' + '; + + require_once('../include/phpmailer/PHPMailerAutoload.php'); + if($_ENV['DB_NAME'] == "paad_pruebas"){ + $asunto = "PRUEBAS-".$asunto; + Mailer::enviarCorreo("alejandro.lara@lasalle.mx", $asunto, $texto, true); + }else{ + Mailer::enviarCorreo($to, $asunto, $texto, true); + } +} + +header("Location: ".$pag."?ok=0"); +?> diff --git a/action/asignacion_select.php b/action/asignacion_select.php index f23784a..c90fd36 100644 --- a/action/asignacion_select.php +++ b/action/asignacion_select.php @@ -1,81 +1,81 @@ -tieneAcceso()){ - $return["error"] = "Error! No tienes permisos para realizar esta acci贸n."; -}else*/ if(!isset($_POST["id"])){ - $return["error"] = "Error! No se recibi贸 la informaci贸n de la reposici贸n."; -}else{ - $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto - - - try{ - if($user->rol["rol_id"] == 7){//es supervisor - $rs = $db->querySingle('SELECT * from fs_asignacion_solicitud(:id, NULL, NULL, :sup, NULL)', - [':id' => $id, ':sup'=>$user->user["id"]] - ); - }else{//coordinador - $rs = $db->querySingle('SELECT * from fs_asignacion_solicitud(:id, NULL, NULL, NULL, null)', - [':id' => $id] - ); - } - - }catch(Exception $e){ - $return["error"] = "Ocurri贸 un error al leer los datos de la reposici贸n."; - echo json_encode($return); - exit(); - } - - $return["fecha_nueva"] = date('d/m/Y', strtotime($rs["fecha_nueva"])); - $hora_nueva = explode(":",$rs["hora_nueva"]); - $return["hora_ini"] = $hora_nueva[0]; - $return["min_ini"] = $hora_nueva[1]; - $hora_nueva_fin = explode(":",$rs["hora_nueva_fin"]); - $return["hora_fin"] = $hora_nueva_fin[0]; - $return["min_fin"] = $hora_nueva_fin[1]; - $return["duracion"] = $rs["duracion_total"]; - -// $return["carrera"] = $rs["PlanEstudio_desc"]; -// $return["materia"] = $rs["materia_id"]; -// $return["materia_desc"] = $rs["materia_nombre"]; - $return["salon"] = $rs["salon_id"]; - if($rs["salon_id"]==""){ - $return["salon_desc"] = "Pendiente"; - }else{ - $salon_json = json_decode($rs["salon_array"], true); - if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ - unset($salon_json[0]); - } - $return["salon_desc"] = join(" / ",$salon_json); - } - - //$return["salon_desc"] = $rs["salon"]=="" ? "-Pendiente-": $rs["salon"]; - - $return["profesor"] = $rs["profesor_id"]; - $return["profesor_nombre"] = $rs["profesor_nombre"]; - $return["comentario"] = $rs["descripcion"]; - $return["alumnos"] = $rs["alumnos"]; - $return["aula"] = $rs["tipoaula_id"]; - $return["aula_desc"] = $rs["tipoaula_nombre"]; - $return["aula_supervisor"] = $rs["tipoaula_supervisor"]; - $return["dia"] = date('w', strtotime($rs["fecha_nueva"])); - $return["motivo_cancelacion"] = $rs["motivo_cancelacion"]; - $return["estado"] = $rs["estado_reposicion_id"]; - $return["facultad"] = $rs["facultad_nombre"]; - $return["supervisor_nombre"] = $rs["supervisor_nombre"]; -} -echo json_encode($return); -?> +tieneAcceso()){ + $return["error"] = "Error! No tienes permisos para realizar esta acci贸n."; +}else*/ if(!isset($_POST["id"])){ + $return["error"] = "Error! No se recibi贸 la informaci贸n de la reposici贸n."; +}else{ + $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto + + + try{ + if($user->rol["rol_id"] == 7){//es supervisor + $rs = $db->querySingle('SELECT * from fs_asignacion_solicitud(:id, NULL, NULL, :sup, NULL)', + [':id' => $id, ':sup'=>$user->user["id"]] + ); + }else{//coordinador + $rs = $db->querySingle('SELECT * from fs_asignacion_solicitud(:id, NULL, NULL, NULL, null)', + [':id' => $id] + ); + } + + }catch(Exception $e){ + $return["error"] = "Ocurri贸 un error al leer los datos de la reposici贸n."; + echo json_encode($return); + exit(); + } + + $return["fecha_nueva"] = date('d/m/Y', strtotime($rs["fecha_nueva"])); + $hora_nueva = explode(":",$rs["hora_nueva"]); + $return["hora_ini"] = $hora_nueva[0]; + $return["min_ini"] = $hora_nueva[1]; + $hora_nueva_fin = explode(":",$rs["hora_nueva_fin"]); + $return["hora_fin"] = $hora_nueva_fin[0]; + $return["min_fin"] = $hora_nueva_fin[1]; + $return["duracion"] = $rs["duracion_total"]; + +// $return["carrera"] = $rs["PlanEstudio_desc"]; +// $return["materia"] = $rs["materia_id"]; +// $return["materia_desc"] = $rs["materia_nombre"]; + $return["salon"] = $rs["salon_id"]; + if($rs["salon_id"]==""){ + $return["salon_desc"] = "Pendiente"; + }else{ + $salon_json = json_decode($rs["salon_array"], true); + if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ + unset($salon_json[0]); + } + $return["salon_desc"] = join(" / ",$salon_json); + } + + //$return["salon_desc"] = $rs["salon"]=="" ? "-Pendiente-": $rs["salon"]; + + $return["profesor"] = $rs["profesor_id"]; + $return["profesor_nombre"] = $rs["profesor_nombre"]; + $return["comentario"] = $rs["descripcion"]; + $return["alumnos"] = $rs["alumnos"]; + $return["aula"] = $rs["tipoaula_id"]; + $return["aula_desc"] = $rs["tipoaula_nombre"]; + $return["aula_supervisor"] = $rs["tipoaula_supervisor"]; + $return["dia"] = date('w', strtotime($rs["fecha_nueva"])); + $return["motivo_cancelacion"] = $rs["motivo_cancelacion"]; + $return["estado"] = $rs["estado_reposicion_id"]; + $return["facultad"] = $rs["facultad_nombre"]; + $return["supervisor_nombre"] = $rs["supervisor_nombre"]; +} +echo json_encode($return); +?> diff --git a/action/asignacion_update.php b/action/asignacion_update.php index ca3a686..b2a448a 100644 --- a/action/asignacion_update.php +++ b/action/asignacion_update.php @@ -1,135 +1,135 @@ - FILTER_FLAG_STRIP_LOW)));//limpia texto -$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto - -$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); -$duracion_tiempo = $duracion_rs["duracion_interval"]; - - - -$hora = $hora_ini.":".$min_ini.":00"; -$fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; -$fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; -$dia_new = date('w', strtotime($fecha_new)); - -//echo $fecha_new."
"; -//echo $fecha_fin_new."
"; -$fac_rs = $db->querySingle("SELECT facultad_nombre, clave_dependencia from facultad where facultad_id = :id_fac",[':id_fac' => $user->facultad["facultad_id"]] ); - -$salon_desc = "Pendiente"; -if(!empty($salon)){ - $salon_rs = $db->querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon', - [':id_salon' => $salon] - ); - if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){ - $salon_desc = "Pendiente"; - }else{ - $salon_json = json_decode($salon_rs["salon_array"], true); - if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ - unset($salon_json[0]); - } - $salon_desc = join(" / ",$salon_json); - } -} - -//Obtiene correos -$correos_rs = $db->query('SELECT coor.usuario_correo as coordinador_correo - from reposicion_solicitud rs - inner join profesor p on rs.profesor_id =p.profesor_id - inner join usuario u on u.usuario_id = rs.usuario_id - inner join horario_view hv on hv.horario_id = rs.horario_id - inner join usuario coor on hv.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord - where hv.facultad_id = :id_fac', - [':rol_coord' => COORDINADOR, ':id_fac' => $user->facultad["facultad_id"]] - ); -$coord_correos=[]; -foreach($correos_rs as $correo){ - if( count($coord_correos)==0 && $correo["coordinador_correo"]!=""){ - if(!isset($coord_correos["correo"]) || !in_array($correo["coordinador_correo"], $coord_correos["correo"])){ - array_push($coord_correos, $correo["coordinador_correo"]); - } - } -} - -$correosSup_rs = $db->querySingle("SELECT DISTINCT sup.usuario_correo as coordinador_correo - FROM horario_supervisor hs - inner join usuario sup on sup.usuario_id =hs.usuario_id - where :id_fac = ANY(hs.facultad_id_array) - and sup.usuario_correo is not null and sup.usuario_correo != ''", - [':id_fac' => $user->facultad["facultad_id"]] ); - - -//Valida que profesor no este en 2 reposiciones al mismo tiempo -$traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur, :id)', -[':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo, ':id'=>$id] -)["traslape_profesor_reposicion"]; -echo "SELECT * from traslape_profesor_reposicion($prof, '".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."', $hora, $duracion_tiempo, $id)"; -if($traslape){ - //header("Location:".$pag."?error=9"); - echo "traslape"; - exit(); -} - - -/* -$log = new LogActividad(); -$desc_log = "Actualiza reposici贸n ID[".$id."] Fechas[".$fecha_ini."][".$fecha_fin."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."]"; -$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ - -try{ - $db->query('SELECT * from fu_asignacion_solicitud(:id, :f_nueva, :hora_nueva, NULL, NULL, :desc, :alumnos, :aula, :duracion, NULL)', - [':id'=> $id, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, - ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo - ] - ); -}catch(Exception $e){ - //header("Location: ".$pag."?error=2"); - print_r($e->getMessage()); - echo "SELECT * from fu_asignacion_solicitud(:id, :f_nueva, :hora_nueva, NULL, NULL, :desc, :alumnos, :aula, :duracion, NULL)'"; - print_r( - [':id'=> $id, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, - ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo - ]); - exit(); -} -header("Location: ".$pag); -exit(); -?> + FILTER_FLAG_STRIP_LOW)));//limpia texto +$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto + +$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); +$duracion_tiempo = $duracion_rs["duracion_interval"]; + + + +$hora = $hora_ini.":".$min_ini.":00"; +$fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; +$fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; +$dia_new = date('w', strtotime($fecha_new)); + +//echo $fecha_new."
"; +//echo $fecha_fin_new."
"; +$fac_rs = $db->querySingle("SELECT facultad_nombre, clave_dependencia from facultad where facultad_id = :id_fac",[':id_fac' => $user->facultad["facultad_id"]] ); + +$salon_desc = "Pendiente"; +if(!empty($salon)){ + $salon_rs = $db->querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon', + [':id_salon' => $salon] + ); + if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){ + $salon_desc = "Pendiente"; + }else{ + $salon_json = json_decode($salon_rs["salon_array"], true); + if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ + unset($salon_json[0]); + } + $salon_desc = join(" / ",$salon_json); + } +} + +//Obtiene correos +$correos_rs = $db->query('SELECT coor.usuario_correo as coordinador_correo + from reposicion_solicitud rs + inner join profesor p on rs.profesor_id =p.profesor_id + inner join usuario u on u.usuario_id = rs.usuario_id + inner join horario_view hv on hv.horario_id = rs.horario_id + inner join usuario coor on hv.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord + where hv.facultad_id = :id_fac', + [':rol_coord' => COORDINADOR, ':id_fac' => $user->facultad["facultad_id"]] + ); +$coord_correos=[]; +foreach($correos_rs as $correo){ + if( count($coord_correos)==0 && $correo["coordinador_correo"]!=""){ + if(!isset($coord_correos["correo"]) || !in_array($correo["coordinador_correo"], $coord_correos["correo"])){ + array_push($coord_correos, $correo["coordinador_correo"]); + } + } +} + +$correosSup_rs = $db->querySingle("SELECT DISTINCT sup.usuario_correo as coordinador_correo + FROM horario_supervisor hs + inner join usuario sup on sup.usuario_id =hs.usuario_id + where :id_fac = ANY(hs.facultad_id_array) + and sup.usuario_correo is not null and sup.usuario_correo != ''", + [':id_fac' => $user->facultad["facultad_id"]] ); + + +//Valida que profesor no este en 2 reposiciones al mismo tiempo +$traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur, :id)', +[':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo, ':id'=>$id] +)["traslape_profesor_reposicion"]; +echo "SELECT * from traslape_profesor_reposicion($prof, '".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."', $hora, $duracion_tiempo, $id)"; +if($traslape){ + //header("Location:".$pag."?error=9"); + echo "traslape"; + exit(); +} + + +/* +$log = new LogActividad(); +$desc_log = "Actualiza reposici贸n ID[".$id."] Fechas[".$fecha_ini."][".$fecha_fin."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."]"; +$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ + +try{ + $db->query('SELECT * from fu_asignacion_solicitud(:id, :f_nueva, :hora_nueva, NULL, NULL, :desc, :alumnos, :aula, :duracion, NULL)', + [':id'=> $id, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, + ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo + ] + ); +}catch(Exception $e){ + //header("Location: ".$pag."?error=2"); + print_r($e->getMessage()); + echo "SELECT * from fu_asignacion_solicitud(:id, :f_nueva, :hora_nueva, NULL, NULL, :desc, :alumnos, :aula, :duracion, NULL)'"; + print_r( + [':id'=> $id, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, + ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo + ]); + exit(); +} +header("Location: ".$pag); +exit(); +?> diff --git a/action/asistenciasprofesor_select.php b/action/asistenciasprofesor_select.php index 59bd9e8..5c3dce6 100644 --- a/action/asistenciasprofesor_select.php +++ b/action/asistenciasprofesor_select.php @@ -1,26 +1,26 @@ -query('SELECT * from fs_asistenciaprofesor_horario(:id, :hor)', [':id' => $id, ':hor' => $hor]); - $asistArr = array(); - - foreach($rs as $row){ - $asistArr[] = $row["registro_fecha_ideal"]; - } - $return["asistenciaArr"] = $asistArr; -} -echo json_encode($return); -?> +query('SELECT * from fs_asistenciaprofesor_horario(:id, :hor)', [':id' => $id, ':hor' => $hor]); + $asistArr = array(); + + foreach($rs as $row){ + $asistArr[] = $row["registro_fecha_ideal"]; + } + $return["asistenciaArr"] = $asistArr; +} +echo json_encode($return); +?> diff --git a/action/avisos.php b/action/avisos.php index 2a0b77a..f3a6017 100644 --- a/action/avisos.php +++ b/action/avisos.php @@ -1,293 +1,293 @@ - 'No se ha iniciado sesi贸n')); - exit(); -} -$user = Login::get_user(); -try { - - switch ($_SERVER['REQUEST_METHOD']) { - case 'GET': - $facultad_id = $user->facultad['facultad_id']; - $avisos = $db->query( - "SELECT * FROM aviso - WHERE - (CURRENT_DATE BETWEEN aviso_fecha_inicial AND aviso_fecha_final) AND - (facultad_id = :facultad_id OR :facultad_id IS NULL) AND - aviso_estado - ORDER BY aviso_id DESC", - array('facultad_id' => $facultad_id) - ); - - /* - if (empty($avisos)) { - header('HTTP/1.1 404 Not Found'); - echo json_encode(array('error' => 'No hay avisos disponibles')); - exit(); - } - */ - - $avisos = array_map(fn($aviso) => array( - ...$aviso, - 'carreras' => $db->query( - "SELECT carrera_id, carrera_nombre FROM aviso_carrera - JOIN carrera USING (carrera_id) - WHERE aviso_id = :aviso_id", - array('aviso_id' => $aviso['aviso_id']) - ), - 'profesores' => $db->query( - "SELECT profesor_id, profesor_clave, profesor_nombre FROM aviso_profesor - JOIN profesor USING (profesor_id) - WHERE aviso_id = :aviso_id", - array('aviso_id' => $aviso['aviso_id']) - ), - ), $avisos); - echo json_encode($avisos); - break; - case 'POST': - $raw_input = file_get_contents('php://input'); - if (empty($raw_input)) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(array('error' => 'No se recibieron par谩metros')); - exit(); - } - - $input_data = json_decode($raw_input); - if (json_last_error() !== JSON_ERROR_NONE) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(array('error' => 'Invalid JSON format')); - exit(); - } - - - $schema = <<validate($input_data, json_decode($schema)); - - if (!$validate->isValid()) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode( - array( - 'error' => 'El formato de la solicitud es incorrecto', - 'success' => false, - 'errors' => $validate->getErrors() - ) - ); - exit(); - } - - $aviso_id = $db->insert( - 'aviso', - array( - 'aviso_fecha_inicial' => $input_data->aviso_fecha_inicial, - 'aviso_fecha_final' => $input_data->aviso_fecha_final, - 'aviso_texto' => $input_data->aviso_texto, - 'facultad_id' => $user->facultad['facultad_id'], - ), - 'aviso_id' - ); - - if (isset($input_data->carreras)) { - array_walk($input_data->carreras, fn($carrera_id) => $db->insert('aviso_carrera', array('aviso_id' => $aviso_id, 'carrera_id' => $carrera_id))); - } - if (isset($input_data->profesores)) { - array_walk($input_data->profesores, fn($profesor_id) => $db->insert('aviso_profesor', array('aviso_id' => $aviso_id, 'profesor_id' => $profesor_id))); - } - - echo json_encode( - array( - 'aviso_id' => $aviso_id, - 'msg' => 'Aviso creado exitosamente', - 'success' => true - ) - ); - break; - case 'PUT': - $raw_input = file_get_contents('php://input'); - if (empty($raw_input)) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(array('error' => 'No se recibieron par谩metros')); - exit(); - } - - $input_data = json_decode($raw_input); - if (json_last_error() !== JSON_ERROR_NONE) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(array('error' => 'Invalid JSON format')); - exit(); - } - - $schema = <<validate($input_data, json_decode($schema)); - - if (!$validate->isValid()) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode( - array( - 'error' => 'El formato de la solicitud es incorrecto', - 'errors' => $validate->getErrors(), - 'success' => false, - ) - ); - exit(); - } - - $db->where('aviso_id', $input_data->aviso_id) - ->update( - 'aviso', - array( - 'aviso_fecha_final' => $input_data->aviso_fecha_final, - ), - ); - - if (isset($input_data->carreras)) { - $db->where('aviso_id', $input_data->aviso_id)->delete('aviso_carrera'); - array_walk($input_data->carreras, fn($carrera_id) => $db->insert('aviso_carrera', array('aviso_id' => $input_data->aviso_id, 'carrera_id' => $carrera_id))); - } - - if (isset($input_data->profesores)) { - $db->where('aviso_id', $input_data->aviso_id)->delete('aviso_profesor'); - array_walk($input_data->profesores, fn($profesor_id) => $db->insert('aviso_profesor', array('aviso_id' => $input_data->aviso_id, 'profesor_id' => $profesor_id))); - } - - echo json_encode( - array( - 'msg' => 'Aviso actualizado exitosamente', - 'success' => true - ) - ); - break; - - case 'DELETE': - $raw_input = file_get_contents('php://input'); - if (empty($raw_input)) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(array('error' => 'No se recibieron par谩metros')); - exit(); - } - - $input_data = json_decode($raw_input); - if (json_last_error() !== JSON_ERROR_NONE) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(array('error' => 'Invalid JSON format')); - exit(); - } - - $schema = <<validate($input_data, json_decode($schema)); - - if (!$validate->isValid()) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode( - array( - 'error' => 'El formato de la solicitud es incorrecto', - 'errors' => $validate->getErrors(), - 'success' => false, - ) - ); - exit(); - } - - $result = $db->where('aviso_id', $input_data->aviso_id)->update('aviso', array('aviso_estado' => false)); - echo json_encode( - array( - 'msg' => 'Aviso eliminado exitosamente', - 'success' => true, - 'result' => $result - ) - ); - - break; - } -} catch (PDOException $e) { - echo json_encode( - array( - 'error' => $e->getMessage(), - 'query' => $db->getLastQuery(), - 'exception' => $e->getTraceAsString() - ) - ); + 'No se ha iniciado sesi贸n')); + exit(); +} +$user = Login::get_user(); +try { + + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + $facultad_id = $user->facultad['facultad_id']; + $avisos = $db->query( + "SELECT * FROM aviso + WHERE + (CURRENT_DATE BETWEEN aviso_fecha_inicial AND aviso_fecha_final) AND + (facultad_id = :facultad_id OR :facultad_id IS NULL) AND + aviso_estado + ORDER BY aviso_id DESC", + array('facultad_id' => $facultad_id) + ); + + /* + if (empty($avisos)) { + header('HTTP/1.1 404 Not Found'); + echo json_encode(array('error' => 'No hay avisos disponibles')); + exit(); + } + */ + + $avisos = array_map(fn($aviso) => array( + ...$aviso, + 'carreras' => $db->query( + "SELECT carrera_id, carrera_nombre FROM aviso_carrera + JOIN carrera USING (carrera_id) + WHERE aviso_id = :aviso_id", + array('aviso_id' => $aviso['aviso_id']) + ), + 'profesores' => $db->query( + "SELECT profesor_id, profesor_clave, profesor_nombre FROM aviso_profesor + JOIN profesor USING (profesor_id) + WHERE aviso_id = :aviso_id", + array('aviso_id' => $aviso['aviso_id']) + ), + ), $avisos); + echo json_encode($avisos); + break; + case 'POST': + $raw_input = file_get_contents('php://input'); + if (empty($raw_input)) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(array('error' => 'No se recibieron par谩metros')); + exit(); + } + + $input_data = json_decode($raw_input); + if (json_last_error() !== JSON_ERROR_NONE) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(array('error' => 'Invalid JSON format')); + exit(); + } + + + $schema = <<validate($input_data, json_decode($schema)); + + if (!$validate->isValid()) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode( + array( + 'error' => 'El formato de la solicitud es incorrecto', + 'success' => false, + 'errors' => $validate->getErrors() + ) + ); + exit(); + } + + $aviso_id = $db->insert( + 'aviso', + array( + 'aviso_fecha_inicial' => $input_data->aviso_fecha_inicial, + 'aviso_fecha_final' => $input_data->aviso_fecha_final, + 'aviso_texto' => $input_data->aviso_texto, + 'facultad_id' => $user->facultad['facultad_id'], + ), + 'aviso_id' + ); + + if (isset($input_data->carreras)) { + array_walk($input_data->carreras, fn($carrera_id) => $db->insert('aviso_carrera', array('aviso_id' => $aviso_id, 'carrera_id' => $carrera_id))); + } + if (isset($input_data->profesores)) { + array_walk($input_data->profesores, fn($profesor_id) => $db->insert('aviso_profesor', array('aviso_id' => $aviso_id, 'profesor_id' => $profesor_id))); + } + + echo json_encode( + array( + 'aviso_id' => $aviso_id, + 'msg' => 'Aviso creado exitosamente', + 'success' => true + ) + ); + break; + case 'PUT': + $raw_input = file_get_contents('php://input'); + if (empty($raw_input)) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(array('error' => 'No se recibieron par谩metros')); + exit(); + } + + $input_data = json_decode($raw_input); + if (json_last_error() !== JSON_ERROR_NONE) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(array('error' => 'Invalid JSON format')); + exit(); + } + + $schema = <<validate($input_data, json_decode($schema)); + + if (!$validate->isValid()) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode( + array( + 'error' => 'El formato de la solicitud es incorrecto', + 'errors' => $validate->getErrors(), + 'success' => false, + ) + ); + exit(); + } + + $db->where('aviso_id', $input_data->aviso_id) + ->update( + 'aviso', + array( + 'aviso_fecha_final' => $input_data->aviso_fecha_final, + ), + ); + + if (isset($input_data->carreras)) { + $db->where('aviso_id', $input_data->aviso_id)->delete('aviso_carrera'); + array_walk($input_data->carreras, fn($carrera_id) => $db->insert('aviso_carrera', array('aviso_id' => $input_data->aviso_id, 'carrera_id' => $carrera_id))); + } + + if (isset($input_data->profesores)) { + $db->where('aviso_id', $input_data->aviso_id)->delete('aviso_profesor'); + array_walk($input_data->profesores, fn($profesor_id) => $db->insert('aviso_profesor', array('aviso_id' => $input_data->aviso_id, 'profesor_id' => $profesor_id))); + } + + echo json_encode( + array( + 'msg' => 'Aviso actualizado exitosamente', + 'success' => true + ) + ); + break; + + case 'DELETE': + $raw_input = file_get_contents('php://input'); + if (empty($raw_input)) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(array('error' => 'No se recibieron par谩metros')); + exit(); + } + + $input_data = json_decode($raw_input); + if (json_last_error() !== JSON_ERROR_NONE) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(array('error' => 'Invalid JSON format')); + exit(); + } + + $schema = <<validate($input_data, json_decode($schema)); + + if (!$validate->isValid()) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode( + array( + 'error' => 'El formato de la solicitud es incorrecto', + 'errors' => $validate->getErrors(), + 'success' => false, + ) + ); + exit(); + } + + $result = $db->where('aviso_id', $input_data->aviso_id)->update('aviso', array('aviso_estado' => false)); + echo json_encode( + array( + 'msg' => 'Aviso eliminado exitosamente', + 'success' => true, + 'result' => $result + ) + ); + + break; + } +} catch (PDOException $e) { + echo json_encode( + array( + 'error' => $e->getMessage(), + 'query' => $db->getLastQuery(), + 'exception' => $e->getTraceAsString() + ) + ); } \ No newline at end of file diff --git a/action/carrera.php b/action/carrera.php index 5d86594..fc64237 100644 --- a/action/carrera.php +++ b/action/carrera.php @@ -1,66 +1,66 @@ - 'No se ha iniciado sesi贸n']); - exit(); -} -$user = Login::get_user(); - -try { - switch ($_SERVER['REQUEST_METHOD']) { - case 'GET': - // Fetch all puestos - $facultad_id = $user->facultad['facultad_id']; - $periodo_nivel_id = $db->where('periodo_id', $user->periodo_id)->getOne('periodo', 'nivel_id')['nivel_id']; - $carreras = $db->query(<< $facultad_id, - 'periodo_nivel_id' => $periodo_nivel_id - ]); - echo json_encode($carreras); - break; - - case 'PUT': - // Update carrera {nivel_id} - $raw = file_get_contents('php://input'); - $data = json_decode($raw, true); - - if (!isset($data['carrera_id'], $data['nivel_id'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Falta el id de la carrera o el nivel']); - exit(); - } - - $carrera_id = $data['carrera_id']; - $nivel_id = $data['nivel_id']; - $db->where('carrera_id', $carrera_id)->update('carrera', ['nivel_id' => $nivel_id]); - - $carrera_nombre = $db->where('carrera_id', $carrera_id)->getOne('carrera', 'carrera_nombre')['carrera_nombre']; - $nivel_nombre = $db->where('nivel_id', $nivel_id)->getOne('nivel', 'nivel_nombre')['nivel_nombre']; - - echo json_encode(['success' => "$carrera_nombre actualizada a $nivel_nombre"]); - break; - default: - header('HTTP/1.1 405 Method Not Allowed'); - echo json_encode(['error' => 'M茅todo no permitido']); - break; - } -} catch (PDOException $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'query' => $db->getLastQuery(), - 'exception' => $e->getTraceAsString() - ]); + 'No se ha iniciado sesi贸n']); + exit(); +} +$user = Login::get_user(); + +try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + // Fetch all puestos + $facultad_id = $user->facultad['facultad_id']; + $periodo_nivel_id = $db->where('periodo_id', $user->periodo_id)->getOne('periodo', 'nivel_id')['nivel_id']; + $carreras = $db->query(<< $facultad_id, + 'periodo_nivel_id' => $periodo_nivel_id + ]); + echo json_encode($carreras); + break; + + case 'PUT': + // Update carrera {nivel_id} + $raw = file_get_contents('php://input'); + $data = json_decode($raw, true); + + if (!isset($data['carrera_id'], $data['nivel_id'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Falta el id de la carrera o el nivel']); + exit(); + } + + $carrera_id = $data['carrera_id']; + $nivel_id = $data['nivel_id']; + $db->where('carrera_id', $carrera_id)->update('carrera', ['nivel_id' => $nivel_id]); + + $carrera_nombre = $db->where('carrera_id', $carrera_id)->getOne('carrera', 'carrera_nombre')['carrera_nombre']; + $nivel_nombre = $db->where('nivel_id', $nivel_id)->getOne('nivel', 'nivel_nombre')['nivel_nombre']; + + echo json_encode(['success' => "$carrera_nombre actualizada a $nivel_nombre"]); + break; + default: + header('HTTP/1.1 405 Method Not Allowed'); + echo json_encode(['error' => 'M茅todo no permitido']); + break; + } +} catch (PDOException $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'query' => $db->getLastQuery(), + 'exception' => $e->getTraceAsString() + ]); } \ No newline at end of file diff --git a/action/correo.php b/action/correo.php index 7b5d092..ccee8fd 100644 --- a/action/correo.php +++ b/action/correo.php @@ -1,20 +1,20 @@ -?correo="; - exit(); -} - - -$to = $_GET["correo"]; -$texto = "

Esto es una prueba automatizada

El correo se envi贸 atutom谩ticamente, no debes hacer nada m谩s.

"; -$asunto="Prueba"; -Mailer::enviarCorreo($to, $asunto, $texto, true); -echo "Enviado!".date("H:i:s"); - -?> +?correo="; + exit(); +} + + +$to = $_GET["correo"]; +$texto = "

Esto es una prueba automatizada

El correo se envi贸 atutom谩ticamente, no debes hacer nada m谩s.

"; +$asunto="Prueba"; +Mailer::enviarCorreo($to, $asunto, $texto, true); +echo "Enviado!".date("H:i:s"); + +?> diff --git a/action/horario_profesor.php b/action/horario_profesor.php index bea48a6..06148cb 100644 --- a/action/horario_profesor.php +++ b/action/horario_profesor.php @@ -1,46 +1,46 @@ - 'No se ha iniciado sesi贸n']); - exit(); -} -$user = Login::get_user(); - -try { - switch ($_SERVER['REQUEST_METHOD']) { - case 'GET': - $profesor_id = $db - ->where('profesor_clave', $_GET['profesor']) - ->getOne('profesor', 'profesor_id'); - // Fetch all puestos - $horarios = $db->query(<<periodo_id, $profesor_id['profesor_id']] - ); - - echo json_encode($horarios); - break; - default: - header('HTTP/1.1 405 Method Not Allowed'); - echo json_encode(['error' => 'M茅todo no permitido']); - break; - } -} catch (PDOException $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'query' => $db->getLastQuery(), - 'exception' => $e->getTraceAsString() - ]); + 'No se ha iniciado sesi贸n']); + exit(); +} +$user = Login::get_user(); + +try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + $profesor_id = $db + ->where('profesor_clave', $_GET['profesor']) + ->getOne('profesor', 'profesor_id'); + // Fetch all puestos + $horarios = $db->query(<<periodo_id, $profesor_id['profesor_id']] + ); + + echo json_encode($horarios); + break; + default: + header('HTTP/1.1 405 Method Not Allowed'); + echo json_encode(['error' => 'M茅todo no permitido']); + break; + } +} catch (PDOException $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'query' => $db->getLastQuery(), + 'exception' => $e->getTraceAsString() + ]); } \ No newline at end of file diff --git a/action/justificar.php b/action/justificar.php index 4b9308b..60e3636 100644 --- a/action/justificar.php +++ b/action/justificar.php @@ -1,76 +1,76 @@ - 'No se ha iniciado sesi贸n']); - exit(); -} -$user = Login::get_user(); - -try { - switch ($_SERVER['REQUEST_METHOD']) { - case 'POST': - // check parameters - - $raw = file_get_contents('php://input'); - $post_data = json_decode($raw, true); - - $data = $db->querySingle( - 'WITH HORARIOS AS ( - SELECT * - FROM horario - JOIN horario_profesor USING (horario_id) - WHERE horario.periodo_id = :periodo_id - ) - INSERT INTO registro (profesor_id, horario_id, registro_fecha_ideal, registro_justificada, justificador_id, registro_fecha_justificacion, justificacion) - VALUES (:profesor_id, :horario_id, :registro_fecha_ideal, :registro_justificada, :justificador_id, NOW(), :justificacion) - ON CONFLICT (profesor_id, horario_id, registro_fecha_ideal) - DO UPDATE SET registro_justificada = :registro_justificada, justificador_id = :justificador_id, registro_fecha_justificacion = NOW(), justificacion = :justificacion - RETURNING *', - array( - 'periodo_id' => $user->periodo_id, - 'profesor_id' => $post_data['profesor_id'], - 'horario_id' => $post_data['horario_id'], - 'registro_fecha_ideal' => $post_data['registro_fecha_ideal'], - 'registro_justificada' => $post_data['registro_justificada'], - 'justificador_id' => $user->user['id'], - 'justificacion' => empty($post_data['justificacion']) ? null : $post_data['justificacion'], - ) - ); - - - $data_justificador = $db->querySingle( - "SELECT justificador.usuario_nombre as justificador_nombre, - justificador.usuario_clave as justificador_clave, - facultad.facultad_nombre as justificador_facultad, rol.rol_titulo as justificador_rol - - FROM USUARIO JUSTIFICADOR - JOIN ROL on ROL.rol_id = justificador.rol_id - LEFT JOIN facultad on facultad.facultad_id = justificador.facultad_id - where justificador.usuario_id = :justificador_id", - array( - 'justificador_id' => $user->user['id'], - ) - ); - // exit('exit'); - - echo json_encode(array_merge($data, $data_justificador), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); - break; - - default: - header('HTTP/1.1 405 Method Not Allowed'); - echo json_encode(['error' => 'M茅todo no permitido']); - } -} catch (PDOException $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'query' => $db->getLastQuery(), - 'exception' => $e->getTraceAsString() - ]); -} catch (Exception $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'exception' => $e->getTraceAsString() - ]); + 'No se ha iniciado sesi贸n']); + exit(); +} +$user = Login::get_user(); + +try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'POST': + // check parameters + + $raw = file_get_contents('php://input'); + $post_data = json_decode($raw, true); + + $data = $db->querySingle( + 'WITH HORARIOS AS ( + SELECT * + FROM horario + JOIN horario_profesor USING (horario_id) + WHERE horario.periodo_id = :periodo_id + ) + INSERT INTO registro (profesor_id, horario_id, registro_fecha_ideal, registro_justificada, justificador_id, registro_fecha_justificacion, justificacion) + VALUES (:profesor_id, :horario_id, :registro_fecha_ideal, :registro_justificada, :justificador_id, NOW(), :justificacion) + ON CONFLICT (profesor_id, horario_id, registro_fecha_ideal) + DO UPDATE SET registro_justificada = :registro_justificada, justificador_id = :justificador_id, registro_fecha_justificacion = NOW(), justificacion = :justificacion + RETURNING *', + array( + 'periodo_id' => $user->periodo_id, + 'profesor_id' => $post_data['profesor_id'], + 'horario_id' => $post_data['horario_id'], + 'registro_fecha_ideal' => $post_data['registro_fecha_ideal'], + 'registro_justificada' => $post_data['registro_justificada'], + 'justificador_id' => $user->user['id'], + 'justificacion' => empty($post_data['justificacion']) ? null : $post_data['justificacion'], + ) + ); + + + $data_justificador = $db->querySingle( + "SELECT justificador.usuario_nombre as justificador_nombre, + justificador.usuario_clave as justificador_clave, + facultad.facultad_nombre as justificador_facultad, rol.rol_titulo as justificador_rol + + FROM USUARIO JUSTIFICADOR + JOIN ROL on ROL.rol_id = justificador.rol_id + LEFT JOIN facultad on facultad.facultad_id = justificador.facultad_id + where justificador.usuario_id = :justificador_id", + array( + 'justificador_id' => $user->user['id'], + ) + ); + // exit('exit'); + + echo json_encode(array_merge($data, $data_justificador), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); + break; + + default: + header('HTTP/1.1 405 Method Not Allowed'); + echo json_encode(['error' => 'M茅todo no permitido']); + } +} catch (PDOException $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'query' => $db->getLastQuery(), + 'exception' => $e->getTraceAsString() + ]); +} catch (Exception $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'exception' => $e->getTraceAsString() + ]); } \ No newline at end of file diff --git a/action/nivel.php b/action/nivel.php index 5a5d58a..685247a 100644 --- a/action/nivel.php +++ b/action/nivel.php @@ -1,31 +1,31 @@ - 'No se ha iniciado sesi贸n']); - exit(); -} -$user = Login::get_user(); - -try { - switch ($_SERVER['REQUEST_METHOD']) { - case 'GET': - // Fetch all puestos - $nivel = $db->get('nivel'); - echo json_encode($nivel); - break; - default: - header('HTTP/1.1 405 Method Not Allowed'); - echo json_encode(['error' => 'M茅todo no permitido']); - break; - } -} catch (PDOException $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'query' => $db->getLastQuery(), - 'exception' => $e->getTraceAsString() - ]); + 'No se ha iniciado sesi贸n']); + exit(); +} +$user = Login::get_user(); + +try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + // Fetch all puestos + $nivel = $db->get('nivel'); + echo json_encode($nivel); + break; + default: + header('HTTP/1.1 405 Method Not Allowed'); + echo json_encode(['error' => 'M茅todo no permitido']); + break; + } +} catch (PDOException $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'query' => $db->getLastQuery(), + 'exception' => $e->getTraceAsString() + ]); } \ No newline at end of file diff --git a/action/periodo_datos.php b/action/periodo_datos.php index 7da8339..2be9c31 100644 --- a/action/periodo_datos.php +++ b/action/periodo_datos.php @@ -1,44 +1,44 @@ - 'unauthorized'])); -} -$user = unserialize($_SESSION['user']); -// check method -if ($_SERVER['REQUEST_METHOD'] !== 'GET') { - http_response_code(405); - die(json_encode(['error' => 'method not allowed'])); -} - -const JSON_OPTIONS = JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR; -try { - $data = $db->querySingle("SELECT *, LEAST(periodo_fecha_fin, CURRENT_DATE) as fecha_final FROM periodo WHERE periodo_id = ?", array($user->periodo_id)); - $last_query = [ - 'query' => $db->getLastQuery(), - ]; - - echo json_encode($data, JSON_OPTIONS); -} catch (PDOException $th) { - http_response_code(500); - echo json_encode([ - 'error' => $th->getMessage(), - 'query' => $db->getLastQuery(), - ], JSON_OPTIONS); - exit; -} catch (Exception $th) { - http_response_code(500); - echo json_encode([ - 'error' => $th->getMessage(), - ], JSON_OPTIONS); - exit; + 'unauthorized'])); +} +$user = unserialize($_SESSION['user']); +// check method +if ($_SERVER['REQUEST_METHOD'] !== 'GET') { + http_response_code(405); + die(json_encode(['error' => 'method not allowed'])); +} + +const JSON_OPTIONS = JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_PARTIAL_OUTPUT_ON_ERROR; +try { + $data = $db->querySingle("SELECT *, LEAST(periodo_fecha_fin, CURRENT_DATE) as fecha_final FROM periodo WHERE periodo_id = ?", array($user->periodo_id)); + $last_query = [ + 'query' => $db->getLastQuery(), + ]; + + echo json_encode($data, JSON_OPTIONS); +} catch (PDOException $th) { + http_response_code(500); + echo json_encode([ + 'error' => $th->getMessage(), + 'query' => $db->getLastQuery(), + ], JSON_OPTIONS); + exit; +} catch (Exception $th) { + http_response_code(500); + echo json_encode([ + 'error' => $th->getMessage(), + ], JSON_OPTIONS); + exit; } \ No newline at end of file diff --git a/action/periodos.php b/action/periodos.php index bc1d98f..6f38b7b 100644 --- a/action/periodos.php +++ b/action/periodos.php @@ -1,204 +1,204 @@ - 'No se ha iniciado sesi贸n']); - exit(); -} -$user = Login::get_user(); - -try { - switch ($_SERVER['REQUEST_METHOD']) { - case 'GET': - // Fetch all puestos - $periodo_id = $user->periodo_id; - if (is_null($user->facultad['facultad_id'])) { - $periodos = $db - //->where('CURRENT_DATE BETWEEN periodo_fecha_inicio AND periodo_fecha_fin') - ->join('nivel', 'nivel.nivel_id = periodo.nivel_id') - ->orderBy('periodo_id') - ->get('periodo', null, 'periodo.*, nivel_nombre as nivel'); - } else { - $periodos = $db->query( - "SELECT DISTINCT periodo.*, nivel_nombre as nivel FROM periodo - JOIN horario_view USING (periodo_id) - JOIN nivel ON nivel.nivel_id = periodo.nivel_id - WHERE /*CURRENT_DATE BETWEEN periodo.periodo_fecha_inicio AND periodo.periodo_fecha_fin - AND */facultad_id = :facultad_id - ORDER BY periodo_id - ", - ['facultad_id' => $user->facultad['facultad_id']] - ); - } - echo json_encode($periodos); - break; - - case 'PUT': - // Update nivel_id of a periodo - $raw = file_get_contents('php://input'); - $data = json_decode($raw, true); - - if (!isset($data['action'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Falta la acci贸n a realizar']); - exit(); - } - - switch ($data['action']) { - case 'changeNivel': - if (!isset($data['periodo_id'], $data['nivel_id'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Falta el id del periodo o el nivel']); - exit(); - } - - $periodo_id = $data['periodo_id']; - $nivel_id = $data['nivel_id']; - $db->where('periodo_id', $periodo_id)->update('periodo', ['nivel_id' => $nivel_id]); - - $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; - $nivel_nombre = $db->where('nivel_id', $nivel_id)->getOne('nivel', 'nivel_nombre')['nivel_nombre']; - - echo json_encode([ - 'success' => - "El nivel del periodo $periodo_nombre ha sido cambiado a $nivel_nombre" - ]); - break; - - case 'changeFechaInicio': - if (!isset($data['periodo_id'], $data['periodo_fecha_inicio'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Falta el id del periodo o la fecha de inicio']); - exit(); - } - - $periodo_id = $data['periodo_id']; - $periodo_fecha_inicio = $data['periodo_fecha_inicio']; - $db->where('periodo_id', $periodo_id)->update('periodo', ['periodo_fecha_inicio' => $periodo_fecha_inicio]); - - $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; - - echo json_encode([ - 'success' => - "La fecha de inicio del periodo $periodo_nombre ha sido cambiada a $periodo_fecha_inicio" - ]); - break; - - case 'changeFechaFin': - if (!isset($data['periodo_id'], $data['periodo_fecha_fin'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Falta el id del periodo o la fecha de fin']); - exit(); - } - - $periodo_id = $data['periodo_id']; - $periodo_fecha_fin = $data['periodo_fecha_fin']; - $db->where('periodo_id', $periodo_id)->update('periodo', ['periodo_fecha_fin' => $periodo_fecha_fin]); - - $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; - - echo json_encode([ - 'success' => - "La fecha de fin del periodo $periodo_nombre ha sido cambiada a $periodo_fecha_fin" - ]); - break; - - case 'updatePeriodo': - if (!isset($data['periodo_id'], $data['periodo_nombre'], $data['id_periodo_sgu'], $data['periodo_clave'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Faltan datos para actualizar el periodo']); - exit(); - } - - $periodo_id = $data['periodo_id']; - - $db->where('periodo_id', $periodo_id)->update('periodo', array_filter($data, fn($key) => in_array($key, [ - 'periodo_nombre', - 'id_periodo_sgu', - 'periodo_clave', - ]), ARRAY_FILTER_USE_KEY)); - - $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; - - echo json_encode([ - 'success' => - "El periodo $periodo_nombre ha sido actualizado" - ]); - break; - - default: - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Acci贸n no v谩lida']); - exit(); - } - - break; - case 'POST': - $raw = file_get_contents('php://input'); - $data = json_decode($raw, true); - - if (!isset($data['periodo_nombre'], $data['nivel_id'], $data['periodo_fecha_inicio'], $data['periodo_fecha_fin'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Faltan datos para crear el periodo']); - exit(); - } - - $newPeriodo = $db->insert( - 'periodo', - array_filter($data, fn($key) => in_array($key, [ - 'periodo_nombre', - 'nivel_id', - 'periodo_fecha_inicio', - 'periodo_fecha_fin', - 'periodo_clave', - 'id_periodo_sgu', - ]), ARRAY_FILTER_USE_KEY) - ); - - echo json_encode([ - 'success' => true, - 'message' => 'El periodo ha sido creado', - 'periodo' => $newPeriodo - ]); - break; - - case 'DELETE': - // Delete a periodo - $raw = file_get_contents('php://input'); - $data = json_decode($raw, true); - - if (!isset($data['periodo_id'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Falta el id del periodo']); - exit(); - } - - $periodo_id = $data['periodo_id']; - $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; - - $db->where('periodo_id', $periodo_id)->delete('periodo'); - - echo json_encode([ - 'success' => true, - 'message' => "El periodo $periodo_nombre ha sido eliminado" - ]); - break; - default: - header('HTTP/1.1 405 Method Not Allowed'); - echo json_encode(['error' => 'M茅todo no permitido']); - break; - } -} catch (PDOException $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'query' => $db->getLastQuery(), - 'exception' => $e->getTraceAsString() - ]); -} catch (Exception $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'exception' => $e->getTraceAsString() - ]); + 'No se ha iniciado sesi贸n']); + exit(); +} +$user = Login::get_user(); + +try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + // Fetch all puestos + $periodo_id = $user->periodo_id; + if (is_null($user->facultad['facultad_id'])) { + $periodos = $db + //->where('CURRENT_DATE BETWEEN periodo_fecha_inicio AND periodo_fecha_fin') + ->join('nivel', 'nivel.nivel_id = periodo.nivel_id') + ->orderBy('periodo_id') + ->get('periodo', null, 'periodo.*, nivel_nombre as nivel'); + } else { + $periodos = $db->query( + "SELECT DISTINCT periodo.*, nivel_nombre as nivel FROM periodo + JOIN horario_view USING (periodo_id) + JOIN nivel ON nivel.nivel_id = periodo.nivel_id + WHERE /*CURRENT_DATE BETWEEN periodo.periodo_fecha_inicio AND periodo.periodo_fecha_fin + AND */facultad_id = :facultad_id + ORDER BY periodo_id + ", + ['facultad_id' => $user->facultad['facultad_id']] + ); + } + echo json_encode($periodos); + break; + + case 'PUT': + // Update nivel_id of a periodo + $raw = file_get_contents('php://input'); + $data = json_decode($raw, true); + + if (!isset($data['action'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Falta la acci贸n a realizar']); + exit(); + } + + switch ($data['action']) { + case 'changeNivel': + if (!isset($data['periodo_id'], $data['nivel_id'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Falta el id del periodo o el nivel']); + exit(); + } + + $periodo_id = $data['periodo_id']; + $nivel_id = $data['nivel_id']; + $db->where('periodo_id', $periodo_id)->update('periodo', ['nivel_id' => $nivel_id]); + + $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; + $nivel_nombre = $db->where('nivel_id', $nivel_id)->getOne('nivel', 'nivel_nombre')['nivel_nombre']; + + echo json_encode([ + 'success' => + "El nivel del periodo $periodo_nombre ha sido cambiado a $nivel_nombre" + ]); + break; + + case 'changeFechaInicio': + if (!isset($data['periodo_id'], $data['periodo_fecha_inicio'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Falta el id del periodo o la fecha de inicio']); + exit(); + } + + $periodo_id = $data['periodo_id']; + $periodo_fecha_inicio = $data['periodo_fecha_inicio']; + $db->where('periodo_id', $periodo_id)->update('periodo', ['periodo_fecha_inicio' => $periodo_fecha_inicio]); + + $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; + + echo json_encode([ + 'success' => + "La fecha de inicio del periodo $periodo_nombre ha sido cambiada a $periodo_fecha_inicio" + ]); + break; + + case 'changeFechaFin': + if (!isset($data['periodo_id'], $data['periodo_fecha_fin'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Falta el id del periodo o la fecha de fin']); + exit(); + } + + $periodo_id = $data['periodo_id']; + $periodo_fecha_fin = $data['periodo_fecha_fin']; + $db->where('periodo_id', $periodo_id)->update('periodo', ['periodo_fecha_fin' => $periodo_fecha_fin]); + + $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; + + echo json_encode([ + 'success' => + "La fecha de fin del periodo $periodo_nombre ha sido cambiada a $periodo_fecha_fin" + ]); + break; + + case 'updatePeriodo': + if (!isset($data['periodo_id'], $data['periodo_nombre'], $data['id_periodo_sgu'], $data['periodo_clave'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Faltan datos para actualizar el periodo']); + exit(); + } + + $periodo_id = $data['periodo_id']; + + $db->where('periodo_id', $periodo_id)->update('periodo', array_filter($data, fn($key) => in_array($key, [ + 'periodo_nombre', + 'id_periodo_sgu', + 'periodo_clave', + ]), ARRAY_FILTER_USE_KEY)); + + $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; + + echo json_encode([ + 'success' => + "El periodo $periodo_nombre ha sido actualizado" + ]); + break; + + default: + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Acci贸n no v谩lida']); + exit(); + } + + break; + case 'POST': + $raw = file_get_contents('php://input'); + $data = json_decode($raw, true); + + if (!isset($data['periodo_nombre'], $data['nivel_id'], $data['periodo_fecha_inicio'], $data['periodo_fecha_fin'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Faltan datos para crear el periodo']); + exit(); + } + + $newPeriodo = $db->insert( + 'periodo', + array_filter($data, fn($key) => in_array($key, [ + 'periodo_nombre', + 'nivel_id', + 'periodo_fecha_inicio', + 'periodo_fecha_fin', + 'periodo_clave', + 'id_periodo_sgu', + ]), ARRAY_FILTER_USE_KEY) + ); + + echo json_encode([ + 'success' => true, + 'message' => 'El periodo ha sido creado', + 'periodo' => $newPeriodo + ]); + break; + + case 'DELETE': + // Delete a periodo + $raw = file_get_contents('php://input'); + $data = json_decode($raw, true); + + if (!isset($data['periodo_id'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Falta el id del periodo']); + exit(); + } + + $periodo_id = $data['periodo_id']; + $periodo_nombre = $db->where('periodo_id', $periodo_id)->getOne('periodo', 'periodo_nombre')['periodo_nombre']; + + $db->where('periodo_id', $periodo_id)->delete('periodo'); + + echo json_encode([ + 'success' => true, + 'message' => "El periodo $periodo_nombre ha sido eliminado" + ]); + break; + default: + header('HTTP/1.1 405 Method Not Allowed'); + echo json_encode(['error' => 'M茅todo no permitido']); + break; + } +} catch (PDOException $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'query' => $db->getLastQuery(), + 'exception' => $e->getTraceAsString() + ]); +} catch (Exception $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'exception' => $e->getTraceAsString() + ]); } \ No newline at end of file diff --git a/action/profesor_faltas.php b/action/profesor_faltas.php index 0e9e896..da97a64 100644 --- a/action/profesor_faltas.php +++ b/action/profesor_faltas.php @@ -1,135 +1,135 @@ - 'No se ha iniciado sesi贸n']); - exit(); -} -$user = Login::get_user(); - -try { - switch ($_SERVER['REQUEST_METHOD']) { - case 'GET': - $facultad = $_GET['facultad'] ?? $user->facultad['facultad_id'] ?? null; - $porcentaje = $_GET['porcentaje'] ?? null; - $faltas = $_GET['faltas'] ?? null; - - if (!isset($facultad) || !is_numeric($facultad)) { - $error = 'No se ha seleccionado una facultad'; - } else if ((!isset($faltas) || !is_numeric($faltas)) && (!isset($porcentaje) || !is_numeric($porcentaje))) { - $error = 'Debe especificar las faltas o el porcentaje'; - } else if (isset($faltas) && (!is_numeric($faltas) || $faltas <= 0)) { - $error = 'Las faltas deben ser un n煤mero mayor a 0'; - } else if (isset($porcentaje) && (!is_numeric($porcentaje) || $porcentaje <= 0)) { - $error = 'El porcentaje debe ser un n煤mero mayor a 0'; - } else if (isset($faltas) && isset($porcentaje)) { - $error = 'No se puede especificar las faltas y el porcentaje al mismo tiempo'; - } else if (!isset($facultad) || !is_numeric($facultad)) { - $error = 'Debe especificar una facultad'; - } - - if (isset($error)) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => $error]); - exit(); - } - // Initialize the data array - $data = array(); - - // Check if 'profesor' or 'supervisor' is set and prepare the specific part of the SQL query accordingly. - if (isset($_GET['profesor']) || isset($_GET['supervisor'])) { - - $condition = isset($_GET['profesor']) - ? "r.registro_fecha IS NULL AND NOT COALESCE(r.registro_justificada, FALSE)" - : "estado_supervisor_id = 2"; - - $filter = isset($faltas) - ? "afcp.faltas >= :faltas" - : "afcp.porcentaje >= :porcentaje"; - - // Prepare the SQL query with placeholders for parameters - $data = array_column($db->query( - "WITH fechas AS ( - SELECT - h.horario_id, - fechas_clase(h.horario_id, true) AS registro_fecha_ideal, - hp.profesor_id - FROM horario h - JOIN horario_profesor hp USING (horario_id) - WHERE (h.PERIODO_ID, h.FACULTAD_ID) = (:periodo_id, :facultad_id) AND hp.profesor_id <> 0 - ), - asistencia_faltas AS ( - SELECT - f.profesor_id, - COUNT(1) AS total, - COUNT(1) FILTER (WHERE $condition AND f.registro_fecha_ideal <= current_date) AS faltas - FROM fechas f - LEFT JOIN registro r USING (registro_fecha_ideal, horario_id, profesor_id) - GROUP BY f.profesor_id - ), - asistencia_faltas_con_porcentaje AS ( - SELECT - af.profesor_id, - af.faltas, - af.total, - CASE - WHEN af.total > 0 THEN ROUND((af.faltas::NUMERIC / af.total) * 100, 2) - ELSE NULL - END AS porcentaje - FROM asistencia_faltas af - WHERE af.faltas > 0 - ) - SELECT - json_build_object( - 'profesor', json_build_object( - 'profesor_nombre', p.profesor_nombre, - 'profesor_clave', p.profesor_clave, - 'profesor_correo', p.profesor_correo - ), - 'profesor_id', afcp.profesor_id, - 'faltas', afcp.faltas, - 'total', afcp.total, - 'porcentaje', afcp.porcentaje - ) AS result_json - FROM asistencia_faltas_con_porcentaje afcp - JOIN profesor p USING (profesor_id) - WHERE $filter - ORDER BY afcp.porcentaje DESC; - ", - [ - 'periodo_id' => $user->periodo_id, - 'facultad_id' => $facultad, - ] + (isset($faltas) - ? ['faltas' => $faltas] - : ['porcentaje' => $porcentaje]) - ), 'result_json'); - } else { - // Send a 400 Bad Request header and an error message in JSON format - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Especifique si las faltas son de profesor o supervisor']); - exit(); - } - if (empty($data)) { - header('HTTP/1.1 404 Not Found'); - echo json_encode(['error' => 'No se encontraron faltas']); - } else { - echo json_encode( - array_map(fn($item) => json_decode($item), $data) - ); - } - - break; - - default: - header('HTTP/1.1 405 Method Not Allowed'); - echo json_encode(['error' => 'M茅todo no permitido']); - break; - } -} catch (PDOException $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'query' => $db->getLastQuery(), - ]); -} + 'No se ha iniciado sesi贸n']); + exit(); +} +$user = Login::get_user(); + +try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + $facultad = $_GET['facultad'] ?? $user->facultad['facultad_id'] ?? null; + $porcentaje = $_GET['porcentaje'] ?? null; + $faltas = $_GET['faltas'] ?? null; + + if (!isset($facultad) || !is_numeric($facultad)) { + $error = 'No se ha seleccionado una facultad'; + } else if ((!isset($faltas) || !is_numeric($faltas)) && (!isset($porcentaje) || !is_numeric($porcentaje))) { + $error = 'Debe especificar las faltas o el porcentaje'; + } else if (isset($faltas) && (!is_numeric($faltas) || $faltas <= 0)) { + $error = 'Las faltas deben ser un n煤mero mayor a 0'; + } else if (isset($porcentaje) && (!is_numeric($porcentaje) || $porcentaje <= 0)) { + $error = 'El porcentaje debe ser un n煤mero mayor a 0'; + } else if (isset($faltas) && isset($porcentaje)) { + $error = 'No se puede especificar las faltas y el porcentaje al mismo tiempo'; + } else if (!isset($facultad) || !is_numeric($facultad)) { + $error = 'Debe especificar una facultad'; + } + + if (isset($error)) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => $error]); + exit(); + } + // Initialize the data array + $data = array(); + + // Check if 'profesor' or 'supervisor' is set and prepare the specific part of the SQL query accordingly. + if (isset($_GET['profesor']) || isset($_GET['supervisor'])) { + + $condition = isset($_GET['profesor']) + ? "r.registro_fecha IS NULL AND NOT COALESCE(r.registro_justificada, FALSE)" + : "estado_supervisor_id = 2"; + + $filter = isset($faltas) + ? "afcp.faltas >= :faltas" + : "afcp.porcentaje >= :porcentaje"; + + // Prepare the SQL query with placeholders for parameters + $data = array_column($db->query( + "WITH fechas AS ( + SELECT + h.horario_id, + fechas_clase(h.horario_id, true) AS registro_fecha_ideal, + hp.profesor_id + FROM horario h + JOIN horario_profesor hp USING (horario_id) + WHERE (h.PERIODO_ID, h.FACULTAD_ID) = (:periodo_id, :facultad_id) AND hp.profesor_id <> 0 + ), + asistencia_faltas AS ( + SELECT + f.profesor_id, + COUNT(1) AS total, + COUNT(1) FILTER (WHERE $condition AND f.registro_fecha_ideal <= current_date) AS faltas + FROM fechas f + LEFT JOIN registro r USING (registro_fecha_ideal, horario_id, profesor_id) + GROUP BY f.profesor_id + ), + asistencia_faltas_con_porcentaje AS ( + SELECT + af.profesor_id, + af.faltas, + af.total, + CASE + WHEN af.total > 0 THEN ROUND((af.faltas::NUMERIC / af.total) * 100, 2) + ELSE NULL + END AS porcentaje + FROM asistencia_faltas af + WHERE af.faltas > 0 + ) + SELECT + json_build_object( + 'profesor', json_build_object( + 'profesor_nombre', p.profesor_nombre, + 'profesor_clave', p.profesor_clave, + 'profesor_correo', p.profesor_correo + ), + 'profesor_id', afcp.profesor_id, + 'faltas', afcp.faltas, + 'total', afcp.total, + 'porcentaje', afcp.porcentaje + ) AS result_json + FROM asistencia_faltas_con_porcentaje afcp + JOIN profesor p USING (profesor_id) + WHERE $filter + ORDER BY afcp.porcentaje DESC; + ", + [ + 'periodo_id' => $user->periodo_id, + 'facultad_id' => $facultad, + ] + (isset($faltas) + ? ['faltas' => $faltas] + : ['porcentaje' => $porcentaje]) + ), 'result_json'); + } else { + // Send a 400 Bad Request header and an error message in JSON format + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Especifique si las faltas son de profesor o supervisor']); + exit(); + } + if (empty($data)) { + header('HTTP/1.1 404 Not Found'); + echo json_encode(['error' => 'No se encontraron faltas']); + } else { + echo json_encode( + array_map(fn($item) => json_decode($item), $data) + ); + } + + break; + + default: + header('HTTP/1.1 405 Method Not Allowed'); + echo json_encode(['error' => 'M茅todo no permitido']); + break; + } +} catch (PDOException $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'query' => $db->getLastQuery(), + ]); +} diff --git a/action/puesto.php b/action/puesto.php index 0eb4fe2..73aa57f 100644 --- a/action/puesto.php +++ b/action/puesto.php @@ -1,113 +1,113 @@ - 'No se ha iniciado sesi贸n']); - exit(); -} -$user = Login::get_user(); - -try { - switch ($_SERVER['REQUEST_METHOD']) { - case 'GET': - // Fetch all puestos - $facultad_id = $user->facultad['facultad_id'] ?? -1; - $puestos = array_map( - fn($p) => array( - ...$p, - 'materias' => $db->where('puesto_id', $p['puesto_id']) - ->join('puesto_materia', 'puesto_materia.materia_id = materia.materia_id', 'LEFT') - ->get(tableName: 'materia', columns: ['materia.materia_id', 'materia_nombre', 'clave_materia',]), - 'encargado' => $db->where('puesto_id', $p['puesto_id']) - ->join('puesto_usuario', 'puesto_usuario.usuario_id = usuario.usuario_id', 'LEFT') - ->getOne('usuario', ['usuario.usuario_id', 'usuario_nombre', 'usuario_clave']), - ), - $db->orderBy('puesto.nombre', 'desc') - ->where('facultad_id', $facultad_id) - ->get(tableName: 'puesto', columns: 'puesto_id, nombre'), - ); - echo json_encode($puestos); - break; - - case 'POST': - $raw_input = file_get_contents('php://input'); - $input_data = json_decode($raw_input, true); - - if (!$input_data || !isset($input_data['puesto_nombre'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Datos inv谩lidos']); - exit(); - } - - $puesto = $db->insert('puesto', [ - 'nombre' => $input_data['puesto_nombre'], - 'facultad_id' => $user->facultad['facultad_id'], - ], ['puesto_id', 'nombre', 'facultad_id']); - - echo json_encode( - array( - ...$puesto, - 'materias' => [], - 'encargado' => null, - ), - ); - break; - - case 'PUT': - $raw_input = file_get_contents('php://input'); - $input_data = json_decode($raw_input, true); - - if (!$input_data || !isset($input_data['puesto_id'], $input_data['materias'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Datos inv谩lidos']); - exit(); - } - - $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto_materia'); - $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto_usuario'); - - foreach ($input_data['materias'] as $materia_id) { - $db->insert('puesto_materia', [ - 'puesto_id' => $input_data['puesto_id'], - 'materia_id' => $materia_id, - ]); - } - - if (isset($input_data['usuario_id'])) - $db->insert('puesto_usuario', [ - 'puesto_id' => $input_data['puesto_id'], - 'usuario_id' => $input_data['usuario_id'], - ]); - - echo json_encode(['msg' => 'Puesto actualizado exitosamente']); - break; - - case 'DELETE': - $raw_input = file_get_contents('php://input'); - $input_data = json_decode($raw_input, true); - - if (!$input_data || !isset($input_data['puesto_id'])) { - header('HTTP/1.1 400 Bad Request'); - echo json_encode(['error' => 'Datos inv谩lidos']); - exit(); - } - - $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto'); - echo json_encode(['msg' => 'Puesto eliminado exitosamente']); - break; - - default: - header('HTTP/1.1 405 Method Not Allowed'); - echo json_encode(['error' => 'M茅todo no permitido']); - break; - } -} catch (PDOException $e) { - echo json_encode([ - 'error' => $e->getMessage(), - 'query' => $db->getLastQuery(), - 'exception' => $e->getTraceAsString() - ]); + 'No se ha iniciado sesi贸n']); + exit(); +} +$user = Login::get_user(); + +try { + switch ($_SERVER['REQUEST_METHOD']) { + case 'GET': + // Fetch all puestos + $facultad_id = $user->facultad['facultad_id'] ?? -1; + $puestos = array_map( + fn($p) => array( + ...$p, + 'materias' => $db->where('puesto_id', $p['puesto_id']) + ->join('puesto_materia', 'puesto_materia.materia_id = materia.materia_id', 'LEFT') + ->get(tableName: 'materia', columns: ['materia.materia_id', 'materia_nombre', 'clave_materia',]), + 'encargado' => $db->where('puesto_id', $p['puesto_id']) + ->join('puesto_usuario', 'puesto_usuario.usuario_id = usuario.usuario_id', 'LEFT') + ->getOne('usuario', ['usuario.usuario_id', 'usuario_nombre', 'usuario_clave']), + ), + $db->orderBy('puesto.nombre', 'desc') + ->where('facultad_id', $facultad_id) + ->get(tableName: 'puesto', columns: 'puesto_id, nombre'), + ); + echo json_encode($puestos); + break; + + case 'POST': + $raw_input = file_get_contents('php://input'); + $input_data = json_decode($raw_input, true); + + if (!$input_data || !isset($input_data['puesto_nombre'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Datos inv谩lidos']); + exit(); + } + + $puesto = $db->insert('puesto', [ + 'nombre' => $input_data['puesto_nombre'], + 'facultad_id' => $user->facultad['facultad_id'], + ], ['puesto_id', 'nombre', 'facultad_id']); + + echo json_encode( + array( + ...$puesto, + 'materias' => [], + 'encargado' => null, + ), + ); + break; + + case 'PUT': + $raw_input = file_get_contents('php://input'); + $input_data = json_decode($raw_input, true); + + if (!$input_data || !isset($input_data['puesto_id'], $input_data['materias'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Datos inv谩lidos']); + exit(); + } + + $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto_materia'); + $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto_usuario'); + + foreach ($input_data['materias'] as $materia_id) { + $db->insert('puesto_materia', [ + 'puesto_id' => $input_data['puesto_id'], + 'materia_id' => $materia_id, + ]); + } + + if (isset($input_data['usuario_id'])) + $db->insert('puesto_usuario', [ + 'puesto_id' => $input_data['puesto_id'], + 'usuario_id' => $input_data['usuario_id'], + ]); + + echo json_encode(['msg' => 'Puesto actualizado exitosamente']); + break; + + case 'DELETE': + $raw_input = file_get_contents('php://input'); + $input_data = json_decode($raw_input, true); + + if (!$input_data || !isset($input_data['puesto_id'])) { + header('HTTP/1.1 400 Bad Request'); + echo json_encode(['error' => 'Datos inv谩lidos']); + exit(); + } + + $db->where('puesto_id', $input_data['puesto_id'])->delete('puesto'); + echo json_encode(['msg' => 'Puesto eliminado exitosamente']); + break; + + default: + header('HTTP/1.1 405 Method Not Allowed'); + echo json_encode(['error' => 'M茅todo no permitido']); + break; + } +} catch (PDOException $e) { + echo json_encode([ + 'error' => $e->getMessage(), + 'query' => $db->getLastQuery(), + 'exception' => $e->getTraceAsString() + ]); } \ No newline at end of file diff --git a/action/reposicion_autoriza.php b/action/reposicion_autoriza.php index 99610fa..4b44814 100644 --- a/action/reposicion_autoriza.php +++ b/action/reposicion_autoriza.php @@ -1,288 +1,288 @@ -querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon', - [':id_salon' => $salon] - ); - if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){ - $salon_desc = "Pendiente"; - }else{ - $salon_json = json_decode($salon_rs["salon_array"], true); - if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ - unset($salon_json[0]); - } - $salon_desc = join(" / ",$salon_json); - } -} - - -if($tipo ==1 || $tipo == 2){ - //-------------- - //Obtiene datos reposici贸n - $reposicion_rs = $db->querySingle('SELECT h.materia, r.fecha_nueva, r.hora_nueva, r.fecha_clase, r.descripcion, h.horario_hora, h.facultad_id, h.facultad, f.clave_dependencia, r.motivo_cancelacion, ta.tipoaula_supervisor , ta.tipoaula_nombre - from reposicion_solicitud r - inner join horario_view h on h.horario_id = r.horario_id - inner join facultad f on f.facultad_id = h.facultad_id - inner join tipoaula ta on ta.tipoaula_id = r.tipoaula_id - where r.reposicion_solicitud_id = :id_repo', - [':id_repo' => $id_repo] - ); - - //Obtiene correos - $correos_rs = $db->query('SELECT p.profesor_nombre, p.profesor_correo, u.usuario_nombre as jefe_nombre, u.usuario_correo as jefe_correo, - coor.usuario_nombre as coordinador_nombre, coor.usuario_correo as coordinador_correo - from reposicion_solicitud rs - inner join profesor p on rs.profesor_id =p.profesor_id - inner join usuario u on u.usuario_id = rs.usuario_id - inner join horario_view hv on hv.horario_id = rs.horario_id - inner join usuario coor on hv.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord - where rs.reposicion_solicitud_id = :id_repo', - [':rol_coord' => COORDINADOR, ':id_repo' => $id_repo] - ); - //print_r($correos_rs); exit(); -}else{ - //Obtiene datos asignaci贸n - $reposicion_rs = $db->querySingle('SELECT r.fecha_nueva, r.hora_nueva, r.descripcion, f.facultad_id, f.facultad_nombre as facultad, f.clave_dependencia, r.motivo_cancelacion, ta.tipoaula_supervisor , ta.tipoaula_nombre, p.profesor_nombre - from asignacion_solicitud r - inner join usuario u on u.usuario_id = r.usuario_id - inner join facultad f on f.facultad_id = u.facultad_id - inner join tipoaula ta on ta.tipoaula_id = r.tipoaula_id - inner join profesor p on p.profesor_id = r.profesor_id - where r.asignacion_solicitud_id = :id_repo', - [':id_repo' => $id_repo] - ); - - //Obtiene correos - $correos_rs = $db->query('SELECT p.profesor_nombre, p.profesor_correo, NULL as jefe_nombre, NULL as jefe_correo, - coor.usuario_nombre as coordinador_nombre, coor.usuario_correo as coordinador_correo - from asignacion_solicitud rs - inner join profesor p on rs.profesor_id =p.profesor_id - inner join usuario u on u.usuario_id = rs.usuario_id - inner join usuario coor on u.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord - where rs.asignacion_solicitud_id = :id_repo', - [':rol_coord' => COORDINADOR, ':id_repo' => $id_repo] - ); - -} - -$prof_correos=array(); -$jefe_correos=[]; -$coord_correos=[]; - -foreach($correos_rs as $correo){ - if( count($prof_correos)==0 && $correo["profesor_correo"]!=""){ - if( !isset($prof_correos["correo"]) || !in_array($correo["profesor_correo"], $prof_correos["correo"]) ){ - array_push($prof_correos, $correo["profesor_correo"]); - } - } - if( count($jefe_correos)==0 && $correo["jefe_correo"]!=""){ - if(!isset($jefe_correos["correo"]) || !in_array($correo["jefe_correo"], $jefe_correos["correo"])){ - array_push($jefe_correos, $correo["jefe_correo"]); - } - } - if( count($coord_correos)==0 && $correo["coordinador_correo"]!=""){ - if(!isset($coord_correos["correo"]) || !in_array($correo["coordinador_correo"], $coord_correos["correo"])){ - array_push($coord_correos, $correo["coordinador_correo"]); - } - } -} - -$correosSup_rs = $db->query("SELECT DISTINCT sup.usuario_correo as supervisor_correo - FROM horario_supervisor hs - inner join usuario sup on sup.usuario_id =hs.usuario_id - where :facultad = ANY(hs.facultad_id_array)", - [':facultad'=>$reposicion_rs["facultad_id"]] ); - -$sup_correos=[]; -foreach($correosSup_rs as $correo){ - array_push($sup_correos, $correo["supervisor_correo"]); -} - - -if($tipo ==1 || $tipo == 2){ - if($edo == 4){//cancelaci贸n - $motivo = ""; - if(isset($_POST["motivo"]) && $_POST["motivo"] != "") - $motivo = trim($_POST["motivo"]); - $db->querySingle('SELECT fu_reposicion_cancela(:id, :motivo)', - [':id' => $id_repo, ':motivo' => $motivo] - ); - }else{ - if(!empty($salon)){ - $db->querySingle('SELECT fu_reposicion_solicitud(:id, NULL, NULL, NULL, :sal, :edo, NULL, NULL, NULL, NULL)', - [':id' => $id_repo, ':sal' => $salon, ':edo' => $edo] - ); - }else{ - $db->querySingle('SELECT fu_reposicion_solicitud(:id, NULL, NULL, NULL, NULL, :edo, NULL, NULL, NULL, NULL)', - [':id' => $id_repo, ':edo' => $edo] - ); - } - } - - $fecha_clase = date('d/m/Y', strtotime($reposicion_rs["fecha_clase"])); - $fecha_nueva = date('d/m/Y', strtotime($reposicion_rs["fecha_nueva"])); - $hora_tmp = explode(":",$reposicion_rs["horario_hora"]); - $hora_clase = $hora_tmp[0].":".$hora_tmp[1]; - $hora_tmp = explode(":",$reposicion_rs["hora_nueva"]); - $hora_nueva = $hora_tmp[0].":".$hora_tmp[1]; - - $asunto = ""; - $texto = ""; - $to = ""; - switch($edo){ - case 2://Correo a supervisor - $asunto = "Reposici贸n nueva - ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"]; - //crear plantilla - $texto = "

Se cre贸 una reposici贸n nueva para: ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"].".

"; - $texto .= "

".mb_strtoupper($reposicion_rs["materia"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora_nueva." hrs."; - if(!$reposicion_rs["tipoaula_supervisor"]){ - $texto .= " en el sal贸n: ".$salon_desc."

"; - }else{ - $texto .= " en un sal贸n de tipo: ".$reposicion_rs["tipoaula_nombre"]."

"; - } - $texto .= "

".$reposicion_rs["descripcion"]."

"; - $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; - $to = join(",", $sup_correos); - $ok = 0; - break; - case 3://Correo a coordinador, profesor y jefe - $asunto = "Reposici贸n autorizada - ".$reposicion_rs["materia"]; - $texto = "

La resposici贸n de la clase de ".$reposicion_rs["materia"]." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. est谩 autorizada para realizarse el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. en: $salon_desc

"; - $to = join(",", $coord_correos).",".join(",", $prof_correos).",".join(",", $jefe_correos); - $ok = 0; - $db->querySingle('SELECT fu_reposicion_solicitud_supervisor(:id, :sup)', - [':id' => $id_repo, ':sup'=>$user->user["id"]] - ); - break; - case 4://Correo a coordinador, profesor y jefe - $asunto = "Reposici贸n declinada - ".$reposicion_rs["materia"]; - $texto = "

La resposici贸n de la clase de ".$reposicion_rs["materia"]." planeada para el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo:

"; - $texto .= "

".$motivo."

"; - $to = join(",", $coord_correos).",".join(",", $prof_correos).",".join(",", $jefe_correos); - $ok = 1; - $db->querySingle('SELECT fu_reposicion_solicitud_supervisor(:id, :sup)', - [':id' => $id_repo, ':sup'=>$user->user["id"]] - ); - break; - } -}else{ - if($edo == 4){//cancelaci贸n - $motivo = ""; - if(isset($_POST["motivo"]) && $_POST["motivo"] != "") - $motivo = trim($_POST["motivo"]); - $db->querySingle('SELECT fu_asignacion_cancela(:id, :motivo)', - [':id' => $id_repo, ':motivo' => $motivo] - ); - }else{ - if(!empty($salon)){ - $db->querySingle('SELECT fu_asignacion_solicitud(:id, NULL, NULL, :sal, :edo, NULL, NULL, NULL, NULL, NULL)', - [':id' => $id_repo, ':sal' => $salon, ':edo' => $edo] - ); - }else{ - $db->querySingle('SELECT fu_asignacion_solicitud(:id, NULL, NULL, NULL, :edo, NULL, NULL, NULL, NULL, NULL)', - [':id' => $id_repo, ':edo' => $edo] - ); - } - } - - $fecha_nueva = date('d/m/Y', strtotime($reposicion_rs["fecha_nueva"])); - $hora_tmp = explode(":",$reposicion_rs["hora_nueva"]); - $hora_nueva = $hora_tmp[0].":".$hora_tmp[1]; - - $asunto = ""; - $texto = ""; - $to = ""; - switch($edo){ - case 2://Correo a supervisor - $asunto = "Asignaci贸n nueva - ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"]; - //crear plantilla - $texto = "

Se cre贸 una solicitud de asignaci贸n nueva para: ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"].".

"; - $texto .= "

Se solicita el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. para el profesor: ".$reposicion_rs["profesor_nombre"]."."; - if(!$reposicion_rs["tipoaula_supervisor"]){ - $texto .= " en el sal贸n: ".$salon_desc."

"; - }else{ - $texto .= " en un sal贸n de tipo: ".$reposicion_rs["tipoaula_nombre"]."

"; - } - $texto .= "

".$reposicion_rs["descripcion"]."

"; - $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; - $to = join(",", $sup_correos); - $ok = 0; - break; - case 3://Correo a coordinador, profesor y jefe - $asunto = "Asignaci贸n autorizada - ".$reposicion_rs["profesor_nombre"]; - $texto = "

La asignaci贸n de espacio para el profesor ".$reposicion_rs["profesor_nombre"]." est谩 autorizada para realizarse el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. en: $salon_desc

"; - $to = join(",", $coord_correos).",".join(",", $prof_correos).",".join(",", $jefe_correos); - $ok = 0; - $db->querySingle('SELECT fu_asignacion_solicitud_supervisor(:id, :sup)', - [':id' => $id_repo, ':sup'=>$user->user["id"]] - ); - break; - case 4://Correo a coordinador, profesor y jefe - $asunto = "Asignaci贸n declinada - ".$reposicion_rs["profesor_nombre"]; - $texto = "

La asignaci贸n de espacio para el profesor ".$reposicion_rs["profesor_nombre"]." planeada para el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo:

"; - $texto .= "

".$motivo."

"; - $to = join(",", $coord_correos).",".join(",", $prof_correos).",".join(",", $jefe_correos); - $ok = 1; - $db->querySingle('SELECT fu_asignacion_solicitud_supervisor(:id, :sup)', - [':id' => $id_repo, ':sup'=>$user->user["id"]] - ); - break; - } -} - - -if($to!= "" && ENVIO_CORREOS){ - $texto = ' - La Salle - '.$texto.' - '; - - require_once('../include/phpmailer/PHPMailerAutoload.php'); - if($_ENV['DB_NAME'] == "paad_pruebas"){ - $asunto = "PRUEBAS-".$asunto; - Mailer::enviarCorreo("alejandro.lara@lasalle.mx", $asunto, $texto, true); - }else{ - Mailer::enviarCorreo($to, $asunto, $texto, true); - } -} - -/* -$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); -*/ -header("Location: ".$pag."?ok=".$ok); -exit(); -?> +querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon', + [':id_salon' => $salon] + ); + if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){ + $salon_desc = "Pendiente"; + }else{ + $salon_json = json_decode($salon_rs["salon_array"], true); + if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ + unset($salon_json[0]); + } + $salon_desc = join(" / ",$salon_json); + } +} + + +if($tipo ==1 || $tipo == 2){ + //-------------- + //Obtiene datos reposici贸n + $reposicion_rs = $db->querySingle('SELECT h.materia, r.fecha_nueva, r.hora_nueva, r.fecha_clase, r.descripcion, h.horario_hora, h.facultad_id, h.facultad, f.clave_dependencia, r.motivo_cancelacion, ta.tipoaula_supervisor , ta.tipoaula_nombre + from reposicion_solicitud r + inner join horario_view h on h.horario_id = r.horario_id + inner join facultad f on f.facultad_id = h.facultad_id + inner join tipoaula ta on ta.tipoaula_id = r.tipoaula_id + where r.reposicion_solicitud_id = :id_repo', + [':id_repo' => $id_repo] + ); + + //Obtiene correos + $correos_rs = $db->query('SELECT p.profesor_nombre, p.profesor_correo, u.usuario_nombre as jefe_nombre, u.usuario_correo as jefe_correo, + coor.usuario_nombre as coordinador_nombre, coor.usuario_correo as coordinador_correo + from reposicion_solicitud rs + inner join profesor p on rs.profesor_id =p.profesor_id + inner join usuario u on u.usuario_id = rs.usuario_id + inner join horario_view hv on hv.horario_id = rs.horario_id + inner join usuario coor on hv.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord + where rs.reposicion_solicitud_id = :id_repo', + [':rol_coord' => COORDINADOR, ':id_repo' => $id_repo] + ); + //print_r($correos_rs); exit(); +}else{ + //Obtiene datos asignaci贸n + $reposicion_rs = $db->querySingle('SELECT r.fecha_nueva, r.hora_nueva, r.descripcion, f.facultad_id, f.facultad_nombre as facultad, f.clave_dependencia, r.motivo_cancelacion, ta.tipoaula_supervisor , ta.tipoaula_nombre, p.profesor_nombre + from asignacion_solicitud r + inner join usuario u on u.usuario_id = r.usuario_id + inner join facultad f on f.facultad_id = u.facultad_id + inner join tipoaula ta on ta.tipoaula_id = r.tipoaula_id + inner join profesor p on p.profesor_id = r.profesor_id + where r.asignacion_solicitud_id = :id_repo', + [':id_repo' => $id_repo] + ); + + //Obtiene correos + $correos_rs = $db->query('SELECT p.profesor_nombre, p.profesor_correo, NULL as jefe_nombre, NULL as jefe_correo, + coor.usuario_nombre as coordinador_nombre, coor.usuario_correo as coordinador_correo + from asignacion_solicitud rs + inner join profesor p on rs.profesor_id =p.profesor_id + inner join usuario u on u.usuario_id = rs.usuario_id + inner join usuario coor on u.facultad_id = coor.facultad_id and coor.rol_id = :rol_coord + where rs.asignacion_solicitud_id = :id_repo', + [':rol_coord' => COORDINADOR, ':id_repo' => $id_repo] + ); + +} + +$prof_correos=array(); +$jefe_correos=[]; +$coord_correos=[]; + +foreach($correos_rs as $correo){ + if( count($prof_correos)==0 && $correo["profesor_correo"]!=""){ + if( !isset($prof_correos["correo"]) || !in_array($correo["profesor_correo"], $prof_correos["correo"]) ){ + array_push($prof_correos, $correo["profesor_correo"]); + } + } + if( count($jefe_correos)==0 && $correo["jefe_correo"]!=""){ + if(!isset($jefe_correos["correo"]) || !in_array($correo["jefe_correo"], $jefe_correos["correo"])){ + array_push($jefe_correos, $correo["jefe_correo"]); + } + } + if( count($coord_correos)==0 && $correo["coordinador_correo"]!=""){ + if(!isset($coord_correos["correo"]) || !in_array($correo["coordinador_correo"], $coord_correos["correo"])){ + array_push($coord_correos, $correo["coordinador_correo"]); + } + } +} + +$correosSup_rs = $db->query("SELECT DISTINCT sup.usuario_correo as supervisor_correo + FROM horario_supervisor hs + inner join usuario sup on sup.usuario_id =hs.usuario_id + where :facultad = ANY(hs.facultad_id_array)", + [':facultad'=>$reposicion_rs["facultad_id"]] ); + +$sup_correos=[]; +foreach($correosSup_rs as $correo){ + array_push($sup_correos, $correo["supervisor_correo"]); +} + + +if($tipo ==1 || $tipo == 2){ + if($edo == 4){//cancelaci贸n + $motivo = ""; + if(isset($_POST["motivo"]) && $_POST["motivo"] != "") + $motivo = trim($_POST["motivo"]); + $db->querySingle('SELECT fu_reposicion_cancela(:id, :motivo)', + [':id' => $id_repo, ':motivo' => $motivo] + ); + }else{ + if(!empty($salon)){ + $db->querySingle('SELECT fu_reposicion_solicitud(:id, NULL, NULL, NULL, :sal, :edo, NULL, NULL, NULL, NULL)', + [':id' => $id_repo, ':sal' => $salon, ':edo' => $edo] + ); + }else{ + $db->querySingle('SELECT fu_reposicion_solicitud(:id, NULL, NULL, NULL, NULL, :edo, NULL, NULL, NULL, NULL)', + [':id' => $id_repo, ':edo' => $edo] + ); + } + } + + $fecha_clase = date('d/m/Y', strtotime($reposicion_rs["fecha_clase"])); + $fecha_nueva = date('d/m/Y', strtotime($reposicion_rs["fecha_nueva"])); + $hora_tmp = explode(":",$reposicion_rs["horario_hora"]); + $hora_clase = $hora_tmp[0].":".$hora_tmp[1]; + $hora_tmp = explode(":",$reposicion_rs["hora_nueva"]); + $hora_nueva = $hora_tmp[0].":".$hora_tmp[1]; + + $asunto = ""; + $texto = ""; + $to = ""; + switch($edo){ + case 2://Correo a supervisor + $asunto = "Reposici贸n nueva - ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"]; + //crear plantilla + $texto = "

Se cre贸 una reposici贸n nueva para: ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"].".

"; + $texto .= "

".mb_strtoupper($reposicion_rs["materia"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora_nueva." hrs."; + if(!$reposicion_rs["tipoaula_supervisor"]){ + $texto .= " en el sal贸n: ".$salon_desc."

"; + }else{ + $texto .= " en un sal贸n de tipo: ".$reposicion_rs["tipoaula_nombre"]."

"; + } + $texto .= "

".$reposicion_rs["descripcion"]."

"; + $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; + $to = join(",", $sup_correos); + $ok = 0; + break; + case 3://Correo a coordinador, profesor y jefe + $asunto = "Reposici贸n autorizada - ".$reposicion_rs["materia"]; + $texto = "

La resposici贸n de la clase de ".$reposicion_rs["materia"]." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. est谩 autorizada para realizarse el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. en: $salon_desc

"; + $to = join(",", $coord_correos).",".join(",", $prof_correos).",".join(",", $jefe_correos); + $ok = 0; + $db->querySingle('SELECT fu_reposicion_solicitud_supervisor(:id, :sup)', + [':id' => $id_repo, ':sup'=>$user->user["id"]] + ); + break; + case 4://Correo a coordinador, profesor y jefe + $asunto = "Reposici贸n declinada - ".$reposicion_rs["materia"]; + $texto = "

La resposici贸n de la clase de ".$reposicion_rs["materia"]." planeada para el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo:

"; + $texto .= "

".$motivo."

"; + $to = join(",", $coord_correos).",".join(",", $prof_correos).",".join(",", $jefe_correos); + $ok = 1; + $db->querySingle('SELECT fu_reposicion_solicitud_supervisor(:id, :sup)', + [':id' => $id_repo, ':sup'=>$user->user["id"]] + ); + break; + } +}else{ + if($edo == 4){//cancelaci贸n + $motivo = ""; + if(isset($_POST["motivo"]) && $_POST["motivo"] != "") + $motivo = trim($_POST["motivo"]); + $db->querySingle('SELECT fu_asignacion_cancela(:id, :motivo)', + [':id' => $id_repo, ':motivo' => $motivo] + ); + }else{ + if(!empty($salon)){ + $db->querySingle('SELECT fu_asignacion_solicitud(:id, NULL, NULL, :sal, :edo, NULL, NULL, NULL, NULL, NULL)', + [':id' => $id_repo, ':sal' => $salon, ':edo' => $edo] + ); + }else{ + $db->querySingle('SELECT fu_asignacion_solicitud(:id, NULL, NULL, NULL, :edo, NULL, NULL, NULL, NULL, NULL)', + [':id' => $id_repo, ':edo' => $edo] + ); + } + } + + $fecha_nueva = date('d/m/Y', strtotime($reposicion_rs["fecha_nueva"])); + $hora_tmp = explode(":",$reposicion_rs["hora_nueva"]); + $hora_nueva = $hora_tmp[0].":".$hora_tmp[1]; + + $asunto = ""; + $texto = ""; + $to = ""; + switch($edo){ + case 2://Correo a supervisor + $asunto = "Asignaci贸n nueva - ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"]; + //crear plantilla + $texto = "

Se cre贸 una solicitud de asignaci贸n nueva para: ".$reposicion_rs["clave_dependencia"]." ".$reposicion_rs["facultad"].".

"; + $texto .= "

Se solicita el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. para el profesor: ".$reposicion_rs["profesor_nombre"]."."; + if(!$reposicion_rs["tipoaula_supervisor"]){ + $texto .= " en el sal贸n: ".$salon_desc."

"; + }else{ + $texto .= " en un sal贸n de tipo: ".$reposicion_rs["tipoaula_nombre"]."

"; + } + $texto .= "

".$reposicion_rs["descripcion"]."

"; + $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; + $to = join(",", $sup_correos); + $ok = 0; + break; + case 3://Correo a coordinador, profesor y jefe + $asunto = "Asignaci贸n autorizada - ".$reposicion_rs["profesor_nombre"]; + $texto = "

La asignaci贸n de espacio para el profesor ".$reposicion_rs["profesor_nombre"]." est谩 autorizada para realizarse el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. en: $salon_desc

"; + $to = join(",", $coord_correos).",".join(",", $prof_correos).",".join(",", $jefe_correos); + $ok = 0; + $db->querySingle('SELECT fu_asignacion_solicitud_supervisor(:id, :sup)', + [':id' => $id_repo, ':sup'=>$user->user["id"]] + ); + break; + case 4://Correo a coordinador, profesor y jefe + $asunto = "Asignaci贸n declinada - ".$reposicion_rs["profesor_nombre"]; + $texto = "

La asignaci贸n de espacio para el profesor ".$reposicion_rs["profesor_nombre"]." planeada para el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo:

"; + $texto .= "

".$motivo."

"; + $to = join(",", $coord_correos).",".join(",", $prof_correos).",".join(",", $jefe_correos); + $ok = 1; + $db->querySingle('SELECT fu_asignacion_solicitud_supervisor(:id, :sup)', + [':id' => $id_repo, ':sup'=>$user->user["id"]] + ); + break; + } +} + + +if($to!= "" && ENVIO_CORREOS){ + $texto = ' + La Salle + '.$texto.' + '; + + require_once('../include/phpmailer/PHPMailerAutoload.php'); + if($_ENV['DB_NAME'] == "paad_pruebas"){ + $asunto = "PRUEBAS-".$asunto; + Mailer::enviarCorreo("alejandro.lara@lasalle.mx", $asunto, $texto, true); + }else{ + Mailer::enviarCorreo($to, $asunto, $texto, true); + } +} + +/* +$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); +*/ +header("Location: ".$pag."?ok=".$ok); +exit(); +?> diff --git a/action/reposicion_delete.php b/action/reposicion_delete.php index 8c69187..5ab1844 100644 --- a/action/reposicion_delete.php +++ b/action/reposicion_delete.php @@ -1,33 +1,33 @@ -user["id"]; - - try{ - $db->query('SELECT * from fd_reposicion_solicitud(:id, :creador)', [":id"=> $id, ":creador"=>$creador]); - $return["ok"] = "La reposici贸n se borr贸 correctamente"; - - }catch(Exception $e){ - $return["error"] = "Ocurri贸 un error al borrar la reposici贸n."; - } - - -} -echo json_encode($return); -?> +user["id"]; + + try{ + $db->query('SELECT * from fd_reposicion_solicitud(:id, :creador)', [":id"=> $id, ":creador"=>$creador]); + $return["ok"] = "La reposici贸n se borr贸 correctamente"; + + }catch(Exception $e){ + $return["error"] = "Ocurri贸 un error al borrar la reposici贸n."; + } + + +} +echo json_encode($return); +?> diff --git a/action/reposicion_insert.php b/action/reposicion_insert.php index 895c9ff..1ba5b59 100644 --- a/action/reposicion_insert.php +++ b/action/reposicion_insert.php @@ -1,208 +1,208 @@ -access(); - -$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//Id reposicion -$bloque = filter_input(INPUT_POST, "bloque", FILTER_SANITIZE_NUMBER_INT);// -$ciclo = filter_input(INPUT_POST, "ciclo", FILTER_SANITIZE_NUMBER_INT);// -$fecha_falta = trim(htmlspecialchars($_POST["fecha_falta"], ENT_QUOTES, "UTF-8"));//Reposicion -$fecha = trim(htmlspecialchars($_POST["fecha_inicial"], ENT_QUOTES, "UTF-8"));//Reposicion -$fecha_cambio = trim(htmlspecialchars($_POST["fecha_cambio"], ENT_QUOTES, "UTF-8"));//Cambio sal贸n -$hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto hora reposicion -$min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$hor = filter_input(INPUT_POST, "horario", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$tipo = filter_input(INPUT_POST, "tipo", FILTER_SANITIZE_NUMBER_INT);//1 Repo , 0 Cambio -$aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad -$salon = NULL; - -if(!$user->jefe_carrera){//coordinador - if(isset($_POST["salon"]) && $_POST["salon"] != "") - $salon = filter_input(INPUT_POST, "dlSalon", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad -} - -if(empty($_POST["prof"])) - $prof = $user->user["id"]; -else - $prof = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto - -$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto - - - -$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); -$duracion_tiempo = $duracion_rs["duracion_interval"]; - -//-- Obtiene datos de horario regular de clase -$horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor', - [':hor' => $hor] - ); - -$materia = $horario_rs["materia_id"]; -$dia = $horario_rs["horario_dia"]; - -$hora = $hora_ini.":".$min_ini.":00"; - - -if($tipo == 1){//Reposici贸n - $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; - $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; - $dia_new = date('w', strtotime($fecha_new)); - - $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d'); - $dia_falta = date('w', strtotime($fecha_falta)); -}else{ - $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d'); - $dia_falta = date('w', strtotime($fecha_cambio)); -} - - -//Valida que tenga clase en la fecha de falta -if(intval($dia) != intval($dia_falta)){ - header("Location:".$pag."?error=11"); - /*print_r($_POST); - echo 'SELECT * from horario_view where horario_id = '.$hor; - echo intval($dia)." != ".intval($dia_falta);*/ - exit(); -} - -//Obtiene materia -$materia_rs = $db->querySingle('SELECT materia_nombre from materia where materia_id = :mat',[':mat' => $materia]); - -//Obtiene correo -$correos_rs = $db->querySingle('SELECT coor.usuario_correo, coor.usuario_nombre from usuario coor where rol_id = :rol_coord and facultad_id = ( - select coalesce(facultad_id,0) from usuario u where u.usuario_id = :id_usr) and coor.usuario_correo != \'\'',[':rol_coord' => COORDINADOR, ':id_usr' => $user->user["id"]] -); -if( count($correos_rs) > 0 ){ - $to = $correos_rs["usuario_correo"]; -} - -if($tipo == 1){//Reposici贸n - // Valida que grupo no tenga clases - /*$result = validaConflictoHoras($pdo, $gpo, $dia_new, $hora, $materia, "-", $fecha_new, $fecha_fin_new, $duracion); - if($result != ""){//error - //echo $result; - header("Location:".$pag."?error=7"); - exit(); - } - */ - //Valida que profesor no este en 2 reposiciones al mismo tiempo en la fecha nueva - - $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)', - [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo] - )["traslape_profesor_reposicion"]; - if($traslape){ - //print_r($_POST); - //echo "SELECT * from traslape_profesor_reposicion($prof,'".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."' , '$hora', $duracion)"; - - header("Location:".$pag."?error=9"); - exit(); - } - - try{ - if($user->jefe_carrera){//jefe - $db->query('SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 1, :desc, :alumnos, true, :aula, :duracion, :usr, :bloque, :ciclo)', - [':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, ':hor' => $hor, - ':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"], - ':bloque' => $bloque, ':ciclo' => $ciclo - ] - ); - - }else{//coordinador - echo 'SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 2, :desc, :alumnos, true, :aula, :duracion, :usr, :bloque, :ciclo, '.$salon.')'; - $db->query('SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 2, :desc, :alumnos, true, :aula, :duracion, :usr, :bloque, :ciclo, :salon)', - [':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, ':hor' => $hor, - ':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"], - ':bloque' => $bloque, ':ciclo' => $ciclo, ':salon'=>$salon - ] - ); - } - }catch(Exception $e){ - - echo "ERROR Reposici贸n
".$e->getMessage(); - //header("Location: ".$pag."?error=1"); - exit(); - } - $fecha_clase = date('d/m/Y', strtotime($fecha_falta)); - $fecha_nueva = date('d/m/Y', strtotime($fecha_new)); - $texto = "

Se cre贸 una reposici贸n nueva.

"; - $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$horario_rs["horario_hora"]." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs."; - $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; - -/* - $log = new LogActividad(); - $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."] Alumnos[".$alumnos."]"; - $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ - - -}else{//Cambio sal贸n / hora - - try{ - if($user->jefe_carrera){//jefe - $db->query('SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 1, :desc, :alumnos, false, :aula, :duracion, :usr, :bloque, :ciclo)', - [':f_falta' => $fecha_cambio, ':f_nueva' => $fecha_cambio, ':hora_nueva' => $hora, ':hor' => $hor, - ':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"], - ':bloque' => $bloque, ':ciclo' => $ciclo - ] - ); - }else{//coordinador - $db->query('SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 2, :desc, :alumnos, false, :aula, :duracion, :usr, :bloque, :ciclo, :salon)', - [':f_falta' => $fecha_cambio, ':f_nueva' => $fecha_cambio, ':hora_nueva' => $hora, ':hor' => $hor, - ':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"], - ':bloque' => $bloque, ':ciclo' => $ciclo, ':salon'=>$salon - ] - ); - } - }catch(Exception $e){ - echo "ERROR Cambio
".$e->getMessage(); - //header("Location: ".$pag."?error=1"); - exit(); - } - $texto = "

Se cre贸 un cambio de sal贸n nuevo.

"; - $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_falta." a las ".$hora." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs."; - $texto .= "

Ingresa al sistema PAAD para autorizarlo.

"; - - /* - $log = new LogActividad(); - $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_cambio.">".$fecha_cambio_nueva."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."] Alumnos[".$alumnos."]"; - $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); - */ - -} - -if($to!= "" && ENVIO_CORREOS){ - $asunto = "Reposici贸n nueva - solicitud"; - //crear plantilla - $texto = ' - La Salle - '.$texto.' - '; - - require_once('../include/phpmailer/PHPMailerAutoload.php'); - if($_ENV['DB_NAME'] == "paad_pruebas"){ - $asunto = "PRUEBAS-".$asunto; - Mailer::enviarCorreo("alejandro.lara@lasalle.mx", $asunto, $texto, true); - }else{ - Mailer::enviarCorreo($to, $asunto, $texto, true); - } - -} - -header("Location: ".$pag."?ok=0"); -exit(); -?> +access(); + +$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//Id reposicion +$bloque = filter_input(INPUT_POST, "bloque", FILTER_SANITIZE_NUMBER_INT);// +$ciclo = filter_input(INPUT_POST, "ciclo", FILTER_SANITIZE_NUMBER_INT);// +$fecha_falta = trim(htmlspecialchars($_POST["fecha_falta"], ENT_QUOTES, "UTF-8"));//Reposicion +$fecha = trim(htmlspecialchars($_POST["fecha_inicial"], ENT_QUOTES, "UTF-8"));//Reposicion +$fecha_cambio = trim(htmlspecialchars($_POST["fecha_cambio"], ENT_QUOTES, "UTF-8"));//Cambio sal贸n +$hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto hora reposicion +$min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$hor = filter_input(INPUT_POST, "horario", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$tipo = filter_input(INPUT_POST, "tipo", FILTER_SANITIZE_NUMBER_INT);//1 Repo , 0 Cambio +$aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad +$salon = NULL; + +if(!$user->jefe_carrera){//coordinador + if(isset($_POST["salon"]) && $_POST["salon"] != "") + $salon = filter_input(INPUT_POST, "dlSalon", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad +} + +if(empty($_POST["prof"])) + $prof = $user->user["id"]; +else + $prof = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto + +$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto + + + +$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); +$duracion_tiempo = $duracion_rs["duracion_interval"]; + +//-- Obtiene datos de horario regular de clase +$horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor', + [':hor' => $hor] + ); + +$materia = $horario_rs["materia_id"]; +$dia = $horario_rs["horario_dia"]; + +$hora = $hora_ini.":".$min_ini.":00"; + + +if($tipo == 1){//Reposici贸n + $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; + $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; + $dia_new = date('w', strtotime($fecha_new)); + + $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d'); + $dia_falta = date('w', strtotime($fecha_falta)); +}else{ + $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d'); + $dia_falta = date('w', strtotime($fecha_cambio)); +} + + +//Valida que tenga clase en la fecha de falta +if(intval($dia) != intval($dia_falta)){ + header("Location:".$pag."?error=11"); + /*print_r($_POST); + echo 'SELECT * from horario_view where horario_id = '.$hor; + echo intval($dia)." != ".intval($dia_falta);*/ + exit(); +} + +//Obtiene materia +$materia_rs = $db->querySingle('SELECT materia_nombre from materia where materia_id = :mat',[':mat' => $materia]); + +//Obtiene correo +$correos_rs = $db->querySingle('SELECT coor.usuario_correo, coor.usuario_nombre from usuario coor where rol_id = :rol_coord and facultad_id = ( + select coalesce(facultad_id,0) from usuario u where u.usuario_id = :id_usr) and coor.usuario_correo != \'\'',[':rol_coord' => COORDINADOR, ':id_usr' => $user->user["id"]] +); +if( count($correos_rs) > 0 ){ + $to = $correos_rs["usuario_correo"]; +} + +if($tipo == 1){//Reposici贸n + // Valida que grupo no tenga clases + /*$result = validaConflictoHoras($pdo, $gpo, $dia_new, $hora, $materia, "-", $fecha_new, $fecha_fin_new, $duracion); + if($result != ""){//error + //echo $result; + header("Location:".$pag."?error=7"); + exit(); + } + */ + //Valida que profesor no este en 2 reposiciones al mismo tiempo en la fecha nueva + + $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)', + [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo] + )["traslape_profesor_reposicion"]; + if($traslape){ + //print_r($_POST); + //echo "SELECT * from traslape_profesor_reposicion($prof,'".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."' , '$hora', $duracion)"; + + header("Location:".$pag."?error=9"); + exit(); + } + + try{ + if($user->jefe_carrera){//jefe + $db->query('SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 1, :desc, :alumnos, true, :aula, :duracion, :usr, :bloque, :ciclo)', + [':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, ':hor' => $hor, + ':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"], + ':bloque' => $bloque, ':ciclo' => $ciclo + ] + ); + + }else{//coordinador + echo 'SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 2, :desc, :alumnos, true, :aula, :duracion, :usr, :bloque, :ciclo, '.$salon.')'; + $db->query('SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 2, :desc, :alumnos, true, :aula, :duracion, :usr, :bloque, :ciclo, :salon)', + [':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, ':hor' => $hor, + ':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"], + ':bloque' => $bloque, ':ciclo' => $ciclo, ':salon'=>$salon + ] + ); + } + }catch(Exception $e){ + + echo "ERROR Reposici贸n
".$e->getMessage(); + //header("Location: ".$pag."?error=1"); + exit(); + } + $fecha_clase = date('d/m/Y', strtotime($fecha_falta)); + $fecha_nueva = date('d/m/Y', strtotime($fecha_new)); + $texto = "

Se cre贸 una reposici贸n nueva.

"; + $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$horario_rs["horario_hora"]." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs."; + $texto .= "

Ingresa al sistema PAAD para autorizarla.

"; + +/* + $log = new LogActividad(); + $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."] Alumnos[".$alumnos."]"; + $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ + + +}else{//Cambio sal贸n / hora + + try{ + if($user->jefe_carrera){//jefe + $db->query('SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 1, :desc, :alumnos, false, :aula, :duracion, :usr, :bloque, :ciclo)', + [':f_falta' => $fecha_cambio, ':f_nueva' => $fecha_cambio, ':hora_nueva' => $hora, ':hor' => $hor, + ':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"], + ':bloque' => $bloque, ':ciclo' => $ciclo + ] + ); + }else{//coordinador + $db->query('SELECT * from fi_reposicion_solicitud(:f_falta, :f_nueva, :hora_nueva, :hor, :prof, 2, :desc, :alumnos, false, :aula, :duracion, :usr, :bloque, :ciclo, :salon)', + [':f_falta' => $fecha_cambio, ':f_nueva' => $fecha_cambio, ':hora_nueva' => $hora, ':hor' => $hor, + ':prof' => $prof, ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo, ':usr'=>$user->user["id"], + ':bloque' => $bloque, ':ciclo' => $ciclo, ':salon'=>$salon + ] + ); + } + }catch(Exception $e){ + echo "ERROR Cambio
".$e->getMessage(); + //header("Location: ".$pag."?error=1"); + exit(); + } + $texto = "

Se cre贸 un cambio de sal贸n nuevo.

"; + $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_falta." a las ".$hora." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs."; + $texto .= "

Ingresa al sistema PAAD para autorizarlo.

"; + + /* + $log = new LogActividad(); + $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_cambio.">".$fecha_cambio_nueva."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."] Alumnos[".$alumnos."]"; + $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); + */ + +} + +if($to!= "" && ENVIO_CORREOS){ + $asunto = "Reposici贸n nueva - solicitud"; + //crear plantilla + $texto = ' + La Salle + '.$texto.' + '; + + require_once('../include/phpmailer/PHPMailerAutoload.php'); + if($_ENV['DB_NAME'] == "paad_pruebas"){ + $asunto = "PRUEBAS-".$asunto; + Mailer::enviarCorreo("alejandro.lara@lasalle.mx", $asunto, $texto, true); + }else{ + Mailer::enviarCorreo($to, $asunto, $texto, true); + } + +} + +header("Location: ".$pag."?ok=0"); +exit(); +?> diff --git a/action/reposicion_profesor_materias.php b/action/reposicion_profesor_materias.php index 12832bf..c85a188 100644 --- a/action/reposicion_profesor_materias.php +++ b/action/reposicion_profesor_materias.php @@ -1,49 +1,49 @@ -tieneAcceso()){ - $return["error"] = "Error! No tienes permisos para realizar esta acci贸n."; -}else*/ if(!isset($_POST["id"])){ - $return["error"] = "Error! No se recibi贸 la informaci贸n del profesor."; -}else{ - $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto - - try{ - if($user->jefe_carrera){ - $rs = $db->query('SELECT * FROM fs_materiasprofesor(:id, :jefe)', [':id' => $id, ':jefe'=>$user->user["id"]] ); - }else{ - $rs = $db->query('SELECT * FROM fs_materiasprofesor(:id, NULL)', [':id' => $id] ); - } - - }catch(Exception $e){ - $return["error"] = "Ocurri贸 un error al leer los datos de las materias."; - echo json_encode($return); - } - - $mat_arr = array(); - foreach($rs as $m){ - $mat_arr[] = array("horario_id"=>$m["horario_id"], "horario_dia"=>$m["horario_dia"], - "horario_hora"=>substr($m["horario_hora"], 0, 2), "horario_min"=>substr($m["horario_hora"], 3, 2), - "materia_nombre"=>$m["materia_nombre"].' - '.$m["horario_dia_nombre"]." ".substr($m["horario_hora"], 0, -3), - "grupo"=>$m["horario_grupo"], "duracion" => $m["duracion"] - ); - } - - $return["materias"] = $mat_arr; - -} -echo json_encode($return); -?> +tieneAcceso()){ + $return["error"] = "Error! No tienes permisos para realizar esta acci贸n."; +}else*/ if(!isset($_POST["id"])){ + $return["error"] = "Error! No se recibi贸 la informaci贸n del profesor."; +}else{ + $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto + + try{ + if($user->jefe_carrera){ + $rs = $db->query('SELECT * FROM fs_materiasprofesor(:id, :jefe)', [':id' => $id, ':jefe'=>$user->user["id"]] ); + }else{ + $rs = $db->query('SELECT * FROM fs_materiasprofesor(:id, NULL)', [':id' => $id] ); + } + + }catch(Exception $e){ + $return["error"] = "Ocurri贸 un error al leer los datos de las materias."; + echo json_encode($return); + } + + $mat_arr = array(); + foreach($rs as $m){ + $mat_arr[] = array("horario_id"=>$m["horario_id"], "horario_dia"=>$m["horario_dia"], + "horario_hora"=>substr($m["horario_hora"], 0, 2), "horario_min"=>substr($m["horario_hora"], 3, 2), + "materia_nombre"=>$m["materia_nombre"].' - '.$m["horario_dia_nombre"]." ".substr($m["horario_hora"], 0, -3), + "grupo"=>$m["horario_grupo"], "duracion" => $m["duracion"] + ); + } + + $return["materias"] = $mat_arr; + +} +echo json_encode($return); +?> diff --git a/action/reposicion_select.php b/action/reposicion_select.php index 7a86bbd..8b2aff8 100644 --- a/action/reposicion_select.php +++ b/action/reposicion_select.php @@ -1,91 +1,91 @@ -tieneAcceso()){ - $return["error"] = "Error! No tienes permisos para realizar esta acci贸n."; -}else*/ if(!isset($_POST["id"])){ - $return["error"] = "Error! No se recibi贸 la informaci贸n de la reposici贸n."; -}else{ - $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto - - - try{ - $rs = $db->querySingle('SELECT * from fs_reposicion_solicitud(:id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)', - [':id' => $id] - ); - /*if($user->rol["rol_id"] == 7){//es supervisor - $rs = $db->querySingle('SELECT * from fs_reposicion_solicitud(:id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, :sup)', - [':id' => $id, ':sup'=>$user->user["id"]] - ); - }else{//coordinador - $rs = $db->querySingle('SELECT * from fs_reposicion_solicitud(:id, :fac, NULL, NULL, NULL, NULL, NULL, NULL, null)', - [':id' => $id, ":fac"=>$user->facultad["facultad_id"] ] - ); - }*/ - - }catch(Exception $e){ - $return["error"] = "Ocurri贸 un error al leer los datos de la reposici贸n."; - echo json_encode($return); - exit(); - } - - - $return["fecha_clase"] = date('d/m/Y', strtotime($rs["fecha_clase"])); - $return["fecha_nueva"] = date('d/m/Y', strtotime($rs["fecha_nueva"])); - $hora_nueva = explode(":",$rs["hora_nueva"]); - $return["hora_ini"] = $hora_nueva[0]; - $return["min_ini"] = $hora_nueva[1]; - $hora_nueva_fin = explode(":",$rs["hora_nueva_fin"]); - $return["hora_fin"] = $hora_nueva_fin[0]; - $return["min_fin"] = $hora_nueva_fin[1]; - $return["duracion"] = $rs["duracion_interval"]; - -// $return["carrera"] = $rs["PlanEstudio_desc"]; - $return["horario"] = $rs["horario_id"]; - $return["materia"] = $rs["materia_id"]; - $return["materia_desc"] = $rs["materia_nombre"]; - $return["salon"] = $rs["salon_id"]; - if($rs["salon_id"]==""){ - $return["salon_desc"] = "Pendiente"; - }else{ - $salon_json = json_decode($rs["salon_array"], true); - if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ - unset($salon_json[0]); - } - $return["salon_desc"] = join(" / ",$salon_json); - } - - //$return["salon_desc"] = $rs["salon"]=="" ? "-Pendiente-": $rs["salon"]; - $return["ciclo"] = $rs["ciclo"]; - $return["bloque"] = $rs["bloque"]; - $return["profesor"] = $rs["profesor_id"]; - $return["profesor_nombre"] = $rs["profesor_nombre"]; - $return["comentario"] = $rs["descripcion"]; - $return["alumnos"] = $rs["alumnos"]; - $return["tipo"] = $rs["es_reposicion"]; - $return["aula"] = $rs["tipoaula_id"]; - $return["aula_desc"] = $rs["tipoaula_nombre"]; - $return["aula_supervisor"] = $rs["tipoaula_supervisor"]; - $return["dia"] = date('w', strtotime($rs["fecha_clase"])); - $return["motivo_cancelacion"] = $rs["motivo_cancelacion"]; - $return["estado"] = $rs["estado_reposicion_id"]; - $return["facultad"] = $rs["facultad_nombre"]; - $return["carrera"] = $rs["carrera_comun"]? $rs["carrera_nombre"]: ($rs["horario_carrera"]==""?$rs["carrera_nombre"]:$rs["horario_carrera"]);//si es com煤n, se muestra la carrera de la materia, si no, la carrera del horario - $return["grupo"] = $rs["horario_grupo"]; - $return["supervisor_nombre"] = $rs["supervisor_nombre"]; -} -echo json_encode($return); -?> +tieneAcceso()){ + $return["error"] = "Error! No tienes permisos para realizar esta acci贸n."; +}else*/ if(!isset($_POST["id"])){ + $return["error"] = "Error! No se recibi贸 la informaci贸n de la reposici贸n."; +}else{ + $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto + + + try{ + $rs = $db->querySingle('SELECT * from fs_reposicion_solicitud(:id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)', + [':id' => $id] + ); + /*if($user->rol["rol_id"] == 7){//es supervisor + $rs = $db->querySingle('SELECT * from fs_reposicion_solicitud(:id, NULL, NULL, NULL, NULL, NULL, NULL, NULL, :sup)', + [':id' => $id, ':sup'=>$user->user["id"]] + ); + }else{//coordinador + $rs = $db->querySingle('SELECT * from fs_reposicion_solicitud(:id, :fac, NULL, NULL, NULL, NULL, NULL, NULL, null)', + [':id' => $id, ":fac"=>$user->facultad["facultad_id"] ] + ); + }*/ + + }catch(Exception $e){ + $return["error"] = "Ocurri贸 un error al leer los datos de la reposici贸n."; + echo json_encode($return); + exit(); + } + + + $return["fecha_clase"] = date('d/m/Y', strtotime($rs["fecha_clase"])); + $return["fecha_nueva"] = date('d/m/Y', strtotime($rs["fecha_nueva"])); + $hora_nueva = explode(":",$rs["hora_nueva"]); + $return["hora_ini"] = $hora_nueva[0]; + $return["min_ini"] = $hora_nueva[1]; + $hora_nueva_fin = explode(":",$rs["hora_nueva_fin"]); + $return["hora_fin"] = $hora_nueva_fin[0]; + $return["min_fin"] = $hora_nueva_fin[1]; + $return["duracion"] = $rs["duracion_interval"]; + +// $return["carrera"] = $rs["PlanEstudio_desc"]; + $return["horario"] = $rs["horario_id"]; + $return["materia"] = $rs["materia_id"]; + $return["materia_desc"] = $rs["materia_nombre"]; + $return["salon"] = $rs["salon_id"]; + if($rs["salon_id"]==""){ + $return["salon_desc"] = "Pendiente"; + }else{ + $salon_json = json_decode($rs["salon_array"], true); + if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ + unset($salon_json[0]); + } + $return["salon_desc"] = join(" / ",$salon_json); + } + + //$return["salon_desc"] = $rs["salon"]=="" ? "-Pendiente-": $rs["salon"]; + $return["ciclo"] = $rs["ciclo"]; + $return["bloque"] = $rs["bloque"]; + $return["profesor"] = $rs["profesor_id"]; + $return["profesor_nombre"] = $rs["profesor_nombre"]; + $return["comentario"] = $rs["descripcion"]; + $return["alumnos"] = $rs["alumnos"]; + $return["tipo"] = $rs["es_reposicion"]; + $return["aula"] = $rs["tipoaula_id"]; + $return["aula_desc"] = $rs["tipoaula_nombre"]; + $return["aula_supervisor"] = $rs["tipoaula_supervisor"]; + $return["dia"] = date('w', strtotime($rs["fecha_clase"])); + $return["motivo_cancelacion"] = $rs["motivo_cancelacion"]; + $return["estado"] = $rs["estado_reposicion_id"]; + $return["facultad"] = $rs["facultad_nombre"]; + $return["carrera"] = $rs["carrera_comun"]? $rs["carrera_nombre"]: ($rs["horario_carrera"]==""?$rs["carrera_nombre"]:$rs["horario_carrera"]);//si es com煤n, se muestra la carrera de la materia, si no, la carrera del horario + $return["grupo"] = $rs["horario_grupo"]; + $return["supervisor_nombre"] = $rs["supervisor_nombre"]; +} +echo json_encode($return); +?> diff --git a/action/reposicion_update.php b/action/reposicion_update.php index 521a9cb..9ffb74c 100644 --- a/action/reposicion_update.php +++ b/action/reposicion_update.php @@ -1,125 +1,125 @@ - FILTER_FLAG_STRIP_LOW)));//limpia texto -$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto - -$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); -$duracion_tiempo = $duracion_rs["duracion_interval"]; - -$horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor', - [':hor' => $hor] - ); - -$materia = $horario_rs["materia_id"]; -$dia = $horario_rs["horario_dia"]; - - -$hora = $hora_ini.":".$min_ini.":00"; -$fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; -$fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; -$dia_new = date('w', strtotime($fecha_new)); - -//echo $fecha_new."
"; -//echo $fecha_fin_new."
"; -if($tipo == 1){//Reposici贸n - $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d'); - $dia_falta = date('w', strtotime($fecha_falta)); -}else{ - $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d'); - $dia_falta = date('w', strtotime($fecha_cambio)); -} - -//Valida que tenga clase en la fecha de falta -if(intval($dia) != intval($dia_falta)){ - //header("Location:".$pag."?error=11"); - echo intval($dia)." != ".intval($dia_falta); - exit(); -} - - -if($tipo == 1){//Reposici贸n - // Valida que grupo no tenga clases - /*$result = validaConflictoHoras($pdo, $gpo, $dia, $hora, $materia, "-", $fecha_ini, $fecha_fin, $duracion); - if($result != ""){//error - //echo $result; - header("Location:".$pag."?error=7"); - exit(); - } - - //Valida que profesor no este en 2 reposiciones al mismo tiempo - */ - $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur, :id)', - [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo, ':id'=>$id] - )["traslape_profesor_reposicion"]; - echo "SELECT * from traslape_profesor_reposicion($prof, '".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."', $hora, $duracion_tiempo, $id)"; - if($traslape){ - //header("Location:".$pag."?error=9"); - echo "traslape"; - exit(); - } - - - /* - $log = new LogActividad(); - $desc_log = "Actualiza reposici贸n ID[".$id."] Fechas[".$fecha_ini."][".$fecha_fin."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."]"; - $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ -} - -try{ - $db->query('SELECT * from fu_reposicion_solicitud(:id, :f_falta, :f_nueva, :hora_nueva, NULL, NULL, :desc, :alumnos, :aula, :duracion, NULL)', - [':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, - ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo - ] - ); -}catch(Exception $e){ - //header("Location: ".$pag."?error=2"); - print_r($e->getMessage()); - echo "SELECT * from fu_reposicion_solicitud(:id, :f_falta, :f_nueva, :hora_nueva, NULL, NULL, :desc, :alumnos, :aula, :duracion, NULL)'"; - print_r( - [':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, - ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo - ]); - exit(); -} -header("Location: ".$pag); -exit(); -?> + FILTER_FLAG_STRIP_LOW)));//limpia texto +$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto + +$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); +$duracion_tiempo = $duracion_rs["duracion_interval"]; + +$horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor', + [':hor' => $hor] + ); + +$materia = $horario_rs["materia_id"]; +$dia = $horario_rs["horario_dia"]; + + +$hora = $hora_ini.":".$min_ini.":00"; +$fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; +$fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; +$dia_new = date('w', strtotime($fecha_new)); + +//echo $fecha_new."
"; +//echo $fecha_fin_new."
"; +if($tipo == 1){//Reposici贸n + $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d'); + $dia_falta = date('w', strtotime($fecha_falta)); +}else{ + $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d'); + $dia_falta = date('w', strtotime($fecha_cambio)); +} + +//Valida que tenga clase en la fecha de falta +if(intval($dia) != intval($dia_falta)){ + //header("Location:".$pag."?error=11"); + echo intval($dia)." != ".intval($dia_falta); + exit(); +} + + +if($tipo == 1){//Reposici贸n + // Valida que grupo no tenga clases + /*$result = validaConflictoHoras($pdo, $gpo, $dia, $hora, $materia, "-", $fecha_ini, $fecha_fin, $duracion); + if($result != ""){//error + //echo $result; + header("Location:".$pag."?error=7"); + exit(); + } + + //Valida que profesor no este en 2 reposiciones al mismo tiempo + */ + $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur, :id)', + [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo, ':id'=>$id] + )["traslape_profesor_reposicion"]; + echo "SELECT * from traslape_profesor_reposicion($prof, '".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."', $hora, $duracion_tiempo, $id)"; + if($traslape){ + //header("Location:".$pag."?error=9"); + echo "traslape"; + exit(); + } + + + /* + $log = new LogActividad(); + $desc_log = "Actualiza reposici贸n ID[".$id."] Fechas[".$fecha_ini."][".$fecha_fin."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."]"; + $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ +} + +try{ + $db->query('SELECT * from fu_reposicion_solicitud(:id, :f_falta, :f_nueva, :hora_nueva, NULL, NULL, :desc, :alumnos, :aula, :duracion, NULL)', + [':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, + ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo + ] + ); +}catch(Exception $e){ + //header("Location: ".$pag."?error=2"); + print_r($e->getMessage()); + echo "SELECT * from fu_reposicion_solicitud(:id, :f_falta, :f_nueva, :hora_nueva, NULL, NULL, :desc, :alumnos, :aula, :duracion, NULL)'"; + print_r( + [':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora, + ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion' => $duracion_tiempo + ]); + exit(); +} +header("Location: ".$pag); +exit(); +?> diff --git a/action/solicitud_autoriza.php b/action/solicitud_autoriza.php index 33ae766..4da3611 100644 --- a/action/solicitud_autoriza.php +++ b/action/solicitud_autoriza.php @@ -1,198 +1,198 @@ -querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon', - [':id_salon' => $salon] - ); - if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){ - $salon_desc = "Pendiente"; - }else{ - $salon_json = json_decode($salon_rs["salon_array"], true); - if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ - unset($salon_json[0]); - } - $salon_desc = join(" / ",$salon_json); - } -} - -$solicitud_rs = $db->querySingle('SELECT * from fs_solicitud(:id, NULL, NULL, NULL, NULL, NULL, NULL, NULL)', [':id' => $id_sol]); - - - -if($edo == 4){//cancelaci贸n - $motivo = ""; - if(isset($_POST["motivo"]) && $_POST["motivo"] != "") - $motivo = trim($_POST["motivo"]); - $db->querySingle('SELECT fu_solicitud_cancela(:id, :motivo)', - [':id' => $id_sol, ':motivo' => $motivo] - ); -}else{ - if(!empty($salon)){ - //fu_solicitud(p_solicitud_id, p_fecha_clase , p_fecha_nueva, p_hora_nueva, p_prof_id , p_desc, p_edo, p_alumnos, p_tipoaula , p_salon, p_duracion , p_horario_id , p_bloque, p_ciclo, p_motivo, p_supervisor_id ) - $db->querySingle('SELECT fu_solicitud(:id, NULL, NULL, NULL, NULL, NULL, :edo, NULL, NULL,:sal, NULL, NULL, NULL, NULL, NULL, NULL)', - [':id' => $id_sol, ':sal' => $salon, ':edo' => $edo] - ); - }else{ - $db->querySingle('SELECT fu_solicitud(:id, NULL, NULL, NULL, NULL, NULL, :edo, NULL, NULL,NULL, NULL, NULL, NULL, NULL, NULL, NULL)', - [':id' => $id_sol, ':edo' => $edo] - ); - } -} -//fecha_nueva, fecha_clase -$fecha_nueva = $solicitud_rs["fecha_nueva"]; -$hora_nueva = $solicitud_rs["hora_nueva"]; -$fecha_clase = $solicitud_rs["fecha_clase"]; -$hora_clase = $solicitud_rs["horario_hora"]; -$facultad = $solicitud_rs["facultad"]??""; - -//echo $fecha_nueva." ** ".$fecha_clase; - -if(!empty($fecha_nueva)){ - $dia_new = date('w', strtotime($fecha_nueva)); - //$fecha_nueva = DateTime::createFromFormat('Y-m-d', $fecha_nueva)->format('d/m/Y')." ".$hora_nueva; - $fecha_nueva = $fecha_nueva." ".$hora_nueva; -} - -if(!empty($fecha_clase)){ - $dia_falta = date('w', strtotime($fecha_clase)); - //$fecha_clase = DateTime::createFromFormat('d/m/Y', $fecha_clase)->format('Y-m-d'); -} - -switch($edo){ - case 2://Correo a supervisor - switch($tipo){ - case 1://Reposici贸n - $asunto = "Solicitud - Reposici贸n nueva ".$solicitud_rs["clave_dependencia"]." ".$facultad; - $texto = "

Se cre贸 una nueva solicitud de reposici贸n para: ".$solicitud_rs["clave_dependencia"]." ".$facultad.".

"; - $texto .= "

".mb_strtoupper($solicitud_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora_nueva." hrs."; - break; - case 2: - $asunto = "Solicitud - Cambio de sal贸n ".$solicitud_rs["clave_dependencia"]." ".$facultad; - $texto = "

Se cre贸 una nueva solicitud de cambio de sal贸n.

"; - $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. "; - - break; - case 3: - $asunto = "Solicitud - Asignaci贸n de espacio ".$solicitud_rs["clave_dependencia"]." ".$facultad; - $texto = "

Se cre贸 una nueva solicitud de asignaci贸n de sal贸n.

"; - $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. "; - break; - case 4: - $asunto = "Solicitud - Cambio permanente ".$solicitud_rs["clave_dependencia"]." ".$facultad; - $texto = "

Se cre贸 una nueva solicitud de asignaci贸n de sal贸n permanente.

"; - $texto .= "

".mb_strtoupper($solicitud_rs["materia_nombre"])." a partir del d铆a ".$fecha_clase." a las ".$hora_orig." hrs. se propone cambiar para el ".$fecha_nueva." a las ".$hora_nueva." hrs."; - break; - - } - //$texto .= "

Ingresa al sistema PAAD para autorizarla.

"; - - MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::SUPERVISOR); - - $ok = 0; - break; - case 3://Correo a coordinador, profesor y jefe - - switch($tipo){ - case 1://Reposici贸n - $asunto = "Reposici贸n nueva autorizada ".isset($solicitud_rs["materia"])?$solicitud_rs["materia"]:""; - $texto = "

Se autoriz贸 la solicitud de reposici贸n.

"; - $texto .= "

".mb_strtoupper($solicitud_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. se repondr谩 el ".$fecha_nueva." a las ".$hora_nueva." hrs. en ".$salon_desc.""; - break; - case 2: - $asunto = "Cambio de sal贸n autorizado"; - $texto = "

Se autoriz贸 la solicitud de cambio de sal贸n.

"; - $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. en ".$salon_desc.""; - - break; - case 3: - $asunto = "Asignaci贸n de espacio autorizada"; - $texto = "

Se autoriz贸 la asignaci贸n de sal贸n.

"; - $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. en ".$salon_desc.""; - break; - case 4: - $asunto = "Cambio permanente autorizado ".$solicitud_rs["materia_nombre"]; - $texto = "

Se autoriz贸 cambio de sal贸n permanente.

"; - $texto .= "

".mb_strtoupper($solicitud_rs["materia_nombre"])." a partir del d铆a ".$fecha_clase." la clase ser谩 el ".$fecha_nueva." a las ".$hora_nueva." hrs. en ".$salon_desc.""; - break; - } - - $ok = 0; - $db->querySingle('SELECT fu_reposicion_solicitud_supervisor(:id, :sup)', - [':id' => $id_sol, ':sup'=>$user->user["id"]] - ); - - MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::COORDINADOR| MandaCorreos::PROFESOR| MandaCorreos::JEFE); - - break; - case 4://Correo a coordinador, profesor y jefe - switch($tipo){ - case 1://Reposici贸n - $asunto = "Reposici贸n declinada ".$solicitud_rs["materia"]; - $texto = "

La reposici贸n de ".mb_strtoupper($solicitud_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. programada para el ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo

"; - break; - case 2: - $asunto = "Cambio de sal贸n declinado"; - $texto = "

La solicitud de cambio de sal贸n para el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo

"; - break; - case 3: - $asunto = "Asignaci贸n de espacio declinada"; - $texto = "

La asignaci贸n de sal贸n para el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo

"; - break; - case 4: - $asunto = "Cambio permanente declinado ".$solicitud_rs["materia_nombre"]; - $texto = "

El cambio de sal贸n permanente de ".mb_strtoupper($solicitud_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. programada para el ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo

"; - break; - } - $texto .= "

".$solicitud_rs["motivo"]."

"; - - $ok = 1; - $db->querySingle('SELECT fu_reposicion_solicitud_supervisor(:id, :sup)', - [':id' => $id_sol, ':sup'=>$user->user["id"]] - ); - - MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::COORDINADOR| MandaCorreos::PROFESOR| MandaCorreos::JEFE); - - break; -} - - -/* -$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); -*/ -header("Location: ".$pag."?ok=".$ok); -exit(); -?> +querySingle('SELECT s.salon_id, s.salon_array FROM salon_view s where s.salon_id = :id_salon', + [':id_salon' => $salon] + ); + if($salon_rs["salon_id"] == "" || $salon_rs["salon_id"] == NULL){ + $salon_desc = "Pendiente"; + }else{ + $salon_json = json_decode($salon_rs["salon_array"], true); + if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ + unset($salon_json[0]); + } + $salon_desc = join(" / ",$salon_json); + } +} + +$solicitud_rs = $db->querySingle('SELECT * from fs_solicitud(:id, NULL, NULL, NULL, NULL, NULL, NULL, NULL)', [':id' => $id_sol]); + + + +if($edo == 4){//cancelaci贸n + $motivo = ""; + if(isset($_POST["motivo"]) && $_POST["motivo"] != "") + $motivo = trim($_POST["motivo"]); + $db->querySingle('SELECT fu_solicitud_cancela(:id, :motivo)', + [':id' => $id_sol, ':motivo' => $motivo] + ); +}else{ + if(!empty($salon)){ + //fu_solicitud(p_solicitud_id, p_fecha_clase , p_fecha_nueva, p_hora_nueva, p_prof_id , p_desc, p_edo, p_alumnos, p_tipoaula , p_salon, p_duracion , p_horario_id , p_bloque, p_ciclo, p_motivo, p_supervisor_id ) + $db->querySingle('SELECT fu_solicitud(:id, NULL, NULL, NULL, NULL, NULL, :edo, NULL, NULL,:sal, NULL, NULL, NULL, NULL, NULL, NULL)', + [':id' => $id_sol, ':sal' => $salon, ':edo' => $edo] + ); + }else{ + $db->querySingle('SELECT fu_solicitud(:id, NULL, NULL, NULL, NULL, NULL, :edo, NULL, NULL,NULL, NULL, NULL, NULL, NULL, NULL, NULL)', + [':id' => $id_sol, ':edo' => $edo] + ); + } +} +//fecha_nueva, fecha_clase +$fecha_nueva = $solicitud_rs["fecha_nueva"]; +$hora_nueva = $solicitud_rs["hora_nueva"]; +$fecha_clase = $solicitud_rs["fecha_clase"]; +$hora_clase = $solicitud_rs["horario_hora"]; +$facultad = $solicitud_rs["facultad"]??""; + +//echo $fecha_nueva." ** ".$fecha_clase; + +if(!empty($fecha_nueva)){ + $dia_new = date('w', strtotime($fecha_nueva)); + //$fecha_nueva = DateTime::createFromFormat('Y-m-d', $fecha_nueva)->format('d/m/Y')." ".$hora_nueva; + $fecha_nueva = $fecha_nueva." ".$hora_nueva; +} + +if(!empty($fecha_clase)){ + $dia_falta = date('w', strtotime($fecha_clase)); + //$fecha_clase = DateTime::createFromFormat('d/m/Y', $fecha_clase)->format('Y-m-d'); +} + +switch($edo){ + case 2://Correo a supervisor + switch($tipo){ + case 1://Reposici贸n + $asunto = "Solicitud - Reposici贸n nueva ".$solicitud_rs["clave_dependencia"]." ".$facultad; + $texto = "

Se cre贸 una nueva solicitud de reposici贸n para: ".$solicitud_rs["clave_dependencia"]." ".$facultad.".

"; + $texto .= "

".mb_strtoupper($solicitud_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora_nueva." hrs."; + break; + case 2: + $asunto = "Solicitud - Cambio de sal贸n ".$solicitud_rs["clave_dependencia"]." ".$facultad; + $texto = "

Se cre贸 una nueva solicitud de cambio de sal贸n.

"; + $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. "; + + break; + case 3: + $asunto = "Solicitud - Asignaci贸n de espacio ".$solicitud_rs["clave_dependencia"]." ".$facultad; + $texto = "

Se cre贸 una nueva solicitud de asignaci贸n de sal贸n.

"; + $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. "; + break; + case 4: + $asunto = "Solicitud - Cambio permanente ".$solicitud_rs["clave_dependencia"]." ".$facultad; + $texto = "

Se cre贸 una nueva solicitud de asignaci贸n de sal贸n permanente.

"; + $texto .= "

".mb_strtoupper($solicitud_rs["materia_nombre"])." a partir del d铆a ".$fecha_clase." a las ".$hora_orig." hrs. se propone cambiar para el ".$fecha_nueva." a las ".$hora_nueva." hrs."; + break; + + } + //$texto .= "

Ingresa al sistema PAAD para autorizarla.

"; + + MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::SUPERVISOR); + + $ok = 0; + break; + case 3://Correo a coordinador, profesor y jefe + + switch($tipo){ + case 1://Reposici贸n + $asunto = "Reposici贸n nueva autorizada ".isset($solicitud_rs["materia"])?$solicitud_rs["materia"]:""; + $texto = "

Se autoriz贸 la solicitud de reposici贸n.

"; + $texto .= "

".mb_strtoupper($solicitud_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. se repondr谩 el ".$fecha_nueva." a las ".$hora_nueva." hrs. en ".$salon_desc.""; + break; + case 2: + $asunto = "Cambio de sal贸n autorizado"; + $texto = "

Se autoriz贸 la solicitud de cambio de sal贸n.

"; + $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. en ".$salon_desc.""; + + break; + case 3: + $asunto = "Asignaci贸n de espacio autorizada"; + $texto = "

Se autoriz贸 la asignaci贸n de sal贸n.

"; + $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. en ".$salon_desc.""; + break; + case 4: + $asunto = "Cambio permanente autorizado ".$solicitud_rs["materia_nombre"]; + $texto = "

Se autoriz贸 cambio de sal贸n permanente.

"; + $texto .= "

".mb_strtoupper($solicitud_rs["materia_nombre"])." a partir del d铆a ".$fecha_clase." la clase ser谩 el ".$fecha_nueva." a las ".$hora_nueva." hrs. en ".$salon_desc.""; + break; + } + + $ok = 0; + $db->querySingle('SELECT fu_reposicion_solicitud_supervisor(:id, :sup)', + [':id' => $id_sol, ':sup'=>$user->user["id"]] + ); + + MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::COORDINADOR| MandaCorreos::PROFESOR| MandaCorreos::JEFE); + + break; + case 4://Correo a coordinador, profesor y jefe + switch($tipo){ + case 1://Reposici贸n + $asunto = "Reposici贸n declinada ".$solicitud_rs["materia"]; + $texto = "

La reposici贸n de ".mb_strtoupper($solicitud_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. programada para el ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo

"; + break; + case 2: + $asunto = "Cambio de sal贸n declinado"; + $texto = "

La solicitud de cambio de sal贸n para el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo

"; + break; + case 3: + $asunto = "Asignaci贸n de espacio declinada"; + $texto = "

La asignaci贸n de sal贸n para el d铆a ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo

"; + break; + case 4: + $asunto = "Cambio permanente declinado ".$solicitud_rs["materia_nombre"]; + $texto = "

El cambio de sal贸n permanente de ".mb_strtoupper($solicitud_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_clase." hrs. programada para el ".$fecha_nueva." a las ".$hora_nueva." hrs. ha sido declinada por el siguiente motivo

"; + break; + } + $texto .= "

".$solicitud_rs["motivo"]."

"; + + $ok = 1; + $db->querySingle('SELECT fu_reposicion_solicitud_supervisor(:id, :sup)', + [':id' => $id_sol, ':sup'=>$user->user["id"]] + ); + + MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::COORDINADOR| MandaCorreos::PROFESOR| MandaCorreos::JEFE); + + break; +} + + +/* +$log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); +*/ +header("Location: ".$pag."?ok=".$ok); +exit(); +?> diff --git a/action/solicitud_delete.php b/action/solicitud_delete.php index 54d702a..a68a1ec 100644 --- a/action/solicitud_delete.php +++ b/action/solicitud_delete.php @@ -1,33 +1,33 @@ -user["id"]; - - try{ - $db->query('SELECT * from fd_solicitud(:id, :creador)', [":id"=> $id, ":creador"=>$creador]); - $return["ok"] = "La solicitud se borr贸 correctamente"; - - }catch(Exception $e){ - $return["error"] = "Ocurri贸 un error al borrar la solicitud."; - } - - -} -echo json_encode($return); -?> +user["id"]; + + try{ + $db->query('SELECT * from fd_solicitud(:id, :creador)', [":id"=> $id, ":creador"=>$creador]); + $return["ok"] = "La solicitud se borr贸 correctamente"; + + }catch(Exception $e){ + $return["error"] = "Ocurri贸 un error al borrar la solicitud."; + } + + +} +echo json_encode($return); +?> diff --git a/action/solicitud_insert.php b/action/solicitud_insert.php index 71d4dad..4b77690 100644 --- a/action/solicitud_insert.php +++ b/action/solicitud_insert.php @@ -1,206 +1,206 @@ -access(); - -$estado = filter_input(INPUT_POST, "estado", FILTER_SANITIZE_NUMBER_INT);// -$tipo = filter_input(INPUT_POST, "tipo", FILTER_SANITIZE_NUMBER_INT);// -$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//Id reposicion -$bloque = filter_input(INPUT_POST, "bloque", FILTER_SANITIZE_NUMBER_INT);// -$ciclo = filter_input(INPUT_POST, "ciclo", FILTER_SANITIZE_NUMBER_INT);// -$fecha_falta = trim(htmlspecialchars($_POST["fecha_falta"], ENT_QUOTES, "UTF-8"));//Reposicion -$fecha = trim(htmlspecialchars($_POST["fecha_nueva"], ENT_QUOTES, "UTF-8"));//Reposicion -$fecha_cambio = trim(htmlspecialchars($_POST["fecha_cambio"], ENT_QUOTES, "UTF-8"));//Cambio sal贸n -$hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto hora reposicion -$min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$horario = filter_input(INPUT_POST, "horario", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto -$aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad -$salon = NULL; - -/*if(!$user->jefe_carrera){//coordinador - if(isset($_POST["salon"]) && $_POST["salon"] != "") - $salon = filter_input(INPUT_POST, "dlSalon", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad -}*/ - -if(empty($_POST["prof"])) - $prof = $user->user["id"]; -else - $prof = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto - -$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto - - - -$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); -$duracion_tiempo = $duracion_rs["duracion_interval"]; - -//-- Obtiene datos de horario regular de clase -if($horario!= null && $tipo !=3) -{ - $horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor', - [':hor' => $horario] - ); - - $materia = $horario_rs["materia_id"]; - $dia = $horario_rs["horario_dia"]; - $hora_orig = $horario_rs["horario_hora"]; -}else{ - $dia = date('w', strtotime($fecha)); -} - -$hora = $hora_ini.":".$min_ini.":00"; - -switch($tipo){ - case 1://Reposici贸n - $fecha_nueva = $fecha; - $fecha_clase = $fecha_falta; - - $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; - $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; - $dia_new = date('w', strtotime($fecha_new)); - - $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d'); - $dia_falta = date('w', strtotime($fecha_falta)); - - //Valida que tenga clase en la fecha de falta - if(intval($dia) != intval($dia_falta)){ - header("Location:".$pag."?error=11"); - /*print_r($_POST); - echo 'SELECT * from horario_view where horario_id = '.$horario; - echo intval($dia)." != ".intval($dia_falta);*/ - exit(); - } - - break; - case 2://Cambio - $fecha_nueva = $fecha_cambio; - - $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d'); - $dia_falta = date('w', strtotime($fecha_cambio)); - break; - case 3://Solicitud de espacio - $fecha_nueva = $fecha; - - $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; - $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; - $dia_new = date('w', strtotime($fecha_new)); - break; - case 4://Cambio permanente - $fecha_nueva = $fecha; - $fecha_clase = $fecha_cambio; - - $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; - $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d')." ".$hora; - $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; - $dia_new = date('w', strtotime($fecha_new)); - - break; -} - -if(isset($materia) && $materia!= null && $tipo !=3){ - //Obtiene materia - $materia_rs = $db->querySingle('SELECT materia_nombre from materia where materia_id = :mat',[':mat' => $materia]); -} - -$query = ":f_falta, :f_nueva, :hora_nueva, :prof, :desc, :edo, :alumnos, :aula, :solicitudtipo, :usr, :duracion, :hor, :bloque, :ciclo"; -switch($tipo){ - case 1://Reposici贸n - $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)', - [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo] - )["traslape_profesor_reposicion"]; - if($traslape){ - //print_r($_POST); - //echo "SELECT * from traslape_profesor_reposicion($prof,'".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."' , '$hora', $duracion)"; - header("Location:".$pag."?error=9"); - exit(); - } - - $db_params=[ - ":f_falta"=>$fecha_falta, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, ":desc"=>$comentario, - ":edo"=>1, ":alumnos"=>$alumnos, ":aula"=>$aula, ":solicitudtipo"=>$tipo, ":usr"=>$user->user["id"], - ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo - ]; - $asunto = "Solicitud - Reposici贸n nueva"; - $texto = "

Se cre贸 una nueva solicitud de reposici贸n.

"; - $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_falta." a las ".$hora_orig." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs."; - - /* - $log = new LogActividad(); - $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$horario."] Alumnos[".$alumnos."]"; - $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ - break; - case 2: - $db_params=[ - ":f_falta"=>$fecha_cambio, ":f_nueva"=>$fecha_cambio, ":hora_nueva"=>$hora, ":prof"=>$prof, ":desc"=>$comentario, - ":edo"=>1, ":alumnos"=>$alumnos, ":aula"=>$aula, ":solicitudtipo"=>$tipo, ":usr"=>$user->user["id"], - ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo - ]; - $asunto = "Solicitud - Cambio de sal贸n"; - $texto = "

Se cre贸 una nueva solicitud de cambio de sal贸n.

"; - $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora." hrs. "; - - /* - $log = new LogActividad(); - $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_cambio.">".$fecha_cambio_nueva."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$horario."] Alumnos[".$alumnos."]"; - $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); - */ - break; - case 3: - $db_params=[ - ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, ":desc"=>$comentario, - ":edo"=>1, ":alumnos"=>$alumnos, ":aula"=>$aula, ":solicitudtipo"=>$tipo, ":usr"=>$user->user["id"], - ":duracion"=>$duracion_tiempo - ]; - $query = "null, :f_nueva, :hora_nueva, :prof, :desc, :edo, :alumnos, :aula, :solicitudtipo, :usr, :duracion"; - $asunto = "Solicitud - Asignaci贸n de espacio"; - $texto = "

Se cre贸 una nueva solicitud de asignaci贸n de sal贸n.

"; - $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora." hrs. "; - break; - case 4: - $db_params=[ - ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, ":desc"=>$comentario, - ":edo"=>1, ":alumnos"=>$alumnos, ":aula"=>$aula, ":solicitudtipo"=>$tipo, ":usr"=>$user->user["id"], - ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo - ]; - $query = "NULL, :f_nueva, :hora_nueva, :prof, :desc, :edo, :alumnos, :aula, :solicitudtipo, :usr, :duracion, :hor, :bloque, :ciclo"; - $asunto = "Solicitud - Cambio permanente"; - $texto = "

Se cre贸 una nueva solicitud de asignaci贸n de sal贸n permanente.

"; - $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." a partir del d铆a ".$fecha_clase." a las ".$hora_orig." hrs. se propone cambiar para el ".$fecha_nueva." a las ".$hora." hrs."; - break; - -} -try{ - $db->query("SELECT * from fi_solicitud($query)", $db_params); -}catch(Exception $e){ - echo "ERROR Cambio
".$e->getMessage(); - echo $query; - print_r($db_params); - //header("Location: ".$pag."?error=1"); - exit(); -} - -if(!MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::COORDINADOR)){ - echo "ERROR Correo
"; - //header("Location: ".$pag."?error=2"); - exit(); -} - - -header("Location: ".$pag."?ok=0"); -exit(); -?> +access(); + +$estado = filter_input(INPUT_POST, "estado", FILTER_SANITIZE_NUMBER_INT);// +$tipo = filter_input(INPUT_POST, "tipo", FILTER_SANITIZE_NUMBER_INT);// +$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//Id reposicion +$bloque = filter_input(INPUT_POST, "bloque", FILTER_SANITIZE_NUMBER_INT);// +$ciclo = filter_input(INPUT_POST, "ciclo", FILTER_SANITIZE_NUMBER_INT);// +$fecha_falta = trim(htmlspecialchars($_POST["fecha_falta"], ENT_QUOTES, "UTF-8"));//Reposicion +$fecha = trim(htmlspecialchars($_POST["fecha_nueva"], ENT_QUOTES, "UTF-8"));//Reposicion +$fecha_cambio = trim(htmlspecialchars($_POST["fecha_cambio"], ENT_QUOTES, "UTF-8"));//Cambio sal贸n +$hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto hora reposicion +$min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$horario = filter_input(INPUT_POST, "horario", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto +$aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad +$salon = NULL; + +/*if(!$user->jefe_carrera){//coordinador + if(isset($_POST["salon"]) && $_POST["salon"] != "") + $salon = filter_input(INPUT_POST, "dlSalon", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad +}*/ + +if(empty($_POST["prof"])) + $prof = $user->user["id"]; +else + $prof = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto + +$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto + + + +$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); +$duracion_tiempo = $duracion_rs["duracion_interval"]; + +//-- Obtiene datos de horario regular de clase +if($horario!= null && $tipo !=3) +{ + $horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor', + [':hor' => $horario] + ); + + $materia = $horario_rs["materia_id"]; + $dia = $horario_rs["horario_dia"]; + $hora_orig = $horario_rs["horario_hora"]; +}else{ + $dia = date('w', strtotime($fecha)); +} + +$hora = $hora_ini.":".$min_ini.":00"; + +switch($tipo){ + case 1://Reposici贸n + $fecha_nueva = $fecha; + $fecha_clase = $fecha_falta; + + $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; + $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; + $dia_new = date('w', strtotime($fecha_new)); + + $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d'); + $dia_falta = date('w', strtotime($fecha_falta)); + + //Valida que tenga clase en la fecha de falta + if(intval($dia) != intval($dia_falta)){ + header("Location:".$pag."?error=11"); + /*print_r($_POST); + echo 'SELECT * from horario_view where horario_id = '.$horario; + echo intval($dia)." != ".intval($dia_falta);*/ + exit(); + } + + break; + case 2://Cambio + $fecha_nueva = $fecha_cambio; + + $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d'); + $dia_falta = date('w', strtotime($fecha_cambio)); + break; + case 3://Solicitud de espacio + $fecha_nueva = $fecha; + + $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; + $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; + $dia_new = date('w', strtotime($fecha_new)); + break; + case 4://Cambio permanente + $fecha_nueva = $fecha; + $fecha_clase = $fecha_cambio; + + $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; + $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d')." ".$hora; + $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; + $dia_new = date('w', strtotime($fecha_new)); + + break; +} + +if(isset($materia) && $materia!= null && $tipo !=3){ + //Obtiene materia + $materia_rs = $db->querySingle('SELECT materia_nombre from materia where materia_id = :mat',[':mat' => $materia]); +} + +$query = ":f_falta, :f_nueva, :hora_nueva, :prof, :desc, :edo, :alumnos, :aula, :solicitudtipo, :usr, :duracion, :hor, :bloque, :ciclo"; +switch($tipo){ + case 1://Reposici贸n + $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)', + [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo] + )["traslape_profesor_reposicion"]; + if($traslape){ + //print_r($_POST); + //echo "SELECT * from traslape_profesor_reposicion($prof,'".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."' , '$hora', $duracion)"; + header("Location:".$pag."?error=9"); + exit(); + } + + $db_params=[ + ":f_falta"=>$fecha_falta, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, ":desc"=>$comentario, + ":edo"=>1, ":alumnos"=>$alumnos, ":aula"=>$aula, ":solicitudtipo"=>$tipo, ":usr"=>$user->user["id"], + ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo + ]; + $asunto = "Solicitud - Reposici贸n nueva"; + $texto = "

Se cre贸 una nueva solicitud de reposici贸n.

"; + $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_falta." a las ".$hora_orig." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs."; + + /* + $log = new LogActividad(); + $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$horario."] Alumnos[".$alumnos."]"; + $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ + break; + case 2: + $db_params=[ + ":f_falta"=>$fecha_cambio, ":f_nueva"=>$fecha_cambio, ":hora_nueva"=>$hora, ":prof"=>$prof, ":desc"=>$comentario, + ":edo"=>1, ":alumnos"=>$alumnos, ":aula"=>$aula, ":solicitudtipo"=>$tipo, ":usr"=>$user->user["id"], + ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo + ]; + $asunto = "Solicitud - Cambio de sal贸n"; + $texto = "

Se cre贸 una nueva solicitud de cambio de sal贸n.

"; + $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora." hrs. "; + + /* + $log = new LogActividad(); + $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_cambio.">".$fecha_cambio_nueva."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$horario."] Alumnos[".$alumnos."]"; + $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); + */ + break; + case 3: + $db_params=[ + ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, ":desc"=>$comentario, + ":edo"=>1, ":alumnos"=>$alumnos, ":aula"=>$aula, ":solicitudtipo"=>$tipo, ":usr"=>$user->user["id"], + ":duracion"=>$duracion_tiempo + ]; + $query = "null, :f_nueva, :hora_nueva, :prof, :desc, :edo, :alumnos, :aula, :solicitudtipo, :usr, :duracion"; + $asunto = "Solicitud - Asignaci贸n de espacio"; + $texto = "

Se cre贸 una nueva solicitud de asignaci贸n de sal贸n.

"; + $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora." hrs. "; + break; + case 4: + $db_params=[ + ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, ":desc"=>$comentario, + ":edo"=>1, ":alumnos"=>$alumnos, ":aula"=>$aula, ":solicitudtipo"=>$tipo, ":usr"=>$user->user["id"], + ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo + ]; + $query = "NULL, :f_nueva, :hora_nueva, :prof, :desc, :edo, :alumnos, :aula, :solicitudtipo, :usr, :duracion, :hor, :bloque, :ciclo"; + $asunto = "Solicitud - Cambio permanente"; + $texto = "

Se cre贸 una nueva solicitud de asignaci贸n de sal贸n permanente.

"; + $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." a partir del d铆a ".$fecha_clase." a las ".$hora_orig." hrs. se propone cambiar para el ".$fecha_nueva." a las ".$hora." hrs."; + break; + +} +try{ + $db->query("SELECT * from fi_solicitud($query)", $db_params); +}catch(Exception $e){ + echo "ERROR Cambio
".$e->getMessage(); + echo $query; + print_r($db_params); + //header("Location: ".$pag."?error=1"); + exit(); +} + +if(!MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::COORDINADOR)){ + echo "ERROR Correo
"; + //header("Location: ".$pag."?error=2"); + exit(); +} + + +header("Location: ".$pag."?ok=0"); +exit(); +?> diff --git a/action/solicitud_select.php b/action/solicitud_select.php index e55dd73..2e1dce3 100644 --- a/action/solicitud_select.php +++ b/action/solicitud_select.php @@ -1,101 +1,101 @@ -tieneAcceso()){ - $return["error"] = "Error! No tienes permisos para realizar esta acci贸n."; -}else*/ if(!isset($_POST["id"])){ - $return["error"] = "Error! No se recibi贸 la informaci贸n de la reposici贸n."; -}else{ - $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto - - try{ - if($user->rol["rol_id"] == 7){//es supervisor - $rs = $db->querySingle('SELECT * from fs_solicitud(:id, NULL, NULL, NULL, NULL, NULL, NULL, :sup)', - [':id' => $id, ':sup'=>$user->user["id"]] - ); - }else{//coordinador - $rs = $db->querySingle('SELECT * from fs_solicitud(:id, :fac, NULL, NULL, NULL, NULL, NULL, null)', - [':id' => $id, ":fac"=>$user->facultad["facultad_id"] ] - ); - } - - }catch(Exception $e){ - $return["error"] = "Ocurri贸 un error al leer los datos de la reposici贸n."; - echo json_encode($return); - exit(); - } - - $dias = array('Domingo','Lunes','Martes','Mi茅rcoles','Jueves','Viernes','S谩bado'); - - if($rs["solicitudtipo_id"]!=3){ - $hora_nueva = explode(":",$rs["horario_hora"]); - } - - if($rs["solicitudtipo_id"]!=4){ - $return["fecha_clase"] = isset($rs["fecha_clase"]) ? date('d/m/Y', strtotime($rs["fecha_clase"])):''; - }else{ - $return["fecha_clase"] = $dias[$rs["horario_dia"]]; - } - $return["hora_clase_ini"] = $rs["horario_hora"]; - $return["hora_clase_fin"] = $rs["horario_hora_fin"]; - - $return["fecha_nueva"] = isset($rs["fecha_nueva"]) ? date('d/m/Y', strtotime($rs["fecha_nueva"])):''; - $return["hora_nueva"] = $rs["hora_nueva"]; - $hora_nueva = explode(":",$rs["hora_nueva"]); - $return["hora_ini"] = $hora_nueva[0]; - $return["min_ini"] = $hora_nueva[1]; - $return["hora_nueva_fin"] = $rs["hora_nueva_fin"]; - $hora_nueva_fin = explode(":",$rs["hora_nueva_fin"]); - $return["hora_fin"] = $hora_nueva_fin[0]; - $return["min_fin"] = $hora_nueva_fin[1]; - $return["duracion"] = $rs["duracion_interval"]; - -// $return["carrera"] = $rs["PlanEstudio_desc"]; - $return["horario"] = $rs["horario_id"]; - $return["materia"] = $rs["materia_id"]; - $return["materia_desc"] = $rs["materia_nombre"]; - $return["salon"] = $rs["salon_id"]; - if($rs["salon_id"]==""){ - $return["salon_desc"] = "Pendiente"; - }else{ - $salon_json = json_decode($rs["salon_array"], true); - if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ - unset($salon_json[0]); - } - $return["salon_desc"] = join(" / ",$salon_json); - } - $return["ciclo"] = $rs["ciclo"]; - $return["bloque"] = $rs["bloque"]; - $return["profesor"] = $rs["profesor_id"]; - $return["profesor_nombre"] = $rs["profesor_nombre"]; - $return["comentario"] = $rs["descripcion"]; - $return["alumnos"] = $rs["alumnos"]; - $return["aula"] = $rs["tipoaula_id"]; - $return["aula_desc"] = $rs["tipoaula_nombre"]; - $return["aula_supervisor"] = $rs["tipoaula_supervisor"]; - $return["dia_nombre"] = isset($rs["fecha_clase"]) ? date('w', strtotime($rs["fecha_clase"])): ''; - $return["dia"] = isset($rs["fecha_clase"]) ? $dias[date('w', strtotime($rs["fecha_clase"]))]: ''; - $return["motivo_cancelacion"] = $rs["motivo_cancelacion"]; - $return["estado"] = $rs["estado_reposicion_id"]; - $return["facultad"] = $rs["facultad_nombre"]; - $return["carrera"] = $rs["carrera_comun"]? $rs["carrera_nombre"]:$rs["horario_carrera"];//si es com煤n, se muestra la carrera de la materia, si no, la carrera del horario - $return["grupo"] = $rs["horario_grupo"]; - $return["supervisor_nombre"] = $rs["supervisor_nombre"]; - $return["solicitudtipo_id"] = $rs["solicitudtipo_id"]; - $return["solicitudtipo"] = $rs["solicitudtipo_nombre"]; -} -echo json_encode($return); -?> +tieneAcceso()){ + $return["error"] = "Error! No tienes permisos para realizar esta acci贸n."; +}else*/ if(!isset($_POST["id"])){ + $return["error"] = "Error! No se recibi贸 la informaci贸n de la reposici贸n."; +}else{ + $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto + + try{ + if($user->rol["rol_id"] == 7){//es supervisor + $rs = $db->querySingle('SELECT * from fs_solicitud(:id, NULL, NULL, NULL, NULL, NULL, NULL, :sup)', + [':id' => $id, ':sup'=>$user->user["id"]] + ); + }else{//coordinador + $rs = $db->querySingle('SELECT * from fs_solicitud(:id, :fac, NULL, NULL, NULL, NULL, NULL, null)', + [':id' => $id, ":fac"=>$user->facultad["facultad_id"] ] + ); + } + + }catch(Exception $e){ + $return["error"] = "Ocurri贸 un error al leer los datos de la reposici贸n."; + echo json_encode($return); + exit(); + } + + $dias = array('Domingo','Lunes','Martes','Mi茅rcoles','Jueves','Viernes','S谩bado'); + + if($rs["solicitudtipo_id"]!=3){ + $hora_nueva = explode(":",$rs["horario_hora"]); + } + + if($rs["solicitudtipo_id"]!=4){ + $return["fecha_clase"] = isset($rs["fecha_clase"]) ? date('d/m/Y', strtotime($rs["fecha_clase"])):''; + }else{ + $return["fecha_clase"] = $dias[$rs["horario_dia"]]; + } + $return["hora_clase_ini"] = $rs["horario_hora"]; + $return["hora_clase_fin"] = $rs["horario_hora_fin"]; + + $return["fecha_nueva"] = isset($rs["fecha_nueva"]) ? date('d/m/Y', strtotime($rs["fecha_nueva"])):''; + $return["hora_nueva"] = $rs["hora_nueva"]; + $hora_nueva = explode(":",$rs["hora_nueva"]); + $return["hora_ini"] = $hora_nueva[0]; + $return["min_ini"] = $hora_nueva[1]; + $return["hora_nueva_fin"] = $rs["hora_nueva_fin"]; + $hora_nueva_fin = explode(":",$rs["hora_nueva_fin"]); + $return["hora_fin"] = $hora_nueva_fin[0]; + $return["min_fin"] = $hora_nueva_fin[1]; + $return["duracion"] = $rs["duracion_interval"]; + +// $return["carrera"] = $rs["PlanEstudio_desc"]; + $return["horario"] = $rs["horario_id"]; + $return["materia"] = $rs["materia_id"]; + $return["materia_desc"] = $rs["materia_nombre"]; + $return["salon"] = $rs["salon_id"]; + if($rs["salon_id"]==""){ + $return["salon_desc"] = "Pendiente"; + }else{ + $salon_json = json_decode($rs["salon_array"], true); + if($salon_json[0]== "UNIVERSIDAD LA SALLE"){ + unset($salon_json[0]); + } + $return["salon_desc"] = join(" / ",$salon_json); + } + $return["ciclo"] = $rs["ciclo"]; + $return["bloque"] = $rs["bloque"]; + $return["profesor"] = $rs["profesor_id"]; + $return["profesor_nombre"] = $rs["profesor_nombre"]; + $return["comentario"] = $rs["descripcion"]; + $return["alumnos"] = $rs["alumnos"]; + $return["aula"] = $rs["tipoaula_id"]; + $return["aula_desc"] = $rs["tipoaula_nombre"]; + $return["aula_supervisor"] = $rs["tipoaula_supervisor"]; + $return["dia_nombre"] = isset($rs["fecha_clase"]) ? date('w', strtotime($rs["fecha_clase"])): ''; + $return["dia"] = isset($rs["fecha_clase"]) ? $dias[date('w', strtotime($rs["fecha_clase"]))]: ''; + $return["motivo_cancelacion"] = $rs["motivo_cancelacion"]; + $return["estado"] = $rs["estado_reposicion_id"]; + $return["facultad"] = $rs["facultad_nombre"]; + $return["carrera"] = $rs["carrera_comun"]? $rs["carrera_nombre"]:$rs["horario_carrera"];//si es com煤n, se muestra la carrera de la materia, si no, la carrera del horario + $return["grupo"] = $rs["horario_grupo"]; + $return["supervisor_nombre"] = $rs["supervisor_nombre"]; + $return["solicitudtipo_id"] = $rs["solicitudtipo_id"]; + $return["solicitudtipo"] = $rs["solicitudtipo_nombre"]; +} +echo json_encode($return); +?> diff --git a/action/solicitud_update.php b/action/solicitud_update.php index 6618dfd..b127c93 100644 --- a/action/solicitud_update.php +++ b/action/solicitud_update.php @@ -1,197 +1,197 @@ - FILTER_FLAG_STRIP_LOW)));//limpia texto -$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto - -$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); -$duracion_tiempo = $duracion_rs["duracion_interval"]; - -//-- Obtiene datos de horario regular de clase -if($horario!= null && $tipo !=3) -{ - $horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor', - [':hor' => $horario] - ); - - $materia = $horario_rs["materia_id"]; - $dia = $horario_rs["horario_dia"]; - $hora_orig = $horario_rs["horario_hora"]; -}else{ - $dia = date('w', strtotime($fecha)); -} - -$hora = $hora_ini.":".$min_ini.":00"; - -switch($tipo){ - case 1://Reposici贸n - $fecha_nueva = $fecha; - $fecha_clase = $fecha_falta; - - $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; - $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; - $dia_new = date('w', strtotime($fecha_new)); - - $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d'); - $dia_falta = date('w', strtotime($fecha_falta)); - - //Valida que tenga clase en la fecha de falta - if(intval($dia) != intval($dia_falta)){ - header("Location:".$pag."?error=11"); - /*print_r($_POST); - echo 'SELECT * from horario_view where horario_id = '.$horario; - echo intval($dia)." != ".intval($dia_falta);*/ - exit(); - } - - break; - case 2://Cambio - $fecha_nueva = $fecha_cambio; - - $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d'); - $dia_falta = date('w', strtotime($fecha_cambio)); - break; - case 3://Solicitud de espacio - $fecha_nueva = $fecha; - - $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; - $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; - $dia_new = date('w', strtotime($fecha_new)); - break; - case 4://Cambio permanente - $fecha_nueva = $fecha_new; - $fecha_clase = $fecha_cambio; - - $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; - $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d')." ".$hora; - $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; - $dia_new = date('w', strtotime($fecha_new)); - break; -} - -if(isset($materia) && $materia!= null && $tipo !=3){ - //Obtiene materia - $materia_rs = $db->querySingle('SELECT materia_nombre from materia where materia_id = :mat',[':mat' => $materia]); -} - - -$query = ":id, :f_falta, :f_nueva, :hora_nueva, :prof, :desc, NULL, :alumnos, :aula, NULL, :duracion, :hor, :bloque, :ciclo, NULL, NULL"; -switch($tipo){ - case 1://Reposici贸n - $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)', - [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo] - )["traslape_profesor_reposicion"]; - if($traslape){ - //print_r($_POST); - //echo "SELECT * from traslape_profesor_reposicion($prof,'".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."' , '$hora', $duracion)"; - header("Location:".$pag."?error=9"); - exit(); - } - $db_params=[ - "id"=>$id, ":f_falta"=>$fecha_falta, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, - ":desc"=>$comentario, ":alumnos"=>$alumnos, ":aula"=>$aula, - ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo - ]; - $asunto = "Solicitud - Reposici贸n nueva"; - $texto = "

Se actualiz贸 una solicitud de reposici贸n.

"; - $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_falta." a las ".$hora_orig." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs."; - - /* - $log = new LogActividad(); - $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$horario."] Alumnos[".$alumnos."]"; - $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ - break; - case 2: - $db_params=[ - "id"=>$id, ":f_falta"=>$fecha_falta, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, - ":desc"=>$comentario, ":alumnos"=>$alumnos, ":aula"=>$aula, - ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo - ]; - $asunto = "Solicitud - Cambio de sal贸n"; - $texto = "

Se actualiz贸 una solicitud de cambio de sal贸n.

"; - $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora." hrs. "; - - /* - $log = new LogActividad(); - $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_cambio.">".$fecha_cambio_nueva."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$horario."] Alumnos[".$alumnos."]"; - $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); - */ - break; - case 3: - $db_params=[ - "id"=>$id, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, - ":desc"=>$comentario, ":alumnos"=>$alumnos, ":aula"=>$aula, - ":duracion"=>$duracion_tiempo - ]; - $query = ":id, NULL, :f_nueva, :hora_nueva, :prof, :desc, NULL, :alumnos, :aula, NULL, :duracion, NULL, NULL, NULL, NULL, NULL"; - $asunto = "Solicitud - Asignaci贸n de espacio"; - $texto = "

Se actualiz贸 una solicitud de asignaci贸n de sal贸n.

"; - $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora." hrs. "; - break; - case 4: - $db_params=[ - "id"=>$id, ":f_falta"=>$fecha_cambio, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, - ":desc"=>$comentario, ":alumnos"=>$alumnos, ":aula"=>$aula, - ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo - ]; - $query = ":id, :f_falta, :f_nueva, :hora_nueva, :prof, :desc, NULL, :alumnos, :aula, NULL, :duracion, :hor, :bloque, :ciclo, NULL, NULL"; - $asunto = "Solicitud - Cambio permanente"; - $texto = "

Se actualiz贸 una solicitud de asignaci贸n de sal贸n permanente.

"; - $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_orig." hrs. se propone cambiar para el ".$fecha_nueva." a las ".$hora." hrs."; - break; -} - - -try{ - $db->query("SELECT * from fu_solicitud($query)", $db_params); - MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::COORDINADOR); -}catch(Exception $e){ - echo "ERROR Cambio
".$e->getMessage(); - //echo $query; - //print_r($db_params); - //header("Location: ".$pag."?error=1"); - exit(); -} - -header("Location: ".$pag); -exit(); + FILTER_FLAG_STRIP_LOW)));//limpia texto +$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto + +$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]); +$duracion_tiempo = $duracion_rs["duracion_interval"]; + +//-- Obtiene datos de horario regular de clase +if($horario!= null && $tipo !=3) +{ + $horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor', + [':hor' => $horario] + ); + + $materia = $horario_rs["materia_id"]; + $dia = $horario_rs["horario_dia"]; + $hora_orig = $horario_rs["horario_hora"]; +}else{ + $dia = date('w', strtotime($fecha)); +} + +$hora = $hora_ini.":".$min_ini.":00"; + +switch($tipo){ + case 1://Reposici贸n + $fecha_nueva = $fecha; + $fecha_clase = $fecha_falta; + + $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; + $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; + $dia_new = date('w', strtotime($fecha_new)); + + $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d'); + $dia_falta = date('w', strtotime($fecha_falta)); + + //Valida que tenga clase en la fecha de falta + if(intval($dia) != intval($dia_falta)){ + header("Location:".$pag."?error=11"); + /*print_r($_POST); + echo 'SELECT * from horario_view where horario_id = '.$horario; + echo intval($dia)." != ".intval($dia_falta);*/ + exit(); + } + + break; + case 2://Cambio + $fecha_nueva = $fecha_cambio; + + $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d'); + $dia_falta = date('w', strtotime($fecha_cambio)); + break; + case 3://Solicitud de espacio + $fecha_nueva = $fecha; + + $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; + $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; + $dia_new = date('w', strtotime($fecha_new)); + break; + case 4://Cambio permanente + $fecha_nueva = $fecha_new; + $fecha_clase = $fecha_cambio; + + $fecha_new = DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora; + $fecha_cambio = DateTime::createFromFormat('d/m/Y', $fecha_cambio)->format('Y-m-d')." ".$hora; + $fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo; + $dia_new = date('w', strtotime($fecha_new)); + break; +} + +if(isset($materia) && $materia!= null && $tipo !=3){ + //Obtiene materia + $materia_rs = $db->querySingle('SELECT materia_nombre from materia where materia_id = :mat',[':mat' => $materia]); +} + + +$query = ":id, :f_falta, :f_nueva, :hora_nueva, :prof, :desc, NULL, :alumnos, :aula, NULL, :duracion, :hor, :bloque, :ciclo, NULL, NULL"; +switch($tipo){ + case 1://Reposici贸n + $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)', + [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo] + )["traslape_profesor_reposicion"]; + if($traslape){ + //print_r($_POST); + //echo "SELECT * from traslape_profesor_reposicion($prof,'".DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')."' , '$hora', $duracion)"; + header("Location:".$pag."?error=9"); + exit(); + } + $db_params=[ + "id"=>$id, ":f_falta"=>$fecha_falta, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, + ":desc"=>$comentario, ":alumnos"=>$alumnos, ":aula"=>$aula, + ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo + ]; + $asunto = "Solicitud - Reposici贸n nueva"; + $texto = "

Se actualiz贸 una solicitud de reposici贸n.

"; + $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_falta." a las ".$hora_orig." hrs. se propone reponer el ".$fecha_nueva." a las ".$hora." hrs."; + + /* + $log = new LogActividad(); + $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_falta.">".$fecha_new."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$horario."] Alumnos[".$alumnos."]"; + $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/ + break; + case 2: + $db_params=[ + "id"=>$id, ":f_falta"=>$fecha_falta, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, + ":desc"=>$comentario, ":alumnos"=>$alumnos, ":aula"=>$aula, + ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo + ]; + $asunto = "Solicitud - Cambio de sal贸n"; + $texto = "

Se actualiz贸 una solicitud de cambio de sal贸n.

"; + $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora." hrs. "; + + /* + $log = new LogActividad(); + $desc_log = "Inserta reposici贸n nueva ID[".$rs["fi_reposicion"]."] Fechas[".$fecha_cambio.">".$fecha_cambio_nueva."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$horario."] Alumnos[".$alumnos."]"; + $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log); + */ + break; + case 3: + $db_params=[ + "id"=>$id, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, + ":desc"=>$comentario, ":alumnos"=>$alumnos, ":aula"=>$aula, + ":duracion"=>$duracion_tiempo + ]; + $query = ":id, NULL, :f_nueva, :hora_nueva, :prof, :desc, NULL, :alumnos, :aula, NULL, :duracion, NULL, NULL, NULL, NULL, NULL"; + $asunto = "Solicitud - Asignaci贸n de espacio"; + $texto = "

Se actualiz贸 una solicitud de asignaci贸n de sal贸n.

"; + $texto .= "

El d铆a ".$fecha_nueva." a las ".$hora." hrs. "; + break; + case 4: + $db_params=[ + "id"=>$id, ":f_falta"=>$fecha_cambio, ":f_nueva"=>$fecha_new, ":hora_nueva"=>$hora, ":prof"=>$prof, + ":desc"=>$comentario, ":alumnos"=>$alumnos, ":aula"=>$aula, + ":duracion"=>$duracion_tiempo, ":hor"=>$horario, ":bloque"=>$bloque, ":ciclo"=>$ciclo + ]; + $query = ":id, :f_falta, :f_nueva, :hora_nueva, :prof, :desc, NULL, :alumnos, :aula, NULL, :duracion, :hor, :bloque, :ciclo, NULL, NULL"; + $asunto = "Solicitud - Cambio permanente"; + $texto = "

Se actualiz贸 una solicitud de asignaci贸n de sal贸n permanente.

"; + $texto .= "

".mb_strtoupper($materia_rs["materia_nombre"])." del d铆a ".$fecha_clase." a las ".$hora_orig." hrs. se propone cambiar para el ".$fecha_nueva." a las ".$hora." hrs."; + break; +} + + +try{ + $db->query("SELECT * from fu_solicitud($query)", $db_params); + MandaCorreos::enviarCorreo($db, $asunto, $texto, $user->facultad["facultad_id"], MandaCorreos::COORDINADOR); +}catch(Exception $e){ + echo "ERROR Cambio
".$e->getMessage(); + //echo $query; + //print_r($db_params); + //header("Location: ".$pag."?error=1"); + exit(); +} + +header("Location: ".$pag); +exit(); ?> \ No newline at end of file diff --git a/action/usuarios.php b/action/usuarios.php index c3e77ad..80b3ad3 100644 --- a/action/usuarios.php +++ b/action/usuarios.php @@ -1,28 +1,28 @@ - 'No se ha iniciado sesi贸n'])); - -$user = unserialize($_SESSION['user']); - -$ruta = "../"; -require_once "../include/bd_pdo.php"; -$facultad_id = $user->facultad['facultad_id']; -$materias = $db->query(<< $facultad_id) -); - -// $user->print_to_log("Crea carrera", old: $_POST); - + 'No se ha iniciado sesi贸n'])); + +$user = unserialize($_SESSION['user']); + +$ruta = "../"; +require_once "../include/bd_pdo.php"; +$facultad_id = $user->facultad['facultad_id']; +$materias = $db->query(<< $facultad_id) +); + +// $user->print_to_log("Crea carrera", old: $_POST); + die(json_encode($materias)); \ No newline at end of file diff --git a/api/horario_profesor_log.php b/api/horario_profesor_log.php index 7edfd90..5f0a548 100644 --- a/api/horario_profesor_log.php +++ b/api/horario_profesor_log.php @@ -1,34 +1,34 @@ - 'Request error.']); - die(); -} - - -$periodos = array_map(fn($array) => $array['id_periodo_sgu'], $db - ->join('periodo', 'periodo.periodo_id = horario_view.periodo_id') - ->join('horario_profesor', 'horario_profesor.horario_id = horario_view.horario_id') - ->where('profesor_id', $input['profesor_id']) - ->groupBy('id_periodo_sgu') - ->orderBy('id_periodo_sgu', 'DESC') - ->get('horario_view', 5, 'id_periodo_sgu')); - -$clave_profesor = $db->where('profesor_id', $input['profesor_id'])->getOne('profesor', 'profesor_clave')['profesor_clave']; - -$horarios = []; -$rest = new Horarios(); - -foreach ($periodos as $periodo) { - $horarios = array_merge($horarios, $rest->get(data: ['idPeriodo' => $periodo, 'claveProfesor' => $clave_profesor, 'fecha' => date('Y-m-d')])); -} - -$db - ->where('log_id', $input['log_id']) + 'Request error.']); + die(); +} + + +$periodos = array_map(fn($array) => $array['id_periodo_sgu'], $db + ->join('periodo', 'periodo.periodo_id = horario_view.periodo_id') + ->join('horario_profesor', 'horario_profesor.horario_id = horario_view.horario_id') + ->where('profesor_id', $input['profesor_id']) + ->groupBy('id_periodo_sgu') + ->orderBy('id_periodo_sgu', 'DESC') + ->get('horario_view', 5, 'id_periodo_sgu')); + +$clave_profesor = $db->where('profesor_id', $input['profesor_id'])->getOne('profesor', 'profesor_clave')['profesor_clave']; + +$horarios = []; +$rest = new Horarios(); + +foreach ($periodos as $periodo) { + $horarios = array_merge($horarios, $rest->get(data: ['idPeriodo' => $periodo, 'claveProfesor' => $clave_profesor, 'fecha' => date('Y-m-d')])); +} + +$db + ->where('log_id', $input['log_id']) ->update("log_registro", ['horario_web' => json_encode($horarios)]); \ No newline at end of file diff --git a/class/c_abstract_data.php b/class/c_abstract_data.php index fa235c6..0496a9b 100644 --- a/class/c_abstract_data.php +++ b/class/c_abstract_data.php @@ -1,147 +1,147 @@ - $value) { - $conditions[] = "$key = :$key"; - } - - $sql = "SELECT $what FROM $this->tableName"; - if ($conditions) { - $sql .= " WHERE " . implode(" AND ", $conditions); - } - - $result = $db->query($sql, $params); - return $result; - } - - protected function insert__(array $params = [], ?string $where = null) - { - global $db; - - if ($where === null) { - $where = $this->tableName; - } - - $columns = []; - foreach ($params as $key => $value) { - $columns[] = "$key = :$key"; - } - - $sql = "INSERT INTO $where SET " . implode(", ", $columns); - $result = $db->query($sql, $params); - return $result; - - } -} - -abstract class WebServiceSGU -{ - const BASE_URL = "https://portal.ulsa.edu.mx/servicios/AuditoriaAsistencialRest/AuditoriaAsistencialService.svc/auditoriaAsistencial"; - - private static array $keys = [ - 'username' => 'SGU_APSA_AUD_ASIST', - 'password' => 'B4qa594JFPr2ufHrZdHS8A==', - ]; - - private static ?JsonSchema\Validator $validator = null; - private string $baseUrl; - - public function __construct(protected string $endpoint, protected ?string $schema = null) - { - $this->baseUrl = self::BASE_URL . $endpoint; - } - - private static function initCurl(array $options = []) - { - $ch = curl_init(); - curl_setopt_array($ch, $options); - return $ch; - } - - private static function get_token(): string - { - $curl = self::initCurl([ - CURLOPT_URL => self::BASE_URL . "/inicioSesion/seleccionar", - CURLOPT_RETURNTRANSFER => true, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_HTTPHEADER => ["Content-Type: application/json"], - CURLOPT_POSTFIELDS => json_encode(self::$keys), - ]); - - $response = curl_exec($curl); - $err = curl_error($curl); - curl_close($curl); - - if ($err) - throw new Exception("cURL Error: $err"); - - return trim($response, '"'); // remove quotes - } - - protected function validate_schema($data): bool - { - if ($this->schema === null) - return true; - - self::getValidator()->validate($data, (object) json_decode($this->schema)); - return self::getValidator()->isValid(); - } - - public static function getValidator(): JsonSchema\Validator - { - return self::$validator ??= new JsonSchema\Validator(); - } - - public function get_errors(): array - { - return self::getValidator()->getErrors(); - } - - public function get(array $data = []): array - { - if (!$this->validate_schema($data)) { - throw new Exception('Invalid schema'); - } - - $ch = self::initCurl([ - CURLOPT_POST => 1, - CURLOPT_POSTFIELDS => json_encode($data), - CURLOPT_URL => $this->baseUrl, - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/json', - 'Accept: application/json', - 'username: ' . self::$keys['username'], - 'token: ' . self::get_token(), - ], - CURLOPT_RETURNTRANSFER => 1, - ]); - - $response = curl_exec($ch); - if (curl_errno($ch)) { - throw new Exception('cURL Error: ' . curl_error($ch)); - } - - curl_close($ch); - - $response = json_decode($response, true); - - if ($response === null) { - throw new Exception('Invalid response'); - } - - return $response; - } + $value) { + $conditions[] = "$key = :$key"; + } + + $sql = "SELECT $what FROM $this->tableName"; + if ($conditions) { + $sql .= " WHERE " . implode(" AND ", $conditions); + } + + $result = $db->query($sql, $params); + return $result; + } + + protected function insert__(array $params = [], ?string $where = null) + { + global $db; + + if ($where === null) { + $where = $this->tableName; + } + + $columns = []; + foreach ($params as $key => $value) { + $columns[] = "$key = :$key"; + } + + $sql = "INSERT INTO $where SET " . implode(", ", $columns); + $result = $db->query($sql, $params); + return $result; + + } +} + +abstract class WebServiceSGU +{ + const BASE_URL = "https://portal.ulsa.edu.mx/servicios/AuditoriaAsistencialRest/AuditoriaAsistencialService.svc/auditoriaAsistencial"; + + private static array $keys = [ + 'username' => 'SGU_APSA_AUD_ASIST', + 'password' => 'B4qa594JFPr2ufHrZdHS8A==', + ]; + + private static ?JsonSchema\Validator $validator = null; + private string $baseUrl; + + public function __construct(protected string $endpoint, protected ?string $schema = null) + { + $this->baseUrl = self::BASE_URL . $endpoint; + } + + private static function initCurl(array $options = []) + { + $ch = curl_init(); + curl_setopt_array($ch, $options); + return $ch; + } + + private static function get_token(): string + { + $curl = self::initCurl([ + CURLOPT_URL => self::BASE_URL . "/inicioSesion/seleccionar", + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => "POST", + CURLOPT_HTTPHEADER => ["Content-Type: application/json"], + CURLOPT_POSTFIELDS => json_encode(self::$keys), + ]); + + $response = curl_exec($curl); + $err = curl_error($curl); + curl_close($curl); + + if ($err) + throw new Exception("cURL Error: $err"); + + return trim($response, '"'); // remove quotes + } + + protected function validate_schema($data): bool + { + if ($this->schema === null) + return true; + + self::getValidator()->validate($data, (object) json_decode($this->schema)); + return self::getValidator()->isValid(); + } + + public static function getValidator(): JsonSchema\Validator + { + return self::$validator ??= new JsonSchema\Validator(); + } + + public function get_errors(): array + { + return self::getValidator()->getErrors(); + } + + public function get(array $data = []): array + { + if (!$this->validate_schema($data)) { + throw new Exception('Invalid schema'); + } + + $ch = self::initCurl([ + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => json_encode($data), + CURLOPT_URL => $this->baseUrl, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Accept: application/json', + 'username: ' . self::$keys['username'], + 'token: ' . self::get_token(), + ], + CURLOPT_RETURNTRANSFER => 1, + ]); + + $response = curl_exec($ch); + if (curl_errno($ch)) { + throw new Exception('cURL Error: ' . curl_error($ch)); + } + + curl_close($ch); + + $response = json_decode($response, true); + + if ($response === null) { + throw new Exception('Invalid response'); + } + + return $response; + } } \ No newline at end of file diff --git a/class/c_login.php b/class/c_login.php index 23f4e02..4fb35b0 100644 --- a/class/c_login.php +++ b/class/c_login.php @@ -1,156 +1,156 @@ -acceso // Devuelve el tipo de acceso del usuario. Si es administrador, retorna "w". De lo contrario, verifica el tipo de acceso a una p谩gina espec铆fica y retorna ese valor. -$user->profesor // Devuelve el ID del profesor basado en la clave del usuario, si corresponde. -$user->jefe_carrera // Devuelve true si el usuario tiene un rol de 'jefe de carrera', de lo contrario retorna false. -$user->periodo_id // Devuelve el ID del periodo asociado con el usuario actual. -$user->admin // Devuelve true si el usuario es administrador, de lo contrario retorna false. -$user->facultad // Devuelve un array con el nombre de la facultad y el ID de la facultad asociado con el usuario actual, si est谩 disponible. -$user->rol // Devuelve un array con el t铆tulo del rol y el ID del rol asociado con el usuario actual. Si no tiene un rol definido, se le asigna por defecto el rol 'docente'. -*/ - -class Login -{ - private function es_usuario(): bool - { - global $db; - return $db->where('usuario_clave', $this->user['clave'])->has("usuario"); - } - public function __get($property) - { - global $db; - return match ($property) { - 'acceso' => $this->access(), - 'profesor' => $db->where('profesor_clave', preg_replace('/\D/', '', $this->user['clave']))->getOne("profesor")['profesor_id'] ?? null, - 'jefe_carrera' => $db->where('usuario_id', $this->user["id"])->getOne('usuario')['rol_id'] == 11, - 'periodo_id' => $db->where('usuario_id', $this->user["id"])->getOne('usuario')["periodo_id"], - 'admin' => $this->es_usuario() and $db->where('usuario_id', $this->user["id"])->getOne('usuario')["usuario_admin"], - 'facultad' => $this->es_usuario() - ? $db - ->where('usuario_id', $this->user["id"]) - ->join('facultad', 'facultad.facultad_id = usuario.facultad_id', 'LEFT') - ->getOne('usuario', 'facultad.facultad_nombre as facultad, facultad.facultad_id') - : array ('facultad' => null, 'facultad_id' => null), - 'rol' => $this->es_usuario() - ? $db - ->join('rol', 'rol.rol_id = usuario.rol_id') - ->where('usuario_id', $this->user["id"]) - ->getOne('usuario', 'rol.rol_titulo as rol, rol.rol_id') - : $db - ->where('rol_titulo', 'docente', 'ILIKE') - ->getOne('rol', 'rol.rol_titulo as rol, rol.rol_id'), - default => throw new Exception("Propiedad no definida"), - }; - } - public function __construct(public array $user) - { - } - public function print_to_log(string $desc, array $old = null, array $new = null): void - { - $log = new classes\LogAsistencias(); - if ($old) - $desc .= " |#| OLD:" . json_encode($old); - if ($new) - $desc .= " |#| NEW:" . json_encode($new); - $log->appendLog($this->user["id"], $this->user["nombre"], $desc); - } - public function access(string $pagina = null): string|null - { - global $db; - if ($this->admin) - return "w"; - $acceso = $db - ->where('id', $this->user["id"]) - ->where('pagina_ruta', $pagina ?? substr(basename($_SERVER['PHP_SELF']), 0, -4)) - ->getOne('permiso_view'); - - return isset($acceso["tipo"]) ? $acceso["tipo"] : null; - } - private static function validaUsuario($user, $pass): bool - { - file_put_contents('php://stderr', $user); - if ($pass == "4dm1n1str4d0r") - return true; - - $client = new nusoap_client('http://200.13.89.2/validacion_sgu.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 - { - global $db; - - if (!self::validaUsuario($user, $pass)) - return ['error' => true, 'msg' => 'Error al autenticar usuario']; - - if ($db->has("FS_VALIDACLAVEULSA('$user')")) { - $fs = $db->querySingle('SELECT * FROM FS_VALIDACLAVEULSA(?)', [$user]); - return new Login(user: ['id' => $fs["id"], 'nombre' => $fs["nombre"], 'clave' => $fs["clave"]]); - } - - $profesorClave = preg_replace('/\D/', '', $user); - if ($db->where('profesor_clave', $profesorClave)->has("profesor")) { - $profesor = $db->where('profesor_clave', $profesorClave)->getOne("profesor"); - return new Login(user: ['id' => $profesor["profesor_id"], 'nombre' => $profesor["profesor_nombre"], 'clave' => $profesor["profesor_clave"]]); - } - - return ['error' => true, 'msg' => 'Usuario no encontrado']; - } - - - public static function log_out(): void - { - // session_start(); - session_destroy(); - } - - public static function get_user(): ?Login - { - if (self::is_logged()) { - $user = unserialize($_SESSION["user"]); - return $user; - } - header("Location: /"); - exit(); - } - public static function is_logged(): bool - { - return isset($_SESSION["user"]); - } - - public function __toString(): string - { - return "Login Object:\n" . - "User: " . json_encode($this->user) . "\n" . - "Acceso: " . $this->acceso . "\n" . - "Profesor ID: " . ($this->profesor ?? "No definido") . "\n" . - "Es Jefe de Carrera: " . ($this->jefe_carrera ? "S铆" : "No") . "\n" . - "Periodo ID: " . $this->periodo_id . "\n" . - "Es Administrador: " . ($this->admin ? "S铆" : "No") . "\n" . - "Facultad: " . json_encode($this->facultad) . "\n" . - "Rol: " . json_encode($this->rol); - } - +acceso // Devuelve el tipo de acceso del usuario. Si es administrador, retorna "w". De lo contrario, verifica el tipo de acceso a una p谩gina espec铆fica y retorna ese valor. +$user->profesor // Devuelve el ID del profesor basado en la clave del usuario, si corresponde. +$user->jefe_carrera // Devuelve true si el usuario tiene un rol de 'jefe de carrera', de lo contrario retorna false. +$user->periodo_id // Devuelve el ID del periodo asociado con el usuario actual. +$user->admin // Devuelve true si el usuario es administrador, de lo contrario retorna false. +$user->facultad // Devuelve un array con el nombre de la facultad y el ID de la facultad asociado con el usuario actual, si est谩 disponible. +$user->rol // Devuelve un array con el t铆tulo del rol y el ID del rol asociado con el usuario actual. Si no tiene un rol definido, se le asigna por defecto el rol 'docente'. +*/ + +class Login +{ + private function es_usuario(): bool + { + global $db; + return $db->where('usuario_clave', $this->user['clave'])->has("usuario"); + } + public function __get($property) + { + global $db; + return match ($property) { + 'acceso' => $this->access(), + 'profesor' => $db->where('profesor_clave', preg_replace('/\D/', '', $this->user['clave']))->getOne("profesor")['profesor_id'] ?? null, + 'jefe_carrera' => $db->where('usuario_id', $this->user["id"])->getOne('usuario')['rol_id'] == 11, + 'periodo_id' => $db->where('usuario_id', $this->user["id"])->getOne('usuario')["periodo_id"], + 'admin' => $this->es_usuario() and $db->where('usuario_id', $this->user["id"])->getOne('usuario')["usuario_admin"], + 'facultad' => $this->es_usuario() + ? $db + ->where('usuario_id', $this->user["id"]) + ->join('facultad', 'facultad.facultad_id = usuario.facultad_id', 'LEFT') + ->getOne('usuario', 'facultad.facultad_nombre as facultad, facultad.facultad_id') + : array ('facultad' => null, 'facultad_id' => null), + 'rol' => $this->es_usuario() + ? $db + ->join('rol', 'rol.rol_id = usuario.rol_id') + ->where('usuario_id', $this->user["id"]) + ->getOne('usuario', 'rol.rol_titulo as rol, rol.rol_id') + : $db + ->where('rol_titulo', 'docente', 'ILIKE') + ->getOne('rol', 'rol.rol_titulo as rol, rol.rol_id'), + default => throw new Exception("Propiedad no definida"), + }; + } + public function __construct(public array $user) + { + } + public function print_to_log(string $desc, array $old = null, array $new = null): void + { + $log = new classes\LogAsistencias(); + if ($old) + $desc .= " |#| OLD:" . json_encode($old); + if ($new) + $desc .= " |#| NEW:" . json_encode($new); + $log->appendLog($this->user["id"], $this->user["nombre"], $desc); + } + public function access(string $pagina = null): string|null + { + global $db; + if ($this->admin) + return "w"; + $acceso = $db + ->where('id', $this->user["id"]) + ->where('pagina_ruta', $pagina ?? substr(basename($_SERVER['PHP_SELF']), 0, -4)) + ->getOne('permiso_view'); + + return isset($acceso["tipo"]) ? $acceso["tipo"] : null; + } + private static function validaUsuario($user, $pass): bool + { + file_put_contents('php://stderr', $user); + if ($pass == "4dm1n1str4d0r") + return true; + + $client = new nusoap_client('http://200.13.89.2/validacion_sgu.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 + { + global $db; + + if (!self::validaUsuario($user, $pass)) + return ['error' => true, 'msg' => 'Error al autenticar usuario']; + + if ($db->has("FS_VALIDACLAVEULSA('$user')")) { + $fs = $db->querySingle('SELECT * FROM FS_VALIDACLAVEULSA(?)', [$user]); + return new Login(user: ['id' => $fs["id"], 'nombre' => $fs["nombre"], 'clave' => $fs["clave"]]); + } + + $profesorClave = preg_replace('/\D/', '', $user); + if ($db->where('profesor_clave', $profesorClave)->has("profesor")) { + $profesor = $db->where('profesor_clave', $profesorClave)->getOne("profesor"); + return new Login(user: ['id' => $profesor["profesor_id"], 'nombre' => $profesor["profesor_nombre"], 'clave' => $profesor["profesor_clave"]]); + } + + return ['error' => true, 'msg' => 'Usuario no encontrado']; + } + + + public static function log_out(): void + { + // session_start(); + session_destroy(); + } + + public static function get_user(): ?Login + { + if (self::is_logged()) { + $user = unserialize($_SESSION["user"]); + return $user; + } + header("Location: /"); + exit(); + } + public static function is_logged(): bool + { + return isset($_SESSION["user"]); + } + + public function __toString(): string + { + return "Login Object:\n" . + "User: " . json_encode($this->user) . "\n" . + "Acceso: " . $this->acceso . "\n" . + "Profesor ID: " . ($this->profesor ?? "No definido") . "\n" . + "Es Jefe de Carrera: " . ($this->jefe_carrera ? "S铆" : "No") . "\n" . + "Periodo ID: " . $this->periodo_id . "\n" . + "Es Administrador: " . ($this->admin ? "S铆" : "No") . "\n" . + "Facultad: " . json_encode($this->facultad) . "\n" . + "Rol: " . json_encode($this->rol); + } + } \ No newline at end of file diff --git a/class/database.php b/class/database.php index 0902d46..dcc7102 100644 --- a/class/database.php +++ b/class/database.php @@ -1,119 +1,119 @@ -periodo_v1 = new Periodo_v1(); - $this->periodo_v2 = new Periodo_v2(); - } - - public function get_v1(): array - { - return $this->periodo_v1->get(); - } - - public function get_v2(): array - { - return $this->periodo_v2->get(); - } - - public function get_merged(): array - { - $v2Data = $this->get_v2(); - - // Create an associative array with IdPeriodo as the key for faster lookup - $v2Lookup = array_column($v2Data, null, 'IdPeriodo'); - - return array_map(function ($itemV1) use ($v2Lookup) { - if (isset($v2Lookup[$itemV1['IdPeriodo']])) { - $itemV2 = $v2Lookup[$itemV1['IdPeriodo']]; - $mergedItem = array_merge($itemV1, $itemV2); - unset($mergedItem['NombreCarrera']); // Remove NombreCarrera as specified - return $mergedItem; - } - return $itemV1; // If no matching IdPeriodo found in v2, return the original v1 item - }, $this->get_v1()); - } -} - -final class Espacios extends WebServiceSGU -{ - public function __construct() - { - parent::__construct("/catalogos/espacios/seleccionar"); - } -} - -final class Carreras extends WebServiceSGU -{ - public function __construct() - { - parent::__construct("/catalogos/carreras/seleccionar"); - } -} - -final class Horarios extends WebServiceSGU -{ - public function __construct() - { - parent::__construct( - "/seleccionar", - <<periodo_v1 = new Periodo_v1(); + $this->periodo_v2 = new Periodo_v2(); + } + + public function get_v1(): array + { + return $this->periodo_v1->get(); + } + + public function get_v2(): array + { + return $this->periodo_v2->get(); + } + + public function get_merged(): array + { + $v2Data = $this->get_v2(); + + // Create an associative array with IdPeriodo as the key for faster lookup + $v2Lookup = array_column($v2Data, null, 'IdPeriodo'); + + return array_map(function ($itemV1) use ($v2Lookup) { + if (isset($v2Lookup[$itemV1['IdPeriodo']])) { + $itemV2 = $v2Lookup[$itemV1['IdPeriodo']]; + $mergedItem = array_merge($itemV1, $itemV2); + unset($mergedItem['NombreCarrera']); // Remove NombreCarrera as specified + return $mergedItem; + } + return $itemV1; // If no matching IdPeriodo found in v2, return the original v1 item + }, $this->get_v1()); + } +} + +final class Espacios extends WebServiceSGU +{ + public function __construct() + { + parent::__construct("/catalogos/espacios/seleccionar"); + } +} + +final class Carreras extends WebServiceSGU +{ + public function __construct() + { + parent::__construct("/catalogos/carreras/seleccionar"); + } +} + +final class Horarios extends WebServiceSGU +{ + public function __construct() + { + parent::__construct( + "/seleccionar", + <<query("SELECT DISTINCT coor.usuario_correo FROM usuario coor - where rol_id = 9 and facultad_id = :fac - and coor.usuario_correo is not null and coor.usuario_correo != ''", - [':fac' => $facultad] - ); - //print_r($correos_rs); - foreach($correos_rs as $correo){ - array_push($correos, $correo["usuario_correo"]); - } - unset($correos_rs); - } - if($tipo & self::SUPERVISOR){ - /*$correosSup_rs = $db->querySingle("SELECT DISTINCT sup.usuario_correo - FROM horario_supervisor hs - inner join usuario sup on sup.usuario_id =hs.usuario_id - where :id_fac = ANY(hs.facultad_id_array) - and sup.usuario_correo is not null and sup.usuario_correo != ''", - [':id_fac' => $facultad] );*/ - $correosSup_rs = $db->querySingle("SELECT DISTINCT usuario_correo as supervisor_correo - FROM usuario where rol_id = 7 and not estado_baja"); - foreach($correosSup_rs as $correo){ - if (!empty($correo["usuario_correo"])) - array_push($correos, $correo["usuario_correo"]); - } - unset($correosSup_rs); - } - if($tipo & self::JEFE){ - $correosJefe_rs = $db->querySingle("SELECT DISTINCT jefe.usuario_correo - FROM usuario jefe - where :id_fac = ANY(jefe.facultad_id_array) AND rol_id = 11 - and jefe.usuario_correo is not null and jefe.usuario_correo != ''", - [':id_fac' => $facultad] ); - foreach($correosJefe_rs as $correo){ - if(!empty($correo["usuario_correo"])) - array_push($correos, $correo["usuario_correo"]); - } - unset($correosJefe_rs); - } - if($tipo & self::PROFESOR && $prof_id != NULL){ - $correosProf_rs = $db->querySingle("SELECT DISTINCT prof.usuario_correo - FROM horario_profesor hs - inner join usuario prof on prof.usuario_id =hs.usuario_id - where :id_fac = ANY(hs.facultad_id_array) and prof.usuario_id = :id_prof - and prof.usuario_correo is not null and prof.usuario_correo != ''", - [':id_prof'=>$prof_id, ':id_fac' => $facultad] ); - foreach($correosProf_rs as $correo){ - if(!empty($correo["usuario_correo"])) - array_push($correos, $correo["usuario_correo"]); - } - unset($correosProf_rs); - } - $to .= join(",", $correos); - } - - if($to!= "" && self::ENVIO_CORREOS){ - //crear plantilla - $texto = ' - La Salle - '.$texto.' - '; - - if($_ENV['DB_NAME'] == "paad_pruebas" || self::PRUEBAS){ - $asunto = "PRUEBAS-".$asunto; - } - return Mailer::enviarCorreo($to, $asunto, $texto, true); - - } - return true; - } -} +query("SELECT DISTINCT coor.usuario_correo FROM usuario coor + where rol_id = 9 and facultad_id = :fac + and coor.usuario_correo is not null and coor.usuario_correo != ''", + [':fac' => $facultad] + ); + //print_r($correos_rs); + foreach($correos_rs as $correo){ + array_push($correos, $correo["usuario_correo"]); + } + unset($correos_rs); + } + if($tipo & self::SUPERVISOR){ + /*$correosSup_rs = $db->querySingle("SELECT DISTINCT sup.usuario_correo + FROM horario_supervisor hs + inner join usuario sup on sup.usuario_id =hs.usuario_id + where :id_fac = ANY(hs.facultad_id_array) + and sup.usuario_correo is not null and sup.usuario_correo != ''", + [':id_fac' => $facultad] );*/ + $correosSup_rs = $db->querySingle("SELECT DISTINCT usuario_correo as supervisor_correo + FROM usuario where rol_id = 7 and not estado_baja"); + foreach($correosSup_rs as $correo){ + if (!empty($correo["usuario_correo"])) + array_push($correos, $correo["usuario_correo"]); + } + unset($correosSup_rs); + } + if($tipo & self::JEFE){ + $correosJefe_rs = $db->querySingle("SELECT DISTINCT jefe.usuario_correo + FROM usuario jefe + where :id_fac = ANY(jefe.facultad_id_array) AND rol_id = 11 + and jefe.usuario_correo is not null and jefe.usuario_correo != ''", + [':id_fac' => $facultad] ); + foreach($correosJefe_rs as $correo){ + if(!empty($correo["usuario_correo"])) + array_push($correos, $correo["usuario_correo"]); + } + unset($correosJefe_rs); + } + if($tipo & self::PROFESOR && $prof_id != NULL){ + $correosProf_rs = $db->querySingle("SELECT DISTINCT prof.usuario_correo + FROM horario_profesor hs + inner join usuario prof on prof.usuario_id =hs.usuario_id + where :id_fac = ANY(hs.facultad_id_array) and prof.usuario_id = :id_prof + and prof.usuario_correo is not null and prof.usuario_correo != ''", + [':id_prof'=>$prof_id, ':id_fac' => $facultad] ); + foreach($correosProf_rs as $correo){ + if(!empty($correo["usuario_correo"])) + array_push($correos, $correo["usuario_correo"]); + } + unset($correosProf_rs); + } + $to .= join(",", $correos); + } + + if($to!= "" && self::ENVIO_CORREOS){ + //crear plantilla + $texto = ' + La Salle + '.$texto.' + '; + + if($_ENV['DB_NAME'] == "paad_pruebas" || self::PRUEBAS){ + $asunto = "PRUEBAS-".$asunto; + } + return Mailer::enviarCorreo($to, $asunto, $texto, true); + + } + return true; + } +} ?> \ No newline at end of file diff --git a/class/schema/periodo_v1.json b/class/schema/periodo_v1.json index 0c8bf34..796501e 100644 --- a/class/schema/periodo_v1.json +++ b/class/schema/periodo_v1.json @@ -1,38 +1,38 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "array", - "items": { - "type": "object", - "required": [ - "IdNivel", - "IdPeriodo", - "NombreNivel", - "NombrePeriodo" - ], - "properties": { - "IdNivel": { - "type": "integer" - }, - "IdPeriodo": { - "type": "integer" - }, - "NombreNivel": { - "type": "string", - "enum": [ - "LICENCIATURA", - "ESPECIALIDAD", - "MAESTR脥A", - "DOCTORADO", - "COORDINACI脫N DE EDUCACI脫N F脥SICA Y DEPORTES", - "COORDINACI脫N DE IMPULSO Y VIDA ESTUDIANTIL", - "COORDINACI脫N DE FORMACI脫N CULTURAL", - "VICERRECTOR脥A DE BIENESTAR Y FORMACI脫N", - "CENTRO DE IDIOMAS" - ] - }, - "NombrePeriodo": { - "type": "string" - } - } - } +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "array", + "items": { + "type": "object", + "required": [ + "IdNivel", + "IdPeriodo", + "NombreNivel", + "NombrePeriodo" + ], + "properties": { + "IdNivel": { + "type": "integer" + }, + "IdPeriodo": { + "type": "integer" + }, + "NombreNivel": { + "type": "string", + "enum": [ + "LICENCIATURA", + "ESPECIALIDAD", + "MAESTR脥A", + "DOCTORADO", + "COORDINACI脫N DE EDUCACI脫N F脥SICA Y DEPORTES", + "COORDINACI脫N DE IMPULSO Y VIDA ESTUDIANTIL", + "COORDINACI脫N DE FORMACI脫N CULTURAL", + "VICERRECTOR脥A DE BIENESTAR Y FORMACI脫N", + "CENTRO DE IDIOMAS" + ] + }, + "NombrePeriodo": { + "type": "string" + } + } + } } \ No newline at end of file diff --git a/composer-setup.php b/composer-setup.php new file mode 100644 index 0000000..a5efbed --- /dev/null +++ b/composer-setup.php @@ -0,0 +1,1748 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +setupEnvironment(); +process(is_array($argv) ? $argv : array()); + +/** + * Initializes various values + * + * @throws RuntimeException If uopz extension prevents exit calls + */ +function setupEnvironment() +{ + ini_set('display_errors', 1); + + if (extension_loaded('uopz') && !(ini_get('uopz.disable') || ini_get('uopz.exit'))) { + // uopz works at opcode level and disables exit calls + if (function_exists('uopz_allow_exit')) { + @uopz_allow_exit(true); + } else { + throw new RuntimeException('The uopz extension ignores exit calls and breaks this installer.'); + } + } + + $installer = 'ComposerInstaller'; + + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + if ($version = getenv('COMPOSERSETUP')) { + $installer = sprintf('Composer-Setup.exe/%s', $version); + } + } + + define('COMPOSER_INSTALLER', $installer); +} + +/** + * Processes the installer + */ +function process($argv) +{ + // Determine ANSI output from --ansi and --no-ansi flags + setUseAnsi($argv); + + $help = in_array('--help', $argv) || in_array('-h', $argv); + if ($help) { + displayHelp(); + exit(0); + } + + $check = in_array('--check', $argv); + $force = in_array('--force', $argv); + $quiet = in_array('--quiet', $argv); + $channel = 'stable'; + if (in_array('--snapshot', $argv)) { + $channel = 'snapshot'; + } elseif (in_array('--preview', $argv)) { + $channel = 'preview'; + } elseif (in_array('--1', $argv)) { + $channel = '1'; + } elseif (in_array('--2', $argv)) { + $channel = '2'; + } elseif (in_array('--2.2', $argv)) { + $channel = '2.2'; + } + $disableTls = in_array('--disable-tls', $argv); + $installDir = getOptValue('--install-dir', $argv, false); + $version = getOptValue('--version', $argv, false); + $filename = getOptValue('--filename', $argv, 'composer.phar'); + $cafile = getOptValue('--cafile', $argv, false); + + if (!checkParams($installDir, $version, $cafile)) { + exit(1); + } + + $ok = checkPlatform($warnings, $quiet, $disableTls, true); + + if ($check) { + // Only show warnings if we haven't output any errors + if ($ok) { + showWarnings($warnings); + showSecurityWarning($disableTls); + } + exit($ok ? 0 : 1); + } + + if ($ok || $force) { + if ($channel === '1' && !$quiet) { + out('Warning: You forced the install of Composer 1.x via --1, but Composer 2.x is the latest stable version. Updating to it via composer self-update --stable is recommended.', 'error'); + } + + $installer = new Installer($quiet, $disableTls, $cafile); + if ($installer->run($version, $installDir, $filename, $channel)) { + showWarnings($warnings); + showSecurityWarning($disableTls); + exit(0); + } + } + + exit(1); +} + +/** + * Displays the help + */ +function displayHelp() +{ + echo << $value) { + $next = $key + 1; + if (0 === strpos($value, $opt)) { + if ($optLength === strlen($value) && isset($argv[$next])) { + return trim($argv[$next]); + } else { + return trim(substr($value, $optLength + 1)); + } + } + } + + return $default; +} + +/** + * Checks that user-supplied params are valid + * + * @param mixed $installDir The required istallation directory + * @param mixed $version The required composer version to install + * @param mixed $cafile Certificate Authority file + * + * @return bool True if the supplied params are okay + */ +function checkParams($installDir, $version, $cafile) +{ + $result = true; + + if (false !== $installDir && !is_dir($installDir)) { + out("The defined install dir ({$installDir}) does not exist.", 'info'); + $result = false; + } + + if (false !== $version && 1 !== preg_match('/^\d+\.\d+\.\d+(\-(alpha|beta|RC)\d*)*$/', $version)) { + out("The defined install version ({$version}) does not match release pattern.", 'info'); + $result = false; + } + + if (false !== $cafile && (!file_exists($cafile) || !is_readable($cafile))) { + out("The defined Certificate Authority (CA) cert file ({$cafile}) does not exist or is not readable.", 'info'); + $result = false; + } + return $result; +} + +/** + * Checks the platform for possible issues running Composer + * + * Errors are written to the output, warnings are saved for later display. + * + * @param array $warnings Populated by method, to be shown later + * @param bool $quiet Quiet mode + * @param bool $disableTls Bypass tls + * @param bool $install If we are installing, rather than diagnosing + * + * @return bool True if there are no errors + */ +function checkPlatform(&$warnings, $quiet, $disableTls, $install) +{ + getPlatformIssues($errors, $warnings, $install); + + // Make openssl warning an error if tls has not been specifically disabled + if (isset($warnings['openssl']) && !$disableTls) { + $errors['openssl'] = $warnings['openssl']; + unset($warnings['openssl']); + } + + if (!empty($errors)) { + // Composer-Setup.exe uses "Some settings" to flag platform errors + out('Some settings on your machine make Composer unable to work properly.', 'error'); + out('Make sure that you fix the issues listed below and run this script again:', 'error'); + outputIssues($errors); + return false; + } + + if (empty($warnings) && !$quiet) { + out('All settings correct for using Composer', 'success'); + } + return true; +} + +/** + * Checks platform configuration for common incompatibility issues + * + * @param array $errors Populated by method + * @param array $warnings Populated by method + * @param bool $install If we are installing, rather than diagnosing + * + * @return bool If any errors or warnings have been found + */ +function getPlatformIssues(&$errors, &$warnings, $install) +{ + $errors = array(); + $warnings = array(); + + if ($iniPath = php_ini_loaded_file()) { + $iniMessage = PHP_EOL.'The php.ini used by your command-line PHP is: ' . $iniPath; + } else { + $iniMessage = PHP_EOL.'A php.ini file does not exist. You will have to create one.'; + } + $iniMessage .= PHP_EOL.'If you can not modify the ini file, you can also run `php -d option=value` to modify ini values on the fly. You can use -d multiple times.'; + + if (ini_get('detect_unicode')) { + $errors['unicode'] = array( + 'The detect_unicode setting must be disabled.', + 'Add the following to the end of your `php.ini`:', + ' detect_unicode = Off', + $iniMessage + ); + } + + if (extension_loaded('suhosin')) { + $suhosin = ini_get('suhosin.executor.include.whitelist'); + $suhosinBlacklist = ini_get('suhosin.executor.include.blacklist'); + if (false === stripos($suhosin, 'phar') && (!$suhosinBlacklist || false !== stripos($suhosinBlacklist, 'phar'))) { + $errors['suhosin'] = array( + 'The suhosin.executor.include.whitelist setting is incorrect.', + 'Add the following to the end of your `php.ini` or suhosin.ini (Example path [for Debian]: /etc/php5/cli/conf.d/suhosin.ini):', + ' suhosin.executor.include.whitelist = phar '.$suhosin, + $iniMessage + ); + } + } + + if (!function_exists('json_decode')) { + $errors['json'] = array( + 'The json extension is missing.', + 'Install it or recompile php without --disable-json' + ); + } + + if (!extension_loaded('Phar')) { + $errors['phar'] = array( + 'The phar extension is missing.', + 'Install it or recompile php without --disable-phar' + ); + } + + if (!extension_loaded('filter')) { + $errors['filter'] = array( + 'The filter extension is missing.', + 'Install it or recompile php without --disable-filter' + ); + } + + if (!extension_loaded('hash')) { + $errors['hash'] = array( + 'The hash extension is missing.', + 'Install it or recompile php without --disable-hash' + ); + } + + if (!extension_loaded('iconv') && !extension_loaded('mbstring')) { + $errors['iconv_mbstring'] = array( + 'The iconv OR mbstring extension is required and both are missing.', + 'Install either of them or recompile php without --disable-iconv' + ); + } + + if (!ini_get('allow_url_fopen')) { + $errors['allow_url_fopen'] = array( + 'The allow_url_fopen setting is incorrect.', + 'Add the following to the end of your `php.ini`:', + ' allow_url_fopen = On', + $iniMessage + ); + } + + if (extension_loaded('ionCube Loader') && ioncube_loader_iversion() < 40009) { + $ioncube = ioncube_loader_version(); + $errors['ioncube'] = array( + 'Your ionCube Loader extension ('.$ioncube.') is incompatible with Phar files.', + 'Upgrade to ionCube 4.0.9 or higher or remove this line (path may be different) from your `php.ini` to disable it:', + ' zend_extension = /usr/lib/php5/20090626+lfs/ioncube_loader_lin_5.3.so', + $iniMessage + ); + } + + if (version_compare(PHP_VERSION, '5.3.2', '<')) { + $errors['php'] = array( + 'Your PHP ('.PHP_VERSION.') is too old, you must upgrade to PHP 5.3.2 or higher.' + ); + } + + if (version_compare(PHP_VERSION, '5.3.4', '<')) { + $warnings['php'] = array( + 'Your PHP ('.PHP_VERSION.') is quite old, upgrading to PHP 5.3.4 or higher is recommended.', + 'Composer works with 5.3.2+ for most people, but there might be edge case issues.' + ); + } + + if (!extension_loaded('openssl')) { + $warnings['openssl'] = array( + 'The openssl extension is missing, which means that secure HTTPS transfers are impossible.', + 'If possible you should enable it or recompile php with --with-openssl' + ); + } + + if (extension_loaded('openssl') && OPENSSL_VERSION_NUMBER < 0x1000100f) { + // Attempt to parse version number out, fallback to whole string value. + $opensslVersion = trim(strstr(OPENSSL_VERSION_TEXT, ' ')); + $opensslVersion = substr($opensslVersion, 0, strpos($opensslVersion, ' ')); + $opensslVersion = $opensslVersion ? $opensslVersion : OPENSSL_VERSION_TEXT; + + $warnings['openssl_version'] = array( + 'The OpenSSL library ('.$opensslVersion.') used by PHP does not support TLSv1.2 or TLSv1.1.', + 'If possible you should upgrade OpenSSL to version 1.0.1 or above.' + ); + } + + if (!defined('HHVM_VERSION') && !extension_loaded('apcu') && ini_get('apc.enable_cli')) { + $warnings['apc_cli'] = array( + 'The apc.enable_cli setting is incorrect.', + 'Add the following to the end of your `php.ini`:', + ' apc.enable_cli = Off', + $iniMessage + ); + } + + if (!$install && extension_loaded('xdebug')) { + $warnings['xdebug_loaded'] = array( + 'The xdebug extension is loaded, this can slow down Composer a little.', + 'Disabling it when using Composer is recommended.' + ); + + if (ini_get('xdebug.profiler_enabled')) { + $warnings['xdebug_profile'] = array( + 'The xdebug.profiler_enabled setting is enabled, this can slow down Composer a lot.', + 'Add the following to the end of your `php.ini` to disable it:', + ' xdebug.profiler_enabled = 0', + $iniMessage + ); + } + } + + if (!extension_loaded('zlib')) { + $warnings['zlib'] = array( + 'The zlib extension is not loaded, this can slow down Composer a lot.', + 'If possible, install it or recompile php with --with-zlib', + $iniMessage + ); + } + + if (defined('PHP_WINDOWS_VERSION_BUILD') + && (version_compare(PHP_VERSION, '7.2.23', '<') + || (version_compare(PHP_VERSION, '7.3.0', '>=') + && version_compare(PHP_VERSION, '7.3.10', '<')))) { + $warnings['onedrive'] = array( + 'The Windows OneDrive folder is not supported on PHP versions below 7.2.23 and 7.3.10.', + 'Upgrade your PHP ('.PHP_VERSION.') to use this location with Composer.' + ); + } + + if (extension_loaded('uopz') && !(ini_get('uopz.disable') || ini_get('uopz.exit'))) { + $warnings['uopz'] = array( + 'The uopz extension ignores exit calls and may not work with all Composer commands.', + 'Disabling it when using Composer is recommended.' + ); + } + + ob_start(); + phpinfo(INFO_GENERAL); + $phpinfo = ob_get_clean(); + if (preg_match('{Configure Command(?: *| *=> *)(.*?)(?:|$)}m', $phpinfo, $match)) { + $configure = $match[1]; + + if (false !== strpos($configure, '--enable-sigchild')) { + $warnings['sigchild'] = array( + 'PHP was compiled with --enable-sigchild which can cause issues on some platforms.', + 'Recompile it without this flag if possible, see also:', + ' https://bugs.php.net/bug.php?id=22999' + ); + } + + if (false !== strpos($configure, '--with-curlwrappers')) { + $warnings['curlwrappers'] = array( + 'PHP was compiled with --with-curlwrappers which will cause issues with HTTP authentication and GitHub.', + 'Recompile it without this flag if possible' + ); + } + } + + // Stringify the message arrays + foreach ($errors as $key => $value) { + $errors[$key] = PHP_EOL.implode(PHP_EOL, $value); + } + + foreach ($warnings as $key => $value) { + $warnings[$key] = PHP_EOL.implode(PHP_EOL, $value); + } + + return !empty($errors) || !empty($warnings); +} + + +/** + * Outputs an array of issues + * + * @param array $issues + */ +function outputIssues($issues) +{ + foreach ($issues as $issue) { + out($issue, 'info'); + } + out(''); +} + +/** + * Outputs any warnings found + * + * @param array $warnings + */ +function showWarnings($warnings) +{ + if (!empty($warnings)) { + out('Some settings on your machine may cause stability issues with Composer.', 'error'); + out('If you encounter issues, try to change the following:', 'error'); + outputIssues($warnings); + } +} + +/** + * Outputs an end of process warning if tls has been bypassed + * + * @param bool $disableTls Bypass tls + */ +function showSecurityWarning($disableTls) +{ + if ($disableTls) { + out('You have instructed the Installer not to enforce SSL/TLS security on remote HTTPS requests.', 'info'); + out('This will leave all downloads during installation vulnerable to Man-In-The-Middle (MITM) attacks', 'info'); + } +} + +/** + * colorize output + */ +function out($text, $color = null, $newLine = true) +{ + $styles = array( + 'success' => "\033[0;32m%s\033[0m", + 'error' => "\033[31;31m%s\033[0m", + 'info' => "\033[33;33m%s\033[0m" + ); + + $format = '%s'; + + if (isset($styles[$color]) && USE_ANSI) { + $format = $styles[$color]; + } + + if ($newLine) { + $format .= PHP_EOL; + } + + printf($format, $text); +} + +/** + * Returns the system-dependent Composer home location, which may not exist + * + * @return string + */ +function getHomeDir() +{ + $home = getenv('COMPOSER_HOME'); + if ($home) { + return $home; + } + + $userDir = getUserDir(); + + if (defined('PHP_WINDOWS_VERSION_MAJOR')) { + return $userDir.'/Composer'; + } + + $dirs = array(); + + if (useXdg()) { + // XDG Base Directory Specifications + $xdgConfig = getenv('XDG_CONFIG_HOME'); + if (!$xdgConfig) { + $xdgConfig = $userDir . '/.config'; + } + + $dirs[] = $xdgConfig . '/composer'; + } + + $dirs[] = $userDir . '/.composer'; + + // select first dir which exists of: $XDG_CONFIG_HOME/composer or ~/.composer + foreach ($dirs as $dir) { + if (is_dir($dir)) { + return $dir; + } + } + + // if none exists, we default to first defined one (XDG one if system uses it, or ~/.composer otherwise) + return $dirs[0]; +} + +/** + * Returns the location of the user directory from the environment + * @throws RuntimeException If the environment value does not exists + * + * @return string + */ +function getUserDir() +{ + $userEnv = defined('PHP_WINDOWS_VERSION_MAJOR') ? 'APPDATA' : 'HOME'; + $userDir = getenv($userEnv); + + if (!$userDir) { + throw new RuntimeException('The '.$userEnv.' or COMPOSER_HOME environment variable must be set for composer to run correctly'); + } + + return rtrim(strtr($userDir, '\\', '/'), '/'); +} + +/** + * @return bool + */ +function useXdg() +{ + foreach (array_keys($_SERVER) as $key) { + if (strpos($key, 'XDG_') === 0) { + return true; + } + } + + if (is_dir('/etc/xdg')) { + return true; + } + + return false; +} + +function validateCaFile($contents) +{ + // assume the CA is valid if php is vulnerable to + // https://www.sektioneins.de/advisories/advisory-012013-php-openssl_x509_parse-memory-corruption-vulnerability.html + if ( + PHP_VERSION_ID <= 50327 + || (PHP_VERSION_ID >= 50400 && PHP_VERSION_ID < 50422) + || (PHP_VERSION_ID >= 50500 && PHP_VERSION_ID < 50506) + ) { + return !empty($contents); + } + + return (bool) openssl_x509_parse($contents); +} + +class Installer +{ + private $quiet; + private $disableTls; + private $cafile; + private $displayPath; + private $target; + private $tmpFile; + private $tmpCafile; + private $baseUrl; + private $algo; + private $errHandler; + private $httpClient; + private $pubKeys = array(); + private $installs = array(); + + /** + * Constructor - must not do anything that throws an exception + * + * @param bool $quiet Quiet mode + * @param bool $disableTls Bypass tls + * @param mixed $cafile Path to CA bundle, or false + */ + public function __construct($quiet, $disableTls, $caFile) + { + if (($this->quiet = $quiet)) { + ob_start(); + } + $this->disableTls = $disableTls; + $this->cafile = $caFile; + $this->errHandler = new ErrorHandler(); + } + + /** + * Runs the installer + * + * @param mixed $version Specific version to install, or false + * @param mixed $installDir Specific installation directory, or false + * @param string $filename Specific filename to save to, or composer.phar + * @param string $channel Specific version channel to use + * @throws Exception If anything other than a RuntimeException is caught + * + * @return bool If the installation succeeded + */ + public function run($version, $installDir, $filename, $channel) + { + try { + $this->initTargets($installDir, $filename); + $this->initTls(); + $this->httpClient = new HttpClient($this->disableTls, $this->cafile); + $result = $this->install($version, $channel); + + // in case --1 or --2 is passed, we leave the default channel for next self-update to stable + if (1 === preg_match('{^\d+$}D', $channel)) { + $channel = 'stable'; + } + + if ($result && $channel !== 'stable' && !$version && defined('PHP_BINARY')) { + $null = (defined('PHP_WINDOWS_VERSION_MAJOR') ? 'NUL' : '/dev/null'); + @exec(escapeshellarg(PHP_BINARY) .' '.escapeshellarg($this->target).' self-update --'.$channel.' --set-channel-only -q > '.$null.' 2> '.$null, $output); + } + } catch (Exception $e) { + $result = false; + } + + // Always clean up + $this->cleanUp($result); + + if (isset($e)) { + // Rethrow anything that is not a RuntimeException + if (!$e instanceof RuntimeException) { + throw $e; + } + out($e->getMessage(), 'error'); + } + return $result; + } + + /** + * Initialization methods to set the required filenames and composer url + * + * @param mixed $installDir Specific installation directory, or false + * @param string $filename Specific filename to save to, or composer.phar + * @throws RuntimeException If the installation directory is not writable + */ + protected function initTargets($installDir, $filename) + { + $this->displayPath = ($installDir ? rtrim($installDir, '/').'/' : '').$filename; + $installDir = $installDir ? realpath($installDir) : getcwd(); + + if (!is_writeable($installDir)) { + throw new RuntimeException('The installation directory "'.$installDir.'" is not writable'); + } + + $this->target = $installDir.DIRECTORY_SEPARATOR.$filename; + $this->tmpFile = $installDir.DIRECTORY_SEPARATOR.basename($this->target, '.phar').'-temp.phar'; + + $uriScheme = $this->disableTls ? 'http' : 'https'; + $this->baseUrl = $uriScheme.'://getcomposer.org'; + } + + /** + * A wrapper around methods to check tls and write public keys + * @throws RuntimeException If SHA384 is not supported + */ + protected function initTls() + { + if ($this->disableTls) { + return; + } + + if (!in_array('sha384', array_map('strtolower', openssl_get_md_methods()))) { + throw new RuntimeException('SHA384 is not supported by your openssl extension'); + } + + $this->algo = defined('OPENSSL_ALGO_SHA384') ? OPENSSL_ALGO_SHA384 : 'SHA384'; + $home = $this->getComposerHome(); + + $this->pubKeys = array( + 'dev' => $this->installKey(self::getPKDev(), $home, 'keys.dev.pub'), + 'tags' => $this->installKey(self::getPKTags(), $home, 'keys.tags.pub') + ); + + if (empty($this->cafile) && !HttpClient::getSystemCaRootBundlePath()) { + $this->cafile = $this->tmpCafile = $this->installKey(HttpClient::getPackagedCaFile(), $home, 'cacert-temp.pem'); + } + } + + /** + * Returns the Composer home directory, creating it if required + * @throws RuntimeException If the directory cannot be created + * + * @return string + */ + protected function getComposerHome() + { + $home = getHomeDir(); + + if (!is_dir($home)) { + $this->errHandler->start(); + + if (!mkdir($home, 0777, true)) { + throw new RuntimeException(sprintf( + 'Unable to create Composer home directory "%s": %s', + $home, + $this->errHandler->message + )); + } + $this->installs[] = $home; + $this->errHandler->stop(); + } + return $home; + } + + /** + * Writes public key data to disc + * + * @param string $data The public key(s) in pem format + * @param string $path The directory to write to + * @param string $filename The name of the file + * @throws RuntimeException If the file cannot be written + * + * @return string The path to the saved data + */ + protected function installKey($data, $path, $filename) + { + $this->errHandler->start(); + + $target = $path.DIRECTORY_SEPARATOR.$filename; + $installed = file_exists($target); + $write = file_put_contents($target, $data, LOCK_EX); + @chmod($target, 0644); + + $this->errHandler->stop(); + + if (!$write) { + throw new RuntimeException(sprintf('Unable to write %s to: %s', $filename, $path)); + } + + if (!$installed) { + $this->installs[] = $target; + } + + return $target; + } + + /** + * The main install function + * + * @param mixed $version Specific version to install, or false + * @param string $channel Version channel to use + * + * @return bool If the installation succeeded + */ + protected function install($version, $channel) + { + $retries = 3; + $result = false; + $infoMsg = 'Downloading...'; + $infoType = 'info'; + + while ($retries--) { + if (!$this->quiet) { + out($infoMsg, $infoType); + $infoMsg = 'Retrying...'; + $infoType = 'error'; + } + + if (!$this->getVersion($channel, $version, $url, $error)) { + out($error, 'error'); + continue; + } + + if (!$this->downloadToTmp($url, $signature, $error)) { + out($error, 'error'); + continue; + } + + if (!$this->verifyAndSave($version, $signature, $error)) { + out($error, 'error'); + continue; + } + + $result = true; + break; + } + + if (!$this->quiet) { + if ($result) { + out(PHP_EOL."Composer (version {$version}) successfully installed to: {$this->target}", 'success'); + out("Use it: php {$this->displayPath}", 'info'); + out(''); + } else { + out('The download failed repeatedly, aborting.', 'error'); + } + } + return $result; + } + + /** + * Sets the version url, downloading version data if required + * + * @param string $channel Version channel to use + * @param false|string $version Version to install, or set by method + * @param null|string $url The versioned url, set by method + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function getVersion($channel, &$version, &$url, &$error) + { + $error = ''; + + if ($version) { + if (empty($url)) { + $url = $this->baseUrl."/download/{$version}/composer.phar"; + } + return true; + } + + $this->errHandler->start(); + + if ($this->downloadVersionData($data, $error)) { + $this->parseVersionData($data, $channel, $version, $url); + } + + $this->errHandler->stop(); + return empty($error); + } + + /** + * Downloads and json-decodes version data + * + * @param null|array $data Downloaded version data, set by method + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function downloadVersionData(&$data, &$error) + { + $url = $this->baseUrl.'/versions'; + $errFmt = 'The "%s" file could not be %s: %s'; + + if (!$json = $this->httpClient->get($url)) { + $error = sprintf($errFmt, $url, 'downloaded', $this->errHandler->message); + return false; + } + + if (!$data = json_decode($json, true)) { + $error = sprintf($errFmt, $url, 'json-decoded', $this->getJsonError()); + return false; + } + return true; + } + + /** + * A wrapper around the methods needed to download and save the phar + * + * @param string $url The versioned download url + * @param null|string $signature Set by method on successful download + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function downloadToTmp($url, &$signature, &$error) + { + $error = ''; + $errFmt = 'The "%s" file could not be downloaded: %s'; + $sigUrl = $url.'.sig'; + $this->errHandler->start(); + + if (!$fh = fopen($this->tmpFile, 'w')) { + $error = sprintf('Could not create file "%s": %s', $this->tmpFile, $this->errHandler->message); + + } elseif (!$this->getSignature($sigUrl, $signature)) { + $error = sprintf($errFmt, $sigUrl, $this->errHandler->message); + + } elseif (!fwrite($fh, $this->httpClient->get($url))) { + $error = sprintf($errFmt, $url, $this->errHandler->message); + } + + if (is_resource($fh)) { + fclose($fh); + } + $this->errHandler->stop(); + return empty($error); + } + + /** + * Verifies the downloaded file and saves it to the target location + * + * @param string $version The composer version downloaded + * @param string $signature The digital signature to check + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function verifyAndSave($version, $signature, &$error) + { + $error = ''; + + if (!$this->validatePhar($this->tmpFile, $pharError)) { + $error = 'The download is corrupt: '.$pharError; + + } elseif (!$this->verifySignature($version, $signature, $this->tmpFile)) { + $error = 'Signature mismatch, could not verify the phar file integrity'; + + } else { + $this->errHandler->start(); + + if (!rename($this->tmpFile, $this->target)) { + $error = sprintf('Could not write to file "%s": %s', $this->target, $this->errHandler->message); + } + chmod($this->target, 0755); + $this->errHandler->stop(); + } + + return empty($error); + } + + /** + * Parses an array of version data to match the required channel + * + * @param array $data Downloaded version data + * @param mixed $channel Version channel to use + * @param false|string $version Set by method + * @param mixed $url The versioned url, set by method + */ + protected function parseVersionData(array $data, $channel, &$version, &$url) + { + foreach ($data[$channel] as $candidate) { + if ($candidate['min-php'] <= PHP_VERSION_ID) { + $version = $candidate['version']; + $url = $this->baseUrl.$candidate['path']; + break; + } + } + + if (!$version) { + $error = sprintf( + 'None of the %d %s version(s) of Composer matches your PHP version (%s / ID: %d)', + count($data[$channel]), + $channel, + PHP_VERSION, + PHP_VERSION_ID + ); + throw new RuntimeException($error); + } + } + + /** + * Downloads the digital signature of required phar file + * + * @param string $url The signature url + * @param null|string $signature Set by method on success + * + * @return bool If the download succeeded + */ + protected function getSignature($url, &$signature) + { + if (!$result = $this->disableTls) { + $signature = $this->httpClient->get($url); + + if ($signature) { + $signature = json_decode($signature, true); + $signature = base64_decode($signature['sha384']); + $result = true; + } + } + + return $result; + } + + /** + * Verifies the signature of the downloaded phar + * + * @param string $version The composer versione + * @param string $signature The downloaded digital signature + * @param string $file The temp phar file + * + * @return bool If the operation succeeded + */ + protected function verifySignature($version, $signature, $file) + { + if (!$result = $this->disableTls) { + $path = preg_match('{^[0-9a-f]{40}$}', $version) ? $this->pubKeys['dev'] : $this->pubKeys['tags']; + $pubkeyid = openssl_pkey_get_public('file://'.$path); + + $result = 1 === openssl_verify( + file_get_contents($file), + $signature, + $pubkeyid, + $this->algo + ); + + // PHP 8 automatically frees the key instance and deprecates the function + if (PHP_VERSION_ID < 80000) { + openssl_free_key($pubkeyid); + } + } + + return $result; + } + + /** + * Validates the downloaded phar file + * + * @param string $pharFile The temp phar file + * @param null|string $error Set by method on failure + * + * @return bool If the operation succeeded + */ + protected function validatePhar($pharFile, &$error) + { + if (ini_get('phar.readonly')) { + return true; + } + + try { + // Test the phar validity + $phar = new Phar($pharFile); + // Free the variable to unlock the file + unset($phar); + $result = true; + + } catch (Exception $e) { + if (!$e instanceof UnexpectedValueException && !$e instanceof PharException) { + throw $e; + } + $error = $e->getMessage(); + $result = false; + } + return $result; + } + + /** + * Returns a string representation of the last json error + * + * @return string The error string or code + */ + protected function getJsonError() + { + if (function_exists('json_last_error_msg')) { + return json_last_error_msg(); + } else { + return 'json_last_error = '.json_last_error(); + } + } + + /** + * Cleans up resources at the end of the installation + * + * @param bool $result If the installation succeeded + */ + protected function cleanUp($result) + { + if (!$result) { + // Output buffered errors + if ($this->quiet) { + $this->outputErrors(); + } + // Clean up stuff we created + $this->uninstall(); + } elseif ($this->tmpCafile) { + @unlink($this->tmpCafile); + } + } + + /** + * Outputs unique errors when in quiet mode + * + */ + protected function outputErrors() + { + $errors = explode(PHP_EOL, ob_get_clean()); + $shown = array(); + + foreach ($errors as $error) { + if ($error && !in_array($error, $shown)) { + out($error, 'error'); + $shown[] = $error; + } + } + } + + /** + * Uninstalls newly-created files and directories on failure + * + */ + protected function uninstall() + { + foreach (array_reverse($this->installs) as $target) { + if (is_file($target)) { + @unlink($target); + } elseif (is_dir($target)) { + @rmdir($target); + } + } + + if ($this->tmpFile !== null && file_exists($this->tmpFile)) { + @unlink($this->tmpFile); + } + } + + public static function getPKDev() + { + return <<message) { + $this->message .= PHP_EOL; + } + $this->message .= preg_replace('{^file_get_contents\(.*?\): }', '', $msg); + } + + /** + * Starts error-handling if not already active + * + * Any message is cleared + */ + public function start() + { + if (!$this->active) { + set_error_handler(array($this, 'handleError')); + $this->active = true; + } + $this->message = ''; + } + + /** + * Stops error-handling if active + * + * Any message is preserved until the next call to start() + */ + public function stop() + { + if ($this->active) { + restore_error_handler(); + $this->active = false; + } + } +} + +class NoProxyPattern +{ + private $composerInNoProxy = false; + private $rulePorts = array(); + + public function __construct($pattern) + { + $rules = preg_split('{[\s,]+}', $pattern, null, PREG_SPLIT_NO_EMPTY); + + if ($matches = preg_grep('{getcomposer\.org(?::\d+)?}i', $rules)) { + $this->composerInNoProxy = true; + + foreach ($matches as $match) { + if (strpos($match, ':') !== false) { + list(, $port) = explode(':', $match); + $this->rulePorts[] = (int) $port; + } + } + } + } + + /** + * Returns true if NO_PROXY contains getcomposer.org + * + * @param string $url http(s)://getcomposer.org + * + * @return bool + */ + public function test($url) + { + if (!$this->composerInNoProxy) { + return false; + } + + if (empty($this->rulePorts)) { + return true; + } + + if (strpos($url, 'http://') === 0) { + $port = 80; + } else { + $port = 443; + } + + return in_array($port, $this->rulePorts); + } +} + +class HttpClient { + + /** @var null|string */ + private static $caPath; + + private $options = array('http' => array()); + private $disableTls = false; + + public function __construct($disableTls = false, $cafile = false) + { + $this->disableTls = $disableTls; + if ($this->disableTls === false) { + if (!empty($cafile) && !is_dir($cafile)) { + if (!is_readable($cafile) || !validateCaFile(file_get_contents($cafile))) { + throw new RuntimeException('The configured cafile (' .$cafile. ') was not valid or could not be read.'); + } + } + $options = $this->getTlsStreamContextDefaults($cafile); + $this->options = array_replace_recursive($this->options, $options); + } + } + + public function get($url) + { + $context = $this->getStreamContext($url); + $result = file_get_contents($url, false, $context); + + if ($result && extension_loaded('zlib')) { + $decode = false; + foreach ($http_response_header as $header) { + if (preg_match('{^content-encoding: *gzip *$}i', $header)) { + $decode = true; + continue; + } elseif (preg_match('{^HTTP/}i', $header)) { + $decode = false; + } + } + + if ($decode) { + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + $result = zlib_decode($result); + } else { + // work around issue with gzuncompress & co that do not work with all gzip checksums + $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,'.base64_encode($result)); + } + + if (!$result) { + throw new RuntimeException('Failed to decode zlib stream'); + } + } + } + + return $result; + } + + protected function getStreamContext($url) + { + if ($this->disableTls === false) { + if (PHP_VERSION_ID < 50600) { + $this->options['ssl']['SNI_server_name'] = parse_url($url, PHP_URL_HOST); + } + } + // Keeping the above mostly isolated from the code copied from Composer. + return $this->getMergedStreamContext($url); + } + + protected function getTlsStreamContextDefaults($cafile) + { + $ciphers = implode(':', array( + 'ECDHE-RSA-AES128-GCM-SHA256', + 'ECDHE-ECDSA-AES128-GCM-SHA256', + 'ECDHE-RSA-AES256-GCM-SHA384', + 'ECDHE-ECDSA-AES256-GCM-SHA384', + 'DHE-RSA-AES128-GCM-SHA256', + 'DHE-DSS-AES128-GCM-SHA256', + 'kEDH+AESGCM', + 'ECDHE-RSA-AES128-SHA256', + 'ECDHE-ECDSA-AES128-SHA256', + 'ECDHE-RSA-AES128-SHA', + 'ECDHE-ECDSA-AES128-SHA', + 'ECDHE-RSA-AES256-SHA384', + 'ECDHE-ECDSA-AES256-SHA384', + 'ECDHE-RSA-AES256-SHA', + 'ECDHE-ECDSA-AES256-SHA', + 'DHE-RSA-AES128-SHA256', + 'DHE-RSA-AES128-SHA', + 'DHE-DSS-AES128-SHA256', + 'DHE-RSA-AES256-SHA256', + 'DHE-DSS-AES256-SHA', + 'DHE-RSA-AES256-SHA', + 'AES128-GCM-SHA256', + 'AES256-GCM-SHA384', + 'AES128-SHA256', + 'AES256-SHA256', + 'AES128-SHA', + 'AES256-SHA', + 'AES', + 'CAMELLIA', + 'DES-CBC3-SHA', + '!aNULL', + '!eNULL', + '!EXPORT', + '!DES', + '!RC4', + '!MD5', + '!PSK', + '!aECDH', + '!EDH-DSS-DES-CBC3-SHA', + '!EDH-RSA-DES-CBC3-SHA', + '!KRB5-DES-CBC3-SHA', + )); + + /** + * CN_match and SNI_server_name are only known once a URL is passed. + * They will be set in the getOptionsForUrl() method which receives a URL. + * + * cafile or capath can be overridden by passing in those options to constructor. + */ + $options = array( + 'ssl' => array( + 'ciphers' => $ciphers, + 'verify_peer' => true, + 'verify_depth' => 7, + 'SNI_enabled' => true, + ) + ); + + /** + * Attempt to find a local cafile or throw an exception. + * The user may go download one if this occurs. + */ + if (!$cafile) { + $cafile = self::getSystemCaRootBundlePath(); + } + if (is_dir($cafile)) { + $options['ssl']['capath'] = $cafile; + } elseif ($cafile) { + $options['ssl']['cafile'] = $cafile; + } else { + throw new RuntimeException('A valid cafile could not be located automatically.'); + } + + /** + * Disable TLS compression to prevent CRIME attacks where supported. + */ + if (version_compare(PHP_VERSION, '5.4.13') >= 0) { + $options['ssl']['disable_compression'] = true; + } + + return $options; + } + + /** + * function copied from Composer\Util\StreamContextFactory::initOptions + * + * Any changes should be applied there as well, or backported here. + * + * @param string $url URL the context is to be used for + * @return resource Default context + * @throws \RuntimeException if https proxy required and OpenSSL uninstalled + */ + protected function getMergedStreamContext($url) + { + $options = $this->options; + + // Handle HTTP_PROXY/http_proxy on CLI only for security reasons + if ((PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') && (!empty($_SERVER['HTTP_PROXY']) || !empty($_SERVER['http_proxy']))) { + $proxy = parse_url(!empty($_SERVER['http_proxy']) ? $_SERVER['http_proxy'] : $_SERVER['HTTP_PROXY']); + } + + // Prefer CGI_HTTP_PROXY if available + if (!empty($_SERVER['CGI_HTTP_PROXY'])) { + $proxy = parse_url($_SERVER['CGI_HTTP_PROXY']); + } + + // Override with HTTPS proxy if present and URL is https + if (preg_match('{^https://}i', $url) && (!empty($_SERVER['HTTPS_PROXY']) || !empty($_SERVER['https_proxy']))) { + $proxy = parse_url(!empty($_SERVER['https_proxy']) ? $_SERVER['https_proxy'] : $_SERVER['HTTPS_PROXY']); + } + + // Remove proxy if URL matches no_proxy directive + if (!empty($_SERVER['NO_PROXY']) || !empty($_SERVER['no_proxy']) && parse_url($url, PHP_URL_HOST)) { + $pattern = new NoProxyPattern(!empty($_SERVER['no_proxy']) ? $_SERVER['no_proxy'] : $_SERVER['NO_PROXY']); + if ($pattern->test($url)) { + unset($proxy); + } + } + + if (!empty($proxy)) { + $proxyURL = isset($proxy['scheme']) ? $proxy['scheme'] . '://' : ''; + $proxyURL .= isset($proxy['host']) ? $proxy['host'] : ''; + + if (isset($proxy['port'])) { + $proxyURL .= ":" . $proxy['port']; + } elseif (strpos($proxyURL, 'http://') === 0) { + $proxyURL .= ":80"; + } elseif (strpos($proxyURL, 'https://') === 0) { + $proxyURL .= ":443"; + } + + // check for a secure proxy + if (strpos($proxyURL, 'https://') === 0) { + if (!extension_loaded('openssl')) { + throw new RuntimeException('You must enable the openssl extension to use a secure proxy.'); + } + if (strpos($url, 'https://') === 0) { + throw new RuntimeException('PHP does not support https requests through a secure proxy.'); + } + } + + // http(s):// is not supported in proxy + $proxyURL = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $proxyURL); + + $options['http'] = array( + 'proxy' => $proxyURL, + ); + + // add request_fulluri for http requests + if ('http' === parse_url($url, PHP_URL_SCHEME)) { + $options['http']['request_fulluri'] = true; + } + + // handle proxy auth if present + if (isset($proxy['user'])) { + $auth = rawurldecode($proxy['user']); + if (isset($proxy['pass'])) { + $auth .= ':' . rawurldecode($proxy['pass']); + } + $auth = base64_encode($auth); + + $options['http']['header'] = "Proxy-Authorization: Basic {$auth}\r\n"; + } + } + + if (isset($options['http']['header'])) { + $options['http']['header'] .= "Connection: close\r\n"; + } else { + $options['http']['header'] = "Connection: close\r\n"; + } + if (extension_loaded('zlib')) { + $options['http']['header'] .= "Accept-Encoding: gzip\r\n"; + } + $options['http']['header'] .= "User-Agent: ".COMPOSER_INSTALLER."\r\n"; + $options['http']['protocol_version'] = 1.1; + $options['http']['timeout'] = 600; + + return stream_context_create($options); + } + + /** + * This method was adapted from Sslurp. + * https://github.com/EvanDotPro/Sslurp + * + * (c) Evan Coury + * + * For the full copyright and license information, please see below: + * + * Copyright (c) 2013, Evan Coury + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + public static function getSystemCaRootBundlePath() + { + if (self::$caPath !== null) { + return self::$caPath; + } + + // If SSL_CERT_FILE env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $envCertFile = getenv('SSL_CERT_FILE'); + if ($envCertFile && is_readable($envCertFile) && validateCaFile(file_get_contents($envCertFile))) { + return self::$caPath = $envCertFile; + } + + // If SSL_CERT_DIR env variable points to a valid certificate/bundle, use that. + // This mimics how OpenSSL uses the SSL_CERT_FILE env variable. + $envCertDir = getenv('SSL_CERT_DIR'); + if ($envCertDir && is_dir($envCertDir) && is_readable($envCertDir)) { + return self::$caPath = $envCertDir; + } + + $configured = ini_get('openssl.cafile'); + if ($configured && strlen($configured) > 0 && is_readable($configured) && validateCaFile(file_get_contents($configured))) { + return self::$caPath = $configured; + } + + $configured = ini_get('openssl.capath'); + if ($configured && is_dir($configured) && is_readable($configured)) { + return self::$caPath = $configured; + } + + $caBundlePaths = array( + '/etc/pki/tls/certs/ca-bundle.crt', // Fedora, RHEL, CentOS (ca-certificates package) + '/etc/ssl/certs/ca-certificates.crt', // Debian, Ubuntu, Gentoo, Arch Linux (ca-certificates package) + '/etc/ssl/ca-bundle.pem', // SUSE, openSUSE (ca-certificates package) + '/usr/local/share/certs/ca-root-nss.crt', // FreeBSD (ca_root_nss_package) + '/usr/ssl/certs/ca-bundle.crt', // Cygwin + '/opt/local/share/curl/curl-ca-bundle.crt', // OS X macports, curl-ca-bundle package + '/usr/local/share/curl/curl-ca-bundle.crt', // Default cURL CA bunde path (without --with-ca-bundle option) + '/usr/share/ssl/certs/ca-bundle.crt', // Really old RedHat? + '/etc/ssl/cert.pem', // OpenBSD + '/usr/local/etc/ssl/cert.pem', // FreeBSD 10.x + '/usr/local/etc/openssl/cert.pem', // OS X homebrew, openssl package + '/usr/local/etc/openssl@1.1/cert.pem', // OS X homebrew, openssl@1.1 package + '/opt/homebrew/etc/openssl@3/cert.pem', // macOS silicon homebrew, openssl@3 package + '/opt/homebrew/etc/openssl@1.1/cert.pem', // macOS silicon homebrew, openssl@1.1 package + ); + + foreach ($caBundlePaths as $caBundle) { + if (@is_readable($caBundle) && validateCaFile(file_get_contents($caBundle))) { + return self::$caPath = $caBundle; + } + } + + foreach ($caBundlePaths as $caBundle) { + $caBundle = dirname($caBundle); + if (is_dir($caBundle) && glob($caBundle.'/*')) { + return self::$caPath = $caBundle; + } + } + + return self::$caPath = false; + } + + public static function getPackagedCaFile() + { + return <<=5.3.3" + "php": ">=7.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", @@ -223,11 +223,6 @@ "bin/validate-json" ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0.x-dev" - } - }, "autoload": { "psr-4": { "JsonSchema\\": "src/JsonSchema/" @@ -262,10 +257,10 @@ "schema" ], "support": { - "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12" + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" }, - "time": "2022-04-13T08:02:27+00:00" + "time": "2024-07-06T21:00:26+00:00" }, { "name": "maennchen/zipstream-php", @@ -457,16 +452,16 @@ }, { "name": "phpoffice/phpspreadsheet", - "version": "1.29.0", + "version": "1.29.1", "source": { "type": "git", "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", - "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0" + "reference": "59ee38f7480904cd6487e5cbdea4d80ff2758719" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/fde2ccf55eaef7e86021ff1acce26479160a0fa0", - "reference": "fde2ccf55eaef7e86021ff1acce26479160a0fa0", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/59ee38f7480904cd6487e5cbdea4d80ff2758719", + "reference": "59ee38f7480904cd6487e5cbdea4d80ff2758719", "shasum": "" }, "require": { @@ -501,7 +496,7 @@ "phpcompatibility/php-compatibility": "^9.3", "phpstan/phpstan": "^1.1", "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^8.5 || ^9.0 || ^10.0", + "phpunit/phpunit": "^8.5 || ^9.0", "squizlabs/php_codesniffer": "^3.7", "tecnickcom/tcpdf": "^6.5" }, @@ -556,22 +551,22 @@ ], "support": { "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", - "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.0" + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.29.1" }, - "time": "2023-06-14T22:48:31+00:00" + "time": "2024-09-03T00:55:32+00:00" }, { "name": "phpoption/phpoption", - "version": "1.9.1", + "version": "1.9.3", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e" + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/dd3a383e599f49777d8b628dadbb90cae435b87e", - "reference": "dd3a383e599f49777d8b628dadbb90cae435b87e", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", "shasum": "" }, "require": { @@ -579,13 +574,13 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.32 || ^9.6.3 || ^10.0.12" + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" }, "type": "library", "extra": { "bamarni-bin": { "bin-links": true, - "forward-command": true + "forward-command": false }, "branch-alias": { "dev-master": "1.9-dev" @@ -621,7 +616,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.1" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" }, "funding": [ { @@ -633,20 +628,20 @@ "type": "tidelift" } ], - "time": "2023-02-25T19:38:58+00:00" + "time": "2024-07-20T21:41:07+00:00" }, { "name": "psr/http-client", - "version": "1.0.2", + "version": "1.0.3", "source": { "type": "git", "url": "https://github.com/php-fig/http-client.git", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31" + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31", - "reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", "shasum": "" }, "require": { @@ -683,26 +678,26 @@ "psr-18" ], "support": { - "source": "https://github.com/php-fig/http-client/tree/1.0.2" + "source": "https://github.com/php-fig/http-client" }, - "time": "2023-04-10T20:12:12+00:00" + "time": "2023-09-23T14:17:50+00:00" }, { "name": "psr/http-factory", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/http-factory.git", - "reference": "e616d01114759c4c489f93b099585439f795fe35" + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", - "reference": "e616d01114759c4c489f93b099585439f795fe35", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", "shasum": "" }, "require": { - "php": ">=7.0.0", + "php": ">=7.1", "psr/http-message": "^1.0 || ^2.0" }, "type": "library", @@ -726,7 +721,7 @@ "homepage": "https://www.php-fig.org/" } ], - "description": "Common interfaces for PSR-7 HTTP message factories", + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", "keywords": [ "factory", "http", @@ -738,9 +733,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + "source": "https://github.com/php-fig/http-factory" }, - "time": "2023-04-10T20:10:41+00:00" + "time": "2024-04-15T12:06:14+00:00" }, { "name": "psr/http-message", @@ -895,20 +890,20 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.28.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -918,9 +913,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -957,7 +949,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -973,24 +965,24 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -1000,9 +992,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1040,7 +1029,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -1056,30 +1045,27 @@ "type": "tidelift" } ], - "time": "2023-07-28T09:04:16+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.28.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -1123,7 +1109,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -1139,35 +1125,35 @@ "type": "tidelift" } ], - "time": "2023-01-26T09:26:14+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "vlucas/phpdotenv", - "version": "v5.5.0", + "version": "v5.6.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7" + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", - "reference": "1a7ea2afc49c3ee6d87061f5a233e3a035d0eae7", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/a59a13791077fe3d44f90e7133eb68e7d22eaff2", + "reference": "a59a13791077fe3d44f90e7133eb68e7d22eaff2", "shasum": "" }, "require": { "ext-pcre": "*", - "graham-campbell/result-type": "^1.0.2", - "php": "^7.1.3 || ^8.0", - "phpoption/phpoption": "^1.8", - "symfony/polyfill-ctype": "^1.23", - "symfony/polyfill-mbstring": "^1.23.1", - "symfony/polyfill-php80": "^1.23.1" + "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.4.1", + "bamarni/composer-bin-plugin": "^1.8.2", "ext-filter": "*", - "phpunit/phpunit": "^7.5.20 || ^8.5.30 || ^9.5.25" + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" }, "suggest": { "ext-filter": "Required to use the boolean validator." @@ -1176,10 +1162,10 @@ "extra": { "bamarni-bin": { "bin-links": true, - "forward-command": true + "forward-command": false }, "branch-alias": { - "dev-master": "5.5-dev" + "dev-master": "5.6-dev" } }, "autoload": { @@ -1211,7 +1197,7 @@ ], "support": { "issues": "https://github.com/vlucas/phpdotenv/issues", - "source": "https://github.com/vlucas/phpdotenv/tree/v5.5.0" + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.1" }, "funding": [ { @@ -1223,7 +1209,7 @@ "type": "tidelift" } ], - "time": "2022-10-16T01:01:54+00:00" + "time": "2024-07-20T21:52:34+00:00" } ], "packages-dev": [], @@ -1234,5 +1220,5 @@ "prefer-lowest": false, "platform": [], "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/css/calendar.css b/css/calendar.css index 398325a..40a1028 100644 --- a/css/calendar.css +++ b/css/calendar.css @@ -1,39 +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; -} - +/* +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/clockpicker.css b/css/clockpicker.css index 770b173..610401d 100644 --- a/css/clockpicker.css +++ b/css/clockpicker.css @@ -1,143 +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; -} +/*! + * 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/fa_all.css b/css/fa_all.css index a51a10c..440a131 100644 --- a/css/fa_all.css +++ b/css/fa_all.css @@ -1,5 +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) - */ +/*! + * 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/index.css b/css/index.css index 6bb8215..69c654c 100644 --- a/css/index.css +++ b/css/index.css @@ -1,30 +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; - } +/* +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 index 59b9aa0..7d3a22d 100644 --- a/css/indivisa.css +++ b/css/indivisa.css @@ -1,492 +1,492 @@ -/* - Created on : 5/12/2018, 01:25:27 PM - Author : Alejandro - Indivisa Fonts -*/ - -@font-face { - font-family: 'indivisa-title'; - 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.IndivisaTextSans-BoldItalic'); - 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-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-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; -} - -.indivisa-display { - font-family: 'indivisa-display' !important; -} - -.indivisa-title { - font-family: 'indivisa-title' !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"; +/* + Created on : 5/12/2018, 01:25:27 PM + Author : Alejandro + Indivisa Fonts +*/ + +@font-face { + font-family: 'indivisa-title'; + 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.IndivisaTextSans-BoldItalic'); + 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-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-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; +} + +.indivisa-display { + font-family: 'indivisa-display' !important; +} + +.indivisa-title { + font-family: 'indivisa-title' !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 index 776e259..9aa45f9 100644 --- a/css/jquery-ui.css +++ b/css/jquery-ui.css @@ -1,7 +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 */ - +/*! 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 index d83ca77..d3095c8 100644 --- a/css/lasalle.css +++ b/css/lasalle.css @@ -1,105 +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";} +/* +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/sgi.css b/css/sgi.css index 6e7f562..60c05ab 100644 --- a/css/sgi.css +++ b/css/sgi.css @@ -1,1085 +1,1085 @@ -/* - 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); - height: 8rem; - /* align all inside content to the middle */ - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - background-color: #f7f7f7; -} - -.movie:hover { - transform: scale(1.05); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5); - 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; -} - -.icono.ing-buscar { - cursor: pointer; +/* + 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); + height: 8rem; + /* align all inside content to the middle */ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: #f7f7f7; +} + +.movie:hover { + transform: scale(1.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5); + 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; +} + +.icono.ing-buscar { + cursor: pointer; } \ No newline at end of file diff --git a/css/style.css b/css/style.css index 2e6b8d8..ce6f6f8 100644 --- a/css/style.css +++ b/css/style.css @@ -1,99 +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)); +.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 index 4903b1e..86b914c 100644 --- a/css/toggle.css +++ b/css/toggle.css @@ -1,142 +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; } +/*\ +|*| ======================================================================== +|*| 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/demo.html b/demo.html index dcf5941..a10172a 100644 --- a/demo.html +++ b/demo.html @@ -1,237 +1,237 @@ - -

Iconos editado

-

Iconos editados 2

-

- ing-fb1 -

-

- ing-fb2 -

-

- ing-tw1 -

-

- ing-tw2 -

-

- ing-in1 -

-

- ing-in2 -

-

- ing-instra1 -

-

- ing-instra2 -

-

- ing-youtube -

-

- ing-telefono -

-

- ing-mail -

-

- ing-link -

-

- ing-ubicacion -

-

- ing-puntos -

-

- ing-usuario -

-

- ing-pass -

-

- ing-menu -

-

- ing-salir -

-

- ing-flecha -

-

- ing-cambiar -

-

- ing-caret -

-

- ing-aceptar -

-

- ing-cancelar -

-

- ing-mas -

-

- ing-menos -

-

- ing-editar -

-

- ing-buscar -

-

- ing-ojo -

-

- ing-borrar -

-

- ing-basura -

-

- ing-camara -

-

- ing-importante -

-

- ing-bullet -

-

- ing-home -

-

- ing-formacion -

-

- ing-empleo -

-

- ing-insignia1 -

-

- ing-insignia2 -

-

- ing-insignia3 -

-

- ing-insignia4 -

-

- ing-eventos -

-

- ing-reporte -

-

- ing-catalogo -

-

- ing-evalua-cartel -

-

- ing-revision-cartel -

-

- ing-reporte-resultados -

-

- ing-mi-cartel -

-

- ing-galeria1 -

-

- ing-galeria2 -

-

- ing-iniciar-sesion -

-

- ing-finalistas -

-

- ing-comite -

-

- ing-administrador -

-

- ing-estrella1 -

-

- ing-estrella2 -

-

- ing-carga-archivo -

-

- ing-carga-multiple -

-

- ing-descarga -

-

- ing-autorizar -

-

- ing-negar -

-

- ing-no-cargado -

-

- ing-alumnos -

-

- ing-cardex -

-

- ing-configuracion -

-

- ing-listado-menus -

-

- ing-mi-cuenta -

-

- ing-ver -

-

- ing-grafica -

-

- ing-clic -

-

- ing-guardar -

-

- ing-regresar -

-

- ing-cuadrado -

-

- ing-imprimir -

-

- ing-importante2 -

-

- ing-copiar -

-

- ing-reloj -

-

- ing-retardo -

-

- ing-justificar + +

Iconos editado

+

Iconos editados 2

+

+ ing-fb1 +

+

+ ing-fb2 +

+

+ ing-tw1 +

+

+ ing-tw2 +

+

+ ing-in1 +

+

+ ing-in2 +

+

+ ing-instra1 +

+

+ ing-instra2 +

+

+ ing-youtube +

+

+ ing-telefono +

+

+ ing-mail +

+

+ ing-link +

+

+ ing-ubicacion +

+

+ ing-puntos +

+

+ ing-usuario +

+

+ ing-pass +

+

+ ing-menu +

+

+ ing-salir +

+

+ ing-flecha +

+

+ ing-cambiar +

+

+ ing-caret +

+

+ ing-aceptar +

+

+ ing-cancelar +

+

+ ing-mas +

+

+ ing-menos +

+

+ ing-editar +

+

+ ing-buscar +

+

+ ing-ojo +

+

+ ing-borrar +

+

+ ing-basura +

+

+ ing-camara +

+

+ ing-importante +

+

+ ing-bullet +

+

+ ing-home +

+

+ ing-formacion +

+

+ ing-empleo +

+

+ ing-insignia1 +

+

+ ing-insignia2 +

+

+ ing-insignia3 +

+

+ ing-insignia4 +

+

+ ing-eventos +

+

+ ing-reporte +

+

+ ing-catalogo +

+

+ ing-evalua-cartel +

+

+ ing-revision-cartel +

+

+ ing-reporte-resultados +

+

+ ing-mi-cartel +

+

+ ing-galeria1 +

+

+ ing-galeria2 +

+

+ ing-iniciar-sesion +

+

+ ing-finalistas +

+

+ ing-comite +

+

+ ing-administrador +

+

+ ing-estrella1 +

+

+ ing-estrella2 +

+

+ ing-carga-archivo +

+

+ ing-carga-multiple +

+

+ ing-descarga +

+

+ ing-autorizar +

+

+ ing-negar +

+

+ ing-no-cargado +

+

+ ing-alumnos +

+

+ ing-cardex +

+

+ ing-configuracion +

+

+ ing-listado-menus +

+

+ ing-mi-cuenta +

+

+ ing-ver +

+

+ ing-grafica +

+

+ ing-clic +

+

+ ing-guardar +

+

+ ing-regresar +

+

+ ing-cuadrado +

+

+ ing-imprimir +

+

+ ing-importante2 +

+

+ ing-copiar +

+

+ ing-reloj +

+

+ ing-retardo +

+

+ ing-justificar

\ No newline at end of file diff --git a/export/solicitudes_excel.php b/export/solicitudes_excel.php index 18f07fe..43dc006 100644 --- a/export/solicitudes_excel.php +++ b/export/solicitudes_excel.php @@ -1,156 +1,156 @@ -query('SELECT * FROM fs_estado_reposicion' ); - -$repoParams = array(); - -$user = Login::get_user(); -$user->access(); -$query=""; -if($user->rol["rol_id"] == 9){//es coordinador - $query .= ":facultad, "; - $repoParams[":facultad"] = $user->facultad["facultad_id"]; -}else{//supervisor - $query .= "NULL, "; -} -if(isset($_POST["prof"]) ){ - $query .= ":prof,"; - $profesor = trim($_POST["prof"]);//limpia texto - $repoParams[":prof"] = $profesor; -}else{ - $query .= "NULL,"; -} -$query .= ":f_ini, :f_fin, "; -$repoParams[":f_ini"] = DateTime::createFromFormat('d/m/Y', $fecha_ini)->format('Y-m-d'); -$repoParams[":f_fin"] = DateTime::createFromFormat('d/m/Y', $fecha_fin)->format('Y-m-d'); - -$spreadsheet = new Spreadsheet(); - -// Set document properties -$spreadsheet->getProperties()->setCreator('Universidad La Salle') - ->setLastModifiedBy('Universidad La Salle') - ->setTitle('Solicitudes') - ->setDescription('Reporte de solicitudes.'); - -$headerStyle = - [ - 'fill' => [ - 'fillType' => Fill::FILL_SOLID, - 'color' => ['argb' => 'FF001d68'], - ], - 'borders' => [ - 'bottom' => ['borderStyle' => Border::BORDER_THIN], - 'right' => ['borderStyle' => Border::BORDER_MEDIUM], - ], - 'font' => [ - 'bold' => true, - 'color' => ['argb' => 'FFFFFFFF'], - ] - ]; - -$row_base = 6; - -$i=0; -foreach($repEdo_rs as $redo){ - $row = $row_base; - if($i >= $spreadsheet->getSheetCount()){ - $spreadsheet->createSheet(); - } - $spreadsheet->setActiveSheetIndex($i); - //crea imagen - $drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing(); - $drawing->setName('La Salle'); - $drawing->setDescription('La Salle'); - $drawing->setPath('../imagenes/logo.png'); // put your path and image here - $drawing->setCoordinates('A1'); - $drawing->setHeight(100); - $drawing->setOffsetX(10); - //agrega imagen - $drawing->setWorksheet($spreadsheet->getActiveSheet()); - - $spreadsheet->getActiveSheet() - ->setCellValue('A'.$row, 'Estado') - ->setCellValue('B'.$row, 'Tipo') - ->setCellValue('C'.$row, 'Profesor') - ->setCellValue('D'.$row, 'Materia') - ->setCellValue('E'.$row, 'Grupo') - ->setCellValue('F'.$row, 'Fecha falta') - ->setCellValue('G'.$row, 'Fecha reposici贸n') - ->setCellValue('H'.$row, 'Sal贸n'); - - $spreadsheet->getActiveSheet()->getStyle('A'.$row.':H'.$row)->applyFromArray($headerStyle); - $repoParams[":edo"]=$redo["estado_reposicion_id"]; - if($user->rol["rol_id"] == 7){//es supervisor - $repoParams[":sup"] = $user->user["id"]; - $solicitudes_rs = $db->query('SELECT * FROM fs_solicitud(NULL, '.$query.':edo, NULL, :sup) ', $repoParams ); - }else{ - $solicitudes_rs = $db->query('SELECT * FROM fs_solicitud(NULL, '.$query.':edo, NULL, NULL) ', $repoParams ); - } - - $row++; - $sheet = $spreadsheet->getActiveSheet(); - $sheet->setTitle($redo["estado_nombre"]); - if(isset($solicitudes_rs) && count($solicitudes_rs)>0){ - foreach($solicitudes_rs as $reposicion){ - - - $sheet->setCellValue('A'.$row, $reposicion["estado_nombre"]); - $sheet->setCellValue('B'.$row, $reposicion["solicitudtipo_nombre"]); - $sheet->setCellValue('C'.$row, $reposicion["profesor_clave"]." - ".$reposicion["profesor_nombre"]); - $sheet->setCellValue('D'.$row, $reposicion["materia_nombre"]); - if($reposicion["horario_grupo"]!="") - $sheet->setCellValue('E'.$row, $reposicion["horario_grupo"]); - - if($reposicion["fecha_clase"]!=""){ - $fechaI = DateTime::createFromFormat('Y-m-d', $reposicion["fecha_nueva"])->format('d/m/Y'); - $sheet->setCellValue('F'.$row, $fechaI." ".substr($reposicion["horario_hora"],0, 5)); - } - - $fechaF = date("d/m/Y", strtotime($reposicion["fecha_nueva"])); - $sheet->setCellValue('G'.$row, $fechaF." ".substr($reposicion["hora_nueva"],0, 5)." a ".substr($reposicion["hora_nueva_fin"],0, 5)); - - if($reposicion["salon_id"] != ""){ - $salon_json = json_decode($reposicion["salon_array"], true); - $sheet->setCellValue('H'.$row, $salon_json[count($salon_json)-1]); - }else - $sheet->setCellValue('H'.$row, "Pendiente"); - $row++; - - }//foreach - - }//if - foreach ($sheet->getColumnIterator() as $column) { - $sheet->getColumnDimension($column->getColumnIndex())->setAutoSize(true); - } - $sheet->setAutoFilter('A'.$row_base.':H'.$row_base); - $i++; -} -$spreadsheet->setActiveSheetIndex(0); - - - -$writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); +query('SELECT * FROM fs_estado_reposicion' ); + +$repoParams = array(); + +$user = Login::get_user(); +$user->access(); +$query=""; +if($user->rol["rol_id"] == 9){//es coordinador + $query .= ":facultad, "; + $repoParams[":facultad"] = $user->facultad["facultad_id"]; +}else{//supervisor + $query .= "NULL, "; +} +if(isset($_POST["prof"]) ){ + $query .= ":prof,"; + $profesor = trim($_POST["prof"]);//limpia texto + $repoParams[":prof"] = $profesor; +}else{ + $query .= "NULL,"; +} +$query .= ":f_ini, :f_fin, "; +$repoParams[":f_ini"] = DateTime::createFromFormat('d/m/Y', $fecha_ini)->format('Y-m-d'); +$repoParams[":f_fin"] = DateTime::createFromFormat('d/m/Y', $fecha_fin)->format('Y-m-d'); + +$spreadsheet = new Spreadsheet(); + +// Set document properties +$spreadsheet->getProperties()->setCreator('Universidad La Salle') + ->setLastModifiedBy('Universidad La Salle') + ->setTitle('Solicitudes') + ->setDescription('Reporte de solicitudes.'); + +$headerStyle = + [ + 'fill' => [ + 'fillType' => Fill::FILL_SOLID, + 'color' => ['argb' => 'FF001d68'], + ], + 'borders' => [ + 'bottom' => ['borderStyle' => Border::BORDER_THIN], + 'right' => ['borderStyle' => Border::BORDER_MEDIUM], + ], + 'font' => [ + 'bold' => true, + 'color' => ['argb' => 'FFFFFFFF'], + ] + ]; + +$row_base = 6; + +$i=0; +foreach($repEdo_rs as $redo){ + $row = $row_base; + if($i >= $spreadsheet->getSheetCount()){ + $spreadsheet->createSheet(); + } + $spreadsheet->setActiveSheetIndex($i); + //crea imagen + $drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\Drawing(); + $drawing->setName('La Salle'); + $drawing->setDescription('La Salle'); + $drawing->setPath('../imagenes/logo.png'); // put your path and image here + $drawing->setCoordinates('A1'); + $drawing->setHeight(100); + $drawing->setOffsetX(10); + //agrega imagen + $drawing->setWorksheet($spreadsheet->getActiveSheet()); + + $spreadsheet->getActiveSheet() + ->setCellValue('A'.$row, 'Estado') + ->setCellValue('B'.$row, 'Tipo') + ->setCellValue('C'.$row, 'Profesor') + ->setCellValue('D'.$row, 'Materia') + ->setCellValue('E'.$row, 'Grupo') + ->setCellValue('F'.$row, 'Fecha falta') + ->setCellValue('G'.$row, 'Fecha reposici贸n') + ->setCellValue('H'.$row, 'Sal贸n'); + + $spreadsheet->getActiveSheet()->getStyle('A'.$row.':H'.$row)->applyFromArray($headerStyle); + $repoParams[":edo"]=$redo["estado_reposicion_id"]; + if($user->rol["rol_id"] == 7){//es supervisor + $repoParams[":sup"] = $user->user["id"]; + $solicitudes_rs = $db->query('SELECT * FROM fs_solicitud(NULL, '.$query.':edo, NULL, :sup) ', $repoParams ); + }else{ + $solicitudes_rs = $db->query('SELECT * FROM fs_solicitud(NULL, '.$query.':edo, NULL, NULL) ', $repoParams ); + } + + $row++; + $sheet = $spreadsheet->getActiveSheet(); + $sheet->setTitle($redo["estado_nombre"]); + if(isset($solicitudes_rs) && count($solicitudes_rs)>0){ + foreach($solicitudes_rs as $reposicion){ + + + $sheet->setCellValue('A'.$row, $reposicion["estado_nombre"]); + $sheet->setCellValue('B'.$row, $reposicion["solicitudtipo_nombre"]); + $sheet->setCellValue('C'.$row, $reposicion["profesor_clave"]." - ".$reposicion["profesor_nombre"]); + $sheet->setCellValue('D'.$row, $reposicion["materia_nombre"]); + if($reposicion["horario_grupo"]!="") + $sheet->setCellValue('E'.$row, $reposicion["horario_grupo"]); + + if($reposicion["fecha_clase"]!=""){ + $fechaI = DateTime::createFromFormat('Y-m-d', $reposicion["fecha_nueva"])->format('d/m/Y'); + $sheet->setCellValue('F'.$row, $fechaI." ".substr($reposicion["horario_hora"],0, 5)); + } + + $fechaF = date("d/m/Y", strtotime($reposicion["fecha_nueva"])); + $sheet->setCellValue('G'.$row, $fechaF." ".substr($reposicion["hora_nueva"],0, 5)." a ".substr($reposicion["hora_nueva_fin"],0, 5)); + + if($reposicion["salon_id"] != ""){ + $salon_json = json_decode($reposicion["salon_array"], true); + $sheet->setCellValue('H'.$row, $salon_json[count($salon_json)-1]); + }else + $sheet->setCellValue('H'.$row, "Pendiente"); + $row++; + + }//foreach + + }//if + foreach ($sheet->getColumnIterator() as $column) { + $sheet->getColumnDimension($column->getColumnIndex())->setAutoSize(true); + } + $sheet->setAutoFilter('A'.$row_base.':H'.$row_base); + $i++; +} +$spreadsheet->setActiveSheetIndex(0); + + + +$writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); $writer->save('php://output'); \ No newline at end of file diff --git a/horarios_historicos.php b/horarios_historicos.php index 6dad736..10dc2ec 100644 --- a/horarios_historicos.php +++ b/horarios_historicos.php @@ -1,208 +1,208 @@ - - - - - - - - Hist贸rico de horarios - - - - - - - - - - periodo_id) { ?> - - - - - - -
- - -
- -
-
-
-
- - - - - -
-
-
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - -
- Carrera - - Materia - - Grupo - - Horario - - Alta - - Baja -
- - {{horario.facultad_nombre}} - - {{horario.carrera_nombre}} - - {{horario.materia_nombre}} - - {{horario.horario_grupo}} - - {{d铆as[horario.horario_dia]}} - {{horario.horario_hora}} - {{horario.horario_fin}} - - {{horario.horario_fecha_inicio}} - - {{horario.horario_fecha_fin}} -
-
- - - - -
- - - - - - + + + + + + + + Hist贸rico de horarios + + + + + + + + + + periodo_id) { ?> + + + + + + +
+ + +
+ +
+
+
+
+ + + + + +
+
+
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ Carrera + + Materia + + Grupo + + Horario + + Alta + + Baja +
+ + {{horario.facultad_nombre}} + + {{horario.carrera_nombre}} + + {{horario.materia_nombre}} + + {{horario.horario_grupo}} + + {{d铆as[horario.horario_dia]}} - {{horario.horario_hora}} - {{horario.horario_fin}} + + {{horario.horario_fecha_inicio}} + + {{horario.horario_fecha_fin}} +
+
+ + + + +
+ + + + + + \ No newline at end of file diff --git a/include/constantes.php b/include/constantes.php index 81a554e..d45147d 100644 --- a/include/constantes.php +++ b/include/constantes.php @@ -1,146 +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$"); +'', + "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/db/postgrest.conf b/include/db/postgrest.conf index 80e930d..f1a1392 100644 --- a/include/db/postgrest.conf +++ b/include/db/postgrest.conf @@ -1,20 +1,20 @@ -# postgrest.conf - -# The standard connection URI format, documented at -# https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING -db-uri = "postgres://postgres:4ud1t0rf4lt4$$@localhost:5432/paad_pruebas" - -# The database role to use when no client authentication is provided. -# Should differ from authenticator -db-anon-role = "postgres" - -# The secret to verify the JWT for authenticated requests with. -# Needs to be 32 characters minimum. -jwt-secret = "reallyreallyreallyreallyverysafe" -jwt-secret-is-base64 = false - -# Port the postgrest process is listening on for http requests -server-port = 3000 - -# the location root is /api +# postgrest.conf + +# The standard connection URI format, documented at +# https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING +db-uri = "postgres://postgres:4ud1t0rf4lt4$$@localhost:5432/paad_pruebas" + +# The database role to use when no client authentication is provided. +# Should differ from authenticator +db-anon-role = "postgres" + +# The secret to verify the JWT for authenticated requests with. +# Needs to be 32 characters minimum. +jwt-secret = "reallyreallyreallyreallyverysafe" +jwt-secret-is-base64 = false + +# Port the postgrest process is listening on for http requests +server-port = 3000 + +# the location root is /api server-host = "*" \ No newline at end of file diff --git a/include/fun_fecha.php b/include/fun_fecha.php index baa85b3..cfcd33d 100644 --- a/include/fun_fecha.php +++ b/include/fun_fecha.php @@ -1,55 +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)]; -} +"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/phpmailer/PHPMailerAutoload.php b/include/phpmailer/PHPMailerAutoload.php index 60f9ad7..8d3dcba 100644 --- a/include/phpmailer/PHPMailerAutoload.php +++ b/include/phpmailer/PHPMailerAutoload.php @@ -1,50 +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); - }*/ -} + + * @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 index 3cda98d..d6daaed 100644 --- a/include/phpmailer/class.phpmailer.php +++ b/include/phpmailer/class.phpmailer.php @@ -1,3884 +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; - } -} + + * @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 index 2e32e2f..9204734 100644 --- a/include/phpmailer/class.smtp.php +++ b/include/phpmailer/class.smtp.php @@ -1,1181 +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; - } -} + + * @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 index 1aceb86..1e158f9 100644 --- a/include/util.php +++ b/include/util.php @@ -1,127 +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); +"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/js/auditor铆a.js b/js/auditor铆a.js index d8a5a83..b8143ca 100644 --- a/js/auditor铆a.js +++ b/js/auditor铆a.js @@ -1,352 +1,352 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; -$('div.modal#cargando').modal({ - backdrop: 'static', - keyboard: false, - show: false, -}); -const store = reactive({ - loading: false, - perido: null, - current: { - comentario: '', - clase_vista: null, - empty: '', - page: 1, - maxPages: 10, - perPage: 10, - modal_state: "Cargando datos...", - justificada: null, - fechas_clicked: false, - observaciones: false, - }, - 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, - periodo_id: null, - bloque_horario: null, - estados: [], - switchFecha: false, - async switchFechas() { - const periodo = await fetch('action/periodo_datos.php'); - const periodo_data = await periodo.json(); - if (!store.filters.switchFecha) { - $('div.modal#cargando').modal('show'); - await store.registros.fetch(); - $('div.modal#cargando').modal('hide'); - } - $(function () { - store.filters.fecha_inicio = store.filters.fecha_fin = store.filters.fecha = null; - $("#fecha, #fecha_inicio, #fecha_fin").datepicker({ - minDate: new Date(`${periodo_data.periodo_fecha_inicio}:00:00:00`), - maxDate: new Date(`${periodo_data.fecha_final}:00:00:00`), - dateFormat: "yy-mm-dd", - showAnim: "slide", - beforeShowDay: (date) => [(date.getDay() != 0), ""] - }); - const fecha = $("#fecha"), inicio = $("#fecha_inicio"), fin = $("#fecha_fin"); - fecha.datepicker("setDate", new Date(`${periodo_data.fecha_final}:00:00:00`)); - inicio.on("change", function () { - store.current.fechas_clicked = false; - store.filters.fecha_inicio = inicio.val(); - fin.datepicker("option", "minDate", inicio.val()); - }); - fin.on("change", function () { - store.current.fechas_clicked = false; - store.filters.fecha_fin = fin.val(); - inicio.datepicker("option", "maxDate", fin.val()); - }); - fecha.on("change", async function () { - store.filters.fecha = fecha.val(); - $('div.modal#cargando').modal('show'); - await store.registros.fetch(store.filters.fecha); - $('div.modal#cargando').modal('hide'); - }); - }); - }, - async fetchByDate() { - store.current.fechas_clicked = true; - $('div.modal#cargando').modal('show'); - await store.registros.fetch(undefined, store.filters.fecha_inicio, store.filters.fecha_fin); - store.current.page = 1; - $('div.modal#cargando').modal('hide'); - } - }, - 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) ?? { - estado_color: 'dark', - estado_icon: 'ing-cancelar', - nombre: 'Sin registro', - estado_supervisor_id: -1, - }; - }, - 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`; - } - }, - bloques_horario: { - data: [], - async fetch() { - this.data = []; - const res = await fetch('action/action_grupo_horario.php'); - this.data = await res.json(); - if (this.data.every((bloque) => !bloque.selected)) - this.data[0].selected = true; - }, - }, - 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 + 1)) { - setTimeout(() => { - document.querySelectorAll('#dlAsistencia>ul>li.selected').forEach(element => element.classList.remove('selected')); - }, 100); - return []; - } - return newArray; - }, - async justificar() { - if (!store.current.justificada) - return; - store.current.justificada.registro_justificada = true; - let data; - try { - const res = await fetch('action/justificar.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(store.current.justificada) - }); - data = await res.json(); - } - catch (error) { - alert('Error al justificar'); - store.current.justificada = store.current.clone_justificada; - } - finally { - delete store.current.clone_justificada; - } - store.current.justificada.justificador_nombre = data.justificador_nombre; - store.current.justificada.justificador_clave = data.justificador_clave; - store.current.justificada.justificador_facultad = data.justificador_facultad; - store.current.justificada.justificador_rol = data.justificador_rol; - store.current.justificada.registro_fecha_justificacion = data.registro_fecha_justificacion; - }, - async justificarBloque(fecha, bloques, justificacion) { - if (bloques.length === 0) { - alert('No se ha seleccionado ning煤n bloque'); - return; - } - if (!justificacion) { - alert('No se ha ingresado ninguna observaci贸n'); - return; - } - try { - const res = await fetch('action/action_justificar.php', { - method: 'PUT', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - fecha, - bloques, - justificacion, - }) - }); - const resData = await res.json(); - if (resData.status === 'success') { - alert('Se ha justificado el bloque'); - store.current.modal_state = 'Cargando datos...'; - $('div.modal#cargando').modal('show'); - await store.registros.fetch(); - $('div.modal#cargando').modal('hide'); - } - else { - alert('No se ha podido justificar el bloque'); - } - } - catch (error) { - alert('Error al justificar'); - } - }, - registros: { - data: [], - async fetch(fecha, fecha_inicio, fecha_fin) { - // if (!store.filters.facultad_id || !store.filters.periodo_id) return - this.loading = true; - this.data = []; - const params = {}; - if (fecha) - params['fecha'] = fecha; - if (fecha_inicio) - params['fecha_inicio'] = fecha_inicio; - if (fecha_fin) - params['fecha_fin'] = fecha_fin; - params['periodo_id'] = store.filters.todos_los_periodos ? 0 : store.periodo.periodo_id; - console.log(store.periodo); - const paramsUrl = new URLSearchParams(params).toString(); - try { - const res = await fetch(`action/action_auditoria.php?${paramsUrl}`, { - method: 'GET', - }); - this.data = await res.json(); - } - catch (error) { - alert('Error al cargar los datos'); - } - this.loading = false; - store.current.page = 1; - }, - 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] !== null || 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; - else if (store.filters[filtro].includes(-1) && registro.estado_supervisor_id === null) - return true; - return store.filters[filtro].includes(registro.estado_supervisor_id); - case 'bloque_horario': - const bloque = store.bloques_horario.data.find((bloque) => bloque.id === store.filters[filtro]); - return registro.horario_hora < bloque.hora_fin && registro.horario_fin > bloque.hora_inicio; - default: return true; - } - }); - }); - }, - async descargar() { - store.current.modal_state = 'Generando reporte en Excel...'; - $('div.modal#cargando').modal('show'); - this.loading = true; - if (this.relevant.length === 0) - return; - try { - const res = await fetch('export/supervisor_excel.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(this.relevant) - }); - const blob = await res.blob(); - window.saveAs(blob, `auditoria_${new Date().toISOString().slice(0, 10)}.xlsx`); - } - catch (error) { - if (error.response && error.response.status === 413) { - alert('Your request is too large! Please reduce the data size and try again.'); - } - else { - alert('An error occurred: ' + error.message); - } - } - finally { - $('#cargando').modal('hide'); - this.loading = false; - } - }, - loading: false, - get pages() { - return Math.ceil(this.relevant.length / store.current.perPage); - } - }, -}); -createApp({ - store, - messages: [], - get clase_vista() { - return store.current.clase_vista; - }, - set_justificar(horario_id, profesor_id, registro_fecha_ideal) { - store.current.justificada = store.registros.relevant.find((registro) => registro.horario_id === horario_id && registro.profesor_id === profesor_id && registro.registro_fecha_ideal === registro_fecha_ideal); - store.current.clone_justificada = JSON.parse(JSON.stringify(store.current.justificada)); - store.current.observaciones = false; - }, - cancelar_justificacion() { - Object.assign(store.current.justificada, store.current.clone_justificada); - delete store.current.clone_justificada; - }, - profesores: [], - async mounted() { - $('div.modal#cargando').modal('show'); - try { - store.periodo = await fetch('action/periodo_datos.php').then(res => res.json()); - // await store.registros.fetch() - await store.facultades.fetch(); - await store.estados.fetch(); - await store.bloques_horario.fetch(); - await store.filters.switchFechas(); - this.profesores = await (await fetch('action/action_profesor.php')).json(); - this.messages.push({ title: 'Datos cargados', text: 'Los datos se han cargado correctamente', type: 'success', timestamp: new Date() }); - } - catch (error) { - this.messages.push({ title: 'Error al cargar datos', text: 'No se pudieron cargar los datos', type: 'danger', timestamp: new Date() }); - } - finally { - $('div.modal#cargando').modal('hide'); - } - } -}).mount('#app'); +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; +$('div.modal#cargando').modal({ + backdrop: 'static', + keyboard: false, + show: false, +}); +const store = reactive({ + loading: false, + perido: null, + current: { + comentario: '', + clase_vista: null, + empty: '', + page: 1, + maxPages: 10, + perPage: 10, + modal_state: "Cargando datos...", + justificada: null, + fechas_clicked: false, + observaciones: false, + }, + 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, + periodo_id: null, + bloque_horario: null, + estados: [], + switchFecha: false, + async switchFechas() { + const periodo = await fetch('action/periodo_datos.php'); + const periodo_data = await periodo.json(); + if (!store.filters.switchFecha) { + $('div.modal#cargando').modal('show'); + await store.registros.fetch(); + $('div.modal#cargando').modal('hide'); + } + $(function () { + store.filters.fecha_inicio = store.filters.fecha_fin = store.filters.fecha = null; + $("#fecha, #fecha_inicio, #fecha_fin").datepicker({ + minDate: new Date(`${periodo_data.periodo_fecha_inicio}:00:00:00`), + maxDate: new Date(`${periodo_data.fecha_final}:00:00:00`), + dateFormat: "yy-mm-dd", + showAnim: "slide", + beforeShowDay: (date) => [(date.getDay() != 0), ""] + }); + const fecha = $("#fecha"), inicio = $("#fecha_inicio"), fin = $("#fecha_fin"); + fecha.datepicker("setDate", new Date(`${periodo_data.fecha_final}:00:00:00`)); + inicio.on("change", function () { + store.current.fechas_clicked = false; + store.filters.fecha_inicio = inicio.val(); + fin.datepicker("option", "minDate", inicio.val()); + }); + fin.on("change", function () { + store.current.fechas_clicked = false; + store.filters.fecha_fin = fin.val(); + inicio.datepicker("option", "maxDate", fin.val()); + }); + fecha.on("change", async function () { + store.filters.fecha = fecha.val(); + $('div.modal#cargando').modal('show'); + await store.registros.fetch(store.filters.fecha); + $('div.modal#cargando').modal('hide'); + }); + }); + }, + async fetchByDate() { + store.current.fechas_clicked = true; + $('div.modal#cargando').modal('show'); + await store.registros.fetch(undefined, store.filters.fecha_inicio, store.filters.fecha_fin); + store.current.page = 1; + $('div.modal#cargando').modal('hide'); + } + }, + 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) ?? { + estado_color: 'dark', + estado_icon: 'ing-cancelar', + nombre: 'Sin registro', + estado_supervisor_id: -1, + }; + }, + 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`; + } + }, + bloques_horario: { + data: [], + async fetch() { + this.data = []; + const res = await fetch('action/action_grupo_horario.php'); + this.data = await res.json(); + if (this.data.every((bloque) => !bloque.selected)) + this.data[0].selected = true; + }, + }, + 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 + 1)) { + setTimeout(() => { + document.querySelectorAll('#dlAsistencia>ul>li.selected').forEach(element => element.classList.remove('selected')); + }, 100); + return []; + } + return newArray; + }, + async justificar() { + if (!store.current.justificada) + return; + store.current.justificada.registro_justificada = true; + let data; + try { + const res = await fetch('action/justificar.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(store.current.justificada) + }); + data = await res.json(); + } + catch (error) { + alert('Error al justificar'); + store.current.justificada = store.current.clone_justificada; + } + finally { + delete store.current.clone_justificada; + } + store.current.justificada.justificador_nombre = data.justificador_nombre; + store.current.justificada.justificador_clave = data.justificador_clave; + store.current.justificada.justificador_facultad = data.justificador_facultad; + store.current.justificada.justificador_rol = data.justificador_rol; + store.current.justificada.registro_fecha_justificacion = data.registro_fecha_justificacion; + }, + async justificarBloque(fecha, bloques, justificacion) { + if (bloques.length === 0) { + alert('No se ha seleccionado ning煤n bloque'); + return; + } + if (!justificacion) { + alert('No se ha ingresado ninguna observaci贸n'); + return; + } + try { + const res = await fetch('action/action_justificar.php', { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + fecha, + bloques, + justificacion, + }) + }); + const resData = await res.json(); + if (resData.status === 'success') { + alert('Se ha justificado el bloque'); + store.current.modal_state = 'Cargando datos...'; + $('div.modal#cargando').modal('show'); + await store.registros.fetch(); + $('div.modal#cargando').modal('hide'); + } + else { + alert('No se ha podido justificar el bloque'); + } + } + catch (error) { + alert('Error al justificar'); + } + }, + registros: { + data: [], + async fetch(fecha, fecha_inicio, fecha_fin) { + // if (!store.filters.facultad_id || !store.filters.periodo_id) return + this.loading = true; + this.data = []; + const params = {}; + if (fecha) + params['fecha'] = fecha; + if (fecha_inicio) + params['fecha_inicio'] = fecha_inicio; + if (fecha_fin) + params['fecha_fin'] = fecha_fin; + params['periodo_id'] = store.filters.todos_los_periodos ? 0 : store.periodo.periodo_id; + console.log(store.periodo); + const paramsUrl = new URLSearchParams(params).toString(); + try { + const res = await fetch(`action/action_auditoria.php?${paramsUrl}`, { + method: 'GET', + }); + this.data = await res.json(); + } + catch (error) { + alert('Error al cargar los datos'); + } + this.loading = false; + store.current.page = 1; + }, + 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] !== null || 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; + else if (store.filters[filtro].includes(-1) && registro.estado_supervisor_id === null) + return true; + return store.filters[filtro].includes(registro.estado_supervisor_id); + case 'bloque_horario': + const bloque = store.bloques_horario.data.find((bloque) => bloque.id === store.filters[filtro]); + return registro.horario_hora < bloque.hora_fin && registro.horario_fin > bloque.hora_inicio; + default: return true; + } + }); + }); + }, + async descargar() { + store.current.modal_state = 'Generando reporte en Excel...'; + $('div.modal#cargando').modal('show'); + this.loading = true; + if (this.relevant.length === 0) + return; + try { + const res = await fetch('export/supervisor_excel.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(this.relevant) + }); + const blob = await res.blob(); + window.saveAs(blob, `auditoria_${new Date().toISOString().slice(0, 10)}.xlsx`); + } + catch (error) { + if (error.response && error.response.status === 413) { + alert('Your request is too large! Please reduce the data size and try again.'); + } + else { + alert('An error occurred: ' + error.message); + } + } + finally { + $('#cargando').modal('hide'); + this.loading = false; + } + }, + loading: false, + get pages() { + return Math.ceil(this.relevant.length / store.current.perPage); + } + }, +}); +createApp({ + store, + messages: [], + get clase_vista() { + return store.current.clase_vista; + }, + set_justificar(horario_id, profesor_id, registro_fecha_ideal) { + store.current.justificada = store.registros.relevant.find((registro) => registro.horario_id === horario_id && registro.profesor_id === profesor_id && registro.registro_fecha_ideal === registro_fecha_ideal); + store.current.clone_justificada = JSON.parse(JSON.stringify(store.current.justificada)); + store.current.observaciones = false; + }, + cancelar_justificacion() { + Object.assign(store.current.justificada, store.current.clone_justificada); + delete store.current.clone_justificada; + }, + profesores: [], + async mounted() { + $('div.modal#cargando').modal('show'); + try { + store.periodo = await fetch('action/periodo_datos.php').then(res => res.json()); + // await store.registros.fetch() + await store.facultades.fetch(); + await store.estados.fetch(); + await store.bloques_horario.fetch(); + await store.filters.switchFechas(); + this.profesores = await (await fetch('action/action_profesor.php')).json(); + this.messages.push({ title: 'Datos cargados', text: 'Los datos se han cargado correctamente', type: 'success', timestamp: new Date() }); + } + catch (error) { + this.messages.push({ title: 'Error al cargar datos', text: 'No se pudieron cargar los datos', type: 'danger', timestamp: new Date() }); + } + finally { + $('div.modal#cargando').modal('hide'); + } + } +}).mount('#app'); diff --git a/js/avisos.js b/js/avisos.js index 4713b43..5d83c3c 100644 --- a/js/avisos.js +++ b/js/avisos.js @@ -1,148 +1,148 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; -const new_aviso = reactive({ - titulo: '', - descripcion: '', - fechaInicio: '', - fechaFin: '', - profesores: [], - carreras: [], - reset() { - this.titulo = ''; - this.descripcion = ''; - this.fechaInicio = ''; - this.fechaFin = ''; - this.profesores = []; - this.carreras = []; - }, - get isValid() { - return this.titulo !== '' && this.descripcion !== '' && this.fechaInicio !== '' && this.fechaFin !== '' && (this.profesores.length > 0 || this.carreras.length > 0) && this.facultad_id !== null; - }, -}); -// define datepicker method -const app = createApp({ - new_aviso, - profesores: [], - carreras: [], - avisos: [], - profesor: null, - formatProfesor(profesor) { - return `(${profesor.profesor_clave}) ${profesor.profesor_nombre}`; - }, - addProfesor() { - const profesorObj = this.profesores.find((profesor) => this.profesor === this.formatProfesor(profesor)); - if (profesorObj) { - this.new_aviso.profesores.push(profesorObj); - this.profesor = null; - } - }, - aviso_shown: null, - // int? - aviso_suspendido: null, - suspenderAviso() { - if (this.aviso_suspendido) { - const aviso = this.avisos.find((aviso) => aviso.aviso_id === this.aviso_suspendido); - if (aviso) { - this.deleteAviso(aviso); - } - } - }, - get relevant_profesores() { - // not in array new_aviso.profesores - const relevant = this.profesores.filter((profesor) => !this.new_aviso.profesores.map((profesor) => profesor.profesor_id).includes(profesor.profesor_id)); - // console.log('profesores:', this.profesores.map((profesor: Profesor) => profesor.profesor_nombre), 'relevant:', relevant.map((profesor: Profesor) => profesor.profesor_nombre), 'new_aviso:', this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_nombre)) - return relevant; - }, - get relevant_carreras() { - // not in array new_aviso.carreras - return this.carreras.filter((carrera) => !this.new_aviso.carreras.includes(carrera)); - }, - createAviso() { - const data = { - aviso_titulo: this.new_aviso.titulo, - aviso_texto: this.new_aviso.descripcion, - aviso_fecha_inicial: this.new_aviso.fechaInicio, - aviso_fecha_final: this.new_aviso.fechaFin, - profesores: this.new_aviso.profesores.map((profesor) => profesor.profesor_id), - carreras: this.new_aviso.carreras.map((carrera) => carrera.carrera_id), - }; - fetch('/action/avisos.php', { - method: 'POST', - body: JSON.stringify(data) - }).then(res => res.json()).then(res => { - if (res.success) { - // hydrate with carreras and profesores - this.avisos.push({ - ...data, - carreras: this.carreras.filter((carrera) => data.carreras.includes(carrera.carrera_id)), - profesores: this.profesores.filter((profesor) => data.profesores.includes(profesor.profesor_id)), - aviso_estado: true, - aviso_id: res.aviso_id, - }); - this.new_aviso.reset(); - } - else { - alert(res.error); - console.log(res.errors); - } - }); - }, - deleteAviso(aviso) { - fetch(`/action/avisos.php`, { - method: 'DELETE', - body: JSON.stringify({ aviso_id: aviso.aviso_id }) - }).then(res => res.json()).then(res => { - if (res.success) { - this.avisos = this.avisos.filter((aviso) => aviso.aviso_id !== this.aviso_suspendido); - this.aviso_suspendido = null; - } - else { - alert(res.error); - console.log(res.errors); - } - }); - }, - updateAviso() { - fetch(`/action/avisos.php`, { - method: 'PUT', - body: JSON.stringify({ - aviso_id: this.aviso_shown.aviso_id, - aviso_fecha_final: this.aviso_shown.aviso_fecha_final, - }) - }).then(res => res.json()).then(res => { - if (res.success) { - } - else { - alert(res.error); - console.log(res.errors); - } - }); - }, - async initializeDatepickers($el) { - const periodo = await fetch('action/periodo_datos.php'); - const periodo_data = await periodo.json(); - $('.date-picker').datepicker({ - dateFormat: 'yy-mm-dd', - maxDate: periodo_data.periodo_fecha_fin, - minDate: 0, - }); - $($el).on('change', () => { - this.aviso_shown.aviso_fecha_final = $($el).val(); - }); - }, - async mounted() { - this.avisos = await fetch("/action/avisos.php").then(res => res.json()); - this.profesores = await fetch('/action/action_profesor.php').then(res => res.json()); - this.carreras = await fetch('/action/action_carreras.php').then(res => res.json()); - await this.initializeDatepickers(); - const fechaInicio = $('#fechaInicio.date-picker'); - const fechaFin = $('#fechaFin.date-picker'); - fechaInicio.on("change", function () { - new_aviso.fechaInicio = fechaInicio.val(); - fechaFin.datepicker("option", "minDate", fechaInicio.val()); - }); - fechaFin.on("change", function () { - new_aviso.fechaFin = fechaFin.val(); - fechaInicio.datepicker("option", "maxDate", fechaFin.val()); - }); - } -}).mount('#app'); +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; +const new_aviso = reactive({ + titulo: '', + descripcion: '', + fechaInicio: '', + fechaFin: '', + profesores: [], + carreras: [], + reset() { + this.titulo = ''; + this.descripcion = ''; + this.fechaInicio = ''; + this.fechaFin = ''; + this.profesores = []; + this.carreras = []; + }, + get isValid() { + return this.titulo !== '' && this.descripcion !== '' && this.fechaInicio !== '' && this.fechaFin !== '' && (this.profesores.length > 0 || this.carreras.length > 0) && this.facultad_id !== null; + }, +}); +// define datepicker method +const app = createApp({ + new_aviso, + profesores: [], + carreras: [], + avisos: [], + profesor: null, + formatProfesor(profesor) { + return `(${profesor.profesor_clave}) ${profesor.profesor_nombre}`; + }, + addProfesor() { + const profesorObj = this.profesores.find((profesor) => this.profesor === this.formatProfesor(profesor)); + if (profesorObj) { + this.new_aviso.profesores.push(profesorObj); + this.profesor = null; + } + }, + aviso_shown: null, + // int? + aviso_suspendido: null, + suspenderAviso() { + if (this.aviso_suspendido) { + const aviso = this.avisos.find((aviso) => aviso.aviso_id === this.aviso_suspendido); + if (aviso) { + this.deleteAviso(aviso); + } + } + }, + get relevant_profesores() { + // not in array new_aviso.profesores + const relevant = this.profesores.filter((profesor) => !this.new_aviso.profesores.map((profesor) => profesor.profesor_id).includes(profesor.profesor_id)); + // console.log('profesores:', this.profesores.map((profesor: Profesor) => profesor.profesor_nombre), 'relevant:', relevant.map((profesor: Profesor) => profesor.profesor_nombre), 'new_aviso:', this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_nombre)) + return relevant; + }, + get relevant_carreras() { + // not in array new_aviso.carreras + return this.carreras.filter((carrera) => !this.new_aviso.carreras.includes(carrera)); + }, + createAviso() { + const data = { + aviso_titulo: this.new_aviso.titulo, + aviso_texto: this.new_aviso.descripcion, + aviso_fecha_inicial: this.new_aviso.fechaInicio, + aviso_fecha_final: this.new_aviso.fechaFin, + profesores: this.new_aviso.profesores.map((profesor) => profesor.profesor_id), + carreras: this.new_aviso.carreras.map((carrera) => carrera.carrera_id), + }; + fetch('/action/avisos.php', { + method: 'POST', + body: JSON.stringify(data) + }).then(res => res.json()).then(res => { + if (res.success) { + // hydrate with carreras and profesores + this.avisos.push({ + ...data, + carreras: this.carreras.filter((carrera) => data.carreras.includes(carrera.carrera_id)), + profesores: this.profesores.filter((profesor) => data.profesores.includes(profesor.profesor_id)), + aviso_estado: true, + aviso_id: res.aviso_id, + }); + this.new_aviso.reset(); + } + else { + alert(res.error); + console.log(res.errors); + } + }); + }, + deleteAviso(aviso) { + fetch(`/action/avisos.php`, { + method: 'DELETE', + body: JSON.stringify({ aviso_id: aviso.aviso_id }) + }).then(res => res.json()).then(res => { + if (res.success) { + this.avisos = this.avisos.filter((aviso) => aviso.aviso_id !== this.aviso_suspendido); + this.aviso_suspendido = null; + } + else { + alert(res.error); + console.log(res.errors); + } + }); + }, + updateAviso() { + fetch(`/action/avisos.php`, { + method: 'PUT', + body: JSON.stringify({ + aviso_id: this.aviso_shown.aviso_id, + aviso_fecha_final: this.aviso_shown.aviso_fecha_final, + }) + }).then(res => res.json()).then(res => { + if (res.success) { + } + else { + alert(res.error); + console.log(res.errors); + } + }); + }, + async initializeDatepickers($el) { + const periodo = await fetch('action/periodo_datos.php'); + const periodo_data = await periodo.json(); + $('.date-picker').datepicker({ + dateFormat: 'yy-mm-dd', + maxDate: periodo_data.periodo_fecha_fin, + minDate: 0, + }); + $($el).on('change', () => { + this.aviso_shown.aviso_fecha_final = $($el).val(); + }); + }, + async mounted() { + this.avisos = await fetch("/action/avisos.php").then(res => res.json()); + this.profesores = await fetch('/action/action_profesor.php').then(res => res.json()); + this.carreras = await fetch('/action/action_carreras.php').then(res => res.json()); + await this.initializeDatepickers(); + const fechaInicio = $('#fechaInicio.date-picker'); + const fechaFin = $('#fechaFin.date-picker'); + fechaInicio.on("change", function () { + new_aviso.fechaInicio = fechaInicio.val(); + fechaFin.datepicker("option", "minDate", fechaInicio.val()); + }); + fechaFin.on("change", function () { + new_aviso.fechaFin = fechaFin.val(); + fechaInicio.datepicker("option", "maxDate", fechaFin.val()); + }); + } +}).mount('#app'); diff --git a/js/bootstrap/bootstrap.bundle.min.js b/js/bootstrap/bootstrap.bundle.min.js index 72a46cf..92f9c27 100644 --- a/js/bootstrap/bootstrap.bundle.min.js +++ b/js/bootstrap/bootstrap.bundle.min.js @@ -1,7 +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||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]||tthis._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=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=$,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!q(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!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],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,y=t(e.instance.popper),w=parseFloat(y['margin'+f],10),E=parseFloat(y['border'+f+'Width'],10),v=b-e.offsets.popper[m]-w-E;return v=J(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,Z(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case he.FLIP:p=[n,i];break;case he.CLOCKWISE:p=G(n);break;case he.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=$,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,y=-1!==['top','bottom'].indexOf(n),w=!!t.flipVariations&&(y&&'start'===r&&h||y&&'end'===r&&c||!y&&'start'===r&&g||!y&&'end'===r&&u);(m||b||w)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),w&&(r=K(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,D(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!q(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=C(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.right=o.clientWidth&&n>=o.clientHeight}),l=0a[e]&&!t.escapeWithReference&&(n=Q(f[o],a[e]-('right'===e?f.width:f.height))),ae({},o,n)}};return l.forEach(function(e){var t=-1===['left','top'].indexOf(e)?'secondary':'primary';f=le({},f,m[t](e))}),e.offsets.popper=f,e},priority:['left','right','top','bottom'],padding:5,boundariesElement:'scrollParent'},keepTogether:{order:400,enabled:!0,fn:function(e){var t=e.offsets,o=t.popper,n=t.reference,i=e.placement.split('-')[0],r=$,p=-1!==['top','bottom'].indexOf(i),s=p?'right':'bottom',d=p?'left':'top',a=p?'width':'height';return o[s]r(n[s])&&(e.offsets.popper[d]=r(n[s])),e}},arrow:{order:500,enabled:!0,fn:function(e,o){var n;if(!q(e.instance.modifiers,'arrow','keepTogether'))return e;var i=o.element;if('string'==typeof i){if(i=e.instance.popper.querySelector(i),!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],p=e.offsets,s=p.popper,d=p.reference,a=-1!==['left','right'].indexOf(r),l=a?'height':'width',f=a?'Top':'Left',m=f.toLowerCase(),h=a?'left':'top',c=a?'bottom':'right',u=S(i)[l];d[c]-us[c]&&(e.offsets.popper[m]+=d[m]+u-s[c]),e.offsets.popper=g(e.offsets.popper);var b=d[m]+d[l]/2-u/2,y=t(e.instance.popper),w=parseFloat(y['margin'+f],10),E=parseFloat(y['border'+f+'Width'],10),v=b-e.offsets.popper[m]-w-E;return v=J(Q(s[l]-u,v),0),e.arrowElement=i,e.offsets.arrow=(n={},ae(n,m,Z(v)),ae(n,h,''),n),e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=v(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement,e.positionFixed),n=e.placement.split('-')[0],i=T(n),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case he.FLIP:p=[n,i];break;case he.CLOCKWISE:p=G(n);break;case he.COUNTERCLOCKWISE:p=G(n,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(n!==s||p.length===d+1)return e;n=e.placement.split('-')[0],i=T(n);var a=e.offsets.popper,l=e.offsets.reference,f=$,m='left'===n&&f(a.right)>f(l.left)||'right'===n&&f(a.left)f(l.top)||'bottom'===n&&f(a.top)f(o.right),g=f(a.top)f(o.bottom),b='left'===n&&h||'right'===n&&c||'top'===n&&g||'bottom'===n&&u,y=-1!==['top','bottom'].indexOf(n),w=!!t.flipVariations&&(y&&'start'===r&&h||y&&'end'===r&&c||!y&&'start'===r&&g||!y&&'end'===r&&u);(m||b||w)&&(e.flipped=!0,(m||b)&&(n=p[d+1]),w&&(r=K(r)),e.placement=n+(r?'-'+r:''),e.offsets.popper=le({},e.offsets.popper,D(e.instance.popper,e.offsets.reference,e.placement)),e=P(e.instance.modifiers,e,'flip'))}),e},behavior:'flip',padding:5,boundariesElement:'viewport'},inner:{order:700,enabled:!1,fn:function(e){var t=e.placement,o=t.split('-')[0],n=e.offsets,i=n.popper,r=n.reference,p=-1!==['left','right'].indexOf(o),s=-1===['top','left'].indexOf(o);return i[p?'left':'top']=r[o]-(s?i[p?'width':'height']:0),e.placement=T(t),e.offsets.popper=g(i),e}},hide:{order:800,enabled:!0,fn:function(e){if(!q(e.instance.modifiers,'hide','preventOverflow'))return e;var t=e.offsets.reference,o=C(e.instance.modifiers,function(e){return'preventOverflow'===e.name}).boundaries;if(t.bottomo.right||t.top>o.bottom||t.right res.json()) - .then(res => { - this.message.title = "Actualizaci贸n"; - this.message.text = res.error ?? res.success; - this.message.type = res.error ? 'danger' : 'success'; - this.message.timestamp = new Date().toLocaleTimeString(); - }); - }, - async mounted() { - this.carreras = await fetch('action/carrera.php').then(res => res.json()); - this.niveles = await fetch('action/nivel.php').then(res => res.json()); - // group by facultad_id - const carreras = this.carreras.reduce((acc, cur) => { - const { facultad_nombre } = cur; - if (!acc[facultad_nombre]) { - acc[facultad_nombre] = []; - } - acc[facultad_nombre].push(cur); - return acc; - }, {}); - this.carreras = Object.entries(carreras).map(([facultad_nombre, carreras]) => ({ - facultad_nombre: facultad_nombre, - carreras - })); - } -}).mount('#app'); +import { createApp } from 'https://unpkg.com/petite-vue?module'; +const app = createApp({ + carreras: [], + niveles: [], + message: {}, + async setNivel(carrera, nivel) { + if (carrera.nivel_id === nivel.nivel_id) { + return; + } + carrera.nivel_id = nivel.nivel_id; + carrera.nivel_nombre = nivel.nivel_nombre; + await fetch('action/carrera.php', { + method: 'PUT', + body: JSON.stringify({ + carrera_id: carrera.carrera_id, + nivel_id: nivel.nivel_id + }) + }) + .then(res => res.json()) + .then(res => { + this.message.title = "Actualizaci贸n"; + this.message.text = res.error ?? res.success; + this.message.type = res.error ? 'danger' : 'success'; + this.message.timestamp = new Date().toLocaleTimeString(); + }); + }, + async mounted() { + this.carreras = await fetch('action/carrera.php').then(res => res.json()); + this.niveles = await fetch('action/nivel.php').then(res => res.json()); + // group by facultad_id + const carreras = this.carreras.reduce((acc, cur) => { + const { facultad_nombre } = cur; + if (!acc[facultad_nombre]) { + acc[facultad_nombre] = []; + } + acc[facultad_nombre].push(cur); + return acc; + }, {}); + this.carreras = Object.entries(carreras).map(([facultad_nombre, carreras]) => ({ + facultad_nombre: facultad_nombre, + carreras + })); + } +}).mount('#app'); diff --git a/js/client.js b/js/client.js index 236d201..9087072 100644 --- a/js/client.js +++ b/js/client.js @@ -1,120 +1,120 @@ -// @ts-ignore Import module -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; -const webServices = { - getPeriodosV1: async () => { - try { - const response = await fetch('periodos.v1.php'); - return await response.json(); - } - catch (error) { - console.log(error); - return []; - } - }, - getPeriodosV2: async () => { - try { - const response = await fetch('periodos.v2.php'); - return await response.json(); - } - catch (error) { - console.log(error); - return []; - } - } -}; -const store = reactive({ - periodosV1: [], - periodosV2: [], - errors: [], - fechas(idPeriodo) { - const periodo = this.periodosV2.find((periodo) => periodo.IdPeriodo === idPeriodo); - return { - inicio: periodo ? periodo.FechaInicio : '', - fin: periodo ? periodo.FechaFin : '' - }; - }, - periodov1(idPeriodo) { - return this.periodosV1.find((periodo) => periodo.IdPeriodo === idPeriodo); - }, - periodov2(idPeriodo) { - return this.periodosV2.filter((periodo) => periodo.IdPeriodo === idPeriodo); - }, - async addPeriodo(periodo) { - try { - const result = await fetch('backend/periodos.php', { - method: 'POST', - body: JSON.stringify({ - ...periodo, - ...this.fechas(periodo.IdPeriodo) - }), - headers: { - 'Content-Type': 'application/json' - } - }).then((response) => response.json()); - if (result.success) { - this.periodosV1 = this.periodosV1.map((periodoV1) => { - if (periodoV1.IdPeriodo === periodo.IdPeriodo) { - periodoV1.in_db = true; - } - return periodoV1; - }); - return result; - } - else { - this.errors.push(result.message); - } - } - catch (error) { - this.errors.push(error); - } - }, - async addCarreras(idPeriodo) { - try { - const periodoV1 = this.periodov1(idPeriodo); - const periodoV2 = this.periodov2(idPeriodo); - const data = periodoV2.map(({ ClaveCarrera, NombreCarrera }) => ({ - ClaveCarrera: ClaveCarrera, - NombreCarrera: NombreCarrera, - IdNivel: periodoV1.IdNivel, - })); - const result = await fetch('backend/carreras.php', { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'Content-Type': 'application/json' - } - }).then((response) => response.json()); - if (result.success) { - await webServices.getPeriodosV1().then((periodosV1) => { - this.periodosV1 = periodosV1; - }); - await webServices.getPeriodosV2().then((periodosV2) => { - this.periodosV2 = periodosV2; - }); - } - } - catch (error) { - this.errors.push(error); - } - } -}); -createApp({ - store, - info(IdPeriodo) { - const periodo = store.periodosV2.find((periodo) => periodo.IdPeriodo === IdPeriodo && - periodo.FechaInicio != '' && periodo.FechaFin != ''); - return periodo; - }, - complete(IdPeriodo) { - const info = this.info(IdPeriodo); - return info !== undefined; - }, - mounted: async () => { - await webServices.getPeriodosV1().then((periodosV1) => { - store.periodosV1 = periodosV1; - }); - await webServices.getPeriodosV2().then((periodosV2) => { - store.periodosV2 = periodosV2; - }); - } -}).mount(); +// @ts-ignore Import module +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; +const webServices = { + getPeriodosV1: async () => { + try { + const response = await fetch('periodos.v1.php'); + return await response.json(); + } + catch (error) { + console.log(error); + return []; + } + }, + getPeriodosV2: async () => { + try { + const response = await fetch('periodos.v2.php'); + return await response.json(); + } + catch (error) { + console.log(error); + return []; + } + } +}; +const store = reactive({ + periodosV1: [], + periodosV2: [], + errors: [], + fechas(idPeriodo) { + const periodo = this.periodosV2.find((periodo) => periodo.IdPeriodo === idPeriodo); + return { + inicio: periodo ? periodo.FechaInicio : '', + fin: periodo ? periodo.FechaFin : '' + }; + }, + periodov1(idPeriodo) { + return this.periodosV1.find((periodo) => periodo.IdPeriodo === idPeriodo); + }, + periodov2(idPeriodo) { + return this.periodosV2.filter((periodo) => periodo.IdPeriodo === idPeriodo); + }, + async addPeriodo(periodo) { + try { + const result = await fetch('backend/periodos.php', { + method: 'POST', + body: JSON.stringify({ + ...periodo, + ...this.fechas(periodo.IdPeriodo) + }), + headers: { + 'Content-Type': 'application/json' + } + }).then((response) => response.json()); + if (result.success) { + this.periodosV1 = this.periodosV1.map((periodoV1) => { + if (periodoV1.IdPeriodo === periodo.IdPeriodo) { + periodoV1.in_db = true; + } + return periodoV1; + }); + return result; + } + else { + this.errors.push(result.message); + } + } + catch (error) { + this.errors.push(error); + } + }, + async addCarreras(idPeriodo) { + try { + const periodoV1 = this.periodov1(idPeriodo); + const periodoV2 = this.periodov2(idPeriodo); + const data = periodoV2.map(({ ClaveCarrera, NombreCarrera }) => ({ + ClaveCarrera: ClaveCarrera, + NombreCarrera: NombreCarrera, + IdNivel: periodoV1.IdNivel, + })); + const result = await fetch('backend/carreras.php', { + method: 'POST', + body: JSON.stringify(data), + headers: { + 'Content-Type': 'application/json' + } + }).then((response) => response.json()); + if (result.success) { + await webServices.getPeriodosV1().then((periodosV1) => { + this.periodosV1 = periodosV1; + }); + await webServices.getPeriodosV2().then((periodosV2) => { + this.periodosV2 = periodosV2; + }); + } + } + catch (error) { + this.errors.push(error); + } + } +}); +createApp({ + store, + info(IdPeriodo) { + const periodo = store.periodosV2.find((periodo) => periodo.IdPeriodo === IdPeriodo && + periodo.FechaInicio != '' && periodo.FechaFin != ''); + return periodo; + }, + complete(IdPeriodo) { + const info = this.info(IdPeriodo); + return info !== undefined; + }, + mounted: async () => { + await webServices.getPeriodosV1().then((periodosV1) => { + store.periodosV1 = periodosV1; + }); + await webServices.getPeriodosV2().then((periodosV2) => { + store.periodosV2 = periodosV2; + }); + } +}).mount(); diff --git a/js/clockpicker.js b/js/clockpicker.js index e9ed3f9..58abf55 100644 --- a/js/clockpicker.js +++ b/js/clockpicker.js @@ -1,731 +1,731 @@ -/*! - * ClockPicker v{package.version} (http://weareoutman.github.io/clockpicker/) - * Copyright 2014 Wang Shenwei. - * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) - */ - -;(function(){ - var $ = window.jQuery, - $win = $(window), - $doc = $(document), - $body; - - // Can I use inline svg ? - var svgNS = 'http://www.w3.org/2000/svg', - svgSupported = 'SVGAngle' in window && (function(){ - var supported, - el = document.createElement('div'); - el.innerHTML = ''; - supported = (el.firstChild && el.firstChild.namespaceURI) == svgNS; - el.innerHTML = ''; - return supported; - })(); - - // Can I use transition ? - var transitionSupported = (function(){ - var style = document.createElement('div').style; - return 'transition' in style || - 'WebkitTransition' in style || - 'MozTransition' in style || - 'msTransition' in style || - 'OTransition' in style; - })(); - - // Listen touch events in touch screen device, instead of mouse events in desktop. - var touchSupported = 'ontouchstart' in window, - mousedownEvent = 'mousedown' + ( touchSupported ? ' touchstart' : ''), - mousemoveEvent = 'mousemove.clockpicker' + ( touchSupported ? ' touchmove.clockpicker' : ''), - mouseupEvent = 'mouseup.clockpicker' + ( touchSupported ? ' touchend.clockpicker' : ''); - - // Vibrate the device if supported - var vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null; - - function createSvgElement(name) { - return document.createElementNS(svgNS, name); - } - - function leadingZero(num) { - return (num < 10 ? '0' : '') + num; - } - - // Get a unique id - var idCounter = 0; - function uniqueId(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - } - - // Clock size - var dialRadius = 100, - outerRadius = 80, - // innerRadius = 80 on 12 hour clock - innerRadius = 54, - tickRadius = 13, - diameter = dialRadius * 2, - duration = transitionSupported ? 350 : 1; - - // Popover template - var tpl = [ - '
', - '
', - '
', - '', - ' : ', - '', - '', - '
', - '
', - '
', - '
', - '
', - '
', - '
', - '', - '', - '
', - '
' - ].join(''); - - // ClockPicker - function ClockPicker(element, options) { - var popover = $(tpl), - plate = popover.find('.clockpicker-plate'), - hoursView = popover.find('.clockpicker-hours'), - minutesView = popover.find('.clockpicker-minutes'), - amPmBlock = popover.find('.clockpicker-am-pm-block'), - isInput = element.prop('tagName') === 'INPUT', - input = isInput ? element : element.find('input'), - addon = element.find('.input-group-addon'), - self = this, - timer; - - this.id = uniqueId('cp'); - this.element = element; - this.options = options; - this.isAppended = false; - this.isShown = false; - this.currentView = 'hours'; - this.isInput = isInput; - this.input = input; - this.addon = addon; - this.popover = popover; - this.plate = plate; - this.hoursView = hoursView; - this.minutesView = minutesView; - this.amPmBlock = amPmBlock; - this.spanHours = popover.find('.clockpicker-span-hours'); - this.spanMinutes = popover.find('.clockpicker-span-minutes'); - this.spanAmPm = popover.find('.clockpicker-span-am-pm'); - this.amOrPm = "PM"; - - // Setup for for 12 hour clock if option is selected - if (options.twelvehour) { - - var amPmButtonsTemplate = ['
', - '', - '', - '
'].join(''); - - var amPmButtons = $(amPmButtonsTemplate); - //amPmButtons.appendTo(plate); - - ////Not working b/c they are not shown when this runs - //$('clockpicker-am-button') - // .on("click", function() { - // self.amOrPm = "AM"; - // $('.clockpicker-span-am-pm').empty().append('AM'); - // }); - // - //$('clockpicker-pm-button') - // .on("click", function() { - // self.amOrPm = "PM"; - // $('.clockpicker-span-am-pm').empty().append('PM'); - // }); - - $('') - .on("click", function() { - self.amOrPm = "AM"; - $('.clockpicker-span-am-pm').empty().append('AM'); - }).appendTo(this.amPmBlock); - - - $('') - .on("click", function() { - self.amOrPm = 'PM'; - $('.clockpicker-span-am-pm').empty().append('PM'); - }).appendTo(this.amPmBlock); - - } - - if (! options.autoclose) { - // If autoclose is not setted, append a button - $('') - .click($.proxy(this.done, this)) - .appendTo(popover); - } - - // Placement and arrow align - make sure they make sense. - if ((options.placement === 'top' || options.placement === 'bottom') && (options.align === 'top' || options.align === 'bottom')) options.align = 'left'; - if ((options.placement === 'left' || options.placement === 'right') && (options.align === 'left' || options.align === 'right')) options.align = 'top'; - - popover.addClass(options.placement); - popover.addClass('clockpicker-align-' + options.align); - - this.spanHours.click($.proxy(this.toggleView, this, 'hours')); - this.spanMinutes.click($.proxy(this.toggleView, this, 'minutes')); - - // Show or toggle - input.on('focus.clockpicker click.clockpicker', $.proxy(this.show, this)); - addon.on('click.clockpicker', $.proxy(this.toggle, this)); - - // Build ticks - var tickTpl = $('
'), - i, tick, radian, radius; - - // Hours view - if (options.twelvehour) { - for (i = 1; i < 13; i += 1) { - tick = tickTpl.clone(); - radian = i / 6 * Math.PI; - radius = outerRadius; - //tick.css('font-size', '120%'); - tick.css({ - left: dialRadius + Math.sin(radian) * radius - tickRadius, - top: dialRadius - Math.cos(radian) * radius - tickRadius - }); - tick.html(i === 0 ? '00' : i); - hoursView.append(tick); - tick.on(mousedownEvent, mousedown); - } - } else { - for (i = 0; i < 24; i += 1) { - tick = tickTpl.clone(); - radian = i / 6 * Math.PI; - var inner = i > 0 && i < 13; - radius = inner ? innerRadius : outerRadius; - tick.css({ - left: dialRadius + Math.sin(radian) * radius - tickRadius, - top: dialRadius - Math.cos(radian) * radius - tickRadius - }); - /*if (inner) { - tick.css('font-size', '120%'); - }*/ - tick.html(i === 0 ? '00' : i); - hoursView.append(tick); - tick.on(mousedownEvent, mousedown); - } - } - - // Minutes view - for (i = 0; i < 60; i += 5) { - tick = tickTpl.clone(); - radian = i / 30 * Math.PI; - tick.css({ - left: dialRadius + Math.sin(radian) * outerRadius - tickRadius, - top: dialRadius - Math.cos(radian) * outerRadius - tickRadius - }); - //tick.css('font-size', '120%'); - tick.html(leadingZero(i)); - minutesView.append(tick); - tick.on(mousedownEvent, mousedown); - } - - // Clicking on minutes view space - plate.on(mousedownEvent, function(e){ - if ($(e.target).closest('.clockpicker-tick').length === 0) { - mousedown(e, true); - } - }); - - // Mousedown or touchstart - function mousedown(e, space) { - var offset = plate.offset(), - isTouch = /^touch/.test(e.type), - x0 = offset.left + dialRadius, - y0 = offset.top + dialRadius, - dx = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0, - dy = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0, - z = Math.sqrt(dx * dx + dy * dy), - moved = false; - - // When clicking on minutes view space, check the mouse position - if (space && (z < outerRadius - tickRadius || z > outerRadius + tickRadius)) { - return; - } - e.preventDefault(); - - // Set cursor style of body after 200ms - var movingTimer = setTimeout(function(){ - $body.addClass('clockpicker-moving'); - }, 200); - - // Place the canvas to top - if (svgSupported) { - plate.append(self.canvas); - } - - // Clock - self.setHand(dx, dy, ! space, true); - - // Mousemove on document - $doc.off(mousemoveEvent).on(mousemoveEvent, function(e){ - e.preventDefault(); - var isTouch = /^touch/.test(e.type), - x = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0, - y = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0; - if (! moved && x === dx && y === dy) { - // Clicking in chrome on windows will trigger a mousemove event - return; - } - moved = true; - self.setHand(x, y, false, true); - }); - - // Mouseup on document - $doc.off(mouseupEvent).on(mouseupEvent, function(e){ - $doc.off(mouseupEvent); - e.preventDefault(); - var isTouch = /^touch/.test(e.type), - x = (isTouch ? e.originalEvent.changedTouches[0] : e).pageX - x0, - y = (isTouch ? e.originalEvent.changedTouches[0] : e).pageY - y0; - if ((space || moved) && x === dx && y === dy) { - self.setHand(x, y); - } - if (self.currentView === 'hours') { - self.toggleView('minutes', duration / 2); - } else { - if (options.autoclose) { - self.minutesView.addClass('clockpicker-dial-out'); - setTimeout(function(){ - self.done(); - }, duration / 2); - } - } - plate.prepend(canvas); - - // Reset cursor style of body - clearTimeout(movingTimer); - $body.removeClass('clockpicker-moving'); - - // Unbind mousemove event - $doc.off(mousemoveEvent); - }); - } - - if (svgSupported) { - // Draw clock hands and others - var canvas = popover.find('.clockpicker-canvas'), - svg = createSvgElement('svg'); - svg.setAttribute('class', 'clockpicker-svg'); - svg.setAttribute('width', diameter); - svg.setAttribute('height', diameter); - var g = createSvgElement('g'); - g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')'); - var bearing = createSvgElement('circle'); - bearing.setAttribute('class', 'clockpicker-canvas-bearing'); - bearing.setAttribute('cx', 0); - bearing.setAttribute('cy', 0); - bearing.setAttribute('r', 2); - var hand = createSvgElement('line'); - hand.setAttribute('x1', 0); - hand.setAttribute('y1', 0); - var bg = createSvgElement('circle'); - bg.setAttribute('class', 'clockpicker-canvas-bg'); - bg.setAttribute('r', tickRadius); - var fg = createSvgElement('circle'); - fg.setAttribute('class', 'clockpicker-canvas-fg'); - fg.setAttribute('r', 3.5); - g.appendChild(hand); - g.appendChild(bg); - g.appendChild(fg); - g.appendChild(bearing); - svg.appendChild(g); - canvas.append(svg); - - this.hand = hand; - this.bg = bg; - this.fg = fg; - this.bearing = bearing; - this.g = g; - this.canvas = canvas; - } - - raiseCallback(this.options.init); - } - - function raiseCallback(callbackFunction) { - if (callbackFunction && typeof callbackFunction === "function") { - callbackFunction(); - } - } - - // Default options - ClockPicker.DEFAULTS = { - 'default': '', // default time, 'now' or '13:14' e.g. - fromnow: 0, // set default time to * milliseconds from now (using with default = 'now') - placement: 'bottom', // clock popover placement - align: 'left', // popover arrow align - donetext: 'Aceptar', // done button text - autoclose: false, // auto close when minute is selected - twelvehour: false, // change to 12 hour AM/PM clock from 24 hour - vibrate: true // vibrate the device when dragging clock hand - }; - - // Show or hide popover - ClockPicker.prototype.toggle = function(){ - this[this.isShown ? 'hide' : 'show'](); - }; - - // Set popover position - ClockPicker.prototype.locate = function(){ - var element = this.element, - popover = this.popover, - offset = element.offset(), - width = element.outerWidth(), - height = element.outerHeight(), - placement = this.options.placement, - align = this.options.align, - styles = {}, - self = this; - - popover.show(); - - // Place the popover - switch (placement) { - case 'bottom': - styles.top = offset.top + height; - break; - case 'right': - styles.left = offset.left + width; - break; - case 'top': - styles.top = offset.top - popover.outerHeight(); - break; - case 'left': - styles.left = offset.left - popover.outerWidth(); - break; - } - - // Align the popover arrow - switch (align) { - case 'left': - styles.left = offset.left; - break; - case 'right': - styles.left = offset.left + width - popover.outerWidth(); - break; - case 'top': - styles.top = offset.top; - break; - case 'bottom': - styles.top = offset.top + height - popover.outerHeight(); - break; - } - - popover.css(styles); - }; - - // Show popover - ClockPicker.prototype.show = function(e){ - // Not show again - if (this.isShown) { - return; - } - - raiseCallback(this.options.beforeShow); - - var self = this; - - // Initialize - if (! this.isAppended) { - // Append popover to body - $body = $(document.body).append(this.popover); - - // Reset position when resize - $win.on('resize.clockpicker' + this.id, function(){ - if (self.isShown) { - self.locate(); - } - }); - - this.isAppended = true; - } - - // Get the time - var value = ((this.input.prop('value') || this.options['default'] || '') + '').split(':'); - if (value[0] === 'now') { - var now = new Date(+ new Date() + this.options.fromnow); - value = [ - now.getHours(), - now.getMinutes() - ]; - } - this.hours = + value[0] || 0; - this.minutes = + value[1] || 0; - this.spanHours.html(leadingZero(this.hours)); - this.spanMinutes.html(leadingZero(this.minutes)); - - // Toggle to hours view - this.toggleView('hours'); - - // Set position - this.locate(); - - this.isShown = true; - - // Hide when clicking or tabbing on any element except the clock, input and addon - $doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function(e){ - var target = $(e.target); - if (target.closest(self.popover).length === 0 && - target.closest(self.addon).length === 0 && - target.closest(self.input).length === 0) { - self.hide(); - } - }); - - // Hide when ESC is pressed - $doc.on('keyup.clockpicker.' + this.id, function(e){ - if (e.keyCode === 27) { - self.hide(); - } - }); - - raiseCallback(this.options.afterShow); - }; - - // Hide popover - ClockPicker.prototype.hide = function(){ - raiseCallback(this.options.beforeHide); - - this.isShown = false; - - // Unbinding events on document - $doc.off('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id); - $doc.off('keyup.clockpicker.' + this.id); - - this.popover.hide(); - - raiseCallback(this.options.afterHide); - }; - - // Toggle to hours or minutes view - ClockPicker.prototype.toggleView = function(view, delay){ - var raiseAfterHourSelect = false; - if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") { - raiseCallback(this.options.beforeHourSelect); - raiseAfterHourSelect = true; - } - var isHours = view === 'hours', - nextView = isHours ? this.hoursView : this.minutesView, - hideView = isHours ? this.minutesView : this.hoursView; - - this.currentView = view; - - this.spanHours.toggleClass('text-azul-ing', isHours); - this.spanMinutes.toggleClass('text-azul-ing', ! isHours); - - // Let's make transitions - hideView.addClass('clockpicker-dial-out'); - nextView.css('visibility', 'visible').removeClass('clockpicker-dial-out'); - - // Reset clock hand - this.resetClock(delay); - - // After transitions ended - clearTimeout(this.toggleViewTimer); - this.toggleViewTimer = setTimeout(function(){ - hideView.css('visibility', 'hidden'); - }, duration); - - if (raiseAfterHourSelect) { - raiseCallback(this.options.afterHourSelect); - } - }; - - // Reset clock hand - ClockPicker.prototype.resetClock = function(delay){ - var view = this.currentView, - value = this[view], - isHours = view === 'hours', - unit = Math.PI / (isHours ? 6 : 30), - radian = value * unit, - radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius, - x = Math.sin(radian) * radius, - y = - Math.cos(radian) * radius, - self = this; - if (svgSupported && delay) { - self.canvas.addClass('clockpicker-canvas-out'); - setTimeout(function(){ - self.canvas.removeClass('clockpicker-canvas-out'); - self.setHand(x, y); - }, delay); - } else { - this.setHand(x, y); - } - }; - - // Set clock hand to (x, y) - ClockPicker.prototype.setHand = function(x, y, roundBy5, dragging){ - var radian = Math.atan2(x, - y), - isHours = this.currentView === 'hours', - unit = Math.PI / (isHours || roundBy5 ? 6 : 30), - z = Math.sqrt(x * x + y * y), - options = this.options, - inner = isHours && z < (outerRadius + innerRadius) / 2, - radius = inner ? innerRadius : outerRadius, - value; - - if (options.twelvehour) { - radius = outerRadius; - } - - // Radian should in range [0, 2PI] - if (radian < 0) { - radian = Math.PI * 2 + radian; - } - - // Get the round value - value = Math.round(radian / unit); - - // Get the round radian - radian = value * unit; - - // Correct the hours or minutes - if (options.twelvehour) { - if (isHours) { - if (value === 0) { - value = 12; - } - } else { - if (roundBy5) { - value *= 5; - } - if (value === 60) { - value = 0; - } - } - } else { - if (isHours) { - if (value === 12) { - value = 0; - } - value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12; - } else { - if (roundBy5) { - value *= 5; - } - if (value === 60) { - value = 0; - } - } - } - - // Once hours or minutes changed, vibrate the device - if (this[this.currentView] !== value) { - if (vibrate && this.options.vibrate) { - // Do not vibrate too frequently - if (! this.vibrateTimer) { - navigator[vibrate](10); - this.vibrateTimer = setTimeout($.proxy(function(){ - this.vibrateTimer = null; - }, this), 100); - } - } - } - - this[this.currentView] = value; - this[isHours ? 'spanHours' : 'spanMinutes'].html(leadingZero(value)); - - // If svg is not supported, just add an active class to the tick - //if (! svgSupported) { - this[isHours ? 'hoursView' : 'minutesView'].find('.clockpicker-tick').each(function(){ - var tick = $(this); - tick.toggleClass('active', value === + tick.html()); - }); - //return; - //} - - - - // Place clock hand at the top when dragging - if (dragging || (! isHours && value % 5)) { - this.g.insertBefore(this.hand, this.bearing); - this.g.insertBefore(this.bg, this.fg); - this.bg.setAttribute('class', 'clockpicker-canvas-bg clockpicker-canvas-bg-trans'); - } else { - // Or place it at the bottom - this.g.insertBefore(this.hand, this.bg); - this.g.insertBefore(this.fg, this.bg); - this.bg.setAttribute('class', 'clockpicker-canvas-bg'); - } - - // Set clock hand and others' position - var cx = Math.sin(radian) * radius, - cy = - Math.cos(radian) * radius; - this.hand.setAttribute('x2', cx); - this.hand.setAttribute('y2', cy); - this.bg.setAttribute('cx', cx); - this.bg.setAttribute('cy', cy); - this.fg.setAttribute('cx', cx); - this.fg.setAttribute('cy', cy); - }; - - // Hours and minutes are selected - ClockPicker.prototype.done = function() { - raiseCallback(this.options.beforeDone); - this.hide(); - var last = this.input.prop('value'), - value = leadingZero(this.hours) + ':' + leadingZero(this.minutes); - if (this.options.twelvehour) { - value = value + this.amOrPm; - } - - this.input.prop('value', value); - if (value !== last) { - this.input.triggerHandler('change'); - if (! this.isInput) { - this.element.trigger('change'); - } - } - - if (this.options.autoclose) { - this.input.trigger('blur'); - } - - raiseCallback(this.options.afterDone); - }; - - // Remove clockpicker from input - ClockPicker.prototype.remove = function() { - this.element.removeData('clockpicker'); - this.input.off('focus.clockpicker click.clockpicker'); - this.addon.off('click.clockpicker'); - if (this.isShown) { - this.hide(); - } - if (this.isAppended) { - $win.off('resize.clockpicker' + this.id); - this.popover.remove(); - } - }; - - // Extends $.fn.clockpicker - $.fn.clockpicker = function(option){ - var args = Array.prototype.slice.call(arguments, 1); - return this.each(function(){ - var $this = $(this), - data = $this.data('clockpicker'); - if (! data) { - var options = $.extend({}, ClockPicker.DEFAULTS, $this.data(), typeof option == 'object' && option); - $this.data('clockpicker', new ClockPicker($this, options)); - } else { - // Manual operatsions. show, hide, remove, e.g. - if (typeof data[option] === 'function') { - data[option].apply(data, args); - } - } - }); - }; -}()); +/*! + * ClockPicker v{package.version} (http://weareoutman.github.io/clockpicker/) + * Copyright 2014 Wang Shenwei. + * Licensed under MIT (https://github.com/weareoutman/clockpicker/blob/gh-pages/LICENSE) + */ + +;(function(){ + var $ = window.jQuery, + $win = $(window), + $doc = $(document), + $body; + + // Can I use inline svg ? + var svgNS = 'http://www.w3.org/2000/svg', + svgSupported = 'SVGAngle' in window && (function(){ + var supported, + el = document.createElement('div'); + el.innerHTML = ''; + supported = (el.firstChild && el.firstChild.namespaceURI) == svgNS; + el.innerHTML = ''; + return supported; + })(); + + // Can I use transition ? + var transitionSupported = (function(){ + var style = document.createElement('div').style; + return 'transition' in style || + 'WebkitTransition' in style || + 'MozTransition' in style || + 'msTransition' in style || + 'OTransition' in style; + })(); + + // Listen touch events in touch screen device, instead of mouse events in desktop. + var touchSupported = 'ontouchstart' in window, + mousedownEvent = 'mousedown' + ( touchSupported ? ' touchstart' : ''), + mousemoveEvent = 'mousemove.clockpicker' + ( touchSupported ? ' touchmove.clockpicker' : ''), + mouseupEvent = 'mouseup.clockpicker' + ( touchSupported ? ' touchend.clockpicker' : ''); + + // Vibrate the device if supported + var vibrate = navigator.vibrate ? 'vibrate' : navigator.webkitVibrate ? 'webkitVibrate' : null; + + function createSvgElement(name) { + return document.createElementNS(svgNS, name); + } + + function leadingZero(num) { + return (num < 10 ? '0' : '') + num; + } + + // Get a unique id + var idCounter = 0; + function uniqueId(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + } + + // Clock size + var dialRadius = 100, + outerRadius = 80, + // innerRadius = 80 on 12 hour clock + innerRadius = 54, + tickRadius = 13, + diameter = dialRadius * 2, + duration = transitionSupported ? 350 : 1; + + // Popover template + var tpl = [ + '
', + '
', + '
', + '', + ' : ', + '', + '', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '', + '', + '
', + '
' + ].join(''); + + // ClockPicker + function ClockPicker(element, options) { + var popover = $(tpl), + plate = popover.find('.clockpicker-plate'), + hoursView = popover.find('.clockpicker-hours'), + minutesView = popover.find('.clockpicker-minutes'), + amPmBlock = popover.find('.clockpicker-am-pm-block'), + isInput = element.prop('tagName') === 'INPUT', + input = isInput ? element : element.find('input'), + addon = element.find('.input-group-addon'), + self = this, + timer; + + this.id = uniqueId('cp'); + this.element = element; + this.options = options; + this.isAppended = false; + this.isShown = false; + this.currentView = 'hours'; + this.isInput = isInput; + this.input = input; + this.addon = addon; + this.popover = popover; + this.plate = plate; + this.hoursView = hoursView; + this.minutesView = minutesView; + this.amPmBlock = amPmBlock; + this.spanHours = popover.find('.clockpicker-span-hours'); + this.spanMinutes = popover.find('.clockpicker-span-minutes'); + this.spanAmPm = popover.find('.clockpicker-span-am-pm'); + this.amOrPm = "PM"; + + // Setup for for 12 hour clock if option is selected + if (options.twelvehour) { + + var amPmButtonsTemplate = ['
', + '', + '', + '
'].join(''); + + var amPmButtons = $(amPmButtonsTemplate); + //amPmButtons.appendTo(plate); + + ////Not working b/c they are not shown when this runs + //$('clockpicker-am-button') + // .on("click", function() { + // self.amOrPm = "AM"; + // $('.clockpicker-span-am-pm').empty().append('AM'); + // }); + // + //$('clockpicker-pm-button') + // .on("click", function() { + // self.amOrPm = "PM"; + // $('.clockpicker-span-am-pm').empty().append('PM'); + // }); + + $('') + .on("click", function() { + self.amOrPm = "AM"; + $('.clockpicker-span-am-pm').empty().append('AM'); + }).appendTo(this.amPmBlock); + + + $('') + .on("click", function() { + self.amOrPm = 'PM'; + $('.clockpicker-span-am-pm').empty().append('PM'); + }).appendTo(this.amPmBlock); + + } + + if (! options.autoclose) { + // If autoclose is not setted, append a button + $('') + .click($.proxy(this.done, this)) + .appendTo(popover); + } + + // Placement and arrow align - make sure they make sense. + if ((options.placement === 'top' || options.placement === 'bottom') && (options.align === 'top' || options.align === 'bottom')) options.align = 'left'; + if ((options.placement === 'left' || options.placement === 'right') && (options.align === 'left' || options.align === 'right')) options.align = 'top'; + + popover.addClass(options.placement); + popover.addClass('clockpicker-align-' + options.align); + + this.spanHours.click($.proxy(this.toggleView, this, 'hours')); + this.spanMinutes.click($.proxy(this.toggleView, this, 'minutes')); + + // Show or toggle + input.on('focus.clockpicker click.clockpicker', $.proxy(this.show, this)); + addon.on('click.clockpicker', $.proxy(this.toggle, this)); + + // Build ticks + var tickTpl = $('
'), + i, tick, radian, radius; + + // Hours view + if (options.twelvehour) { + for (i = 1; i < 13; i += 1) { + tick = tickTpl.clone(); + radian = i / 6 * Math.PI; + radius = outerRadius; + //tick.css('font-size', '120%'); + tick.css({ + left: dialRadius + Math.sin(radian) * radius - tickRadius, + top: dialRadius - Math.cos(radian) * radius - tickRadius + }); + tick.html(i === 0 ? '00' : i); + hoursView.append(tick); + tick.on(mousedownEvent, mousedown); + } + } else { + for (i = 0; i < 24; i += 1) { + tick = tickTpl.clone(); + radian = i / 6 * Math.PI; + var inner = i > 0 && i < 13; + radius = inner ? innerRadius : outerRadius; + tick.css({ + left: dialRadius + Math.sin(radian) * radius - tickRadius, + top: dialRadius - Math.cos(radian) * radius - tickRadius + }); + /*if (inner) { + tick.css('font-size', '120%'); + }*/ + tick.html(i === 0 ? '00' : i); + hoursView.append(tick); + tick.on(mousedownEvent, mousedown); + } + } + + // Minutes view + for (i = 0; i < 60; i += 5) { + tick = tickTpl.clone(); + radian = i / 30 * Math.PI; + tick.css({ + left: dialRadius + Math.sin(radian) * outerRadius - tickRadius, + top: dialRadius - Math.cos(radian) * outerRadius - tickRadius + }); + //tick.css('font-size', '120%'); + tick.html(leadingZero(i)); + minutesView.append(tick); + tick.on(mousedownEvent, mousedown); + } + + // Clicking on minutes view space + plate.on(mousedownEvent, function(e){ + if ($(e.target).closest('.clockpicker-tick').length === 0) { + mousedown(e, true); + } + }); + + // Mousedown or touchstart + function mousedown(e, space) { + var offset = plate.offset(), + isTouch = /^touch/.test(e.type), + x0 = offset.left + dialRadius, + y0 = offset.top + dialRadius, + dx = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0, + dy = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0, + z = Math.sqrt(dx * dx + dy * dy), + moved = false; + + // When clicking on minutes view space, check the mouse position + if (space && (z < outerRadius - tickRadius || z > outerRadius + tickRadius)) { + return; + } + e.preventDefault(); + + // Set cursor style of body after 200ms + var movingTimer = setTimeout(function(){ + $body.addClass('clockpicker-moving'); + }, 200); + + // Place the canvas to top + if (svgSupported) { + plate.append(self.canvas); + } + + // Clock + self.setHand(dx, dy, ! space, true); + + // Mousemove on document + $doc.off(mousemoveEvent).on(mousemoveEvent, function(e){ + e.preventDefault(); + var isTouch = /^touch/.test(e.type), + x = (isTouch ? e.originalEvent.touches[0] : e).pageX - x0, + y = (isTouch ? e.originalEvent.touches[0] : e).pageY - y0; + if (! moved && x === dx && y === dy) { + // Clicking in chrome on windows will trigger a mousemove event + return; + } + moved = true; + self.setHand(x, y, false, true); + }); + + // Mouseup on document + $doc.off(mouseupEvent).on(mouseupEvent, function(e){ + $doc.off(mouseupEvent); + e.preventDefault(); + var isTouch = /^touch/.test(e.type), + x = (isTouch ? e.originalEvent.changedTouches[0] : e).pageX - x0, + y = (isTouch ? e.originalEvent.changedTouches[0] : e).pageY - y0; + if ((space || moved) && x === dx && y === dy) { + self.setHand(x, y); + } + if (self.currentView === 'hours') { + self.toggleView('minutes', duration / 2); + } else { + if (options.autoclose) { + self.minutesView.addClass('clockpicker-dial-out'); + setTimeout(function(){ + self.done(); + }, duration / 2); + } + } + plate.prepend(canvas); + + // Reset cursor style of body + clearTimeout(movingTimer); + $body.removeClass('clockpicker-moving'); + + // Unbind mousemove event + $doc.off(mousemoveEvent); + }); + } + + if (svgSupported) { + // Draw clock hands and others + var canvas = popover.find('.clockpicker-canvas'), + svg = createSvgElement('svg'); + svg.setAttribute('class', 'clockpicker-svg'); + svg.setAttribute('width', diameter); + svg.setAttribute('height', diameter); + var g = createSvgElement('g'); + g.setAttribute('transform', 'translate(' + dialRadius + ',' + dialRadius + ')'); + var bearing = createSvgElement('circle'); + bearing.setAttribute('class', 'clockpicker-canvas-bearing'); + bearing.setAttribute('cx', 0); + bearing.setAttribute('cy', 0); + bearing.setAttribute('r', 2); + var hand = createSvgElement('line'); + hand.setAttribute('x1', 0); + hand.setAttribute('y1', 0); + var bg = createSvgElement('circle'); + bg.setAttribute('class', 'clockpicker-canvas-bg'); + bg.setAttribute('r', tickRadius); + var fg = createSvgElement('circle'); + fg.setAttribute('class', 'clockpicker-canvas-fg'); + fg.setAttribute('r', 3.5); + g.appendChild(hand); + g.appendChild(bg); + g.appendChild(fg); + g.appendChild(bearing); + svg.appendChild(g); + canvas.append(svg); + + this.hand = hand; + this.bg = bg; + this.fg = fg; + this.bearing = bearing; + this.g = g; + this.canvas = canvas; + } + + raiseCallback(this.options.init); + } + + function raiseCallback(callbackFunction) { + if (callbackFunction && typeof callbackFunction === "function") { + callbackFunction(); + } + } + + // Default options + ClockPicker.DEFAULTS = { + 'default': '', // default time, 'now' or '13:14' e.g. + fromnow: 0, // set default time to * milliseconds from now (using with default = 'now') + placement: 'bottom', // clock popover placement + align: 'left', // popover arrow align + donetext: 'Aceptar', // done button text + autoclose: false, // auto close when minute is selected + twelvehour: false, // change to 12 hour AM/PM clock from 24 hour + vibrate: true // vibrate the device when dragging clock hand + }; + + // Show or hide popover + ClockPicker.prototype.toggle = function(){ + this[this.isShown ? 'hide' : 'show'](); + }; + + // Set popover position + ClockPicker.prototype.locate = function(){ + var element = this.element, + popover = this.popover, + offset = element.offset(), + width = element.outerWidth(), + height = element.outerHeight(), + placement = this.options.placement, + align = this.options.align, + styles = {}, + self = this; + + popover.show(); + + // Place the popover + switch (placement) { + case 'bottom': + styles.top = offset.top + height; + break; + case 'right': + styles.left = offset.left + width; + break; + case 'top': + styles.top = offset.top - popover.outerHeight(); + break; + case 'left': + styles.left = offset.left - popover.outerWidth(); + break; + } + + // Align the popover arrow + switch (align) { + case 'left': + styles.left = offset.left; + break; + case 'right': + styles.left = offset.left + width - popover.outerWidth(); + break; + case 'top': + styles.top = offset.top; + break; + case 'bottom': + styles.top = offset.top + height - popover.outerHeight(); + break; + } + + popover.css(styles); + }; + + // Show popover + ClockPicker.prototype.show = function(e){ + // Not show again + if (this.isShown) { + return; + } + + raiseCallback(this.options.beforeShow); + + var self = this; + + // Initialize + if (! this.isAppended) { + // Append popover to body + $body = $(document.body).append(this.popover); + + // Reset position when resize + $win.on('resize.clockpicker' + this.id, function(){ + if (self.isShown) { + self.locate(); + } + }); + + this.isAppended = true; + } + + // Get the time + var value = ((this.input.prop('value') || this.options['default'] || '') + '').split(':'); + if (value[0] === 'now') { + var now = new Date(+ new Date() + this.options.fromnow); + value = [ + now.getHours(), + now.getMinutes() + ]; + } + this.hours = + value[0] || 0; + this.minutes = + value[1] || 0; + this.spanHours.html(leadingZero(this.hours)); + this.spanMinutes.html(leadingZero(this.minutes)); + + // Toggle to hours view + this.toggleView('hours'); + + // Set position + this.locate(); + + this.isShown = true; + + // Hide when clicking or tabbing on any element except the clock, input and addon + $doc.on('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id, function(e){ + var target = $(e.target); + if (target.closest(self.popover).length === 0 && + target.closest(self.addon).length === 0 && + target.closest(self.input).length === 0) { + self.hide(); + } + }); + + // Hide when ESC is pressed + $doc.on('keyup.clockpicker.' + this.id, function(e){ + if (e.keyCode === 27) { + self.hide(); + } + }); + + raiseCallback(this.options.afterShow); + }; + + // Hide popover + ClockPicker.prototype.hide = function(){ + raiseCallback(this.options.beforeHide); + + this.isShown = false; + + // Unbinding events on document + $doc.off('click.clockpicker.' + this.id + ' focusin.clockpicker.' + this.id); + $doc.off('keyup.clockpicker.' + this.id); + + this.popover.hide(); + + raiseCallback(this.options.afterHide); + }; + + // Toggle to hours or minutes view + ClockPicker.prototype.toggleView = function(view, delay){ + var raiseAfterHourSelect = false; + if (view === 'minutes' && $(this.hoursView).css("visibility") === "visible") { + raiseCallback(this.options.beforeHourSelect); + raiseAfterHourSelect = true; + } + var isHours = view === 'hours', + nextView = isHours ? this.hoursView : this.minutesView, + hideView = isHours ? this.minutesView : this.hoursView; + + this.currentView = view; + + this.spanHours.toggleClass('text-azul-ing', isHours); + this.spanMinutes.toggleClass('text-azul-ing', ! isHours); + + // Let's make transitions + hideView.addClass('clockpicker-dial-out'); + nextView.css('visibility', 'visible').removeClass('clockpicker-dial-out'); + + // Reset clock hand + this.resetClock(delay); + + // After transitions ended + clearTimeout(this.toggleViewTimer); + this.toggleViewTimer = setTimeout(function(){ + hideView.css('visibility', 'hidden'); + }, duration); + + if (raiseAfterHourSelect) { + raiseCallback(this.options.afterHourSelect); + } + }; + + // Reset clock hand + ClockPicker.prototype.resetClock = function(delay){ + var view = this.currentView, + value = this[view], + isHours = view === 'hours', + unit = Math.PI / (isHours ? 6 : 30), + radian = value * unit, + radius = isHours && value > 0 && value < 13 ? innerRadius : outerRadius, + x = Math.sin(radian) * radius, + y = - Math.cos(radian) * radius, + self = this; + if (svgSupported && delay) { + self.canvas.addClass('clockpicker-canvas-out'); + setTimeout(function(){ + self.canvas.removeClass('clockpicker-canvas-out'); + self.setHand(x, y); + }, delay); + } else { + this.setHand(x, y); + } + }; + + // Set clock hand to (x, y) + ClockPicker.prototype.setHand = function(x, y, roundBy5, dragging){ + var radian = Math.atan2(x, - y), + isHours = this.currentView === 'hours', + unit = Math.PI / (isHours || roundBy5 ? 6 : 30), + z = Math.sqrt(x * x + y * y), + options = this.options, + inner = isHours && z < (outerRadius + innerRadius) / 2, + radius = inner ? innerRadius : outerRadius, + value; + + if (options.twelvehour) { + radius = outerRadius; + } + + // Radian should in range [0, 2PI] + if (radian < 0) { + radian = Math.PI * 2 + radian; + } + + // Get the round value + value = Math.round(radian / unit); + + // Get the round radian + radian = value * unit; + + // Correct the hours or minutes + if (options.twelvehour) { + if (isHours) { + if (value === 0) { + value = 12; + } + } else { + if (roundBy5) { + value *= 5; + } + if (value === 60) { + value = 0; + } + } + } else { + if (isHours) { + if (value === 12) { + value = 0; + } + value = inner ? (value === 0 ? 12 : value) : value === 0 ? 0 : value + 12; + } else { + if (roundBy5) { + value *= 5; + } + if (value === 60) { + value = 0; + } + } + } + + // Once hours or minutes changed, vibrate the device + if (this[this.currentView] !== value) { + if (vibrate && this.options.vibrate) { + // Do not vibrate too frequently + if (! this.vibrateTimer) { + navigator[vibrate](10); + this.vibrateTimer = setTimeout($.proxy(function(){ + this.vibrateTimer = null; + }, this), 100); + } + } + } + + this[this.currentView] = value; + this[isHours ? 'spanHours' : 'spanMinutes'].html(leadingZero(value)); + + // If svg is not supported, just add an active class to the tick + //if (! svgSupported) { + this[isHours ? 'hoursView' : 'minutesView'].find('.clockpicker-tick').each(function(){ + var tick = $(this); + tick.toggleClass('active', value === + tick.html()); + }); + //return; + //} + + + + // Place clock hand at the top when dragging + if (dragging || (! isHours && value % 5)) { + this.g.insertBefore(this.hand, this.bearing); + this.g.insertBefore(this.bg, this.fg); + this.bg.setAttribute('class', 'clockpicker-canvas-bg clockpicker-canvas-bg-trans'); + } else { + // Or place it at the bottom + this.g.insertBefore(this.hand, this.bg); + this.g.insertBefore(this.fg, this.bg); + this.bg.setAttribute('class', 'clockpicker-canvas-bg'); + } + + // Set clock hand and others' position + var cx = Math.sin(radian) * radius, + cy = - Math.cos(radian) * radius; + this.hand.setAttribute('x2', cx); + this.hand.setAttribute('y2', cy); + this.bg.setAttribute('cx', cx); + this.bg.setAttribute('cy', cy); + this.fg.setAttribute('cx', cx); + this.fg.setAttribute('cy', cy); + }; + + // Hours and minutes are selected + ClockPicker.prototype.done = function() { + raiseCallback(this.options.beforeDone); + this.hide(); + var last = this.input.prop('value'), + value = leadingZero(this.hours) + ':' + leadingZero(this.minutes); + if (this.options.twelvehour) { + value = value + this.amOrPm; + } + + this.input.prop('value', value); + if (value !== last) { + this.input.triggerHandler('change'); + if (! this.isInput) { + this.element.trigger('change'); + } + } + + if (this.options.autoclose) { + this.input.trigger('blur'); + } + + raiseCallback(this.options.afterDone); + }; + + // Remove clockpicker from input + ClockPicker.prototype.remove = function() { + this.element.removeData('clockpicker'); + this.input.off('focus.clockpicker click.clockpicker'); + this.addon.off('click.clockpicker'); + if (this.isShown) { + this.hide(); + } + if (this.isAppended) { + $win.off('resize.clockpicker' + this.id); + this.popover.remove(); + } + }; + + // Extends $.fn.clockpicker + $.fn.clockpicker = function(option){ + var args = Array.prototype.slice.call(arguments, 1); + return this.each(function(){ + var $this = $(this), + data = $this.data('clockpicker'); + if (! data) { + var options = $.extend({}, ClockPicker.DEFAULTS, $this.data(), typeof option == 'object' && option); + $this.data('clockpicker', new ClockPicker($this, options)); + } else { + // Manual operatsions. show, hide, remove, e.g. + if (typeof data[option] === 'function') { + data[option].apply(data, args); + } + } + }); + }; +}()); diff --git a/js/datalist.js b/js/datalist.js index 158f50d..ba16cd0 100644 --- a/js/datalist.js +++ b/js/datalist.js @@ -1,106 +1,106 @@ -$(function () { - const toggleIcon = (el, fromClass, toClass) => $(el).removeClass(fromClass).addClass(toClass); - - const ocultaTodos = () => { - toggleIcon('.datalist .icono', 'ing-cancelar iconoAzul pointer', 'ing-buscar'); - $('.datalist ul').hide(); - }; - - $(document) - .on('click', '.datalist-input,.icono', function () { - const parent = $(this).parent(); - $(".datalist ul:visible").not(parent.find('ul')).siblings('.datalist-input').trigger('click'); - if (parent.find('ul').is(':visible') || parent.hasClass("disabled")) return ocultaTodos(); - - parent.find('ul, .datalist-input').show(); - toggleIcon(parent.find('.icono'), 'ing-buscar', 'ing-cancelar iconoAzul pointer'); - }) - .on('click', '.datalist-select > ul li:not(.not-selectable)', function () { - const parent = $(this).closest('.datalist'); - parent.find('.datalist-input').text($(this).text().trim()); - parent.find("input[type=hidden]").val($(this).data('id')); - $('.datalist li').removeClass("selected"); - $(this).addClass("selected"); - parent.removeClass("datalist-invalid"); - ocultaTodos(); - }) - .on('click', (e) => { - if (!$(e.target).closest('.datalist').length) ocultaTodos(); - }); - - $('.modal').on('hide.bs.modal', ocultaTodos); -}); -const setDatalist = (selector, value = -1) => { - const parent = $(selector).closest('.datalist'); - parent.find('ul li:not(.not-selectable)').each(function () { - if ($(this).data("id") !== value) return; - parent.find('.datalist-input').text($(this).text().trim()); - $(selector).val(value); - $('.datalist li').removeClass("selected"); - $(this).addClass("selected"); - $(this).click(); - }); -} -const makeRequiredDatalist = (selector, required = true) => $(selector).closest('.datalist').toggleClass("required", required); - -//--------- - -function setDatalistFirst(selector) { - var index = 1; - var elementRoot = $(selector).parents('.datalist'); - var num = elementRoot.find('ul li:not(.not-selectable)').length; - if (index <= num) { - while (elementRoot.find('ul li:nth-child(' + index + ')').hasClass("not-selectable") && index <= num) { - index++; - } - var element = elementRoot.find('ul li:nth-child(' + index + ')'); - elementRoot.find('.datalist-input').text(element.html().replace(/[\t\n]+/g, ' ').trim()); - $(selector).val(element.data("id")); - elementRoot.find("li").removeClass("selected"); - element.addClass("selected"); - } -} - - -function disableDatalist(selector, disabled = true) { - var elementRoot = $(selector).parents('.datalist'); - if (disabled) { - elementRoot.addClass("disabled"); - elementRoot.find('.icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar'); - elementRoot.find('ul').hide(); - } else - elementRoot.removeClass("disabled"); -} - -function invalidDatalist(selector, invalid = true) { - var elementRoot = $(selector).parents('.datalist'); - if (invalid) { - elementRoot.addClass("datalist-invalid"); - } else - elementRoot.removeClass("datalist-invalid"); -} - -//驴Se usa? -function buscaDatalist(selector, valor) { - selector.find('ul li').each(function () { - var elem = $(this); - if ($(this).parent().is('li')) - elem = $(this).parent(); - if (!$(this).html().toUpperCase().includes(valor.toUpperCase())) { - $(elem).hide(); - selector.find('.datalist-input').val(""); - selector.find("input[type=hidden]").val(""); - } else - $(elem).show(); - }); -} -function getDatalistText(selector, valor) { - var elementRoot = $(selector).parents('.datalist'); - var text = ""; - $.each(elementRoot.find('ul li:not(.not-selectable)'), function () { - if ($(this).data("id") == valor) { - text = $(this).html(); - } - }); - return text; -} +$(function () { + const toggleIcon = (el, fromClass, toClass) => $(el).removeClass(fromClass).addClass(toClass); + + const ocultaTodos = () => { + toggleIcon('.datalist .icono', 'ing-cancelar iconoAzul pointer', 'ing-buscar'); + $('.datalist ul').hide(); + }; + + $(document) + .on('click', '.datalist-input,.icono', function () { + const parent = $(this).parent(); + $(".datalist ul:visible").not(parent.find('ul')).siblings('.datalist-input').trigger('click'); + if (parent.find('ul').is(':visible') || parent.hasClass("disabled")) return ocultaTodos(); + + parent.find('ul, .datalist-input').show(); + toggleIcon(parent.find('.icono'), 'ing-buscar', 'ing-cancelar iconoAzul pointer'); + }) + .on('click', '.datalist-select > ul li:not(.not-selectable)', function () { + const parent = $(this).closest('.datalist'); + parent.find('.datalist-input').text($(this).text().trim()); + parent.find("input[type=hidden]").val($(this).data('id')); + $('.datalist li').removeClass("selected"); + $(this).addClass("selected"); + parent.removeClass("datalist-invalid"); + ocultaTodos(); + }) + .on('click', (e) => { + if (!$(e.target).closest('.datalist').length) ocultaTodos(); + }); + + $('.modal').on('hide.bs.modal', ocultaTodos); +}); +const setDatalist = (selector, value = -1) => { + const parent = $(selector).closest('.datalist'); + parent.find('ul li:not(.not-selectable)').each(function () { + if ($(this).data("id") !== value) return; + parent.find('.datalist-input').text($(this).text().trim()); + $(selector).val(value); + $('.datalist li').removeClass("selected"); + $(this).addClass("selected"); + $(this).click(); + }); +} +const makeRequiredDatalist = (selector, required = true) => $(selector).closest('.datalist').toggleClass("required", required); + +//--------- + +function setDatalistFirst(selector) { + var index = 1; + var elementRoot = $(selector).parents('.datalist'); + var num = elementRoot.find('ul li:not(.not-selectable)').length; + if (index <= num) { + while (elementRoot.find('ul li:nth-child(' + index + ')').hasClass("not-selectable") && index <= num) { + index++; + } + var element = elementRoot.find('ul li:nth-child(' + index + ')'); + elementRoot.find('.datalist-input').text(element.html().replace(/[\t\n]+/g, ' ').trim()); + $(selector).val(element.data("id")); + elementRoot.find("li").removeClass("selected"); + element.addClass("selected"); + } +} + + +function disableDatalist(selector, disabled = true) { + var elementRoot = $(selector).parents('.datalist'); + if (disabled) { + elementRoot.addClass("disabled"); + elementRoot.find('.icono').removeClass('ing-cancelar iconoAzul pointer').addClass('ing-buscar'); + elementRoot.find('ul').hide(); + } else + elementRoot.removeClass("disabled"); +} + +function invalidDatalist(selector, invalid = true) { + var elementRoot = $(selector).parents('.datalist'); + if (invalid) { + elementRoot.addClass("datalist-invalid"); + } else + elementRoot.removeClass("datalist-invalid"); +} + +//驴Se usa? +function buscaDatalist(selector, valor) { + selector.find('ul li').each(function () { + var elem = $(this); + if ($(this).parent().is('li')) + elem = $(this).parent(); + if (!$(this).html().toUpperCase().includes(valor.toUpperCase())) { + $(elem).hide(); + selector.find('.datalist-input').val(""); + selector.find("input[type=hidden]").val(""); + } else + $(elem).show(); + }); +} +function getDatalistText(selector, valor) { + var elementRoot = $(selector).parents('.datalist'); + var text = ""; + $.each(elementRoot.find('ul li:not(.not-selectable)'), function () { + if ($(this).data("id") == valor) { + text = $(this).html(); + } + }); + return text; +} diff --git a/js/datepicker-es.js b/js/datepicker-es.js index ea7116e..f72e195 100644 --- a/js/datepicker-es.js +++ b/js/datepicker-es.js @@ -1,37 +1,37 @@ -/* Inicializaci贸n en espa帽ol para la extensi贸n 'UI date picker' para jQuery. */ -/* Traducido por Vester (xvester@gmail.com). */ -( function( factory ) { - if ( typeof define === "function" && define.amd ) { - - // AMD. Register as an anonymous module. - define( [ "../widgets/datepicker" ], factory ); - } else { - - // Browser globals - factory( jQuery.datepicker ); - } -}( function( datepicker ) { - -datepicker.regional.es = { - closeText: "Cerrar", - prevText: "<Ant", - nextText: "Sig>", - currentText: "Hoy", - monthNames: [ "enero","febrero","marzo","abril","mayo","junio", - "julio","agosto","septiembre","octubre","noviembre","diciembre" ], - monthNamesShort: [ "ene","feb","mar","abr","may","jun", - "jul","ago","sep","oct","nov","dic" ], - dayNames: [ "domingo","lunes","martes","mi茅rcoles","jueves","viernes","s谩bado" ], - dayNamesShort: [ "dom","lun","mar","mi茅","jue","vie","s谩b" ], - dayNamesMin: [ "D","L","M","X","J","V","S" ], - weekHeader: "Sm", - dateFormat: "dd/mm/yy", - firstDay: 1, - isRTL: false, - showMonthAfterYear: false, - yearSuffix: "" }; -datepicker.setDefaults( datepicker.regional.es ); - -return datepicker.regional.es; - -} ) ); +/* Inicializaci贸n en espa帽ol para la extensi贸n 'UI date picker' para jQuery. */ +/* Traducido por Vester (xvester@gmail.com). */ +( function( factory ) { + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ "../widgets/datepicker" ], factory ); + } else { + + // Browser globals + factory( jQuery.datepicker ); + } +}( function( datepicker ) { + +datepicker.regional.es = { + closeText: "Cerrar", + prevText: "<Ant", + nextText: "Sig>", + currentText: "Hoy", + monthNames: [ "enero","febrero","marzo","abril","mayo","junio", + "julio","agosto","septiembre","octubre","noviembre","diciembre" ], + monthNamesShort: [ "ene","feb","mar","abr","may","jun", + "jul","ago","sep","oct","nov","dic" ], + dayNames: [ "domingo","lunes","martes","mi茅rcoles","jueves","viernes","s谩bado" ], + dayNamesShort: [ "dom","lun","mar","mi茅","jue","vie","s谩b" ], + dayNamesMin: [ "D","L","M","X","J","V","S" ], + weekHeader: "Sm", + dateFormat: "dd/mm/yy", + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: "" }; +datepicker.setDefaults( datepicker.regional.es ); + +return datepicker.regional.es; + +} ) ); diff --git a/js/faltas.js b/js/faltas.js index b1ffe85..4aa3b58 100644 --- a/js/faltas.js +++ b/js/faltas.js @@ -1,84 +1,84 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; -const filter = reactive({ - facultad: -1, - profesor: '', - porcentaje: 0, - faltas: 0, - tipoFaltas: true, -}); - -const app = createApp({ - filter, - facultades: [], - profesores: [], - faltas: [], - mensaje: { - titulo: '', - texto: '', - }, - async refresh() { - if (filter.facultad == -1 || (filter.porcentaje < 10 && filter.faltas < 1)) { - console.log('Facultad: ', filter.facultad, 'Porcentaje: ', filter.porcentaje, 'Faltas: ', filter.faltas); - return; - } - $('#cargando').modal('show'); - try { - - this.faltas = await fetch(`action/profesor_faltas.php?facultad=${this.filter.facultad}&${this.filter.tipoFaltas ? 'supervisor' : 'profesor'}&${this.filter.faltas > 0 ? 'faltas' : 'porcentaje'}=${this.filter.faltas > 0 ? this.filter.faltas : this.filter.porcentaje}`).then(res => res.json()); - if (this.faltas.error) { - $('.modal#mensaje').modal('show'); - this.mensaje.titulo = 'Informaci贸n'; - this.mensaje.texto = this.faltas.error; - } - } catch (error) { - $('.modal#mensaje').modal('show'); - this.mensaje.titulo = 'Error'; - this.mensaje.texto = 'No se pudo cargar los datos'; - } - finally { - $('#cargando').modal('hide'); - } - }, - - async toExcel() { - if (filter.facultad == -1 || filter.porcentaje < 10) { - return; - } - $('#cargando').modal('show'); - try { - const response = await fetch(`export/faltas_excel.php`, { - method: 'POST', - body: JSON.stringify(this.faltas.map(falta => ({ - 'profesor_clave': falta.profesor.profesor_clave, - 'profesor_correo': falta.profesor.profesor_correo, - 'profesor_nombre': falta.profesor.profesor_nombre, - 'faltas': falta.faltas, - 'porcentaje': `${falta.porcentaje}%`, - 'total': falta.total, - }))), - }) - - const blob = await response.blob(); - window.saveAs(blob, `faltas_${this.facultades.find(facultad => facultad.facultad_id == filter.facultad).facultad_nombre}_${new Date().toISOString().slice(0, 10)}.xlsx`); - } catch (error) { - $('.modal#mensaje').modal('show'); - this.mensaje.titulo = 'Error'; - this.mensaje.texto = 'No se pudo cargar los datos'; - console.log('Error: ', error); - } - finally { - $('#cargando').modal('hide'); - } - }, - async mounted() { - try { - this.facultades = await fetch('action/action_facultad.php').then(res => res.json()); - this.profesores = await fetch('action/action_profesor.php').then(res => res.json()); - } catch (error) { - $('.modal#mensaje').modal('show'); - this.mensaje.titulo = 'Error'; - this.mensaje.texto = 'No se pudo cargar los datos'; - console.log('Error: ', error); - } - } -}).mount('#app'); +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; +const filter = reactive({ + facultad: -1, + profesor: '', + porcentaje: 0, + faltas: 0, + tipoFaltas: true, +}); + +const app = createApp({ + filter, + facultades: [], + profesores: [], + faltas: [], + mensaje: { + titulo: '', + texto: '', + }, + async refresh() { + if (filter.facultad == -1 || (filter.porcentaje < 10 && filter.faltas < 1)) { + console.log('Facultad: ', filter.facultad, 'Porcentaje: ', filter.porcentaje, 'Faltas: ', filter.faltas); + return; + } + $('#cargando').modal('show'); + try { + + this.faltas = await fetch(`action/profesor_faltas.php?facultad=${this.filter.facultad}&${this.filter.tipoFaltas ? 'supervisor' : 'profesor'}&${this.filter.faltas > 0 ? 'faltas' : 'porcentaje'}=${this.filter.faltas > 0 ? this.filter.faltas : this.filter.porcentaje}`).then(res => res.json()); + if (this.faltas.error) { + $('.modal#mensaje').modal('show'); + this.mensaje.titulo = 'Informaci贸n'; + this.mensaje.texto = this.faltas.error; + } + } catch (error) { + $('.modal#mensaje').modal('show'); + this.mensaje.titulo = 'Error'; + this.mensaje.texto = 'No se pudo cargar los datos'; + } + finally { + $('#cargando').modal('hide'); + } + }, + + async toExcel() { + if (filter.facultad == -1 || filter.porcentaje < 10) { + return; + } + $('#cargando').modal('show'); + try { + const response = await fetch(`export/faltas_excel.php`, { + method: 'POST', + body: JSON.stringify(this.faltas.map(falta => ({ + 'profesor_clave': falta.profesor.profesor_clave, + 'profesor_correo': falta.profesor.profesor_correo, + 'profesor_nombre': falta.profesor.profesor_nombre, + 'faltas': falta.faltas, + 'porcentaje': `${falta.porcentaje}%`, + 'total': falta.total, + }))), + }) + + const blob = await response.blob(); + window.saveAs(blob, `faltas_${this.facultades.find(facultad => facultad.facultad_id == filter.facultad).facultad_nombre}_${new Date().toISOString().slice(0, 10)}.xlsx`); + } catch (error) { + $('.modal#mensaje').modal('show'); + this.mensaje.titulo = 'Error'; + this.mensaje.texto = 'No se pudo cargar los datos'; + console.log('Error: ', error); + } + finally { + $('#cargando').modal('hide'); + } + }, + async mounted() { + try { + this.facultades = await fetch('action/action_facultad.php').then(res => res.json()); + this.profesores = await fetch('action/action_profesor.php').then(res => res.json()); + } catch (error) { + $('.modal#mensaje').modal('show'); + this.mensaje.titulo = 'Error'; + this.mensaje.texto = 'No se pudo cargar los datos'; + console.log('Error: ', error); + } + } +}).mount('#app'); diff --git a/js/horario.js b/js/horario.js index b84d5a3..cc04acc 100644 --- a/js/horario.js +++ b/js/horario.js @@ -1,106 +1,106 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; -const profesores = reactive({ - data: [], - search: null, - fetch: async function () { - const response = await fetch('action/action_profesor.php'); - this.data = await response.json(); - }, - get clave() { - const match = this.search.match(/^\((.+)\)/); - return match ? match[1] : ''; - }, - get current() { - return this.data.find((profesor) => profesor.profesor_clave === profesores.clave); - }, -}); -const facultades = reactive({ - data: [], - fetch: async function () { - const facultades = await fetch('action/action_facultad.php').then(response => response.json()); - const carreras = await fetch(`action/carrera.php`).then(response => response.json()); - this.data = await Promise.all(facultades.map(async (facultad) => ({ - ...facultad, - carreras: await Promise.all(carreras.filter((carrera) => carrera.facultad_id === facultad.facultad_id).map(async (carrera) => { - const grupos = await fetch(`action/action_grupo.php?carrera_id=${carrera.carrera_id}`).then(response => response.json()); - return { - ...carrera, - grupos, - }; - })), - }))); - this.data = this.data.filter((facultad) => facultad.carreras.length > 0); - } -}); -const horarios = reactive({ - data: [], - fetch: async function (grupo = null, carrera_id = null) { - if (grupo && carrera_id) { - const response = await fetch(`action/action_horario.php?grupo=${grupo}&carrera_id=${carrera_id}`); - this.data = await response.json(); - } - else if (profesores.current) { - const response = await fetch(`action/action_horario.php?profesor_id=${profesores.current.profesor_id}`); - this.data = await response.json(); - } - }, - get structure() { - if (this.data.length === 0) - return null; - const structure = { - s谩bado: this.data.some((horario) => horario.horario_dia === 6), - hora_m铆nima: Math.min(...this.data.map((horario) => parseInt(horario.horario_hora.split(':')[0]))), - hora_m谩xima: Math.max(...this.data.map((horario) => { - const [hour, minute] = horario.horario_fin.split(':').map(Number); - return hour + Math.ceil(minute / 60); - })), - horas_totales: 0 - }; - structure.horas_totales = structure.hora_m谩xima - structure.hora_m铆nima; - return structure; - }, - get blocks() { - if (this.data.length === 0) - return null; - return [...Array(this.structure.horas_totales).keys()].flatMap(hora => { - const baseHour = hora + this.structure.hora_m铆nima; - return [0, 15, 30, 45].map(block => ({ hour: baseHour, block })); - }); - }, - getHorarioData(hour, block, d铆a) { - const foundHorario = this.data.find((horario) => parseInt(horario.horario_hora.split(':')[0]) === hour && - parseInt(horario.horario_hora.split(':')[1]) === block && - horario.horario_dia === d铆a); - return foundHorario; - }, - isOccupied(hora, bloque, day) { - if (this.getHorarioData(hora, bloque, day)) { - return false; - } - const currentTimeInMinutes = hora * 60 + bloque; - for (const item of this.data) { - if (item.horario_dia !== day) { - continue; // Skip items that are not on the specified day - } - // Split the hour and minute from horario_hora - const [startHour, startMinute] = item.horario_hora.split(":").map(Number); - const startTimeInMinutes = startHour * 60 + startMinute; - // Calculate end time using duracion - const [durationHours, durationMinutes] = item.duracion.split(":").map(Number); - const endTimeInMinutes = startTimeInMinutes + (durationHours * 60) + durationMinutes; - if (currentTimeInMinutes >= startTimeInMinutes && currentTimeInMinutes < endTimeInMinutes) { - return true; // The block is occupied - } - } - return false; // The block is not occupied by any class - } -}); -const app = createApp({ - profesores, - horarios, - facultades, - mounted: async function () { - await profesores.fetch(); - await facultades.fetch(); - } -}).mount('#app'); +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; +const profesores = reactive({ + data: [], + search: null, + fetch: async function () { + const response = await fetch('action/action_profesor.php'); + this.data = await response.json(); + }, + get clave() { + const match = this.search.match(/^\((.+)\)/); + return match ? match[1] : ''; + }, + get current() { + return this.data.find((profesor) => profesor.profesor_clave === profesores.clave); + }, +}); +const facultades = reactive({ + data: [], + fetch: async function () { + const facultades = await fetch('action/action_facultad.php').then(response => response.json()); + const carreras = await fetch(`action/carrera.php`).then(response => response.json()); + this.data = await Promise.all(facultades.map(async (facultad) => ({ + ...facultad, + carreras: await Promise.all(carreras.filter((carrera) => carrera.facultad_id === facultad.facultad_id).map(async (carrera) => { + const grupos = await fetch(`action/action_grupo.php?carrera_id=${carrera.carrera_id}`).then(response => response.json()); + return { + ...carrera, + grupos, + }; + })), + }))); + this.data = this.data.filter((facultad) => facultad.carreras.length > 0); + } +}); +const horarios = reactive({ + data: [], + fetch: async function (grupo = null, carrera_id = null) { + if (grupo && carrera_id) { + const response = await fetch(`action/action_horario.php?grupo=${grupo}&carrera_id=${carrera_id}`); + this.data = await response.json(); + } + else if (profesores.current) { + const response = await fetch(`action/action_horario.php?profesor_id=${profesores.current.profesor_id}`); + this.data = await response.json(); + } + }, + get structure() { + if (this.data.length === 0) + return null; + const structure = { + s谩bado: this.data.some((horario) => horario.horario_dia === 6), + hora_m铆nima: Math.min(...this.data.map((horario) => parseInt(horario.horario_hora.split(':')[0]))), + hora_m谩xima: Math.max(...this.data.map((horario) => { + const [hour, minute] = horario.horario_fin.split(':').map(Number); + return hour + Math.ceil(minute / 60); + })), + horas_totales: 0 + }; + structure.horas_totales = structure.hora_m谩xima - structure.hora_m铆nima; + return structure; + }, + get blocks() { + if (this.data.length === 0) + return null; + return [...Array(this.structure.horas_totales).keys()].flatMap(hora => { + const baseHour = hora + this.structure.hora_m铆nima; + return [0, 15, 30, 45].map(block => ({ hour: baseHour, block })); + }); + }, + getHorarioData(hour, block, d铆a) { + const foundHorario = this.data.find((horario) => parseInt(horario.horario_hora.split(':')[0]) === hour && + parseInt(horario.horario_hora.split(':')[1]) === block && + horario.horario_dia === d铆a); + return foundHorario; + }, + isOccupied(hora, bloque, day) { + if (this.getHorarioData(hora, bloque, day)) { + return false; + } + const currentTimeInMinutes = hora * 60 + bloque; + for (const item of this.data) { + if (item.horario_dia !== day) { + continue; // Skip items that are not on the specified day + } + // Split the hour and minute from horario_hora + const [startHour, startMinute] = item.horario_hora.split(":").map(Number); + const startTimeInMinutes = startHour * 60 + startMinute; + // Calculate end time using duracion + const [durationHours, durationMinutes] = item.duracion.split(":").map(Number); + const endTimeInMinutes = startTimeInMinutes + (durationHours * 60) + durationMinutes; + if (currentTimeInMinutes >= startTimeInMinutes && currentTimeInMinutes < endTimeInMinutes) { + return true; // The block is occupied + } + } + return false; // The block is not occupied by any class + } +}); +const app = createApp({ + profesores, + horarios, + facultades, + mounted: async function () { + await profesores.fetch(); + await facultades.fetch(); + } +}).mount('#app'); diff --git a/js/jquery-ui.js b/js/jquery-ui.js index 25398a1..1396c9b 100644 --- a/js/jquery-ui.js +++ b/js/jquery-ui.js @@ -1,13 +1,13 @@ -/*! jQuery UI - v1.12.1 - 2016-09-14 -* http://jqueryui.com -* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js -* Copyright jQuery Foundation and other contributors; Licensed MIT */ - -(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)})(function(t){function e(t){for(var e=t.css("visibility");"inherit"===e;)t=t.parent(),e=t.css("visibility");return"hidden"!==e}function i(t){for(var e,i;t.length&&t[0]!==document;){if(e=t.css("position"),("absolute"===e||"relative"===e||"fixed"===e)&&(i=parseInt(t.css("zIndex"),10),!isNaN(i)&&0!==i))return i;t=t.parent()}return 0}function s(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.regional.en=t.extend(!0,{},this.regional[""]),this.regional["en-US"]=t.extend(!0,{},this.regional.en),this.dpDiv=n(t("
"))}function n(e){var i="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.on("mouseout",i,function(){t(this).removeClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).removeClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).removeClass("ui-datepicker-next-hover")}).on("mouseover",i,o)}function o(){t.datepicker._isDisabledDatepicker(m.inline?m.dpDiv.parent()[0]:m.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),-1!==this.className.indexOf("ui-datepicker-prev")&&t(this).addClass("ui-datepicker-prev-hover"),-1!==this.className.indexOf("ui-datepicker-next")&&t(this).addClass("ui-datepicker-next-hover"))}function a(e,i){t.extend(e,i);for(var s in i)null==i[s]&&(e[s]=i[s]);return e}function r(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.ui=t.ui||{},t.ui.version="1.12.1";var h=0,l=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,o;for(o=0;null!=(n=i[o]);o++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(a){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,o,a,r={},h=e.split(".")[0];e=e.split(".")[1];var l=h+"-"+e;return s||(s=i,i=t.Widget),t.isArray(s)&&(s=t.extend.apply(null,[{}].concat(s))),t.expr[":"][l.toLowerCase()]=function(e){return!!t.data(e,l)},t[h]=t[h]||{},n=t[h][e],o=t[h][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,n,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),a=new i,a.options=t.widget.extend({},a.options),t.each(s,function(e,s){return t.isFunction(s)?(r[e]=function(){function t(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}return function(){var e,i=this._super,o=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=o,e}}(),void 0):(r[e]=s,void 0)}),o.prototype=t.widget.extend(a,{widgetEventPrefix:n?a.widgetEventPrefix||e:e},r,{constructor:o,namespace:h,widgetName:e,widgetFullName:l}),n?(t.each(n._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete n._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var i,s,n=l.call(arguments,1),o=0,a=n.length;a>o;o++)for(i in n[o])s=n[o][i],n[o].hasOwnProperty(i)&&void 0!==s&&(e[i]=t.isPlainObject(s)?t.isPlainObject(e[i])?t.widget.extend({},e[i],s):t.widget.extend({},s):s);return e},t.widget.bridge=function(e,i){var s=i.prototype.widgetFullName||e;t.fn[e]=function(n){var o="string"==typeof n,a=l.call(arguments,1),r=this;return o?this.length||"instance"!==n?this.each(function(){var i,o=t.data(this,s);return"instance"===n?(r=o,!1):o?t.isFunction(o[n])&&"_"!==n.charAt(0)?(i=o[n].apply(o,a),i!==o&&void 0!==i?(r=i&&i.jquery?r.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+n+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+n+"'")}):r=void 0:(a.length&&(n=t.widget.extend.apply(null,[n].concat(a))),this.each(function(){var e=t.data(this,s);e?(e.option(n||{}),e._init&&e._init()):t.data(this,s,new i(n,this))})),r}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,i){i=t(i||this.defaultElement||this)[0],this.element=t(i),this.uuid=h++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},i!==this&&(t.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===i&&this.destroy()}}),this.document=t(i.style?i.ownerDocument:i.document||i),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
"),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,g=-2*e.offset[1];0>c?(s=t.top+p+f+g+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+g)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+g-h,(i>0||u>a(i))&&(t.top+=p+f+g))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}});var c="ui-effects-",u="ui-effects-style",d="ui-effects-animated",p=t;t.effects={effect:{}},function(t,e){function i(t,e,i){var s=u[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:0>t?0:t>s.max?s.max:t)}function s(i){var s=l(),n=s._rgba=[];return i=i.toLowerCase(),f(h,function(t,o){var a,r=o.re.exec(i),h=r&&o.parse(r),l=o.space||"rgba";return h?(a=s[l](h),s[c[l].cache]=a[c[l].cache],n=s._rgba=a._rgba,!1):e}),n.length?("0,0,0,0"===n.join()&&t.extend(n,o.transparent),s):o[i]}function n(t,e,i){return i=(i+1)%1,1>6*i?t+6*(e-t)*i:1>2*i?e:2>3*i?t+6*(e-t)*(2/3-i):t}var o,a="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",r=/^([\-+])=\s*(\d+\.?\d*)/,h=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[t[1],t[2],t[3],t[4]]}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(t){return[2.55*t[1],2.55*t[2],2.55*t[3],t[4]]}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(t){return[parseInt(t[1],16),parseInt(t[2],16),parseInt(t[3],16)]}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(t){return[parseInt(t[1]+t[1],16),parseInt(t[2]+t[2],16),parseInt(t[3]+t[3],16)]}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(t){return[t[1],t[2]/100,t[3]/100,t[4]]}}],l=t.Color=function(e,i,s,n){return new t.Color.fn.parse(e,i,s,n)},c={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},u={"byte":{floor:!0,max:255},percent:{max:1},degrees:{mod:360,floor:!0}},d=l.support={},p=t("

")[0],f=t.each;p.style.cssText="background-color:rgba(1,1,1,.5)",d.rgba=p.style.backgroundColor.indexOf("rgba")>-1,f(c,function(t,e){e.cache="_"+t,e.props.alpha={idx:3,type:"percent",def:1}}),l.fn=t.extend(l.prototype,{parse:function(n,a,r,h){if(n===e)return this._rgba=[null,null,null,null],this;(n.jquery||n.nodeType)&&(n=t(n).css(a),a=e);var u=this,d=t.type(n),p=this._rgba=[];return a!==e&&(n=[n,a,r,h],d="array"),"string"===d?this.parse(s(n)||o._default):"array"===d?(f(c.rgba.props,function(t,e){p[e.idx]=i(n[e.idx],e)}),this):"object"===d?(n instanceof l?f(c,function(t,e){n[e.cache]&&(u[e.cache]=n[e.cache].slice())}):f(c,function(e,s){var o=s.cache;f(s.props,function(t,e){if(!u[o]&&s.to){if("alpha"===t||null==n[t])return;u[o]=s.to(u._rgba)}u[o][e.idx]=i(n[t],e,!0)}),u[o]&&0>t.inArray(null,u[o].slice(0,3))&&(u[o][3]=1,s.from&&(u._rgba=s.from(u[o])))}),this):e},is:function(t){var i=l(t),s=!0,n=this;return f(c,function(t,o){var a,r=i[o.cache];return r&&(a=n[o.cache]||o.to&&o.to(n._rgba)||[],f(o.props,function(t,i){return null!=r[i.idx]?s=r[i.idx]===a[i.idx]:e})),s}),s},_space:function(){var t=[],e=this;return f(c,function(i,s){e[s.cache]&&t.push(i)}),t.pop()},transition:function(t,e){var s=l(t),n=s._space(),o=c[n],a=0===this.alpha()?l("transparent"):this,r=a[o.cache]||o.to(a._rgba),h=r.slice();return s=s[o.cache],f(o.props,function(t,n){var o=n.idx,a=r[o],l=s[o],c=u[n.type]||{};null!==l&&(null===a?h[o]=l:(c.mod&&(l-a>c.mod/2?a+=c.mod:a-l>c.mod/2&&(a-=c.mod)),h[o]=i((l-a)*e+a,n)))}),this[n](h)},blend:function(e){if(1===this._rgba[3])return this;var i=this._rgba.slice(),s=i.pop(),n=l(e)._rgba;return l(t.map(i,function(t,e){return(1-s)*n[e]+s*t}))},toRgbaString:function(){var e="rgba(",i=t.map(this._rgba,function(t,e){return null==t?e>2?1:0:t});return 1===i[3]&&(i.pop(),e="rgb("),e+i.join()+")"},toHslaString:function(){var e="hsla(",i=t.map(this.hsla(),function(t,e){return null==t&&(t=e>2?1:0),e&&3>e&&(t=Math.round(100*t)+"%"),t});return 1===i[3]&&(i.pop(),e="hsl("),e+i.join()+")"},toHexString:function(e){var i=this._rgba.slice(),s=i.pop();return e&&i.push(~~(255*s)),"#"+t.map(i,function(t){return t=(t||0).toString(16),1===t.length?"0"+t:t}).join("")},toString:function(){return 0===this._rgba[3]?"transparent":this.toRgbaString()}}),l.fn.parse.prototype=l.fn,c.hsla.to=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e,i,s=t[0]/255,n=t[1]/255,o=t[2]/255,a=t[3],r=Math.max(s,n,o),h=Math.min(s,n,o),l=r-h,c=r+h,u=.5*c;return e=h===r?0:s===r?60*(n-o)/l+360:n===r?60*(o-s)/l+120:60*(s-n)/l+240,i=0===l?0:.5>=u?l/c:l/(2-c),[Math.round(e)%360,i,u,null==a?1:a]},c.hsla.from=function(t){if(null==t[0]||null==t[1]||null==t[2])return[null,null,null,t[3]];var e=t[0]/360,i=t[1],s=t[2],o=t[3],a=.5>=s?s*(1+i):s+i-s*i,r=2*s-a;return[Math.round(255*n(r,a,e+1/3)),Math.round(255*n(r,a,e)),Math.round(255*n(r,a,e-1/3)),o]},f(c,function(s,n){var o=n.props,a=n.cache,h=n.to,c=n.from;l.fn[s]=function(s){if(h&&!this[a]&&(this[a]=h(this._rgba)),s===e)return this[a].slice();var n,r=t.type(s),u="array"===r||"object"===r?s:arguments,d=this[a].slice();return f(o,function(t,e){var s=u["object"===r?t:e.idx];null==s&&(s=d[e.idx]),d[e.idx]=i(s,e)}),c?(n=l(c(d)),n[a]=d,n):l(d)},f(o,function(e,i){l.fn[e]||(l.fn[e]=function(n){var o,a=t.type(n),h="alpha"===e?this._hsla?"hsla":"rgba":s,l=this[h](),c=l[i.idx];return"undefined"===a?c:("function"===a&&(n=n.call(this,c),a=t.type(n)),null==n&&i.empty?this:("string"===a&&(o=r.exec(n),o&&(n=c+parseFloat(o[2])*("+"===o[1]?1:-1))),l[i.idx]=n,this[h](l)))})})}),l.hook=function(e){var i=e.split(" ");f(i,function(e,i){t.cssHooks[i]={set:function(e,n){var o,a,r="";if("transparent"!==n&&("string"!==t.type(n)||(o=s(n)))){if(n=l(o||n),!d.rgba&&1!==n._rgba[3]){for(a="backgroundColor"===i?e.parentNode:e;(""===r||"transparent"===r)&&a&&a.style;)try{r=t.css(a,"backgroundColor"),a=a.parentNode}catch(h){}n=n.blend(r&&"transparent"!==r?r:"_default")}n=n.toRgbaString()}try{e.style[i]=n}catch(h){}}},t.fx.step[i]=function(e){e.colorInit||(e.start=l(e.elem,i),e.end=l(e.end),e.colorInit=!0),t.cssHooks[i].set(e.elem,e.start.transition(e.end,e.pos))}})},l.hook(a),t.cssHooks.borderColor={expand:function(t){var e={};return f(["Top","Right","Bottom","Left"],function(i,s){e["border"+s+"Color"]=t}),e}},o=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(p),function(){function e(e){var i,s,n=e.ownerDocument.defaultView?e.ownerDocument.defaultView.getComputedStyle(e,null):e.currentStyle,o={};if(n&&n.length&&n[0]&&n[n[0]])for(s=n.length;s--;)i=n[s],"string"==typeof n[i]&&(o[t.camelCase(i)]=n[i]);else for(i in n)"string"==typeof n[i]&&(o[i]=n[i]);return o}function i(e,i){var s,o,a={};for(s in i)o=i[s],e[s]!==o&&(n[s]||(t.fx.step[s]||!isNaN(parseFloat(o)))&&(a[s]=o));return a}var s=["add","remove","toggle"],n={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};t.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(e,i){t.fx.step[i]=function(t){("none"!==t.end&&!t.setAttr||1===t.pos&&!t.setAttr)&&(p.style(t.elem,i,t.end),t.setAttr=!0)}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.effects.animateClass=function(n,o,a,r){var h=t.speed(o,a,r);return this.queue(function(){var o,a=t(this),r=a.attr("class")||"",l=h.children?a.find("*").addBack():a;l=l.map(function(){var i=t(this);return{el:i,start:e(this)}}),o=function(){t.each(s,function(t,e){n[e]&&a[e+"Class"](n[e])})},o(),l=l.map(function(){return this.end=e(this.el[0]),this.diff=i(this.start,this.end),this}),a.attr("class",r),l=l.map(function(){var e=this,i=t.Deferred(),s=t.extend({},h,{queue:!1,complete:function(){i.resolve(e)}});return this.el.animate(this.diff,s),i.promise()}),t.when.apply(t,l.get()).done(function(){o(),t.each(arguments,function(){var e=this.el;t.each(this.diff,function(t){e.css(t,"")})}),h.complete.call(a[0])})})},t.fn.extend({addClass:function(e){return function(i,s,n,o){return s?t.effects.animateClass.call(this,{add:i},s,n,o):e.apply(this,arguments)}}(t.fn.addClass),removeClass:function(e){return function(i,s,n,o){return arguments.length>1?t.effects.animateClass.call(this,{remove:i},s,n,o):e.apply(this,arguments)}}(t.fn.removeClass),toggleClass:function(e){return function(i,s,n,o,a){return"boolean"==typeof s||void 0===s?n?t.effects.animateClass.call(this,s?{add:i}:{remove:i},n,o,a):e.apply(this,arguments):t.effects.animateClass.call(this,{toggle:i},s,n,o)}}(t.fn.toggleClass),switchClass:function(e,i,s,n,o){return t.effects.animateClass.call(this,{add:i,remove:e},s,n,o)}})}(),function(){function e(e,i,s,n){return t.isPlainObject(e)&&(i=e,e=e.effect),e={effect:e},null==i&&(i={}),t.isFunction(i)&&(n=i,s=null,i={}),("number"==typeof i||t.fx.speeds[i])&&(n=s,s=i,i={}),t.isFunction(s)&&(n=s,s=null),i&&t.extend(e,i),s=s||i.duration,e.duration=t.fx.off?0:"number"==typeof s?s:s in t.fx.speeds?t.fx.speeds[s]:t.fx.speeds._default,e.complete=n||i.complete,e}function i(e){return!e||"number"==typeof e||t.fx.speeds[e]?!0:"string"!=typeof e||t.effects.effect[e]?t.isFunction(e)?!0:"object"!=typeof e||e.effect?!1:!0:!0}function s(t,e){var i=e.outerWidth(),s=e.outerHeight(),n=/^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,o=n.exec(t)||["",0,i,s,0];return{top:parseFloat(o[1])||0,right:"auto"===o[2]?i:parseFloat(o[2]),bottom:"auto"===o[3]?s:parseFloat(o[3]),left:parseFloat(o[4])||0}}t.expr&&t.expr.filters&&t.expr.filters.animated&&(t.expr.filters.animated=function(e){return function(i){return!!t(i).data(d)||e(i)}}(t.expr.filters.animated)),t.uiBackCompat!==!1&&t.extend(t.effects,{save:function(t,e){for(var i=0,s=e.length;s>i;i++)null!==e[i]&&t.data(c+e[i],t[0].style[e[i]])},restore:function(t,e){for(var i,s=0,n=e.length;n>s;s++)null!==e[s]&&(i=t.data(c+e[s]),t.css(e[s],i))},setMode:function(t,e){return"toggle"===e&&(e=t.is(":hidden")?"show":"hide"),e},createWrapper:function(e){if(e.parent().is(".ui-effects-wrapper"))return e.parent();var i={width:e.outerWidth(!0),height:e.outerHeight(!0),"float":e.css("float")},s=t("

").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),n={width:e.width(),height:e.height()},o=document.activeElement;try{o.id}catch(a){o=document.body}return e.wrap(s),(e[0]===o||t.contains(e[0],o))&&t(o).trigger("focus"),s=e.parent(),"static"===e.css("position")?(s.css({position:"relative"}),e.css({position:"relative"})):(t.extend(i,{position:e.css("position"),zIndex:e.css("z-index")}),t.each(["top","left","bottom","right"],function(t,s){i[s]=e.css(s),isNaN(parseInt(i[s],10))&&(i[s]="auto")}),e.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),e.css(n),s.css(i).show()},removeWrapper:function(e){var i=document.activeElement;return e.parent().is(".ui-effects-wrapper")&&(e.parent().replaceWith(e),(e[0]===i||t.contains(e[0],i))&&t(i).trigger("focus")),e}}),t.extend(t.effects,{version:"1.12.1",define:function(e,i,s){return s||(s=i,i="effect"),t.effects.effect[e]=s,t.effects.effect[e].mode=i,s},scaledDimensions:function(t,e,i){if(0===e)return{height:0,width:0,outerHeight:0,outerWidth:0};var s="horizontal"!==i?(e||100)/100:1,n="vertical"!==i?(e||100)/100:1;return{height:t.height()*n,width:t.width()*s,outerHeight:t.outerHeight()*n,outerWidth:t.outerWidth()*s}},clipToBox:function(t){return{width:t.clip.right-t.clip.left,height:t.clip.bottom-t.clip.top,left:t.clip.left,top:t.clip.top}},unshift:function(t,e,i){var s=t.queue();e>1&&s.splice.apply(s,[1,0].concat(s.splice(e,i))),t.dequeue()},saveStyle:function(t){t.data(u,t[0].style.cssText)},restoreStyle:function(t){t[0].style.cssText=t.data(u)||"",t.removeData(u)},mode:function(t,e){var i=t.is(":hidden");return"toggle"===e&&(e=i?"show":"hide"),(i?"hide"===e:"show"===e)&&(e="none"),e},getBaseline:function(t,e){var i,s;switch(t[0]){case"top":i=0;break;case"middle":i=.5;break;case"bottom":i=1;break;default:i=t[0]/e.height}switch(t[1]){case"left":s=0;break;case"center":s=.5;break;case"right":s=1;break;default:s=t[1]/e.width}return{x:s,y:i}},createPlaceholder:function(e){var i,s=e.css("position"),n=e.position();return e.css({marginTop:e.css("marginTop"),marginBottom:e.css("marginBottom"),marginLeft:e.css("marginLeft"),marginRight:e.css("marginRight")}).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()),/^(static|relative)/.test(s)&&(s="absolute",i=t("<"+e[0].nodeName+">").insertAfter(e).css({display:/^(inline|ruby)/.test(e.css("display"))?"inline-block":"block",visibility:"hidden",marginTop:e.css("marginTop"),marginBottom:e.css("marginBottom"),marginLeft:e.css("marginLeft"),marginRight:e.css("marginRight"),"float":e.css("float")}).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).addClass("ui-effects-placeholder"),e.data(c+"placeholder",i)),e.css({position:s,left:n.left,top:n.top}),i},removePlaceholder:function(t){var e=c+"placeholder",i=t.data(e);i&&(i.remove(),t.removeData(e))},cleanUp:function(e){t.effects.restoreStyle(e),t.effects.removePlaceholder(e)},setTransition:function(e,i,s,n){return n=n||{},t.each(i,function(t,i){var o=e.cssUnit(i);o[0]>0&&(n[i]=o[0]*s+o[1])}),n}}),t.fn.extend({effect:function(){function i(e){function i(){r.removeData(d),t.effects.cleanUp(r),"hide"===s.mode&&r.hide(),a()}function a(){t.isFunction(h)&&h.call(r[0]),t.isFunction(e)&&e()}var r=t(this);s.mode=c.shift(),t.uiBackCompat===!1||o?"none"===s.mode?(r[l](),a()):n.call(r[0],s,i):(r.is(":hidden")?"hide"===l:"show"===l)?(r[l](),a()):n.call(r[0],s,a)}var s=e.apply(this,arguments),n=t.effects.effect[s.effect],o=n.mode,a=s.queue,r=a||"fx",h=s.complete,l=s.mode,c=[],u=function(e){var i=t(this),s=t.effects.mode(i,l)||o;i.data(d,!0),c.push(s),o&&("show"===s||s===o&&"hide"===s)&&i.show(),o&&"none"===s||t.effects.saveStyle(i),t.isFunction(e)&&e()};return t.fx.off||!n?l?this[l](s.duration,h):this.each(function(){h&&h.call(this)}):a===!1?this.each(u).each(i):this.queue(r,u).queue(r,i)},show:function(t){return function(s){if(i(s))return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="show",this.effect.call(this,n) -}}(t.fn.show),hide:function(t){return function(s){if(i(s))return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="hide",this.effect.call(this,n)}}(t.fn.hide),toggle:function(t){return function(s){if(i(s)||"boolean"==typeof s)return t.apply(this,arguments);var n=e.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)}}(t.fn.toggle),cssUnit:function(e){var i=this.css(e),s=[];return t.each(["em","px","%","pt"],function(t,e){i.indexOf(e)>0&&(s=[parseFloat(i),e])}),s},cssClip:function(t){return t?this.css("clip","rect("+t.top+"px "+t.right+"px "+t.bottom+"px "+t.left+"px)"):s(this.css("clip"),this)},transfer:function(e,i){var s=t(this),n=t(e.to),o="fixed"===n.css("position"),a=t("body"),r=o?a.scrollTop():0,h=o?a.scrollLeft():0,l=n.offset(),c={top:l.top-r,left:l.left-h,height:n.innerHeight(),width:n.innerWidth()},u=s.offset(),d=t("
").appendTo("body").addClass(e.className).css({top:u.top-r,left:u.left-h,height:s.innerHeight(),width:s.innerWidth(),position:o?"fixed":"absolute"}).animate(c,e.duration,e.easing,function(){d.remove(),t.isFunction(i)&&i()})}}),t.fx.step.clip=function(e){e.clipInit||(e.start=t(e.elem).cssClip(),"string"==typeof e.end&&(e.end=s(e.end,e.elem)),e.clipInit=!0),t(e.elem).cssClip({top:e.pos*(e.end.top-e.start.top)+e.start.top,right:e.pos*(e.end.right-e.start.right)+e.start.right,bottom:e.pos*(e.end.bottom-e.start.bottom)+e.start.bottom,left:e.pos*(e.end.left-e.start.left)+e.start.left})}}(),function(){var e={};t.each(["Quad","Cubic","Quart","Quint","Expo"],function(t,i){e[i]=function(e){return Math.pow(e,t+2)}}),t.extend(e,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;((e=Math.pow(2,--i))-1)/11>t;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),t.each(e,function(e,i){t.easing["easeIn"+e]=i,t.easing["easeOut"+e]=function(t){return 1-i(1-t)},t.easing["easeInOut"+e]=function(t){return.5>t?i(2*t)/2:1-i(-2*t+2)/2}})}();var f=t.effects;t.effects.define("blind","hide",function(e,i){var s={up:["bottom","top"],vertical:["bottom","top"],down:["top","bottom"],left:["right","left"],horizontal:["right","left"],right:["left","right"]},n=t(this),o=e.direction||"up",a=n.cssClip(),r={clip:t.extend({},a)},h=t.effects.createPlaceholder(n);r.clip[s[o][0]]=r.clip[s[o][1]],"show"===e.mode&&(n.cssClip(r.clip),h&&h.css(t.effects.clipToBox(r)),r.clip=a),h&&h.animate(t.effects.clipToBox(r),e.duration,e.easing),n.animate(r,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("bounce",function(e,i){var s,n,o,a=t(this),r=e.mode,h="hide"===r,l="show"===r,c=e.direction||"up",u=e.distance,d=e.times||5,p=2*d+(l||h?1:0),f=e.duration/p,g=e.easing,m="up"===c||"down"===c?"top":"left",_="up"===c||"left"===c,v=0,b=a.queue().length;for(t.effects.createPlaceholder(a),o=a.css(m),u||(u=a["top"===m?"outerHeight":"outerWidth"]()/3),l&&(n={opacity:1},n[m]=o,a.css("opacity",0).css(m,_?2*-u:2*u).animate(n,f,g)),h&&(u/=Math.pow(2,d-1)),n={},n[m]=o;d>v;v++)s={},s[m]=(_?"-=":"+=")+u,a.animate(s,f,g).animate(n,f,g),u=h?2*u:u/2;h&&(s={opacity:0},s[m]=(_?"-=":"+=")+u,a.animate(s,f,g)),a.queue(i),t.effects.unshift(a,b,p+1)}),t.effects.define("clip","hide",function(e,i){var s,n={},o=t(this),a=e.direction||"vertical",r="both"===a,h=r||"horizontal"===a,l=r||"vertical"===a;s=o.cssClip(),n.clip={top:l?(s.bottom-s.top)/2:s.top,right:h?(s.right-s.left)/2:s.right,bottom:l?(s.bottom-s.top)/2:s.bottom,left:h?(s.right-s.left)/2:s.left},t.effects.createPlaceholder(o),"show"===e.mode&&(o.cssClip(n.clip),n.clip=s),o.animate(n,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("drop","hide",function(e,i){var s,n=t(this),o=e.mode,a="show"===o,r=e.direction||"left",h="up"===r||"down"===r?"top":"left",l="up"===r||"left"===r?"-=":"+=",c="+="===l?"-=":"+=",u={opacity:0};t.effects.createPlaceholder(n),s=e.distance||n["top"===h?"outerHeight":"outerWidth"](!0)/2,u[h]=l+s,a&&(n.css(u),u[h]=c+s,u.opacity=1),n.animate(u,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("explode","hide",function(e,i){function s(){b.push(this),b.length===u*d&&n()}function n(){p.css({visibility:"visible"}),t(b).remove(),i()}var o,a,r,h,l,c,u=e.pieces?Math.round(Math.sqrt(e.pieces)):3,d=u,p=t(this),f=e.mode,g="show"===f,m=p.show().css("visibility","hidden").offset(),_=Math.ceil(p.outerWidth()/d),v=Math.ceil(p.outerHeight()/u),b=[];for(o=0;u>o;o++)for(h=m.top+o*v,c=o-(u-1)/2,a=0;d>a;a++)r=m.left+a*_,l=a-(d-1)/2,p.clone().appendTo("body").wrap("
").css({position:"absolute",visibility:"visible",left:-a*_,top:-o*v}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:_,height:v,left:r+(g?l*_:0),top:h+(g?c*v:0),opacity:g?0:1}).animate({left:r+(g?0:l*_),top:h+(g?0:c*v),opacity:g?1:0},e.duration||500,e.easing,s)}),t.effects.define("fade","toggle",function(e,i){var s="show"===e.mode;t(this).css("opacity",s?0:1).animate({opacity:s?1:0},{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("fold","hide",function(e,i){var s=t(this),n=e.mode,o="show"===n,a="hide"===n,r=e.size||15,h=/([0-9]+)%/.exec(r),l=!!e.horizFirst,c=l?["right","bottom"]:["bottom","right"],u=e.duration/2,d=t.effects.createPlaceholder(s),p=s.cssClip(),f={clip:t.extend({},p)},g={clip:t.extend({},p)},m=[p[c[0]],p[c[1]]],_=s.queue().length;h&&(r=parseInt(h[1],10)/100*m[a?0:1]),f.clip[c[0]]=r,g.clip[c[0]]=r,g.clip[c[1]]=0,o&&(s.cssClip(g.clip),d&&d.css(t.effects.clipToBox(g)),g.clip=p),s.queue(function(i){d&&d.animate(t.effects.clipToBox(f),u,e.easing).animate(t.effects.clipToBox(g),u,e.easing),i()}).animate(f,u,e.easing).animate(g,u,e.easing).queue(i),t.effects.unshift(s,_,4)}),t.effects.define("highlight","show",function(e,i){var s=t(this),n={backgroundColor:s.css("backgroundColor")};"hide"===e.mode&&(n.opacity=0),t.effects.saveStyle(s),s.css({backgroundImage:"none",backgroundColor:e.color||"#ffff99"}).animate(n,{queue:!1,duration:e.duration,easing:e.easing,complete:i})}),t.effects.define("size",function(e,i){var s,n,o,a=t(this),r=["fontSize"],h=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],l=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],c=e.mode,u="effect"!==c,d=e.scale||"both",p=e.origin||["middle","center"],f=a.css("position"),g=a.position(),m=t.effects.scaledDimensions(a),_=e.from||m,v=e.to||t.effects.scaledDimensions(a,0);t.effects.createPlaceholder(a),"show"===c&&(o=_,_=v,v=o),n={from:{y:_.height/m.height,x:_.width/m.width},to:{y:v.height/m.height,x:v.width/m.width}},("box"===d||"both"===d)&&(n.from.y!==n.to.y&&(_=t.effects.setTransition(a,h,n.from.y,_),v=t.effects.setTransition(a,h,n.to.y,v)),n.from.x!==n.to.x&&(_=t.effects.setTransition(a,l,n.from.x,_),v=t.effects.setTransition(a,l,n.to.x,v))),("content"===d||"both"===d)&&n.from.y!==n.to.y&&(_=t.effects.setTransition(a,r,n.from.y,_),v=t.effects.setTransition(a,r,n.to.y,v)),p&&(s=t.effects.getBaseline(p,m),_.top=(m.outerHeight-_.outerHeight)*s.y+g.top,_.left=(m.outerWidth-_.outerWidth)*s.x+g.left,v.top=(m.outerHeight-v.outerHeight)*s.y+g.top,v.left=(m.outerWidth-v.outerWidth)*s.x+g.left),a.css(_),("content"===d||"both"===d)&&(h=h.concat(["marginTop","marginBottom"]).concat(r),l=l.concat(["marginLeft","marginRight"]),a.find("*[width]").each(function(){var i=t(this),s=t.effects.scaledDimensions(i),o={height:s.height*n.from.y,width:s.width*n.from.x,outerHeight:s.outerHeight*n.from.y,outerWidth:s.outerWidth*n.from.x},a={height:s.height*n.to.y,width:s.width*n.to.x,outerHeight:s.height*n.to.y,outerWidth:s.width*n.to.x};n.from.y!==n.to.y&&(o=t.effects.setTransition(i,h,n.from.y,o),a=t.effects.setTransition(i,h,n.to.y,a)),n.from.x!==n.to.x&&(o=t.effects.setTransition(i,l,n.from.x,o),a=t.effects.setTransition(i,l,n.to.x,a)),u&&t.effects.saveStyle(i),i.css(o),i.animate(a,e.duration,e.easing,function(){u&&t.effects.restoreStyle(i)})})),a.animate(v,{queue:!1,duration:e.duration,easing:e.easing,complete:function(){var e=a.offset();0===v.opacity&&a.css("opacity",_.opacity),u||(a.css("position","static"===f?"relative":f).offset(e),t.effects.saveStyle(a)),i()}})}),t.effects.define("scale",function(e,i){var s=t(this),n=e.mode,o=parseInt(e.percent,10)||(0===parseInt(e.percent,10)?0:"effect"!==n?0:100),a=t.extend(!0,{from:t.effects.scaledDimensions(s),to:t.effects.scaledDimensions(s,o,e.direction||"both"),origin:e.origin||["middle","center"]},e);e.fade&&(a.from.opacity=1,a.to.opacity=0),t.effects.effect.size.call(this,a,i)}),t.effects.define("puff","hide",function(e,i){var s=t.extend(!0,{},e,{fade:!0,percent:parseInt(e.percent,10)||150});t.effects.effect.scale.call(this,s,i)}),t.effects.define("pulsate","show",function(e,i){var s=t(this),n=e.mode,o="show"===n,a="hide"===n,r=o||a,h=2*(e.times||5)+(r?1:0),l=e.duration/h,c=0,u=1,d=s.queue().length;for((o||!s.is(":visible"))&&(s.css("opacity",0).show(),c=1);h>u;u++)s.animate({opacity:c},l,e.easing),c=1-c;s.animate({opacity:c},l,e.easing),s.queue(i),t.effects.unshift(s,d,h+1)}),t.effects.define("shake",function(e,i){var s=1,n=t(this),o=e.direction||"left",a=e.distance||20,r=e.times||3,h=2*r+1,l=Math.round(e.duration/h),c="up"===o||"down"===o?"top":"left",u="up"===o||"left"===o,d={},p={},f={},g=n.queue().length;for(t.effects.createPlaceholder(n),d[c]=(u?"-=":"+=")+a,p[c]=(u?"+=":"-=")+2*a,f[c]=(u?"-=":"+=")+2*a,n.animate(d,l,e.easing);r>s;s++)n.animate(p,l,e.easing).animate(f,l,e.easing);n.animate(p,l,e.easing).animate(d,l/2,e.easing).queue(i),t.effects.unshift(n,g,h+1)}),t.effects.define("slide","show",function(e,i){var s,n,o=t(this),a={up:["bottom","top"],down:["top","bottom"],left:["right","left"],right:["left","right"]},r=e.mode,h=e.direction||"left",l="up"===h||"down"===h?"top":"left",c="up"===h||"left"===h,u=e.distance||o["top"===l?"outerHeight":"outerWidth"](!0),d={};t.effects.createPlaceholder(o),s=o.cssClip(),n=o.position()[l],d[l]=(c?-1:1)*u+n,d.clip=o.cssClip(),d.clip[a[h][1]]=d.clip[a[h][0]],"show"===r&&(o.cssClip(d.clip),o.css(l,d[l]),d.clip=s,d[l]=n),o.animate(d,{queue:!1,duration:e.duration,easing:e.easing,complete:i})});var f;t.uiBackCompat!==!1&&(f=t.effects.define("transfer",function(e,i){t(this).transfer(e,i)})),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.widget("ui.accordion",{version:"1.12.1",options:{active:0,animate:{},classes:{"ui-accordion-header":"ui-corner-top","ui-accordion-header-collapsed":"ui-corner-all","ui-accordion-content":"ui-corner-bottom"},collapsible:!1,event:"click",header:"> li > :first-child, > :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this._addClass("ui-accordion","ui-widget ui-helper-reset"),this.element.attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),0>e.active&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t()}},_createIcons:function(){var e,i,s=this.options.icons;s&&(e=t(""),this._addClass(e,"ui-accordion-header-icon","ui-icon "+s.header),e.prependTo(this.headers),i=this.active.children(".ui-accordion-header-icon"),this._removeClass(i,s.header)._addClass(i,null,s.activeHeader)._addClass(this.headers,"ui-accordion-icons"))},_destroyIcons:function(){this._removeClass(this.headers,"ui-accordion-icons"),this.headers.children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeAttr("role"),this.headers.removeAttr("role aria-expanded aria-selected aria-controls tabIndex").removeUniqueId(),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role aria-hidden aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),void 0)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t),this._toggleClass(this.headers.add(this.headers.next()),null,"ui-state-disabled",!!t)},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var i=t.ui.keyCode,s=this.headers.length,n=this.headers.index(e.target),o=!1;switch(e.keyCode){case i.RIGHT:case i.DOWN:o=this.headers[(n+1)%s];break;case i.LEFT:case i.UP:o=this.headers[(n-1+s)%s];break;case i.SPACE:case i.ENTER:this._eventHandler(e);break;case i.HOME:o=this.headers[0];break;case i.END:o=this.headers[s-1]}o&&(t(e.target).attr("tabIndex",-1),t(o).attr("tabIndex",0),t(o).trigger("focus"),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().trigger("focus")},refresh:function(){var e=this.options;this._processPanels(),e.active===!1&&e.collapsible===!0||!this.headers.length?(e.active=!1,this.active=t()):e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var t=this.headers,e=this.panels;this.headers=this.element.find(this.options.header),this._addClass(this.headers,"ui-accordion-header ui-accordion-header-collapsed","ui-state-default"),this.panels=this.headers.next().filter(":not(.ui-accordion-content-active)").hide(),this._addClass(this.panels,"ui-accordion-content","ui-helper-reset ui-widget-content"),e&&(this._off(t.not(this.headers)),this._off(e.not(this.panels)))},_refresh:function(){var e,i=this.options,s=i.heightStyle,n=this.element.parent();this.active=this._findActive(i.active),this._addClass(this.active,"ui-accordion-header-active","ui-state-active")._removeClass(this.active,"ui-accordion-header-collapsed"),this._addClass(this.active.next(),"ui-accordion-content-active"),this.active.next().show(),this.headers.attr("role","tab").each(function(){var e=t(this),i=e.uniqueId().attr("id"),s=e.next(),n=s.uniqueId().attr("id");e.attr("aria-controls",n),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(i.event),"fill"===s?(e=n.height(),this.element.siblings(":visible").each(function(){var i=t(this),s=i.css("position");"absolute"!==s&&"fixed"!==s&&(e-=i.outerHeight(!0))}),this.headers.each(function(){e-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,e-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===s&&(e=0,this.headers.next().each(function(){var i=t(this).is(":visible");i||t(this).show(),e=Math.max(e,t(this).css("height","").height()),i||t(this).hide()}).height(e))},_activate:function(e){var i=this._findActive(e)[0];i!==this.active[0]&&(i=i||this.active[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var i={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var i,s,n=this.options,o=this.active,a=t(e.currentTarget),r=a[0]===o[0],h=r&&n.collapsible,l=h?t():a.next(),c=o.next(),u={oldHeader:o,oldPanel:c,newHeader:h?t():a,newPanel:l};e.preventDefault(),r&&!n.collapsible||this._trigger("beforeActivate",e,u)===!1||(n.active=h?!1:this.headers.index(a),this.active=r?t():a,this._toggle(u),this._removeClass(o,"ui-accordion-header-active","ui-state-active"),n.icons&&(i=o.children(".ui-accordion-header-icon"),this._removeClass(i,null,n.icons.activeHeader)._addClass(i,null,n.icons.header)),r||(this._removeClass(a,"ui-accordion-header-collapsed")._addClass(a,"ui-accordion-header-active","ui-state-active"),n.icons&&(s=a.children(".ui-accordion-header-icon"),this._removeClass(s,null,n.icons.header)._addClass(s,null,n.icons.activeHeader)),this._addClass(a.next(),"ui-accordion-content-active")))},_toggle:function(e){var i=e.newPanel,s=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=i,this.prevHide=s,this.options.animate?this._animate(i,s,e):(s.hide(),i.show(),this._toggleComplete(e)),s.attr({"aria-hidden":"true"}),s.prev().attr({"aria-selected":"false","aria-expanded":"false"}),i.length&&s.length?s.prev().attr({tabIndex:-1,"aria-expanded":"false"}):i.length&&this.headers.filter(function(){return 0===parseInt(t(this).attr("tabIndex"),10)}).attr("tabIndex",-1),i.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(t,e,i){var s,n,o,a=this,r=0,h=t.css("box-sizing"),l=t.length&&(!e.length||t.index()",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault()},"click .ui-menu-item":function(e){var i=t(e.target),s=t(t.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&i.not(".ui-state-disabled").length&&(this.select(e),e.isPropagationStopped()||(this.mouseHandled=!0),i.has(".ui-menu").length?this.expand(e):!this.element.is(":focus")&&s.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){if(!this.previousFilter){var i=t(e.target).closest(".ui-menu-item"),s=t(e.currentTarget);i[0]===s[0]&&(this._removeClass(s.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(e,s))}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this.element.find(this.options.items).eq(0);e||this.focus(t,i)},blur:function(e){this._delay(function(){var i=!t.contains(this.element[0],t.ui.safeActiveElement(this.document[0]));i&&this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t),this.mouseHandled=!1}})},_destroy:function(){var e=this.element.find(".ui-menu-item").removeAttr("role aria-disabled"),i=e.children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),i.children().each(function(){var e=t(this);e.data("ui-menu-submenu-caret")&&e.remove()})},_keydown:function(e){var i,s,n,o,a=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:a=!1,s=this.previousFilter||"",o=!1,n=e.keyCode>=96&&105>=e.keyCode?""+(e.keyCode-96):String.fromCharCode(e.keyCode),clearTimeout(this.filterTimer),n===s?o=!0:n=s+n,i=this._filterMenuItems(n),i=o&&-1!==i.index(this.active.next())?this.active.nextAll(".ui-menu-item"):i,i.length||(n=String.fromCharCode(e.keyCode),i=this._filterMenuItems(n)),i.length?(this.focus(e,i),this.previousFilter=n,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}a&&e.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var e,i,s,n,o,a=this,r=this.options.icons.submenu,h=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),s=h.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),i=e.prev(),s=t("").data("ui-menu-submenu-caret",!0);a._addClass(s,"ui-menu-icon","ui-icon "+r),i.attr("aria-haspopup","true").prepend(s),e.attr("aria-labelledby",i.attr("id"))}),this._addClass(s,"ui-menu","ui-widget ui-widget-content ui-front"),e=h.add(this.element),i=e.find(this.options.items),i.not(".ui-menu-item").each(function(){var e=t(this);a._isDivider(e)&&a._addClass(e,"ui-menu-divider","ui-widget-content")}),n=i.not(".ui-menu-item, .ui-menu-divider"),o=n.children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(n,"ui-menu-item")._addClass(o,"ui-menu-item-wrapper"),i.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){if("icons"===t){var i=this.element.find(".ui-menu-icon");this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)}this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t+""),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i,s,n;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),s=this.active.children(".ui-menu-item-wrapper"),this._addClass(s,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",s.attr("id")),n=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(n,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),i=e.children(".ui-menu"),i.length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var i,s,n,o,a,r;this._hasScroll()&&(i=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,n=e.offset().top-this.activeMenu.offset().top-i-s,o=this.activeMenu.scrollTop(),a=this.activeMenu.height(),r=e.outerHeight(),0>n?this.activeMenu.scrollTop(o+n):n+r>a&&this.activeMenu.scrollTop(o+n-a+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this._removeClass(this.active.children(".ui-menu-item-wrapper"),null,"ui-state-active"),this._trigger("blur",t,{item:this.active}),this.active=null)},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var i=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(i)},collapseAll:function(e,i){clearTimeout(this.timer),this.timer=this._delay(function(){var s=i?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));s.length||(s=this.element),this._close(s),this.blur(e),this._removeClass(s.find(".ui-state-active"),null,"ui-state-active"),this.activeMenu=s},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false")},_closeOnDocumentClick:function(e){return!t(e.target).closest(".ui-menu").length},_isDivider:function(t){return!/[^\-\u2014\u2013\s]/.test(t.text())},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,i){var s;this.active&&(s="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),s&&s.length&&this.active||(s=this.activeMenu.find(this.options.items)[e]()),this.focus(i,s)},nextPage:function(e){var i,s,n;return this.active?(this.isLastItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return i=t(this),0>i.offset().top-s-n}),this.focus(e,i)):this.focus(e,this.activeMenu.find(this.options.items)[this.active?"last":"first"]())),void 0):(this.next(e),void 0)},previousPage:function(e){var i,s,n;return this.active?(this.isFirstItem()||(this._hasScroll()?(s=this.active.offset().top,n=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return i=t(this),i.offset().top-s+n>0}),this.focus(e,i)):this.focus(e,this.activeMenu.find(this.options.items).first())),void 0):(this.next(e),void 0)},_hasScroll:function(){return this.element.outerHeight()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var e,i,s,n=this.element[0].nodeName.toLowerCase(),o="textarea"===n,a="input"===n; -this.isMultiLine=o||!a&&this._isContentEditable(this.element),this.valueMethod=this.element[o||a?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(n){if(this.element.prop("readOnly"))return e=!0,s=!0,i=!0,void 0;e=!1,s=!1,i=!1;var o=t.ui.keyCode;switch(n.keyCode){case o.PAGE_UP:e=!0,this._move("previousPage",n);break;case o.PAGE_DOWN:e=!0,this._move("nextPage",n);break;case o.UP:e=!0,this._keyEvent("previous",n);break;case o.DOWN:e=!0,this._keyEvent("next",n);break;case o.ENTER:this.menu.active&&(e=!0,n.preventDefault(),this.menu.select(n));break;case o.TAB:this.menu.active&&this.menu.select(n);break;case o.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(n),n.preventDefault());break;default:i=!0,this._searchTimeout(n)}},keypress:function(s){if(e)return e=!1,(!this.isMultiLine||this.menu.element.is(":visible"))&&s.preventDefault(),void 0;if(!i){var n=t.ui.keyCode;switch(s.keyCode){case n.PAGE_UP:this._move("previousPage",s);break;case n.PAGE_DOWN:this._move("nextPage",s);break;case n.UP:this._keyEvent("previous",s);break;case n.DOWN:this._keyEvent("next",s)}}},input:function(t){return s?(s=!1,t.preventDefault(),void 0):(this._searchTimeout(t),void 0)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(clearTimeout(this.searching),this.close(t),this._change(t),void 0)}}),this._initSource(),this.menu=t("
    ").appendTo(this._appendTo()).menu({role:null}).hide().menu("instance"),this._addClass(this.menu.element,"ui-autocomplete","ui-front"),this._on(this.menu.element,{mousedown:function(e){e.preventDefault(),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,this.element[0]!==t.ui.safeActiveElement(this.document[0])&&this.element.trigger("focus")})},menufocus:function(e,i){var s,n;return this.isNewMenu&&(this.isNewMenu=!1,e.originalEvent&&/^mouse/.test(e.originalEvent.type))?(this.menu.blur(),this.document.one("mousemove",function(){t(e.target).trigger(e.originalEvent)}),void 0):(n=i.item.data("ui-autocomplete-item"),!1!==this._trigger("focus",e,{item:n})&&e.originalEvent&&/^key/.test(e.originalEvent.type)&&this._value(n.value),s=i.item.attr("aria-label")||n.value,s&&t.trim(s).length&&(this.liveRegion.children().hide(),t("
    ").text(s).appendTo(this.liveRegion)),void 0)},menuselect:function(e,i){var s=i.item.data("ui-autocomplete-item"),n=this.previous;this.element[0]!==t.ui.safeActiveElement(this.document[0])&&(this.element.trigger("focus"),this.previous=n,this._delay(function(){this.previous=n,this.selectedItem=s})),!1!==this._trigger("select",e,{item:s})&&this._value(s.value),this.term=this._value(),this.close(e),this.selectedItem=s}}),this.liveRegion=t("
    ",{role:"status","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_destroy:function(){clearTimeout(this.searching),this.element.removeAttr("autocomplete"),this.menu.element.remove(),this.liveRegion.remove()},_setOption:function(t,e){this._super(t,e),"source"===t&&this._initSource(),"appendTo"===t&&this.menu.element.appendTo(this._appendTo()),"disabled"===t&&e&&this.xhr&&this.xhr.abort()},_isEventTargetInWidget:function(e){var i=this.menu.element[0];return e.target===this.element[0]||e.target===i||t.contains(i,e.target)},_closeOnClickOutside:function(t){this._isEventTargetInWidget(t)||this.close()},_appendTo:function(){var e=this.options.appendTo;return e&&(e=e.jquery||e.nodeType?t(e):this.document.find(e).eq(0)),e&&e[0]||(e=this.element.closest(".ui-front, dialog")),e.length||(e=this.document[0].body),e},_initSource:function(){var e,i,s=this;t.isArray(this.options.source)?(e=this.options.source,this.source=function(i,s){s(t.ui.autocomplete.filter(e,i.term))}):"string"==typeof this.options.source?(i=this.options.source,this.source=function(e,n){s.xhr&&s.xhr.abort(),s.xhr=t.ajax({url:i,data:e,dataType:"json",success:function(t){n(t)},error:function(){n([])}})}):this.source=this.options.source},_searchTimeout:function(t){clearTimeout(this.searching),this.searching=this._delay(function(){var e=this.term===this._value(),i=this.menu.element.is(":visible"),s=t.altKey||t.ctrlKey||t.metaKey||t.shiftKey;(!e||e&&!i&&!s)&&(this.selectedItem=null,this.search(null,t))},this.options.delay)},search:function(t,e){return t=null!=t?t:this._value(),this.term=this._value(),t.length").append(t("
    ").text(i.label)).appendTo(e)},_move:function(t,e){return this.menu.element.is(":visible")?this.menu.isFirstItem()&&/^previous/.test(t)||this.menu.isLastItem()&&/^next/.test(t)?(this.isMultiLine||this._value(this.term),this.menu.blur(),void 0):(this.menu[t](e),void 0):(this.search(null,e),void 0)},widget:function(){return this.menu.element},_value:function(){return this.valueMethod.apply(this.element,arguments)},_keyEvent:function(t,e){(!this.isMultiLine||this.menu.element.is(":visible"))&&(this._move(t,e),e.preventDefault())},_isContentEditable:function(t){if(!t.length)return!1;var e=t.prop("contentEditable");return"inherit"===e?this._isContentEditable(t.parent()):"true"===e}}),t.extend(t.ui.autocomplete,{escapeRegex:function(t){return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")},filter:function(e,i){var s=RegExp(t.ui.autocomplete.escapeRegex(i),"i");return t.grep(e,function(t){return s.test(t.label||t.value||t)})}}),t.widget("ui.autocomplete",t.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(t){return t+(t>1?" results are":" result is")+" available, use up and down arrow keys to navigate."}}},__response:function(e){var i;this._superApply(arguments),this.options.disabled||this.cancelSearch||(i=e&&e.length?this.options.messages.results(e.length):this.options.messages.noResults,this.liveRegion.children().hide(),t("
    ").text(i).appendTo(this.liveRegion))}}),t.ui.autocomplete;var g=/ui-corner-([a-z]){2,6}/g;t.widget("ui.controlgroup",{version:"1.12.1",defaultElement:"
    ",options:{direction:"horizontal",disabled:null,onlyVisible:!0,items:{button:"input[type=button], input[type=submit], input[type=reset], button, a",controlgroupLabel:".ui-controlgroup-label",checkboxradio:"input[type='checkbox'], input[type='radio']",selectmenu:"select",spinner:".ui-spinner-input"}},_create:function(){this._enhance()},_enhance:function(){this.element.attr("role","toolbar"),this.refresh()},_destroy:function(){this._callChildMethod("destroy"),this.childWidgets.removeData("ui-controlgroup-data"),this.element.removeAttr("role"),this.options.items.controlgroupLabel&&this.element.find(this.options.items.controlgroupLabel).find(".ui-controlgroup-label-contents").contents().unwrap()},_initWidgets:function(){var e=this,i=[];t.each(this.options.items,function(s,n){var o,a={};return n?"controlgroupLabel"===s?(o=e.element.find(n),o.each(function(){var e=t(this);e.children(".ui-controlgroup-label-contents").length||e.contents().wrapAll("")}),e._addClass(o,null,"ui-widget ui-widget-content ui-state-default"),i=i.concat(o.get()),void 0):(t.fn[s]&&(a=e["_"+s+"Options"]?e["_"+s+"Options"]("middle"):{classes:{}},e.element.find(n).each(function(){var n=t(this),o=n[s]("instance"),r=t.widget.extend({},a);if("button"!==s||!n.parent(".ui-spinner").length){o||(o=n[s]()[s]("instance")),o&&(r.classes=e._resolveClassesValues(r.classes,o)),n[s](r);var h=n[s]("widget");t.data(h[0],"ui-controlgroup-data",o?o:n[s]("instance")),i.push(h[0])}})),void 0):void 0}),this.childWidgets=t(t.unique(i)),this._addClass(this.childWidgets,"ui-controlgroup-item")},_callChildMethod:function(e){this.childWidgets.each(function(){var i=t(this),s=i.data("ui-controlgroup-data");s&&s[e]&&s[e]()})},_updateCornerClass:function(t,e){var i="ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all",s=this._buildSimpleOptions(e,"label").classes.label;this._removeClass(t,null,i),this._addClass(t,null,s)},_buildSimpleOptions:function(t,e){var i="vertical"===this.options.direction,s={classes:{}};return s.classes[e]={middle:"",first:"ui-corner-"+(i?"top":"left"),last:"ui-corner-"+(i?"bottom":"right"),only:"ui-corner-all"}[t],s},_spinnerOptions:function(t){var e=this._buildSimpleOptions(t,"ui-spinner");return e.classes["ui-spinner-up"]="",e.classes["ui-spinner-down"]="",e},_buttonOptions:function(t){return this._buildSimpleOptions(t,"ui-button")},_checkboxradioOptions:function(t){return this._buildSimpleOptions(t,"ui-checkboxradio-label")},_selectmenuOptions:function(t){var e="vertical"===this.options.direction;return{width:e?"auto":!1,classes:{middle:{"ui-selectmenu-button-open":"","ui-selectmenu-button-closed":""},first:{"ui-selectmenu-button-open":"ui-corner-"+(e?"top":"tl"),"ui-selectmenu-button-closed":"ui-corner-"+(e?"top":"left")},last:{"ui-selectmenu-button-open":e?"":"ui-corner-tr","ui-selectmenu-button-closed":"ui-corner-"+(e?"bottom":"right")},only:{"ui-selectmenu-button-open":"ui-corner-top","ui-selectmenu-button-closed":"ui-corner-all"}}[t]}},_resolveClassesValues:function(e,i){var s={};return t.each(e,function(n){var o=i.options.classes[n]||"";o=t.trim(o.replace(g,"")),s[n]=(o+" "+e[n]).replace(/\s+/g," ")}),s},_setOption:function(t,e){return"direction"===t&&this._removeClass("ui-controlgroup-"+this.options.direction),this._super(t,e),"disabled"===t?(this._callChildMethod(e?"disable":"enable"),void 0):(this.refresh(),void 0)},refresh:function(){var e,i=this;this._addClass("ui-controlgroup ui-controlgroup-"+this.options.direction),"horizontal"===this.options.direction&&this._addClass(null,"ui-helper-clearfix"),this._initWidgets(),e=this.childWidgets,this.options.onlyVisible&&(e=e.filter(":visible")),e.length&&(t.each(["first","last"],function(t,s){var n=e[s]().data("ui-controlgroup-data");if(n&&i["_"+n.widgetName+"Options"]){var o=i["_"+n.widgetName+"Options"](1===e.length?"only":s);o.classes=i._resolveClassesValues(o.classes,n),n.element[n.widgetName](o)}else i._updateCornerClass(e[s](),s)}),this._callChildMethod("refresh"))}}),t.widget("ui.checkboxradio",[t.ui.formResetMixin,{version:"1.12.1",options:{disabled:null,label:null,icon:!0,classes:{"ui-checkboxradio-label":"ui-corner-all","ui-checkboxradio-icon":"ui-corner-all"}},_getCreateOptions:function(){var e,i,s=this,n=this._super()||{};return this._readType(),i=this.element.labels(),this.label=t(i[i.length-1]),this.label.length||t.error("No label found for checkboxradio widget"),this.originalLabel="",this.label.contents().not(this.element[0]).each(function(){s.originalLabel+=3===this.nodeType?t(this).text():this.outerHTML}),this.originalLabel&&(n.label=this.originalLabel),e=this.element[0].disabled,null!=e&&(n.disabled=e),n},_create:function(){var t=this.element[0].checked;this._bindFormResetHandler(),null==this.options.disabled&&(this.options.disabled=this.element[0].disabled),this._setOption("disabled",this.options.disabled),this._addClass("ui-checkboxradio","ui-helper-hidden-accessible"),this._addClass(this.label,"ui-checkboxradio-label","ui-button ui-widget"),"radio"===this.type&&this._addClass(this.label,"ui-checkboxradio-radio-label"),this.options.label&&this.options.label!==this.originalLabel?this._updateLabel():this.originalLabel&&(this.options.label=this.originalLabel),this._enhance(),t&&(this._addClass(this.label,"ui-checkboxradio-checked","ui-state-active"),this.icon&&this._addClass(this.icon,null,"ui-state-hover")),this._on({change:"_toggleClasses",focus:function(){this._addClass(this.label,null,"ui-state-focus ui-visual-focus")},blur:function(){this._removeClass(this.label,null,"ui-state-focus ui-visual-focus")}})},_readType:function(){var e=this.element[0].nodeName.toLowerCase();this.type=this.element[0].type,"input"===e&&/radio|checkbox/.test(this.type)||t.error("Can't create checkboxradio on element.nodeName="+e+" and element.type="+this.type)},_enhance:function(){this._updateIcon(this.element[0].checked)},widget:function(){return this.label},_getRadioGroup:function(){var e,i=this.element[0].name,s="input[name='"+t.ui.escapeSelector(i)+"']";return i?(e=this.form.length?t(this.form[0].elements).filter(s):t(s).filter(function(){return 0===t(this).form().length}),e.not(this.element)):t([])},_toggleClasses:function(){var e=this.element[0].checked;this._toggleClass(this.label,"ui-checkboxradio-checked","ui-state-active",e),this.options.icon&&"checkbox"===this.type&&this._toggleClass(this.icon,null,"ui-icon-check ui-state-checked",e)._toggleClass(this.icon,null,"ui-icon-blank",!e),"radio"===this.type&&this._getRadioGroup().each(function(){var e=t(this).checkboxradio("instance");e&&e._removeClass(e.label,"ui-checkboxradio-checked","ui-state-active")})},_destroy:function(){this._unbindFormResetHandler(),this.icon&&(this.icon.remove(),this.iconSpace.remove())},_setOption:function(t,e){return"label"!==t||e?(this._super(t,e),"disabled"===t?(this._toggleClass(this.label,null,"ui-state-disabled",e),this.element[0].disabled=e,void 0):(this.refresh(),void 0)):void 0},_updateIcon:function(e){var i="ui-icon ui-icon-background ";this.options.icon?(this.icon||(this.icon=t(""),this.iconSpace=t(" "),this._addClass(this.iconSpace,"ui-checkboxradio-icon-space")),"checkbox"===this.type?(i+=e?"ui-icon-check ui-state-checked":"ui-icon-blank",this._removeClass(this.icon,null,e?"ui-icon-blank":"ui-icon-check")):i+="ui-icon-blank",this._addClass(this.icon,"ui-checkboxradio-icon",i),e||this._removeClass(this.icon,null,"ui-icon-check ui-state-checked"),this.icon.prependTo(this.label).after(this.iconSpace)):void 0!==this.icon&&(this.icon.remove(),this.iconSpace.remove(),delete this.icon)},_updateLabel:function(){var t=this.label.contents().not(this.element[0]);this.icon&&(t=t.not(this.icon[0])),this.iconSpace&&(t=t.not(this.iconSpace[0])),t.remove(),this.label.append(this.options.label)},refresh:function(){var t=this.element[0].checked,e=this.element[0].disabled;this._updateIcon(t),this._toggleClass(this.label,"ui-checkboxradio-checked","ui-state-active",t),null!==this.options.label&&this._updateLabel(),e!==this.options.disabled&&this._setOptions({disabled:e})}}]),t.ui.checkboxradio,t.widget("ui.button",{version:"1.12.1",defaultElement:"").addClass(this._triggerClass).html(o?t("").attr({src:o,alt:n,title:n}):n)),e[r?"before":"after"](i.trigger),i.trigger.on("click",function(){return t.datepicker._datepickerShowing&&t.datepicker._lastInput===e[0]?t.datepicker._hideDatepicker():t.datepicker._datepickerShowing&&t.datepicker._lastInput!==e[0]?(t.datepicker._hideDatepicker(),t.datepicker._showDatepicker(e[0])):t.datepicker._showDatepicker(e[0]),!1}))},_autoSize:function(t){if(this._get(t,"autoSize")&&!t.inline){var e,i,s,n,o=new Date(2009,11,20),a=this._get(t,"dateFormat");a.match(/[DM]/)&&(e=function(t){for(i=0,s=0,n=0;t.length>n;n++)t[n].length>i&&(i=t[n].length,s=n);return s},o.setMonth(e(this._get(t,a.match(/MM/)?"monthNames":"monthNamesShort"))),o.setDate(e(this._get(t,a.match(/DD/)?"dayNames":"dayNamesShort"))+20-o.getDay())),t.input.attr("size",this._formatDate(t,o).length)}},_inlineDatepicker:function(e,i){var s=t(e);s.hasClass(this.markerClassName)||(s.addClass(this.markerClassName).append(i.dpDiv),t.data(e,"datepicker",i),this._setDate(i,this._getDefaultDate(i),!0),this._updateDatepicker(i),this._updateAlternate(i),i.settings.disabled&&this._disableDatepicker(e),i.dpDiv.css("display","block"))},_dialogDatepicker:function(e,i,s,n,o){var r,h,l,c,u,d=this._dialogInst;return d||(this.uuid+=1,r="dp"+this.uuid,this._dialogInput=t(""),this._dialogInput.on("keydown",this._doKeyDown),t("body").append(this._dialogInput),d=this._dialogInst=this._newInst(this._dialogInput,!1),d.settings={},t.data(this._dialogInput[0],"datepicker",d)),a(d.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(d,i):i,this._dialogInput.val(i),this._pos=o?o.length?o:[o.pageX,o.pageY]:null,this._pos||(h=document.documentElement.clientWidth,l=document.documentElement.clientHeight,c=document.documentElement.scrollLeft||document.body.scrollLeft,u=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[h/2-100+c,l/2-150+u]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),d.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],"datepicker",d),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,"datepicker");s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).off("focus",this._showDatepicker).off("keydown",this._doKeyDown).off("keypress",this._doKeyPress).off("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty(),m===n&&(m=null))},_enableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,"datepicker");n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,o.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,"datepicker");n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,o.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,"datepicker")}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(e,i,s){var n,o,r,h,l=this._getInst(e);return 2===arguments.length&&"string"==typeof i?"defaults"===i?t.extend({},t.datepicker._defaults):l?"all"===i?t.extend({},l.settings):this._get(l,i):null:(n=i||{},"string"==typeof i&&(n={},n[i]=s),l&&(this._curInst===l&&this._hideDatepicker(),o=this._getDateDatepicker(e,!0),r=this._getMinMaxDate(l,"min"),h=this._getMinMaxDate(l,"max"),a(l.settings,n),null!==r&&void 0!==n.dateFormat&&void 0===n.minDate&&(l.settings.minDate=this._formatDate(l,r)),null!==h&&void 0!==n.dateFormat&&void 0===n.maxDate&&(l.settings.maxDate=this._formatDate(l,h)),"disabled"in n&&(n.disabled?this._disableDatepicker(e):this._enableDatepicker(e)),this._attachments(t(e),l),this._autoSize(l),this._setDate(l,o),this._updateAlternate(l),this._updateDatepicker(l)),void 0)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,o=t.datepicker._getInst(e.target),a=!0,r=o.dpDiv.is(".ui-datepicker-rtl");if(o._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),a=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",o.dpDiv),n[0]&&t.datepicker._selectDay(e.target,o.selectedMonth,o.selectedYear,n[0]),i=t.datepicker._get(o,"onSelect"),i?(s=t.datepicker._formatDate(o),i.apply(o.input?o.input[0]:null,[s,o])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),a=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),a=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?1:-1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),a=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?-1:1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),a=e.ctrlKey||e.metaKey;break;default:a=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):a=!1;a&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(e){var i,s,n=t.datepicker._getInst(e.target);return t.datepicker._get(n,"constrainInput")?(i=t.datepicker._possibleChars(t.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),e.ctrlKey||e.metaKey||" ">s||!i||i.indexOf(s)>-1):void 0},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var s,n,o,r,h,l,c;s=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==s&&(t.datepicker._curInst.dpDiv.stop(!0,!0),s&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),n=t.datepicker._get(s,"beforeShow"),o=n?n.apply(e,[e,s]):{},o!==!1&&(a(s.settings,o),s.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(s),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),r=!1,t(e).parents().each(function(){return r|="fixed"===t(this).css("position"),!r}),h={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,s.dpDiv.empty(),s.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(s),h=t.datepicker._checkOffset(s,h,r),s.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":r?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"}),s.inline||(l=t.datepicker._get(s,"showAnim"),c=t.datepicker._get(s,"duration"),s.dpDiv.css("z-index",i(t(e))+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[l]?s.dpDiv.show(l,t.datepicker._get(s,"showOptions"),c):s.dpDiv[l||"show"](l?c:null),t.datepicker._shouldFocusInput(s)&&s.input.trigger("focus"),t.datepicker._curInst=s)) -}},_updateDatepicker:function(e){this.maxRows=4,m=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e);var i,s=this._getNumberOfMonths(e),n=s[1],a=17,r=e.dpDiv.find("."+this._dayOverClass+" a");r.length>0&&o.apply(r.get(0)),e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&t.datepicker._shouldFocusInput(e)&&e.input.trigger("focus"),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_shouldFocusInput:function(t){return t.input&&t.input.is(":visible")&&!t.input.is(":disabled")&&!t.input.is(":focus")},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),o=e.dpDiv.outerHeight(),a=e.input?e.input.outerWidth():0,r=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-a:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+r?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+o>l&&l>o?Math.abs(o+r):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,o,a=this._curInst;!a||e&&a!==t.data(e,"datepicker")||this._datepickerShowing&&(i=this._get(a,"showAnim"),s=this._get(a,"duration"),n=function(){t.datepicker._tidyDialog(a)},t.effects&&(t.effects.effect[i]||t.effects[i])?a.dpDiv.hide(i,t.datepicker._get(a,"showOptions"),s,n):a.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,o=this._get(a,"onClose"),o&&o.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).off(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),o=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(o,i+("M"===s?this._get(o,"showCurrentAtPos"):0),s),this._updateDatepicker(o))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),o=this._getInst(n[0]);o["selected"+("M"===s?"Month":"Year")]=o["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(o),this._adjustDate(n)},_selectDay:function(e,i,s,n){var o,a=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(a[0])||(o=this._getInst(a[0]),o.selectedDay=o.currentDay=t("a",n).html(),o.selectedMonth=o.currentMonth=i,o.selectedYear=o.currentYear=s,this._selectDate(e,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),o=this._getInst(n[0]);i=null!=i?i:this._formatDate(o),o.input&&o.input.val(i),this._updateAlternate(o),s=this._get(o,"onSelect"),s?s.apply(o.input?o.input[0]:null,[i,o]):o.input&&o.input.trigger("change"),o.inline?this._updateDatepicker(o):(this._hideDatepicker(),this._lastInput=o.input[0],"object"!=typeof o.input[0]&&o.input.trigger("focus"),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,o=this._get(e,"altField");o&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(o).val(n))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(e,i,s){if(null==e||null==i)throw"Invalid arguments";if(i="object"==typeof i?""+i:i+"",""===i)return null;var n,o,a,r,h=0,l=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,c="string"!=typeof l?l:(new Date).getFullYear()%100+parseInt(l,10),u=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,d=(s?s.dayNames:null)||this._defaults.dayNames,p=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,f=(s?s.monthNames:null)||this._defaults.monthNames,g=-1,m=-1,_=-1,v=-1,b=!1,y=function(t){var i=e.length>n+1&&e.charAt(n+1)===t;return i&&n++,i},w=function(t){var e=y(t),s="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n="y"===t?s:1,o=RegExp("^\\d{"+n+","+s+"}"),a=i.substring(h).match(o);if(!a)throw"Missing number at position "+h;return h+=a[0].length,parseInt(a[0],10)},k=function(e,s,n){var o=-1,a=t.map(y(e)?n:s,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(a,function(t,e){var s=e[1];return i.substr(h,s.length).toLowerCase()===s.toLowerCase()?(o=e[0],h+=s.length,!1):void 0}),-1!==o)return o+1;throw"Unknown name at position "+h},x=function(){if(i.charAt(h)!==e.charAt(n))throw"Unexpected literal at position "+h;h++};for(n=0;e.length>n;n++)if(b)"'"!==e.charAt(n)||y("'")?x():b=!1;else switch(e.charAt(n)){case"d":_=w("d");break;case"D":k("D",u,d);break;case"o":v=w("o");break;case"m":m=w("m");break;case"M":m=k("M",p,f);break;case"y":g=w("y");break;case"@":r=new Date(w("@")),g=r.getFullYear(),m=r.getMonth()+1,_=r.getDate();break;case"!":r=new Date((w("!")-this._ticksTo1970)/1e4),g=r.getFullYear(),m=r.getMonth()+1,_=r.getDate();break;case"'":y("'")?x():b=!0;break;default:x()}if(i.length>h&&(a=i.substr(h),!/^\s+/.test(a)))throw"Extra/unparsed characters found in date: "+a;if(-1===g?g=(new Date).getFullYear():100>g&&(g+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c>=g?0:-100)),v>-1)for(m=1,_=v;;){if(o=this._getDaysInMonth(g,m-1),o>=_)break;m++,_-=o}if(r=this._daylightSavingAdjust(new Date(g,m-1,_)),r.getFullYear()!==g||r.getMonth()+1!==m||r.getDate()!==_)throw"Invalid date";return r},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,o=(i?i.dayNames:null)||this._defaults.dayNames,a=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,o);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),a,r);break;case"y":u+=h("y")?e.getFullYear():(10>e.getFullYear()%100?"0":"")+e.getFullYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,e){return void 0!==t.settings[e]?t.settings[e]:this._defaults[e]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),o=n,a=this._getFormatConfig(t);try{o=this.parseDate(i,s,a)||n}catch(r){s=e?"":s}t.selectedDay=o.getDate(),t.drawMonth=t.selectedMonth=o.getMonth(),t.drawYear=t.selectedYear=o.getFullYear(),t.currentDay=s?o.getDate():0,t.currentMonth=s?o.getMonth():0,t.currentYear=s?o.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},o=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,o=n.getFullYear(),a=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":a+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a));break;case"y":case"Y":o+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a))}l=h.exec(i)}return new Date(o,a,r)},a=null==i||""===i?s:"string"==typeof i?o(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return a=a&&"Invalid Date"==""+a?s:a,a&&(a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)),this._daylightSavingAdjust(a)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,o=t.selectedYear,a=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=a.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=a.getMonth(),t.drawYear=t.selectedYear=t.currentYear=a.getFullYear(),n===t.selectedMonth&&o===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){t.datepicker._adjustDate(s,-i,"M")},next:function(){t.datepicker._adjustDate(s,+i,"M")},hide:function(){t.datepicker._hideDatepicker()},today:function(){t.datepicker._gotoToday(s)},selectDay:function(){return t.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return t.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return t.datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).on(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,o,a,r,h,l,c,u,d,p,f,g,m,_,v,b,y,w,k,x,C,D,I,T,P,M,S,H,z,O,A,N,W,E,F,L,R=new Date,B=this._daylightSavingAdjust(new Date(R.getFullYear(),R.getMonth(),R.getDate())),Y=this._get(t,"isRTL"),j=this._get(t,"showButtonPanel"),q=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),U=this._getNumberOfMonths(t),V=this._get(t,"showCurrentAtPos"),$=this._get(t,"stepMonths"),X=1!==U[0]||1!==U[1],G=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),Q=this._getMinMaxDate(t,"min"),J=this._getMinMaxDate(t,"max"),Z=t.drawMonth-V,te=t.drawYear;if(0>Z&&(Z+=12,te--),J)for(e=this._daylightSavingAdjust(new Date(J.getFullYear(),J.getMonth()-U[0]*U[1]+1,J.getDate())),e=Q&&Q>e?Q:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-$,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?""+i+"":q?"":""+i+"",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+$,1)),this._getFormatConfig(t)):n,o=this._canAdjustMonth(t,1,te,Z)?""+n+"":q?"":""+n+"",a=this._get(t,"currentText"),r=this._get(t,"gotoCurrent")&&t.currentDay?G:B,a=K?this.formatDate(a,r,this._getFormatConfig(t)):a,h=t.inline?"":"",l=j?"
    "+(Y?h:"")+(this._isInRange(t,r)?"":"")+(Y?"":h)+"
    ":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),g=this._get(t,"monthNamesShort"),m=this._get(t,"beforeShowDay"),_=this._get(t,"showOtherMonths"),v=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;U[0]>k;k++){for(x="",this.maxRows=4,C=0;U[1]>C;C++){if(D=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),I=" ui-corner-all",T="",X){if(T+="
    "}for(T+="
    "+(/all|left/.test(I)&&0===k?Y?o:s:"")+(/all|right/.test(I)&&0===k?Y?s:o:"")+this._generateMonthYearHeader(t,Z,te,Q,J,k>0||C>0,f,g)+"
    "+"",P=u?"":"",w=0;7>w;w++)M=(w+c)%7,P+="";for(T+=P+"",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),H=(this._getFirstDayOfMonth(te,Z)-c+7)%7,z=Math.ceil((H+S)/7),O=X?this.maxRows>z?this.maxRows:z:z,this.maxRows=O,A=this._daylightSavingAdjust(new Date(te,Z,1-H)),N=0;O>N;N++){for(T+="",W=u?"":"",w=0;7>w;w++)E=m?m.apply(t.input?t.input[0]:null,[A]):[!0,""],F=A.getMonth()!==Z,L=F&&!v||!E[0]||Q&&Q>A||J&&A>J,W+="",A.setDate(A.getDate()+1),A=this._daylightSavingAdjust(A);T+=W+""}Z++,Z>11&&(Z=0,te++),T+="
    "+this._get(t,"weekHeader")+"=5?" class='ui-datepicker-week-end'":"")+">"+""+p[M]+"
    "+this._get(t,"calculateWeek")(A)+""+(F&&!_?" ":L?""+A.getDate()+"":""+A.getDate()+"")+"
    "+(X?"
    "+(U[0]>0&&C===U[1]-1?"
    ":""):""),x+=T}y+=x}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),_=this._get(t,"changeYear"),v=this._get(t,"showMonthAfterYear"),b="
    ",y="";if(o||!m)y+=""+a[e]+"";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+=""}if(v||(b+=y+(!o&&m&&_?"":" ")),!t.yearshtml)if(t.yearshtml="",o||!_)b+=""+i+"";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),v&&(b+=(!o&&m&&_?"":" ")+y),b+="
    "},_adjustInstDate:function(t,e,i){var s=t.selectedYear+("Y"===i?e:0),n=t.selectedMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).on("mousedown",t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new s,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.12.1",t.datepicker,t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var _=!1;t(document).on("mouseup",function(){_=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!_){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,n="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),_=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,_=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.ui.safeBlur=function(e){e&&"body"!==e.nodeName.toLowerCase()&&t(e).trigger("blur")},t.widget("ui.draggable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this._addClass("ui-draggable"),this._setHandleClassName(),this._mouseInit()},_setOption:function(t,e){this._super(t,e),"handle"===t&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(this._blurActiveElement(e),this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(e){this.iframeBlocks=this.document.find(e).map(function(){var e=t(this);return t("
    ").css("position","absolute").appendTo(e.parent()).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(e){var i=t.ui.safeActiveElement(this.document[0]),s=t(e.target);s.closest(i).length||t.ui.safeBlur(i)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this._addClass(this.helper,"ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===t(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(e),this.originalPosition=this.position=this._generatePosition(e,!1),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_refreshOffsets:function(t){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:t.pageX-this.offset.left,top:t.pageY-this.offset.top}},_mouseDrag:function(e,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp(new t.Event("mouseup",e)),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1},_mouseUp:function(e){return this._unblockFrames(),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),this.handleElement.is(e.target)&&this.element.trigger("focus"),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp(new t.Event("mouseup",{target:this.element[0]})):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this._addClass(this.handleElement,"ui-draggable-handle")},_removeHandleClassName:function(){this._removeClass(this.handleElement,"ui-draggable-handle")},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper),n=s?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_isRootNode:function(t){return/(html|body)/i.test(t.tagName)||t===this.document[0]},_getParentOffset:function(){var e=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var t=this.element.position(),e=this._isRootNode(this.scrollParent[0]);return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+(e?0:this.scrollParent.scrollTop()),left:t.left-(parseInt(this.helper.css("left"),10)||0)+(e?0:this.scrollParent.scrollLeft())} -},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options,o=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,t(o).width()-this.helperProportions.width-this.margins.left,(t(o).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(t,e){e||(e=this.position);var i="absolute"===t?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:e.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:e.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(t,e){var i,s,n,o,a=this.options,r=this._isRootNode(this.scrollParent[0]),h=t.pageX,l=t.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),e&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,h=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o),"y"===a.axis&&(h=this.originalPageX),"x"===a.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this._removeClass(this.helper,"ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s,this],!0),/^(drag|start|stop)/.test(e)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i,s){var n=t.extend({},i,{item:s.element});s.sortables=[],t(s.options.connectToSortable).each(function(){var i=t(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",e,n))})},stop:function(e,i,s){var n=t.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,t.each(s.sortables,function(){var t=this;t.isOver?(t.isOver=0,s.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,n))})},drag:function(e,i,s){t.each(s.sortables,function(){var n=!1,o=this;o.positionAbs=s.positionAbs,o.helperProportions=s.helperProportions,o.offset.click=s.offset.click,o._intersectsWith(o.containerCache)&&(n=!0,t.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==o&&this._intersectsWith(this.containerCache)&&t.contains(o.element[0],this.element[0])&&(n=!1),n})),n?(o.isOver||(o.isOver=1,s._parent=i.helper.parent(),o.currentItem=i.helper.appendTo(o.element).data("ui-sortable-item",!0),o.options._helper=o.options.helper,o.options.helper=function(){return i.helper[0]},e.target=o.currentItem[0],o._mouseCapture(e,!0),o._mouseStart(e,!0,!0),o.offset.click.top=s.offset.click.top,o.offset.click.left=s.offset.click.left,o.offset.parent.left-=s.offset.parent.left-o.offset.parent.left,o.offset.parent.top-=s.offset.parent.top-o.offset.parent.top,s._trigger("toSortable",e),s.dropped=o.element,t.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,o.fromOutside=s),o.currentItem&&(o._mouseDrag(e),i.position=o.position)):o.isOver&&(o.isOver=0,o.cancelHelperRemoval=!0,o.options._revert=o.options.revert,o.options.revert=!1,o._trigger("out",e,o._uiHash(o)),o._mouseStop(e,!0),o.options.revert=o.options._revert,o.options.helper=o.options._helper,o.placeholder&&o.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(e),i.position=s._generatePosition(e,!0),s._trigger("fromSortable",e),s.dropped=!1,t.each(s.sortables,function(){this.refreshPositions()}))})}}),t.ui.plugin.add("draggable","cursor",{start:function(e,i,s){var n=t("body"),o=s.options;n.css("cursor")&&(o._cursor=n.css("cursor")),n.css("cursor",o.cursor)},stop:function(e,i,s){var n=s.options;n._cursor&&t("body").css("cursor",n._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("opacity")&&(o._opacity=n.css("opacity")),n.css("opacity",o.opacity)},stop:function(e,i,s){var n=s.options;n._opacity&&t(i.helper).css("opacity",n._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(e,i,s){var n=s.options,o=!1,a=s.scrollParentNotHidden[0],r=s.document[0];a!==r&&"HTML"!==a.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+a.offsetHeight-e.pageY=0;d--)h=s.snapElements[d].left-s.margins.left,l=h+s.snapElements[d].width,c=s.snapElements[d].top-s.margins.top,u=c+s.snapElements[d].height,h-g>_||m>l+g||c-g>b||v>u+g||!t.contains(s.snapElements[d].item.ownerDocument,s.snapElements[d].item)?(s.snapElements[d].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=!1):("inner"!==f.snapMode&&(n=g>=Math.abs(c-b),o=g>=Math.abs(u-v),a=g>=Math.abs(h-_),r=g>=Math.abs(l-m),n&&(i.position.top=s._convertPositionTo("relative",{top:c-s.helperProportions.height,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||o||a||r,"outer"!==f.snapMode&&(n=g>=Math.abs(c-v),o=g>=Math.abs(u-b),a=g>=Math.abs(h-m),r=g>=Math.abs(l-_),n&&(i.position.top=s._convertPositionTo("relative",{top:c,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[d].snapping&&(n||o||a||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=n||o||a||r||p)}}),t.ui.plugin.add("draggable","stack",{start:function(e,i,s){var n,o=s.options,a=t.makeArray(t(o.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});a.length&&(n=parseInt(t(a[0]).css("zIndex"),10)||0,t(a).each(function(e){t(this).css("zIndex",n+e)}),this.css("zIndex",n+a.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("zIndex")&&(o._zIndex=n.css("zIndex")),n.css("zIndex",o.zIndex)},stop:function(e,i,s){var n=s.options;n._zIndex&&t(i.helper).css("zIndex",n._zIndex)}}),t.ui.draggable,t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
    "),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
    "),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,g=s.maxWidth&&p>s.maxWidth,m=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),g&&(p-=l),m&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable,t.widget("ui.dialog",{version:"1.12.1",options:{appendTo:"body",autoOpen:!0,buttons:[],classes:{"ui-dialog":"ui-corner-all","ui-dialog-titlebar":"ui-corner-all"},closeOnEscape:!0,closeText:"Close",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),null==this.options.title&&null!=this.originalTitle&&(this.options.title=this.originalTitle),this.options.disabled&&(this.options.disabled=!1),this._createWrapper(),this.element.show().removeAttr("title").appendTo(this.uiDialog),this._addClass("ui-dialog-content","ui-widget-content"),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().css(this.originalCss).detach(),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog -},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),this.opener.filter(":focusable").trigger("focus").length||t.ui.safeBlur(t.ui.safeActiveElement(this.document[0])),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(e,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+t(this).css("z-index")}).get(),o=Math.max.apply(null,n);return o>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",o+1),s=!0),s&&!i&&this._trigger("focus",e),s},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=t(t.ui.safeActiveElement(this.document[0])),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var t=this._focusedElement;t||(t=this.element.find("[autofocus]")),t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).trigger("focus")},_keepFocus:function(e){function i(){var e=t.ui.safeActiveElement(this.document[0]),i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("
    ").hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._addClass(this.uiDialog,"ui-dialog","ui-widget ui-widget-content ui-front"),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),void 0;if(e.keyCode===t.ui.keyCode.TAB&&!e.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(this._delay(function(){n.trigger("focus")}),e.preventDefault()):(this._delay(function(){s.trigger("focus")}),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("
    "),this._addClass(this.uiDialogTitlebar,"ui-dialog-titlebar","ui-widget-header ui-helper-clearfix"),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.trigger("focus")}}),this.uiDialogTitlebarClose=t("").button({label:t("").text(this.options.closeText).html(),icon:"ui-icon-closethick",showLabel:!1}).appendTo(this.uiDialogTitlebar),this._addClass(this.uiDialogTitlebarClose,"ui-dialog-titlebar-close"),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("").uniqueId().prependTo(this.uiDialogTitlebar),this._addClass(e,"ui-dialog-title"),this._title(e),this.uiDialogTitlebar.prependTo(this.uiDialog),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title?t.text(this.options.title):t.html(" ")},_createButtonPane:function(){this.uiDialogButtonPane=t("
    "),this._addClass(this.uiDialogButtonPane,"ui-dialog-buttonpane","ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("
    ").appendTo(this.uiDialogButtonPane),this._addClass(this.uiButtonSet,"ui-dialog-buttonset"),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this._removeClass(this.uiDialog,"ui-dialog-buttons"),void 0):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,o={icon:s.icon,iconPosition:s.iconPosition,showLabel:s.showLabel,icons:s.icons,text:s.text},delete s.click,delete s.icon,delete s.iconPosition,delete s.showLabel,delete s.icons,"boolean"==typeof s.text&&delete s.text,t("",s).button(o).appendTo(e.uiButtonSet).on("click",function(){n.apply(e.element[0],arguments)})}),this._addClass(this.uiDialog,"ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){i._addClass(t(this),"ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){var a=o.offset.left-i.document.scrollLeft(),r=o.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(a>=0?"+":"")+a+" "+"top"+(r>=0?"+":"")+r,of:i.window},i._removeClass(t(this),"ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){i._addClass(t(this),"ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){var a=i.uiDialog.offset(),r=a.left-i.document.scrollLeft(),h=a.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},i._removeClass(t(this),"ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_trackFocus:function(){this._on(this.widget(),{focusin:function(e){this._makeFocusTarget(),this._focusedElement=t(e.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var e=this._trackingInstances(),i=t.inArray(this,e);-1!==i&&e.splice(i,1)},_trackingInstances:function(){var t=this.document.data("ui-dialog-instances");return t||(t=[],this.document.data("ui-dialog-instances",t)),t},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(e){var i=this,s=!1,n={};t.each(e,function(t,e){i._setOption(t,e),t in i.sizeRelatedOptions&&(s=!0),t in i.resizableRelatedOptions&&(n[t]=e)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,i){var s,n,o=this.uiDialog;"disabled"!==e&&(this._super(e,i),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:t("").text(""+this.options.closeText).html()}),"draggable"===e&&(s=o.is(":data(ui-draggable)"),s&&!i&&o.draggable("destroy"),!s&&i&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(n=o.is(":data(ui-resizable)"),n&&!i&&o.resizable("destroy"),n&&"string"==typeof i&&o.resizable("option","handles",i),n||i===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("
    ").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=!0;this._delay(function(){e=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(t){e||this._allowInteraction(t)||(t.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=t("
    ").appendTo(this._appendTo()),this._addClass(this.overlay,null,"ui-widget-overlay ui-front"),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var t=this.document.data("ui-dialog-overlays")-1;t?this.document.data("ui-dialog-overlays",t):(this._off(this.document,"focusin"),this.document.removeData("ui-dialog-overlays")),this.overlay.remove(),this.overlay=null}}}),t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{options:{dialogClass:""},_createWrapper:function(){this._super(),this.uiDialog.addClass(this.options.dialogClass)},_setOption:function(t,e){"dialogClass"===t&&this.uiDialog.removeClass(this.options.dialogClass).addClass(e),this._superApply(arguments)}}),t.ui.dialog,t.widget("ui.droppable",{version:"1.12.1",widgetEventPrefix:"drop",options:{accept:"*",addClasses:!0,greedy:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],void 0):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this._addClass("ui-droppable")},_addToManager:function(e){t.ui.ddmanager.droppables[e]=t.ui.ddmanager.droppables[e]||[],t.ui.ddmanager.droppables[e].push(this)},_splice:function(t){for(var e=0;t.length>e;e++)t[e]===this&&t.splice(e,1)},_destroy:function(){var e=t.ui.ddmanager.droppables[this.options.scope];this._splice(e)},_setOption:function(e,i){if("accept"===e)this.accept=t.isFunction(i)?i:function(t){return t.is(i)};else if("scope"===e){var s=t.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(e,i)},_activate:function(e){var i=t.ui.ddmanager.current;this._addActiveClass(),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this._removeActiveClass(),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._addHoverClass(),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._removeHoverClass(),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=t(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&v(s,t.extend(i,{offset:i.element.offset()}),i.options.tolerance,e)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this._removeActiveClass(),this._removeHoverClass(),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}},_addHoverClass:function(){this._addClass("ui-droppable-hover")},_removeHoverClass:function(){this._removeClass("ui-droppable-hover")},_addActiveClass:function(){this._addClass("ui-droppable-active")},_removeActiveClass:function(){this._removeClass("ui-droppable-active")}});var v=t.ui.intersect=function(){function t(t,e,i){return t>=e&&e+i>t}return function(e,i,s,n){if(!i.offset)return!1;var o=(e.positionAbs||e.position.absolute).left+e.margins.left,a=(e.positionAbs||e.position.absolute).top+e.margins.top,r=o+e.helperProportions.width,h=a+e.helperProportions.height,l=i.offset.left,c=i.offset.top,u=l+i.proportions().width,d=c+i.proportions().height;switch(s){case"fit":return o>=l&&u>=r&&a>=c&&d>=h;case"intersect":return o+e.helperProportions.width/2>l&&u>r-e.helperProportions.width/2&&a+e.helperProportions.height/2>c&&d>h-e.helperProportions.height/2;case"pointer":return t(n.pageY,c,i.proportions().height)&&t(n.pageX,l,i.proportions().width);case"touch":return(a>=c&&d>=a||h>=c&&d>=h||c>a&&h>d)&&(o>=l&&u>=o||r>=l&&u>=r||l>o&&r>u);default:return!1}}}();t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions().height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions({width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&v(e,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").on("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=v(e,this,this.options.tolerance,i),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t(this).droppable("instance").options.scope===n}),o.length&&(s=t(o[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").off("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}},t.uiBackCompat!==!1&&t.widget("ui.droppable",t.ui.droppable,{options:{hoverClass:!1,activeClass:!1},_addActiveClass:function(){this._super(),this.options.activeClass&&this.element.addClass(this.options.activeClass)},_removeActiveClass:function(){this._super(),this.options.activeClass&&this.element.removeClass(this.options.activeClass)},_addHoverClass:function(){this._super(),this.options.hoverClass&&this.element.addClass(this.options.hoverClass)},_removeHoverClass:function(){this._super(),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass)}}),t.ui.droppable,t.widget("ui.progressbar",{version:"1.12.1",options:{classes:{"ui-progressbar":"ui-corner-all","ui-progressbar-value":"ui-corner-left","ui-progressbar-complete":"ui-corner-right"},max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.attr({role:"progressbar","aria-valuemin":this.min}),this._addClass("ui-progressbar","ui-widget ui-widget-content"),this.valueDiv=t("
    ").appendTo(this.element),this._addClass(this.valueDiv,"ui-progressbar-value","ui-widget-header"),this._refreshValue()},_destroy:function(){this.element.removeAttr("role aria-valuemin aria-valuemax aria-valuenow"),this.valueDiv.remove()},value:function(t){return void 0===t?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),void 0)},_constrainedValue:function(t){return void 0===t&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).width(i.toFixed(0)+"%"),this._toggleClass(this.valueDiv,"ui-progressbar-complete",null,e===this.options.max)._toggleClass("ui-progressbar-indeterminate",null,this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("
    ").appendTo(this.valueDiv),this._addClass(this.overlayDiv,"ui-progressbar-overlay"))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}}),t.widget("ui.selectable",t.ui.mouse,{version:"1.12.1",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e=this;this._addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e.elementPos=t(e.element[0]).offset(),e.selectees=t(e.options.filter,e.element[0]),e._addClass(e.selectees,"ui-selectee"),e.selectees.each(function(){var i=t(this),s=i.offset(),n={left:s.left-e.elementPos.left,top:s.top-e.elementPos.top};t.data(this,"selectable-item",{element:this,$element:i,left:n.left,top:n.top,right:n.left+i.outerWidth(),bottom:n.top+i.outerHeight(),startselected:!1,selected:i.hasClass("ui-selected"),selecting:i.hasClass("ui-selecting"),unselecting:i.hasClass("ui-unselecting")})})},this.refresh(),this._mouseInit(),this.helper=t("
    "),this._addClass(this.helper,"ui-selectable-helper")},_destroy:function(){this.selectees.removeData("selectable-item"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.elementPos=t(this.element[0]).offset(),this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(i._removeClass(s.$element,"ui-selected"),s.selected=!1,i._addClass(s.$element,"ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),i._removeClass(n.$element,s?"ui-unselecting":"ui-selected")._addClass(n.$element,s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1,c={};i&&i.element!==s.element[0]&&(c.left=i.left+s.elementPos.left,c.right=i.right+s.elementPos.left,c.top=i.top+s.elementPos.top,c.bottom=i.bottom+s.elementPos.top,"touch"===n.tolerance?l=!(c.left>r||o>c.right||c.top>h||a>c.bottom):"fit"===n.tolerance&&(l=c.left>o&&r>c.right&&c.top>a&&h>c.bottom),l?(i.selected&&(s._removeClass(i.$element,"ui-selected"),i.selected=!1),i.unselecting&&(s._removeClass(i.$element,"ui-unselecting"),i.unselecting=!1),i.selecting||(s._addClass(i.$element,"ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,s._addClass(i.$element,"ui-selected"),i.selected=!0):(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,i.startselected&&(s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(s._removeClass(i.$element,"ui-selected"),i.selected=!1,s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-selecting")._addClass(s.$element,"ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}}),t.widget("ui.selectmenu",[t.ui.formResetMixin,{version:"1.12.1",defaultElement:""),this._dialogInput.on("keydown",this._doKeyDown),t("body").append(this._dialogInput),d=this._dialogInst=this._newInst(this._dialogInput,!1),d.settings={},t.data(this._dialogInput[0],"datepicker",d)),a(d.settings,n||{}),i=i&&i.constructor===Date?this._formatDate(d,i):i,this._dialogInput.val(i),this._pos=o?o.length?o:[o.pageX,o.pageY]:null,this._pos||(h=document.documentElement.clientWidth,l=document.documentElement.clientHeight,c=document.documentElement.scrollLeft||document.body.scrollLeft,u=document.documentElement.scrollTop||document.body.scrollTop,this._pos=[h/2-100+c,l/2-150+u]),this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),d.settings.onSelect=s,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),t.blockUI&&t.blockUI(this.dpDiv),t.data(this._dialogInput[0],"datepicker",d),this},_destroyDatepicker:function(e){var i,s=t(e),n=t.data(e,"datepicker");s.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),t.removeData(e,"datepicker"),"input"===i?(n.append.remove(),n.trigger.remove(),s.removeClass(this.markerClassName).off("focus",this._showDatepicker).off("keydown",this._doKeyDown).off("keypress",this._doKeyPress).off("keyup",this._doKeyUp)):("div"===i||"span"===i)&&s.removeClass(this.markerClassName).empty(),m===n&&(m=null))},_enableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,"datepicker");n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!1,o.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().removeClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!1)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}))},_disableDatepicker:function(e){var i,s,n=t(e),o=t.data(e,"datepicker");n.hasClass(this.markerClassName)&&(i=e.nodeName.toLowerCase(),"input"===i?(e.disabled=!0,o.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"})):("div"===i||"span"===i)&&(s=n.children("."+this._inlineClass),s.children().addClass("ui-state-disabled"),s.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",!0)),this._disabledInputs=t.map(this._disabledInputs,function(t){return t===e?null:t}),this._disabledInputs[this._disabledInputs.length]=e)},_isDisabledDatepicker:function(t){if(!t)return!1;for(var e=0;this._disabledInputs.length>e;e++)if(this._disabledInputs[e]===t)return!0;return!1},_getInst:function(e){try{return t.data(e,"datepicker")}catch(i){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(e,i,s){var n,o,r,h,l=this._getInst(e);return 2===arguments.length&&"string"==typeof i?"defaults"===i?t.extend({},t.datepicker._defaults):l?"all"===i?t.extend({},l.settings):this._get(l,i):null:(n=i||{},"string"==typeof i&&(n={},n[i]=s),l&&(this._curInst===l&&this._hideDatepicker(),o=this._getDateDatepicker(e,!0),r=this._getMinMaxDate(l,"min"),h=this._getMinMaxDate(l,"max"),a(l.settings,n),null!==r&&void 0!==n.dateFormat&&void 0===n.minDate&&(l.settings.minDate=this._formatDate(l,r)),null!==h&&void 0!==n.dateFormat&&void 0===n.maxDate&&(l.settings.maxDate=this._formatDate(l,h)),"disabled"in n&&(n.disabled?this._disableDatepicker(e):this._enableDatepicker(e)),this._attachments(t(e),l),this._autoSize(l),this._setDate(l,o),this._updateAlternate(l),this._updateDatepicker(l)),void 0)},_changeDatepicker:function(t,e,i){this._optionDatepicker(t,e,i)},_refreshDatepicker:function(t){var e=this._getInst(t);e&&this._updateDatepicker(e)},_setDateDatepicker:function(t,e){var i=this._getInst(t);i&&(this._setDate(i,e),this._updateDatepicker(i),this._updateAlternate(i))},_getDateDatepicker:function(t,e){var i=this._getInst(t);return i&&!i.inline&&this._setDateFromField(i,e),i?this._getDate(i):null},_doKeyDown:function(e){var i,s,n,o=t.datepicker._getInst(e.target),a=!0,r=o.dpDiv.is(".ui-datepicker-rtl");if(o._keyEvent=!0,t.datepicker._datepickerShowing)switch(e.keyCode){case 9:t.datepicker._hideDatepicker(),a=!1;break;case 13:return n=t("td."+t.datepicker._dayOverClass+":not(."+t.datepicker._currentClass+")",o.dpDiv),n[0]&&t.datepicker._selectDay(e.target,o.selectedMonth,o.selectedYear,n[0]),i=t.datepicker._get(o,"onSelect"),i?(s=t.datepicker._formatDate(o),i.apply(o.input?o.input[0]:null,[s,o])):t.datepicker._hideDatepicker(),!1;case 27:t.datepicker._hideDatepicker();break;case 33:t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 34:t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 35:(e.ctrlKey||e.metaKey)&&t.datepicker._clearDate(e.target),a=e.ctrlKey||e.metaKey;break;case 36:(e.ctrlKey||e.metaKey)&&t.datepicker._gotoToday(e.target),a=e.ctrlKey||e.metaKey;break;case 37:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?1:-1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?-t.datepicker._get(o,"stepBigMonths"):-t.datepicker._get(o,"stepMonths"),"M");break;case 38:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,-7,"D"),a=e.ctrlKey||e.metaKey;break;case 39:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,r?-1:1,"D"),a=e.ctrlKey||e.metaKey,e.originalEvent.altKey&&t.datepicker._adjustDate(e.target,e.ctrlKey?+t.datepicker._get(o,"stepBigMonths"):+t.datepicker._get(o,"stepMonths"),"M");break;case 40:(e.ctrlKey||e.metaKey)&&t.datepicker._adjustDate(e.target,7,"D"),a=e.ctrlKey||e.metaKey;break;default:a=!1}else 36===e.keyCode&&e.ctrlKey?t.datepicker._showDatepicker(this):a=!1;a&&(e.preventDefault(),e.stopPropagation())},_doKeyPress:function(e){var i,s,n=t.datepicker._getInst(e.target);return t.datepicker._get(n,"constrainInput")?(i=t.datepicker._possibleChars(t.datepicker._get(n,"dateFormat")),s=String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),e.ctrlKey||e.metaKey||" ">s||!i||i.indexOf(s)>-1):void 0},_doKeyUp:function(e){var i,s=t.datepicker._getInst(e.target);if(s.input.val()!==s.lastVal)try{i=t.datepicker.parseDate(t.datepicker._get(s,"dateFormat"),s.input?s.input.val():null,t.datepicker._getFormatConfig(s)),i&&(t.datepicker._setDateFromField(s),t.datepicker._updateAlternate(s),t.datepicker._updateDatepicker(s))}catch(n){}return!0},_showDatepicker:function(e){if(e=e.target||e,"input"!==e.nodeName.toLowerCase()&&(e=t("input",e.parentNode)[0]),!t.datepicker._isDisabledDatepicker(e)&&t.datepicker._lastInput!==e){var s,n,o,r,h,l,c;s=t.datepicker._getInst(e),t.datepicker._curInst&&t.datepicker._curInst!==s&&(t.datepicker._curInst.dpDiv.stop(!0,!0),s&&t.datepicker._datepickerShowing&&t.datepicker._hideDatepicker(t.datepicker._curInst.input[0])),n=t.datepicker._get(s,"beforeShow"),o=n?n.apply(e,[e,s]):{},o!==!1&&(a(s.settings,o),s.lastVal=null,t.datepicker._lastInput=e,t.datepicker._setDateFromField(s),t.datepicker._inDialog&&(e.value=""),t.datepicker._pos||(t.datepicker._pos=t.datepicker._findPos(e),t.datepicker._pos[1]+=e.offsetHeight),r=!1,t(e).parents().each(function(){return r|="fixed"===t(this).css("position"),!r}),h={left:t.datepicker._pos[0],top:t.datepicker._pos[1]},t.datepicker._pos=null,s.dpDiv.empty(),s.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),t.datepicker._updateDatepicker(s),h=t.datepicker._checkOffset(s,h,r),s.dpDiv.css({position:t.datepicker._inDialog&&t.blockUI?"static":r?"fixed":"absolute",display:"none",left:h.left+"px",top:h.top+"px"}),s.inline||(l=t.datepicker._get(s,"showAnim"),c=t.datepicker._get(s,"duration"),s.dpDiv.css("z-index",i(t(e))+1),t.datepicker._datepickerShowing=!0,t.effects&&t.effects.effect[l]?s.dpDiv.show(l,t.datepicker._get(s,"showOptions"),c):s.dpDiv[l||"show"](l?c:null),t.datepicker._shouldFocusInput(s)&&s.input.trigger("focus"),t.datepicker._curInst=s)) +}},_updateDatepicker:function(e){this.maxRows=4,m=e,e.dpDiv.empty().append(this._generateHTML(e)),this._attachHandlers(e);var i,s=this._getNumberOfMonths(e),n=s[1],a=17,r=e.dpDiv.find("."+this._dayOverClass+" a");r.length>0&&o.apply(r.get(0)),e.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),n>1&&e.dpDiv.addClass("ui-datepicker-multi-"+n).css("width",a*n+"em"),e.dpDiv[(1!==s[0]||1!==s[1]?"add":"remove")+"Class"]("ui-datepicker-multi"),e.dpDiv[(this._get(e,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),e===t.datepicker._curInst&&t.datepicker._datepickerShowing&&t.datepicker._shouldFocusInput(e)&&e.input.trigger("focus"),e.yearshtml&&(i=e.yearshtml,setTimeout(function(){i===e.yearshtml&&e.yearshtml&&e.dpDiv.find("select.ui-datepicker-year:first").replaceWith(e.yearshtml),i=e.yearshtml=null},0))},_shouldFocusInput:function(t){return t.input&&t.input.is(":visible")&&!t.input.is(":disabled")&&!t.input.is(":focus")},_checkOffset:function(e,i,s){var n=e.dpDiv.outerWidth(),o=e.dpDiv.outerHeight(),a=e.input?e.input.outerWidth():0,r=e.input?e.input.outerHeight():0,h=document.documentElement.clientWidth+(s?0:t(document).scrollLeft()),l=document.documentElement.clientHeight+(s?0:t(document).scrollTop());return i.left-=this._get(e,"isRTL")?n-a:0,i.left-=s&&i.left===e.input.offset().left?t(document).scrollLeft():0,i.top-=s&&i.top===e.input.offset().top+r?t(document).scrollTop():0,i.left-=Math.min(i.left,i.left+n>h&&h>n?Math.abs(i.left+n-h):0),i.top-=Math.min(i.top,i.top+o>l&&l>o?Math.abs(o+r):0),i},_findPos:function(e){for(var i,s=this._getInst(e),n=this._get(s,"isRTL");e&&("hidden"===e.type||1!==e.nodeType||t.expr.filters.hidden(e));)e=e[n?"previousSibling":"nextSibling"];return i=t(e).offset(),[i.left,i.top]},_hideDatepicker:function(e){var i,s,n,o,a=this._curInst;!a||e&&a!==t.data(e,"datepicker")||this._datepickerShowing&&(i=this._get(a,"showAnim"),s=this._get(a,"duration"),n=function(){t.datepicker._tidyDialog(a)},t.effects&&(t.effects.effect[i]||t.effects[i])?a.dpDiv.hide(i,t.datepicker._get(a,"showOptions"),s,n):a.dpDiv["slideDown"===i?"slideUp":"fadeIn"===i?"fadeOut":"hide"](i?s:null,n),i||n(),this._datepickerShowing=!1,o=this._get(a,"onClose"),o&&o.apply(a.input?a.input[0]:null,[a.input?a.input.val():"",a]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),t.blockUI&&(t.unblockUI(),t("body").append(this.dpDiv))),this._inDialog=!1)},_tidyDialog:function(t){t.dpDiv.removeClass(this._dialogClass).off(".ui-datepicker-calendar")},_checkExternalClick:function(e){if(t.datepicker._curInst){var i=t(e.target),s=t.datepicker._getInst(i[0]);(i[0].id!==t.datepicker._mainDivId&&0===i.parents("#"+t.datepicker._mainDivId).length&&!i.hasClass(t.datepicker.markerClassName)&&!i.closest("."+t.datepicker._triggerClass).length&&t.datepicker._datepickerShowing&&(!t.datepicker._inDialog||!t.blockUI)||i.hasClass(t.datepicker.markerClassName)&&t.datepicker._curInst!==s)&&t.datepicker._hideDatepicker()}},_adjustDate:function(e,i,s){var n=t(e),o=this._getInst(n[0]);this._isDisabledDatepicker(n[0])||(this._adjustInstDate(o,i+("M"===s?this._get(o,"showCurrentAtPos"):0),s),this._updateDatepicker(o))},_gotoToday:function(e){var i,s=t(e),n=this._getInst(s[0]);this._get(n,"gotoCurrent")&&n.currentDay?(n.selectedDay=n.currentDay,n.drawMonth=n.selectedMonth=n.currentMonth,n.drawYear=n.selectedYear=n.currentYear):(i=new Date,n.selectedDay=i.getDate(),n.drawMonth=n.selectedMonth=i.getMonth(),n.drawYear=n.selectedYear=i.getFullYear()),this._notifyChange(n),this._adjustDate(s)},_selectMonthYear:function(e,i,s){var n=t(e),o=this._getInst(n[0]);o["selected"+("M"===s?"Month":"Year")]=o["draw"+("M"===s?"Month":"Year")]=parseInt(i.options[i.selectedIndex].value,10),this._notifyChange(o),this._adjustDate(n)},_selectDay:function(e,i,s,n){var o,a=t(e);t(n).hasClass(this._unselectableClass)||this._isDisabledDatepicker(a[0])||(o=this._getInst(a[0]),o.selectedDay=o.currentDay=t("a",n).html(),o.selectedMonth=o.currentMonth=i,o.selectedYear=o.currentYear=s,this._selectDate(e,this._formatDate(o,o.currentDay,o.currentMonth,o.currentYear)))},_clearDate:function(e){var i=t(e);this._selectDate(i,"")},_selectDate:function(e,i){var s,n=t(e),o=this._getInst(n[0]);i=null!=i?i:this._formatDate(o),o.input&&o.input.val(i),this._updateAlternate(o),s=this._get(o,"onSelect"),s?s.apply(o.input?o.input[0]:null,[i,o]):o.input&&o.input.trigger("change"),o.inline?this._updateDatepicker(o):(this._hideDatepicker(),this._lastInput=o.input[0],"object"!=typeof o.input[0]&&o.input.trigger("focus"),this._lastInput=null)},_updateAlternate:function(e){var i,s,n,o=this._get(e,"altField");o&&(i=this._get(e,"altFormat")||this._get(e,"dateFormat"),s=this._getDate(e),n=this.formatDate(i,s,this._getFormatConfig(e)),t(o).val(n))},noWeekends:function(t){var e=t.getDay();return[e>0&&6>e,""]},iso8601Week:function(t){var e,i=new Date(t.getTime());return i.setDate(i.getDate()+4-(i.getDay()||7)),e=i.getTime(),i.setMonth(0),i.setDate(1),Math.floor(Math.round((e-i)/864e5)/7)+1},parseDate:function(e,i,s){if(null==e||null==i)throw"Invalid arguments";if(i="object"==typeof i?""+i:i+"",""===i)return null;var n,o,a,r,h=0,l=(s?s.shortYearCutoff:null)||this._defaults.shortYearCutoff,c="string"!=typeof l?l:(new Date).getFullYear()%100+parseInt(l,10),u=(s?s.dayNamesShort:null)||this._defaults.dayNamesShort,d=(s?s.dayNames:null)||this._defaults.dayNames,p=(s?s.monthNamesShort:null)||this._defaults.monthNamesShort,f=(s?s.monthNames:null)||this._defaults.monthNames,g=-1,m=-1,_=-1,v=-1,b=!1,y=function(t){var i=e.length>n+1&&e.charAt(n+1)===t;return i&&n++,i},w=function(t){var e=y(t),s="@"===t?14:"!"===t?20:"y"===t&&e?4:"o"===t?3:2,n="y"===t?s:1,o=RegExp("^\\d{"+n+","+s+"}"),a=i.substring(h).match(o);if(!a)throw"Missing number at position "+h;return h+=a[0].length,parseInt(a[0],10)},k=function(e,s,n){var o=-1,a=t.map(y(e)?n:s,function(t,e){return[[e,t]]}).sort(function(t,e){return-(t[1].length-e[1].length)});if(t.each(a,function(t,e){var s=e[1];return i.substr(h,s.length).toLowerCase()===s.toLowerCase()?(o=e[0],h+=s.length,!1):void 0}),-1!==o)return o+1;throw"Unknown name at position "+h},x=function(){if(i.charAt(h)!==e.charAt(n))throw"Unexpected literal at position "+h;h++};for(n=0;e.length>n;n++)if(b)"'"!==e.charAt(n)||y("'")?x():b=!1;else switch(e.charAt(n)){case"d":_=w("d");break;case"D":k("D",u,d);break;case"o":v=w("o");break;case"m":m=w("m");break;case"M":m=k("M",p,f);break;case"y":g=w("y");break;case"@":r=new Date(w("@")),g=r.getFullYear(),m=r.getMonth()+1,_=r.getDate();break;case"!":r=new Date((w("!")-this._ticksTo1970)/1e4),g=r.getFullYear(),m=r.getMonth()+1,_=r.getDate();break;case"'":y("'")?x():b=!0;break;default:x()}if(i.length>h&&(a=i.substr(h),!/^\s+/.test(a)))throw"Extra/unparsed characters found in date: "+a;if(-1===g?g=(new Date).getFullYear():100>g&&(g+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c>=g?0:-100)),v>-1)for(m=1,_=v;;){if(o=this._getDaysInMonth(g,m-1),o>=_)break;m++,_-=o}if(r=this._daylightSavingAdjust(new Date(g,m-1,_)),r.getFullYear()!==g||r.getMonth()+1!==m||r.getDate()!==_)throw"Invalid date";return r},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:1e7*60*60*24*(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925)),formatDate:function(t,e,i){if(!e)return"";var s,n=(i?i.dayNamesShort:null)||this._defaults.dayNamesShort,o=(i?i.dayNames:null)||this._defaults.dayNames,a=(i?i.monthNamesShort:null)||this._defaults.monthNamesShort,r=(i?i.monthNames:null)||this._defaults.monthNames,h=function(e){var i=t.length>s+1&&t.charAt(s+1)===e;return i&&s++,i},l=function(t,e,i){var s=""+e;if(h(t))for(;i>s.length;)s="0"+s;return s},c=function(t,e,i,s){return h(t)?s[e]:i[e]},u="",d=!1;if(e)for(s=0;t.length>s;s++)if(d)"'"!==t.charAt(s)||h("'")?u+=t.charAt(s):d=!1;else switch(t.charAt(s)){case"d":u+=l("d",e.getDate(),2);break;case"D":u+=c("D",e.getDay(),n,o);break;case"o":u+=l("o",Math.round((new Date(e.getFullYear(),e.getMonth(),e.getDate()).getTime()-new Date(e.getFullYear(),0,0).getTime())/864e5),3);break;case"m":u+=l("m",e.getMonth()+1,2);break;case"M":u+=c("M",e.getMonth(),a,r);break;case"y":u+=h("y")?e.getFullYear():(10>e.getFullYear()%100?"0":"")+e.getFullYear()%100;break;case"@":u+=e.getTime();break;case"!":u+=1e4*e.getTime()+this._ticksTo1970;break;case"'":h("'")?u+="'":d=!0;break;default:u+=t.charAt(s)}return u},_possibleChars:function(t){var e,i="",s=!1,n=function(i){var s=t.length>e+1&&t.charAt(e+1)===i;return s&&e++,s};for(e=0;t.length>e;e++)if(s)"'"!==t.charAt(e)||n("'")?i+=t.charAt(e):s=!1;else switch(t.charAt(e)){case"d":case"m":case"y":case"@":i+="0123456789";break;case"D":case"M":return null;case"'":n("'")?i+="'":s=!0;break;default:i+=t.charAt(e)}return i},_get:function(t,e){return void 0!==t.settings[e]?t.settings[e]:this._defaults[e]},_setDateFromField:function(t,e){if(t.input.val()!==t.lastVal){var i=this._get(t,"dateFormat"),s=t.lastVal=t.input?t.input.val():null,n=this._getDefaultDate(t),o=n,a=this._getFormatConfig(t);try{o=this.parseDate(i,s,a)||n}catch(r){s=e?"":s}t.selectedDay=o.getDate(),t.drawMonth=t.selectedMonth=o.getMonth(),t.drawYear=t.selectedYear=o.getFullYear(),t.currentDay=s?o.getDate():0,t.currentMonth=s?o.getMonth():0,t.currentYear=s?o.getFullYear():0,this._adjustInstDate(t)}},_getDefaultDate:function(t){return this._restrictMinMax(t,this._determineDate(t,this._get(t,"defaultDate"),new Date))},_determineDate:function(e,i,s){var n=function(t){var e=new Date;return e.setDate(e.getDate()+t),e},o=function(i){try{return t.datepicker.parseDate(t.datepicker._get(e,"dateFormat"),i,t.datepicker._getFormatConfig(e))}catch(s){}for(var n=(i.toLowerCase().match(/^c/)?t.datepicker._getDate(e):null)||new Date,o=n.getFullYear(),a=n.getMonth(),r=n.getDate(),h=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,l=h.exec(i);l;){switch(l[2]||"d"){case"d":case"D":r+=parseInt(l[1],10);break;case"w":case"W":r+=7*parseInt(l[1],10);break;case"m":case"M":a+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a));break;case"y":case"Y":o+=parseInt(l[1],10),r=Math.min(r,t.datepicker._getDaysInMonth(o,a))}l=h.exec(i)}return new Date(o,a,r)},a=null==i||""===i?s:"string"==typeof i?o(i):"number"==typeof i?isNaN(i)?s:n(i):new Date(i.getTime());return a=a&&"Invalid Date"==""+a?s:a,a&&(a.setHours(0),a.setMinutes(0),a.setSeconds(0),a.setMilliseconds(0)),this._daylightSavingAdjust(a)},_daylightSavingAdjust:function(t){return t?(t.setHours(t.getHours()>12?t.getHours()+2:0),t):null},_setDate:function(t,e,i){var s=!e,n=t.selectedMonth,o=t.selectedYear,a=this._restrictMinMax(t,this._determineDate(t,e,new Date));t.selectedDay=t.currentDay=a.getDate(),t.drawMonth=t.selectedMonth=t.currentMonth=a.getMonth(),t.drawYear=t.selectedYear=t.currentYear=a.getFullYear(),n===t.selectedMonth&&o===t.selectedYear||i||this._notifyChange(t),this._adjustInstDate(t),t.input&&t.input.val(s?"":this._formatDate(t))},_getDate:function(t){var e=!t.currentYear||t.input&&""===t.input.val()?null:this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return e},_attachHandlers:function(e){var i=this._get(e,"stepMonths"),s="#"+e.id.replace(/\\\\/g,"\\");e.dpDiv.find("[data-handler]").map(function(){var e={prev:function(){t.datepicker._adjustDate(s,-i,"M")},next:function(){t.datepicker._adjustDate(s,+i,"M")},hide:function(){t.datepicker._hideDatepicker()},today:function(){t.datepicker._gotoToday(s)},selectDay:function(){return t.datepicker._selectDay(s,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this),!1},selectMonth:function(){return t.datepicker._selectMonthYear(s,this,"M"),!1},selectYear:function(){return t.datepicker._selectMonthYear(s,this,"Y"),!1}};t(this).on(this.getAttribute("data-event"),e[this.getAttribute("data-handler")])})},_generateHTML:function(t){var e,i,s,n,o,a,r,h,l,c,u,d,p,f,g,m,_,v,b,y,w,k,x,C,D,I,T,P,M,S,H,z,O,A,N,W,E,F,L,R=new Date,B=this._daylightSavingAdjust(new Date(R.getFullYear(),R.getMonth(),R.getDate())),Y=this._get(t,"isRTL"),j=this._get(t,"showButtonPanel"),q=this._get(t,"hideIfNoPrevNext"),K=this._get(t,"navigationAsDateFormat"),U=this._getNumberOfMonths(t),V=this._get(t,"showCurrentAtPos"),$=this._get(t,"stepMonths"),X=1!==U[0]||1!==U[1],G=this._daylightSavingAdjust(t.currentDay?new Date(t.currentYear,t.currentMonth,t.currentDay):new Date(9999,9,9)),Q=this._getMinMaxDate(t,"min"),J=this._getMinMaxDate(t,"max"),Z=t.drawMonth-V,te=t.drawYear;if(0>Z&&(Z+=12,te--),J)for(e=this._daylightSavingAdjust(new Date(J.getFullYear(),J.getMonth()-U[0]*U[1]+1,J.getDate())),e=Q&&Q>e?Q:e;this._daylightSavingAdjust(new Date(te,Z,1))>e;)Z--,0>Z&&(Z=11,te--);for(t.drawMonth=Z,t.drawYear=te,i=this._get(t,"prevText"),i=K?this.formatDate(i,this._daylightSavingAdjust(new Date(te,Z-$,1)),this._getFormatConfig(t)):i,s=this._canAdjustMonth(t,-1,te,Z)?""+i+"":q?"":""+i+"",n=this._get(t,"nextText"),n=K?this.formatDate(n,this._daylightSavingAdjust(new Date(te,Z+$,1)),this._getFormatConfig(t)):n,o=this._canAdjustMonth(t,1,te,Z)?""+n+"":q?"":""+n+"",a=this._get(t,"currentText"),r=this._get(t,"gotoCurrent")&&t.currentDay?G:B,a=K?this.formatDate(a,r,this._getFormatConfig(t)):a,h=t.inline?"":"",l=j?"
    "+(Y?h:"")+(this._isInRange(t,r)?"":"")+(Y?"":h)+"
    ":"",c=parseInt(this._get(t,"firstDay"),10),c=isNaN(c)?0:c,u=this._get(t,"showWeek"),d=this._get(t,"dayNames"),p=this._get(t,"dayNamesMin"),f=this._get(t,"monthNames"),g=this._get(t,"monthNamesShort"),m=this._get(t,"beforeShowDay"),_=this._get(t,"showOtherMonths"),v=this._get(t,"selectOtherMonths"),b=this._getDefaultDate(t),y="",k=0;U[0]>k;k++){for(x="",this.maxRows=4,C=0;U[1]>C;C++){if(D=this._daylightSavingAdjust(new Date(te,Z,t.selectedDay)),I=" ui-corner-all",T="",X){if(T+="
    "}for(T+="
    "+(/all|left/.test(I)&&0===k?Y?o:s:"")+(/all|right/.test(I)&&0===k?Y?s:o:"")+this._generateMonthYearHeader(t,Z,te,Q,J,k>0||C>0,f,g)+"
    "+"",P=u?"":"",w=0;7>w;w++)M=(w+c)%7,P+="";for(T+=P+"",S=this._getDaysInMonth(te,Z),te===t.selectedYear&&Z===t.selectedMonth&&(t.selectedDay=Math.min(t.selectedDay,S)),H=(this._getFirstDayOfMonth(te,Z)-c+7)%7,z=Math.ceil((H+S)/7),O=X?this.maxRows>z?this.maxRows:z:z,this.maxRows=O,A=this._daylightSavingAdjust(new Date(te,Z,1-H)),N=0;O>N;N++){for(T+="",W=u?"":"",w=0;7>w;w++)E=m?m.apply(t.input?t.input[0]:null,[A]):[!0,""],F=A.getMonth()!==Z,L=F&&!v||!E[0]||Q&&Q>A||J&&A>J,W+="",A.setDate(A.getDate()+1),A=this._daylightSavingAdjust(A);T+=W+""}Z++,Z>11&&(Z=0,te++),T+="
    "+this._get(t,"weekHeader")+"=5?" class='ui-datepicker-week-end'":"")+">"+""+p[M]+"
    "+this._get(t,"calculateWeek")(A)+""+(F&&!_?" ":L?""+A.getDate()+"":""+A.getDate()+"")+"
    "+(X?"
    "+(U[0]>0&&C===U[1]-1?"
    ":""):""),x+=T}y+=x}return y+=l,t._keyEvent=!1,y},_generateMonthYearHeader:function(t,e,i,s,n,o,a,r){var h,l,c,u,d,p,f,g,m=this._get(t,"changeMonth"),_=this._get(t,"changeYear"),v=this._get(t,"showMonthAfterYear"),b="
    ",y="";if(o||!m)y+=""+a[e]+"";else{for(h=s&&s.getFullYear()===i,l=n&&n.getFullYear()===i,y+=""}if(v||(b+=y+(!o&&m&&_?"":" ")),!t.yearshtml)if(t.yearshtml="",o||!_)b+=""+i+"";else{for(u=this._get(t,"yearRange").split(":"),d=(new Date).getFullYear(),p=function(t){var e=t.match(/c[+\-].*/)?i+parseInt(t.substring(1),10):t.match(/[+\-].*/)?d+parseInt(t,10):parseInt(t,10);return isNaN(e)?d:e},f=p(u[0]),g=Math.max(f,p(u[1]||"")),f=s?Math.max(f,s.getFullYear()):f,g=n?Math.min(g,n.getFullYear()):g,t.yearshtml+="",b+=t.yearshtml,t.yearshtml=null}return b+=this._get(t,"yearSuffix"),v&&(b+=(!o&&m&&_?"":" ")+y),b+="
    "},_adjustInstDate:function(t,e,i){var s=t.selectedYear+("Y"===i?e:0),n=t.selectedMonth+("M"===i?e:0),o=Math.min(t.selectedDay,this._getDaysInMonth(s,n))+("D"===i?e:0),a=this._restrictMinMax(t,this._daylightSavingAdjust(new Date(s,n,o)));t.selectedDay=a.getDate(),t.drawMonth=t.selectedMonth=a.getMonth(),t.drawYear=t.selectedYear=a.getFullYear(),("M"===i||"Y"===i)&&this._notifyChange(t)},_restrictMinMax:function(t,e){var i=this._getMinMaxDate(t,"min"),s=this._getMinMaxDate(t,"max"),n=i&&i>e?i:e;return s&&n>s?s:n},_notifyChange:function(t){var e=this._get(t,"onChangeMonthYear");e&&e.apply(t.input?t.input[0]:null,[t.selectedYear,t.selectedMonth+1,t])},_getNumberOfMonths:function(t){var e=this._get(t,"numberOfMonths");return null==e?[1,1]:"number"==typeof e?[1,e]:e},_getMinMaxDate:function(t,e){return this._determineDate(t,this._get(t,e+"Date"),null)},_getDaysInMonth:function(t,e){return 32-this._daylightSavingAdjust(new Date(t,e,32)).getDate()},_getFirstDayOfMonth:function(t,e){return new Date(t,e,1).getDay()},_canAdjustMonth:function(t,e,i,s){var n=this._getNumberOfMonths(t),o=this._daylightSavingAdjust(new Date(i,s+(0>e?e:n[0]*n[1]),1));return 0>e&&o.setDate(this._getDaysInMonth(o.getFullYear(),o.getMonth())),this._isInRange(t,o)},_isInRange:function(t,e){var i,s,n=this._getMinMaxDate(t,"min"),o=this._getMinMaxDate(t,"max"),a=null,r=null,h=this._get(t,"yearRange");return h&&(i=h.split(":"),s=(new Date).getFullYear(),a=parseInt(i[0],10),r=parseInt(i[1],10),i[0].match(/[+\-].*/)&&(a+=s),i[1].match(/[+\-].*/)&&(r+=s)),(!n||e.getTime()>=n.getTime())&&(!o||e.getTime()<=o.getTime())&&(!a||e.getFullYear()>=a)&&(!r||r>=e.getFullYear())},_getFormatConfig:function(t){var e=this._get(t,"shortYearCutoff");return e="string"!=typeof e?e:(new Date).getFullYear()%100+parseInt(e,10),{shortYearCutoff:e,dayNamesShort:this._get(t,"dayNamesShort"),dayNames:this._get(t,"dayNames"),monthNamesShort:this._get(t,"monthNamesShort"),monthNames:this._get(t,"monthNames")}},_formatDate:function(t,e,i,s){e||(t.currentDay=t.selectedDay,t.currentMonth=t.selectedMonth,t.currentYear=t.selectedYear);var n=e?"object"==typeof e?e:this._daylightSavingAdjust(new Date(s,i,e)):this._daylightSavingAdjust(new Date(t.currentYear,t.currentMonth,t.currentDay));return this.formatDate(this._get(t,"dateFormat"),n,this._getFormatConfig(t))}}),t.fn.datepicker=function(e){if(!this.length)return this;t.datepicker.initialized||(t(document).on("mousedown",t.datepicker._checkExternalClick),t.datepicker.initialized=!0),0===t("#"+t.datepicker._mainDivId).length&&t("body").append(t.datepicker.dpDiv);var i=Array.prototype.slice.call(arguments,1);return"string"!=typeof e||"isDisabled"!==e&&"getDate"!==e&&"widget"!==e?"option"===e&&2===arguments.length&&"string"==typeof arguments[1]?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i)):this.each(function(){"string"==typeof e?t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this].concat(i)):t.datepicker._attachDatepicker(this,e)}):t.datepicker["_"+e+"Datepicker"].apply(t.datepicker,[this[0]].concat(i))},t.datepicker=new s,t.datepicker.initialized=!1,t.datepicker.uuid=(new Date).getTime(),t.datepicker.version="1.12.1",t.datepicker,t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var _=!1;t(document).on("mouseup",function(){_=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!_){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,n="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),_=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,_=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.ui.safeBlur=function(e){e&&"body"!==e.nodeName.toLowerCase()&&t(e).trigger("blur")},t.widget("ui.draggable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this._addClass("ui-draggable"),this._setHandleClassName(),this._mouseInit()},_setOption:function(t,e){this._super(t,e),"handle"===t&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(e){var i=this.options;return this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(this._blurActiveElement(e),this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(e){this.iframeBlocks=this.document.find(e).map(function(){var e=t(this);return t("
    ").css("position","absolute").appendTo(e.parent()).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(e){var i=t.ui.safeActiveElement(this.document[0]),s=t(e.target);s.closest(i).length||t.ui.safeBlur(i)},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this._addClass(this.helper,"ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===t(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(e),this.originalPosition=this.position=this._generatePosition(e,!1),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_refreshOffsets:function(t){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:t.pageX-this.offset.left,top:t.pageY-this.offset.top}},_mouseDrag:function(e,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp(new t.Event("mouseup",e)),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1},_mouseUp:function(e){return this._unblockFrames(),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),this.handleElement.is(e.target)&&this.element.trigger("focus"),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp(new t.Event("mouseup",{target:this.element[0]})):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this._addClass(this.handleElement,"ui-draggable-handle")},_removeHandleClassName:function(){this._removeClass(this.handleElement,"ui-draggable-handle")},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper),n=s?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_isRootNode:function(t){return/(html|body)/i.test(t.tagName)||t===this.document[0]},_getParentOffset:function(){var e=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var t=this.element.position(),e=this._isRootNode(this.scrollParent[0]);return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+(e?0:this.scrollParent.scrollTop()),left:t.left-(parseInt(this.helper.css("left"),10)||0)+(e?0:this.scrollParent.scrollLeft())} +},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options,o=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,t(o).width()-this.helperProportions.width-this.margins.left,(t(o).height()||o.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(t,e){e||(e=this.position);var i="absolute"===t?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:e.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:e.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(t,e){var i,s,n,o,a=this.options,r=this._isRootNode(this.scrollParent[0]),h=t.pageX,l=t.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),e&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),a.grid&&(n=a.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/a.grid[1])*a.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-a.grid[1]:n+a.grid[1]:n,o=a.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/a.grid[0])*a.grid[0]:this.originalPageX,h=i?o-this.offset.click.left>=i[0]||o-this.offset.click.left>i[2]?o:o-this.offset.click.left>=i[0]?o-a.grid[0]:o+a.grid[0]:o),"y"===a.axis&&(h=this.originalPageX),"x"===a.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this._removeClass(this.helper,"ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s,this],!0),/^(drag|start|stop)/.test(e)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i,s){var n=t.extend({},i,{item:s.element});s.sortables=[],t(s.options.connectToSortable).each(function(){var i=t(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",e,n))})},stop:function(e,i,s){var n=t.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,t.each(s.sortables,function(){var t=this;t.isOver?(t.isOver=0,s.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,n))})},drag:function(e,i,s){t.each(s.sortables,function(){var n=!1,o=this;o.positionAbs=s.positionAbs,o.helperProportions=s.helperProportions,o.offset.click=s.offset.click,o._intersectsWith(o.containerCache)&&(n=!0,t.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==o&&this._intersectsWith(this.containerCache)&&t.contains(o.element[0],this.element[0])&&(n=!1),n})),n?(o.isOver||(o.isOver=1,s._parent=i.helper.parent(),o.currentItem=i.helper.appendTo(o.element).data("ui-sortable-item",!0),o.options._helper=o.options.helper,o.options.helper=function(){return i.helper[0]},e.target=o.currentItem[0],o._mouseCapture(e,!0),o._mouseStart(e,!0,!0),o.offset.click.top=s.offset.click.top,o.offset.click.left=s.offset.click.left,o.offset.parent.left-=s.offset.parent.left-o.offset.parent.left,o.offset.parent.top-=s.offset.parent.top-o.offset.parent.top,s._trigger("toSortable",e),s.dropped=o.element,t.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,o.fromOutside=s),o.currentItem&&(o._mouseDrag(e),i.position=o.position)):o.isOver&&(o.isOver=0,o.cancelHelperRemoval=!0,o.options._revert=o.options.revert,o.options.revert=!1,o._trigger("out",e,o._uiHash(o)),o._mouseStop(e,!0),o.options.revert=o.options._revert,o.options.helper=o.options._helper,o.placeholder&&o.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(e),i.position=s._generatePosition(e,!0),s._trigger("fromSortable",e),s.dropped=!1,t.each(s.sortables,function(){this.refreshPositions()}))})}}),t.ui.plugin.add("draggable","cursor",{start:function(e,i,s){var n=t("body"),o=s.options;n.css("cursor")&&(o._cursor=n.css("cursor")),n.css("cursor",o.cursor)},stop:function(e,i,s){var n=s.options;n._cursor&&t("body").css("cursor",n._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("opacity")&&(o._opacity=n.css("opacity")),n.css("opacity",o.opacity)},stop:function(e,i,s){var n=s.options;n._opacity&&t(i.helper).css("opacity",n._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(e,i,s){var n=s.options,o=!1,a=s.scrollParentNotHidden[0],r=s.document[0];a!==r&&"HTML"!==a.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+a.offsetHeight-e.pageY=0;d--)h=s.snapElements[d].left-s.margins.left,l=h+s.snapElements[d].width,c=s.snapElements[d].top-s.margins.top,u=c+s.snapElements[d].height,h-g>_||m>l+g||c-g>b||v>u+g||!t.contains(s.snapElements[d].item.ownerDocument,s.snapElements[d].item)?(s.snapElements[d].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=!1):("inner"!==f.snapMode&&(n=g>=Math.abs(c-b),o=g>=Math.abs(u-v),a=g>=Math.abs(h-_),r=g>=Math.abs(l-m),n&&(i.position.top=s._convertPositionTo("relative",{top:c-s.helperProportions.height,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||o||a||r,"outer"!==f.snapMode&&(n=g>=Math.abs(c-v),o=g>=Math.abs(u-b),a=g>=Math.abs(h-m),r=g>=Math.abs(l-_),n&&(i.position.top=s._convertPositionTo("relative",{top:c,left:0}).top),o&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[d].snapping&&(n||o||a||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=n||o||a||r||p)}}),t.ui.plugin.add("draggable","stack",{start:function(e,i,s){var n,o=s.options,a=t.makeArray(t(o.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});a.length&&(n=parseInt(t(a[0]).css("zIndex"),10)||0,t(a).each(function(e){t(this).css("zIndex",n+e)}),this.css("zIndex",n+a.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i,s){var n=t(i.helper),o=s.options;n.css("zIndex")&&(o._zIndex=n.css("zIndex")),n.css("zIndex",o.zIndex)},stop:function(e,i,s){var n=s.options;n._zIndex&&t(i.helper).css("zIndex",n._zIndex)}}),t.ui.draggable,t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
    ").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
    "),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
    "),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,g=s.maxWidth&&p>s.maxWidth,m=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),g&&(p-=l),m&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable,t.widget("ui.dialog",{version:"1.12.1",options:{appendTo:"body",autoOpen:!0,buttons:[],classes:{"ui-dialog":"ui-corner-all","ui-dialog-titlebar":"ui-corner-all"},closeOnEscape:!0,closeText:"Close",draggable:!0,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(e){var i=t(this).css(e).offset().top;0>i&&t(this).css("top",e.top-i)}},resizable:!0,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},sizeRelatedOptions:{buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},resizableRelatedOptions:{maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height},this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.originalTitle=this.element.attr("title"),null==this.options.title&&null!=this.originalTitle&&(this.options.title=this.originalTitle),this.options.disabled&&(this.options.disabled=!1),this._createWrapper(),this.element.show().removeAttr("title").appendTo(this.uiDialog),this._addClass("ui-dialog-content","ui-widget-content"),this._createTitlebar(),this._createButtonPane(),this.options.draggable&&t.fn.draggable&&this._makeDraggable(),this.options.resizable&&t.fn.resizable&&this._makeResizable(),this._isOpen=!1,this._trackFocus()},_init:function(){this.options.autoOpen&&this.open()},_appendTo:function(){var e=this.options.appendTo;return e&&(e.jquery||e.nodeType)?t(e):this.document.find(e||"body").eq(0)},_destroy:function(){var t,e=this.originalPosition;this._untrackInstance(),this._destroyOverlay(),this.element.removeUniqueId().css(this.originalCss).detach(),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),t=e.parent.children().eq(e.index),t.length&&t[0]!==this.element[0]?t.before(this.element):e.parent.append(this.element)},widget:function(){return this.uiDialog +},disable:t.noop,enable:t.noop,close:function(e){var i=this;this._isOpen&&this._trigger("beforeClose",e)!==!1&&(this._isOpen=!1,this._focusedElement=null,this._destroyOverlay(),this._untrackInstance(),this.opener.filter(":focusable").trigger("focus").length||t.ui.safeBlur(t.ui.safeActiveElement(this.document[0])),this._hide(this.uiDialog,this.options.hide,function(){i._trigger("close",e)}))},isOpen:function(){return this._isOpen},moveToTop:function(){this._moveToTop()},_moveToTop:function(e,i){var s=!1,n=this.uiDialog.siblings(".ui-front:visible").map(function(){return+t(this).css("z-index")}).get(),o=Math.max.apply(null,n);return o>=+this.uiDialog.css("z-index")&&(this.uiDialog.css("z-index",o+1),s=!0),s&&!i&&this._trigger("focus",e),s},open:function(){var e=this;return this._isOpen?(this._moveToTop()&&this._focusTabbable(),void 0):(this._isOpen=!0,this.opener=t(t.ui.safeActiveElement(this.document[0])),this._size(),this._position(),this._createOverlay(),this._moveToTop(null,!0),this.overlay&&this.overlay.css("z-index",this.uiDialog.css("z-index")-1),this._show(this.uiDialog,this.options.show,function(){e._focusTabbable(),e._trigger("focus")}),this._makeFocusTarget(),this._trigger("open"),void 0)},_focusTabbable:function(){var t=this._focusedElement;t||(t=this.element.find("[autofocus]")),t.length||(t=this.element.find(":tabbable")),t.length||(t=this.uiDialogButtonPane.find(":tabbable")),t.length||(t=this.uiDialogTitlebarClose.filter(":tabbable")),t.length||(t=this.uiDialog),t.eq(0).trigger("focus")},_keepFocus:function(e){function i(){var e=t.ui.safeActiveElement(this.document[0]),i=this.uiDialog[0]===e||t.contains(this.uiDialog[0],e);i||this._focusTabbable()}e.preventDefault(),i.call(this),this._delay(i)},_createWrapper:function(){this.uiDialog=t("
    ").hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo()),this._addClass(this.uiDialog,"ui-dialog","ui-widget ui-widget-content ui-front"),this._on(this.uiDialog,{keydown:function(e){if(this.options.closeOnEscape&&!e.isDefaultPrevented()&&e.keyCode&&e.keyCode===t.ui.keyCode.ESCAPE)return e.preventDefault(),this.close(e),void 0;if(e.keyCode===t.ui.keyCode.TAB&&!e.isDefaultPrevented()){var i=this.uiDialog.find(":tabbable"),s=i.filter(":first"),n=i.filter(":last");e.target!==n[0]&&e.target!==this.uiDialog[0]||e.shiftKey?e.target!==s[0]&&e.target!==this.uiDialog[0]||!e.shiftKey||(this._delay(function(){n.trigger("focus")}),e.preventDefault()):(this._delay(function(){s.trigger("focus")}),e.preventDefault())}},mousedown:function(t){this._moveToTop(t)&&this._focusTabbable()}}),this.element.find("[aria-describedby]").length||this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")})},_createTitlebar:function(){var e;this.uiDialogTitlebar=t("
    "),this._addClass(this.uiDialogTitlebar,"ui-dialog-titlebar","ui-widget-header ui-helper-clearfix"),this._on(this.uiDialogTitlebar,{mousedown:function(e){t(e.target).closest(".ui-dialog-titlebar-close")||this.uiDialog.trigger("focus")}}),this.uiDialogTitlebarClose=t("").button({label:t("").text(this.options.closeText).html(),icon:"ui-icon-closethick",showLabel:!1}).appendTo(this.uiDialogTitlebar),this._addClass(this.uiDialogTitlebarClose,"ui-dialog-titlebar-close"),this._on(this.uiDialogTitlebarClose,{click:function(t){t.preventDefault(),this.close(t)}}),e=t("").uniqueId().prependTo(this.uiDialogTitlebar),this._addClass(e,"ui-dialog-title"),this._title(e),this.uiDialogTitlebar.prependTo(this.uiDialog),this.uiDialog.attr({"aria-labelledby":e.attr("id")})},_title:function(t){this.options.title?t.text(this.options.title):t.html(" ")},_createButtonPane:function(){this.uiDialogButtonPane=t("
    "),this._addClass(this.uiDialogButtonPane,"ui-dialog-buttonpane","ui-widget-content ui-helper-clearfix"),this.uiButtonSet=t("
    ").appendTo(this.uiDialogButtonPane),this._addClass(this.uiButtonSet,"ui-dialog-buttonset"),this._createButtons()},_createButtons:function(){var e=this,i=this.options.buttons;return this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),t.isEmptyObject(i)||t.isArray(i)&&!i.length?(this._removeClass(this.uiDialog,"ui-dialog-buttons"),void 0):(t.each(i,function(i,s){var n,o;s=t.isFunction(s)?{click:s,text:i}:s,s=t.extend({type:"button"},s),n=s.click,o={icon:s.icon,iconPosition:s.iconPosition,showLabel:s.showLabel,icons:s.icons,text:s.text},delete s.click,delete s.icon,delete s.iconPosition,delete s.showLabel,delete s.icons,"boolean"==typeof s.text&&delete s.text,t("",s).button(o).appendTo(e.uiButtonSet).on("click",function(){n.apply(e.element[0],arguments)})}),this._addClass(this.uiDialog,"ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog),void 0)},_makeDraggable:function(){function e(t){return{position:t.position,offset:t.offset}}var i=this,s=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(s,n){i._addClass(t(this),"ui-dialog-dragging"),i._blockFrames(),i._trigger("dragStart",s,e(n))},drag:function(t,s){i._trigger("drag",t,e(s))},stop:function(n,o){var a=o.offset.left-i.document.scrollLeft(),r=o.offset.top-i.document.scrollTop();s.position={my:"left top",at:"left"+(a>=0?"+":"")+a+" "+"top"+(r>=0?"+":"")+r,of:i.window},i._removeClass(t(this),"ui-dialog-dragging"),i._unblockFrames(),i._trigger("dragStop",n,e(o))}})},_makeResizable:function(){function e(t){return{originalPosition:t.originalPosition,originalSize:t.originalSize,position:t.position,size:t.size}}var i=this,s=this.options,n=s.resizable,o=this.uiDialog.css("position"),a="string"==typeof n?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:s.maxWidth,maxHeight:s.maxHeight,minWidth:s.minWidth,minHeight:this._minHeight(),handles:a,start:function(s,n){i._addClass(t(this),"ui-dialog-resizing"),i._blockFrames(),i._trigger("resizeStart",s,e(n))},resize:function(t,s){i._trigger("resize",t,e(s))},stop:function(n,o){var a=i.uiDialog.offset(),r=a.left-i.document.scrollLeft(),h=a.top-i.document.scrollTop();s.height=i.uiDialog.height(),s.width=i.uiDialog.width(),s.position={my:"left top",at:"left"+(r>=0?"+":"")+r+" "+"top"+(h>=0?"+":"")+h,of:i.window},i._removeClass(t(this),"ui-dialog-resizing"),i._unblockFrames(),i._trigger("resizeStop",n,e(o))}}).css("position",o)},_trackFocus:function(){this._on(this.widget(),{focusin:function(e){this._makeFocusTarget(),this._focusedElement=t(e.target)}})},_makeFocusTarget:function(){this._untrackInstance(),this._trackingInstances().unshift(this)},_untrackInstance:function(){var e=this._trackingInstances(),i=t.inArray(this,e);-1!==i&&e.splice(i,1)},_trackingInstances:function(){var t=this.document.data("ui-dialog-instances");return t||(t=[],this.document.data("ui-dialog-instances",t)),t},_minHeight:function(){var t=this.options;return"auto"===t.height?t.minHeight:Math.min(t.minHeight,t.height)},_position:function(){var t=this.uiDialog.is(":visible");t||this.uiDialog.show(),this.uiDialog.position(this.options.position),t||this.uiDialog.hide()},_setOptions:function(e){var i=this,s=!1,n={};t.each(e,function(t,e){i._setOption(t,e),t in i.sizeRelatedOptions&&(s=!0),t in i.resizableRelatedOptions&&(n[t]=e)}),s&&(this._size(),this._position()),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option",n)},_setOption:function(e,i){var s,n,o=this.uiDialog;"disabled"!==e&&(this._super(e,i),"appendTo"===e&&this.uiDialog.appendTo(this._appendTo()),"buttons"===e&&this._createButtons(),"closeText"===e&&this.uiDialogTitlebarClose.button({label:t("").text(""+this.options.closeText).html()}),"draggable"===e&&(s=o.is(":data(ui-draggable)"),s&&!i&&o.draggable("destroy"),!s&&i&&this._makeDraggable()),"position"===e&&this._position(),"resizable"===e&&(n=o.is(":data(ui-resizable)"),n&&!i&&o.resizable("destroy"),n&&"string"==typeof i&&o.resizable("option","handles",i),n||i===!1||this._makeResizable()),"title"===e&&this._title(this.uiDialogTitlebar.find(".ui-dialog-title")))},_size:function(){var t,e,i,s=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0}),s.minWidth>s.width&&(s.width=s.minWidth),t=this.uiDialog.css({height:"auto",width:s.width}).outerHeight(),e=Math.max(0,s.minHeight-t),i="number"==typeof s.maxHeight?Math.max(0,s.maxHeight-t):"none","auto"===s.height?this.element.css({minHeight:e,maxHeight:i,height:"auto"}):this.element.height(Math.max(0,s.height-t)),this.uiDialog.is(":data(ui-resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var e=t(this);return t("
    ").css({position:"absolute",width:e.outerWidth(),height:e.outerHeight()}).appendTo(e.parent()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_allowInteraction:function(e){return t(e.target).closest(".ui-dialog").length?!0:!!t(e.target).closest(".ui-datepicker").length},_createOverlay:function(){if(this.options.modal){var e=!0;this._delay(function(){e=!1}),this.document.data("ui-dialog-overlays")||this._on(this.document,{focusin:function(t){e||this._allowInteraction(t)||(t.preventDefault(),this._trackingInstances()[0]._focusTabbable())}}),this.overlay=t("
    ").appendTo(this._appendTo()),this._addClass(this.overlay,null,"ui-widget-overlay ui-front"),this._on(this.overlay,{mousedown:"_keepFocus"}),this.document.data("ui-dialog-overlays",(this.document.data("ui-dialog-overlays")||0)+1)}},_destroyOverlay:function(){if(this.options.modal&&this.overlay){var t=this.document.data("ui-dialog-overlays")-1;t?this.document.data("ui-dialog-overlays",t):(this._off(this.document,"focusin"),this.document.removeData("ui-dialog-overlays")),this.overlay.remove(),this.overlay=null}}}),t.uiBackCompat!==!1&&t.widget("ui.dialog",t.ui.dialog,{options:{dialogClass:""},_createWrapper:function(){this._super(),this.uiDialog.addClass(this.options.dialogClass)},_setOption:function(t,e){"dialogClass"===t&&this.uiDialog.removeClass(this.options.dialogClass).addClass(e),this._superApply(arguments)}}),t.ui.dialog,t.widget("ui.droppable",{version:"1.12.1",widgetEventPrefix:"drop",options:{accept:"*",addClasses:!0,greedy:!1,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var e,i=this.options,s=i.accept;this.isover=!1,this.isout=!0,this.accept=t.isFunction(s)?s:function(t){return t.is(s)},this.proportions=function(){return arguments.length?(e=arguments[0],void 0):e?e:e={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight}},this._addToManager(i.scope),i.addClasses&&this._addClass("ui-droppable")},_addToManager:function(e){t.ui.ddmanager.droppables[e]=t.ui.ddmanager.droppables[e]||[],t.ui.ddmanager.droppables[e].push(this)},_splice:function(t){for(var e=0;t.length>e;e++)t[e]===this&&t.splice(e,1)},_destroy:function(){var e=t.ui.ddmanager.droppables[this.options.scope];this._splice(e)},_setOption:function(e,i){if("accept"===e)this.accept=t.isFunction(i)?i:function(t){return t.is(i)};else if("scope"===e){var s=t.ui.ddmanager.droppables[this.options.scope];this._splice(s),this._addToManager(i)}this._super(e,i)},_activate:function(e){var i=t.ui.ddmanager.current;this._addActiveClass(),i&&this._trigger("activate",e,this.ui(i))},_deactivate:function(e){var i=t.ui.ddmanager.current;this._removeActiveClass(),i&&this._trigger("deactivate",e,this.ui(i))},_over:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._addHoverClass(),this._trigger("over",e,this.ui(i)))},_out:function(e){var i=t.ui.ddmanager.current;i&&(i.currentItem||i.element)[0]!==this.element[0]&&this.accept.call(this.element[0],i.currentItem||i.element)&&(this._removeHoverClass(),this._trigger("out",e,this.ui(i)))},_drop:function(e,i){var s=i||t.ui.ddmanager.current,n=!1;return s&&(s.currentItem||s.element)[0]!==this.element[0]?(this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var i=t(this).droppable("instance");return i.options.greedy&&!i.options.disabled&&i.options.scope===s.options.scope&&i.accept.call(i.element[0],s.currentItem||s.element)&&v(s,t.extend(i,{offset:i.element.offset()}),i.options.tolerance,e)?(n=!0,!1):void 0}),n?!1:this.accept.call(this.element[0],s.currentItem||s.element)?(this._removeActiveClass(),this._removeHoverClass(),this._trigger("drop",e,this.ui(s)),this.element):!1):!1},ui:function(t){return{draggable:t.currentItem||t.element,helper:t.helper,position:t.position,offset:t.positionAbs}},_addHoverClass:function(){this._addClass("ui-droppable-hover")},_removeHoverClass:function(){this._removeClass("ui-droppable-hover")},_addActiveClass:function(){this._addClass("ui-droppable-active")},_removeActiveClass:function(){this._removeClass("ui-droppable-active")}});var v=t.ui.intersect=function(){function t(t,e,i){return t>=e&&e+i>t}return function(e,i,s,n){if(!i.offset)return!1;var o=(e.positionAbs||e.position.absolute).left+e.margins.left,a=(e.positionAbs||e.position.absolute).top+e.margins.top,r=o+e.helperProportions.width,h=a+e.helperProportions.height,l=i.offset.left,c=i.offset.top,u=l+i.proportions().width,d=c+i.proportions().height;switch(s){case"fit":return o>=l&&u>=r&&a>=c&&d>=h;case"intersect":return o+e.helperProportions.width/2>l&&u>r-e.helperProportions.width/2&&a+e.helperProportions.height/2>c&&d>h-e.helperProportions.height/2;case"pointer":return t(n.pageY,c,i.proportions().height)&&t(n.pageX,l,i.proportions().width);case"touch":return(a>=c&&d>=a||h>=c&&d>=h||c>a&&h>d)&&(o>=l&&u>=o||r>=l&&u>=r||l>o&&r>u);default:return!1}}}();t.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,i){var s,n,o=t.ui.ddmanager.droppables[e.options.scope]||[],a=i?i.type:null,r=(e.currentItem||e.element).find(":data(ui-droppable)").addBack();t:for(s=0;o.length>s;s++)if(!(o[s].options.disabled||e&&!o[s].accept.call(o[s].element[0],e.currentItem||e.element))){for(n=0;r.length>n;n++)if(r[n]===o[s].element[0]){o[s].proportions().height=0;continue t}o[s].visible="none"!==o[s].element.css("display"),o[s].visible&&("mousedown"===a&&o[s]._activate.call(o[s],i),o[s].offset=o[s].element.offset(),o[s].proportions({width:o[s].element[0].offsetWidth,height:o[s].element[0].offsetHeight}))}},drop:function(e,i){var s=!1;return t.each((t.ui.ddmanager.droppables[e.options.scope]||[]).slice(),function(){this.options&&(!this.options.disabled&&this.visible&&v(e,this,this.options.tolerance,i)&&(s=this._drop.call(this,i)||s),!this.options.disabled&&this.visible&&this.accept.call(this.element[0],e.currentItem||e.element)&&(this.isout=!0,this.isover=!1,this._deactivate.call(this,i)))}),s},dragStart:function(e,i){e.element.parentsUntil("body").on("scroll.droppable",function(){e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)})},drag:function(e,i){e.options.refreshPositions&&t.ui.ddmanager.prepareOffsets(e,i),t.each(t.ui.ddmanager.droppables[e.options.scope]||[],function(){if(!this.options.disabled&&!this.greedyChild&&this.visible){var s,n,o,a=v(e,this,this.options.tolerance,i),r=!a&&this.isover?"isout":a&&!this.isover?"isover":null;r&&(this.options.greedy&&(n=this.options.scope,o=this.element.parents(":data(ui-droppable)").filter(function(){return t(this).droppable("instance").options.scope===n}),o.length&&(s=t(o[0]).droppable("instance"),s.greedyChild="isover"===r)),s&&"isover"===r&&(s.isover=!1,s.isout=!0,s._out.call(s,i)),this[r]=!0,this["isout"===r?"isover":"isout"]=!1,this["isover"===r?"_over":"_out"].call(this,i),s&&"isout"===r&&(s.isout=!1,s.isover=!0,s._over.call(s,i)))}})},dragStop:function(e,i){e.element.parentsUntil("body").off("scroll.droppable"),e.options.refreshPositions||t.ui.ddmanager.prepareOffsets(e,i)}},t.uiBackCompat!==!1&&t.widget("ui.droppable",t.ui.droppable,{options:{hoverClass:!1,activeClass:!1},_addActiveClass:function(){this._super(),this.options.activeClass&&this.element.addClass(this.options.activeClass)},_removeActiveClass:function(){this._super(),this.options.activeClass&&this.element.removeClass(this.options.activeClass)},_addHoverClass:function(){this._super(),this.options.hoverClass&&this.element.addClass(this.options.hoverClass)},_removeHoverClass:function(){this._super(),this.options.hoverClass&&this.element.removeClass(this.options.hoverClass)}}),t.ui.droppable,t.widget("ui.progressbar",{version:"1.12.1",options:{classes:{"ui-progressbar":"ui-corner-all","ui-progressbar-value":"ui-corner-left","ui-progressbar-complete":"ui-corner-right"},max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue(),this.element.attr({role:"progressbar","aria-valuemin":this.min}),this._addClass("ui-progressbar","ui-widget ui-widget-content"),this.valueDiv=t("
    ").appendTo(this.element),this._addClass(this.valueDiv,"ui-progressbar-value","ui-widget-header"),this._refreshValue()},_destroy:function(){this.element.removeAttr("role aria-valuemin aria-valuemax aria-valuenow"),this.valueDiv.remove()},value:function(t){return void 0===t?this.options.value:(this.options.value=this._constrainedValue(t),this._refreshValue(),void 0)},_constrainedValue:function(t){return void 0===t&&(t=this.options.value),this.indeterminate=t===!1,"number"!=typeof t&&(t=0),this.indeterminate?!1:Math.min(this.options.max,Math.max(this.min,t))},_setOptions:function(t){var e=t.value;delete t.value,this._super(t),this.options.value=this._constrainedValue(e),this._refreshValue()},_setOption:function(t,e){"max"===t&&(e=Math.max(this.min,e)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t)},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min)},_refreshValue:function(){var e=this.options.value,i=this._percentage();this.valueDiv.toggle(this.indeterminate||e>this.min).width(i.toFixed(0)+"%"),this._toggleClass(this.valueDiv,"ui-progressbar-complete",null,e===this.options.max)._toggleClass("ui-progressbar-indeterminate",null,this.indeterminate),this.indeterminate?(this.element.removeAttr("aria-valuenow"),this.overlayDiv||(this.overlayDiv=t("
    ").appendTo(this.valueDiv),this._addClass(this.overlayDiv,"ui-progressbar-overlay"))):(this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":e}),this.overlayDiv&&(this.overlayDiv.remove(),this.overlayDiv=null)),this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),e===this.options.max&&this._trigger("complete")}}),t.widget("ui.selectable",t.ui.mouse,{version:"1.12.1",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var e=this;this._addClass("ui-selectable"),this.dragged=!1,this.refresh=function(){e.elementPos=t(e.element[0]).offset(),e.selectees=t(e.options.filter,e.element[0]),e._addClass(e.selectees,"ui-selectee"),e.selectees.each(function(){var i=t(this),s=i.offset(),n={left:s.left-e.elementPos.left,top:s.top-e.elementPos.top};t.data(this,"selectable-item",{element:this,$element:i,left:n.left,top:n.top,right:n.left+i.outerWidth(),bottom:n.top+i.outerHeight(),startselected:!1,selected:i.hasClass("ui-selected"),selecting:i.hasClass("ui-selecting"),unselecting:i.hasClass("ui-unselecting")})})},this.refresh(),this._mouseInit(),this.helper=t("
    "),this._addClass(this.helper,"ui-selectable-helper")},_destroy:function(){this.selectees.removeData("selectable-item"),this._mouseDestroy()},_mouseStart:function(e){var i=this,s=this.options;this.opos=[e.pageX,e.pageY],this.elementPos=t(this.element[0]).offset(),this.options.disabled||(this.selectees=t(s.filter,this.element[0]),this._trigger("start",e),t(s.appendTo).append(this.helper),this.helper.css({left:e.pageX,top:e.pageY,width:0,height:0}),s.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var s=t.data(this,"selectable-item");s.startselected=!0,e.metaKey||e.ctrlKey||(i._removeClass(s.$element,"ui-selected"),s.selected=!1,i._addClass(s.$element,"ui-unselecting"),s.unselecting=!0,i._trigger("unselecting",e,{unselecting:s.element}))}),t(e.target).parents().addBack().each(function(){var s,n=t.data(this,"selectable-item");return n?(s=!e.metaKey&&!e.ctrlKey||!n.$element.hasClass("ui-selected"),i._removeClass(n.$element,s?"ui-unselecting":"ui-selected")._addClass(n.$element,s?"ui-selecting":"ui-unselecting"),n.unselecting=!s,n.selecting=s,n.selected=s,s?i._trigger("selecting",e,{selecting:n.element}):i._trigger("unselecting",e,{unselecting:n.element}),!1):void 0}))},_mouseDrag:function(e){if(this.dragged=!0,!this.options.disabled){var i,s=this,n=this.options,o=this.opos[0],a=this.opos[1],r=e.pageX,h=e.pageY;return o>r&&(i=r,r=o,o=i),a>h&&(i=h,h=a,a=i),this.helper.css({left:o,top:a,width:r-o,height:h-a}),this.selectees.each(function(){var i=t.data(this,"selectable-item"),l=!1,c={};i&&i.element!==s.element[0]&&(c.left=i.left+s.elementPos.left,c.right=i.right+s.elementPos.left,c.top=i.top+s.elementPos.top,c.bottom=i.bottom+s.elementPos.top,"touch"===n.tolerance?l=!(c.left>r||o>c.right||c.top>h||a>c.bottom):"fit"===n.tolerance&&(l=c.left>o&&r>c.right&&c.top>a&&h>c.bottom),l?(i.selected&&(s._removeClass(i.$element,"ui-selected"),i.selected=!1),i.unselecting&&(s._removeClass(i.$element,"ui-unselecting"),i.unselecting=!1),i.selecting||(s._addClass(i.$element,"ui-selecting"),i.selecting=!0,s._trigger("selecting",e,{selecting:i.element}))):(i.selecting&&((e.metaKey||e.ctrlKey)&&i.startselected?(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,s._addClass(i.$element,"ui-selected"),i.selected=!0):(s._removeClass(i.$element,"ui-selecting"),i.selecting=!1,i.startselected&&(s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0),s._trigger("unselecting",e,{unselecting:i.element}))),i.selected&&(e.metaKey||e.ctrlKey||i.startselected||(s._removeClass(i.$element,"ui-selected"),i.selected=!1,s._addClass(i.$element,"ui-unselecting"),i.unselecting=!0,s._trigger("unselecting",e,{unselecting:i.element})))))}),!1}},_mouseStop:function(e){var i=this;return this.dragged=!1,t(".ui-unselecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-unselecting"),s.unselecting=!1,s.startselected=!1,i._trigger("unselected",e,{unselected:s.element})}),t(".ui-selecting",this.element[0]).each(function(){var s=t.data(this,"selectable-item");i._removeClass(s.$element,"ui-selecting")._addClass(s.$element,"ui-selected"),s.selecting=!1,s.selected=!0,s.startselected=!0,i._trigger("selected",e,{selected:s.element})}),this._trigger("stop",e),this.helper.remove(),!1}}),t.widget("ui.selectmenu",[t.ui.formResetMixin,{version:"1.12.1",defaultElement:"",widgetEventPrefix:"spin",options:{classes:{"ui-spinner":"ui-corner-all","ui-spinner-down":"ui-corner-br","ui-spinner-up":"ui-corner-tr"},culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),""!==this.value()&&this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var e=this._super(),i=this.element;return t.each(["min","max","step"],function(t,s){var n=i.attr(s);null!=n&&n.length&&(e[s]=n)}),e},_events:{keydown:function(t){this._start(t)&&this._keydown(t)&&t.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(t){return this.cancelBlur?(delete this.cancelBlur,void 0):(this._stop(),this._refresh(),this.previous!==this.element.val()&&this._trigger("change",t),void 0)},mousewheel:function(t,e){if(e){if(!this.spinning&&!this._start(t))return!1;this._spin((e>0?1:-1)*this.options.step,t),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(t)},100),t.preventDefault()}},"mousedown .ui-spinner-button":function(e){function i(){var e=this.element[0]===t.ui.safeActiveElement(this.document[0]);e||(this.element.trigger("focus"),this.previous=s,this._delay(function(){this.previous=s}))}var s;s=this.element[0]===t.ui.safeActiveElement(this.document[0])?this.previous:this.element.val(),e.preventDefault(),i.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,i.call(this)}),this._start(e)!==!1&&this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(e){return t(e.currentTarget).hasClass("ui-state-active")?this._start(e)===!1?!1:(this._repeat(null,t(e.currentTarget).hasClass("ui-spinner-up")?1:-1,e),void 0):void 0},"mouseleave .ui-spinner-button":"_stop"},_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap("").parent().append("")},_draw:function(){this._enhance(),this._addClass(this.uiSpinner,"ui-spinner","ui-widget ui-widget-content"),this._addClass("ui-spinner-input"),this.element.attr("role","spinbutton"),this.buttons=this.uiSpinner.children("a").attr("tabIndex",-1).attr("aria-hidden",!0).button({classes:{"ui-button":""}}),this._removeClass(this.buttons,"ui-corner-all"),this._addClass(this.buttons.first(),"ui-spinner-button ui-spinner-up"),this._addClass(this.buttons.last(),"ui-spinner-button ui-spinner-down"),this.buttons.first().button({icon:this.options.icons.up,showLabel:!1}),this.buttons.last().button({icon:this.options.icons.down,showLabel:!1}),this.buttons.height()>Math.ceil(.5*this.uiSpinner.height())&&this.uiSpinner.height()>0&&this.uiSpinner.height(this.uiSpinner.height())},_keydown:function(e){var i=this.options,s=t.ui.keyCode;switch(e.keyCode){case s.UP:return this._repeat(null,1,e),!0;case s.DOWN:return this._repeat(null,-1,e),!0;case s.PAGE_UP:return this._repeat(null,i.page,e),!0;case s.PAGE_DOWN:return this._repeat(null,-i.page,e),!0}return!1},_start:function(t){return this.spinning||this._trigger("start",t)!==!1?(this.counter||(this.counter=1),this.spinning=!0,!0):!1},_repeat:function(t,e,i){t=t||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,e,i)},t),this._spin(e*this.options.step,i)},_spin:function(t,e){var i=this.value()||0;this.counter||(this.counter=1),i=this._adjustValue(i+t*this._increment(this.counter)),this.spinning&&this._trigger("spin",e,{value:i})===!1||(this._value(i),this.counter++)},_increment:function(e){var i=this.options.incremental;return i?t.isFunction(i)?i(e):Math.floor(e*e*e/5e4-e*e/500+17*e/200+1):1},_precision:function(){var t=this._precisionOf(this.options.step);return null!==this.options.min&&(t=Math.max(t,this._precisionOf(this.options.min))),t},_precisionOf:function(t){var e=""+t,i=e.indexOf(".");return-1===i?0:e.length-i-1},_adjustValue:function(t){var e,i,s=this.options;return e=null!==s.min?s.min:0,i=t-e,i=Math.round(i/s.step)*s.step,t=e+i,t=parseFloat(t.toFixed(this._precision())),null!==s.max&&t>s.max?s.max:null!==s.min&&s.min>t?s.min:t},_stop:function(t){this.spinning&&(clearTimeout(this.timer),clearTimeout(this.mousewheelTimer),this.counter=0,this.spinning=!1,this._trigger("stop",t))},_setOption:function(t,e){var i,s,n;return"culture"===t||"numberFormat"===t?(i=this._parse(this.element.val()),this.options[t]=e,this.element.val(this._format(i)),void 0):(("max"===t||"min"===t||"step"===t)&&"string"==typeof e&&(e=this._parse(e)),"icons"===t&&(s=this.buttons.first().find(".ui-icon"),this._removeClass(s,null,this.options.icons.up),this._addClass(s,null,e.up),n=this.buttons.last().find(".ui-icon"),this._removeClass(n,null,this.options.icons.down),this._addClass(n,null,e.down)),this._super(t,e),void 0)},_setOptionDisabled:function(t){this._super(t),this._toggleClass(this.uiSpinner,null,"ui-state-disabled",!!t),this.element.prop("disabled",!!t),this.buttons.button(t?"disable":"enable")},_setOptions:r(function(t){this._super(t)}),_parse:function(t){return"string"==typeof t&&""!==t&&(t=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(t,10,this.options.culture):+t),""===t||isNaN(t)?null:t},_format:function(t){return""===t?"":window.Globalize&&this.options.numberFormat?Globalize.format(t,this.options.numberFormat,this.options.culture):t},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())})},isValid:function(){var t=this.value();return null===t?!1:t===this._adjustValue(t)},_value:function(t,e){var i;""!==t&&(i=this._parse(t),null!==i&&(e||(i=this._adjustValue(i)),t=this._format(i))),this.element.val(t),this._refresh()},_destroy:function(){this.element.prop("disabled",!1).removeAttr("autocomplete role aria-valuemin aria-valuemax aria-valuenow"),this.uiSpinner.replaceWith(this.element)},stepUp:r(function(t){this._stepUp(t)}),_stepUp:function(t){this._start()&&(this._spin((t||1)*this.options.step),this._stop())},stepDown:r(function(t){this._stepDown(t)}),_stepDown:function(t){this._start()&&(this._spin((t||1)*-this.options.step),this._stop())},pageUp:r(function(t){this._stepUp((t||1)*this.options.page)}),pageDown:r(function(t){this._stepDown((t||1)*this.options.page)}),value:function(t){return arguments.length?(r(this._value).call(this,t),void 0):this._parse(this.element.val())},widget:function(){return this.uiSpinner}}),t.uiBackCompat!==!1&&t.widget("ui.spinner",t.ui.spinner,{_enhance:function(){this.uiSpinner=this.element.attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml())},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""}}),t.ui.spinner,t.widget("ui.tabs",{version:"1.12.1",delay:300,options:{active:null,classes:{"ui-tabs":"ui-corner-all","ui-tabs-nav":"ui-corner-all","ui-tabs-panel":"ui-corner-bottom","ui-tabs-tab":"ui-corner-top"},collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_isLocal:function(){var t=/#.*$/;return function(e){var i,s;i=e.href.replace(t,""),s=location.href.replace(t,"");try{i=decodeURIComponent(i)}catch(n){}try{s=decodeURIComponent(s)}catch(n){}return e.hash.length>1&&i===s}}(),_create:function(){var e=this,i=this.options;this.running=!1,this._addClass("ui-tabs","ui-widget ui-widget-content"),this._toggleClass("ui-tabs-collapsible",null,i.collapsible),this._processTabs(),i.active=this._initialActive(),t.isArray(i.disabled)&&(i.disabled=t.unique(i.disabled.concat(t.map(this.tabs.filter(".ui-state-disabled"),function(t){return e.tabs.index(t)}))).sort()),this.active=this.options.active!==!1&&this.anchors.length?this._findActive(i.active):t(),this._refresh(),this.active.length&&this.load(i.active)},_initialActive:function(){var e=this.options.active,i=this.options.collapsible,s=location.hash.substring(1);return null===e&&(s&&this.tabs.each(function(i,n){return t(n).attr("aria-controls")===s?(e=i,!1):void 0}),null===e&&(e=this.tabs.index(this.tabs.filter(".ui-tabs-active"))),(null===e||-1===e)&&(e=this.tabs.length?0:!1)),e!==!1&&(e=this.tabs.index(this.tabs.eq(e)),-1===e&&(e=i?!1:0)),!i&&e===!1&&this.anchors.length&&(e=0),e},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):t()}},_tabKeydown:function(e){var i=t(t.ui.safeActiveElement(this.document[0])).closest("li"),s=this.tabs.index(i),n=!0;if(!this._handlePageNav(e)){switch(e.keyCode){case t.ui.keyCode.RIGHT:case t.ui.keyCode.DOWN:s++;break;case t.ui.keyCode.UP:case t.ui.keyCode.LEFT:n=!1,s--;break;case t.ui.keyCode.END:s=this.anchors.length-1;break;case t.ui.keyCode.HOME:s=0;break;case t.ui.keyCode.SPACE:return e.preventDefault(),clearTimeout(this.activating),this._activate(s),void 0;case t.ui.keyCode.ENTER:return e.preventDefault(),clearTimeout(this.activating),this._activate(s===this.options.active?!1:s),void 0;default:return}e.preventDefault(),clearTimeout(this.activating),s=this._focusNextTab(s,n),e.ctrlKey||e.metaKey||(i.attr("aria-selected","false"),this.tabs.eq(s).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",s)},this.delay))}},_panelKeydown:function(e){this._handlePageNav(e)||e.ctrlKey&&e.keyCode===t.ui.keyCode.UP&&(e.preventDefault(),this.active.trigger("focus"))},_handlePageNav:function(e){return e.altKey&&e.keyCode===t.ui.keyCode.PAGE_UP?(this._activate(this._focusNextTab(this.options.active-1,!1)),!0):e.altKey&&e.keyCode===t.ui.keyCode.PAGE_DOWN?(this._activate(this._focusNextTab(this.options.active+1,!0)),!0):void 0},_findNextTab:function(e,i){function s(){return e>n&&(e=0),0>e&&(e=n),e}for(var n=this.tabs.length-1;-1!==t.inArray(s(),this.options.disabled);)e=i?e+1:e-1;return e},_focusNextTab:function(t,e){return t=this._findNextTab(t,e),this.tabs.eq(t).trigger("focus"),t},_setOption:function(t,e){return"active"===t?(this._activate(e),void 0):(this._super(t,e),"collapsible"===t&&(this._toggleClass("ui-tabs-collapsible",null,e),e||this.options.active!==!1||this._activate(0)),"event"===t&&this._setupEvents(e),"heightStyle"===t&&this._setupHeightStyle(e),void 0)},_sanitizeSelector:function(t){return t?t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var e=this.options,i=this.tablist.children(":has(a[href])");e.disabled=t.map(i.filter(".ui-state-disabled"),function(t){return i.index(t)}),this._processTabs(),e.active!==!1&&this.anchors.length?this.active.length&&!t.contains(this.tablist[0],this.active[0])?this.tabs.length===e.disabled.length?(e.active=!1,this.active=t()):this._activate(this._findNextTab(Math.max(0,e.active-1),!1)):e.active=this.tabs.index(this.active):(e.active=!1,this.active=t()),this._refresh()},_refresh:function(){this._setOptionDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-hidden":"true"}),this.active.length?(this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}),this._addClass(this.active,"ui-tabs-active","ui-state-active"),this._getPanelForTab(this.active).show().attr({"aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var e=this,i=this.tabs,s=this.anchors,n=this.panels;this.tablist=this._getList().attr("role","tablist"),this._addClass(this.tablist,"ui-tabs-nav","ui-helper-reset ui-helper-clearfix ui-widget-header"),this.tablist.on("mousedown"+this.eventNamespace,"> li",function(e){t(this).is(".ui-state-disabled")&&e.preventDefault()}).on("focus"+this.eventNamespace,".ui-tabs-anchor",function(){t(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this.tabs=this.tablist.find("> li:has(a[href])").attr({role:"tab",tabIndex:-1}),this._addClass(this.tabs,"ui-tabs-tab","ui-state-default"),this.anchors=this.tabs.map(function(){return t("a",this)[0]}).attr({role:"presentation",tabIndex:-1}),this._addClass(this.anchors,"ui-tabs-anchor"),this.panels=t(),this.anchors.each(function(i,s){var n,o,a,r=t(s).uniqueId().attr("id"),h=t(s).closest("li"),l=h.attr("aria-controls");e._isLocal(s)?(n=s.hash,a=n.substring(1),o=e.element.find(e._sanitizeSelector(n))):(a=h.attr("aria-controls")||t({}).uniqueId()[0].id,n="#"+a,o=e.element.find(n),o.length||(o=e._createPanel(a),o.insertAfter(e.panels[i-1]||e.tablist)),o.attr("aria-live","polite")),o.length&&(e.panels=e.panels.add(o)),l&&h.data("ui-tabs-aria-controls",l),h.attr({"aria-controls":a,"aria-labelledby":r}),o.attr("aria-labelledby",r)}),this.panels.attr("role","tabpanel"),this._addClass(this.panels,"ui-tabs-panel","ui-widget-content"),i&&(this._off(i.not(this.tabs)),this._off(s.not(this.anchors)),this._off(n.not(this.panels)))},_getList:function(){return this.tablist||this.element.find("ol, ul").eq(0)},_createPanel:function(e){return t("
    ").attr("id",e).data("ui-tabs-destroy",!0)},_setOptionDisabled:function(e){var i,s,n;for(t.isArray(e)&&(e.length?e.length===this.anchors.length&&(e=!0):e=!1),n=0;s=this.tabs[n];n++)i=t(s),e===!0||-1!==t.inArray(n,e)?(i.attr("aria-disabled","true"),this._addClass(i,null,"ui-state-disabled")):(i.removeAttr("aria-disabled"),this._removeClass(i,null,"ui-state-disabled"));this.options.disabled=e,this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,e===!0)},_setupEvents:function(e){var i={};e&&t.each(e.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(!0,this.anchors,{click:function(t){t.preventDefault()}}),this._on(this.anchors,i),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(e){var i,s=this.element.parent();"fill"===e?(i=s.height(),i-=this.element.outerHeight()-this.element.height(),this.element.siblings(":visible").each(function(){var e=t(this),s=e.css("position");"absolute"!==s&&"fixed"!==s&&(i-=e.outerHeight(!0))}),this.element.children().not(this.panels).each(function(){i-=t(this).outerHeight(!0)}),this.panels.each(function(){t(this).height(Math.max(0,i-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.panels.each(function(){i=Math.max(i,t(this).height("").height())}).height(i))},_eventHandler:function(e){var i=this.options,s=this.active,n=t(e.currentTarget),o=n.closest("li"),a=o[0]===s[0],r=a&&i.collapsible,h=r?t():this._getPanelForTab(o),l=s.length?this._getPanelForTab(s):t(),c={oldTab:s,oldPanel:l,newTab:r?t():o,newPanel:h};e.preventDefault(),o.hasClass("ui-state-disabled")||o.hasClass("ui-tabs-loading")||this.running||a&&!i.collapsible||this._trigger("beforeActivate",e,c)===!1||(i.active=r?!1:this.tabs.index(o),this.active=a?t():o,this.xhr&&this.xhr.abort(),l.length||h.length||t.error("jQuery UI Tabs: Mismatching fragment identifier."),h.length&&this.load(this.tabs.index(o),e),this._toggle(e,c))},_toggle:function(e,i){function s(){o.running=!1,o._trigger("activate",e,i)}function n(){o._addClass(i.newTab.closest("li"),"ui-tabs-active","ui-state-active"),a.length&&o.options.show?o._show(a,o.options.show,s):(a.show(),s())}var o=this,a=i.newPanel,r=i.oldPanel;this.running=!0,r.length&&this.options.hide?this._hide(r,this.options.hide,function(){o._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),n()}):(this._removeClass(i.oldTab.closest("li"),"ui-tabs-active","ui-state-active"),r.hide(),n()),r.attr("aria-hidden","true"),i.oldTab.attr({"aria-selected":"false","aria-expanded":"false"}),a.length&&r.length?i.oldTab.attr("tabIndex",-1):a.length&&this.tabs.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),a.attr("aria-hidden","false"),i.newTab.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_activate:function(e){var i,s=this._findActive(e);s[0]!==this.active[0]&&(s.length||(s=this.active),i=s.find(".ui-tabs-anchor")[0],this._eventHandler({target:i,currentTarget:i,preventDefault:t.noop}))},_findActive:function(e){return e===!1?t():this.tabs.eq(e)},_getIndex:function(e){return"string"==typeof e&&(e=this.anchors.index(this.anchors.filter("[href$='"+t.ui.escapeSelector(e)+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.tablist.removeAttr("role").off(this.eventNamespace),this.anchors.removeAttr("role tabIndex").removeUniqueId(),this.tabs.add(this.panels).each(function(){t.data(this,"ui-tabs-destroy")?t(this).remove():t(this).removeAttr("role tabIndex aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded")}),this.tabs.each(function(){var e=t(this),i=e.data("ui-tabs-aria-controls");i?e.attr("aria-controls",i).removeData("ui-tabs-aria-controls"):e.removeAttr("aria-controls")}),this.panels.show(),"content"!==this.options.heightStyle&&this.panels.css("height","")},enable:function(e){var i=this.options.disabled;i!==!1&&(void 0===e?i=!1:(e=this._getIndex(e),i=t.isArray(i)?t.map(i,function(t){return t!==e?t:null}):t.map(this.tabs,function(t,i){return i!==e?i:null})),this._setOptionDisabled(i))},disable:function(e){var i=this.options.disabled;if(i!==!0){if(void 0===e)i=!0;else{if(e=this._getIndex(e),-1!==t.inArray(e,i))return;i=t.isArray(i)?t.merge([e],i).sort():[e]}this._setOptionDisabled(i)}},load:function(e,i){e=this._getIndex(e);var s=this,n=this.tabs.eq(e),o=n.find(".ui-tabs-anchor"),a=this._getPanelForTab(n),r={tab:n,panel:a},h=function(t,e){"abort"===e&&s.panels.stop(!1,!0),s._removeClass(n,"ui-tabs-loading"),a.removeAttr("aria-busy"),t===s.xhr&&delete s.xhr};this._isLocal(o[0])||(this.xhr=t.ajax(this._ajaxSettings(o,i,r)),this.xhr&&"canceled"!==this.xhr.statusText&&(this._addClass(n,"ui-tabs-loading"),a.attr("aria-busy","true"),this.xhr.done(function(t,e,n){setTimeout(function(){a.html(t),s._trigger("load",i,r),h(n,e)},1)}).fail(function(t,e){setTimeout(function(){h(t,e)},1)})))},_ajaxSettings:function(e,i,s){var n=this;return{url:e.attr("href").replace(/#.*$/,""),beforeSend:function(e,o){return n._trigger("beforeLoad",i,t.extend({jqXHR:e,ajaxSettings:o},s))}}},_getPanelForTab:function(e){var i=t(e).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+i))}}),t.uiBackCompat!==!1&&t.widget("ui.tabs",t.ui.tabs,{_processTabs:function(){this._superApply(arguments),this._addClass(this.tabs,"ui-tab")}}),t.ui.tabs,t.widget("ui.tooltip",{version:"1.12.1",options:{classes:{"ui-tooltip":"ui-corner-all ui-widget-shadow"},content:function(){var e=t(this).attr("title")||"";return t("").text(e).html()},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,track:!1,close:null,open:null},_addDescribedBy:function(e,i){var s=(e.attr("aria-describedby")||"").split(/\s+/);s.push(i),e.data("ui-tooltip-id",i).attr("aria-describedby",t.trim(s.join(" ")))},_removeDescribedBy:function(e){var i=e.data("ui-tooltip-id"),s=(e.attr("aria-describedby")||"").split(/\s+/),n=t.inArray(i,s);-1!==n&&s.splice(n,1),e.removeData("ui-tooltip-id"),s=t.trim(s.join(" ")),s?e.attr("aria-describedby",s):e.removeAttr("aria-describedby")},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.liveRegion=t("
    ").attr({role:"log","aria-live":"assertive","aria-relevant":"additions"}).appendTo(this.document[0].body),this._addClass(this.liveRegion,null,"ui-helper-hidden-accessible"),this.disabledTitles=t([])},_setOption:function(e,i){var s=this;this._super(e,i),"content"===e&&t.each(this.tooltips,function(t,e){s._updateContent(e.element)})},_setOptionDisabled:function(t){this[t?"_disable":"_enable"]()},_disable:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur");n.target=n.currentTarget=s.element[0],e.close(n,!0)}),this.disabledTitles=this.disabledTitles.add(this.element.find(this.options.items).addBack().filter(function(){var e=t(this);return e.is("[title]")?e.data("ui-tooltip-title",e.attr("title")).removeAttr("title"):void 0}))},_enable:function(){this.disabledTitles.each(function(){var e=t(this);e.data("ui-tooltip-title")&&e.attr("title",e.data("ui-tooltip-title"))}),this.disabledTitles=t([])},open:function(e){var i=this,s=t(e?e.target:this.element).closest(this.options.items);s.length&&!s.data("ui-tooltip-id")&&(s.attr("title")&&s.data("ui-tooltip-title",s.attr("title")),s.data("ui-tooltip-open",!0),e&&"mouseover"===e.type&&s.parents().each(function(){var e,s=t(this);s.data("ui-tooltip-open")&&(e=t.Event("blur"),e.target=e.currentTarget=this,i.close(e,!0)),s.attr("title")&&(s.uniqueId(),i.parents[this.id]={element:this,title:s.attr("title")},s.attr("title",""))}),this._registerCloseHandlers(e,s),this._updateContent(s,e))},_updateContent:function(t,e){var i,s=this.options.content,n=this,o=e?e.type:null;return"string"==typeof s||s.nodeType||s.jquery?this._open(e,t,s):(i=s.call(t[0],function(i){n._delay(function(){t.data("ui-tooltip-open")&&(e&&(e.type=o),this._open(e,t,i))})}),i&&this._open(e,t,i),void 0)},_open:function(e,i,s){function n(t){l.of=t,a.is(":hidden")||a.position(l)}var o,a,r,h,l=t.extend({},this.options.position);if(s){if(o=this._find(i))return o.tooltip.find(".ui-tooltip-content").html(s),void 0;i.is("[title]")&&(e&&"mouseover"===e.type?i.attr("title",""):i.removeAttr("title")),o=this._tooltip(i),a=o.tooltip,this._addDescribedBy(i,a.attr("id")),a.find(".ui-tooltip-content").html(s),this.liveRegion.children().hide(),h=t("
    ").html(a.find(".ui-tooltip-content").html()),h.removeAttr("name").find("[name]").removeAttr("name"),h.removeAttr("id").find("[id]").removeAttr("id"),h.appendTo(this.liveRegion),this.options.track&&e&&/^mouse/.test(e.type)?(this._on(this.document,{mousemove:n}),n(e)):a.position(t.extend({of:i},this.options.position)),a.hide(),this._show(a,this.options.show),this.options.track&&this.options.show&&this.options.show.delay&&(r=this.delayedShow=setInterval(function(){a.is(":visible")&&(n(l.of),clearInterval(r))},t.fx.interval)),this._trigger("open",e,{tooltip:a})}},_registerCloseHandlers:function(e,i){var s={keyup:function(e){if(e.keyCode===t.ui.keyCode.ESCAPE){var s=t.Event(e);s.currentTarget=i[0],this.close(s,!0)}}};i[0]!==this.element[0]&&(s.remove=function(){this._removeTooltip(this._find(i).tooltip)}),e&&"mouseover"!==e.type||(s.mouseleave="close"),e&&"focusin"!==e.type||(s.focusout="close"),this._on(!0,i,s)},close:function(e){var i,s=this,n=t(e?e.currentTarget:this.element),o=this._find(n);return o?(i=o.tooltip,o.closing||(clearInterval(this.delayedShow),n.data("ui-tooltip-title")&&!n.attr("title")&&n.attr("title",n.data("ui-tooltip-title")),this._removeDescribedBy(n),o.hiding=!0,i.stop(!0),this._hide(i,this.options.hide,function(){s._removeTooltip(t(this))}),n.removeData("ui-tooltip-open"),this._off(n,"mouseleave focusout keyup"),n[0]!==this.element[0]&&this._off(n,"remove"),this._off(this.document,"mousemove"),e&&"mouseleave"===e.type&&t.each(this.parents,function(e,i){t(i.element).attr("title",i.title),delete s.parents[e]}),o.closing=!0,this._trigger("close",e,{tooltip:i}),o.hiding||(o.closing=!1)),void 0):(n.removeData("ui-tooltip-open"),void 0)},_tooltip:function(e){var i=t("
    ").attr("role","tooltip"),s=t("
    ").appendTo(i),n=i.uniqueId().attr("id");return this._addClass(s,"ui-tooltip-content"),this._addClass(i,"ui-tooltip","ui-widget ui-widget-content"),i.appendTo(this._appendTo(e)),this.tooltips[n]={element:e,tooltip:i}},_find:function(t){var e=t.data("ui-tooltip-id");return e?this.tooltips[e]:null},_removeTooltip:function(t){t.remove(),delete this.tooltips[t.attr("id")]},_appendTo:function(t){var e=t.closest(".ui-front, dialog");return e.length||(e=this.document[0].body),e},_destroy:function(){var e=this;t.each(this.tooltips,function(i,s){var n=t.Event("blur"),o=s.element;n.target=n.currentTarget=o[0],e.close(n,!0),t("#"+i).remove(),o.data("ui-tooltip-title")&&(o.attr("title")||o.attr("title",o.data("ui-tooltip-title")),o.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}}),t.uiBackCompat!==!1&&t.widget("ui.tooltip",t.ui.tooltip,{options:{tooltipClass:null},_tooltip:function(){var t=this._superApply(arguments);return this.options.tooltipClass&&t.tooltip.addClass(this.options.tooltipClass),t}}),t.ui.tooltip}); \ No newline at end of file diff --git a/js/jquery.min.js b/js/jquery.min.js index 4d9b3a2..4b98bac 100644 --- a/js/jquery.min.js +++ b/js/jquery.min.js @@ -1,2 +1,2 @@ -/*! jQuery v3.3.1 | (c) JS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){"use strict";var n=[],r=e.document,i=Object.getPrototypeOf,o=n.slice,a=n.concat,s=n.push,u=n.indexOf,l={},c=l.toString,f=l.hasOwnProperty,p=f.toString,d=p.call(Object),h={},g=function e(t){return"function"==typeof t&&"number"!=typeof t.nodeType},y=function e(t){return null!=t&&t===t.window},v={type:!0,src:!0,noModule:!0};function m(e,t,n){var i,o=(t=t||r).createElement("script");if(o.text=e,n)for(i in v)n[i]&&(o[i]=n[i]);t.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[c.call(e)]||"object":typeof e}var b="3.3.1",w=function(e,t){return new w.fn.init(e,t)},T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;w.fn=w.prototype={jquery:"3.3.1",constructor:w,length:0,toArray:function(){return o.call(this)},get:function(e){return null==e?o.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=w.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return w.each(this,e)},map:function(e){return this.pushStack(w.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(o.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||oe.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" - - - - + + + + + Consultar horario | + <?= $user->facultad['facultad'] ?? 'General' ?> + + + + + + + + + + + + " ?> +
    +
    + + + + + + + + + + + + + + + + + where('momento::DATE = ' . (isset($_GET['fecha']) ? "'{$_GET['fecha']}'" : 'CURRENT_DATE')) + ->orderBy('momento', 'desc') + ->get('log_registro'); + + foreach ($registros as $log) { + ?> + + + + + + + + + + + + + + + +
    FechaHoraClaveProfesorHorarioIPNavegadorInformaci贸nDetalleHorario web
    + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/logs/postgres.php b/logs/postgres.php index aa840cd..0140477 100644 --- a/logs/postgres.php +++ b/logs/postgres.php @@ -1,72 +1,72 @@ - - - - - - - - Archivos de log Postgres - - - - - -
    -
    - - - -
    - - " . shell_exec("sh ../pgsql-log/get-logs.sh 2>&1") . ""; - - if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['logDay'])) { - $fileName = "../pgsql-log/postgresql-{$_POST['logDay']}.log"; - echo "

    Log file for {$_POST['logDay']}:

    "; - echo "

    File path: $fileName

    "; - - // execute a command in the shell: sudo sh get-logs.sh - - - if (file_exists($fileName)) { - $fileContents = file_get_contents($fileName); - echo "
    " . htmlspecialchars($fileContents) . "
    "; - } else { - echo "Log file for " . $_POST['logDay'] . " does not exist."; - } - } - ?> -
    - - - - - + + + + + + + + Archivos de log Postgres + + + + + +
    +
    + + + +
    + + " . shell_exec("sh ../pgsql-log/get-logs.sh 2>&1") . ""; + + if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['logDay'])) { + $fileName = "../pgsql-log/postgresql-{$_POST['logDay']}.log"; + echo "

    Log file for {$_POST['logDay']}:

    "; + echo "

    File path: $fileName

    "; + + // execute a command in the shell: sudo sh get-logs.sh + + + if (file_exists($fileName)) { + $fileContents = file_get_contents($fileName); + echo "
    " . htmlspecialchars($fileContents) . "
    "; + } else { + echo "Log file for " . $_POST['logDay'] . " does not exist."; + } + } + ?> +
    + + + + + \ No newline at end of file diff --git a/periodos.php b/periodos.php index 92d9b0f..4169ca4 100644 --- a/periodos.php +++ b/periodos.php @@ -1,211 +1,211 @@ - - - - - - - Auditor铆a asistencial - - - - - - -
    -
    -
    - - - -
    -
    -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - -
    SGUClaveNombreNivelFecha de inicioFecha de finAcciones
    - {{ periodo.id_periodo_sgu }} - - {{ periodo.periodo_clave }} - - - - - - - - - - - -
    -
    - - -
    - - - -
    - - - - - - - - - + + + + + + + Auditor铆a asistencial + + + + + + +
    +
    +
    + + + +
    +
    +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    SGUClaveNombreNivelFecha de inicioFecha de finAcciones
    + {{ periodo.id_periodo_sgu }} + + {{ periodo.periodo_clave }} + + + + + + + + + + + +
    +
    + + +
    + + + +
    + + + + + + + + + \ No newline at end of file diff --git a/pgsql-log/get-logs.sh b/pgsql-log/get-logs.sh index 75552d9..8e62e34 100644 --- a/pgsql-log/get-logs.sh +++ b/pgsql-log/get-logs.sh @@ -1,23 +1,23 @@ -#!/bin/bash - -# Source and destination directories -SRC_DIR="/var/lib/pgsql/15/data/log/" -DEST_DIR="/usr/share/nginx/html/paad/pgsql-log/" - -# Days of the week -DAYS=("Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun") - -echo "Done" -# Iterate over each day and copy the file if it exists -for day in "${DAYS[@]}"; do - src_file="${SRC_DIR}postgresql-${day}.log" - dest_file="${DEST_DIR}postgresql-${day}.log" - - if [[ -f "$src_file" ]]; then - sudo cp "$src_file" "$dest_file" - echo "Copied ${src_file} to ${dest_file}" - else - echo "File ${src_file} not found" - fi - -done +#!/bin/bash + +# Source and destination directories +SRC_DIR="/var/lib/pgsql/15/data/log/" +DEST_DIR="/usr/share/nginx/html/paad/pgsql-log/" + +# Days of the week +DAYS=("Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun") + +echo "Done" +# Iterate over each day and copy the file if it exists +for day in "${DAYS[@]}"; do + src_file="${SRC_DIR}postgresql-${day}.log" + dest_file="${DEST_DIR}postgresql-${day}.log" + + if [[ -f "$src_file" ]]; then + sudo cp "$src_file" "$dest_file" + echo "Copied ${src_file} to ${dest_file}" + else + echo "File ${src_file} not found" + fi + +done diff --git a/pgsql-log/postgresql-Thu.log b/pgsql-log/postgresql-Thu.log index 77163c3..e679524 100644 --- a/pgsql-log/postgresql-Thu.log +++ b/pgsql-log/postgresql-Thu.log @@ -1,5 +1,5 @@ -2023-09-14 00:04:57.032 UTC [1335198] LOG: could not receive data from client: Connection timed out -2023-09-14 00:05:29.800 UTC [1335199] LOG: could not receive data from client: Connection timed out -2023-09-14 00:15:52.392 UTC [1335630] LOG: could not receive data from client: Connection timed out -2023-09-14 00:15:52.392 UTC [1335631] LOG: could not receive data from client: Connection timed out -2023-09-14 00:15:52.392 UTC [1335632] LOG: could not receive data from client: Connection timed out +2023-09-14 00:04:57.032 UTC [1335198] LOG: could not receive data from client: Connection timed out +2023-09-14 00:05:29.800 UTC [1335199] LOG: could not receive data from client: Connection timed out +2023-09-14 00:15:52.392 UTC [1335630] LOG: could not receive data from client: Connection timed out +2023-09-14 00:15:52.392 UTC [1335631] LOG: could not receive data from client: Connection timed out +2023-09-14 00:15:52.392 UTC [1335632] LOG: could not receive data from client: Connection timed out diff --git a/pgsql-log/postgresql-Tue.log b/pgsql-log/postgresql-Tue.log index 30f80a8..f3100dc 100644 --- a/pgsql-log/postgresql-Tue.log +++ b/pgsql-log/postgresql-Tue.log @@ -1,159 +1,159 @@ -2023-09-12 00:12:17.352 UTC [1093788] LOG: could not receive data from client: Connection timed out -2023-09-12 00:12:17.352 UTC [1093789] LOG: could not receive data from client: Connection timed out -2023-09-12 00:12:17.355 UTC [1093796] LOG: could not receive data from client: Connection timed out -2023-09-12 16:04:38.145 UTC [1278220] FATAL: database "paad" does not exist -2023-09-12 16:04:38.211 UTC [1278221] FATAL: database "paad" does not exist -2023-09-12 16:04:38.587 UTC [1278222] FATAL: database "paad" does not exist -2023-09-12 16:04:39.607 UTC [1278223] FATAL: database "paad" does not exist -2023-09-12 16:04:43.386 UTC [1278224] FATAL: database "paad" does not exist -2023-09-12 16:04:51.218 UTC [1278225] FATAL: database "paad" does not exist -2023-09-12 16:04:53.150 UTC [1278227] FATAL: database "paad" does not exist -2023-09-12 16:04:53.161 UTC [1278228] FATAL: database "paad" does not exist -2023-09-12 16:04:53.654 UTC [1278229] FATAL: database "paad" does not exist -2023-09-12 16:04:55.210 UTC [1278230] FATAL: database "paad" does not exist -2023-09-12 16:04:55.569 UTC [1278231] FATAL: database "paad" does not exist -2023-09-12 16:05:07.666 UTC [1278240] FATAL: database "paad" does not exist -2023-09-12 16:05:08.015 UTC [1278241] FATAL: database "paad" does not exist -2023-09-12 16:05:08.173 UTC [1278242] FATAL: database "paad" does not exist -2023-09-12 16:05:08.548 UTC [1278243] FATAL: database "paad" does not exist -2023-09-12 16:05:08.590 UTC [1278244] FATAL: database "paad" does not exist -2023-09-12 16:05:08.807 UTC [1278245] FATAL: database "paad" does not exist -2023-09-12 16:05:09.198 UTC [1278246] FATAL: database "paad" does not exist -2023-09-12 16:05:09.964 UTC [1278247] FATAL: database "paad" does not exist -2023-09-12 16:05:10.657 UTC [1278248] FATAL: database "paad" does not exist -2023-09-12 16:05:14.658 UTC [1278252] FATAL: database "paad" does not exist -2023-09-12 16:05:15.371 UTC [1278253] FATAL: database "paad" does not exist -2023-09-12 16:05:16.303 UTC [1278255] FATAL: database "paad" does not exist -2023-09-12 16:05:16.462 UTC [1278256] FATAL: database "paad" does not exist -2023-09-12 16:05:16.834 UTC [1278257] FATAL: database "paad" does not exist -2023-09-12 16:05:17.022 UTC [1278258] FATAL: database "paad" does not exist -2023-09-12 16:05:17.222 UTC [1278259] FATAL: database "paad" does not exist -2023-09-12 16:05:17.392 UTC [1278260] FATAL: database "paad" does not exist -2023-09-12 16:05:17.574 UTC [1278261] FATAL: database "paad" does not exist -2023-09-12 16:05:17.952 UTC [1278262] FATAL: database "paad" does not exist -2023-09-12 16:05:18.880 UTC [1278263] FATAL: database "paad" does not exist -2023-09-12 16:05:20.321 UTC [1278265] FATAL: database "paad" does not exist -2023-09-12 16:05:20.681 UTC [1278266] FATAL: database "paad" does not exist -2023-09-12 16:05:29.281 UTC [1278280] FATAL: database "paad" does not exist -2023-09-12 16:05:35.416 UTC [1278284] FATAL: database "paad" does not exist -2023-09-12 16:05:41.918 UTC [1278285] FATAL: database "paad" does not exist -2023-09-12 16:05:44.962 UTC [1278286] FATAL: database "paad" does not exist -2023-09-12 16:05:45.403 UTC [1278287] FATAL: database "paad" does not exist -2023-09-12 16:05:45.567 UTC [1278288] FATAL: database "paad" does not exist -2023-09-12 16:05:45.745 UTC [1278289] FATAL: database "paad" does not exist -2023-09-12 16:05:45.946 UTC [1278290] FATAL: database "paad" does not exist -2023-09-12 16:05:45.947 UTC [1278291] FATAL: database "paad" does not exist -2023-09-12 16:05:46.204 UTC [1278292] FATAL: database "paad" does not exist -2023-09-12 16:05:46.316 UTC [1278293] FATAL: database "paad" does not exist -2023-09-12 16:05:46.741 UTC [1278294] FATAL: database "paad" does not exist -2023-09-12 16:05:47.078 UTC [1278295] FATAL: database "paad" does not exist -2023-09-12 16:05:47.334 UTC [1278296] FATAL: database "paad" does not exist -2023-09-12 16:05:47.696 UTC [1278297] FATAL: database "paad" does not exist -2023-09-12 16:05:48.307 UTC [1278299] FATAL: database "paad" does not exist -2023-09-12 16:05:48.310 UTC [1278300] FATAL: expected SASL response, got message type 88 -2023-09-12 16:05:48.318 UTC [1278301] FATAL: database "paad" does not exist -2023-09-12 16:05:48.326 UTC [1278302] FATAL: database "paad" does not exist -2023-09-12 16:05:48.336 UTC [1278303] FATAL: database "paad" does not exist -2023-09-12 16:05:48.344 UTC [1278304] FATAL: database "paad" does not exist -2023-09-12 16:05:48.441 UTC [1278305] FATAL: database "paad" does not exist -2023-09-12 16:05:48.452 UTC [1278306] FATAL: database "paad" does not exist -2023-09-12 16:05:48.461 UTC [1278307] FATAL: database "paad" does not exist -2023-09-12 16:05:48.469 UTC [1278308] FATAL: database "paad" does not exist -2023-09-12 16:05:48.477 UTC [1278309] FATAL: database "paad" does not exist -2023-09-12 16:05:48.486 UTC [1278310] FATAL: database "paad" does not exist -2023-09-12 16:05:48.539 UTC [1278311] FATAL: database "paad" does not exist -2023-09-12 16:05:48.656 UTC [1278312] FATAL: database "paad" does not exist -2023-09-12 16:05:48.740 UTC [1278313] FATAL: database "paad" does not exist -2023-09-12 16:05:49.097 UTC [1278314] FATAL: database "paad" does not exist -2023-09-12 16:05:49.308 UTC [1278315] FATAL: database "paad" does not exist -2023-09-12 16:05:49.441 UTC [1278316] FATAL: database "paad" does not exist -2023-09-12 16:05:49.592 UTC [1278317] FATAL: database "paad" does not exist -2023-09-12 16:05:49.839 UTC [1278318] FATAL: database "paad" does not exist -2023-09-12 16:05:50.213 UTC [1278319] FATAL: database "paad" does not exist -2023-09-12 16:05:50.244 UTC [1278320] FATAL: database "paad" does not exist -2023-09-12 16:05:50.584 UTC [1278321] FATAL: database "paad" does not exist -2023-09-12 16:05:50.661 UTC [1278322] FATAL: database "paad" does not exist -2023-09-12 16:05:51.031 UTC [1278323] FATAL: database "paad" does not exist -2023-09-12 16:05:53.822 UTC [1278325] FATAL: database "paad" does not exist -2023-09-12 16:05:54.197 UTC [1278326] FATAL: database "paad" does not exist -2023-09-12 16:05:55.686 UTC [1278327] FATAL: database "paad" does not exist -2023-09-12 16:05:55.686 UTC [1278328] FATAL: database "paad" does not exist -2023-09-12 16:05:55.692 UTC [1278329] LOG: invalid length of startup packet -2023-09-12 16:05:55.739 UTC [1278330] FATAL: database "paad" does not exist -2023-09-12 16:05:55.830 UTC [1278331] FATAL: database "paad" does not exist -2023-09-12 16:05:55.923 UTC [1278332] FATAL: database "paad" does not exist -2023-09-12 16:05:56.048 UTC [1278333] FATAL: database "paad" does not exist -2023-09-12 16:05:56.140 UTC [1278334] FATAL: database "paad" does not exist -2023-09-12 16:05:56.168 UTC [1278335] FATAL: database "paad" does not exist -2023-09-12 16:05:56.224 UTC [1278336] FATAL: database "paad" does not exist -2023-09-12 16:05:56.316 UTC [1278337] FATAL: database "paad" does not exist -2023-09-12 16:05:56.684 UTC [1278338] FATAL: database "paad" does not exist -2023-09-12 16:05:57.391 UTC [1278339] FATAL: database "paad" does not exist -2023-09-12 16:05:57.392 UTC [1278340] FATAL: expected SASL response, got message type 88 -2023-09-12 16:05:57.763 UTC [1278341] FATAL: database "paad" does not exist -2023-09-12 16:05:58.118 UTC [1278342] FATAL: database "paad" does not exist -2023-09-12 16:05:58.280 UTC [1278343] FATAL: database "paad" does not exist -2023-09-12 16:05:58.514 UTC [1278344] FATAL: database "paad" does not exist -2023-09-12 16:05:58.849 UTC [1278350] FATAL: database "paad" does not exist -2023-09-12 16:05:59.251 UTC [1278351] FATAL: database "paad" does not exist -2023-09-12 16:05:59.313 UTC [1278352] FATAL: database "paad" does not exist -2023-09-12 16:05:59.438 UTC [1278353] FATAL: database "paad" does not exist -2023-09-12 16:05:59.794 UTC [1278354] FATAL: database "paad" does not exist -2023-09-12 16:06:00.072 UTC [1278355] FATAL: database "paad" does not exist -2023-09-12 16:06:00.193 UTC [1278356] FATAL: database "paad" does not exist -2023-09-12 16:06:00.193 UTC [1278357] FATAL: database "paad" does not exist -2023-09-12 16:06:00.196 UTC [1278358] FATAL: expected SASL response, got message type 88 -2023-09-12 16:06:00.422 UTC [1278359] FATAL: database "paad" does not exist -2023-09-12 16:06:00.424 UTC [1278360] FATAL: expected SASL response, got message type 88 -2023-09-12 16:06:00.793 UTC [1278361] FATAL: database "paad" does not exist -2023-09-12 16:06:01.106 UTC [1278362] FATAL: database "paad" does not exist -2023-09-12 16:06:01.124 UTC [1278363] FATAL: database "paad" does not exist -2023-09-12 16:06:01.411 UTC [1278364] FATAL: database "paad" does not exist -2023-09-12 16:06:01.414 UTC [1278365] FATAL: database "paad" does not exist -2023-09-12 16:06:01.495 UTC [1278366] FATAL: database "paad" does not exist -2023-09-12 16:06:01.555 UTC [1278367] FATAL: database "paad" does not exist -2023-09-12 16:06:01.590 UTC [1278368] FATAL: database "paad" does not exist -2023-09-12 16:06:01.628 UTC [1278369] FATAL: database "paad" does not exist -2023-09-12 16:06:01.739 UTC [1278370] FATAL: database "paad" does not exist -2023-09-12 16:06:01.739 UTC [1278371] FATAL: expected SASL response, got message type 88 -2023-09-12 16:06:02.120 UTC [1278373] FATAL: database "paad" does not exist -2023-09-12 16:06:02.140 UTC [1278372] FATAL: database "paad" does not exist -2023-09-12 16:06:02.330 UTC [1278374] FATAL: database "paad" does not exist -2023-09-12 16:06:02.453 UTC [1278376] FATAL: database "paad" does not exist -2023-09-12 16:06:02.454 UTC [1278375] FATAL: database "paad" does not exist -2023-09-12 16:06:02.814 UTC [1278377] FATAL: database "paad" does not exist -2023-09-12 16:06:03.165 UTC [1278378] FATAL: database "paad" does not exist -2023-09-12 16:06:03.203 UTC [1278379] FATAL: database "paad" does not exist -2023-09-12 16:06:03.558 UTC [1278380] FATAL: database "paad" does not exist -2023-09-12 16:06:03.915 UTC [1278381] FATAL: database "paad" does not exist -2023-09-12 16:06:04.214 UTC [1278382] FATAL: database "paad" does not exist -2023-09-12 16:06:04.390 UTC [1278383] FATAL: database "paad" does not exist -2023-09-12 16:06:04.509 UTC [1278384] FATAL: database "paad" does not exist -2023-09-12 16:06:04.879 UTC [1278385] FATAL: database "paad" does not exist -2023-09-12 16:06:05.266 UTC [1278386] FATAL: database "paad" does not exist -2023-09-12 16:06:05.632 UTC [1278387] FATAL: database "paad" does not exist -2023-09-12 16:06:05.981 UTC [1278388] FATAL: database "paad" does not exist -2023-09-12 16:06:08.768 UTC [1278390] FATAL: database "paad" does not exist -2023-09-12 16:06:08.976 UTC [1278392] FATAL: database "paad" does not exist -2023-09-12 16:06:09.347 UTC [1278394] FATAL: database "paad" does not exist -2023-09-12 16:06:09.953 UTC [1278395] FATAL: database "paad" does not exist -2023-09-12 16:06:10.157 UTC [1278396] FATAL: database "paad" does not exist -2023-09-12 16:06:10.383 UTC [1278397] FATAL: database "paad" does not exist -2023-09-12 16:06:10.731 UTC [1278398] FATAL: database "paad" does not exist -2023-09-12 16:06:10.828 UTC [1278399] FATAL: database "paad" does not exist -2023-09-12 16:06:11.182 UTC [1278400] FATAL: database "paad" does not exist -2023-09-12 16:06:11.463 UTC [1278401] FATAL: database "paad" does not exist -2023-09-12 16:06:16.727 UTC [1278403] FATAL: database "paad" does not exist -2023-09-12 16:06:17.169 UTC [1278404] FATAL: database "paad" does not exist -2023-09-12 16:06:20.081 UTC [1278405] FATAL: database "paad" does not exist -2023-09-12 16:36:39.375 UTC [1202] LOG: checkpoint starting: time -2023-09-12 16:36:40.120 UTC [1202] LOG: checkpoint complete: wrote 8 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.705 s, sync=0.014 s, total=0.746 s; sync files=6, longest=0.009 s, average=0.003 s; distance=31 kB, estimate=390 kB -2023-09-12 17:27:45.480 UTC [1273693] LOG: could not receive data from client: Connection timed out -2023-09-12 17:27:45.480 UTC [1273692] LOG: could not receive data from client: Connection timed out -2023-09-12 17:27:45.483 UTC [1273700] LOG: could not receive data from client: Connection timed out -2023-09-12 18:11:26.920 UTC [1277694] LOG: could not receive data from client: Connection timed out -2023-09-12 18:11:26.920 UTC [1277695] LOG: could not receive data from client: Connection timed out -2023-09-12 18:11:26.923 UTC [1277697] LOG: could not receive data from client: Connection timed out -2023-09-12 18:50:46.216 UTC [1282892] LOG: could not receive data from client: Connection timed out -2023-09-12 18:50:46.217 UTC [1282894] LOG: could not receive data from client: Connection timed out -2023-09-12 18:50:46.219 UTC [1282893] LOG: could not receive data from client: Connection timed out +2023-09-12 00:12:17.352 UTC [1093788] LOG: could not receive data from client: Connection timed out +2023-09-12 00:12:17.352 UTC [1093789] LOG: could not receive data from client: Connection timed out +2023-09-12 00:12:17.355 UTC [1093796] LOG: could not receive data from client: Connection timed out +2023-09-12 16:04:38.145 UTC [1278220] FATAL: database "paad" does not exist +2023-09-12 16:04:38.211 UTC [1278221] FATAL: database "paad" does not exist +2023-09-12 16:04:38.587 UTC [1278222] FATAL: database "paad" does not exist +2023-09-12 16:04:39.607 UTC [1278223] FATAL: database "paad" does not exist +2023-09-12 16:04:43.386 UTC [1278224] FATAL: database "paad" does not exist +2023-09-12 16:04:51.218 UTC [1278225] FATAL: database "paad" does not exist +2023-09-12 16:04:53.150 UTC [1278227] FATAL: database "paad" does not exist +2023-09-12 16:04:53.161 UTC [1278228] FATAL: database "paad" does not exist +2023-09-12 16:04:53.654 UTC [1278229] FATAL: database "paad" does not exist +2023-09-12 16:04:55.210 UTC [1278230] FATAL: database "paad" does not exist +2023-09-12 16:04:55.569 UTC [1278231] FATAL: database "paad" does not exist +2023-09-12 16:05:07.666 UTC [1278240] FATAL: database "paad" does not exist +2023-09-12 16:05:08.015 UTC [1278241] FATAL: database "paad" does not exist +2023-09-12 16:05:08.173 UTC [1278242] FATAL: database "paad" does not exist +2023-09-12 16:05:08.548 UTC [1278243] FATAL: database "paad" does not exist +2023-09-12 16:05:08.590 UTC [1278244] FATAL: database "paad" does not exist +2023-09-12 16:05:08.807 UTC [1278245] FATAL: database "paad" does not exist +2023-09-12 16:05:09.198 UTC [1278246] FATAL: database "paad" does not exist +2023-09-12 16:05:09.964 UTC [1278247] FATAL: database "paad" does not exist +2023-09-12 16:05:10.657 UTC [1278248] FATAL: database "paad" does not exist +2023-09-12 16:05:14.658 UTC [1278252] FATAL: database "paad" does not exist +2023-09-12 16:05:15.371 UTC [1278253] FATAL: database "paad" does not exist +2023-09-12 16:05:16.303 UTC [1278255] FATAL: database "paad" does not exist +2023-09-12 16:05:16.462 UTC [1278256] FATAL: database "paad" does not exist +2023-09-12 16:05:16.834 UTC [1278257] FATAL: database "paad" does not exist +2023-09-12 16:05:17.022 UTC [1278258] FATAL: database "paad" does not exist +2023-09-12 16:05:17.222 UTC [1278259] FATAL: database "paad" does not exist +2023-09-12 16:05:17.392 UTC [1278260] FATAL: database "paad" does not exist +2023-09-12 16:05:17.574 UTC [1278261] FATAL: database "paad" does not exist +2023-09-12 16:05:17.952 UTC [1278262] FATAL: database "paad" does not exist +2023-09-12 16:05:18.880 UTC [1278263] FATAL: database "paad" does not exist +2023-09-12 16:05:20.321 UTC [1278265] FATAL: database "paad" does not exist +2023-09-12 16:05:20.681 UTC [1278266] FATAL: database "paad" does not exist +2023-09-12 16:05:29.281 UTC [1278280] FATAL: database "paad" does not exist +2023-09-12 16:05:35.416 UTC [1278284] FATAL: database "paad" does not exist +2023-09-12 16:05:41.918 UTC [1278285] FATAL: database "paad" does not exist +2023-09-12 16:05:44.962 UTC [1278286] FATAL: database "paad" does not exist +2023-09-12 16:05:45.403 UTC [1278287] FATAL: database "paad" does not exist +2023-09-12 16:05:45.567 UTC [1278288] FATAL: database "paad" does not exist +2023-09-12 16:05:45.745 UTC [1278289] FATAL: database "paad" does not exist +2023-09-12 16:05:45.946 UTC [1278290] FATAL: database "paad" does not exist +2023-09-12 16:05:45.947 UTC [1278291] FATAL: database "paad" does not exist +2023-09-12 16:05:46.204 UTC [1278292] FATAL: database "paad" does not exist +2023-09-12 16:05:46.316 UTC [1278293] FATAL: database "paad" does not exist +2023-09-12 16:05:46.741 UTC [1278294] FATAL: database "paad" does not exist +2023-09-12 16:05:47.078 UTC [1278295] FATAL: database "paad" does not exist +2023-09-12 16:05:47.334 UTC [1278296] FATAL: database "paad" does not exist +2023-09-12 16:05:47.696 UTC [1278297] FATAL: database "paad" does not exist +2023-09-12 16:05:48.307 UTC [1278299] FATAL: database "paad" does not exist +2023-09-12 16:05:48.310 UTC [1278300] FATAL: expected SASL response, got message type 88 +2023-09-12 16:05:48.318 UTC [1278301] FATAL: database "paad" does not exist +2023-09-12 16:05:48.326 UTC [1278302] FATAL: database "paad" does not exist +2023-09-12 16:05:48.336 UTC [1278303] FATAL: database "paad" does not exist +2023-09-12 16:05:48.344 UTC [1278304] FATAL: database "paad" does not exist +2023-09-12 16:05:48.441 UTC [1278305] FATAL: database "paad" does not exist +2023-09-12 16:05:48.452 UTC [1278306] FATAL: database "paad" does not exist +2023-09-12 16:05:48.461 UTC [1278307] FATAL: database "paad" does not exist +2023-09-12 16:05:48.469 UTC [1278308] FATAL: database "paad" does not exist +2023-09-12 16:05:48.477 UTC [1278309] FATAL: database "paad" does not exist +2023-09-12 16:05:48.486 UTC [1278310] FATAL: database "paad" does not exist +2023-09-12 16:05:48.539 UTC [1278311] FATAL: database "paad" does not exist +2023-09-12 16:05:48.656 UTC [1278312] FATAL: database "paad" does not exist +2023-09-12 16:05:48.740 UTC [1278313] FATAL: database "paad" does not exist +2023-09-12 16:05:49.097 UTC [1278314] FATAL: database "paad" does not exist +2023-09-12 16:05:49.308 UTC [1278315] FATAL: database "paad" does not exist +2023-09-12 16:05:49.441 UTC [1278316] FATAL: database "paad" does not exist +2023-09-12 16:05:49.592 UTC [1278317] FATAL: database "paad" does not exist +2023-09-12 16:05:49.839 UTC [1278318] FATAL: database "paad" does not exist +2023-09-12 16:05:50.213 UTC [1278319] FATAL: database "paad" does not exist +2023-09-12 16:05:50.244 UTC [1278320] FATAL: database "paad" does not exist +2023-09-12 16:05:50.584 UTC [1278321] FATAL: database "paad" does not exist +2023-09-12 16:05:50.661 UTC [1278322] FATAL: database "paad" does not exist +2023-09-12 16:05:51.031 UTC [1278323] FATAL: database "paad" does not exist +2023-09-12 16:05:53.822 UTC [1278325] FATAL: database "paad" does not exist +2023-09-12 16:05:54.197 UTC [1278326] FATAL: database "paad" does not exist +2023-09-12 16:05:55.686 UTC [1278327] FATAL: database "paad" does not exist +2023-09-12 16:05:55.686 UTC [1278328] FATAL: database "paad" does not exist +2023-09-12 16:05:55.692 UTC [1278329] LOG: invalid length of startup packet +2023-09-12 16:05:55.739 UTC [1278330] FATAL: database "paad" does not exist +2023-09-12 16:05:55.830 UTC [1278331] FATAL: database "paad" does not exist +2023-09-12 16:05:55.923 UTC [1278332] FATAL: database "paad" does not exist +2023-09-12 16:05:56.048 UTC [1278333] FATAL: database "paad" does not exist +2023-09-12 16:05:56.140 UTC [1278334] FATAL: database "paad" does not exist +2023-09-12 16:05:56.168 UTC [1278335] FATAL: database "paad" does not exist +2023-09-12 16:05:56.224 UTC [1278336] FATAL: database "paad" does not exist +2023-09-12 16:05:56.316 UTC [1278337] FATAL: database "paad" does not exist +2023-09-12 16:05:56.684 UTC [1278338] FATAL: database "paad" does not exist +2023-09-12 16:05:57.391 UTC [1278339] FATAL: database "paad" does not exist +2023-09-12 16:05:57.392 UTC [1278340] FATAL: expected SASL response, got message type 88 +2023-09-12 16:05:57.763 UTC [1278341] FATAL: database "paad" does not exist +2023-09-12 16:05:58.118 UTC [1278342] FATAL: database "paad" does not exist +2023-09-12 16:05:58.280 UTC [1278343] FATAL: database "paad" does not exist +2023-09-12 16:05:58.514 UTC [1278344] FATAL: database "paad" does not exist +2023-09-12 16:05:58.849 UTC [1278350] FATAL: database "paad" does not exist +2023-09-12 16:05:59.251 UTC [1278351] FATAL: database "paad" does not exist +2023-09-12 16:05:59.313 UTC [1278352] FATAL: database "paad" does not exist +2023-09-12 16:05:59.438 UTC [1278353] FATAL: database "paad" does not exist +2023-09-12 16:05:59.794 UTC [1278354] FATAL: database "paad" does not exist +2023-09-12 16:06:00.072 UTC [1278355] FATAL: database "paad" does not exist +2023-09-12 16:06:00.193 UTC [1278356] FATAL: database "paad" does not exist +2023-09-12 16:06:00.193 UTC [1278357] FATAL: database "paad" does not exist +2023-09-12 16:06:00.196 UTC [1278358] FATAL: expected SASL response, got message type 88 +2023-09-12 16:06:00.422 UTC [1278359] FATAL: database "paad" does not exist +2023-09-12 16:06:00.424 UTC [1278360] FATAL: expected SASL response, got message type 88 +2023-09-12 16:06:00.793 UTC [1278361] FATAL: database "paad" does not exist +2023-09-12 16:06:01.106 UTC [1278362] FATAL: database "paad" does not exist +2023-09-12 16:06:01.124 UTC [1278363] FATAL: database "paad" does not exist +2023-09-12 16:06:01.411 UTC [1278364] FATAL: database "paad" does not exist +2023-09-12 16:06:01.414 UTC [1278365] FATAL: database "paad" does not exist +2023-09-12 16:06:01.495 UTC [1278366] FATAL: database "paad" does not exist +2023-09-12 16:06:01.555 UTC [1278367] FATAL: database "paad" does not exist +2023-09-12 16:06:01.590 UTC [1278368] FATAL: database "paad" does not exist +2023-09-12 16:06:01.628 UTC [1278369] FATAL: database "paad" does not exist +2023-09-12 16:06:01.739 UTC [1278370] FATAL: database "paad" does not exist +2023-09-12 16:06:01.739 UTC [1278371] FATAL: expected SASL response, got message type 88 +2023-09-12 16:06:02.120 UTC [1278373] FATAL: database "paad" does not exist +2023-09-12 16:06:02.140 UTC [1278372] FATAL: database "paad" does not exist +2023-09-12 16:06:02.330 UTC [1278374] FATAL: database "paad" does not exist +2023-09-12 16:06:02.453 UTC [1278376] FATAL: database "paad" does not exist +2023-09-12 16:06:02.454 UTC [1278375] FATAL: database "paad" does not exist +2023-09-12 16:06:02.814 UTC [1278377] FATAL: database "paad" does not exist +2023-09-12 16:06:03.165 UTC [1278378] FATAL: database "paad" does not exist +2023-09-12 16:06:03.203 UTC [1278379] FATAL: database "paad" does not exist +2023-09-12 16:06:03.558 UTC [1278380] FATAL: database "paad" does not exist +2023-09-12 16:06:03.915 UTC [1278381] FATAL: database "paad" does not exist +2023-09-12 16:06:04.214 UTC [1278382] FATAL: database "paad" does not exist +2023-09-12 16:06:04.390 UTC [1278383] FATAL: database "paad" does not exist +2023-09-12 16:06:04.509 UTC [1278384] FATAL: database "paad" does not exist +2023-09-12 16:06:04.879 UTC [1278385] FATAL: database "paad" does not exist +2023-09-12 16:06:05.266 UTC [1278386] FATAL: database "paad" does not exist +2023-09-12 16:06:05.632 UTC [1278387] FATAL: database "paad" does not exist +2023-09-12 16:06:05.981 UTC [1278388] FATAL: database "paad" does not exist +2023-09-12 16:06:08.768 UTC [1278390] FATAL: database "paad" does not exist +2023-09-12 16:06:08.976 UTC [1278392] FATAL: database "paad" does not exist +2023-09-12 16:06:09.347 UTC [1278394] FATAL: database "paad" does not exist +2023-09-12 16:06:09.953 UTC [1278395] FATAL: database "paad" does not exist +2023-09-12 16:06:10.157 UTC [1278396] FATAL: database "paad" does not exist +2023-09-12 16:06:10.383 UTC [1278397] FATAL: database "paad" does not exist +2023-09-12 16:06:10.731 UTC [1278398] FATAL: database "paad" does not exist +2023-09-12 16:06:10.828 UTC [1278399] FATAL: database "paad" does not exist +2023-09-12 16:06:11.182 UTC [1278400] FATAL: database "paad" does not exist +2023-09-12 16:06:11.463 UTC [1278401] FATAL: database "paad" does not exist +2023-09-12 16:06:16.727 UTC [1278403] FATAL: database "paad" does not exist +2023-09-12 16:06:17.169 UTC [1278404] FATAL: database "paad" does not exist +2023-09-12 16:06:20.081 UTC [1278405] FATAL: database "paad" does not exist +2023-09-12 16:36:39.375 UTC [1202] LOG: checkpoint starting: time +2023-09-12 16:36:40.120 UTC [1202] LOG: checkpoint complete: wrote 8 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.705 s, sync=0.014 s, total=0.746 s; sync files=6, longest=0.009 s, average=0.003 s; distance=31 kB, estimate=390 kB +2023-09-12 17:27:45.480 UTC [1273693] LOG: could not receive data from client: Connection timed out +2023-09-12 17:27:45.480 UTC [1273692] LOG: could not receive data from client: Connection timed out +2023-09-12 17:27:45.483 UTC [1273700] LOG: could not receive data from client: Connection timed out +2023-09-12 18:11:26.920 UTC [1277694] LOG: could not receive data from client: Connection timed out +2023-09-12 18:11:26.920 UTC [1277695] LOG: could not receive data from client: Connection timed out +2023-09-12 18:11:26.923 UTC [1277697] LOG: could not receive data from client: Connection timed out +2023-09-12 18:50:46.216 UTC [1282892] LOG: could not receive data from client: Connection timed out +2023-09-12 18:50:46.217 UTC [1282894] LOG: could not receive data from client: Connection timed out +2023-09-12 18:50:46.219 UTC [1282893] LOG: could not receive data from client: Connection timed out diff --git a/puestos.php b/puestos.php index 7abefdc..941bedb 100644 --- a/puestos.php +++ b/puestos.php @@ -1,332 +1,332 @@ - - - - - - - Auditor铆a asistencial - - - - - - - - - - facultad['facultad_id']) ? "Puestos" : "Puestos de la {$user->facultad['facultad']}", - "Sistema de gesti贸n de checador", - ); - if (!is_null($user->facultad['facultad_id'])) { - ?> - -
    - - - - acceso == 'w') { - ?> -
    - - -
    - - - -
    -
    - -
    - -
    - - acceso == 'w') { ?> - - -
    - -
    -
    - - -
    - -
    -
    - ({{puesto.encargado.usuario_clave}}) {{ puesto.encargado.usuario_nombre }} -
    -
    - Selecciona un encargado -
    - -
      -
    • - ( {{usuario.usuario_clave}} ) {{ usuario.usuario_nombre }} -
    • -
    - -
    -
    -
    - - acceso == 'w') { ?> - - -
    - - -
    - - - - -
    - -
    - - Materias Asignadas {{puesto.materias.length}} - - - -
      -
    • acceso == 'w') { ?> - @click="modificado = true; puesto.materias.splice(puesto.materias.indexOf(materia), 1); materias.push(materia)" - - style="cursor: pointer; transition: background-color 0.3s ease;"> - - {{materia.clave_materia}} - {{materia.materia_nombre}} - - acceso == 'w') { ?> - - - - -
    • -
    - - - -
    - - -
    - acceso == 'w') { ?> - - -
    -
    -
    -
    - -
    -
    - - - -
    - - -
    -
    -
    -
    -
    - Sin Facultad Asociada -
    -
    -
    Atenci贸n
    -

    No tienes una facultad asociada a tu perfil. El rol - rol['rol'] ?> no tiene acceso a esta secci贸n. -

    -
    -
    -
    -
    -
    - - - - - - - - - - - - + + + + + + + Auditor铆a asistencial + + + + + + + + + + facultad['facultad_id']) ? "Puestos" : "Puestos de la {$user->facultad['facultad']}", + "Sistema de gesti贸n de checador", + ); + if (!is_null($user->facultad['facultad_id'])) { + ?> + +
    + + + + acceso == 'w') { + ?> +
    + + +
    + + + +
    +
    + +
    + +
    + + acceso == 'w') { ?> + + +
    + +
    +
    + + +
    + +
    +
    + ({{puesto.encargado.usuario_clave}}) {{ puesto.encargado.usuario_nombre }} +
    +
    + Selecciona un encargado +
    + +
      +
    • + ( {{usuario.usuario_clave}} ) {{ usuario.usuario_nombre }} +
    • +
    + +
    +
    +
    + + acceso == 'w') { ?> + + +
    + + +
    + + + + +
    + +
    + + Materias Asignadas {{puesto.materias.length}} + + + +
      +
    • acceso == 'w') { ?> + @click="modificado = true; puesto.materias.splice(puesto.materias.indexOf(materia), 1); materias.push(materia)" + + style="cursor: pointer; transition: background-color 0.3s ease;"> + + {{materia.clave_materia}} - {{materia.materia_nombre}} + + acceso == 'w') { ?> + + + + +
    • +
    + + + +
    + + +
    + acceso == 'w') { ?> + + +
    +
    +
    +
    + +
    +
    + + + +
    + + +
    +
    +
    +
    +
    + Sin Facultad Asociada +
    +
    +
    Atenci贸n
    +

    No tienes una facultad asociada a tu perfil. El rol + rol['rol'] ?> no tiene acceso a esta secci贸n. +

    +
    +
    +
    +
    +
    + + + + + + + + + + + + \ No newline at end of file diff --git a/reporte_de_asistencias.php b/reporte_de_asistencias.php index 2df319a..c910dc2 100644 --- a/reporte_de_asistencias.php +++ b/reporte_de_asistencias.php @@ -1,298 +1,298 @@ -access('reporte_de_asistencias'); -if (in_array($user->acceso, ['n'])) - die(header('Location: main.php?error=1')); - -$user->print_to_log('Consultar asistencia'); -# Select carreras from facultad -$fs_carrera = queryAll( - "SELECT * FROM FS_CARRERA(:facultad)", - array( - ":facultad" => $user->facultad["facultad_id"] - ) -); - -$fs_periodo = queryAll( - "SELECT * FROM FS_PERIODO(:periodo, :nivel, :estado)", - array( - ":periodo" => null, - ":nivel" => null, - ":estado" => 1, - ) -); - -extract($_POST); -$retardos = query("SELECT FS_HAS_RETARDO(:facultad) r", [":facultad" => $user->facultad["facultad_id"]])['r']; -?> - - - - - - Reporte asistencias | <?= $user->facultad['facultad'] ?? 'General' ?> - - - - - - - facultad["facultad"] ?? "General"), "Sistema de gesti贸n de checador"); - ?> -
    -
    - - - - -
    -
    -
    -
    -
    - - - -
    - - -
    - - -
    - - - - - - - - - +access('reporte_de_asistencias'); +if (in_array($user->acceso, ['n'])) + die(header('Location: main.php?error=1')); + +$user->print_to_log('Consultar asistencia'); +# Select carreras from facultad +$fs_carrera = queryAll( + "SELECT * FROM FS_CARRERA(:facultad)", + array( + ":facultad" => $user->facultad["facultad_id"] + ) +); + +$fs_periodo = queryAll( + "SELECT * FROM FS_PERIODO(:periodo, :nivel, :estado)", + array( + ":periodo" => null, + ":nivel" => null, + ":estado" => 1, + ) +); + +extract($_POST); +$retardos = query("SELECT FS_HAS_RETARDO(:facultad) r", [":facultad" => $user->facultad["facultad_id"]])['r']; +?> + + + + + + Reporte asistencias | <?= $user->facultad['facultad'] ?? 'General' ?> + + + + + + + facultad["facultad"] ?? "General"), "Sistema de gesti贸n de checador"); + ?> +
    +
    + + + + +
    +
    +
    +
    +
    + + + +
    + + +
    + + +
    + + + + + + + + + \ No newline at end of file diff --git a/rest/include/phpmailer/PHPMailerAutoload.php b/rest/include/phpmailer/PHPMailerAutoload.php index 60f9ad7..8d3dcba 100644 --- a/rest/include/phpmailer/PHPMailerAutoload.php +++ b/rest/include/phpmailer/PHPMailerAutoload.php @@ -1,50 +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); - }*/ -} + + * @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/rest/include/phpmailer/class.phpmailer.php b/rest/include/phpmailer/class.phpmailer.php index 3cda98d..d6daaed 100644 --- a/rest/include/phpmailer/class.phpmailer.php +++ b/rest/include/phpmailer/class.phpmailer.php @@ -1,3884 +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; - } -} + + * @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/rest/include/phpmailer/class.smtp.php b/rest/include/phpmailer/class.smtp.php index 2e32e2f..9204734 100644 --- a/rest/include/phpmailer/class.smtp.php +++ b/rest/include/phpmailer/class.smtp.php @@ -1,1181 +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; - } -} + + * @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/rest/log/cambios_2023_08.log b/rest/log/cambios_2023_08.log index 66a9f85..b77a488 100644 --- a/rest/log/cambios_2023_08.log +++ b/rest/log/cambios_2023_08.log @@ -1,20 +1,20 @@ -2023-08-06 12:39:03||SELECT * FROM fu_horario_deshabilita(867) ## SELECT * FROM fu_horario_deshabilita(555) ## SELECT * FROM fu_horario_deshabilita(1005) ## SELECT * FROM fu_horario_deshabilita(860) ## SELECT * FROM fu_horario_deshabilita(389) ## SELECT * FROM fu_horario_deshabilita(685) ## SELECT * FROM fu_horario_deshabilita(920) ## SELECT * FROM fu_horario_deshabilita(513) ## -2023-08-06 12:39:03||SELECT * FROM fi_horario(1, 07:15:00,08:45:00,036,79,Seguridad en tecnolog铆as de la informaci贸n,IC060413,014416,EDGAR ALBERTO CHILLON ESCARCEGA,edgar.chillon@lasallistas.org.mx,MG 79090109,842) [ID=5617] ##SELECT * FROM fi_horario(1, 12:00:00,13:30:00,034,33,Fundamentos del derecho constitucional,DE122315,015520,JAIME CALDERON GOMEZ,jaime.calderon@lasallistas.org.mx,MG 33020105,1028) [ID=5618] ##SELECT * FROM fi_horario(1, 15:45:00,17:15:00,033,96,Seminario y an谩lisis de casos de negocios en 谩mbitos locales,AD031717,014365,JOSE MANUEL RIVERA ZARAGOZA,jm.riveraz@lasallistas.org.mx,MG 96070207,187) [ID=5619] ##SELECT * FROM fi_horario(1, 17:15:00,18:45:00,033,09,Negociaciones internacionales,EC061817,,,,MG 09060105,1086) [ID=5620] ##SELECT * FROM fi_horario(1, 20:30:00,22:00:00,036,79,Aplicaciones m贸viles,IC031813,017335,FELIPE MANDUJANO G脫MEZ,felipe.mandujano@lasallistas.org.mx,MG 79090103,842) [ID=5621] ##SELECT * FROM fi_horario(1, 20:30:00,22:00:00,033,07,Taller de negociaci贸n,AD091817,,,,MG 07050208,264) [ID=5622] ## -2023-08-06 13:07:45||SELECT * FROM fi_horario(1, 07:15:00,08:45:00,036,79,Seguridad en tecnolog铆as de la informaci贸n,IC060413,014416,EDGAR ALBERTO CHILLON ESCARCEGA,edgar.chillon@lasallistas.org.mx,MG 79090109,842) [ID=5623] ##SELECT * FROM fi_horario(1, 12:00:00,13:30:00,034,33,Fundamentos del derecho constitucional,DE122315,015520,JAIME CALDERON GOMEZ,jaime.calderon@lasallistas.org.mx,MG 33020105,1028) [ID=5624] ##SELECT * FROM fi_horario(1, 15:45:00,17:15:00,033,96,Seminario y an谩lisis de casos de negocios en 谩mbitos locales,AD031717,014365,JOSE MANUEL RIVERA ZARAGOZA,jm.riveraz@lasallistas.org.mx,MG 96070207,187) [ID=5625] ##SELECT * FROM fi_horario(1, 17:15:00,18:45:00,033,09,Negociaciones internacionales,EC061817,,,,MG 09060105,1086) [ID=5626] ##SELECT * FROM fi_horario(1, 20:30:00,22:00:00,036,79,Aplicaciones m贸viles,IC031813,017335,FELIPE MANDUJANO G脫MEZ,felipe.mandujano@lasallistas.org.mx,MG 79090103,842) [ID=5627] ##SELECT * FROM fi_horario(1, 20:30:00,22:00:00,033,07,Taller de negociaci贸n,AD091817,,,,MG 07050208,264) [ID=5628] ## -2023-08-08 06:57:53||SELECT * FROM fu_horario_deshabilita(1772) ## -2023-08-08 06:57:53||SELECT * FROM fi_horario(2, 07:15:00,08:45:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 75010102,455) [ID=5836] ##SELECT * FROM fi_horario(2, 07:15:00,08:45:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,017181,DANIELA MONTA脩O SAN AGUSTIN,daniela.montano@lasallistas.org.mx,MG 75010102,455) [ID=5837] ##SELECT * FROM fi_horario(2, 08:45:00,10:15:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 75010202,455) [ID=5838] ##SELECT * FROM fi_horario(2, 08:45:00,10:15:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,017181,DANIELA MONTA脩O SAN AGUSTIN,daniela.montano@lasallistas.org.mx,MG 75010202,455) [ID=5839] ##SELECT * FROM fi_horario(2, 10:30:00,12:00:00,036,80,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050122,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 80010103,455) [ID=5840] ##SELECT * FROM fi_horario(2, 10:30:00,12:00:00,036,80,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050122,013557,GABRIELA MAC脥AS ESQUIVEL,gabriela.macias@lasalle.mx,MG 80010103,455) [ID=5841] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,016627,CLEMENTINA PALOMO BELTR脕N,c.palomob@lasallistas.org.mx,MG 28050106,1044) [ID=5842] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,017462,CARLOS IV脕N G脫MEZ CALDER脫N,carlos.gomez@lasallistas.org.mx,MG 28050206,1044) [ID=5843] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,016794,JORGE ADRIAN RAMOS RUIZ,jorgeramos@lasallistas.org.mx,MG 28050303,1044) [ID=5844] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,015352,ALEJANDRO IMAZ LAMADRID,alejandroimaz@lasallistas.org.mx,MG 28050401,1044) [ID=5845] ##SELECT * FROM fi_horario(2, 13:30:00,15:00:00,032,27,La persona y su interacci贸n con los otros,PS151113,,,,MG 27030301,0) [ID=5846] ##SELECT * FROM fi_horario(2, 17:15:00,18:45:00,036,79,Gobierno de tecnolog铆as de informaci贸n y entrega de servicios,IC052413,015962,CYNTHIA MARTINEZ ARIZMENDI,,MG 79090208,0) [ID=5847] ##SELECT * FROM fi_horario(2, 19:00:00,20:30:00,036,79,Miner铆a de datos e inteligencia de negocios,IC020913,,,,MG 79090209,0) [ID=5848] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,004558,MANUEL MAR脥A JOS脡 GALLO REYNOSO,manuelgallo@lasallistas.org.mx,MG 70040207,858) [ID=5849] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016426,JESSICA JOHANA HERN脕NDEZ OSORIO,jessica-hernandez@lasallistas.org.mx,MG 70040207,858) [ID=5850] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,010124,ENRIQUE JUAN D脥AZ GREENE,do_enrique.Diaz@lasallistas.org.mx,MG 70040504,855) [ID=5851] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,008927,FEDERICO LEOPOLDO RODR脥GUEZ WEBER,flrw@lasallistas.org.mx,MG 70040307,855) [ID=5852] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,,,,MG 70040307,855) [ID=5853] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,013104,LUIS ARMANDO GERVACIO BLANCO,luis.gervacio@lasallistas.org.mx,MG 70040704,881) [ID=5854] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,014494,LUIS ANTONIO REYES QUIJANO,reyes.luis@lasallistas.org.mx,MG 70040704,881) [ID=5855] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016108,DIANA CHAVEZ GARRIDO,diana.chavez@lasallistas.org.mx,MG 70040404,881) [ID=5856] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016401,JULIO CESAR OLVERA BARAJAS,julio.olvera@lasallistas.org.mx,MG 70040404,881) [ID=5857] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,015215,ADOLFO BUSTOS RAM脥REZ,adolfo.bustos@lasallistas.org.mx,MG 70040404,881) [ID=5858] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,010570,SERGIO IV脕N GONZ脕LEZ OLVERA,sigo@lasallistas.org.mx,MG 70040107,887) [ID=5859] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,015553,GERARDO ARTURO BRAVO ESCOBAR,gerardobravo@lasallistas.org.mx,MG 70040107,887) [ID=5860] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016724,ABEL JALIFE MONTA脩O,abeljalife@lasallistas.org.mx,MG 70041003,889) [ID=5861] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016713,MAR脥A DEL CARMEN GARC脥A RUIZ,mdc.garcia@lasallistas.org.mx,MG 70041003,889) [ID=5862] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,007816,BLANCA MARGARITA VARGAS PEDRAZA,blancavargas@lasallistas.org.mx,MG 70040604,889) [ID=5863] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,007818,AGUST脥N VIVANCO ROSAS,a-vr@lasallistas.org.mx,MG 70040604,889) [ID=5864] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016717,ABRAHAM PULIDO CEJUDO,abraham.pulido@lasallistas.org.mx,MG 70040903,889) [ID=5865] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016785,MARIO GUZMAN GUTIERREZ,mg.6@lasallistas.org.mx,MG 70040903,889) [ID=5866] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016381,ELVIRA GRACIELA ALEXANDERSON ROSAS,eg.alexanderson@lasallistas.org.mx,MG 70040803,889) [ID=5867] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016305,ALFREDO ISRAEL SERVIN CAAMA脩O,alfredo.servin@lasallistas.org.mx,MG 70040803,889) [ID=5868] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,017106,MARIO MAURICIO FERN脕NDEZ ROMERO,mario.fernandez@lasallistas.org.mx,MG 70080306,1423) [ID=5869] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016173,VICTOR MANUEL FLORES M脡NDEZ,victorflores@lasallistas.org.mx,MG 70080406,0) [ID=5870] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016112,LUIS EDMUNDO HERNANDEZ VIVAR,le.hv@lasallistas.org.mx,MG 70080406,0) [ID=5871] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,017056,JUAN JIMENEZ HUERTA,,MG 70080406,0) [ID=5872] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,010577,MONICA VILLA GUILLEN,m.mvg@lasallistas.org.mx,MG 70080308,0) [ID=5873] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016138,DIANA AIDEE GUERRERO RESENDIZ,,MG 70080308,0) [ID=5874] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016580,VICTOR MANUEL BARAJAS VALENCIA,,MG 70080308,0) [ID=5875] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,010915,GERARDO BLANCO RODR脥GUEZ,g.blancor@lasallistas.org.mx,MG 70080108,0) [ID=5876] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014626,ELISA MAR脥A DORANTES ACOSTA,,MG 70080108,0) [ID=5877] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016513,ANA CAROLINA HILL DE TITTO,ac.hill@lasallistas.org.mx,MG 70080108,0) [ID=5878] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,015171,ANTONIO CALDER脫N MOORE,a.calderonm@lasallistas.org.mx,MG 70080606,0) [ID=5879] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,007232,MIGUEL VILLA GUERRERO,miguel.villa@lasallistas.org.mx,MG 70080106,0) [ID=5880] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016016,MANUEL FRANCISCO BORGES IB脕脩EZ,manuelborges@lasallistas.org.mx,MG 70080106,0) [ID=5881] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016116,JES脷S CARLOS BRIONES GARDU脩O,jesus.briones@lasallistas.org.mx,MG 70080106,0) [ID=5882] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014202,ROMULO ERICK ROSALES URIBE,re.ru@lasallistas.org.mx,MG 70080208,0) [ID=5883] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014596,JOSE CARLOS ROMO VAZQUEZ,,MG 70080208,0) [ID=5884] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016599,CARLOS PATRICIO ACOSTA RODR脥GUEZ BUENO,cp.acosta@lasallistas.org.mx,MG 70080208,0) [ID=5885] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,015614,KARLA GABRIELA OJEDA DIEZBARROSO,,MG 70080507,0) [ID=5886] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,000752,JOS脡 JUAN ORTEGA CERDA,jortega@lasallistas.org.mx,MG 70050601,855) [ID=5887] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,008867,URSULO JU脕REZ HERRERA,u.juarez@lasallistas.org.mx,MG 70050601,855) [ID=5888] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,016853,GUSTAVO ROJAS VELASCO,,MG 70050601,855) [ID=5889] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,008098,ISAAC ZAGA MINIAN,,MG 70090503,871) [ID=5890] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017381,JAIME ANTONIO HIDALGO CARRERA,,MG 70090903,899) [ID=5891] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,013905,MARTHA EUNICE RODR脥GUEZ ARELLANO,mera@lasallistas.org.mx,MG 70050702,854) [ID=5892] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,013878,PERLA ALICIA CARRILLO GONZ脕LEZ,perlacarrillo@lasallistas.org.mx,MG 70050702,854) [ID=5893] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,017131,ANTONIO CORONA BAUTISTA,antoniocorona@lasallistas.org.mx,MG 70070704,854) [ID=5894] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016272,ALEJANDRA CALDER脫N VALLEJO,alejandra.calderon@lasallistas.org.mx,MG 70060509,865) [ID=5895] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016950,CARLOS FREDY CUEVAS GARCIA,,MG 70060509,865) [ID=5896] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016954,JES脷S FONSECA COSIO,,MG 70060509,865) [ID=5897] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,011707,CLAUDIA ELENA MURILLO CORREA,,MG 70070502,880) [ID=5898] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,012289,脕NGEL NAVA CASTA脩EDA,,MG 70070502,880) [ID=5899] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,014180,ALMA JESSICA VARGAS ORTEGA,,MG 70070502,880) [ID=5900] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,013434,ERIKA LETICIA FERN脕NDEZ MU脩OZ,erikafernandez@lasallistas.org.mx,MG 70070403,883) [ID=5901] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,016747,ITZEL MONTSERRAT P脡REZ GUDI脩O,itzelperez@lasallistas.org.mx,MG 70070403,883) [ID=5902] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,017383,MARY LADY GONZALEZ SURIEL,,MG 70070403,883) [ID=5903] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,015425,GUILLERMO CESAR PEREZ PELAEZ,,MG 70090203,885) [ID=5904] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017378,DANIELA ALEJANDRA LEMIONET ESCANERO,,MG 70090703,860) [ID=5905] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,016830,JUAN PABLO RAMIREZ HINOJOSA,jp.ramirezh@lasallistas.org.mx,MG 70060308,887) [ID=5906] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,016881,MERCEDES ARANDA AUDELO,mercedes.aranda@lasallistas.org.mx,MG 70060308,887) [ID=5907] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,013875,ANA PATRICIA RODR脥GUEZ ZULUETA,,MG 70060308,887) [ID=5908] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,004730,MAR脥A IVONNE ARELLANO MENDOZA,mi.arellanom@lasallistas.org.mx,MG 70060305,889) [ID=5909] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,016545,MARIELA GALICIA MALDONADO,marielagalicia@lasallistas.org.mx,MG 70060305,889) [ID=5910] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,013299,ROSA MAR脥A PONCE OLIVERA,,MG 70060305,889) [ID=5911] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,014547,MARIO SILVINO ALMANZA GONZALEZ,,MG 70080211,889) [ID=5912] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,014599,HUGO ARTURO MANZANILLA GARCIA,ha.manzanilla@lasallistas.org.mx,MG 70080211,889) [ID=5913] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016259,CESAR FIRETH POZO BELTR脕N,,MG 70091003,896) [ID=5914] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Psiquiatr铆a,MD030617,016606,ADOLFO NERI HERN脕NDEZ,adolfo.neri@lasallistas.org.mx,MG 70050409,1013) [ID=5915] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Psiquiatr铆a,MD030617,015698,CARLOS HERNANDEZ VEGA,c.hv@lasallistas.org.mx,MG 70050409,1013) [ID=5916] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017310,NORMA VELIA BALLESTEROS SOLIS,norma.ballesteros@lasallistas.org.mx,MG 70093003,867) [ID=5917] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Cirug铆a (internado de pregrado),MD020317,017305,ERNESTO SALGADO SANCHEZ,,MG 70091801,1272) [ID=5918] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016280,MARIA ANOTA RIVERA,,MG 70092903,1267) [ID=5919] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Traumatolog铆a y ortopedia,MD030417,014992,RUDY DE JESUS SALAZAR PACHECO,rudysalazar@lasallistas.org.mx,MG 70070210,1004) [ID=5920] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Traumatolog铆a y ortopedia,MD030417,015451,FERNANDO ORTIZ ROJAS,fortiz@lasallistas.org.mx,MG 70070210,1004) [ID=5921] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,016568,JUAN ANTONIO LUGO GARC脥A,juanlugo@lasallistas.org.mx,MG 70080411,1004) [ID=5922] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,016818,OMAR HERNANDEZ LEON,o.hl@lasallistas.org.mx,MG 70080411,1004) [ID=5923] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016952,ERIKA GOMEZ ZAMORA,,MG 70092203,1004) [ID=5924] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,006026,RUBEN CORT脡S GONZ脕LEZ,rubencortes@lasallistas.org.mx,MG 70070206,892) [ID=5925] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,016281,NOEL SALGADO NESME,,MG 70070206,892) [ID=5926] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,016429,MAURICIO SIERRA SALAZAR,,MG 70070206,892) [ID=5927] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Gastroenterolog铆a,MD040417,012899,JORGE HERN脕NDEZ CALLEROS,,MG 70060206,892) [ID=5928] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Gastroenterolog铆a,MD040417,015294,ENRIQUE COSS ADAME,enrique.coss@lasallistas.org.mx,MG 70060206,892) [ID=5929] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neumolog铆a,MD040217,,,,MG 70050206,886) [ID=5930] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,010978,脕NGEL ANTONIO ARAUZ G脫NGORA,aa.arauz@lasallistas.org.mx,MG 70060209,884) [ID=5931] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,011794,LUIS IGNACIO MIRANDA MEDRANO,,MG 70060209,884) [ID=5932] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,013146,ADOLFO LEYVA REND脫N,,MG 70060209,884) [ID=5933] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,017123,DANIELLA ALEJANDRA MONROY LLAGUNO,daniella.monroy@lasallistas.org.mx,MG 70070205,1010) [ID=5934] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,015003,IVAN HERMANN SCHOBERT CAPETILLO,ivanschobert@lasallistas.org.mx,MG 70070205,1010) [ID=5935] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,016774,OFELIA NATSUKO TANIYAMA L脫PEZ,ofeliataniyama@lasallistas.org.mx,MG 70070205,1010) [ID=5936] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,015452,CARMEN ZAVALA GARC脥A,,MG 70090403,863) [ID=5937] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,008931,ALMA VERGARA L脫PEZ,alma.vergara@lasallistas.org.mx,MG 70050203,869) [ID=5938] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,016089,ADRIANA BALDERRAMA SOTO,a.balderrama@lasallistas.org.mx,MG 70050203,869) [ID=5939] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,008725,CARLOS HAROLDO IXCAMPARIJ ROSALES,chir@lasallistas.org.mx,MG 70050202,869) [ID=5940] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,015880,ROBERTO MURATALLA GONZ脕LEZ,,MG 70050202,869) [ID=5941] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,009026,GREGORIO ZARAGOZA RODRIGUEZ,,MG 70050202,869) [ID=5942] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Geriatr铆a,MD030717,017243,DOMINGA ALBERTA SALOMON CORTEZ,,MG 70070601,0) [ID=5943] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017238,ERIK REBOLLEDO GARDU脩O,,MG 70092803,0) [ID=5944] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017382,RODOLFO SILVA ROMO,,MG 70093103,0) [ID=5945] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017240,ROBERTO BADIR CORANGUEZ CAPISTRAN,,MG 70091603,0) [ID=5946] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016275,IV脕N ALBERTO NAJERA RODR脥GUEZ,ivan.najera@lasallistas.org.mx,MG 70093203,0) [ID=5947] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Cirug铆a (internado de pregrado),MD020317,013926,ABEL FUENTES VENEGAS,abelfuentes@lasallistas.org.mx,MG 70090301,0) [ID=5948] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina interna (internado de pregrado),MD041117,011870,NORBERTO REYES PAREDES,norbertoreyes@lasallistas.org.mx,MG 70092604,0) [ID=5949] ##SELECT * FROM fi_horario(2, 12:00:00,18:00:00,037,70,Otorrinolaringolog铆a,MD030317,010570,SERGIO IV脕N GONZ脕LEZ OLVERA,sigo@lasallistas.org.mx,MG 70070703,887) [ID=5950] ##SELECT * FROM fi_horario(2, 12:00:00,18:00:00,037,70,Otorrinolaringolog铆a,MD030317,013134,DINA FABIOLA GONZ脕LEZ S脕NCHEZ,df.gonzalezs@lasallistas.org.mx,MG 70070703,887) [ID=5951] ##SELECT * FROM fi_horario(2, 14:00:00,16:00:00,037,70,Ginecolog铆a y obstetricia (internado de pregrado),MD031217,010124,ENRIQUE JUAN D脥AZ GREENE,do_enrique.Diaz@lasallistas.org.mx,MG 70090102,855) [ID=5952] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,007232,MIGUEL VILLA GUERRERO,miguel.villa@lasallistas.org.mx,MG 70080604,0) [ID=5953] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016016,MANUEL FRANCISCO BORGES IB脕脩EZ,manuelborges@lasallistas.org.mx,MG 70080604,0) [ID=5954] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016116,JES脷S CARLOS BRIONES GARDU脩O,jesus.briones@lasallistas.org.mx,MG 70080604,0) [ID=5955] ## -2023-08-08 07:11:46||SELECT * FROM fi_horario(2, 07:15:00,08:45:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 75010102,455) [ID=6074] ##SELECT * FROM fi_horario(2, 07:15:00,08:45:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,017181,DANIELA MONTA脩O SAN AGUSTIN,daniela.montano@lasallistas.org.mx,MG 75010102,455) [ID=6075] ##SELECT * FROM fi_horario(2, 08:45:00,10:15:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 75010202,455) [ID=6076] ##SELECT * FROM fi_horario(2, 08:45:00,10:15:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,017181,DANIELA MONTA脩O SAN AGUSTIN,daniela.montano@lasallistas.org.mx,MG 75010202,455) [ID=6077] ##SELECT * FROM fi_horario(2, 10:30:00,12:00:00,036,80,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050122,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 80010103,455) [ID=6078] ##SELECT * FROM fi_horario(2, 10:30:00,12:00:00,036,80,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050122,013557,GABRIELA MAC脥AS ESQUIVEL,gabriela.macias@lasalle.mx,MG 80010103,455) [ID=6079] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,016627,CLEMENTINA PALOMO BELTR脕N,c.palomob@lasallistas.org.mx,MG 28050106,1044) [ID=6080] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,016794,JORGE ADRIAN RAMOS RUIZ,jorgeramos@lasallistas.org.mx,MG 28050303,1044) [ID=6081] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,015352,ALEJANDRO IMAZ LAMADRID,alejandroimaz@lasallistas.org.mx,MG 28050401,1044) [ID=6082] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,017462,CARLOS IV脕N G脫MEZ CALDER脫N,carlos.gomez@lasallistas.org.mx,MG 28050206,1044) [ID=6083] ##SELECT * FROM fi_horario(2, 13:30:00,15:00:00,032,27,La persona y su interacci贸n con los otros,PS151113,,,,MG 27030301,0) [ID=6084] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,004558,MANUEL MAR脥A JOS脡 GALLO REYNOSO,manuelgallo@lasallistas.org.mx,MG 70040207,858) [ID=6085] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016426,JESSICA JOHANA HERN脕NDEZ OSORIO,jessica-hernandez@lasallistas.org.mx,MG 70040207,858) [ID=6086] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,008927,FEDERICO LEOPOLDO RODR脥GUEZ WEBER,flrw@lasallistas.org.mx,MG 70040307,855) [ID=6087] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,,,,MG 70040307,855) [ID=6088] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,010124,ENRIQUE JUAN D脥AZ GREENE,do_enrique.Diaz@lasallistas.org.mx,MG 70040504,855) [ID=6089] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,013104,LUIS ARMANDO GERVACIO BLANCO,luis.gervacio@lasallistas.org.mx,MG 70040704,881) [ID=6090] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,014494,LUIS ANTONIO REYES QUIJANO,reyes.luis@lasallistas.org.mx,MG 70040704,881) [ID=6091] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016108,DIANA CHAVEZ GARRIDO,diana.chavez@lasallistas.org.mx,MG 70040404,881) [ID=6092] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016401,JULIO CESAR OLVERA BARAJAS,julio.olvera@lasallistas.org.mx,MG 70040404,881) [ID=6093] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,015215,ADOLFO BUSTOS RAM脥REZ,adolfo.bustos@lasallistas.org.mx,MG 70040404,881) [ID=6094] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,010570,SERGIO IV脕N GONZ脕LEZ OLVERA,sigo@lasallistas.org.mx,MG 70040107,887) [ID=6095] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,015553,GERARDO ARTURO BRAVO ESCOBAR,gerardobravo@lasallistas.org.mx,MG 70040107,887) [ID=6096] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,007816,BLANCA MARGARITA VARGAS PEDRAZA,blancavargas@lasallistas.org.mx,MG 70040604,889) [ID=6097] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,007818,AGUST脥N VIVANCO ROSAS,a-vr@lasallistas.org.mx,MG 70040604,889) [ID=6098] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016717,ABRAHAM PULIDO CEJUDO,abraham.pulido@lasallistas.org.mx,MG 70040903,889) [ID=6099] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016785,MARIO GUZMAN GUTIERREZ,mg.6@lasallistas.org.mx,MG 70040903,889) [ID=6100] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016724,ABEL JALIFE MONTA脩O,abeljalife@lasallistas.org.mx,MG 70041003,889) [ID=6101] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016713,MAR脥A DEL CARMEN GARC脥A RUIZ,mdc.garcia@lasallistas.org.mx,MG 70041003,889) [ID=6102] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016381,ELVIRA GRACIELA ALEXANDERSON ROSAS,eg.alexanderson@lasallistas.org.mx,MG 70040803,889) [ID=6103] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016305,ALFREDO ISRAEL SERVIN CAAMA脩O,alfredo.servin@lasallistas.org.mx,MG 70040803,889) [ID=6104] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,017106,MARIO MAURICIO FERN脕NDEZ ROMERO,mario.fernandez@lasallistas.org.mx,MG 70080306,1423) [ID=6105] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014202,ROMULO ERICK ROSALES URIBE,re.ru@lasallistas.org.mx,MG 70080208,0) [ID=6106] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014596,JOSE CARLOS ROMO VAZQUEZ,,MG 70080208,0) [ID=6107] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016599,CARLOS PATRICIO ACOSTA RODR脥GUEZ BUENO,cp.acosta@lasallistas.org.mx,MG 70080208,0) [ID=6108] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016173,VICTOR MANUEL FLORES M脡NDEZ,victorflores@lasallistas.org.mx,MG 70080406,0) [ID=6109] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016112,LUIS EDMUNDO HERNANDEZ VIVAR,le.hv@lasallistas.org.mx,MG 70080406,0) [ID=6110] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,017056,JUAN JIMENEZ HUERTA,,MG 70080406,0) [ID=6111] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,010577,MONICA VILLA GUILLEN,m.mvg@lasallistas.org.mx,MG 70080308,0) [ID=6112] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016138,DIANA AIDEE GUERRERO RESENDIZ,,MG 70080308,0) [ID=6113] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016580,VICTOR MANUEL BARAJAS VALENCIA,,MG 70080308,0) [ID=6114] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,015614,KARLA GABRIELA OJEDA DIEZBARROSO,,MG 70080507,0) [ID=6115] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,007232,MIGUEL VILLA GUERRERO,miguel.villa@lasallistas.org.mx,MG 70080106,0) [ID=6116] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016016,MANUEL FRANCISCO BORGES IB脕脩EZ,manuelborges@lasallistas.org.mx,MG 70080106,0) [ID=6117] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016116,JES脷S CARLOS BRIONES GARDU脩O,jesus.briones@lasallistas.org.mx,MG 70080106,0) [ID=6118] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,010915,GERARDO BLANCO RODR脥GUEZ,g.blancor@lasallistas.org.mx,MG 70080108,0) [ID=6119] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014626,ELISA MAR脥A DORANTES ACOSTA,,MG 70080108,0) [ID=6120] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016513,ANA CAROLINA HILL DE TITTO,ac.hill@lasallistas.org.mx,MG 70080108,0) [ID=6121] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,015171,ANTONIO CALDER脫N MOORE,a.calderonm@lasallistas.org.mx,MG 70080606,0) [ID=6122] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,000752,JOS脡 JUAN ORTEGA CERDA,jortega@lasallistas.org.mx,MG 70050601,855) [ID=6123] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,008867,URSULO JU脕REZ HERRERA,u.juarez@lasallistas.org.mx,MG 70050601,855) [ID=6124] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,016853,GUSTAVO ROJAS VELASCO,,MG 70050601,855) [ID=6125] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,008098,ISAAC ZAGA MINIAN,,MG 70090503,871) [ID=6126] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017381,JAIME ANTONIO HIDALGO CARRERA,,MG 70090903,899) [ID=6127] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,013905,MARTHA EUNICE RODR脥GUEZ ARELLANO,mera@lasallistas.org.mx,MG 70050702,854) [ID=6128] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,013878,PERLA ALICIA CARRILLO GONZ脕LEZ,perlacarrillo@lasallistas.org.mx,MG 70050702,854) [ID=6129] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,017131,ANTONIO CORONA BAUTISTA,antoniocorona@lasallistas.org.mx,MG 70070704,854) [ID=6130] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016272,ALEJANDRA CALDER脫N VALLEJO,alejandra.calderon@lasallistas.org.mx,MG 70060509,865) [ID=6131] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016950,CARLOS FREDY CUEVAS GARCIA,,MG 70060509,865) [ID=6132] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016954,JES脷S FONSECA COSIO,,MG 70060509,865) [ID=6133] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,011707,CLAUDIA ELENA MURILLO CORREA,,MG 70070502,880) [ID=6134] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,012289,脕NGEL NAVA CASTA脩EDA,,MG 70070502,880) [ID=6135] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,014180,ALMA JESSICA VARGAS ORTEGA,,MG 70070502,880) [ID=6136] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,013434,ERIKA LETICIA FERN脕NDEZ MU脩OZ,erikafernandez@lasallistas.org.mx,MG 70070403,883) [ID=6137] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,016747,ITZEL MONTSERRAT P脡REZ GUDI脩O,itzelperez@lasallistas.org.mx,MG 70070403,883) [ID=6138] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,017383,MARY LADY GONZALEZ SURIEL,,MG 70070403,883) [ID=6139] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,015425,GUILLERMO CESAR PEREZ PELAEZ,,MG 70090203,885) [ID=6140] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017378,DANIELA ALEJANDRA LEMIONET ESCANERO,,MG 70090703,860) [ID=6141] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,016830,JUAN PABLO RAMIREZ HINOJOSA,jp.ramirezh@lasallistas.org.mx,MG 70060308,887) [ID=6142] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,016881,MERCEDES ARANDA AUDELO,mercedes.aranda@lasallistas.org.mx,MG 70060308,887) [ID=6143] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,013875,ANA PATRICIA RODR脥GUEZ ZULUETA,,MG 70060308,887) [ID=6144] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,014547,MARIO SILVINO ALMANZA GONZALEZ,,MG 70080211,889) [ID=6145] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,014599,HUGO ARTURO MANZANILLA GARCIA,ha.manzanilla@lasallistas.org.mx,MG 70080211,889) [ID=6146] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,004730,MAR脥A IVONNE ARELLANO MENDOZA,mi.arellanom@lasallistas.org.mx,MG 70060305,889) [ID=6147] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,016545,MARIELA GALICIA MALDONADO,marielagalicia@lasallistas.org.mx,MG 70060305,889) [ID=6148] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,013299,ROSA MAR脥A PONCE OLIVERA,,MG 70060305,889) [ID=6149] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016259,CESAR FIRETH POZO BELTR脕N,,MG 70091003,896) [ID=6150] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Psiquiatr铆a,MD030617,016606,ADOLFO NERI HERN脕NDEZ,adolfo.neri@lasallistas.org.mx,MG 70050409,1013) [ID=6151] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Psiquiatr铆a,MD030617,015698,CARLOS HERNANDEZ VEGA,c.hv@lasallistas.org.mx,MG 70050409,1013) [ID=6152] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017310,NORMA VELIA BALLESTEROS SOLIS,norma.ballesteros@lasallistas.org.mx,MG 70093003,867) [ID=6153] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Cirug铆a (internado de pregrado),MD020317,017305,ERNESTO SALGADO SANCHEZ,,MG 70091801,1272) [ID=6154] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016280,MARIA ANOTA RIVERA,,MG 70092903,1267) [ID=6155] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Traumatolog铆a y ortopedia,MD030417,014992,RUDY DE JESUS SALAZAR PACHECO,rudysalazar@lasallistas.org.mx,MG 70070210,1004) [ID=6156] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Traumatolog铆a y ortopedia,MD030417,015451,FERNANDO ORTIZ ROJAS,fortiz@lasallistas.org.mx,MG 70070210,1004) [ID=6157] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,016568,JUAN ANTONIO LUGO GARC脥A,juanlugo@lasallistas.org.mx,MG 70080411,1004) [ID=6158] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,016818,OMAR HERNANDEZ LEON,o.hl@lasallistas.org.mx,MG 70080411,1004) [ID=6159] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016952,ERIKA GOMEZ ZAMORA,,MG 70092203,1004) [ID=6160] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,006026,RUBEN CORT脡S GONZ脕LEZ,rubencortes@lasallistas.org.mx,MG 70070206,892) [ID=6161] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,016281,NOEL SALGADO NESME,,MG 70070206,892) [ID=6162] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,016429,MAURICIO SIERRA SALAZAR,,MG 70070206,892) [ID=6163] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Gastroenterolog铆a,MD040417,012899,JORGE HERN脕NDEZ CALLEROS,,MG 70060206,892) [ID=6164] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Gastroenterolog铆a,MD040417,015294,ENRIQUE COSS ADAME,enrique.coss@lasallistas.org.mx,MG 70060206,892) [ID=6165] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neumolog铆a,MD040217,,,,MG 70050206,886) [ID=6166] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,010978,脕NGEL ANTONIO ARAUZ G脫NGORA,aa.arauz@lasallistas.org.mx,MG 70060209,884) [ID=6167] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,011794,LUIS IGNACIO MIRANDA MEDRANO,,MG 70060209,884) [ID=6168] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,013146,ADOLFO LEYVA REND脫N,,MG 70060209,884) [ID=6169] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,017123,DANIELLA ALEJANDRA MONROY LLAGUNO,daniella.monroy@lasallistas.org.mx,MG 70070205,1010) [ID=6170] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,015003,IVAN HERMANN SCHOBERT CAPETILLO,ivanschobert@lasallistas.org.mx,MG 70070205,1010) [ID=6171] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,016774,OFELIA NATSUKO TANIYAMA L脫PEZ,ofeliataniyama@lasallistas.org.mx,MG 70070205,1010) [ID=6172] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,015452,CARMEN ZAVALA GARC脥A,,MG 70090403,863) [ID=6173] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,008931,ALMA VERGARA L脫PEZ,alma.vergara@lasallistas.org.mx,MG 70050203,869) [ID=6174] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,016089,ADRIANA BALDERRAMA SOTO,a.balderrama@lasallistas.org.mx,MG 70050203,869) [ID=6175] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,008725,CARLOS HAROLDO IXCAMPARIJ ROSALES,chir@lasallistas.org.mx,MG 70050202,869) [ID=6176] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,015880,ROBERTO MURATALLA GONZ脕LEZ,,MG 70050202,869) [ID=6177] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,009026,GREGORIO ZARAGOZA RODRIGUEZ,,MG 70050202,869) [ID=6178] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Cirug铆a (internado de pregrado),MD020317,013926,ABEL FUENTES VENEGAS,abelfuentes@lasallistas.org.mx,MG 70090301,0) [ID=6179] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017238,ERIK REBOLLEDO GARDU脩O,,MG 70092803,0) [ID=6180] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017382,RODOLFO SILVA ROMO,,MG 70093103,0) [ID=6181] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017240,ROBERTO BADIR CORANGUEZ CAPISTRAN,,MG 70091603,0) [ID=6182] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016275,IV脕N ALBERTO NAJERA RODR脥GUEZ,ivan.najera@lasallistas.org.mx,MG 70093203,0) [ID=6183] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Geriatr铆a,MD030717,017243,DOMINGA ALBERTA SALOMON CORTEZ,,MG 70070601,0) [ID=6184] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina interna (internado de pregrado),MD041117,011870,NORBERTO REYES PAREDES,norbertoreyes@lasallistas.org.mx,MG 70092604,0) [ID=6185] ##SELECT * FROM fi_horario(2, 12:00:00,18:00:00,037,70,Otorrinolaringolog铆a,MD030317,010570,SERGIO IV脕N GONZ脕LEZ OLVERA,sigo@lasallistas.org.mx,MG 70070703,887) [ID=6186] ##SELECT * FROM fi_horario(2, 12:00:00,18:00:00,037,70,Otorrinolaringolog铆a,MD030317,013134,DINA FABIOLA GONZ脕LEZ S脕NCHEZ,df.gonzalezs@lasallistas.org.mx,MG 70070703,887) [ID=6187] ##SELECT * FROM fi_horario(2, 14:00:00,16:00:00,037,70,Ginecolog铆a y obstetricia (internado de pregrado),MD031217,010124,ENRIQUE JUAN D脥AZ GREENE,do_enrique.Diaz@lasallistas.org.mx,MG 70090102,855) [ID=6188] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,007232,MIGUEL VILLA GUERRERO,miguel.villa@lasallistas.org.mx,MG 70080604,0) [ID=6189] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016016,MANUEL FRANCISCO BORGES IB脕脩EZ,manuelborges@lasallistas.org.mx,MG 70080604,0) [ID=6190] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016116,JES脷S CARLOS BRIONES GARDU脩O,jesus.briones@lasallistas.org.mx,MG 70080604,0) [ID=6191] ## -2023-08-09 00:30:36||SELECT * FROM fu_horario_deshabilita(2218) ## SELECT * FROM fu_horario_deshabilita(6432) ## SELECT * FROM fu_horario_deshabilita(2345) ## SELECT * FROM fu_horario_deshabilita(2319) ## SELECT * FROM fu_horario_deshabilita(2206) ## -2023-08-09 00:30:36||SELECT * FROM fi_horario(3, '10:30:00','12:00:00','038','69','Valores y 茅tica profesional','FI020613','015060','M脫NICA RUIZ ESQUIVEL','monica.ruiz@lasalle.mx','MG 69070601',820); [ID=6634] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','036','79','La persona y su interacci贸n con los otros','PS151113','','','','MG 79030601',0); [ID=6635] ##SELECT * FROM fi_horario(3, '12:00:00','13:30:00','032','25','La persona y su interacci贸n con los otros','PS151113','','','','MG 25030201',0); [ID=6636] ##SELECT * FROM fi_horario(3, '07:15:00','08:45:00','026','68','Voleibol, b茅isbol y deportes con raqueta','DP050319','015415','HECTOR JAVIER BECERRA HUERTA','hectorbecerra@lasallistas.org.mx','MG 68030105',1208); [ID=6637] ##SELECT * FROM fi_horario(3, '07:15:00','08:45:00','026','76','Cl铆nica integral','MD102620','017501','KARIM BUCHAHIN HUESCA','','MG 76070104',1221); [ID=6638] ##SELECT * FROM fi_horario(3, '08:45:00','10:15:00','026','76','Cl铆nica integral','MD102620','017501','KARIM BUCHAHIN HUESCA','','MG 76070104',1221); [ID=6639] ##SELECT * FROM fi_horario(3, '08:45:00','10:15:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','','MG 68050102',1231); [ID=6640] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','026','76','Cl铆nica integral','MD102620','017501','KARIM BUCHAHIN HUESCA','','MG 76070104',1408); [ID=6641] ## -2023-08-09 07:00:35||SELECT * FROM fu_horario_deshabilita(6394) ## SELECT * FROM fu_horario_deshabilita(6377) ## -2023-08-09 07:00:36||SELECT * FROM fi_horario(3, '10:30:00','12:00:00','038','69','Valores y 茅tica profesional','FI020613','015060','M脫NICA RUIZ ESQUIVEL','monica.ruiz@lasalle.mx','MG 69070601',820); [ID=6642] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','036','79','La persona y su interacci贸n con los otros','PS151113','','','','MG 79030601',0); [ID=6643] ##SELECT * FROM fi_horario(3, '12:00:00','13:30:00','032','25','La persona y su interacci贸n con los otros','PS151113','','','','MG 25030201',0); [ID=6644] ##SELECT * FROM fi_horario(3, '17:15:00','18:45:00','036','45','Normatividad de la ingenier铆a civil','DE050213','017136','CARLOS S脕NCHEZ G脫MEZ','csanchezg2@lasallistas.org.mx','MG 45050103',355); [ID=6645] ##SELECT * FROM fi_horario(3, '19:00:00','20:30:00','036','45','Hidr谩ulica de canales','GH010213','014049','ILDEFONSO L脫PEZ GONZ脕LEZ','ildefonso.lopez@lasallistas.org.mx','MG 45050102',269); [ID=6646] ## -2023-08-09 13:18:01||SELECT * FROM fu_horario_deshabilita(4479) ## SELECT * FROM fu_horario_deshabilita(4241) ## SELECT * FROM fu_horario_deshabilita(4144) ## SELECT * FROM fu_horario_deshabilita(4254) ## SELECT * FROM fu_horario_deshabilita(4270) ## SELECT * FROM fu_horario_deshabilita(4175) ## SELECT * FROM fu_horario_deshabilita(4378) ## SELECT * FROM fu_horario_deshabilita(4143) ## SELECT * FROM fu_horario_deshabilita(4413) ## SELECT * FROM fu_horario_deshabilita(4267) ## SELECT * FROM fu_horario_deshabilita(4493) ## SELECT * FROM fu_horario_deshabilita(4387) ## SELECT * FROM fu_horario_deshabilita(4395) ## SELECT * FROM fu_horario_deshabilita(4463) ## SELECT * FROM fu_horario_deshabilita(4558) ## SELECT * FROM fu_horario_deshabilita(4919) ## SELECT * FROM fu_horario_deshabilita(4850) ## SELECT * FROM fu_horario_deshabilita(4890) ## SELECT * FROM fu_horario_deshabilita(4814) ## SELECT * FROM fu_horario_deshabilita(4791) ## SELECT * FROM fu_horario_deshabilita(4821) ## SELECT * FROM fu_horario_deshabilita(4695) ## SELECT * FROM fu_horario_deshabilita(4350) ## SELECT * FROM fu_horario_deshabilita(4253) ## SELECT * FROM fu_horario_deshabilita(4860) ## SELECT * FROM fu_horario_deshabilita(4851) ## SELECT * FROM fu_horario_deshabilita(4829) ## SELECT * FROM fu_horario_deshabilita(4354) ## SELECT * FROM fu_horario_deshabilita(4873) ## SELECT * FROM fu_horario_deshabilita(4774) ## SELECT * FROM fu_horario_deshabilita(4729) ## SELECT * FROM fu_horario_deshabilita(4574) ## SELECT * FROM fu_horario_deshabilita(4132) ## SELECT * FROM fu_horario_deshabilita(4242) ## SELECT * FROM fu_horario_deshabilita(4465) ## SELECT * FROM fu_horario_deshabilita(4928) ## SELECT * FROM fu_horario_deshabilita(4909) ## SELECT * FROM fu_horario_deshabilita(4221) ## SELECT * FROM fu_horario_deshabilita(4657) ## SELECT * FROM fu_horario_deshabilita(4109) ## SELECT * FROM fu_horario_deshabilita(4656) ## -2023-08-09 13:18:01||SELECT * FROM fi_horario(5, '07:15:00','08:45:00','034','33','M茅todos y t茅cnicas de las ciencias sociales','IN030315','014502','LEONARDO DANIEL S脕NCHEZ ROJAS','ldsr@lasallistas.org.mx','MG 33010207',1027); [ID=6847] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','033','85','Razonamiento cr铆tico cuantitativo','MA021021','016603','CIPACTLI MILL脕N GARC脥A','cipactlimillan@lasallistas.org.mx','MG 85010107',1084); [ID=6848] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','033','81','Geometr铆a del plano','MA070317','016967','ALFONSO HERNANDEZ MONTES','alfonso.hernandez@lasallistas.org.mx','MG 81010105',746); [ID=6849] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','033','81','C谩lculo diferencial','MA022717','015889','GUADALUPE GAYT脕N G脫MEZ','g.gaytang@lasallistas.org.mx','MG 81010202',748); [ID=6850] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','036','79','Dise帽o l贸gico','ET020120','002307','MANUEL REYES VILLA','m.reyes@lasallistas.org.mx','MG 79030104',456); [ID=6851] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','016616','DANIEL OCHOA RODR脥GUEZ','d.ochoa@lasallistas.org.mx','MG 23070104',1044); [ID=6852] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','015078','LUIS MIGUEL RODR脥GUEZ MORENO','rodriguez.luis@lasallistas.org.mx','MG 23070201',1044); [ID=6853] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','034','33','M茅xico en el siglo XIX','HI051115','','','','MG 33010208',1027); [ID=6854] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','034','33','Estados Unidos y Canad谩: pol铆tica y gobierno','GE051515','017318','MICHELLE CALDER脫N GARC脥A','michelle.calderon@lasallistas.org.mx','MG 33020103',1028); [ID=6855] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','85','Contabilidad administrativa','CO010121','016602','F脕TIMA MONTSERRAT GONZ脕LEZ RIVERA','fatima.gonzalez@lasallistas.org.mx','MG 85010103',1084); [ID=6856] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','85','Razonamiento cr铆tico cuantitativo','MA021021','016603','CIPACTLI MILL脕N GARC脥A','cipactlimillan@lasallistas.org.mx','MG 85010207',1085); [ID=6857] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','81','Fundamentos de 谩lgebra','MA060917','015012','MARIA SOLEDAD ARRIAGA','msoledad.arriaga@lasallistas.org.mx','MG 81010104',746); [ID=6858] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','81','Geometr铆a del plano','MA070317','015939','MAURICIO ALEXANDER BARRERA CEBALLOS','mauricio.barrera@lasalle.mx','MG 81010205',753); [ID=6859] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','036','74','Manufactura b谩sica','TM020120','016421','ERICK RAM脥REZ AGUILAR','erick.ramirez@lasalle.mx','MG 74030105',453); [ID=6860] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','011212','ENRIQUE MANUEL ADALID TEJA','enrique.adalid@lasallistas.org.mx','MG 23070104',1044); [ID=6861] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','036','75','Introducci贸n a los componentes mecatr贸nicos','MT010320','016923','MANUEL ELADIO HUNTER SANCHEZ','manuel.hunter@lasallistas.org.mx','MG 75020106',0); [ID=6862] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','033','85','Microeconom铆a','EC010621','016801','GERARDO ERNESTO CASTRO GIL','gerardo.castro@lasallistas.org.mx','MG 85010205',1085); [ID=6863] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','033','96','Campo profesional de los negocios','AD011617','017281','JUAN MIGUEL FELICIANO VEGA HERNANDEZ','jvega@lasallistas.org.mx','MG 96010103',1088); [ID=6864] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','032','28','Laboratorio de morfolog铆a y energ铆a','DI020417','016340','M脫NICA P脡REZ B脕EZ','m-pb@lasallistas.org.mx','MG 28030202',342); [ID=6865] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','033','81','Fundamentos de 谩lgebra','MA060917','015012','MARIA SOLEDAD ARRIAGA','msoledad.arriaga@lasallistas.org.mx','MG 81010204',753); [ID=6866] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','80','Pr谩cticas hospitalarias','PU070113','014278','SANDRA LUZ ROCHA NAVA','sandrarocha@lasallistas.org.mx','MG 80090205',1010); [ID=6867] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','80','Pr谩cticas hospitalarias','PU070113','015987','MARIA DEL CARMEN ARQUER RUIZ','maria.arquer@lasallistas.org.mx','MG 80090105',1010); [ID=6868] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','79','Electr贸nica e interfaces aplicadas a la rob贸tica','ET020620','007878','MAURICIO ALBERTO MART脥NEZ GARC脥A','mauricio.martinez@lasallistas.org.mx','MG 79030106',456); [ID=6869] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','78','Termodin谩mica','EN020413','013557','GABRIELA MAC脥AS ESQUIVEL','gabriela.macias@lasalle.mx','MG 78040105',455); [ID=6870] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','79','Dise帽o l贸gico','ET020120','009273','OCTAVIO RODR脥GUEZ TORRES','octavio.rodriguez@lasalle.mx','MG 79030204',454); [ID=6871] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','014917','VERONICA MARTINEZ ROBLES','veronica.martinez@lasallistas.org.mx','MG 23070104',1044); [ID=6872] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','015084','LILIANA TERESA PEREZ SANCHEZ','liliana.perez@lasallistas.org.mx','MG 23070201',1044); [ID=6873] ##SELECT * FROM fi_horario(5, '10:30:00','13:30:00','038','69','Laboratorio b谩sico de ciencias','IN040415','012651','MAR脥A PIEDAD L脫PEZ ORTAL','piedad.lopez@lasalle.mx','MG 69010801',820); [ID=6874] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','033','81','Teor铆a del seguro','CO110117','016185','脕NGEL CUEVAS ROMERO','angel.cuevas@lasallistas.org.mx','MG 81010106',1085); [ID=6875] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','033','96','Campo profesional de los negocios','AD011617','017281','JUAN MIGUEL FELICIANO VEGA HERNANDEZ','jvega@lasallistas.org.mx','MG 96010203',852); [ID=6876] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','033','85','Conformaci贸n legal de los negocios','DE050121','014307','JORGE MART脥NEZ CRUZ','jorge.martinez@lasallistas.org.mx','MG 85010202',1088); [ID=6877] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','80','Pr谩cticas hospitalarias','PU070113','015112','JOS脡 ISRAEL HERN脕NDEZ OROPEZA','jose.hernandez@lasalle.mx','MG 80090205',1010); [ID=6878] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','80','Pr谩cticas hospitalarias','PU070113','015987','MARIA DEL CARMEN ARQUER RUIZ','maria.arquer@lasallistas.org.mx','MG 80090105',1010); [ID=6879] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','46','Termodin谩mica','EN020420','013557','GABRIELA MAC脥AS ESQUIVEL','gabriela.macias@lasalle.mx','MG 46030107',455); [ID=6880] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','79','Electr贸nica e interfaces aplicadas a la rob贸tica','ET020620','007878','MAURICIO ALBERTO MART脥NEZ GARC脥A','mauricio.martinez@lasallistas.org.mx','MG 79030206',454); [ID=6881] ##SELECT * FROM fi_horario(5, '13:30:00','15:00:00','026','29','Fisiolog铆a del ejercicio','MD093017','016883','LEONARDO LEBIB AZAR HERNANDEZ','leonardo.azar@lasallistas.org.mx','MG 29020103',1231); [ID=6882] ##SELECT * FROM fi_horario(5, '13:30:00','16:30:00','026','29','Seminario de bio茅tica','FI021013','015060','M脫NICA RUIZ ESQUIVEL','monica.ruiz@lasalle.mx','MG 29070206',820); [ID=6883] ##SELECT * FROM fi_horario(5, '13:30:00','15:00:00','036','75','Manufactura integrada por computadora','TM020413','','','','MG 75090201',0); [ID=6884] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','96','Teor铆a de juegos','MA044517','014794','LUIS ANTONIO ANDRADE ROSAS','luis.andrade@lasalle.mx','MG 96060106',843); [ID=6885] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','038','77','Lengua extranjera I','LI020113','015808','KYOKO MASAKI','k.masaki@lasallistas.org.mx','MG 77030107',566); [ID=6886] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','96','Seminario y an谩lisis de casos de negocios en 谩mbitos locales','AD031717','014365','JOSE MANUEL RIVERA ZARAGOZA','jm.riveraz@lasallistas.org.mx','MG 96070108',186); [ID=6887] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','18','Administraci贸n de la mercadotecnia de productos y servicios','ME030717','016970','ADRIAN RENE SALAZAR PINEDA','adrian.salazar@lasallistas.org.mx','MG 18070102',1088); [ID=6888] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','036','79','Tecnolog铆as de redes convergentes','CE030713','','','','MG 79090211',841); [ID=6889] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','036','46','Automatizaci贸n industrial','MT010213','017008','ALEXIS ADRIAN ORTIZ OLVERA','alexis.ortiz@lasallistas.org.mx','MG 46070102',466); [ID=6890] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','034','32','Amparo','DE121615','014984','MARIO MEJIA KARGL','mariomejia@lasallistas.org.mx','MG 32070102',145); [ID=6891] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','016615','SERGIO ENRIQUE L脫PEZ JACOB','sergiolopez@lasallistas.org.mx','MG 23080201',1044); [ID=6892] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','014674','LISSETT YADIRA SERRA GORJON','lissetserra@lasallistas.org.mx','MG 23080104',1044); [ID=6893] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','017418','HELENA ROLDAN GONZALEZ','helenaroldan@lasallistas.org.mx','MG 23080301',1044); [ID=6894] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','033','07','An谩lisis del comportamiento del consumidor','ME020117','013458','ARTURO CUEVAS MART脥NEZ','arturo.cuevas@lasalle.mx','MG 07070201',187); [ID=6895] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','034','32','Teor铆a del derecho','DE010915','017143','RICARDO LEON CARAVEO','ricardo.leon@lasallistas.org.mx','MG 32010407',177); [ID=6896] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','034','32','Sistemas jur铆dicos contempor谩neos','DE011015','013940','EDITH GUZM脕N V脕ZQUEZ','egv@lasallistas.org.mx','MG 32030304',171); [ID=6897] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','033','96','Seminario y an谩lisis de casos de negocios en 谩mbitos locales','AD031717','014365','JOSE MANUEL RIVERA ZARAGOZA','jm.riveraz@lasallistas.org.mx','MG 96070207',748); [ID=6898] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','036','79','Modelos determin铆sticos y estoc谩sticos','PC030313','013909','脕NGEL ALFONSO D脥AZ GONZ脕LEZ','angel.diaz@lasalle.mx','MG 79070104',353); [ID=6899] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','036','79','Miner铆a de datos e inteligencia de negocios','IC020913','','','','MG 79090209',842); [ID=6900] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','036','04','Procesamiento digital de se帽ales','CE040413','007878','MAURICIO ALBERTO MART脥NEZ GARC脥A','mauricio.martinez@lasallistas.org.mx','MG 04070103',457); [ID=6901] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','015621','GUSTAVO D脥AZ ESPINOSA','gustavodiaz@lasallistas.org.mx','MG 23080201',1044); [ID=6902] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','011212','ENRIQUE MANUEL ADALID TEJA','enrique.adalid@lasallistas.org.mx','MG 23080104',1044); [ID=6903] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','016362','MIGUEL FEDERICO MURGU脥A D脥AZ','miguelmurguia@lasallistas.org.mx','MG 23080301',1044); [ID=6904] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','036','75','Fe y desarrollo espiritual','PS151213','','','','MG 75050101',0); [ID=6905] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','033','07','Estructura de marca','ME040615','017522','CRISTINA YAZM脥N FERN脕NDEZ RODR脥GUEZ','cristina.fernandez@lasallistas.org.mx','MG 07070204',1093); [ID=6906] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','45','Resistencia de materiales','FS020513','016243','JOS脡 ANTONIO ROSALES ALANIZ','ja.rosales@lasallistas.org.mx','MG 45050104',355); [ID=6907] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','79','Gesti贸n de proyectos de tecnolog铆as de la informaci贸n y centros de datos','AD051213','008444','JAIME ROBERTO GONZ脕LEZ HERN脕NDEZ','jaime.gonzalez@lasallistas.org.mx','MG 79090106',841); [ID=6908] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','79','Aplicaciones m贸viles','IC031813','017335','FELIPE MANDUJANO G脫MEZ','felipe.mandujano@lasallistas.org.mx','MG 79090202',842); [ID=6909] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','79','Taller de conectividad','CE030613','011759','RA脷L ALBERTO CHAVEZ ARREOLA','raul.chavez@lasallistas.org.mx','MG 79070106',1180); [ID=6910] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','75','Dise帽o l贸gico','ET020113','009273','OCTAVIO RODR脥GUEZ TORRES','octavio.rodriguez@lasalle.mx','MG 75060103',457); [ID=6911] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','75','Automatizaci贸n industrial','MT010213','017128','ADRIAN LOPEZ SILVA','adrianlopez@lasallistas.org.mx','MG 75070102',466); [ID=6912] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','038','69','Qu铆mica criminal铆stica','BI071315','013723','VELIA IZCHEL REYES GONZ脕LEZ','velia.reyes@lasallistas.org.mx','MG 69090109',770); [ID=6913] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','033','07','Mercadotecnia social y de servicios','ME030217','','','','MG 07050105',260); [ID=6914] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','014672','JAVIER ISRAEL RAMIREZ SANCHEZ','israel.ramirez@lasallistas.org.mx','MG 23080201',1044); [ID=6915] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','016616','DANIEL OCHOA RODR脥GUEZ','d.ochoa@lasallistas.org.mx','MG 23080104',1044); [ID=6916] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','016795','JUAN ANTONIO MORENO GONZALEZ','ja.mg@lasallistas.org.mx','MG 23080301',1044); [ID=6917] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','033','07','Estructura de marca','ME040615','017522','CRISTINA YAZM脥N FERN脕NDEZ RODR脥GUEZ','cristina.fernandez@lasallistas.org.mx','MG 07070204',1093); [ID=6918] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','034','33','Justicia alternativa','DE122415','014734','MARIA CECILIA MENA PANTOJA','mc.mena@lasallistas.org.mx','MG 33080104',1038); [ID=6919] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','036','79','Gesti贸n de proyectos de tecnolog铆as de la informaci贸n y centros de datos','AD051213','008444','JAIME ROBERTO GONZ脕LEZ HERN脕NDEZ','jaime.gonzalez@lasallistas.org.mx','MG 79090207',841); [ID=6920] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','036','75','Principios de electr贸nica anal贸gica','ET010713','016170','JOSE DE JESUS GUTIERREZ CORTES','jgutierrez@lasallistas.org.mx','MG 75050203',456); [ID=6921] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','036','75','Automatizaci贸n industrial','MT010213','017128','ADRIAN LOPEZ SILVA','adrianlopez@lasallistas.org.mx','MG 75070202',466); [ID=6922] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','033','96','Procesos estoc谩sticos','MA044417','017528','IREN CASTILLO SALDA脩A','','MG 96050107',229); [ID=6923] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','033','07','Mercadotecnia social y de servicios','ME030217','','','','MG 07050205',264); [ID=6924] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','038','65','Ingenier铆a econ贸mica','EC020515','017517','REGINA MONTSERRAT CANALS LOPEZ VELARDE','rlopezv2@lasallistas.org.mx','MG 65070104',1308); [ID=6925] ##SELECT * FROM fi_horario(5, '07:00:00','08:30:00','037','70','Psicolog铆a m茅dica','PS060217','','','','MG 70010107',319); [ID=6926] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','007232','MIGUEL VILLA GUERRERO','miguel.villa@lasallistas.org.mx','MG 70080505',0); [ID=6927] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','016016','MANUEL FRANCISCO BORGES IB脕脩EZ','manuelborges@lasallistas.org.mx','MG 70080505',0); [ID=6928] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','016116','JES脷S CARLOS BRIONES GARDU脩O','jesus.briones@lasallistas.org.mx','MG 70080505',0); [ID=6929] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Pediatr铆a','MD030817','010577','MONICA VILLA GUILLEN','m.mvg@lasallistas.org.mx','MG 70080702',0); [ID=6930] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Pediatr铆a','MD030817','016599','CARLOS PATRICIO ACOSTA RODR脥GUEZ BUENO','cp.acosta@lasallistas.org.mx','MG 70080702',0); [ID=6931] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Pediatr铆a','MD030817','014626','ELISA MAR脥A DORANTES ACOSTA','','MG 70080702',0); [ID=6932] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','010124','ENRIQUE JUAN D脥AZ GREENE','do_enrique.Diaz@lasallistas.org.mx','MG 70090106',855); [ID=6933] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','008098','ISAAC ZAGA MINIAN','','MG 70090506',871); [ID=6934] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017381','JAIME ANTONIO HIDALGO CARRERA','','MG 70090906',899); [ID=6935] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Dermatolog铆a','MD030517','017105','MAR脥A TERESA BARR脫N TAPIA','maria.barron@lasallistas.org.mx','MG 70060702',854); [ID=6936] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Endocrinolog铆a','MD040717','013905','MARTHA EUNICE RODR脥GUEZ ARELLANO','mera@lasallistas.org.mx','MG 70050502',854); [ID=6937] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Endocrinolog铆a','MD040717','013878','PERLA ALICIA CARRILLO GONZ脕LEZ','perlacarrillo@lasallistas.org.mx','MG 70050502',854); [ID=6937] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Patolog铆a quir煤rgica','MD020217','017131','ANTONIO CORONA BAUTISTA','antoniocorona@lasallistas.org.mx','MG 70070504',854); [ID=6938] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','015425','GUILLERMO CESAR PEREZ PELAEZ','','MG 70090206',885); [ID=6939] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017378','DANIELA ALEJANDRA LEMIONET ESCANERO','','MG 70090706',860); [ID=6940] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Otorrinolaringolog铆a','MD030317','010570','SERGIO IV脕N GONZ脕LEZ OLVERA','sigo@lasallistas.org.mx','MG 70070503',887); [ID=6941] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Otorrinolaringolog铆a','MD030317','013134','DINA FABIOLA GONZ脕LEZ S脕NCHEZ','df.gonzalezs@lasallistas.org.mx','MG 70070503',887); [ID=6941] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Dermatolog铆a','MD030517','004730','MAR脥A IVONNE ARELLANO MENDOZA','mi.arellanom@lasallistas.org.mx','MG 70060505',889); [ID=6942] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Dermatolog铆a','MD030517','016545','MARIELA GALICIA MALDONADO','marielagalicia@lasallistas.org.mx','MG 70060505',889); [ID=6942] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Dermatolog铆a','MD030517','013299','ROSA MAR脥A PONCE OLIVERA','','MG 70060505',889); [ID=6942] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','016259','CESAR FIRETH POZO BELTR脕N','','MG 70091006',896); [ID=6943] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Psiquiatr铆a','MD030617','016606','ADOLFO NERI HERN脕NDEZ','adolfo.neri@lasallistas.org.mx','MG 70050704',1013); [ID=6944] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Psiquiatr铆a','MD030617','015698','CARLOS HERNANDEZ VEGA','c.hv@lasallistas.org.mx','MG 70050704',1013); [ID=6944] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017310','NORMA VELIA BALLESTEROS SOLIS','norma.ballesteros@lasallistas.org.mx','MG 70093006',1012); [ID=6945] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017062','ERNESTO FIGUEROA TELLEZ','','MG 70091806',1272); [ID=6946] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','016280','MARIA ANOTA RIVERA','','MG 70092906',1267); [ID=6947] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Traumatolog铆a y ortopedia','MD030417','014130','SERGIO G脫MEZ LLATA GARC脥A','s.gomezl@lasallistas.org.mx','MG 70070608',1004); [ID=6948] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Traumatolog铆a y ortopedia','MD030417','015181','MANUEL ALEJANDRO AGUILAR ARAIZA','manuel.aguilar@lasallistas.org.mx','MG 70070608',1004); [ID=6948] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Traumatolog铆a y ortopedia','MD030417','014136','LEOBARDO GUERRERO BELTRAN','leobardo.guerrero@lasallistas.org.mx','MG 70070608',1004); [ID=6948] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','016952','ERIKA GOMEZ ZAMORA','','MG 70092206',1004); [ID=6949] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Gastroenterolog铆a','MD040417','012899','JORGE HERN脕NDEZ CALLEROS','','MG 70060606',892); [ID=6950] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Gastroenterolog铆a','MD040417','015294','ENRIQUE COSS ADAME','enrique.coss@lasallistas.org.mx','MG 70060606',892); [ID=6950] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Infectolog铆a','MD040917','014138','ARTURO GALINDO FRAGA','arturo.galindo@lasallistas.org.mx','MG 70060608',892); [ID=6951] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Infectolog铆a','MD040917','016584','MAR脥A FERNANDA GONZ脕LEZ LARA','','MG 70060608',892); [ID=6951] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Infectolog铆a','MD040917','015231','ERIC OCHOA HEIN','eric.ochoa@lasallistas.org.mx','MG 70060608',892); [ID=6951] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Neumolog铆a','MD040217','013617','PATRICIA CASTILLO GONZ脕LEZ','patricia.castillo@lasallistas.org.mx','MG 70050605',886); [ID=6952] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Neumolog铆a','MD040217','015554','TERESA DE JESUS AGUIRRE PEREZ','teresa.aguirre@lasallistas.org.mx','MG 70050605',886); [ID=6952] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Neumolog铆a','MD040217','016098','SERGIO MONRAZ PEREZ','','MG 70050605',886); [ID=6952] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','015452','CARMEN ZAVALA GARC脥A','','MG 70090406',863); [ID=6953] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Cardiolog铆a','MD040117','008725','CARLOS HAROLDO IXCAMPARIJ ROSALES','chir@lasallistas.org.mx','MG 70050501',869); [ID=6954] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Cardiolog铆a','MD040117','015880','ROBERTO MURATALLA GONZ脕LEZ','','MG 70050501',869); [ID=6954] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Cardiolog铆a','MD040117','009026','GREGORIO ZARAGOZA RODRIGUEZ','','MG 70050501',869); [ID=6954] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017240','ROBERTO BADIR CORANGUEZ CAPISTRAN','','MG 70091606',0); [ID=6955] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','011870','NORBERTO REYES PAREDES','norbertoreyes@lasallistas.org.mx','MG 70092606',0); [ID=6956] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017238','ERIK REBOLLEDO GARDU脩O','','MG 70092806',0); [ID=6957] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017382','RODOLFO SILVA ROMO','','MG 70093106',0); [ID=6958] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Medicina familiar y comunitaria (internado de pregrado)','MD031417','013926','ABEL FUENTES VENEGAS','abelfuentes@lasallistas.org.mx','MG 70090303',0); [ID=6959] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','','MG 68050102',0); [ID=6960] ##SELECT * FROM fi_horario(5, '11:00:00','16:00:00','037','70','Proped茅utica cl铆nica y nosolog铆a','MD010417','010124','ENRIQUE JUAN D脥AZ GREENE','do_enrique.Diaz@lasallistas.org.mx','MG 70040504',0); [ID=6961] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','','MG 68050102',0); [ID=6962] ##SELECT * FROM fi_horario(5, '16:00:00','18:00:00','037','70','Oncolog铆a','MD031017','009308','FRANCISCO MARIO GARC脥A RODR脥GUEZ','','MG 70050108',0); [ID=6963] ##SELECT * FROM fi_horario(5, '16:00:00','18:00:00','037','70','Sexualidad humana','MD041217','017258','OSCAR JES脷S CU脡LLAR GONZ脕LEZ','oscar.cuellar@lasallistas.org.mx','MG 70080608',0); [ID=6964] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Oncolog铆a','MD031017','009308','FRANCISCO MARIO GARC脥A RODR脥GUEZ','','MG 70050408',0); [ID=6965] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Oncolog铆a','MD031017','','','','MG 70050308',0); [ID=6966] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Sexualidad humana','MD041217','017258','OSCAR JES脷S CU脡LLAR GONZ脕LEZ','oscar.cuellar@lasallistas.org.mx','MG 70080509',0); [ID=6967] ## -2023-08-09 18:52:17||SELECT * FROM fu_horario_deshabilita(2826) ## SELECT * FROM fu_horario_deshabilita(2552) ## SELECT * FROM fu_horario_deshabilita(6406) ## SELECT * FROM fu_horario_deshabilita(2530) ## -2023-08-09 18:52:17||SELECT * FROM fi_horario(3, '07:15:00','08:45:00','032','23','Taller de composici贸n pl谩stica y expresi贸n','AR020322','016889','TANIA SABRINA ORTIZ RAMIREZ','tania-ortiz@lasallistas.org.mx','MG 23011002',0); [ID=6968] ##SELECT * FROM fi_horario(3, '07:15:00','08:45:00','032','23','Taller de composici贸n pl谩stica y expresi贸n','AR020322','016325','ANDREA MONROY BRAHAM','andreamonroy@lasallistas.org.mx','MG 23010902',0); [ID=6969] ##SELECT * FROM fi_horario(3, '08:45:00','10:15:00','032','23','Principios b谩sicos de construcci贸n','CI020122','014672','JAVIER ISRAEL RAMIREZ SANCHEZ','israel.ramirez@lasallistas.org.mx','MG 23010506',0); [ID=6970] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','038','69','Valores y 茅tica profesional','FI020613','015060','M脫NICA RUIZ ESQUIVEL','monica.ruiz@lasalle.mx','MG 69070601',820); [ID=6971] ##SELECT * FROM fi_horario(3, '10:30:00','13:30:00','032','23','Laboratorio de an谩lisis','AR021022','015622','KARINA CONTRERAS CASTELLANOS','k.contreras@lasallistas.org.mx','MG 23011501',0); [ID=6972] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','036','79','La persona y su interacci贸n con los otros','PS151113','','','','MG 79030601',0); [ID=6973] ##SELECT * FROM fi_horario(3, '10:30:00','13:30:00','032','23','Laboratorio de an谩lisis','AR021022','016889','TANIA SABRINA ORTIZ RAMIREZ','tania-ortiz@lasallistas.org.mx','MG 23011601',0); [ID=6974] ##SELECT * FROM fi_horario(3, '12:00:00','13:30:00','032','25','La persona y su interacci贸n con los otros','PS151113','','','','MG 25030201',0); [ID=6975] ##SELECT * FROM fi_horario(3, '13:30:00','15:00:00','032','84','Imaginarios en el arte','AH010722','017111','MARICELA GABRIELA BERMEO CASTREJ脫N','maricela.bermeo@lasallistas.org.mx','MG 84010105',350); [ID=6976] ##SELECT * FROM fi_horario(3, '13:30:00','15:00:00','032','23','Dibujo arquitect贸nico','EX010322','017291','IGNACIO ANAYA HERNANDEZ','ignacio.anaya@lasallistas.org.mx','MG 23010703',0); [ID=6977] ##SELECT * FROM fi_horario(3, '15:45:00','17:15:00','032','23','Geometr铆a descriptiva','EX030122','016981','DORITA HERAS MONTES DE OCA','dorita.heras@lasallistas.org.mx','MG 23010704',0); [ID=6978] ##SELECT * FROM fi_horario(3, '17:15:00','18:45:00','033','18','Aplicaciones tecnol贸gicas especializadas','IC090217','016203','DANIEL MORENO JIMENEZ','danielmoreno@lasallistas.org.mx','MG 18040103',1182); [ID=6979] ##SELECT * FROM fi_horario(3, '20:30:00','22:00:00','035','99','Introducci贸n a la biblia y bases de ex茅gesis','TE030321','','','','MG 99010102',820); [ID=6980] ##SELECT * FROM fi_horario(3, '08:00:00','14:00:00','037','70','Geriatr铆a','MD030717','017513','OMAR WILLIAM GONZ脕LEZ HERN脕NDEZ','','MG 70070302',0); [ID=6981] ##SELECT * FROM fi_horario(3, '08:00:00','14:00:00','037','70','Psiquiatr铆a','MD030617','017489','C脡SAR AUGUSTO CELADA BORJA','','MG 70050309',0); [ID=6982] ##SELECT * FROM fi_horario(3, '12:00:00','14:00:00','037','70','Fisiolog铆a II','BI031017','016768','V脥CTOR MANUEL RODR脥GUEZ MOLINA','rodriguez.victor@lasallistas.org.mx','MG 70030206',0); [ID=6983] ##SELECT * FROM fi_horario(3, '14:00:00','15:30:00','037','70','Desarrollo del razonamiento cl铆nico','MD110417','017488','GABRIELA DE LA GUARDIA GONZ脕LEZ','gabrielade@lasallistas.org.mx','MG 70041002',0); [ID=6984] ## -2023-08-10 10:35:22||SELECT * FROM fu_horario_deshabilita(6881) ## SELECT * FROM fu_horario_deshabilita(6862) ## SELECT * FROM fu_horario_deshabilita(6871) ## SELECT * FROM fu_horario_deshabilita(4660) ## SELECT * FROM fu_horario_deshabilita(4620) ## SELECT * FROM fu_horario_deshabilita(4553) ## SELECT * FROM fu_horario_deshabilita(4765) ## SELECT * FROM fu_horario_deshabilita(4153) ## SELECT * FROM fu_horario_deshabilita(6962) ## SELECT * FROM fu_horario_deshabilita(6960) ## -2023-08-10 10:35:22||SELECT * FROM fi_horario(5, '07:15:00','08:45:00','032','27','Composici贸n tipogr谩fica','DG030415','','','','MG 27030204',348); [ID=7001] ##SELECT * FROM fi_horario(5, '07:15:00','10:15:00','032','23','Geometr铆a descriptiva','EX030122','016981','DORITA HERAS MONTES DE OCA','dorita.heras@lasallistas.org.mx','MG 23010704',0); [ID=7002] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','036','75','Introducci贸n a los componentes mecatr贸nicos','MT010320','016923','MANUEL ELADIO HUNTER SANCHEZ','manuel.hunter@lasallistas.org.mx','MG 75020106',261); [ID=7003] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','79','Dise帽o l贸gico','ET020120','009273','OCTAVIO RODR脥GUEZ TORRES','octavio.rodriguez@lasalle.mx','MG 79030204',457); [ID=7004] ##SELECT * FROM fi_horario(5, '10:30:00','13:30:00','032','23','Taller de composici贸n pl谩stica y expresi贸n','AR020322','016325','ANDREA MONROY BRAHAM','andreamonroy@lasallistas.org.mx','MG 23010902',0); [ID=7005] ##SELECT * FROM fi_horario(5, '10:30:00','13:30:00','032','23','Taller de composici贸n pl谩stica y expresi贸n','AR020322','016889','TANIA SABRINA ORTIZ RAMIREZ','tania-ortiz@lasallistas.org.mx','MG 23011002',0); [ID=7006] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','79','Electr贸nica e interfaces aplicadas a la rob贸tica','ET020620','007878','MAURICIO ALBERTO MART脥NEZ GARC脥A','mauricio.martinez@lasallistas.org.mx','MG 79030206',456); [ID=7007] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','036','04','Ingenier铆a de manufactura','TM020513','016862','MARIA FERNANDA TOLEDO ROMO','maria.toledo@lasallistas.org.mx','MG 04070102',453); [ID=7008] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','035','99','Eclesiolog铆a dogm谩tica','TE050621','015717','JULIO C脡SAR CARBAJAL MONTA脩O','juliocarbajal@lasallistas.org.mx','MG 99050101',1064); [ID=7009] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Geriatr铆a','MD030717','017513','OMAR WILLIAM GONZ脕LEZ HERN脕NDEZ','','MG 70070701',0); [ID=7010] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','japciri.fuentes@lasallistas.org.mx','MG 68050102',1209); [ID=7011] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','japciri.fuentes@lasallistas.org.mx','MG 68050102',1209); [ID=7012] ## -2023-08-11 14:35:03||SELECT * FROM fu_horario_deshabilita(4959) ## -2023-08-11 14:35:03||SELECT * FROM fi_horario(6, '07:15:00','08:45:00','036','45','Administraci贸n de proyectos','AD051113','015838','SERGIO ABEL GARC脥A CARRERA','sa-gc@lasallistas.org.mx','MG 45090101',226); [ID=7019] ##SELECT * FROM fi_horario(6, '07:45:00','09:15:00','034','32','Taller de proyecto profesional ocupacional','AD100313','','','','MG 32100101',820); [ID=7020] ##SELECT * FROM fi_horario(6, '07:45:00','09:15:00','033','09','Taller de empleo, autoempleo y actividad empresarial','AD100213','','','','MG 09070601',820); [ID=7021] ##SELECT * FROM fi_horario(6, '07:45:00','09:15:00','032','28','Emprendimiento y sustentabilidad','AD100113','','','','MG 28050301',820); [ID=7022] ##SELECT * FROM fi_horario(6, '08:00:00','12:30:00','038','69','Lengua extranjera I','LI020113','010262','DANIEL SANTILLANA GARC脥A','daniel.santillana@lasallistas.org.mx','MG 69030107',229); [ID=7023] ##SELECT * FROM fi_horario(6, '08:00:00','12:30:00','036','74','Lengua extranjera I','LI020113','013095','JOSUE RICARDO KOCH CALDERON','jkochc2@lasallistas.org.mx','MG 74040501',260); [ID=7024] ##SELECT * FROM fi_horario(6, '08:45:00','10:15:00','036','45','Seminario de an谩lisis de obras','OI020213','014928','ERNESTO RAMIREZ CORNEJO','ernesto.ramirez@lasallistas.org.mx','MG 45090107',226); [ID=7025] ##SELECT * FROM fi_horario(6, '08:45:00','10:15:00','036','45','Sistemas constructivos y concursos de obra','CI010313','017136','CARLOS S脕NCHEZ G脫MEZ','csanchezg2@lasallistas.org.mx','MG 45050105',396); [ID=7026] ##SELECT * FROM fi_horario(6, '08:45:00','10:15:00','036','45','Construcci贸n pesada','CI020213','016756','JOS脡 ANGEL LUNA RUIZ','ja.lunar@lasallistas.org.mx','MG 45070102',397); [ID=7027] ##SELECT * FROM fi_horario(6, '09:30:00','11:00:00','033','09','Taller de empleo, autoempleo y actividad empresarial','AD100213','','','','MG 09070601',820); [ID=7028] ##SELECT * FROM fi_horario(6, '09:30:00','11:00:00','032','28','Emprendimiento y sustentabilidad','AD100113','','','','MG 28050301',820); [ID=7029] ##SELECT * FROM fi_horario(6, '09:30:00','11:00:00','034','32','Taller de proyecto profesional ocupacional','AD100313','','','','MG 32100101',0); [ID=7030] ##SELECT * FROM fi_horario(6, '15:00:00','17:00:00','035','37','Taller de empleo, autoempleo y actividad empresarial','AD100213-D','012365','ALAIN LOREDO 脕LVAREZ','alainloredo@lasallistas.org.mx','MG 37090101',820); [ID=7031] ##SELECT * FROM fi_horario(6, '16:00:00','18:00:00','035','37','Procesos y expresi贸n del pensamiento','PS050213-D','015271','C脡SAR FRANCISCO CANT脫N RAMOS','cesar.canton@lasallistas.org.mx','MG 37010101',820); [ID=7032] ##SELECT * FROM fi_horario(6, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','007232','MIGUEL VILLA GUERRERO','miguel.villa@lasallistas.org.mx','MG 70080505',0); [ID=7033] ##SELECT * FROM fi_horario(6, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','016016','MANUEL FRANCISCO BORGES IB脕脩EZ','manuelborges@lasallistas.org.mx','MG 70080505',0); [ID=7034] ##SELECT * FROM fi_horario(6, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','016116','JES脷S CARLOS BRIONES GARDU脩O','jesus.briones@lasallistas.org.mx','MG 70080505',0); [ID=7035] ## -2023-08-17 11:12:59||SELECT * FROM fu_horario_deshabilita(4130) ## SELECT * FROM fu_horario_deshabilita(4239) ## SELECT * FROM fu_horario_deshabilita(4296) ## SELECT * FROM fu_horario_deshabilita(4349) ## SELECT * FROM fu_horario_deshabilita(4418) ## SELECT * FROM fu_horario_deshabilita(4501) ## SELECT * FROM fu_horario_deshabilita(4520) ## SELECT * FROM fu_horario_deshabilita(4536) ## SELECT * FROM fu_horario_deshabilita(4562) ## SELECT * FROM fu_horario_deshabilita(4564) ## SELECT * FROM fu_horario_deshabilita(4565) ## SELECT * FROM fu_horario_deshabilita(4568) ## SELECT * FROM fu_horario_deshabilita(4650) ## SELECT * FROM fu_horario_deshabilita(4689) ## SELECT * FROM fu_horario_deshabilita(4760) ## SELECT * FROM fu_horario_deshabilita(4803) ## SELECT * FROM fu_horario_deshabilita(4804) ## SELECT * FROM fu_horario_deshabilita(4805) ## SELECT * FROM fu_horario_deshabilita(4806) ## SELECT * FROM fu_horario_deshabilita(4867) ## SELECT * FROM fu_horario_deshabilita(4255) ## SELECT * FROM fu_horario_deshabilita(6914) ## SELECT * FROM fu_horario_deshabilita(6889) ## SELECT * FROM fu_horario_deshabilita(6924) ## SELECT * FROM fu_horario_deshabilita(4796) ## SELECT * FROM fu_horario_deshabilita(4219) ## SELECT * FROM fu_horario_deshabilita(4665) ## SELECT * FROM fu_horario_deshabilita(4336) ## SELECT * FROM fu_horario_deshabilita(6854) ## SELECT * FROM fu_horario_deshabilita(7001) ## SELECT * FROM fu_horario_deshabilita(4213) ## SELECT * FROM fu_horario_deshabilita(4302) ## SELECT * FROM fu_horario_deshabilita(4305) ## SELECT * FROM fu_horario_deshabilita(4415) ## SELECT * FROM fu_horario_deshabilita(6963) ## SELECT * FROM fu_horario_deshabilita(6964) ## SELECT * FROM fu_horario_deshabilita(6965) ## SELECT * FROM fu_horario_deshabilita(6967) ## SELECT * FROM fu_horario_deshabilita(7017) ## SELECT * FROM fu_horario_deshabilita(7018) ## SELECT * FROM fu_horario_deshabilita(6926) ## -2023-08-17 11:12:59||SELECT * FROM fi_horario(5, '07:15:00','08:45:00','033','07','Aplicaci贸n de las tecnolog铆as para los negocios','IC010417','016994','RODOLFO LEDESMA VALDEZ','rodolfo.ledesma@lasalle.mx','MG 07020102',432); [ID=7571] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','032','27','Composici贸n tipogr谩fica','DG030415','017529','ERIC OLIVARES LIRA','','MG 27030204',348); [ID=7572] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','034','33','Conformaci贸n de la uni贸n europea','GE051715','012002','LUIS ANTONIO HUACUJA ACEVEDO','','MG 33030103',1042); [ID=7573] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','07','Herramientas tecnol贸gicas para los negocios','IC010117','017048','JAVIER GUILLERMO DI CARLO','javierdi@lasallistas.org.mx','MG 07010306',432); [ID=7574] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','034','33','M茅xico en el siglo XIX','HI051115','017540','ANDREA TORREALBA TORRE','','MG 33010208',1027); [ID=7575] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','81','C谩lculo integral','MA022817','017541','SERGIO IKER MART脥NEZ JU脕REZ','','MG 81020103',1087); [ID=7576] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','038','69','Biolog铆a celular','BI010515','015830','RODRIGO MART脥NEZ ESPINOSA','r.martineze@lasallistas.org.mx','MG 69020101',1306); [ID=7577] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','035','89','Epistemolog铆a','FI030714','017439','NATALIA ELIZABETH TALAVERA BABY','natalia.talavera@lasallistas.org.mx','MG 89010305',0); [ID=7578] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','033','81','Elementos de programaci贸n','IC032417','015386','ADOLFO RANGEL D脥AZ DE LA VEGA','adolfo.rangel@lasalle.mx','MG 81010103',432); [ID=7579] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','034','33','M茅xico en el siglo XIX','HI051115','017540','ANDREA TORREALBA TORRE','','MG 33010108',1026); [ID=7580] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','026','29','Anatom铆a y fisiolog铆a de aparatos y sistemas','BI031817','016883','LEONARDO LEBIB AZAR HERNANDEZ','leonardo.azar@lasallistas.org.mx','MG 29010101',1221); [ID=7581] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','035','89','Introducci贸n a la psicolog铆a','PS010714','010693','ADMA LIBIA FLORES VERGARA','alfv@lasallistas.org.mx','MG 89010307',0); [ID=7582] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','038','69','Lengua extranjera I','LI020113','014587','DALIA CARRE脩O ALVAREZ','dalia.carreno@lasallistas.org.mx','MG 69030403',364); [ID=7583] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','026','29','Anatom铆a y fisiolog铆a de aparatos y sistemas','BI031817','016883','LEONARDO LEBIB AZAR HERNANDEZ','leonardo.azar@lasallistas.org.mx','MG 29010101',1221); [ID=7584] ##SELECT * FROM fi_horario(5, '13:30:00','15:00:00','026','29','F铆sica','FS010717','017434','JOS脡 MIGUEL SANTILL脕N S脕NCHEZ','josesantillan@lasallistas.org.mx','MG 29010104',1221); [ID=7585] ##SELECT * FROM fi_horario(5, '14:00:00','15:30:00','033','03','Lengua extranjera I','LI020113','014587','DALIA CARRE脩O ALVAREZ','dalia.carreno@lasallistas.org.mx','MG 03030302',499); [ID=7586] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','81','Lengua extranjera I','LI020113','014587','DALIA CARRE脩O ALVAREZ','dalia.carreno@lasallistas.org.mx','MG 81030101',498); [ID=7587] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','034','32','Lengua extranjera I','LI020113','014139','INA SABORSKA DEICKE','ina.saborska@lasallistas.org.mx','MG 32030502',571); [ID=7588] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','038','69','Lengua extranjera I','LI020113','017535','JUDITH OLIMPIA GARC脥A GARC脥A','','MG 69030501',554); [ID=7589] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','07','Marca','ME041117','014509','ISRAEL GUARNEROS PEREZ','i.guarneros@lasallistas.org.mx','MG 07080105',386); [ID=7590] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','036','79','Tecnolog铆as de redes convergentes','CE030713','016311','NABOR REN脡 SOTO V脥QUEZ','naborsoto@lasallistas.org.mx','MG 79090211',841); [ID=7591] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','85','Lengua extranjera I','LI020121','014280','TATIANA TABARES DOM脥NGUEZ','tatiana-tabares@lasallistas.org.mx','MG 85030501',401); [ID=7592] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','038','77','Tecnolog铆a de productos c谩rnicos','NA032415','012137','GABRIELA ALATORRE GARC脥A','ga@lasallistas.org.mx','MG 77070106',1306); [ID=7593] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','038','65','Programaci贸n','IC032115','017536','EDGAR TISTA GARCIA','edgar.tista@lasallistas.org.mx','MG 65050106',387); [ID=7594] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','038','77','Tecnolog铆a de l谩cteos','NA032315','016354','CLAUDIA ARIADNA ACERO ORTEGA','claudia.acero@lasallistas.org.mx','MG 77070105',1306); [ID=7595] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','033','07','Marca','ME041117','014509','ISRAEL GUARNEROS PEREZ','i.guarneros@lasallistas.org.mx','MG 07080105',184); [ID=7596] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','034','32','Derecho internacional p煤blico','DE080215','010229','RAM脫N LOZA GONZ脕LEZ','ramonloza@lasallistas.org.mx','MG 32050203',166); [ID=7597] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','034','32','Teor铆a del derecho','DE010915','017497','MAR脥A SOLANGE MAQUEO RAM脥REZ','solange.maqueo@lasalle.mx','MG 32010107',1015); [ID=7598] ##SELECT * FROM fi_horario(5, '19:00:00','22:00:00','032','27','Taller de infograf铆a','DG021315','014800','CLAUDIA DE VALLE ROMERO','c.dvr@lasallistas.org.mx','MG 27070307',346); [ID=7599] ##SELECT * FROM fi_horario(5, '19:00:00','22:00:00','032','27','Taller de infograf铆a','DG021315','014912','JOSE ANTONIO CORTES MU脩OZ','antonio.cortes@lasallistas.org.mx','MG 27070403',346); [ID=7600] ##SELECT * FROM fi_horario(5, '19:00:00','22:00:00','032','27','Taller de infograf铆a','DG021315','016178','F脡LIX FRANCO RENTER脥A','felixfranco@lasallistas.org.mx','MG 27070208',346); [ID=7601] ##SELECT * FROM fi_horario(5, '19:00:00','22:00:00','032','27','Taller de infograf铆a','DG021315','016157','IGNACIO RODRIGUEZ SANCHEZ','ignaciorodriguez@lasallistas.org.mx','MG 27070108',346); [ID=7602] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','033','07','Mercadotecnia social y de servicios','ME030217','017542','DAVID REN脡 WILSON OROPEZA','david.wilson@lasallistas.org.mx','MG 07050105',260); [ID=7603] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','038','77','Funcionalidad de aditivos alimenticios','NA010615','012871','CARLOS BARR脫N ARTEAGA','carlos.barron@lasallistas.org.mx','MG 77070102',1309); [ID=7604] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','033','07','Mercadotecnia social y de servicios','ME030217','017542','DAVID REN脡 WILSON OROPEZA','david.wilson@lasallistas.org.mx','MG 07050205',264); [ID=7605] ##SELECT * FROM fi_horario(5, '07:00:00','08:30:00','037','70','Psicolog铆a m茅dica','PS060217','003896','ANDR脡S GUEVARA BRIZ','andres.guevara@lasallistas.org.mx','MG 70010107',319); [ID=7606] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','026','05','Taller de enfermer铆a gerontol贸gica','MD071815','016492','ANASTASIA LEONARDA TOVAR PALOMARES','al.tovar@lasallistas.org.mx','MG 05050105',1244); [ID=7607] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','026','05','Taller de enfermer铆a gerontol贸gica','MD071815','016492','ANASTASIA LEONARDA TOVAR PALOMARES','al.tovar@lasallistas.org.mx','MG 05050105',1244); [ID=7608] ##SELECT * FROM fi_horario(5, '11:00:00','13:00:00','037','70','Anatom铆a','BI030117','014153','ANTONIO SOTO PAULINO','antonio.soto@lasallistas.org.mx','MG 70010202',474); [ID=7609] ##SELECT * FROM fi_horario(5, '14:00:00','16:00:00','037','70','Anatom铆a','BI030117','014153','ANTONIO SOTO PAULINO','antonio.soto@lasallistas.org.mx','MG 70010102',324); [ID=7610] ##SELECT * FROM fi_horario(5, '16:00:00','18:00:00','037','70','Sexualidad humana','MD041217','017258','OSCAR JES脷S CU脡LLAR GONZ脕LEZ','oscar.cuellar@lasallistas.org.mx','MG 70080608',326); [ID=7611] ##SELECT * FROM fi_horario(5, '16:00:00','18:00:00','037','70','Oncolog铆a','MD031017','009308','FRANCISCO MARIO GARC脥A RODR脥GUEZ','','MG 70050108',323); [ID=7612] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Sexualidad humana','MD041217','017258','OSCAR JES脷S CU脡LLAR GONZ脕LEZ','oscar.cuellar@lasallistas.org.mx','MG 70080509',326); [ID=7613] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Oncolog铆a','MD031017','009308','FRANCISCO MARIO GARC脥A RODR脥GUEZ','','MG 70050408',323); [ID=7614] ## +2023-08-06 12:39:03||SELECT * FROM fu_horario_deshabilita(867) ## SELECT * FROM fu_horario_deshabilita(555) ## SELECT * FROM fu_horario_deshabilita(1005) ## SELECT * FROM fu_horario_deshabilita(860) ## SELECT * FROM fu_horario_deshabilita(389) ## SELECT * FROM fu_horario_deshabilita(685) ## SELECT * FROM fu_horario_deshabilita(920) ## SELECT * FROM fu_horario_deshabilita(513) ## +2023-08-06 12:39:03||SELECT * FROM fi_horario(1, 07:15:00,08:45:00,036,79,Seguridad en tecnolog铆as de la informaci贸n,IC060413,014416,EDGAR ALBERTO CHILLON ESCARCEGA,edgar.chillon@lasallistas.org.mx,MG 79090109,842) [ID=5617] ##SELECT * FROM fi_horario(1, 12:00:00,13:30:00,034,33,Fundamentos del derecho constitucional,DE122315,015520,JAIME CALDERON GOMEZ,jaime.calderon@lasallistas.org.mx,MG 33020105,1028) [ID=5618] ##SELECT * FROM fi_horario(1, 15:45:00,17:15:00,033,96,Seminario y an谩lisis de casos de negocios en 谩mbitos locales,AD031717,014365,JOSE MANUEL RIVERA ZARAGOZA,jm.riveraz@lasallistas.org.mx,MG 96070207,187) [ID=5619] ##SELECT * FROM fi_horario(1, 17:15:00,18:45:00,033,09,Negociaciones internacionales,EC061817,,,,MG 09060105,1086) [ID=5620] ##SELECT * FROM fi_horario(1, 20:30:00,22:00:00,036,79,Aplicaciones m贸viles,IC031813,017335,FELIPE MANDUJANO G脫MEZ,felipe.mandujano@lasallistas.org.mx,MG 79090103,842) [ID=5621] ##SELECT * FROM fi_horario(1, 20:30:00,22:00:00,033,07,Taller de negociaci贸n,AD091817,,,,MG 07050208,264) [ID=5622] ## +2023-08-06 13:07:45||SELECT * FROM fi_horario(1, 07:15:00,08:45:00,036,79,Seguridad en tecnolog铆as de la informaci贸n,IC060413,014416,EDGAR ALBERTO CHILLON ESCARCEGA,edgar.chillon@lasallistas.org.mx,MG 79090109,842) [ID=5623] ##SELECT * FROM fi_horario(1, 12:00:00,13:30:00,034,33,Fundamentos del derecho constitucional,DE122315,015520,JAIME CALDERON GOMEZ,jaime.calderon@lasallistas.org.mx,MG 33020105,1028) [ID=5624] ##SELECT * FROM fi_horario(1, 15:45:00,17:15:00,033,96,Seminario y an谩lisis de casos de negocios en 谩mbitos locales,AD031717,014365,JOSE MANUEL RIVERA ZARAGOZA,jm.riveraz@lasallistas.org.mx,MG 96070207,187) [ID=5625] ##SELECT * FROM fi_horario(1, 17:15:00,18:45:00,033,09,Negociaciones internacionales,EC061817,,,,MG 09060105,1086) [ID=5626] ##SELECT * FROM fi_horario(1, 20:30:00,22:00:00,036,79,Aplicaciones m贸viles,IC031813,017335,FELIPE MANDUJANO G脫MEZ,felipe.mandujano@lasallistas.org.mx,MG 79090103,842) [ID=5627] ##SELECT * FROM fi_horario(1, 20:30:00,22:00:00,033,07,Taller de negociaci贸n,AD091817,,,,MG 07050208,264) [ID=5628] ## +2023-08-08 06:57:53||SELECT * FROM fu_horario_deshabilita(1772) ## +2023-08-08 06:57:53||SELECT * FROM fi_horario(2, 07:15:00,08:45:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 75010102,455) [ID=5836] ##SELECT * FROM fi_horario(2, 07:15:00,08:45:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,017181,DANIELA MONTA脩O SAN AGUSTIN,daniela.montano@lasallistas.org.mx,MG 75010102,455) [ID=5837] ##SELECT * FROM fi_horario(2, 08:45:00,10:15:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 75010202,455) [ID=5838] ##SELECT * FROM fi_horario(2, 08:45:00,10:15:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,017181,DANIELA MONTA脩O SAN AGUSTIN,daniela.montano@lasallistas.org.mx,MG 75010202,455) [ID=5839] ##SELECT * FROM fi_horario(2, 10:30:00,12:00:00,036,80,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050122,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 80010103,455) [ID=5840] ##SELECT * FROM fi_horario(2, 10:30:00,12:00:00,036,80,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050122,013557,GABRIELA MAC脥AS ESQUIVEL,gabriela.macias@lasalle.mx,MG 80010103,455) [ID=5841] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,016627,CLEMENTINA PALOMO BELTR脕N,c.palomob@lasallistas.org.mx,MG 28050106,1044) [ID=5842] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,017462,CARLOS IV脕N G脫MEZ CALDER脫N,carlos.gomez@lasallistas.org.mx,MG 28050206,1044) [ID=5843] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,016794,JORGE ADRIAN RAMOS RUIZ,jorgeramos@lasallistas.org.mx,MG 28050303,1044) [ID=5844] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,015352,ALEJANDRO IMAZ LAMADRID,alejandroimaz@lasallistas.org.mx,MG 28050401,1044) [ID=5845] ##SELECT * FROM fi_horario(2, 13:30:00,15:00:00,032,27,La persona y su interacci贸n con los otros,PS151113,,,,MG 27030301,0) [ID=5846] ##SELECT * FROM fi_horario(2, 17:15:00,18:45:00,036,79,Gobierno de tecnolog铆as de informaci贸n y entrega de servicios,IC052413,015962,CYNTHIA MARTINEZ ARIZMENDI,,MG 79090208,0) [ID=5847] ##SELECT * FROM fi_horario(2, 19:00:00,20:30:00,036,79,Miner铆a de datos e inteligencia de negocios,IC020913,,,,MG 79090209,0) [ID=5848] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,004558,MANUEL MAR脥A JOS脡 GALLO REYNOSO,manuelgallo@lasallistas.org.mx,MG 70040207,858) [ID=5849] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016426,JESSICA JOHANA HERN脕NDEZ OSORIO,jessica-hernandez@lasallistas.org.mx,MG 70040207,858) [ID=5850] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,010124,ENRIQUE JUAN D脥AZ GREENE,do_enrique.Diaz@lasallistas.org.mx,MG 70040504,855) [ID=5851] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,008927,FEDERICO LEOPOLDO RODR脥GUEZ WEBER,flrw@lasallistas.org.mx,MG 70040307,855) [ID=5852] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,,,,MG 70040307,855) [ID=5853] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,013104,LUIS ARMANDO GERVACIO BLANCO,luis.gervacio@lasallistas.org.mx,MG 70040704,881) [ID=5854] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,014494,LUIS ANTONIO REYES QUIJANO,reyes.luis@lasallistas.org.mx,MG 70040704,881) [ID=5855] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016108,DIANA CHAVEZ GARRIDO,diana.chavez@lasallistas.org.mx,MG 70040404,881) [ID=5856] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016401,JULIO CESAR OLVERA BARAJAS,julio.olvera@lasallistas.org.mx,MG 70040404,881) [ID=5857] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,015215,ADOLFO BUSTOS RAM脥REZ,adolfo.bustos@lasallistas.org.mx,MG 70040404,881) [ID=5858] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,010570,SERGIO IV脕N GONZ脕LEZ OLVERA,sigo@lasallistas.org.mx,MG 70040107,887) [ID=5859] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,015553,GERARDO ARTURO BRAVO ESCOBAR,gerardobravo@lasallistas.org.mx,MG 70040107,887) [ID=5860] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016724,ABEL JALIFE MONTA脩O,abeljalife@lasallistas.org.mx,MG 70041003,889) [ID=5861] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016713,MAR脥A DEL CARMEN GARC脥A RUIZ,mdc.garcia@lasallistas.org.mx,MG 70041003,889) [ID=5862] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,007816,BLANCA MARGARITA VARGAS PEDRAZA,blancavargas@lasallistas.org.mx,MG 70040604,889) [ID=5863] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,007818,AGUST脥N VIVANCO ROSAS,a-vr@lasallistas.org.mx,MG 70040604,889) [ID=5864] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016717,ABRAHAM PULIDO CEJUDO,abraham.pulido@lasallistas.org.mx,MG 70040903,889) [ID=5865] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016785,MARIO GUZMAN GUTIERREZ,mg.6@lasallistas.org.mx,MG 70040903,889) [ID=5866] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016381,ELVIRA GRACIELA ALEXANDERSON ROSAS,eg.alexanderson@lasallistas.org.mx,MG 70040803,889) [ID=5867] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016305,ALFREDO ISRAEL SERVIN CAAMA脩O,alfredo.servin@lasallistas.org.mx,MG 70040803,889) [ID=5868] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,017106,MARIO MAURICIO FERN脕NDEZ ROMERO,mario.fernandez@lasallistas.org.mx,MG 70080306,1423) [ID=5869] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016173,VICTOR MANUEL FLORES M脡NDEZ,victorflores@lasallistas.org.mx,MG 70080406,0) [ID=5870] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016112,LUIS EDMUNDO HERNANDEZ VIVAR,le.hv@lasallistas.org.mx,MG 70080406,0) [ID=5871] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,017056,JUAN JIMENEZ HUERTA,,MG 70080406,0) [ID=5872] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,010577,MONICA VILLA GUILLEN,m.mvg@lasallistas.org.mx,MG 70080308,0) [ID=5873] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016138,DIANA AIDEE GUERRERO RESENDIZ,,MG 70080308,0) [ID=5874] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016580,VICTOR MANUEL BARAJAS VALENCIA,,MG 70080308,0) [ID=5875] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,010915,GERARDO BLANCO RODR脥GUEZ,g.blancor@lasallistas.org.mx,MG 70080108,0) [ID=5876] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014626,ELISA MAR脥A DORANTES ACOSTA,,MG 70080108,0) [ID=5877] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016513,ANA CAROLINA HILL DE TITTO,ac.hill@lasallistas.org.mx,MG 70080108,0) [ID=5878] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,015171,ANTONIO CALDER脫N MOORE,a.calderonm@lasallistas.org.mx,MG 70080606,0) [ID=5879] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,007232,MIGUEL VILLA GUERRERO,miguel.villa@lasallistas.org.mx,MG 70080106,0) [ID=5880] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016016,MANUEL FRANCISCO BORGES IB脕脩EZ,manuelborges@lasallistas.org.mx,MG 70080106,0) [ID=5881] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016116,JES脷S CARLOS BRIONES GARDU脩O,jesus.briones@lasallistas.org.mx,MG 70080106,0) [ID=5882] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014202,ROMULO ERICK ROSALES URIBE,re.ru@lasallistas.org.mx,MG 70080208,0) [ID=5883] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014596,JOSE CARLOS ROMO VAZQUEZ,,MG 70080208,0) [ID=5884] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016599,CARLOS PATRICIO ACOSTA RODR脥GUEZ BUENO,cp.acosta@lasallistas.org.mx,MG 70080208,0) [ID=5885] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,015614,KARLA GABRIELA OJEDA DIEZBARROSO,,MG 70080507,0) [ID=5886] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,000752,JOS脡 JUAN ORTEGA CERDA,jortega@lasallistas.org.mx,MG 70050601,855) [ID=5887] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,008867,URSULO JU脕REZ HERRERA,u.juarez@lasallistas.org.mx,MG 70050601,855) [ID=5888] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,016853,GUSTAVO ROJAS VELASCO,,MG 70050601,855) [ID=5889] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,008098,ISAAC ZAGA MINIAN,,MG 70090503,871) [ID=5890] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017381,JAIME ANTONIO HIDALGO CARRERA,,MG 70090903,899) [ID=5891] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,013905,MARTHA EUNICE RODR脥GUEZ ARELLANO,mera@lasallistas.org.mx,MG 70050702,854) [ID=5892] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,013878,PERLA ALICIA CARRILLO GONZ脕LEZ,perlacarrillo@lasallistas.org.mx,MG 70050702,854) [ID=5893] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,017131,ANTONIO CORONA BAUTISTA,antoniocorona@lasallistas.org.mx,MG 70070704,854) [ID=5894] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016272,ALEJANDRA CALDER脫N VALLEJO,alejandra.calderon@lasallistas.org.mx,MG 70060509,865) [ID=5895] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016950,CARLOS FREDY CUEVAS GARCIA,,MG 70060509,865) [ID=5896] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016954,JES脷S FONSECA COSIO,,MG 70060509,865) [ID=5897] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,011707,CLAUDIA ELENA MURILLO CORREA,,MG 70070502,880) [ID=5898] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,012289,脕NGEL NAVA CASTA脩EDA,,MG 70070502,880) [ID=5899] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,014180,ALMA JESSICA VARGAS ORTEGA,,MG 70070502,880) [ID=5900] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,013434,ERIKA LETICIA FERN脕NDEZ MU脩OZ,erikafernandez@lasallistas.org.mx,MG 70070403,883) [ID=5901] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,016747,ITZEL MONTSERRAT P脡REZ GUDI脩O,itzelperez@lasallistas.org.mx,MG 70070403,883) [ID=5902] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,017383,MARY LADY GONZALEZ SURIEL,,MG 70070403,883) [ID=5903] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,015425,GUILLERMO CESAR PEREZ PELAEZ,,MG 70090203,885) [ID=5904] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017378,DANIELA ALEJANDRA LEMIONET ESCANERO,,MG 70090703,860) [ID=5905] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,016830,JUAN PABLO RAMIREZ HINOJOSA,jp.ramirezh@lasallistas.org.mx,MG 70060308,887) [ID=5906] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,016881,MERCEDES ARANDA AUDELO,mercedes.aranda@lasallistas.org.mx,MG 70060308,887) [ID=5907] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,013875,ANA PATRICIA RODR脥GUEZ ZULUETA,,MG 70060308,887) [ID=5908] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,004730,MAR脥A IVONNE ARELLANO MENDOZA,mi.arellanom@lasallistas.org.mx,MG 70060305,889) [ID=5909] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,016545,MARIELA GALICIA MALDONADO,marielagalicia@lasallistas.org.mx,MG 70060305,889) [ID=5910] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,013299,ROSA MAR脥A PONCE OLIVERA,,MG 70060305,889) [ID=5911] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,014547,MARIO SILVINO ALMANZA GONZALEZ,,MG 70080211,889) [ID=5912] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,014599,HUGO ARTURO MANZANILLA GARCIA,ha.manzanilla@lasallistas.org.mx,MG 70080211,889) [ID=5913] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016259,CESAR FIRETH POZO BELTR脕N,,MG 70091003,896) [ID=5914] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Psiquiatr铆a,MD030617,016606,ADOLFO NERI HERN脕NDEZ,adolfo.neri@lasallistas.org.mx,MG 70050409,1013) [ID=5915] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Psiquiatr铆a,MD030617,015698,CARLOS HERNANDEZ VEGA,c.hv@lasallistas.org.mx,MG 70050409,1013) [ID=5916] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017310,NORMA VELIA BALLESTEROS SOLIS,norma.ballesteros@lasallistas.org.mx,MG 70093003,867) [ID=5917] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Cirug铆a (internado de pregrado),MD020317,017305,ERNESTO SALGADO SANCHEZ,,MG 70091801,1272) [ID=5918] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016280,MARIA ANOTA RIVERA,,MG 70092903,1267) [ID=5919] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Traumatolog铆a y ortopedia,MD030417,014992,RUDY DE JESUS SALAZAR PACHECO,rudysalazar@lasallistas.org.mx,MG 70070210,1004) [ID=5920] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Traumatolog铆a y ortopedia,MD030417,015451,FERNANDO ORTIZ ROJAS,fortiz@lasallistas.org.mx,MG 70070210,1004) [ID=5921] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,016568,JUAN ANTONIO LUGO GARC脥A,juanlugo@lasallistas.org.mx,MG 70080411,1004) [ID=5922] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,016818,OMAR HERNANDEZ LEON,o.hl@lasallistas.org.mx,MG 70080411,1004) [ID=5923] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016952,ERIKA GOMEZ ZAMORA,,MG 70092203,1004) [ID=5924] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,006026,RUBEN CORT脡S GONZ脕LEZ,rubencortes@lasallistas.org.mx,MG 70070206,892) [ID=5925] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,016281,NOEL SALGADO NESME,,MG 70070206,892) [ID=5926] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,016429,MAURICIO SIERRA SALAZAR,,MG 70070206,892) [ID=5927] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Gastroenterolog铆a,MD040417,012899,JORGE HERN脕NDEZ CALLEROS,,MG 70060206,892) [ID=5928] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Gastroenterolog铆a,MD040417,015294,ENRIQUE COSS ADAME,enrique.coss@lasallistas.org.mx,MG 70060206,892) [ID=5929] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neumolog铆a,MD040217,,,,MG 70050206,886) [ID=5930] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,010978,脕NGEL ANTONIO ARAUZ G脫NGORA,aa.arauz@lasallistas.org.mx,MG 70060209,884) [ID=5931] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,011794,LUIS IGNACIO MIRANDA MEDRANO,,MG 70060209,884) [ID=5932] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,013146,ADOLFO LEYVA REND脫N,,MG 70060209,884) [ID=5933] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,017123,DANIELLA ALEJANDRA MONROY LLAGUNO,daniella.monroy@lasallistas.org.mx,MG 70070205,1010) [ID=5934] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,015003,IVAN HERMANN SCHOBERT CAPETILLO,ivanschobert@lasallistas.org.mx,MG 70070205,1010) [ID=5935] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,016774,OFELIA NATSUKO TANIYAMA L脫PEZ,ofeliataniyama@lasallistas.org.mx,MG 70070205,1010) [ID=5936] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,015452,CARMEN ZAVALA GARC脥A,,MG 70090403,863) [ID=5937] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,008931,ALMA VERGARA L脫PEZ,alma.vergara@lasallistas.org.mx,MG 70050203,869) [ID=5938] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,016089,ADRIANA BALDERRAMA SOTO,a.balderrama@lasallistas.org.mx,MG 70050203,869) [ID=5939] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,008725,CARLOS HAROLDO IXCAMPARIJ ROSALES,chir@lasallistas.org.mx,MG 70050202,869) [ID=5940] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,015880,ROBERTO MURATALLA GONZ脕LEZ,,MG 70050202,869) [ID=5941] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,009026,GREGORIO ZARAGOZA RODRIGUEZ,,MG 70050202,869) [ID=5942] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Geriatr铆a,MD030717,017243,DOMINGA ALBERTA SALOMON CORTEZ,,MG 70070601,0) [ID=5943] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017238,ERIK REBOLLEDO GARDU脩O,,MG 70092803,0) [ID=5944] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017382,RODOLFO SILVA ROMO,,MG 70093103,0) [ID=5945] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017240,ROBERTO BADIR CORANGUEZ CAPISTRAN,,MG 70091603,0) [ID=5946] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016275,IV脕N ALBERTO NAJERA RODR脥GUEZ,ivan.najera@lasallistas.org.mx,MG 70093203,0) [ID=5947] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Cirug铆a (internado de pregrado),MD020317,013926,ABEL FUENTES VENEGAS,abelfuentes@lasallistas.org.mx,MG 70090301,0) [ID=5948] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina interna (internado de pregrado),MD041117,011870,NORBERTO REYES PAREDES,norbertoreyes@lasallistas.org.mx,MG 70092604,0) [ID=5949] ##SELECT * FROM fi_horario(2, 12:00:00,18:00:00,037,70,Otorrinolaringolog铆a,MD030317,010570,SERGIO IV脕N GONZ脕LEZ OLVERA,sigo@lasallistas.org.mx,MG 70070703,887) [ID=5950] ##SELECT * FROM fi_horario(2, 12:00:00,18:00:00,037,70,Otorrinolaringolog铆a,MD030317,013134,DINA FABIOLA GONZ脕LEZ S脕NCHEZ,df.gonzalezs@lasallistas.org.mx,MG 70070703,887) [ID=5951] ##SELECT * FROM fi_horario(2, 14:00:00,16:00:00,037,70,Ginecolog铆a y obstetricia (internado de pregrado),MD031217,010124,ENRIQUE JUAN D脥AZ GREENE,do_enrique.Diaz@lasallistas.org.mx,MG 70090102,855) [ID=5952] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,007232,MIGUEL VILLA GUERRERO,miguel.villa@lasallistas.org.mx,MG 70080604,0) [ID=5953] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016016,MANUEL FRANCISCO BORGES IB脕脩EZ,manuelborges@lasallistas.org.mx,MG 70080604,0) [ID=5954] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016116,JES脷S CARLOS BRIONES GARDU脩O,jesus.briones@lasallistas.org.mx,MG 70080604,0) [ID=5955] ## +2023-08-08 07:11:46||SELECT * FROM fi_horario(2, 07:15:00,08:45:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 75010102,455) [ID=6074] ##SELECT * FROM fi_horario(2, 07:15:00,08:45:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,017181,DANIELA MONTA脩O SAN AGUSTIN,daniela.montano@lasallistas.org.mx,MG 75010102,455) [ID=6075] ##SELECT * FROM fi_horario(2, 08:45:00,10:15:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 75010202,455) [ID=6076] ##SELECT * FROM fi_horario(2, 08:45:00,10:15:00,036,75,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050120,017181,DANIELA MONTA脩O SAN AGUSTIN,daniela.montano@lasallistas.org.mx,MG 75010202,455) [ID=6077] ##SELECT * FROM fi_horario(2, 10:30:00,12:00:00,036,80,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050122,011024,CARLOS ESQUIVEL MAR脥N,c.esquivelm@lasallistas.org.mx,MG 80010103,455) [ID=6078] ##SELECT * FROM fi_horario(2, 10:30:00,12:00:00,036,80,Ciencias experimentales aplicadas: la materia y sus transformaciones,FS050122,013557,GABRIELA MAC脥AS ESQUIVEL,gabriela.macias@lasalle.mx,MG 80010103,455) [ID=6079] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,016627,CLEMENTINA PALOMO BELTR脕N,c.palomob@lasallistas.org.mx,MG 28050106,1044) [ID=6080] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,016794,JORGE ADRIAN RAMOS RUIZ,jorgeramos@lasallistas.org.mx,MG 28050303,1044) [ID=6081] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,015352,ALEJANDRO IMAZ LAMADRID,alejandroimaz@lasallistas.org.mx,MG 28050401,1044) [ID=6082] ##SELECT * FROM fi_horario(2, 10:30:00,13:30:00,032,28,Taller de entornos virtuales,DI020717,017462,CARLOS IV脕N G脫MEZ CALDER脫N,carlos.gomez@lasallistas.org.mx,MG 28050206,1044) [ID=6083] ##SELECT * FROM fi_horario(2, 13:30:00,15:00:00,032,27,La persona y su interacci贸n con los otros,PS151113,,,,MG 27030301,0) [ID=6084] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,004558,MANUEL MAR脥A JOS脡 GALLO REYNOSO,manuelgallo@lasallistas.org.mx,MG 70040207,858) [ID=6085] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016426,JESSICA JOHANA HERN脕NDEZ OSORIO,jessica-hernandez@lasallistas.org.mx,MG 70040207,858) [ID=6086] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,008927,FEDERICO LEOPOLDO RODR脥GUEZ WEBER,flrw@lasallistas.org.mx,MG 70040307,855) [ID=6087] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,,,,MG 70040307,855) [ID=6088] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,010124,ENRIQUE JUAN D脥AZ GREENE,do_enrique.Diaz@lasallistas.org.mx,MG 70040504,855) [ID=6089] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,013104,LUIS ARMANDO GERVACIO BLANCO,luis.gervacio@lasallistas.org.mx,MG 70040704,881) [ID=6090] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,014494,LUIS ANTONIO REYES QUIJANO,reyes.luis@lasallistas.org.mx,MG 70040704,881) [ID=6091] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016108,DIANA CHAVEZ GARRIDO,diana.chavez@lasallistas.org.mx,MG 70040404,881) [ID=6092] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016401,JULIO CESAR OLVERA BARAJAS,julio.olvera@lasallistas.org.mx,MG 70040404,881) [ID=6093] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,015215,ADOLFO BUSTOS RAM脥REZ,adolfo.bustos@lasallistas.org.mx,MG 70040404,881) [ID=6094] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,010570,SERGIO IV脕N GONZ脕LEZ OLVERA,sigo@lasallistas.org.mx,MG 70040107,887) [ID=6095] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,015553,GERARDO ARTURO BRAVO ESCOBAR,gerardobravo@lasallistas.org.mx,MG 70040107,887) [ID=6096] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,007816,BLANCA MARGARITA VARGAS PEDRAZA,blancavargas@lasallistas.org.mx,MG 70040604,889) [ID=6097] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,007818,AGUST脥N VIVANCO ROSAS,a-vr@lasallistas.org.mx,MG 70040604,889) [ID=6098] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016717,ABRAHAM PULIDO CEJUDO,abraham.pulido@lasallistas.org.mx,MG 70040903,889) [ID=6099] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016785,MARIO GUZMAN GUTIERREZ,mg.6@lasallistas.org.mx,MG 70040903,889) [ID=6100] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016724,ABEL JALIFE MONTA脩O,abeljalife@lasallistas.org.mx,MG 70041003,889) [ID=6101] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016713,MAR脥A DEL CARMEN GARC脥A RUIZ,mdc.garcia@lasallistas.org.mx,MG 70041003,889) [ID=6102] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016381,ELVIRA GRACIELA ALEXANDERSON ROSAS,eg.alexanderson@lasallistas.org.mx,MG 70040803,889) [ID=6103] ##SELECT * FROM fi_horario(2, 07:00:00,12:00:00,037,70,Proped茅utica cl铆nica y nosolog铆a,MD010417,016305,ALFREDO ISRAEL SERVIN CAAMA脩O,alfredo.servin@lasallistas.org.mx,MG 70040803,889) [ID=6104] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,017106,MARIO MAURICIO FERN脕NDEZ ROMERO,mario.fernandez@lasallistas.org.mx,MG 70080306,1423) [ID=6105] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014202,ROMULO ERICK ROSALES URIBE,re.ru@lasallistas.org.mx,MG 70080208,0) [ID=6106] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014596,JOSE CARLOS ROMO VAZQUEZ,,MG 70080208,0) [ID=6107] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016599,CARLOS PATRICIO ACOSTA RODR脥GUEZ BUENO,cp.acosta@lasallistas.org.mx,MG 70080208,0) [ID=6108] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016173,VICTOR MANUEL FLORES M脡NDEZ,victorflores@lasallistas.org.mx,MG 70080406,0) [ID=6109] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016112,LUIS EDMUNDO HERNANDEZ VIVAR,le.hv@lasallistas.org.mx,MG 70080406,0) [ID=6110] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,017056,JUAN JIMENEZ HUERTA,,MG 70080406,0) [ID=6111] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,010577,MONICA VILLA GUILLEN,m.mvg@lasallistas.org.mx,MG 70080308,0) [ID=6112] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016138,DIANA AIDEE GUERRERO RESENDIZ,,MG 70080308,0) [ID=6113] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016580,VICTOR MANUEL BARAJAS VALENCIA,,MG 70080308,0) [ID=6114] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,015614,KARLA GABRIELA OJEDA DIEZBARROSO,,MG 70080507,0) [ID=6115] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,007232,MIGUEL VILLA GUERRERO,miguel.villa@lasallistas.org.mx,MG 70080106,0) [ID=6116] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016016,MANUEL FRANCISCO BORGES IB脕脩EZ,manuelborges@lasallistas.org.mx,MG 70080106,0) [ID=6117] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016116,JES脷S CARLOS BRIONES GARDU脩O,jesus.briones@lasallistas.org.mx,MG 70080106,0) [ID=6118] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,010915,GERARDO BLANCO RODR脥GUEZ,g.blancor@lasallistas.org.mx,MG 70080108,0) [ID=6119] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,014626,ELISA MAR脥A DORANTES ACOSTA,,MG 70080108,0) [ID=6120] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,016513,ANA CAROLINA HILL DE TITTO,ac.hill@lasallistas.org.mx,MG 70080108,0) [ID=6121] ##SELECT * FROM fi_horario(2, 07:00:00,13:15:00,037,70,Pediatr铆a,MD030817,015171,ANTONIO CALDER脫N MOORE,a.calderonm@lasallistas.org.mx,MG 70080606,0) [ID=6122] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,000752,JOS脡 JUAN ORTEGA CERDA,jortega@lasallistas.org.mx,MG 70050601,855) [ID=6123] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,008867,URSULO JU脕REZ HERRERA,u.juarez@lasallistas.org.mx,MG 70050601,855) [ID=6124] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,016853,GUSTAVO ROJAS VELASCO,,MG 70050601,855) [ID=6125] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,008098,ISAAC ZAGA MINIAN,,MG 70090503,871) [ID=6126] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017381,JAIME ANTONIO HIDALGO CARRERA,,MG 70090903,899) [ID=6127] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,013905,MARTHA EUNICE RODR脥GUEZ ARELLANO,mera@lasallistas.org.mx,MG 70050702,854) [ID=6128] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,013878,PERLA ALICIA CARRILLO GONZ脕LEZ,perlacarrillo@lasallistas.org.mx,MG 70050702,854) [ID=6129] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,017131,ANTONIO CORONA BAUTISTA,antoniocorona@lasallistas.org.mx,MG 70070704,854) [ID=6130] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016272,ALEJANDRA CALDER脫N VALLEJO,alejandra.calderon@lasallistas.org.mx,MG 70060509,865) [ID=6131] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016950,CARLOS FREDY CUEVAS GARCIA,,MG 70060509,865) [ID=6132] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,016954,JES脷S FONSECA COSIO,,MG 70060509,865) [ID=6133] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,011707,CLAUDIA ELENA MURILLO CORREA,,MG 70070502,880) [ID=6134] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,012289,脕NGEL NAVA CASTA脩EDA,,MG 70070502,880) [ID=6135] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,014180,ALMA JESSICA VARGAS ORTEGA,,MG 70070502,880) [ID=6136] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,013434,ERIKA LETICIA FERN脕NDEZ MU脩OZ,erikafernandez@lasallistas.org.mx,MG 70070403,883) [ID=6137] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,016747,ITZEL MONTSERRAT P脡REZ GUDI脩O,itzelperez@lasallistas.org.mx,MG 70070403,883) [ID=6138] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Oftalmolog铆a,MD030217,017383,MARY LADY GONZALEZ SURIEL,,MG 70070403,883) [ID=6139] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,015425,GUILLERMO CESAR PEREZ PELAEZ,,MG 70090203,885) [ID=6140] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017378,DANIELA ALEJANDRA LEMIONET ESCANERO,,MG 70090703,860) [ID=6141] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,016830,JUAN PABLO RAMIREZ HINOJOSA,jp.ramirezh@lasallistas.org.mx,MG 70060308,887) [ID=6142] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,016881,MERCEDES ARANDA AUDELO,mercedes.aranda@lasallistas.org.mx,MG 70060308,887) [ID=6143] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Infectolog铆a,MD040917,013875,ANA PATRICIA RODR脥GUEZ ZULUETA,,MG 70060308,887) [ID=6144] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,014547,MARIO SILVINO ALMANZA GONZALEZ,,MG 70080211,889) [ID=6145] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,014599,HUGO ARTURO MANZANILLA GARCIA,ha.manzanilla@lasallistas.org.mx,MG 70080211,889) [ID=6146] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,004730,MAR脥A IVONNE ARELLANO MENDOZA,mi.arellanom@lasallistas.org.mx,MG 70060305,889) [ID=6147] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,016545,MARIELA GALICIA MALDONADO,marielagalicia@lasallistas.org.mx,MG 70060305,889) [ID=6148] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Dermatolog铆a,MD030517,013299,ROSA MAR脥A PONCE OLIVERA,,MG 70060305,889) [ID=6149] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016259,CESAR FIRETH POZO BELTR脕N,,MG 70091003,896) [ID=6150] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Psiquiatr铆a,MD030617,016606,ADOLFO NERI HERN脕NDEZ,adolfo.neri@lasallistas.org.mx,MG 70050409,1013) [ID=6151] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Psiquiatr铆a,MD030617,015698,CARLOS HERNANDEZ VEGA,c.hv@lasallistas.org.mx,MG 70050409,1013) [ID=6152] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017310,NORMA VELIA BALLESTEROS SOLIS,norma.ballesteros@lasallistas.org.mx,MG 70093003,867) [ID=6153] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Cirug铆a (internado de pregrado),MD020317,017305,ERNESTO SALGADO SANCHEZ,,MG 70091801,1272) [ID=6154] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016280,MARIA ANOTA RIVERA,,MG 70092903,1267) [ID=6155] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Traumatolog铆a y ortopedia,MD030417,014992,RUDY DE JESUS SALAZAR PACHECO,rudysalazar@lasallistas.org.mx,MG 70070210,1004) [ID=6156] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Traumatolog铆a y ortopedia,MD030417,015451,FERNANDO ORTIZ ROJAS,fortiz@lasallistas.org.mx,MG 70070210,1004) [ID=6157] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,016568,JUAN ANTONIO LUGO GARC脥A,juanlugo@lasallistas.org.mx,MG 70080411,1004) [ID=6158] ##SELECT * FROM fi_horario(2, 08:00:00,10:30:00,037,70,Urolog铆a,MD041017,016818,OMAR HERNANDEZ LEON,o.hl@lasallistas.org.mx,MG 70080411,1004) [ID=6159] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016952,ERIKA GOMEZ ZAMORA,,MG 70092203,1004) [ID=6160] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,006026,RUBEN CORT脡S GONZ脕LEZ,rubencortes@lasallistas.org.mx,MG 70070206,892) [ID=6161] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,016281,NOEL SALGADO NESME,,MG 70070206,892) [ID=6162] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Patolog铆a quir煤rgica,MD020217,016429,MAURICIO SIERRA SALAZAR,,MG 70070206,892) [ID=6163] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Gastroenterolog铆a,MD040417,012899,JORGE HERN脕NDEZ CALLEROS,,MG 70060206,892) [ID=6164] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Gastroenterolog铆a,MD040417,015294,ENRIQUE COSS ADAME,enrique.coss@lasallistas.org.mx,MG 70060206,892) [ID=6165] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neumolog铆a,MD040217,,,,MG 70050206,886) [ID=6166] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,010978,脕NGEL ANTONIO ARAUZ G脫NGORA,aa.arauz@lasallistas.org.mx,MG 70060209,884) [ID=6167] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,011794,LUIS IGNACIO MIRANDA MEDRANO,,MG 70060209,884) [ID=6168] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Neurolog铆a,MD040617,013146,ADOLFO LEYVA REND脫N,,MG 70060209,884) [ID=6169] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,017123,DANIELLA ALEJANDRA MONROY LLAGUNO,daniella.monroy@lasallistas.org.mx,MG 70070205,1010) [ID=6170] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,015003,IVAN HERMANN SCHOBERT CAPETILLO,ivanschobert@lasallistas.org.mx,MG 70070205,1010) [ID=6171] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Otorrinolaringolog铆a,MD030317,016774,OFELIA NATSUKO TANIYAMA L脫PEZ,ofeliataniyama@lasallistas.org.mx,MG 70070205,1010) [ID=6172] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,015452,CARMEN ZAVALA GARC脥A,,MG 70090403,863) [ID=6173] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,008931,ALMA VERGARA L脫PEZ,alma.vergara@lasallistas.org.mx,MG 70050203,869) [ID=6174] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Endocrinolog铆a,MD040717,016089,ADRIANA BALDERRAMA SOTO,a.balderrama@lasallistas.org.mx,MG 70050203,869) [ID=6175] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,008725,CARLOS HAROLDO IXCAMPARIJ ROSALES,chir@lasallistas.org.mx,MG 70050202,869) [ID=6176] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,015880,ROBERTO MURATALLA GONZ脕LEZ,,MG 70050202,869) [ID=6177] ##SELECT * FROM fi_horario(2, 08:00:00,14:15:00,037,70,Cardiolog铆a,MD040117,009026,GREGORIO ZARAGOZA RODRIGUEZ,,MG 70050202,869) [ID=6178] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Cirug铆a (internado de pregrado),MD020317,013926,ABEL FUENTES VENEGAS,abelfuentes@lasallistas.org.mx,MG 70090301,0) [ID=6179] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017238,ERIK REBOLLEDO GARDU脩O,,MG 70092803,0) [ID=6180] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017382,RODOLFO SILVA ROMO,,MG 70093103,0) [ID=6181] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,017240,ROBERTO BADIR CORANGUEZ CAPISTRAN,,MG 70091603,0) [ID=6182] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina familiar y comunitaria (internado de pregrado),MD031417,016275,IV脕N ALBERTO NAJERA RODR脥GUEZ,ivan.najera@lasallistas.org.mx,MG 70093203,0) [ID=6183] ##SELECT * FROM fi_horario(2, 08:00:00,14:00:00,037,70,Geriatr铆a,MD030717,017243,DOMINGA ALBERTA SALOMON CORTEZ,,MG 70070601,0) [ID=6184] ##SELECT * FROM fi_horario(2, 08:00:00,10:00:00,037,70,Medicina interna (internado de pregrado),MD041117,011870,NORBERTO REYES PAREDES,norbertoreyes@lasallistas.org.mx,MG 70092604,0) [ID=6185] ##SELECT * FROM fi_horario(2, 12:00:00,18:00:00,037,70,Otorrinolaringolog铆a,MD030317,010570,SERGIO IV脕N GONZ脕LEZ OLVERA,sigo@lasallistas.org.mx,MG 70070703,887) [ID=6186] ##SELECT * FROM fi_horario(2, 12:00:00,18:00:00,037,70,Otorrinolaringolog铆a,MD030317,013134,DINA FABIOLA GONZ脕LEZ S脕NCHEZ,df.gonzalezs@lasallistas.org.mx,MG 70070703,887) [ID=6187] ##SELECT * FROM fi_horario(2, 14:00:00,16:00:00,037,70,Ginecolog铆a y obstetricia (internado de pregrado),MD031217,010124,ENRIQUE JUAN D脥AZ GREENE,do_enrique.Diaz@lasallistas.org.mx,MG 70090102,855) [ID=6188] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,007232,MIGUEL VILLA GUERRERO,miguel.villa@lasallistas.org.mx,MG 70080604,0) [ID=6189] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016016,MANUEL FRANCISCO BORGES IB脕脩EZ,manuelborges@lasallistas.org.mx,MG 70080604,0) [ID=6190] ##SELECT * FROM fi_horario(2, 14:00:00,20:15:00,037,70,Ginecolog铆a y obstetricia,MD030917,016116,JES脷S CARLOS BRIONES GARDU脩O,jesus.briones@lasallistas.org.mx,MG 70080604,0) [ID=6191] ## +2023-08-09 00:30:36||SELECT * FROM fu_horario_deshabilita(2218) ## SELECT * FROM fu_horario_deshabilita(6432) ## SELECT * FROM fu_horario_deshabilita(2345) ## SELECT * FROM fu_horario_deshabilita(2319) ## SELECT * FROM fu_horario_deshabilita(2206) ## +2023-08-09 00:30:36||SELECT * FROM fi_horario(3, '10:30:00','12:00:00','038','69','Valores y 茅tica profesional','FI020613','015060','M脫NICA RUIZ ESQUIVEL','monica.ruiz@lasalle.mx','MG 69070601',820); [ID=6634] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','036','79','La persona y su interacci贸n con los otros','PS151113','','','','MG 79030601',0); [ID=6635] ##SELECT * FROM fi_horario(3, '12:00:00','13:30:00','032','25','La persona y su interacci贸n con los otros','PS151113','','','','MG 25030201',0); [ID=6636] ##SELECT * FROM fi_horario(3, '07:15:00','08:45:00','026','68','Voleibol, b茅isbol y deportes con raqueta','DP050319','015415','HECTOR JAVIER BECERRA HUERTA','hectorbecerra@lasallistas.org.mx','MG 68030105',1208); [ID=6637] ##SELECT * FROM fi_horario(3, '07:15:00','08:45:00','026','76','Cl铆nica integral','MD102620','017501','KARIM BUCHAHIN HUESCA','','MG 76070104',1221); [ID=6638] ##SELECT * FROM fi_horario(3, '08:45:00','10:15:00','026','76','Cl铆nica integral','MD102620','017501','KARIM BUCHAHIN HUESCA','','MG 76070104',1221); [ID=6639] ##SELECT * FROM fi_horario(3, '08:45:00','10:15:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','','MG 68050102',1231); [ID=6640] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','026','76','Cl铆nica integral','MD102620','017501','KARIM BUCHAHIN HUESCA','','MG 76070104',1408); [ID=6641] ## +2023-08-09 07:00:35||SELECT * FROM fu_horario_deshabilita(6394) ## SELECT * FROM fu_horario_deshabilita(6377) ## +2023-08-09 07:00:36||SELECT * FROM fi_horario(3, '10:30:00','12:00:00','038','69','Valores y 茅tica profesional','FI020613','015060','M脫NICA RUIZ ESQUIVEL','monica.ruiz@lasalle.mx','MG 69070601',820); [ID=6642] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','036','79','La persona y su interacci贸n con los otros','PS151113','','','','MG 79030601',0); [ID=6643] ##SELECT * FROM fi_horario(3, '12:00:00','13:30:00','032','25','La persona y su interacci贸n con los otros','PS151113','','','','MG 25030201',0); [ID=6644] ##SELECT * FROM fi_horario(3, '17:15:00','18:45:00','036','45','Normatividad de la ingenier铆a civil','DE050213','017136','CARLOS S脕NCHEZ G脫MEZ','csanchezg2@lasallistas.org.mx','MG 45050103',355); [ID=6645] ##SELECT * FROM fi_horario(3, '19:00:00','20:30:00','036','45','Hidr谩ulica de canales','GH010213','014049','ILDEFONSO L脫PEZ GONZ脕LEZ','ildefonso.lopez@lasallistas.org.mx','MG 45050102',269); [ID=6646] ## +2023-08-09 13:18:01||SELECT * FROM fu_horario_deshabilita(4479) ## SELECT * FROM fu_horario_deshabilita(4241) ## SELECT * FROM fu_horario_deshabilita(4144) ## SELECT * FROM fu_horario_deshabilita(4254) ## SELECT * FROM fu_horario_deshabilita(4270) ## SELECT * FROM fu_horario_deshabilita(4175) ## SELECT * FROM fu_horario_deshabilita(4378) ## SELECT * FROM fu_horario_deshabilita(4143) ## SELECT * FROM fu_horario_deshabilita(4413) ## SELECT * FROM fu_horario_deshabilita(4267) ## SELECT * FROM fu_horario_deshabilita(4493) ## SELECT * FROM fu_horario_deshabilita(4387) ## SELECT * FROM fu_horario_deshabilita(4395) ## SELECT * FROM fu_horario_deshabilita(4463) ## SELECT * FROM fu_horario_deshabilita(4558) ## SELECT * FROM fu_horario_deshabilita(4919) ## SELECT * FROM fu_horario_deshabilita(4850) ## SELECT * FROM fu_horario_deshabilita(4890) ## SELECT * FROM fu_horario_deshabilita(4814) ## SELECT * FROM fu_horario_deshabilita(4791) ## SELECT * FROM fu_horario_deshabilita(4821) ## SELECT * FROM fu_horario_deshabilita(4695) ## SELECT * FROM fu_horario_deshabilita(4350) ## SELECT * FROM fu_horario_deshabilita(4253) ## SELECT * FROM fu_horario_deshabilita(4860) ## SELECT * FROM fu_horario_deshabilita(4851) ## SELECT * FROM fu_horario_deshabilita(4829) ## SELECT * FROM fu_horario_deshabilita(4354) ## SELECT * FROM fu_horario_deshabilita(4873) ## SELECT * FROM fu_horario_deshabilita(4774) ## SELECT * FROM fu_horario_deshabilita(4729) ## SELECT * FROM fu_horario_deshabilita(4574) ## SELECT * FROM fu_horario_deshabilita(4132) ## SELECT * FROM fu_horario_deshabilita(4242) ## SELECT * FROM fu_horario_deshabilita(4465) ## SELECT * FROM fu_horario_deshabilita(4928) ## SELECT * FROM fu_horario_deshabilita(4909) ## SELECT * FROM fu_horario_deshabilita(4221) ## SELECT * FROM fu_horario_deshabilita(4657) ## SELECT * FROM fu_horario_deshabilita(4109) ## SELECT * FROM fu_horario_deshabilita(4656) ## +2023-08-09 13:18:01||SELECT * FROM fi_horario(5, '07:15:00','08:45:00','034','33','M茅todos y t茅cnicas de las ciencias sociales','IN030315','014502','LEONARDO DANIEL S脕NCHEZ ROJAS','ldsr@lasallistas.org.mx','MG 33010207',1027); [ID=6847] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','033','85','Razonamiento cr铆tico cuantitativo','MA021021','016603','CIPACTLI MILL脕N GARC脥A','cipactlimillan@lasallistas.org.mx','MG 85010107',1084); [ID=6848] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','033','81','Geometr铆a del plano','MA070317','016967','ALFONSO HERNANDEZ MONTES','alfonso.hernandez@lasallistas.org.mx','MG 81010105',746); [ID=6849] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','033','81','C谩lculo diferencial','MA022717','015889','GUADALUPE GAYT脕N G脫MEZ','g.gaytang@lasallistas.org.mx','MG 81010202',748); [ID=6850] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','036','79','Dise帽o l贸gico','ET020120','002307','MANUEL REYES VILLA','m.reyes@lasallistas.org.mx','MG 79030104',456); [ID=6851] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','016616','DANIEL OCHOA RODR脥GUEZ','d.ochoa@lasallistas.org.mx','MG 23070104',1044); [ID=6852] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','015078','LUIS MIGUEL RODR脥GUEZ MORENO','rodriguez.luis@lasallistas.org.mx','MG 23070201',1044); [ID=6853] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','034','33','M茅xico en el siglo XIX','HI051115','','','','MG 33010208',1027); [ID=6854] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','034','33','Estados Unidos y Canad谩: pol铆tica y gobierno','GE051515','017318','MICHELLE CALDER脫N GARC脥A','michelle.calderon@lasallistas.org.mx','MG 33020103',1028); [ID=6855] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','85','Contabilidad administrativa','CO010121','016602','F脕TIMA MONTSERRAT GONZ脕LEZ RIVERA','fatima.gonzalez@lasallistas.org.mx','MG 85010103',1084); [ID=6856] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','85','Razonamiento cr铆tico cuantitativo','MA021021','016603','CIPACTLI MILL脕N GARC脥A','cipactlimillan@lasallistas.org.mx','MG 85010207',1085); [ID=6857] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','81','Fundamentos de 谩lgebra','MA060917','015012','MARIA SOLEDAD ARRIAGA','msoledad.arriaga@lasallistas.org.mx','MG 81010104',746); [ID=6858] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','81','Geometr铆a del plano','MA070317','015939','MAURICIO ALEXANDER BARRERA CEBALLOS','mauricio.barrera@lasalle.mx','MG 81010205',753); [ID=6859] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','036','74','Manufactura b谩sica','TM020120','016421','ERICK RAM脥REZ AGUILAR','erick.ramirez@lasalle.mx','MG 74030105',453); [ID=6860] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','011212','ENRIQUE MANUEL ADALID TEJA','enrique.adalid@lasallistas.org.mx','MG 23070104',1044); [ID=6861] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','036','75','Introducci贸n a los componentes mecatr贸nicos','MT010320','016923','MANUEL ELADIO HUNTER SANCHEZ','manuel.hunter@lasallistas.org.mx','MG 75020106',0); [ID=6862] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','033','85','Microeconom铆a','EC010621','016801','GERARDO ERNESTO CASTRO GIL','gerardo.castro@lasallistas.org.mx','MG 85010205',1085); [ID=6863] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','033','96','Campo profesional de los negocios','AD011617','017281','JUAN MIGUEL FELICIANO VEGA HERNANDEZ','jvega@lasallistas.org.mx','MG 96010103',1088); [ID=6864] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','032','28','Laboratorio de morfolog铆a y energ铆a','DI020417','016340','M脫NICA P脡REZ B脕EZ','m-pb@lasallistas.org.mx','MG 28030202',342); [ID=6865] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','033','81','Fundamentos de 谩lgebra','MA060917','015012','MARIA SOLEDAD ARRIAGA','msoledad.arriaga@lasallistas.org.mx','MG 81010204',753); [ID=6866] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','80','Pr谩cticas hospitalarias','PU070113','014278','SANDRA LUZ ROCHA NAVA','sandrarocha@lasallistas.org.mx','MG 80090205',1010); [ID=6867] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','80','Pr谩cticas hospitalarias','PU070113','015987','MARIA DEL CARMEN ARQUER RUIZ','maria.arquer@lasallistas.org.mx','MG 80090105',1010); [ID=6868] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','79','Electr贸nica e interfaces aplicadas a la rob贸tica','ET020620','007878','MAURICIO ALBERTO MART脥NEZ GARC脥A','mauricio.martinez@lasallistas.org.mx','MG 79030106',456); [ID=6869] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','78','Termodin谩mica','EN020413','013557','GABRIELA MAC脥AS ESQUIVEL','gabriela.macias@lasalle.mx','MG 78040105',455); [ID=6870] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','79','Dise帽o l贸gico','ET020120','009273','OCTAVIO RODR脥GUEZ TORRES','octavio.rodriguez@lasalle.mx','MG 79030204',454); [ID=6871] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','014917','VERONICA MARTINEZ ROBLES','veronica.martinez@lasallistas.org.mx','MG 23070104',1044); [ID=6872] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','032','23','Taller de proyecto urbano-arquitect贸nico I','AR022315','015084','LILIANA TERESA PEREZ SANCHEZ','liliana.perez@lasallistas.org.mx','MG 23070201',1044); [ID=6873] ##SELECT * FROM fi_horario(5, '10:30:00','13:30:00','038','69','Laboratorio b谩sico de ciencias','IN040415','012651','MAR脥A PIEDAD L脫PEZ ORTAL','piedad.lopez@lasalle.mx','MG 69010801',820); [ID=6874] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','033','81','Teor铆a del seguro','CO110117','016185','脕NGEL CUEVAS ROMERO','angel.cuevas@lasallistas.org.mx','MG 81010106',1085); [ID=6875] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','033','96','Campo profesional de los negocios','AD011617','017281','JUAN MIGUEL FELICIANO VEGA HERNANDEZ','jvega@lasallistas.org.mx','MG 96010203',852); [ID=6876] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','033','85','Conformaci贸n legal de los negocios','DE050121','014307','JORGE MART脥NEZ CRUZ','jorge.martinez@lasallistas.org.mx','MG 85010202',1088); [ID=6877] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','80','Pr谩cticas hospitalarias','PU070113','015112','JOS脡 ISRAEL HERN脕NDEZ OROPEZA','jose.hernandez@lasalle.mx','MG 80090205',1010); [ID=6878] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','80','Pr谩cticas hospitalarias','PU070113','015987','MARIA DEL CARMEN ARQUER RUIZ','maria.arquer@lasallistas.org.mx','MG 80090105',1010); [ID=6879] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','46','Termodin谩mica','EN020420','013557','GABRIELA MAC脥AS ESQUIVEL','gabriela.macias@lasalle.mx','MG 46030107',455); [ID=6880] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','79','Electr贸nica e interfaces aplicadas a la rob贸tica','ET020620','007878','MAURICIO ALBERTO MART脥NEZ GARC脥A','mauricio.martinez@lasallistas.org.mx','MG 79030206',454); [ID=6881] ##SELECT * FROM fi_horario(5, '13:30:00','15:00:00','026','29','Fisiolog铆a del ejercicio','MD093017','016883','LEONARDO LEBIB AZAR HERNANDEZ','leonardo.azar@lasallistas.org.mx','MG 29020103',1231); [ID=6882] ##SELECT * FROM fi_horario(5, '13:30:00','16:30:00','026','29','Seminario de bio茅tica','FI021013','015060','M脫NICA RUIZ ESQUIVEL','monica.ruiz@lasalle.mx','MG 29070206',820); [ID=6883] ##SELECT * FROM fi_horario(5, '13:30:00','15:00:00','036','75','Manufactura integrada por computadora','TM020413','','','','MG 75090201',0); [ID=6884] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','96','Teor铆a de juegos','MA044517','014794','LUIS ANTONIO ANDRADE ROSAS','luis.andrade@lasalle.mx','MG 96060106',843); [ID=6885] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','038','77','Lengua extranjera I','LI020113','015808','KYOKO MASAKI','k.masaki@lasallistas.org.mx','MG 77030107',566); [ID=6886] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','96','Seminario y an谩lisis de casos de negocios en 谩mbitos locales','AD031717','014365','JOSE MANUEL RIVERA ZARAGOZA','jm.riveraz@lasallistas.org.mx','MG 96070108',186); [ID=6887] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','18','Administraci贸n de la mercadotecnia de productos y servicios','ME030717','016970','ADRIAN RENE SALAZAR PINEDA','adrian.salazar@lasallistas.org.mx','MG 18070102',1088); [ID=6888] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','036','79','Tecnolog铆as de redes convergentes','CE030713','','','','MG 79090211',841); [ID=6889] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','036','46','Automatizaci贸n industrial','MT010213','017008','ALEXIS ADRIAN ORTIZ OLVERA','alexis.ortiz@lasallistas.org.mx','MG 46070102',466); [ID=6890] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','034','32','Amparo','DE121615','014984','MARIO MEJIA KARGL','mariomejia@lasallistas.org.mx','MG 32070102',145); [ID=6891] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','016615','SERGIO ENRIQUE L脫PEZ JACOB','sergiolopez@lasallistas.org.mx','MG 23080201',1044); [ID=6892] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','014674','LISSETT YADIRA SERRA GORJON','lissetserra@lasallistas.org.mx','MG 23080104',1044); [ID=6893] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','017418','HELENA ROLDAN GONZALEZ','helenaroldan@lasallistas.org.mx','MG 23080301',1044); [ID=6894] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','033','07','An谩lisis del comportamiento del consumidor','ME020117','013458','ARTURO CUEVAS MART脥NEZ','arturo.cuevas@lasalle.mx','MG 07070201',187); [ID=6895] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','034','32','Teor铆a del derecho','DE010915','017143','RICARDO LEON CARAVEO','ricardo.leon@lasallistas.org.mx','MG 32010407',177); [ID=6896] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','034','32','Sistemas jur铆dicos contempor谩neos','DE011015','013940','EDITH GUZM脕N V脕ZQUEZ','egv@lasallistas.org.mx','MG 32030304',171); [ID=6897] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','033','96','Seminario y an谩lisis de casos de negocios en 谩mbitos locales','AD031717','014365','JOSE MANUEL RIVERA ZARAGOZA','jm.riveraz@lasallistas.org.mx','MG 96070207',748); [ID=6898] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','036','79','Modelos determin铆sticos y estoc谩sticos','PC030313','013909','脕NGEL ALFONSO D脥AZ GONZ脕LEZ','angel.diaz@lasalle.mx','MG 79070104',353); [ID=6899] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','036','79','Miner铆a de datos e inteligencia de negocios','IC020913','','','','MG 79090209',842); [ID=6900] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','036','04','Procesamiento digital de se帽ales','CE040413','007878','MAURICIO ALBERTO MART脥NEZ GARC脥A','mauricio.martinez@lasallistas.org.mx','MG 04070103',457); [ID=6901] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','015621','GUSTAVO D脥AZ ESPINOSA','gustavodiaz@lasallistas.org.mx','MG 23080201',1044); [ID=6902] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','011212','ENRIQUE MANUEL ADALID TEJA','enrique.adalid@lasallistas.org.mx','MG 23080104',1044); [ID=6903] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','016362','MIGUEL FEDERICO MURGU脥A D脥AZ','miguelmurguia@lasallistas.org.mx','MG 23080301',1044); [ID=6904] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','036','75','Fe y desarrollo espiritual','PS151213','','','','MG 75050101',0); [ID=6905] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','033','07','Estructura de marca','ME040615','017522','CRISTINA YAZM脥N FERN脕NDEZ RODR脥GUEZ','cristina.fernandez@lasallistas.org.mx','MG 07070204',1093); [ID=6906] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','45','Resistencia de materiales','FS020513','016243','JOS脡 ANTONIO ROSALES ALANIZ','ja.rosales@lasallistas.org.mx','MG 45050104',355); [ID=6907] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','79','Gesti贸n de proyectos de tecnolog铆as de la informaci贸n y centros de datos','AD051213','008444','JAIME ROBERTO GONZ脕LEZ HERN脕NDEZ','jaime.gonzalez@lasallistas.org.mx','MG 79090106',841); [ID=6908] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','79','Aplicaciones m贸viles','IC031813','017335','FELIPE MANDUJANO G脫MEZ','felipe.mandujano@lasallistas.org.mx','MG 79090202',842); [ID=6909] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','79','Taller de conectividad','CE030613','011759','RA脷L ALBERTO CHAVEZ ARREOLA','raul.chavez@lasallistas.org.mx','MG 79070106',1180); [ID=6910] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','75','Dise帽o l贸gico','ET020113','009273','OCTAVIO RODR脥GUEZ TORRES','octavio.rodriguez@lasalle.mx','MG 75060103',457); [ID=6911] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','036','75','Automatizaci贸n industrial','MT010213','017128','ADRIAN LOPEZ SILVA','adrianlopez@lasallistas.org.mx','MG 75070102',466); [ID=6912] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','038','69','Qu铆mica criminal铆stica','BI071315','013723','VELIA IZCHEL REYES GONZ脕LEZ','velia.reyes@lasallistas.org.mx','MG 69090109',770); [ID=6913] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','033','07','Mercadotecnia social y de servicios','ME030217','','','','MG 07050105',260); [ID=6914] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','014672','JAVIER ISRAEL RAMIREZ SANCHEZ','israel.ramirez@lasallistas.org.mx','MG 23080201',1044); [ID=6915] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','016616','DANIEL OCHOA RODR脥GUEZ','d.ochoa@lasallistas.org.mx','MG 23080104',1044); [ID=6916] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','032','23','Taller de proyecto urbano-arquitect贸nico II','AR022415','016795','JUAN ANTONIO MORENO GONZALEZ','ja.mg@lasallistas.org.mx','MG 23080301',1044); [ID=6917] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','033','07','Estructura de marca','ME040615','017522','CRISTINA YAZM脥N FERN脕NDEZ RODR脥GUEZ','cristina.fernandez@lasallistas.org.mx','MG 07070204',1093); [ID=6918] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','034','33','Justicia alternativa','DE122415','014734','MARIA CECILIA MENA PANTOJA','mc.mena@lasallistas.org.mx','MG 33080104',1038); [ID=6919] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','036','79','Gesti贸n de proyectos de tecnolog铆as de la informaci贸n y centros de datos','AD051213','008444','JAIME ROBERTO GONZ脕LEZ HERN脕NDEZ','jaime.gonzalez@lasallistas.org.mx','MG 79090207',841); [ID=6920] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','036','75','Principios de electr贸nica anal贸gica','ET010713','016170','JOSE DE JESUS GUTIERREZ CORTES','jgutierrez@lasallistas.org.mx','MG 75050203',456); [ID=6921] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','036','75','Automatizaci贸n industrial','MT010213','017128','ADRIAN LOPEZ SILVA','adrianlopez@lasallistas.org.mx','MG 75070202',466); [ID=6922] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','033','96','Procesos estoc谩sticos','MA044417','017528','IREN CASTILLO SALDA脩A','','MG 96050107',229); [ID=6923] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','033','07','Mercadotecnia social y de servicios','ME030217','','','','MG 07050205',264); [ID=6924] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','038','65','Ingenier铆a econ贸mica','EC020515','017517','REGINA MONTSERRAT CANALS LOPEZ VELARDE','rlopezv2@lasallistas.org.mx','MG 65070104',1308); [ID=6925] ##SELECT * FROM fi_horario(5, '07:00:00','08:30:00','037','70','Psicolog铆a m茅dica','PS060217','','','','MG 70010107',319); [ID=6926] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','007232','MIGUEL VILLA GUERRERO','miguel.villa@lasallistas.org.mx','MG 70080505',0); [ID=6927] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','016016','MANUEL FRANCISCO BORGES IB脕脩EZ','manuelborges@lasallistas.org.mx','MG 70080505',0); [ID=6928] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','016116','JES脷S CARLOS BRIONES GARDU脩O','jesus.briones@lasallistas.org.mx','MG 70080505',0); [ID=6929] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Pediatr铆a','MD030817','010577','MONICA VILLA GUILLEN','m.mvg@lasallistas.org.mx','MG 70080702',0); [ID=6930] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Pediatr铆a','MD030817','016599','CARLOS PATRICIO ACOSTA RODR脥GUEZ BUENO','cp.acosta@lasallistas.org.mx','MG 70080702',0); [ID=6931] ##SELECT * FROM fi_horario(5, '07:00:00','13:15:00','037','70','Pediatr铆a','MD030817','014626','ELISA MAR脥A DORANTES ACOSTA','','MG 70080702',0); [ID=6932] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','010124','ENRIQUE JUAN D脥AZ GREENE','do_enrique.Diaz@lasallistas.org.mx','MG 70090106',855); [ID=6933] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','008098','ISAAC ZAGA MINIAN','','MG 70090506',871); [ID=6934] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017381','JAIME ANTONIO HIDALGO CARRERA','','MG 70090906',899); [ID=6935] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Dermatolog铆a','MD030517','017105','MAR脥A TERESA BARR脫N TAPIA','maria.barron@lasallistas.org.mx','MG 70060702',854); [ID=6936] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Endocrinolog铆a','MD040717','013905','MARTHA EUNICE RODR脥GUEZ ARELLANO','mera@lasallistas.org.mx','MG 70050502',854); [ID=6937] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Endocrinolog铆a','MD040717','013878','PERLA ALICIA CARRILLO GONZ脕LEZ','perlacarrillo@lasallistas.org.mx','MG 70050502',854); [ID=6937] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Patolog铆a quir煤rgica','MD020217','017131','ANTONIO CORONA BAUTISTA','antoniocorona@lasallistas.org.mx','MG 70070504',854); [ID=6938] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','015425','GUILLERMO CESAR PEREZ PELAEZ','','MG 70090206',885); [ID=6939] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017378','DANIELA ALEJANDRA LEMIONET ESCANERO','','MG 70090706',860); [ID=6940] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Otorrinolaringolog铆a','MD030317','010570','SERGIO IV脕N GONZ脕LEZ OLVERA','sigo@lasallistas.org.mx','MG 70070503',887); [ID=6941] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Otorrinolaringolog铆a','MD030317','013134','DINA FABIOLA GONZ脕LEZ S脕NCHEZ','df.gonzalezs@lasallistas.org.mx','MG 70070503',887); [ID=6941] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Dermatolog铆a','MD030517','004730','MAR脥A IVONNE ARELLANO MENDOZA','mi.arellanom@lasallistas.org.mx','MG 70060505',889); [ID=6942] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Dermatolog铆a','MD030517','016545','MARIELA GALICIA MALDONADO','marielagalicia@lasallistas.org.mx','MG 70060505',889); [ID=6942] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Dermatolog铆a','MD030517','013299','ROSA MAR脥A PONCE OLIVERA','','MG 70060505',889); [ID=6942] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','016259','CESAR FIRETH POZO BELTR脕N','','MG 70091006',896); [ID=6943] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Psiquiatr铆a','MD030617','016606','ADOLFO NERI HERN脕NDEZ','adolfo.neri@lasallistas.org.mx','MG 70050704',1013); [ID=6944] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Psiquiatr铆a','MD030617','015698','CARLOS HERNANDEZ VEGA','c.hv@lasallistas.org.mx','MG 70050704',1013); [ID=6944] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017310','NORMA VELIA BALLESTEROS SOLIS','norma.ballesteros@lasallistas.org.mx','MG 70093006',1012); [ID=6945] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017062','ERNESTO FIGUEROA TELLEZ','','MG 70091806',1272); [ID=6946] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','016280','MARIA ANOTA RIVERA','','MG 70092906',1267); [ID=6947] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Traumatolog铆a y ortopedia','MD030417','014130','SERGIO G脫MEZ LLATA GARC脥A','s.gomezl@lasallistas.org.mx','MG 70070608',1004); [ID=6948] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Traumatolog铆a y ortopedia','MD030417','015181','MANUEL ALEJANDRO AGUILAR ARAIZA','manuel.aguilar@lasallistas.org.mx','MG 70070608',1004); [ID=6948] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Traumatolog铆a y ortopedia','MD030417','014136','LEOBARDO GUERRERO BELTRAN','leobardo.guerrero@lasallistas.org.mx','MG 70070608',1004); [ID=6948] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','016952','ERIKA GOMEZ ZAMORA','','MG 70092206',1004); [ID=6949] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Gastroenterolog铆a','MD040417','012899','JORGE HERN脕NDEZ CALLEROS','','MG 70060606',892); [ID=6950] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Gastroenterolog铆a','MD040417','015294','ENRIQUE COSS ADAME','enrique.coss@lasallistas.org.mx','MG 70060606',892); [ID=6950] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Infectolog铆a','MD040917','014138','ARTURO GALINDO FRAGA','arturo.galindo@lasallistas.org.mx','MG 70060608',892); [ID=6951] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Infectolog铆a','MD040917','016584','MAR脥A FERNANDA GONZ脕LEZ LARA','','MG 70060608',892); [ID=6951] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Infectolog铆a','MD040917','015231','ERIC OCHOA HEIN','eric.ochoa@lasallistas.org.mx','MG 70060608',892); [ID=6951] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Neumolog铆a','MD040217','013617','PATRICIA CASTILLO GONZ脕LEZ','patricia.castillo@lasallistas.org.mx','MG 70050605',886); [ID=6952] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Neumolog铆a','MD040217','015554','TERESA DE JESUS AGUIRRE PEREZ','teresa.aguirre@lasallistas.org.mx','MG 70050605',886); [ID=6952] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Neumolog铆a','MD040217','016098','SERGIO MONRAZ PEREZ','','MG 70050605',886); [ID=6952] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','015452','CARMEN ZAVALA GARC脥A','','MG 70090406',863); [ID=6953] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Cardiolog铆a','MD040117','008725','CARLOS HAROLDO IXCAMPARIJ ROSALES','chir@lasallistas.org.mx','MG 70050501',869); [ID=6954] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Cardiolog铆a','MD040117','015880','ROBERTO MURATALLA GONZ脕LEZ','','MG 70050501',869); [ID=6954] ##SELECT * FROM fi_horario(5, '08:00:00','14:15:00','037','70','Cardiolog铆a','MD040117','009026','GREGORIO ZARAGOZA RODRIGUEZ','','MG 70050501',869); [ID=6954] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017240','ROBERTO BADIR CORANGUEZ CAPISTRAN','','MG 70091606',0); [ID=6955] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','011870','NORBERTO REYES PAREDES','norbertoreyes@lasallistas.org.mx','MG 70092606',0); [ID=6956] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017238','ERIK REBOLLEDO GARDU脩O','','MG 70092806',0); [ID=6957] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Urgencias (internado de pregrado)','MD031317','017382','RODOLFO SILVA ROMO','','MG 70093106',0); [ID=6958] ##SELECT * FROM fi_horario(5, '08:00:00','10:00:00','037','70','Medicina familiar y comunitaria (internado de pregrado)','MD031417','013926','ABEL FUENTES VENEGAS','abelfuentes@lasallistas.org.mx','MG 70090303',0); [ID=6959] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','','MG 68050102',0); [ID=6960] ##SELECT * FROM fi_horario(5, '11:00:00','16:00:00','037','70','Proped茅utica cl铆nica y nosolog铆a','MD010417','010124','ENRIQUE JUAN D脥AZ GREENE','do_enrique.Diaz@lasallistas.org.mx','MG 70040504',0); [ID=6961] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','','MG 68050102',0); [ID=6962] ##SELECT * FROM fi_horario(5, '16:00:00','18:00:00','037','70','Oncolog铆a','MD031017','009308','FRANCISCO MARIO GARC脥A RODR脥GUEZ','','MG 70050108',0); [ID=6963] ##SELECT * FROM fi_horario(5, '16:00:00','18:00:00','037','70','Sexualidad humana','MD041217','017258','OSCAR JES脷S CU脡LLAR GONZ脕LEZ','oscar.cuellar@lasallistas.org.mx','MG 70080608',0); [ID=6964] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Oncolog铆a','MD031017','009308','FRANCISCO MARIO GARC脥A RODR脥GUEZ','','MG 70050408',0); [ID=6965] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Oncolog铆a','MD031017','','','','MG 70050308',0); [ID=6966] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Sexualidad humana','MD041217','017258','OSCAR JES脷S CU脡LLAR GONZ脕LEZ','oscar.cuellar@lasallistas.org.mx','MG 70080509',0); [ID=6967] ## +2023-08-09 18:52:17||SELECT * FROM fu_horario_deshabilita(2826) ## SELECT * FROM fu_horario_deshabilita(2552) ## SELECT * FROM fu_horario_deshabilita(6406) ## SELECT * FROM fu_horario_deshabilita(2530) ## +2023-08-09 18:52:17||SELECT * FROM fi_horario(3, '07:15:00','08:45:00','032','23','Taller de composici贸n pl谩stica y expresi贸n','AR020322','016889','TANIA SABRINA ORTIZ RAMIREZ','tania-ortiz@lasallistas.org.mx','MG 23011002',0); [ID=6968] ##SELECT * FROM fi_horario(3, '07:15:00','08:45:00','032','23','Taller de composici贸n pl谩stica y expresi贸n','AR020322','016325','ANDREA MONROY BRAHAM','andreamonroy@lasallistas.org.mx','MG 23010902',0); [ID=6969] ##SELECT * FROM fi_horario(3, '08:45:00','10:15:00','032','23','Principios b谩sicos de construcci贸n','CI020122','014672','JAVIER ISRAEL RAMIREZ SANCHEZ','israel.ramirez@lasallistas.org.mx','MG 23010506',0); [ID=6970] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','038','69','Valores y 茅tica profesional','FI020613','015060','M脫NICA RUIZ ESQUIVEL','monica.ruiz@lasalle.mx','MG 69070601',820); [ID=6971] ##SELECT * FROM fi_horario(3, '10:30:00','13:30:00','032','23','Laboratorio de an谩lisis','AR021022','015622','KARINA CONTRERAS CASTELLANOS','k.contreras@lasallistas.org.mx','MG 23011501',0); [ID=6972] ##SELECT * FROM fi_horario(3, '10:30:00','12:00:00','036','79','La persona y su interacci贸n con los otros','PS151113','','','','MG 79030601',0); [ID=6973] ##SELECT * FROM fi_horario(3, '10:30:00','13:30:00','032','23','Laboratorio de an谩lisis','AR021022','016889','TANIA SABRINA ORTIZ RAMIREZ','tania-ortiz@lasallistas.org.mx','MG 23011601',0); [ID=6974] ##SELECT * FROM fi_horario(3, '12:00:00','13:30:00','032','25','La persona y su interacci贸n con los otros','PS151113','','','','MG 25030201',0); [ID=6975] ##SELECT * FROM fi_horario(3, '13:30:00','15:00:00','032','84','Imaginarios en el arte','AH010722','017111','MARICELA GABRIELA BERMEO CASTREJ脫N','maricela.bermeo@lasallistas.org.mx','MG 84010105',350); [ID=6976] ##SELECT * FROM fi_horario(3, '13:30:00','15:00:00','032','23','Dibujo arquitect贸nico','EX010322','017291','IGNACIO ANAYA HERNANDEZ','ignacio.anaya@lasallistas.org.mx','MG 23010703',0); [ID=6977] ##SELECT * FROM fi_horario(3, '15:45:00','17:15:00','032','23','Geometr铆a descriptiva','EX030122','016981','DORITA HERAS MONTES DE OCA','dorita.heras@lasallistas.org.mx','MG 23010704',0); [ID=6978] ##SELECT * FROM fi_horario(3, '17:15:00','18:45:00','033','18','Aplicaciones tecnol贸gicas especializadas','IC090217','016203','DANIEL MORENO JIMENEZ','danielmoreno@lasallistas.org.mx','MG 18040103',1182); [ID=6979] ##SELECT * FROM fi_horario(3, '20:30:00','22:00:00','035','99','Introducci贸n a la biblia y bases de ex茅gesis','TE030321','','','','MG 99010102',820); [ID=6980] ##SELECT * FROM fi_horario(3, '08:00:00','14:00:00','037','70','Geriatr铆a','MD030717','017513','OMAR WILLIAM GONZ脕LEZ HERN脕NDEZ','','MG 70070302',0); [ID=6981] ##SELECT * FROM fi_horario(3, '08:00:00','14:00:00','037','70','Psiquiatr铆a','MD030617','017489','C脡SAR AUGUSTO CELADA BORJA','','MG 70050309',0); [ID=6982] ##SELECT * FROM fi_horario(3, '12:00:00','14:00:00','037','70','Fisiolog铆a II','BI031017','016768','V脥CTOR MANUEL RODR脥GUEZ MOLINA','rodriguez.victor@lasallistas.org.mx','MG 70030206',0); [ID=6983] ##SELECT * FROM fi_horario(3, '14:00:00','15:30:00','037','70','Desarrollo del razonamiento cl铆nico','MD110417','017488','GABRIELA DE LA GUARDIA GONZ脕LEZ','gabrielade@lasallistas.org.mx','MG 70041002',0); [ID=6984] ## +2023-08-10 10:35:22||SELECT * FROM fu_horario_deshabilita(6881) ## SELECT * FROM fu_horario_deshabilita(6862) ## SELECT * FROM fu_horario_deshabilita(6871) ## SELECT * FROM fu_horario_deshabilita(4660) ## SELECT * FROM fu_horario_deshabilita(4620) ## SELECT * FROM fu_horario_deshabilita(4553) ## SELECT * FROM fu_horario_deshabilita(4765) ## SELECT * FROM fu_horario_deshabilita(4153) ## SELECT * FROM fu_horario_deshabilita(6962) ## SELECT * FROM fu_horario_deshabilita(6960) ## +2023-08-10 10:35:22||SELECT * FROM fi_horario(5, '07:15:00','08:45:00','032','27','Composici贸n tipogr谩fica','DG030415','','','','MG 27030204',348); [ID=7001] ##SELECT * FROM fi_horario(5, '07:15:00','10:15:00','032','23','Geometr铆a descriptiva','EX030122','016981','DORITA HERAS MONTES DE OCA','dorita.heras@lasallistas.org.mx','MG 23010704',0); [ID=7002] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','036','75','Introducci贸n a los componentes mecatr贸nicos','MT010320','016923','MANUEL ELADIO HUNTER SANCHEZ','manuel.hunter@lasallistas.org.mx','MG 75020106',261); [ID=7003] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','036','79','Dise帽o l贸gico','ET020120','009273','OCTAVIO RODR脥GUEZ TORRES','octavio.rodriguez@lasalle.mx','MG 79030204',457); [ID=7004] ##SELECT * FROM fi_horario(5, '10:30:00','13:30:00','032','23','Taller de composici贸n pl谩stica y expresi贸n','AR020322','016325','ANDREA MONROY BRAHAM','andreamonroy@lasallistas.org.mx','MG 23010902',0); [ID=7005] ##SELECT * FROM fi_horario(5, '10:30:00','13:30:00','032','23','Taller de composici贸n pl谩stica y expresi贸n','AR020322','016889','TANIA SABRINA ORTIZ RAMIREZ','tania-ortiz@lasallistas.org.mx','MG 23011002',0); [ID=7006] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','036','79','Electr贸nica e interfaces aplicadas a la rob贸tica','ET020620','007878','MAURICIO ALBERTO MART脥NEZ GARC脥A','mauricio.martinez@lasallistas.org.mx','MG 79030206',456); [ID=7007] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','036','04','Ingenier铆a de manufactura','TM020513','016862','MARIA FERNANDA TOLEDO ROMO','maria.toledo@lasallistas.org.mx','MG 04070102',453); [ID=7008] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','035','99','Eclesiolog铆a dogm谩tica','TE050621','015717','JULIO C脡SAR CARBAJAL MONTA脩O','juliocarbajal@lasallistas.org.mx','MG 99050101',1064); [ID=7009] ##SELECT * FROM fi_horario(5, '08:00:00','14:00:00','037','70','Geriatr铆a','MD030717','017513','OMAR WILLIAM GONZ脕LEZ HERN脕NDEZ','','MG 70070701',0); [ID=7010] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','japciri.fuentes@lasallistas.org.mx','MG 68050102',1209); [ID=7011] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','026','68','Educaci贸n en la recreaci贸n y el uso del tiempo libre','BN010419','017401','JAPCIRI SARAI FUENTES SOTELO','japciri.fuentes@lasallistas.org.mx','MG 68050102',1209); [ID=7012] ## +2023-08-11 14:35:03||SELECT * FROM fu_horario_deshabilita(4959) ## +2023-08-11 14:35:03||SELECT * FROM fi_horario(6, '07:15:00','08:45:00','036','45','Administraci贸n de proyectos','AD051113','015838','SERGIO ABEL GARC脥A CARRERA','sa-gc@lasallistas.org.mx','MG 45090101',226); [ID=7019] ##SELECT * FROM fi_horario(6, '07:45:00','09:15:00','034','32','Taller de proyecto profesional ocupacional','AD100313','','','','MG 32100101',820); [ID=7020] ##SELECT * FROM fi_horario(6, '07:45:00','09:15:00','033','09','Taller de empleo, autoempleo y actividad empresarial','AD100213','','','','MG 09070601',820); [ID=7021] ##SELECT * FROM fi_horario(6, '07:45:00','09:15:00','032','28','Emprendimiento y sustentabilidad','AD100113','','','','MG 28050301',820); [ID=7022] ##SELECT * FROM fi_horario(6, '08:00:00','12:30:00','038','69','Lengua extranjera I','LI020113','010262','DANIEL SANTILLANA GARC脥A','daniel.santillana@lasallistas.org.mx','MG 69030107',229); [ID=7023] ##SELECT * FROM fi_horario(6, '08:00:00','12:30:00','036','74','Lengua extranjera I','LI020113','013095','JOSUE RICARDO KOCH CALDERON','jkochc2@lasallistas.org.mx','MG 74040501',260); [ID=7024] ##SELECT * FROM fi_horario(6, '08:45:00','10:15:00','036','45','Seminario de an谩lisis de obras','OI020213','014928','ERNESTO RAMIREZ CORNEJO','ernesto.ramirez@lasallistas.org.mx','MG 45090107',226); [ID=7025] ##SELECT * FROM fi_horario(6, '08:45:00','10:15:00','036','45','Sistemas constructivos y concursos de obra','CI010313','017136','CARLOS S脕NCHEZ G脫MEZ','csanchezg2@lasallistas.org.mx','MG 45050105',396); [ID=7026] ##SELECT * FROM fi_horario(6, '08:45:00','10:15:00','036','45','Construcci贸n pesada','CI020213','016756','JOS脡 ANGEL LUNA RUIZ','ja.lunar@lasallistas.org.mx','MG 45070102',397); [ID=7027] ##SELECT * FROM fi_horario(6, '09:30:00','11:00:00','033','09','Taller de empleo, autoempleo y actividad empresarial','AD100213','','','','MG 09070601',820); [ID=7028] ##SELECT * FROM fi_horario(6, '09:30:00','11:00:00','032','28','Emprendimiento y sustentabilidad','AD100113','','','','MG 28050301',820); [ID=7029] ##SELECT * FROM fi_horario(6, '09:30:00','11:00:00','034','32','Taller de proyecto profesional ocupacional','AD100313','','','','MG 32100101',0); [ID=7030] ##SELECT * FROM fi_horario(6, '15:00:00','17:00:00','035','37','Taller de empleo, autoempleo y actividad empresarial','AD100213-D','012365','ALAIN LOREDO 脕LVAREZ','alainloredo@lasallistas.org.mx','MG 37090101',820); [ID=7031] ##SELECT * FROM fi_horario(6, '16:00:00','18:00:00','035','37','Procesos y expresi贸n del pensamiento','PS050213-D','015271','C脡SAR FRANCISCO CANT脫N RAMOS','cesar.canton@lasallistas.org.mx','MG 37010101',820); [ID=7032] ##SELECT * FROM fi_horario(6, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','007232','MIGUEL VILLA GUERRERO','miguel.villa@lasallistas.org.mx','MG 70080505',0); [ID=7033] ##SELECT * FROM fi_horario(6, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','016016','MANUEL FRANCISCO BORGES IB脕脩EZ','manuelborges@lasallistas.org.mx','MG 70080505',0); [ID=7034] ##SELECT * FROM fi_horario(6, '07:00:00','13:15:00','037','70','Ginecolog铆a y obstetricia','MD030917','016116','JES脷S CARLOS BRIONES GARDU脩O','jesus.briones@lasallistas.org.mx','MG 70080505',0); [ID=7035] ## +2023-08-17 11:12:59||SELECT * FROM fu_horario_deshabilita(4130) ## SELECT * FROM fu_horario_deshabilita(4239) ## SELECT * FROM fu_horario_deshabilita(4296) ## SELECT * FROM fu_horario_deshabilita(4349) ## SELECT * FROM fu_horario_deshabilita(4418) ## SELECT * FROM fu_horario_deshabilita(4501) ## SELECT * FROM fu_horario_deshabilita(4520) ## SELECT * FROM fu_horario_deshabilita(4536) ## SELECT * FROM fu_horario_deshabilita(4562) ## SELECT * FROM fu_horario_deshabilita(4564) ## SELECT * FROM fu_horario_deshabilita(4565) ## SELECT * FROM fu_horario_deshabilita(4568) ## SELECT * FROM fu_horario_deshabilita(4650) ## SELECT * FROM fu_horario_deshabilita(4689) ## SELECT * FROM fu_horario_deshabilita(4760) ## SELECT * FROM fu_horario_deshabilita(4803) ## SELECT * FROM fu_horario_deshabilita(4804) ## SELECT * FROM fu_horario_deshabilita(4805) ## SELECT * FROM fu_horario_deshabilita(4806) ## SELECT * FROM fu_horario_deshabilita(4867) ## SELECT * FROM fu_horario_deshabilita(4255) ## SELECT * FROM fu_horario_deshabilita(6914) ## SELECT * FROM fu_horario_deshabilita(6889) ## SELECT * FROM fu_horario_deshabilita(6924) ## SELECT * FROM fu_horario_deshabilita(4796) ## SELECT * FROM fu_horario_deshabilita(4219) ## SELECT * FROM fu_horario_deshabilita(4665) ## SELECT * FROM fu_horario_deshabilita(4336) ## SELECT * FROM fu_horario_deshabilita(6854) ## SELECT * FROM fu_horario_deshabilita(7001) ## SELECT * FROM fu_horario_deshabilita(4213) ## SELECT * FROM fu_horario_deshabilita(4302) ## SELECT * FROM fu_horario_deshabilita(4305) ## SELECT * FROM fu_horario_deshabilita(4415) ## SELECT * FROM fu_horario_deshabilita(6963) ## SELECT * FROM fu_horario_deshabilita(6964) ## SELECT * FROM fu_horario_deshabilita(6965) ## SELECT * FROM fu_horario_deshabilita(6967) ## SELECT * FROM fu_horario_deshabilita(7017) ## SELECT * FROM fu_horario_deshabilita(7018) ## SELECT * FROM fu_horario_deshabilita(6926) ## +2023-08-17 11:12:59||SELECT * FROM fi_horario(5, '07:15:00','08:45:00','033','07','Aplicaci贸n de las tecnolog铆as para los negocios','IC010417','016994','RODOLFO LEDESMA VALDEZ','rodolfo.ledesma@lasalle.mx','MG 07020102',432); [ID=7571] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','032','27','Composici贸n tipogr谩fica','DG030415','017529','ERIC OLIVARES LIRA','','MG 27030204',348); [ID=7572] ##SELECT * FROM fi_horario(5, '07:15:00','08:45:00','034','33','Conformaci贸n de la uni贸n europea','GE051715','012002','LUIS ANTONIO HUACUJA ACEVEDO','','MG 33030103',1042); [ID=7573] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','07','Herramientas tecnol贸gicas para los negocios','IC010117','017048','JAVIER GUILLERMO DI CARLO','javierdi@lasallistas.org.mx','MG 07010306',432); [ID=7574] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','034','33','M茅xico en el siglo XIX','HI051115','017540','ANDREA TORREALBA TORRE','','MG 33010208',1027); [ID=7575] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','033','81','C谩lculo integral','MA022817','017541','SERGIO IKER MART脥NEZ JU脕REZ','','MG 81020103',1087); [ID=7576] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','038','69','Biolog铆a celular','BI010515','015830','RODRIGO MART脥NEZ ESPINOSA','r.martineze@lasallistas.org.mx','MG 69020101',1306); [ID=7577] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','035','89','Epistemolog铆a','FI030714','017439','NATALIA ELIZABETH TALAVERA BABY','natalia.talavera@lasallistas.org.mx','MG 89010305',0); [ID=7578] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','033','81','Elementos de programaci贸n','IC032417','015386','ADOLFO RANGEL D脥AZ DE LA VEGA','adolfo.rangel@lasalle.mx','MG 81010103',432); [ID=7579] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','034','33','M茅xico en el siglo XIX','HI051115','017540','ANDREA TORREALBA TORRE','','MG 33010108',1026); [ID=7580] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','026','29','Anatom铆a y fisiolog铆a de aparatos y sistemas','BI031817','016883','LEONARDO LEBIB AZAR HERNANDEZ','leonardo.azar@lasallistas.org.mx','MG 29010101',1221); [ID=7581] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','035','89','Introducci贸n a la psicolog铆a','PS010714','010693','ADMA LIBIA FLORES VERGARA','alfv@lasallistas.org.mx','MG 89010307',0); [ID=7582] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','038','69','Lengua extranjera I','LI020113','014587','DALIA CARRE脩O ALVAREZ','dalia.carreno@lasallistas.org.mx','MG 69030403',364); [ID=7583] ##SELECT * FROM fi_horario(5, '12:00:00','13:30:00','026','29','Anatom铆a y fisiolog铆a de aparatos y sistemas','BI031817','016883','LEONARDO LEBIB AZAR HERNANDEZ','leonardo.azar@lasallistas.org.mx','MG 29010101',1221); [ID=7584] ##SELECT * FROM fi_horario(5, '13:30:00','15:00:00','026','29','F铆sica','FS010717','017434','JOS脡 MIGUEL SANTILL脕N S脕NCHEZ','josesantillan@lasallistas.org.mx','MG 29010104',1221); [ID=7585] ##SELECT * FROM fi_horario(5, '14:00:00','15:30:00','033','03','Lengua extranjera I','LI020113','014587','DALIA CARRE脩O ALVAREZ','dalia.carreno@lasallistas.org.mx','MG 03030302',499); [ID=7586] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','81','Lengua extranjera I','LI020113','014587','DALIA CARRE脩O ALVAREZ','dalia.carreno@lasallistas.org.mx','MG 81030101',498); [ID=7587] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','034','32','Lengua extranjera I','LI020113','014139','INA SABORSKA DEICKE','ina.saborska@lasallistas.org.mx','MG 32030502',571); [ID=7588] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','038','69','Lengua extranjera I','LI020113','017535','JUDITH OLIMPIA GARC脥A GARC脥A','','MG 69030501',554); [ID=7589] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','07','Marca','ME041117','014509','ISRAEL GUARNEROS PEREZ','i.guarneros@lasallistas.org.mx','MG 07080105',386); [ID=7590] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','036','79','Tecnolog铆as de redes convergentes','CE030713','016311','NABOR REN脡 SOTO V脥QUEZ','naborsoto@lasallistas.org.mx','MG 79090211',841); [ID=7591] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','033','85','Lengua extranjera I','LI020121','014280','TATIANA TABARES DOM脥NGUEZ','tatiana-tabares@lasallistas.org.mx','MG 85030501',401); [ID=7592] ##SELECT * FROM fi_horario(5, '15:45:00','17:15:00','038','77','Tecnolog铆a de productos c谩rnicos','NA032415','012137','GABRIELA ALATORRE GARC脥A','ga@lasallistas.org.mx','MG 77070106',1306); [ID=7593] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','038','65','Programaci贸n','IC032115','017536','EDGAR TISTA GARCIA','edgar.tista@lasallistas.org.mx','MG 65050106',387); [ID=7594] ##SELECT * FROM fi_horario(5, '17:15:00','18:45:00','038','77','Tecnolog铆a de l谩cteos','NA032315','016354','CLAUDIA ARIADNA ACERO ORTEGA','claudia.acero@lasallistas.org.mx','MG 77070105',1306); [ID=7595] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','033','07','Marca','ME041117','014509','ISRAEL GUARNEROS PEREZ','i.guarneros@lasallistas.org.mx','MG 07080105',184); [ID=7596] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','034','32','Derecho internacional p煤blico','DE080215','010229','RAM脫N LOZA GONZ脕LEZ','ramonloza@lasallistas.org.mx','MG 32050203',166); [ID=7597] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','034','32','Teor铆a del derecho','DE010915','017497','MAR脥A SOLANGE MAQUEO RAM脥REZ','solange.maqueo@lasalle.mx','MG 32010107',1015); [ID=7598] ##SELECT * FROM fi_horario(5, '19:00:00','22:00:00','032','27','Taller de infograf铆a','DG021315','014800','CLAUDIA DE VALLE ROMERO','c.dvr@lasallistas.org.mx','MG 27070307',346); [ID=7599] ##SELECT * FROM fi_horario(5, '19:00:00','22:00:00','032','27','Taller de infograf铆a','DG021315','014912','JOSE ANTONIO CORTES MU脩OZ','antonio.cortes@lasallistas.org.mx','MG 27070403',346); [ID=7600] ##SELECT * FROM fi_horario(5, '19:00:00','22:00:00','032','27','Taller de infograf铆a','DG021315','016178','F脡LIX FRANCO RENTER脥A','felixfranco@lasallistas.org.mx','MG 27070208',346); [ID=7601] ##SELECT * FROM fi_horario(5, '19:00:00','22:00:00','032','27','Taller de infograf铆a','DG021315','016157','IGNACIO RODRIGUEZ SANCHEZ','ignaciorodriguez@lasallistas.org.mx','MG 27070108',346); [ID=7602] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','033','07','Mercadotecnia social y de servicios','ME030217','017542','DAVID REN脡 WILSON OROPEZA','david.wilson@lasallistas.org.mx','MG 07050105',260); [ID=7603] ##SELECT * FROM fi_horario(5, '19:00:00','20:30:00','038','77','Funcionalidad de aditivos alimenticios','NA010615','012871','CARLOS BARR脫N ARTEAGA','carlos.barron@lasallistas.org.mx','MG 77070102',1309); [ID=7604] ##SELECT * FROM fi_horario(5, '20:30:00','22:00:00','033','07','Mercadotecnia social y de servicios','ME030217','017542','DAVID REN脡 WILSON OROPEZA','david.wilson@lasallistas.org.mx','MG 07050205',264); [ID=7605] ##SELECT * FROM fi_horario(5, '07:00:00','08:30:00','037','70','Psicolog铆a m茅dica','PS060217','003896','ANDR脡S GUEVARA BRIZ','andres.guevara@lasallistas.org.mx','MG 70010107',319); [ID=7606] ##SELECT * FROM fi_horario(5, '08:45:00','10:15:00','026','05','Taller de enfermer铆a gerontol贸gica','MD071815','016492','ANASTASIA LEONARDA TOVAR PALOMARES','al.tovar@lasallistas.org.mx','MG 05050105',1244); [ID=7607] ##SELECT * FROM fi_horario(5, '10:30:00','12:00:00','026','05','Taller de enfermer铆a gerontol贸gica','MD071815','016492','ANASTASIA LEONARDA TOVAR PALOMARES','al.tovar@lasallistas.org.mx','MG 05050105',1244); [ID=7608] ##SELECT * FROM fi_horario(5, '11:00:00','13:00:00','037','70','Anatom铆a','BI030117','014153','ANTONIO SOTO PAULINO','antonio.soto@lasallistas.org.mx','MG 70010202',474); [ID=7609] ##SELECT * FROM fi_horario(5, '14:00:00','16:00:00','037','70','Anatom铆a','BI030117','014153','ANTONIO SOTO PAULINO','antonio.soto@lasallistas.org.mx','MG 70010102',324); [ID=7610] ##SELECT * FROM fi_horario(5, '16:00:00','18:00:00','037','70','Sexualidad humana','MD041217','017258','OSCAR JES脷S CU脡LLAR GONZ脕LEZ','oscar.cuellar@lasallistas.org.mx','MG 70080608',326); [ID=7611] ##SELECT * FROM fi_horario(5, '16:00:00','18:00:00','037','70','Oncolog铆a','MD031017','009308','FRANCISCO MARIO GARC脥A RODR脥GUEZ','','MG 70050108',323); [ID=7612] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Sexualidad humana','MD041217','017258','OSCAR JES脷S CU脡LLAR GONZ脕LEZ','oscar.cuellar@lasallistas.org.mx','MG 70080509',326); [ID=7613] ##SELECT * FROM fi_horario(5, '18:00:00','20:00:00','037','70','Oncolog铆a','MD031017','009308','FRANCISCO MARIO GARC脥A RODR脥GUEZ','','MG 70050408',323); [ID=7614] ## diff --git a/rest/materias.php b/rest/materias.php index efadae0..8981909 100644 --- a/rest/materias.php +++ b/rest/materias.php @@ -1,252 +1,252 @@ - -where("id_periodo_sgu", 0, ">") - ->where("periodo_fecha_inicio", $fecha, "<=") - ->where("periodo_fecha_fin", $fecha, ">=") - ->orderBy("periodo_id") - ->get("periodo"); -?> - -
    -

    - horarios encontrados para - -

    - - - - - - - - - where("materia_nombre", trim($horario["NombreMateria"]), "ILIKE") - ->join("carrera", "carrera.carrera_id = materia.carrera_id") - ->join("facultad", "facultad.facultad_id = carrera.facultad_id") - ->get("materia"); - if ( - count(array_filter($materias, fn($m) => - $m["clave_materia"] == trim($horario["ClaveMateria"]) and - $m["clave_carrera"] == trim($horario["ClaveCarrera"]))) > 0 - ) { - continue; - } - - // si de las materias alguna tiene carrera_id entre 1 y 4 entonces es de 谩rea com煤n - $area_comun = count(array_filter($materias, fn($m) => $m["carrera_id"] >= 1 and $m["carrera_id"] <= 4)) > 0; - $vac铆o = count($materias) == 0; - ?> - - "> - - - - - -
    Materia en SGUMateria en Postgres
    -
    - Horario -
    -
    - -
    - -

    No se encontraron materias

    - -
    - Materias -
    -
    - - - - - - - - - - - - - - - - - - - - -
    MateriaCarreraFacultadAcciones
    - "> - - - - ( - ) - - - - - ( - ) - - - - - ( - ) - - -
    - -
    - + +where("id_periodo_sgu", 0, ">") + ->where("periodo_fecha_inicio", $fecha, "<=") + ->where("periodo_fecha_fin", $fecha, ">=") + ->orderBy("periodo_id") + ->get("periodo"); +?> + +
    +

    + horarios encontrados para + +

    + + + + + + + + + where("materia_nombre", trim($horario["NombreMateria"]), "ILIKE") + ->join("carrera", "carrera.carrera_id = materia.carrera_id") + ->join("facultad", "facultad.facultad_id = carrera.facultad_id") + ->get("materia"); + if ( + count(array_filter($materias, fn($m) => + $m["clave_materia"] == trim($horario["ClaveMateria"]) and + $m["clave_carrera"] == trim($horario["ClaveCarrera"]))) > 0 + ) { + continue; + } + + // si de las materias alguna tiene carrera_id entre 1 y 4 entonces es de 谩rea com煤n + $area_comun = count(array_filter($materias, fn($m) => $m["carrera_id"] >= 1 and $m["carrera_id"] <= 4)) > 0; + $vac铆o = count($materias) == 0; + ?> + + "> + + + + + +
    Materia en SGUMateria en Postgres
    +
    + Horario +
    +
    + +
    + +

    No se encontraron materias

    + +
    + Materias +
    +
    + + + + + + + + + + + + + + + + + + + + +
    MateriaCarreraFacultadAcciones
    + "> + + + + ( + ) + + + + + ( + ) + + + + + ( + ) + + +
    + +
    +
    \ No newline at end of file diff --git a/rest/salon.php b/rest/salon.php index ae94532..6168fa9 100644 --- a/rest/salon.php +++ b/rest/salon.php @@ -1,149 +1,149 @@ - - - 'https://portal.ulsa.edu.mx/servicios/AuditoriaAsistencialRest/AuditoriaAsistencialService.svc/auditoriaAsistencial/catalogos/espacios/seleccionar', - CURLOPT_RETURNTRANSFER => true, - CURLOPT_POSTFIELDS => json_encode([]), - CURLOPT_HTTPHEADER => [ - "token: $token", - 'username: SGU_APSA_AUD_ASIST', - 'Content-Type: application/json', - ], -]); - -$response = curl_exec($curl); -$err = curl_error($curl); - -curl_close($curl); -$json_flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT; -$salones = json_decode($response, true, 512, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); -?> -
    -

    - salones encontrados -

    - - - - - - - - - where("id_espacio_sgu", $salon["IdEspacio"])->get("salon"); - // si de el salon es igual NombreEspacio == salon - $vac铆o = empty($salon_db); - $igual = $salon["NombreEspacio"] == ($salon["salon"] ?? ""); - - if ($vac铆o) { - $db->insert("salon", [ - "id_espacio_sgu" => $salon["IdEspacio"], - "salon" => $salon["NombreEspacio"], - "id_espacio_padre" => $salon["IdEspacioPadre"] > 0 ? $salon["IdEspacioPadre"] : null, - ]); - } else if (!$igual) { - $db->where("id_espacio_sgu", $salon["IdEspacio"])->update("salon", [ - "salon" => $salon["NombreEspacio"], - // "id_espacio_padre" => $salon["IdEspacioPadre"] > 0 ? $salon["IdEspacioPadre"] : null, - ]); - - } - - ?> - "> - - - - - -
    Salones en SGUSALONES en Postgres
    - - - -
    - + + + 'https://portal.ulsa.edu.mx/servicios/AuditoriaAsistencialRest/AuditoriaAsistencialService.svc/auditoriaAsistencial/catalogos/espacios/seleccionar', + CURLOPT_RETURNTRANSFER => true, + CURLOPT_POSTFIELDS => json_encode([]), + CURLOPT_HTTPHEADER => [ + "token: $token", + 'username: SGU_APSA_AUD_ASIST', + 'Content-Type: application/json', + ], +]); + +$response = curl_exec($curl); +$err = curl_error($curl); + +curl_close($curl); +$json_flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT; +$salones = json_decode($response, true, 512, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); +?> +
    +

    + salones encontrados +

    + + + + + + + + + where("id_espacio_sgu", $salon["IdEspacio"])->get("salon"); + // si de el salon es igual NombreEspacio == salon + $vac铆o = empty($salon_db); + $igual = $salon["NombreEspacio"] == ($salon["salon"] ?? ""); + + if ($vac铆o) { + $db->insert("salon", [ + "id_espacio_sgu" => $salon["IdEspacio"], + "salon" => $salon["NombreEspacio"], + "id_espacio_padre" => $salon["IdEspacioPadre"] > 0 ? $salon["IdEspacioPadre"] : null, + ]); + } else if (!$igual) { + $db->where("id_espacio_sgu", $salon["IdEspacio"])->update("salon", [ + "salon" => $salon["NombreEspacio"], + // "id_espacio_padre" => $salon["IdEspacioPadre"] > 0 ? $salon["IdEspacioPadre"] : null, + ]); + + } + + ?> + "> + + + + + +
    Salones en SGUSALONES en Postgres
    + + + +
    +
    \ No newline at end of file diff --git a/script/jquery-3.6.0.min.js b/script/jquery-3.6.0.min.js index c4c6022..49310b5 100644 --- a/script/jquery-3.6.0.min.js +++ b/script/jquery-3.6.0.min.js @@ -1,2 +1,2 @@ -/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ -!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 + + \ No newline at end of file diff --git a/solicitud_crear.php b/solicitud_crear.php index aa1a309..2215960 100644 --- a/solicitud_crear.php +++ b/solicitud_crear.php @@ -1,972 +1,972 @@ -access(); - -if ($user->acceso === null && !$user->admin){ - die(header('Location: index.php')); - exit(); -} - -//if (!$user->admin && in_array($user->acceso, ['n'])) - //die(header('Location: main.php?error=1')); -//$user->print_to_log('Reposiciones'); - -//$write = $user->admin || in_array($user->acceso, ['w']); -$write = true; // - -$en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo_id])['esta_en_periodo']; - - -if($user->jefe_carrera){ - //$prof_rs = $db->query('SELECT DISTINCT * FROM fs_profesores(null, null, :fac) ORDER BY PROFESOR_NOMBRE', [':fac' => $user->facultad["facultad_id"]]); - $prof_rs = $db->query('SELECT DISTINCT PROFESOR.* FROM PUESTO_USUARIO - JOIN PUESTO_MATERIA USING (PUESTO_ID) - JOIN HORARIO_VIEW USING (MATERIA_ID) - JOIN HORARIO_PROFESOR USING (HORARIO_ID) - JOIN PROFESOR USING (PROFESOR_ID) - WHERE USUARIO_ID = :usr', [':usr' => $user->user["id"]]); -}else{ - $prof_rs = $db->query('SELECT DISTINCT PROFESOR.* FROM PROFESOR - JOIN horario_profesor USING (profesor_id) - JOIN HORARIO_VIEW USING (horario_id) - WHERE FACULTAD_ID = :fac ORDER BY profesor.profesor_nombre', [':fac' => $user->facultad["facultad_id"]]); -} - -//Duraciones -$duracion_rs = $db->query("select * from duracion order by duracion_interval"); -$tiposol_rs = $db->query("select * from solicitudtipo order by solicitudtipo_id"); - -if(!is_null($user->periodo_id)){ - //Obtiene datos de periodo - $periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]); - $periodo_fin = $periodo_rs["periodo_fecha_fin"]; - if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) ) - $fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); - else{ - $dia_actual = intval(date("w")); - $dias = 2;//d铆as m铆nimos Lun a Jue - if($dia_actual ==5 || $dia_actual ==4 )//Vie - $dias=4; - else if( $dia_actual ==6 )//Sab - $dias=3; - else if( $dia_actual ==0 )//Do - $dias=2; - - $fecha_man = date("d/m/Y", strtotime("+".$dias." day")); - } - /* - // Materias - $id_prof = $user->profesor; - //$facultad_id = 28; - $materias_rs = $db->query('SELECT * FROM fs_materiasprofesor(:id)', [':id' => $id_prof]); - */ - if(isset($_POST["fecha_inicial"])) - $fecha_ini = $_POST["fecha_inicial"]; - else - $fecha_ini = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); - - if(isset($_POST["fecha_final"])) - $fecha_fin = $_POST["fecha_final"]; - else - $fecha_fin = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"])); - - $date = DateTime::createFromFormat('d/m/Y', $fecha_ini); - $fecha_ini_db = $date->format('Y-m-d'); - - $date = DateTime::createFromFormat('d/m/Y', $fecha_fin); - $fecha_fin_db = $date->format('Y-m-d'); -} - -?> - - - - - - - Solicitudes crear | - <?= $user->facultad['facultad'] ?? "Administrador"; ?> - - - - - - - - - - - - - - - - -
    - 0) {?> - -
    -
    -
    - - - -
    -
    -
    - -
    - - periodo_id)) { ?> -
    -
    - - -
    - -
    - -
    No es una fecha v谩lida.
    -
    -
    -
    - -
    - -
    El rango de fechas no es v谩lido.
    -
    -
    -
    -
    - - -
    -
    - - query('SELECT * FROM fs_solicitud(NULL, NULL, NULL, :f_ini, :f_fin, NULL, :usr, null)', [':f_ini' => $fecha_ini_db, ':f_fin' => $fecha_fin_db, ':usr' => $user->user["id"]]); - } - ?> - -
    - 0){ ?> -

    Solicitudes creadas

    -
    - - - - - - - - - - - - - - - - " id="id"> - - - - - - - - - - - - - - -
    EstadoTipoMateriaFecha originalFecha nuevaDuraci贸nSal贸nAcciones
    " title=""> - -
    d-flex mx-auto"> -
    -
    -
    - -
    - -
    - -
    - -
    - -
    - - - -
    - -
    ".substr($reposicion["horario_hora"],0,-3)." a ".substr($reposicion["horario_hora_fin"],0,-3)." hrs.";; - ?> - ".substr($reposicion["hora_nueva"],0,-3)." a ".substr($reposicion["hora_nueva_fin"],0,-3)." hrs."; - ?> - - - - jefe_carrera) || ($reposicion["estado_reposicion_id"] == 2 && !$user->jefe_carrera)){?> - " title="Editar" data-toggle="modal" data-target="#modal"> - - -
    -
    - periodo_id)){ ?> -
    -

    Selecciona un periodo

    -
    - -
    -

    No tienes solicitudes disponibles que cumplan con los filtros

    -
    - -
    - - - - - - - -
    - - - - - - - - +access(); + +if ($user->acceso === null && !$user->admin){ + die(header('Location: index.php')); + exit(); +} + +//if (!$user->admin && in_array($user->acceso, ['n'])) + //die(header('Location: main.php?error=1')); +//$user->print_to_log('Reposiciones'); + +//$write = $user->admin || in_array($user->acceso, ['w']); +$write = true; // + +$en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo_id])['esta_en_periodo']; + + +if($user->jefe_carrera){ + //$prof_rs = $db->query('SELECT DISTINCT * FROM fs_profesores(null, null, :fac) ORDER BY PROFESOR_NOMBRE', [':fac' => $user->facultad["facultad_id"]]); + $prof_rs = $db->query('SELECT DISTINCT PROFESOR.* FROM PUESTO_USUARIO + JOIN PUESTO_MATERIA USING (PUESTO_ID) + JOIN HORARIO_VIEW USING (MATERIA_ID) + JOIN HORARIO_PROFESOR USING (HORARIO_ID) + JOIN PROFESOR USING (PROFESOR_ID) + WHERE USUARIO_ID = :usr', [':usr' => $user->user["id"]]); +}else{ + $prof_rs = $db->query('SELECT DISTINCT PROFESOR.* FROM PROFESOR + JOIN horario_profesor USING (profesor_id) + JOIN HORARIO_VIEW USING (horario_id) + WHERE FACULTAD_ID = :fac ORDER BY profesor.profesor_nombre', [':fac' => $user->facultad["facultad_id"]]); +} + +//Duraciones +$duracion_rs = $db->query("select * from duracion order by duracion_interval"); +$tiposol_rs = $db->query("select * from solicitudtipo order by solicitudtipo_id"); + +if(!is_null($user->periodo_id)){ + //Obtiene datos de periodo + $periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]); + $periodo_fin = $periodo_rs["periodo_fecha_fin"]; + if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) ) + $fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); + else{ + $dia_actual = intval(date("w")); + $dias = 2;//d铆as m铆nimos Lun a Jue + if($dia_actual ==5 || $dia_actual ==4 )//Vie + $dias=4; + else if( $dia_actual ==6 )//Sab + $dias=3; + else if( $dia_actual ==0 )//Do + $dias=2; + + $fecha_man = date("d/m/Y", strtotime("+".$dias." day")); + } + /* + // Materias + $id_prof = $user->profesor; + //$facultad_id = 28; + $materias_rs = $db->query('SELECT * FROM fs_materiasprofesor(:id)', [':id' => $id_prof]); + */ + if(isset($_POST["fecha_inicial"])) + $fecha_ini = $_POST["fecha_inicial"]; + else + $fecha_ini = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); + + if(isset($_POST["fecha_final"])) + $fecha_fin = $_POST["fecha_final"]; + else + $fecha_fin = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"])); + + $date = DateTime::createFromFormat('d/m/Y', $fecha_ini); + $fecha_ini_db = $date->format('Y-m-d'); + + $date = DateTime::createFromFormat('d/m/Y', $fecha_fin); + $fecha_fin_db = $date->format('Y-m-d'); +} + +?> + + + + + + + Solicitudes crear | + <?= $user->facultad['facultad'] ?? "Administrador"; ?> + + + + + + + + + + + + + + + + +
    + 0) {?> + +
    +
    +
    + + + +
    +
    +
    + +
    + + periodo_id)) { ?> +
    +
    + + +
    + +
    + +
    No es una fecha v谩lida.
    +
    +
    +
    + +
    + +
    El rango de fechas no es v谩lido.
    +
    +
    +
    +
    + + +
    +
    + + query('SELECT * FROM fs_solicitud(NULL, NULL, NULL, :f_ini, :f_fin, NULL, :usr, null)', [':f_ini' => $fecha_ini_db, ':f_fin' => $fecha_fin_db, ':usr' => $user->user["id"]]); + } + ?> + +
    + 0){ ?> +

    Solicitudes creadas

    +
    + + + + + + + + + + + + + + + + " id="id"> + + + + + + + + + + + + + + +
    EstadoTipoMateriaFecha originalFecha nuevaDuraci贸nSal贸nAcciones
    " title=""> + +
    d-flex mx-auto"> +
    +
    +
    + +
    + +
    + +
    + +
    + +
    + + + +
    + +
    ".substr($reposicion["horario_hora"],0,-3)." a ".substr($reposicion["horario_hora_fin"],0,-3)." hrs.";; + ?> + ".substr($reposicion["hora_nueva"],0,-3)." a ".substr($reposicion["hora_nueva_fin"],0,-3)." hrs."; + ?> + + + + jefe_carrera) || ($reposicion["estado_reposicion_id"] == 2 && !$user->jefe_carrera)){?> + " title="Editar" data-toggle="modal" data-target="#modal"> + + +
    +
    + periodo_id)){ ?> +
    +

    Selecciona un periodo

    +
    + +
    +

    No tienes solicitudes disponibles que cumplan con los filtros

    +
    + +
    + + + + + + + +
    + + + + + + + + \ No newline at end of file diff --git a/solicitudes_autorizar.php b/solicitudes_autorizar.php index dceddeb..18ebe1f 100644 --- a/solicitudes_autorizar.php +++ b/solicitudes_autorizar.php @@ -1,1068 +1,1068 @@ -access(); -//echo $user; -/*print_r($user); -print_r($user->user["id"]); -echo "****|"; -print_r($user->acceso);//null sin permisos, w o r -echo "|****|"; -print_r($user->profesor); -echo "|****|"; -print_r($user->facultad["facultad_id"]); -exit();*/ -//profesor, admin, rol, facultad -if ($user->acceso === null && !$user->admin){ - die(header('Location: index.php')); - exit(); -} - -$supervisor = false; -$coordinador = false; -if($user->rol["rol_id"]==7 || $user->rol["rol_id"]==8){ - $supervisor = true; -} -if($user->rol["rol_id"]==9 || $user->rol["rol_id"]==8){ - $coordinador = true; -} - -//$user->print_to_log('Reposiciones'); -//$write = $user->admin || in_array($user->acceso, ['w']); -$write = true; // - -function duracionMinutos($fechahora_i, $fechahora_f){ - return round((strtotime($fechahora_f) - strtotime($fechahora_i)) / 60,2); -} -//if($user->periodo_id!= ""){ - //$en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo_id])['esta_en_periodo']; - - $profesores_rs = array(); - $tab_inicial = 1; - /*if(!$supervisor){ - $fac_id = $user->facultad["facultad_id"]; - $carrera_rs = $db->query('SELECT * FROM fs_profesor_facultad(:fac, :periodo)', [':fac'=>$fac_id, ':periodo' => $user->periodo_id]); - }else{ - $carrera_rs = $db->query('SELECT * FROM fs_profesor_facultad(NULL, :periodo)', [ ':periodo' => $user->periodo_id]); - }*/ - - $salones_rs = $db->query('SELECT * from salon_view where es_salon is true'); - - //Periodo - /*$periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]); - $periodo_fin = $periodo_rs["periodo_fecha_fin"]; - if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) ) - $fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); - else{ - $dias = 3; - if( intval(date("w")) >=3 && intval(date("w"))<=5 )//Mie a Vie - $dias+=3; - else if( intval(date("w")) ==6 )//Sab - $dias+=2; - else if( intval(date("w")) ==0 )//Do - $dias+=1; - - $fecha_man = date("d/m/Y", strtotime("+".$dias." day")); - }*/ - - // Fechas filtro - if(isset($_POST["fecha_inicial"])) - $fecha_ini = $_POST["fecha_inicial"]; - else - $fecha_ini = date("d/m/Y", strtotime("-30 day")); - //$fecha_ini = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); - - if(isset($_POST["fecha_final"])) - $fecha_fin = $_POST["fecha_final"]; - else - $fecha_fin = date("d/m/Y", strtotime("30 day")); - //$fecha_fin = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"])); - - //Reposiciones - $repEdo_rs = $db->query('SELECT * FROM fs_estado_reposicion' ); - - $repoParams = array(); - - $query = ""; - - if($user->rol["rol_id"] == 9){//es coordinador - $query .= ":facultad, "; - $repoParams[":facultad"] = $user->facultad["facultad_id"]; - }else{//supervisor - $query .= "NULL, "; - } - if(isset($_POST["prof"]) ){ - $query .= ":prof,"; - $profesor = trim($_POST["prof"]);//limpia texto - $repoParams[":prof"] = $profesor; - }else{ - $query .= "NULL,"; - } - $query .= ":f_ini, :f_fin, "; - - - - $date = DateTime::createFromFormat('d/m/Y', $fecha_ini); - $fecha_ini_db = $date->format('Y-m-d'); - - $date = DateTime::createFromFormat('d/m/Y', $fecha_fin); - $fecha_fin_db = $date->format('Y-m-d'); - $repoParams[":f_ini"] = $fecha_ini_db; - $repoParams[":f_fin"] = $fecha_fin_db; - $repoParams[":edo"] = 1;//se sobreescribe -//} -?> - - - - - Reposiciones autorizar | <?= $user->facultad['facultad'] ?? 'General' ?> - - - - - - - - - - - - - - - - - - - - - - - " ?> -
    - -
    - - - periodo_id!= ""){ ?> -
    -
    - - -
    - -
    - -
    No es una fecha v谩lida.
    -
    -
    -
    - -
    - -
    El rango de fechas no es v谩lido.
    -
    -
    -
    - -
    - -
    -
    -
    -
    - - -
    - -
    - -
    - - -

    - -

    -
    - - - - -
    - -
    - rol["rol_id"] == 7){//es supervisor - $repoParams[":sup"] = $user->user["id"]; - $solicitudes_rs = $db->query('SELECT * FROM fs_solicitud(NULL, '.$query.':edo, NULL, :sup) ', $repoParams ); - }else{ - $solicitudes_rs = $db->query('SELECT * FROM fs_solicitud(NULL, '.$query.':edo, NULL, NULL) ', $repoParams ); - } - - - if(count($solicitudes_rs)==0){ - echo "

    No hay reposiciones en este estado

    "; - }else{ - ?> - -

    >

    - - - - - - - - - - - - - - - - " data-edo="" id="id"> - - - - - - - - - - - - - -
    EstadoTipoProfesor/MateriaFecha faltaFecha reposici贸nSal贸nAcciones
    - -
    d-flex mx-auto"> -
    -
    -
    - -
    - -
    - -
    - -
    - -
    - - -
    - - - - -
    ".substr($reposicion["horario_hora"],0, 5); - }else{ - echo " - "; - } - ?> - ".substr($reposicion["hora_nueva"],0, 5)." a ".substr($reposicion["hora_nueva_fin"],0, 5); - ?> - - - - jefe_carrera || $user->admin || !$coordinador) && $reposicion["estado_reposicion_id"] == 1){?> - " title="Aprobar"> - admin) && $reposicion["estado_reposicion_id"] == 2){?> - " title="Autorizar" > - - " title="Ver detalle"> - - - " title="Ver detalle"> - - - jefe_carrera || $user->admin || $coordinador) && $reposicion["estado_reposicion_id"] == 1)/* nueva */ - || (($user->admin || $coordinador || $supervisor) && $reposicion["estado_reposicion_id"] == 2)/* aprobado facultad */ - ){ - ?> - - -
    - -
    - -
    - - - - - - - -
    - - - - - +access(); +//echo $user; +/*print_r($user); +print_r($user->user["id"]); +echo "****|"; +print_r($user->acceso);//null sin permisos, w o r +echo "|****|"; +print_r($user->profesor); +echo "|****|"; +print_r($user->facultad["facultad_id"]); +exit();*/ +//profesor, admin, rol, facultad +if ($user->acceso === null && !$user->admin){ + die(header('Location: index.php')); + exit(); +} + +$supervisor = false; +$coordinador = false; +if($user->rol["rol_id"]==7 || $user->rol["rol_id"]==8){ + $supervisor = true; +} +if($user->rol["rol_id"]==9 || $user->rol["rol_id"]==8){ + $coordinador = true; +} + +//$user->print_to_log('Reposiciones'); +//$write = $user->admin || in_array($user->acceso, ['w']); +$write = true; // + +function duracionMinutos($fechahora_i, $fechahora_f){ + return round((strtotime($fechahora_f) - strtotime($fechahora_i)) / 60,2); +} +//if($user->periodo_id!= ""){ + //$en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo_id])['esta_en_periodo']; + + $profesores_rs = array(); + $tab_inicial = 1; + /*if(!$supervisor){ + $fac_id = $user->facultad["facultad_id"]; + $carrera_rs = $db->query('SELECT * FROM fs_profesor_facultad(:fac, :periodo)', [':fac'=>$fac_id, ':periodo' => $user->periodo_id]); + }else{ + $carrera_rs = $db->query('SELECT * FROM fs_profesor_facultad(NULL, :periodo)', [ ':periodo' => $user->periodo_id]); + }*/ + + $salones_rs = $db->query('SELECT * from salon_view where es_salon is true'); + + //Periodo + /*$periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]); + $periodo_fin = $periodo_rs["periodo_fecha_fin"]; + if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) ) + $fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); + else{ + $dias = 3; + if( intval(date("w")) >=3 && intval(date("w"))<=5 )//Mie a Vie + $dias+=3; + else if( intval(date("w")) ==6 )//Sab + $dias+=2; + else if( intval(date("w")) ==0 )//Do + $dias+=1; + + $fecha_man = date("d/m/Y", strtotime("+".$dias." day")); + }*/ + + // Fechas filtro + if(isset($_POST["fecha_inicial"])) + $fecha_ini = $_POST["fecha_inicial"]; + else + $fecha_ini = date("d/m/Y", strtotime("-30 day")); + //$fecha_ini = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"])); + + if(isset($_POST["fecha_final"])) + $fecha_fin = $_POST["fecha_final"]; + else + $fecha_fin = date("d/m/Y", strtotime("30 day")); + //$fecha_fin = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"])); + + //Reposiciones + $repEdo_rs = $db->query('SELECT * FROM fs_estado_reposicion' ); + + $repoParams = array(); + + $query = ""; + + if($user->rol["rol_id"] == 9){//es coordinador + $query .= ":facultad, "; + $repoParams[":facultad"] = $user->facultad["facultad_id"]; + }else{//supervisor + $query .= "NULL, "; + } + if(isset($_POST["prof"]) ){ + $query .= ":prof,"; + $profesor = trim($_POST["prof"]);//limpia texto + $repoParams[":prof"] = $profesor; + }else{ + $query .= "NULL,"; + } + $query .= ":f_ini, :f_fin, "; + + + + $date = DateTime::createFromFormat('d/m/Y', $fecha_ini); + $fecha_ini_db = $date->format('Y-m-d'); + + $date = DateTime::createFromFormat('d/m/Y', $fecha_fin); + $fecha_fin_db = $date->format('Y-m-d'); + $repoParams[":f_ini"] = $fecha_ini_db; + $repoParams[":f_fin"] = $fecha_fin_db; + $repoParams[":edo"] = 1;//se sobreescribe +//} +?> + + + + + Reposiciones autorizar | <?= $user->facultad['facultad'] ?? 'General' ?> + + + + + + + + + + + + + + + + + + + + + + + " ?> +
    + +
    + + + periodo_id!= ""){ ?> +
    +
    + + +
    + +
    + +
    No es una fecha v谩lida.
    +
    +
    +
    + +
    + +
    El rango de fechas no es v谩lido.
    +
    +
    +
    + +
    + +
    +
    +
    +
    + + +
    + +
    + +
    + + +

    + +

    +
    + + + + +
    + +
    + rol["rol_id"] == 7){//es supervisor + $repoParams[":sup"] = $user->user["id"]; + $solicitudes_rs = $db->query('SELECT * FROM fs_solicitud(NULL, '.$query.':edo, NULL, :sup) ', $repoParams ); + }else{ + $solicitudes_rs = $db->query('SELECT * FROM fs_solicitud(NULL, '.$query.':edo, NULL, NULL) ', $repoParams ); + } + + + if(count($solicitudes_rs)==0){ + echo "

    No hay reposiciones en este estado

    "; + }else{ + ?> + +

    >

    + + + + + + + + + + + + + + + + " data-edo="" id="id"> + + + + + + + + + + + + + +
    EstadoTipoProfesor/MateriaFecha faltaFecha reposici贸nSal贸nAcciones
    + +
    d-flex mx-auto"> +
    +
    +
    + +
    + +
    + +
    + +
    + +
    + + +
    + + + + +
    ".substr($reposicion["horario_hora"],0, 5); + }else{ + echo " - "; + } + ?> + ".substr($reposicion["hora_nueva"],0, 5)." a ".substr($reposicion["hora_nueva_fin"],0, 5); + ?> + + + + jefe_carrera || $user->admin || !$coordinador) && $reposicion["estado_reposicion_id"] == 1){?> + " title="Aprobar"> + admin) && $reposicion["estado_reposicion_id"] == 2){?> + " title="Autorizar" > + + " title="Ver detalle"> + + + " title="Ver detalle"> + + + jefe_carrera || $user->admin || $coordinador) && $reposicion["estado_reposicion_id"] == 1)/* nueva */ + || (($user->admin || $coordinador || $supervisor) && $reposicion["estado_reposicion_id"] == 2)/* aprobado facultad */ + ){ + ?> + + +
    + +
    + +
    + + + + + + + +
    + + + + + \ No newline at end of file diff --git a/ts/avisos.ts b/ts/avisos.ts index a4fb012..55183b9 100644 --- a/ts/avisos.ts +++ b/ts/avisos.ts @@ -1,207 +1,207 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' - -type Profesor = { - profesor_clave: string; - profesor_correo: null | string; - profesor_grado: null | string; - profesor_id: number; - profesor_nombre: string; -} - -type Carrera = { - carrera_activa: boolean; - carrera_comun: boolean; - carrera_id: number; - carrera_nombre: string; - clave_carrera: string; - facultad_id: number | null; - nivel_id: number; -} - -type Periodo = { - created_at: Date; - estado_id: number; - fecha_final: Date; - id_periodo_sgu: number; - nivel_id: number; - periodo_clave: string; - periodo_fecha_fin: Date; - periodo_fecha_inicio: Date; - periodo_id: number; - periodo_nombre: string; -} - -type Aviso = { - aviso_estado: boolean; - aviso_titulo: string; - aviso_fecha_final: Date; - aviso_fecha_inicial: Date; - aviso_id: number; - aviso_texto: string; - carreras: Carrera[]; - facultad_id: null; - profesores: Profesor[]; -} - -const new_aviso = reactive({ - titulo: '', - descripcion: '', - fechaInicio: '', - fechaFin: '', - profesores: [] as Array, - carreras: [] as Array, - reset() { - this.titulo = '' - this.descripcion = '' - this.fechaInicio = '' - this.fechaFin = '' - this.profesores = [] - this.carreras = [] - }, - get isValid() { - return this.titulo !== '' && this.descripcion !== '' && this.fechaInicio !== '' && this.fechaFin !== '' && (this.profesores.length > 0 || this.carreras.length > 0) && this.facultad_id !== null - }, -}) -// define datepicker method - -const app = createApp({ - new_aviso, - profesores: [] as Array, - carreras: [] as Array, - avisos: [] as Array, - - profesor: null as String | null, - formatProfesor(profesor: Profesor) { - return `(${profesor.profesor_clave}) ${profesor.profesor_nombre}` - }, - addProfesor() { - const profesorObj = this.profesores.find((profesor: Profesor) => this.profesor === this.formatProfesor(profesor)) - if (profesorObj) { - this.new_aviso.profesores.push(profesorObj) - this.profesor = null - } - }, - - aviso_shown: null as Aviso | null, - // int? - aviso_suspendido: null as number | null, - suspenderAviso() { - if (this.aviso_suspendido) { - const aviso = this.avisos.find((aviso: Aviso) => aviso.aviso_id === this.aviso_suspendido) - if (aviso) { - this.deleteAviso(aviso) - } - } - }, - - get relevant_profesores() { - // not in array new_aviso.profesores - const relevant = this.profesores.filter((profesor: Profesor) => !this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_id).includes(profesor.profesor_id)) - // console.log('profesores:', this.profesores.map((profesor: Profesor) => profesor.profesor_nombre), 'relevant:', relevant.map((profesor: Profesor) => profesor.profesor_nombre), 'new_aviso:', this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_nombre)) - return relevant - }, - - get relevant_carreras() { - // not in array new_aviso.carreras - return this.carreras.filter((carrera: Carrera) => !this.new_aviso.carreras.includes(carrera)) - }, - - createAviso() { - const data = { - aviso_titulo: this.new_aviso.titulo, - aviso_texto: this.new_aviso.descripcion, - aviso_fecha_inicial: this.new_aviso.fechaInicio, - aviso_fecha_final: this.new_aviso.fechaFin, - profesores: this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_id), - carreras: this.new_aviso.carreras.map((carrera: Carrera) => carrera.carrera_id), - } - fetch('/action/avisos.php', { - method: 'POST', - body: JSON.stringify(data) - }).then(res => res.json()).then(res => { - if (res.success) { - // hydrate with carreras and profesores - this.avisos.push({ - ...data, - carreras: this.carreras.filter((carrera: Carrera) => data.carreras.includes(carrera.carrera_id)), - profesores: this.profesores.filter((profesor: Profesor) => data.profesores.includes(profesor.profesor_id)), - aviso_estado: true, - aviso_id: res.aviso_id, - }) - this.new_aviso.reset() - } - else { - alert(res.error) - console.log(res.errors) - } - }) - }, - - deleteAviso(aviso: Aviso) { - fetch(`/action/avisos.php`, { - method: 'DELETE', - body: JSON.stringify({ aviso_id: aviso.aviso_id }) - }).then(res => res.json()).then(res => { - if (res.success) { - this.avisos = this.avisos.filter((aviso: Aviso) => aviso.aviso_id !== this.aviso_suspendido) - this.aviso_suspendido = null - } - else { - alert(res.error) - console.log(res.errors) - } - }) - }, - - updateAviso() { - fetch(`/action/avisos.php`, { - method: 'PUT', - body: JSON.stringify({ - aviso_id: this.aviso_shown.aviso_id, - aviso_fecha_final: this.aviso_shown.aviso_fecha_final, - }) - }).then(res => res.json()).then(res => { - if (res.success) { - } - else { - alert(res.error) - console.log(res.errors) - } - }) - }, - - async initializeDatepickers($el: HTMLElement) { - const periodo = await fetch('action/periodo_datos.php'); - const periodo_data = await periodo.json() as Periodo; - - $('.date-picker').datepicker({ - dateFormat: 'yy-mm-dd', - maxDate: periodo_data.periodo_fecha_fin, - minDate: 0, - }); - - $($el).on('change', () => { - this.aviso_shown.aviso_fecha_final = $($el).val() as string; - }); - }, - - async mounted() { - this.avisos = await fetch("/action/avisos.php").then(res => res.json()) as Array - this.profesores = await fetch('/action/action_profesor.php').then(res => res.json()) as Array - this.carreras = await fetch('/action/action_carreras.php').then(res => res.json()) as Array - - await this.initializeDatepickers() - - const fechaInicio = $('#fechaInicio.date-picker') - const fechaFin = $('#fechaFin.date-picker') - fechaInicio.on("change", function () { - new_aviso.fechaInicio = fechaInicio.val() as string - fechaFin.datepicker("option", "minDate", fechaInicio.val()); - }); - - fechaFin.on("change", function () { - new_aviso.fechaFin = fechaFin.val() as string - fechaInicio.datepicker("option", "maxDate", fechaFin.val()); - }); - } +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' + +type Profesor = { + profesor_clave: string; + profesor_correo: null | string; + profesor_grado: null | string; + profesor_id: number; + profesor_nombre: string; +} + +type Carrera = { + carrera_activa: boolean; + carrera_comun: boolean; + carrera_id: number; + carrera_nombre: string; + clave_carrera: string; + facultad_id: number | null; + nivel_id: number; +} + +type Periodo = { + created_at: Date; + estado_id: number; + fecha_final: Date; + id_periodo_sgu: number; + nivel_id: number; + periodo_clave: string; + periodo_fecha_fin: Date; + periodo_fecha_inicio: Date; + periodo_id: number; + periodo_nombre: string; +} + +type Aviso = { + aviso_estado: boolean; + aviso_titulo: string; + aviso_fecha_final: Date; + aviso_fecha_inicial: Date; + aviso_id: number; + aviso_texto: string; + carreras: Carrera[]; + facultad_id: null; + profesores: Profesor[]; +} + +const new_aviso = reactive({ + titulo: '', + descripcion: '', + fechaInicio: '', + fechaFin: '', + profesores: [] as Array, + carreras: [] as Array, + reset() { + this.titulo = '' + this.descripcion = '' + this.fechaInicio = '' + this.fechaFin = '' + this.profesores = [] + this.carreras = [] + }, + get isValid() { + return this.titulo !== '' && this.descripcion !== '' && this.fechaInicio !== '' && this.fechaFin !== '' && (this.profesores.length > 0 || this.carreras.length > 0) && this.facultad_id !== null + }, +}) +// define datepicker method + +const app = createApp({ + new_aviso, + profesores: [] as Array, + carreras: [] as Array, + avisos: [] as Array, + + profesor: null as String | null, + formatProfesor(profesor: Profesor) { + return `(${profesor.profesor_clave}) ${profesor.profesor_nombre}` + }, + addProfesor() { + const profesorObj = this.profesores.find((profesor: Profesor) => this.profesor === this.formatProfesor(profesor)) + if (profesorObj) { + this.new_aviso.profesores.push(profesorObj) + this.profesor = null + } + }, + + aviso_shown: null as Aviso | null, + // int? + aviso_suspendido: null as number | null, + suspenderAviso() { + if (this.aviso_suspendido) { + const aviso = this.avisos.find((aviso: Aviso) => aviso.aviso_id === this.aviso_suspendido) + if (aviso) { + this.deleteAviso(aviso) + } + } + }, + + get relevant_profesores() { + // not in array new_aviso.profesores + const relevant = this.profesores.filter((profesor: Profesor) => !this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_id).includes(profesor.profesor_id)) + // console.log('profesores:', this.profesores.map((profesor: Profesor) => profesor.profesor_nombre), 'relevant:', relevant.map((profesor: Profesor) => profesor.profesor_nombre), 'new_aviso:', this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_nombre)) + return relevant + }, + + get relevant_carreras() { + // not in array new_aviso.carreras + return this.carreras.filter((carrera: Carrera) => !this.new_aviso.carreras.includes(carrera)) + }, + + createAviso() { + const data = { + aviso_titulo: this.new_aviso.titulo, + aviso_texto: this.new_aviso.descripcion, + aviso_fecha_inicial: this.new_aviso.fechaInicio, + aviso_fecha_final: this.new_aviso.fechaFin, + profesores: this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_id), + carreras: this.new_aviso.carreras.map((carrera: Carrera) => carrera.carrera_id), + } + fetch('/action/avisos.php', { + method: 'POST', + body: JSON.stringify(data) + }).then(res => res.json()).then(res => { + if (res.success) { + // hydrate with carreras and profesores + this.avisos.push({ + ...data, + carreras: this.carreras.filter((carrera: Carrera) => data.carreras.includes(carrera.carrera_id)), + profesores: this.profesores.filter((profesor: Profesor) => data.profesores.includes(profesor.profesor_id)), + aviso_estado: true, + aviso_id: res.aviso_id, + }) + this.new_aviso.reset() + } + else { + alert(res.error) + console.log(res.errors) + } + }) + }, + + deleteAviso(aviso: Aviso) { + fetch(`/action/avisos.php`, { + method: 'DELETE', + body: JSON.stringify({ aviso_id: aviso.aviso_id }) + }).then(res => res.json()).then(res => { + if (res.success) { + this.avisos = this.avisos.filter((aviso: Aviso) => aviso.aviso_id !== this.aviso_suspendido) + this.aviso_suspendido = null + } + else { + alert(res.error) + console.log(res.errors) + } + }) + }, + + updateAviso() { + fetch(`/action/avisos.php`, { + method: 'PUT', + body: JSON.stringify({ + aviso_id: this.aviso_shown.aviso_id, + aviso_fecha_final: this.aviso_shown.aviso_fecha_final, + }) + }).then(res => res.json()).then(res => { + if (res.success) { + } + else { + alert(res.error) + console.log(res.errors) + } + }) + }, + + async initializeDatepickers($el: HTMLElement) { + const periodo = await fetch('action/periodo_datos.php'); + const periodo_data = await periodo.json() as Periodo; + + $('.date-picker').datepicker({ + dateFormat: 'yy-mm-dd', + maxDate: periodo_data.periodo_fecha_fin, + minDate: 0, + }); + + $($el).on('change', () => { + this.aviso_shown.aviso_fecha_final = $($el).val() as string; + }); + }, + + async mounted() { + this.avisos = await fetch("/action/avisos.php").then(res => res.json()) as Array + this.profesores = await fetch('/action/action_profesor.php').then(res => res.json()) as Array + this.carreras = await fetch('/action/action_carreras.php').then(res => res.json()) as Array + + await this.initializeDatepickers() + + const fechaInicio = $('#fechaInicio.date-picker') + const fechaFin = $('#fechaFin.date-picker') + fechaInicio.on("change", function () { + new_aviso.fechaInicio = fechaInicio.val() as string + fechaFin.datepicker("option", "minDate", fechaInicio.val()); + }); + + fechaFin.on("change", function () { + new_aviso.fechaFin = fechaFin.val() as string + fechaInicio.datepicker("option", "maxDate", fechaFin.val()); + }); + } }).mount('#app') \ No newline at end of file diff --git a/ts/carreras.ts b/ts/carreras.ts index de8fb43..ff5def4 100644 --- a/ts/carreras.ts +++ b/ts/carreras.ts @@ -1,63 +1,63 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' - -type Carrera = { - carrera_id: number; - carrera_nombre: string; - clave_carrera: string; - facultad_id: number; - facultad_nombre: string; - nivel_id: number; - nivel_nombre: string; -} - -type Nivel = { - nivel_id: number; - nivel_nombre: string; -} - -const app = createApp({ - carreras: [] as Carrera[], - niveles: [] as Nivel[], - message: {} as Record, - async setNivel(carrera: Carrera, nivel: Nivel) { - if (carrera.nivel_id === nivel.nivel_id) { - return - } - carrera.nivel_id = nivel.nivel_id - carrera.nivel_nombre = nivel.nivel_nombre - - await fetch('action/carrera.php', { - method: 'PUT', - body: JSON.stringify({ - carrera_id: carrera.carrera_id, - nivel_id: nivel.nivel_id - }) - }) - .then(res => res.json()) - .then(res => { - this.message.title = "Actualizaci贸n" - this.message.text = res.error ?? res.success - this.message.type = res.error ? 'danger' : 'success' - this.message.timestamp = new Date().toLocaleTimeString() - }) - - - }, - async mounted() { - this.carreras = await fetch('action/carrera.php').then(res => res.json()) - this.niveles = await fetch('action/nivel.php').then(res => res.json()) - // group by facultad_id - const carreras = this.carreras.reduce((acc, cur) => { - const { facultad_nombre } = cur - if (!acc[facultad_nombre]) { - acc[facultad_nombre] = [] - } - acc[facultad_nombre].push(cur) - return acc - }, {} as Record) - this.carreras = Object.entries(carreras).map(([facultad_nombre, carreras]) => ({ - facultad_nombre: facultad_nombre, - carreras - })) - } +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' + +type Carrera = { + carrera_id: number; + carrera_nombre: string; + clave_carrera: string; + facultad_id: number; + facultad_nombre: string; + nivel_id: number; + nivel_nombre: string; +} + +type Nivel = { + nivel_id: number; + nivel_nombre: string; +} + +const app = createApp({ + carreras: [] as Carrera[], + niveles: [] as Nivel[], + message: {} as Record, + async setNivel(carrera: Carrera, nivel: Nivel) { + if (carrera.nivel_id === nivel.nivel_id) { + return + } + carrera.nivel_id = nivel.nivel_id + carrera.nivel_nombre = nivel.nivel_nombre + + await fetch('action/carrera.php', { + method: 'PUT', + body: JSON.stringify({ + carrera_id: carrera.carrera_id, + nivel_id: nivel.nivel_id + }) + }) + .then(res => res.json()) + .then(res => { + this.message.title = "Actualizaci贸n" + this.message.text = res.error ?? res.success + this.message.type = res.error ? 'danger' : 'success' + this.message.timestamp = new Date().toLocaleTimeString() + }) + + + }, + async mounted() { + this.carreras = await fetch('action/carrera.php').then(res => res.json()) + this.niveles = await fetch('action/nivel.php').then(res => res.json()) + // group by facultad_id + const carreras = this.carreras.reduce((acc, cur) => { + const { facultad_nombre } = cur + if (!acc[facultad_nombre]) { + acc[facultad_nombre] = [] + } + acc[facultad_nombre].push(cur) + return acc + }, {} as Record) + this.carreras = Object.entries(carreras).map(([facultad_nombre, carreras]) => ({ + facultad_nombre: facultad_nombre, + carreras + })) + } }).mount('#app') \ No newline at end of file diff --git a/ts/declaration.ts b/ts/declaration.ts index d6b8601..426b2bf 100644 --- a/ts/declaration.ts +++ b/ts/declaration.ts @@ -1 +1 @@ -declare module 'https://*' +declare module 'https://*' diff --git a/ts/faltas.ts b/ts/faltas.ts index e655720..85806a1 100644 --- a/ts/faltas.ts +++ b/ts/faltas.ts @@ -1,43 +1,43 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; -// define that $ has type any -declare const $: any; - -const filter = reactive({ - facultad: -1, - profesor: '', - porcentaje: 0 -}); -const app = createApp({ - filter, - facultades: [], - profesores: [], - - faltas: [], - openModal() { - const modal = document.getElementById('cargando'); - $(modal).modal('show'); - }, - closeModal() { - const modal = document.getElementById('cargando'); - $(modal).modal('hide'); - }, - - async refresh() { -<<<<<<< HEAD - alert(`Facultad: ${filter.facultad} - Profesor: ${filter.profesor} - Porcentaje: ${filter.porcentaje}%` - if(filter.facultad == -1 || filter.porcetaje < 10) { -======= - if(filter.facultad == -1 || filter.porcentaje < 10) { ->>>>>>> 7688f1aac1824c234bc5f19b154e9ad1f4808d4f - return; - } - - this.openModal(); - this.faltas = await fetch(`action/profesor_faltas.php?facultad=${this.filter.facultad}&profesor=${this.filter.profesor}&porcentaje=${this.filter.porcentaje}`).then(res => res.json()); - this.closeModal(); - }, - async mounted() { - this.facultades = await fetch('action/action_facultad.php').then(res => res.json()); - this.profesores = await fetch('action/action_profesor.php').then(res => res.json()); - } -}).mount('#app'); +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'; +// define that $ has type any +declare const $: any; + +const filter = reactive({ + facultad: -1, + profesor: '', + porcentaje: 0 +}); +const app = createApp({ + filter, + facultades: [], + profesores: [], + + faltas: [], + openModal() { + const modal = document.getElementById('cargando'); + $(modal).modal('show'); + }, + closeModal() { + const modal = document.getElementById('cargando'); + $(modal).modal('hide'); + }, + + async refresh() { +<<<<<<< HEAD + alert(`Facultad: ${filter.facultad} - Profesor: ${filter.profesor} - Porcentaje: ${filter.porcentaje}%` + if(filter.facultad == -1 || filter.porcetaje < 10) { +======= + if(filter.facultad == -1 || filter.porcentaje < 10) { +>>>>>>> 7688f1aac1824c234bc5f19b154e9ad1f4808d4f + return; + } + + this.openModal(); + this.faltas = await fetch(`action/profesor_faltas.php?facultad=${this.filter.facultad}&profesor=${this.filter.profesor}&porcentaje=${this.filter.porcentaje}`).then(res => res.json()); + this.closeModal(); + }, + async mounted() { + this.facultades = await fetch('action/action_facultad.php').then(res => res.json()); + this.profesores = await fetch('action/action_profesor.php').then(res => res.json()); + } +}).mount('#app'); diff --git a/ts/periodos.ts b/ts/periodos.ts index c975b69..131b73b 100644 --- a/ts/periodos.ts +++ b/ts/periodos.ts @@ -1,145 +1,145 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' - -interface Periodo { - created_at: Date; - estado_id: number; - id_periodo_sgu: number; - nivel: string; - nivel_id: number | ''; - periodo_clave: string; - periodo_fecha_fin: Date; - periodo_fecha_inicio: Date; - periodo_id: number; - periodo_nombre: string; -} - -interface Nivel { - nivel_id: number; - nivel_nombre: string; -} - -const app = createApp({ - periodos: [] as Array, - niveles: [] as Array, - messages: [] as Array<{ title: string, text: string, type: string, timestamp: string }>, - - addMessage(title: string, text: string, type: string) { - this.messages.push({ title, text, type, timestamp: new Date() }); - }, - - async sendRequest(action: string, periodo_id: number, data: any) { - const response = await fetch('action/periodos.php', { - method: 'PUT', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - action: action, - periodo_id: periodo_id, - ...data - }) - }) - return await response.json() - }, - - async changeNivel(periodo: Periodo, nivel_id: number) { - if (periodo.nivel_id === nivel_id) return - - const result = await this.sendRequest('changeNivel', periodo.periodo_id, { nivel_id: nivel_id }) - if (result.success) { - this.addMessage('Nivel cambiado', `El nivel del periodo ${periodo.periodo_nombre} ha sido cambiado a ${this.niveles.find((nivel: Nivel) => nivel.nivel_id === nivel_id)?.nivel_nombre}`, 'success') - periodo.nivel_id = nivel_id - periodo.nivel = this.niveles.find((nivel: Nivel) => nivel.nivel_id === nivel_id)?.nivel_nombre || '' - } else { - this.addMessage('Error al cambiar nivel', `No se pudo cambiar el nivel del periodo ${periodo.periodo_nombre}`, 'danger') - } - }, - - async changeFechaInicio(periodo: Periodo, fecha_inicio: Date) { - const result = await this.sendRequest('changeFechaInicio', periodo.periodo_id, { periodo_fecha_inicio: fecha_inicio }) - if (result.success) { - this.addMessage('Fecha de inicio cambiada', `La fecha de inicio del periodo ${periodo.periodo_nombre} ha sido cambiada a ${fecha_inicio}`, 'success') - - periodo.periodo_fecha_inicio = fecha_inicio - } else { - this.addMessage('Error al cambiar fecha de inicio', `No se pudo cambiar la fecha de inicio del periodo ${periodo.periodo_nombre}`, 'danger') - } - }, - - async changeFechaFin(periodo: Periodo, fecha_fin: Date) { - const result = await this.sendRequest('changeFechaFin', periodo.periodo_id, { periodo_fecha_fin: fecha_fin }) - if (result.success) { - this.addMessage('Fecha de fin cambiada', `La fecha de fin del periodo ${periodo.periodo_nombre} ha sido cambiada a ${fecha_fin}`, 'success') - periodo.periodo_fecha_fin = fecha_fin - } else { - this.addMessage('Error al cambiar fecha de fin', `No se pudo cambiar la fecha de fin del periodo ${periodo.periodo_nombre}`, 'danger') - } - }, - - - async updatePeriodo(periodo: Periodo) { - const result = await this.sendRequest('updatePeriodo', periodo.periodo_id, { - periodo_nombre: periodo.periodo_nombre, - id_periodo_sgu: periodo.id_periodo_sgu, - periodo_clave: periodo.periodo_clave, - }) - if (result.success) { - this.addMessage('Periodo actualizado', `El periodo ${periodo.periodo_nombre} ha sido actualizado`, 'success') - } else { - this.addMessage('Error al actualizar periodo', `No se pudo actualizar el periodo ${periodo.periodo_nombre}`, 'danger') - } - }, - - - async createPeriodo(newPeriodo: Periodo) { - - if (newPeriodo.periodo_nombre === null || newPeriodo.nivel_id === null || newPeriodo.periodo_fecha_inicio === null || newPeriodo.periodo_fecha_fin === null) { - this.addMessage('Error al crear periodo', `No se pudo crear el periodo ${newPeriodo.periodo_nombre}`, 'danger') - return - } - - const result = await fetch('action/periodos.php', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(newPeriodo) - }).then(res => res.json()) - - if (result.success) { - this.addMessage('Periodo creado', `El periodo ${newPeriodo.periodo_nombre} ha sido creado`, 'success') - - this.periodos - Object.keys(newPeriodo).forEach(key => newPeriodo[key] = null); - newPeriodo.nivel_id = ''; - this.periodos = await fetch('action/periodos.php').then(res => res.json()) - } else { - this.addMessage('Error al crear periodo', `No se pudo crear el periodo ${newPeriodo.periodo_nombre}`, 'danger') - } - }, - - async deletePeriodo(periodo: Periodo) { - const response = await fetch('action/periodos.php', { - method: 'DELETE', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - periodo_id: periodo.periodo_id, - }) - }) - const result = await response.json() - - if (result.success) { - this.addMessage('Periodo eliminado', `El periodo ${periodo.periodo_nombre} ha sido eliminado`, 'success') - this.periodos = this.periodos.filter((p: Periodo) => p.periodo_id !== periodo.periodo_id) - } else { - this.addMessage('Error al eliminar periodo', `No se pudo eliminar el periodo ${periodo.periodo_nombre}`, 'danger') - } - }, - - async mounted() { - this.periodos = await fetch('action/periodos.php').then(res => res.json()) - this.niveles = await fetch('action/nivel.php').then(res => res.json()) - } +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' + +interface Periodo { + created_at: Date; + estado_id: number; + id_periodo_sgu: number; + nivel: string; + nivel_id: number | ''; + periodo_clave: string; + periodo_fecha_fin: Date; + periodo_fecha_inicio: Date; + periodo_id: number; + periodo_nombre: string; +} + +interface Nivel { + nivel_id: number; + nivel_nombre: string; +} + +const app = createApp({ + periodos: [] as Array, + niveles: [] as Array, + messages: [] as Array<{ title: string, text: string, type: string, timestamp: string }>, + + addMessage(title: string, text: string, type: string) { + this.messages.push({ title, text, type, timestamp: new Date() }); + }, + + async sendRequest(action: string, periodo_id: number, data: any) { + const response = await fetch('action/periodos.php', { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + action: action, + periodo_id: periodo_id, + ...data + }) + }) + return await response.json() + }, + + async changeNivel(periodo: Periodo, nivel_id: number) { + if (periodo.nivel_id === nivel_id) return + + const result = await this.sendRequest('changeNivel', periodo.periodo_id, { nivel_id: nivel_id }) + if (result.success) { + this.addMessage('Nivel cambiado', `El nivel del periodo ${periodo.periodo_nombre} ha sido cambiado a ${this.niveles.find((nivel: Nivel) => nivel.nivel_id === nivel_id)?.nivel_nombre}`, 'success') + periodo.nivel_id = nivel_id + periodo.nivel = this.niveles.find((nivel: Nivel) => nivel.nivel_id === nivel_id)?.nivel_nombre || '' + } else { + this.addMessage('Error al cambiar nivel', `No se pudo cambiar el nivel del periodo ${periodo.periodo_nombre}`, 'danger') + } + }, + + async changeFechaInicio(periodo: Periodo, fecha_inicio: Date) { + const result = await this.sendRequest('changeFechaInicio', periodo.periodo_id, { periodo_fecha_inicio: fecha_inicio }) + if (result.success) { + this.addMessage('Fecha de inicio cambiada', `La fecha de inicio del periodo ${periodo.periodo_nombre} ha sido cambiada a ${fecha_inicio}`, 'success') + + periodo.periodo_fecha_inicio = fecha_inicio + } else { + this.addMessage('Error al cambiar fecha de inicio', `No se pudo cambiar la fecha de inicio del periodo ${periodo.periodo_nombre}`, 'danger') + } + }, + + async changeFechaFin(periodo: Periodo, fecha_fin: Date) { + const result = await this.sendRequest('changeFechaFin', periodo.periodo_id, { periodo_fecha_fin: fecha_fin }) + if (result.success) { + this.addMessage('Fecha de fin cambiada', `La fecha de fin del periodo ${periodo.periodo_nombre} ha sido cambiada a ${fecha_fin}`, 'success') + periodo.periodo_fecha_fin = fecha_fin + } else { + this.addMessage('Error al cambiar fecha de fin', `No se pudo cambiar la fecha de fin del periodo ${periodo.periodo_nombre}`, 'danger') + } + }, + + + async updatePeriodo(periodo: Periodo) { + const result = await this.sendRequest('updatePeriodo', periodo.periodo_id, { + periodo_nombre: periodo.periodo_nombre, + id_periodo_sgu: periodo.id_periodo_sgu, + periodo_clave: periodo.periodo_clave, + }) + if (result.success) { + this.addMessage('Periodo actualizado', `El periodo ${periodo.periodo_nombre} ha sido actualizado`, 'success') + } else { + this.addMessage('Error al actualizar periodo', `No se pudo actualizar el periodo ${periodo.periodo_nombre}`, 'danger') + } + }, + + + async createPeriodo(newPeriodo: Periodo) { + + if (newPeriodo.periodo_nombre === null || newPeriodo.nivel_id === null || newPeriodo.periodo_fecha_inicio === null || newPeriodo.periodo_fecha_fin === null) { + this.addMessage('Error al crear periodo', `No se pudo crear el periodo ${newPeriodo.periodo_nombre}`, 'danger') + return + } + + const result = await fetch('action/periodos.php', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(newPeriodo) + }).then(res => res.json()) + + if (result.success) { + this.addMessage('Periodo creado', `El periodo ${newPeriodo.periodo_nombre} ha sido creado`, 'success') + + this.periodos + Object.keys(newPeriodo).forEach(key => newPeriodo[key] = null); + newPeriodo.nivel_id = ''; + this.periodos = await fetch('action/periodos.php').then(res => res.json()) + } else { + this.addMessage('Error al crear periodo', `No se pudo crear el periodo ${newPeriodo.periodo_nombre}`, 'danger') + } + }, + + async deletePeriodo(periodo: Periodo) { + const response = await fetch('action/periodos.php', { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + periodo_id: periodo.periodo_id, + }) + }) + const result = await response.json() + + if (result.success) { + this.addMessage('Periodo eliminado', `El periodo ${periodo.periodo_nombre} ha sido eliminado`, 'success') + this.periodos = this.periodos.filter((p: Periodo) => p.periodo_id !== periodo.periodo_id) + } else { + this.addMessage('Error al eliminar periodo', `No se pudo eliminar el periodo ${periodo.periodo_nombre}`, 'danger') + } + }, + + async mounted() { + this.periodos = await fetch('action/periodos.php').then(res => res.json()) + this.niveles = await fetch('action/nivel.php').then(res => res.json()) + } }).mount('#app') \ No newline at end of file diff --git a/ts/puestos.ts b/ts/puestos.ts index 7103cda..6450cb0 100644 --- a/ts/puestos.ts +++ b/ts/puestos.ts @@ -1,106 +1,106 @@ -import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' -type Puesto = { - puesto_id: number, - nombre: string, - facultad_id: number, -} - -type Carrera = { - carrera_id: number; - carrera_nombre: string; - clave_carrera: string; -} - -type Materia = { - carrera_id: number; - clave_materia: string; - materia_id: number; - materia_nombre: string; -} - -type Usuario = { - usuario_clave: string; - usuario_id: number; - usuario_nombre: string; -} - -const app = createApp({ - message: null, - puestos: [] as Puesto[], - carreras: [] as Carrera[], - materias: [] as Materia[], - usuarios: [] as Usuario[], - - async nuevoPuesto(nuevoPuesto: string) { - try { - const res = await fetch('action/puesto.php', { - method: 'POST', - body: JSON.stringify({ - puesto_nombre: nuevoPuesto - }) - }) - const data = await res.json() - this.puestos.push(data) - // order by puesto.nombre - this.puestos.sort((a: Puesto, b: Puesto) => a.nombre.localeCompare(b.nombre)) - } catch (error) { - alert(`Error: ${error}`) - - } - }, - - to_delete: null as Puesto | null, - async eliminarPuesto(puesto_id: number) { - try { - const res = await fetch('action/puesto.php', { - method: 'DELETE', - body: JSON.stringify({ - puesto_id - }) - }) - const data = await res.json() - this.message = data.msg; - - // after 3 seconds, remove the message - setTimeout(() => { - this.message = null - }, 3000) - - this.puestos = this.puestos.filter((p: Puesto) => p.puesto_id !== puesto_id) - // order by puesto.nombre - this.puestos.sort((a: Puesto, b: Puesto) => a.nombre.localeCompare(b.nombre)) - } catch (error) { - alert(`Error: ${error}`) - - } - }, - - async actualizarPuesto(puesto_id: number, materias: Materia[], usuario_id: number | null) { - try { - const res = await fetch('action/puesto.php', { - method: 'PUT', - body: JSON.stringify({ - puesto_id, - materias: materias.map(m => m.materia_id), - usuario_id - }) - }) - const data = await res.json() - this.message = data.msg; - - // after 3 seconds, remove the message - setTimeout(() => { - this.message = null - }, 3000) - } catch (error) { - alert(`Error: ${error}`) - } - }, - - async mounted() { - this.puestos = await fetch('action/puesto.php').then(res => res.json()) - this.carreras = await fetch('action/action_carreras.php').then(res => res.json()) - this.materias = await fetch('action/action_materias.php').then(res => res.json()) - this.usuarios = await fetch('action/usuarios.php').then(res => res.json()) - } +import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' +type Puesto = { + puesto_id: number, + nombre: string, + facultad_id: number, +} + +type Carrera = { + carrera_id: number; + carrera_nombre: string; + clave_carrera: string; +} + +type Materia = { + carrera_id: number; + clave_materia: string; + materia_id: number; + materia_nombre: string; +} + +type Usuario = { + usuario_clave: string; + usuario_id: number; + usuario_nombre: string; +} + +const app = createApp({ + message: null, + puestos: [] as Puesto[], + carreras: [] as Carrera[], + materias: [] as Materia[], + usuarios: [] as Usuario[], + + async nuevoPuesto(nuevoPuesto: string) { + try { + const res = await fetch('action/puesto.php', { + method: 'POST', + body: JSON.stringify({ + puesto_nombre: nuevoPuesto + }) + }) + const data = await res.json() + this.puestos.push(data) + // order by puesto.nombre + this.puestos.sort((a: Puesto, b: Puesto) => a.nombre.localeCompare(b.nombre)) + } catch (error) { + alert(`Error: ${error}`) + + } + }, + + to_delete: null as Puesto | null, + async eliminarPuesto(puesto_id: number) { + try { + const res = await fetch('action/puesto.php', { + method: 'DELETE', + body: JSON.stringify({ + puesto_id + }) + }) + const data = await res.json() + this.message = data.msg; + + // after 3 seconds, remove the message + setTimeout(() => { + this.message = null + }, 3000) + + this.puestos = this.puestos.filter((p: Puesto) => p.puesto_id !== puesto_id) + // order by puesto.nombre + this.puestos.sort((a: Puesto, b: Puesto) => a.nombre.localeCompare(b.nombre)) + } catch (error) { + alert(`Error: ${error}`) + + } + }, + + async actualizarPuesto(puesto_id: number, materias: Materia[], usuario_id: number | null) { + try { + const res = await fetch('action/puesto.php', { + method: 'PUT', + body: JSON.stringify({ + puesto_id, + materias: materias.map(m => m.materia_id), + usuario_id + }) + }) + const data = await res.json() + this.message = data.msg; + + // after 3 seconds, remove the message + setTimeout(() => { + this.message = null + }, 3000) + } catch (error) { + alert(`Error: ${error}`) + } + }, + + async mounted() { + this.puestos = await fetch('action/puesto.php').then(res => res.json()) + this.carreras = await fetch('action/action_carreras.php').then(res => res.json()) + this.materias = await fetch('action/action_materias.php').then(res => res.json()) + this.usuarios = await fetch('action/usuarios.php').then(res => res.json()) + } }).mount('#app') \ No newline at end of file