{"id":22853,"date":"2026-03-10T15:41:21","date_gmt":"2026-03-10T15:41:21","guid":{"rendered":"https:\/\/esi.uclm.es\/?page_id=22853"},"modified":"2026-09-20T07:27:04","modified_gmt":"2026-09-20T07:27:04","slug":"consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica","status":"publish","type":"page","link":"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/","title":{"rendered":"Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica"},"content":{"rendered":"\n<div id=\"esi-examenes\">\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Montserrat:wght@400;500;600;700&#038;family=JetBrains+Mono:wght@400;500&#038;display=swap\" rel=\"stylesheet\">\n<style>\n  \/* ===== Ex\u00e1menes ESI \u2014 todo acotado a #esi-examenes, no toca el resto de la p\u00e1gina ===== *\/\n  #esi-examenes {\n    --esi-blue: #0097d7;\n    --esi-navy: #0077ad;\n    --esi-accent: #e8a838;\n    --bg: #f7f8fa;\n    --card: #ffffff;\n    --text: #4d4d4d;\n    --text-strong: #2f2f2f;\n    --text-muted: #767575;\n    --border: #e0e0e0;\n    --oblig-bg: #ffffff;\n    --tech-bg: #f2f8fc;\n    --tech-border: #a8d7ef;\n    --opt-bg: #fafafa;\n    --opt-border: #c9cdd2;\n    --next-bg: #fdf5e6;\n    --next-border: #e8a838;\n    --shadow-sm: 0 1px 2px rgba(0,0,0,.05);\n    --shadow-md: 0 2px 8px rgba(0,0,0,.07);\n    --radius: 6px;\n    --radius-lg: 8px;\n    font-family: Montserrat, 'DM Sans', system-ui, sans-serif;\n    color: var(--text);\n    line-height: 1.5;\n    display: block;\n  }\n  #esi-examenes *, #esi-examenes *::before, #esi-examenes *::after { margin: 0; padding: 0; box-sizing: border-box; }\n  #esi-examenes .mono { font-family: 'JetBrains Mono', monospace; }\n\n  \/* ----- barra superior: cuatrimestre | convocatoria ----- *\/\n  #esi-examenes .toolbar { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; padding: 0 0 1rem; }\n  #esi-examenes .toolbar-sep { width: 1px; height: 26px; background: var(--border); flex-shrink: 0; }\n  #esi-examenes .mode-tabs { display: flex; flex-wrap: wrap; gap: .25rem; background: #f0f1f3; border: 1px solid var(--border); border-radius: var(--radius); padding: 3px; }\n  #esi-examenes .mode-tab { position: relative; padding: .45rem 1rem; border: none; background: transparent; color: var(--text-muted); font-family: inherit; font-size: .82rem; font-weight: 600; border-radius: 4px; cursor: pointer; transition: background .15s, color .15s; line-height: 1.2; }\n  #esi-examenes .mode-tab:hover { color: var(--esi-navy); background: rgba(0,151,215,.08); }\n  #esi-examenes .mode-tab.active { background: var(--esi-blue); color: #fff; }\n  #esi-examenes .mode-tab:disabled { opacity: .4; cursor: not-allowed; background: transparent; color: var(--text-muted); }\n\n  \/* ----- filtros ----- *\/\n  #esi-examenes .filters-bar { display: flex; align-items: flex-end; gap: 1rem 1.4rem; flex-wrap: wrap; padding: .9rem 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }\n  #esi-examenes .filter-group { display: flex; flex-direction: column; gap: .3rem; }\n  #esi-examenes .filter-group > label, #esi-examenes .filter-group > .flabel { font-size: .66rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-muted); }\n  #esi-examenes .filter-group select, #esi-examenes .filter-group input { font-family: inherit; font-size: .82rem; padding: .4rem .65rem; border: 1px solid var(--border); border-radius: var(--radius); background: var(--card); color: var(--text); min-width: 150px; transition: border-color .15s; }\n  #esi-examenes .filter-group input { min-width: 190px; }\n  #esi-examenes .filter-group select:focus, #esi-examenes .filter-group input:focus { outline: none; border-color: var(--esi-blue); }\n  #esi-examenes .filter-chip-row { display: flex; gap: .3rem; flex-wrap: wrap; }\n  #esi-examenes .filter-chip { padding: .35rem .75rem; font-family: inherit; font-size: .76rem; font-weight: 600; border: 1px solid var(--border); border-radius: 20px; background: var(--card); color: var(--text-muted); cursor: pointer; transition: all .15s; white-space: nowrap; line-height: 1.2; }\n  #esi-examenes .filter-chip:hover { border-color: var(--esi-blue); color: var(--esi-blue); }\n  #esi-examenes .filter-chip.active { background: var(--esi-blue); color: #fff; border-color: var(--esi-blue); }\n  #esi-examenes .btn-clear { margin-left: auto; padding: .4rem .9rem; font-family: inherit; font-size: .76rem; font-weight: 600; border: 1px solid var(--border); border-radius: var(--radius); background: var(--card); color: var(--text-muted); cursor: pointer; transition: all .15s; }\n  #esi-examenes .btn-clear:hover { border-color: #b30133; color: #b30133; }\n\n  \/* ----- cabecera de convocatoria + estado ----- *\/\n  #esi-examenes .main { padding: 1.25rem 0 2rem; max-width: 100%; }\n  #esi-examenes .convo-head { display: flex; align-items: center; gap: .6rem .9rem; flex-wrap: wrap; margin-bottom: .35rem; }\n  #esi-examenes .convo-head h2 { font-family: inherit; font-size: 1.05rem; font-weight: 700; color: var(--text-strong); line-height: 1.3; }\n  #esi-examenes .convo-range { font-size: .74rem; color: var(--text-muted); }\n  #esi-examenes .pill-next { display: inline-flex; align-items: center; gap: .3rem; font-size: .62rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #8a6200; background: var(--next-bg); border: 1px solid var(--next-border); border-radius: 999px; padding: .15rem .55rem; }\n  #esi-examenes .pill-next::before { content: \"\"; width: 6px; height: 6px; border-radius: 50%; background: var(--esi-accent); }\n  #esi-examenes .link-next { font-family: inherit; font-size: .74rem; font-weight: 600; color: var(--esi-blue); background: none; border: none; cursor: pointer; padding: 0; border-bottom: 1px dashed currentColor; }\n  #esi-examenes .link-next:hover { color: var(--esi-navy); }\n\n  #esi-examenes .status-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; flex-wrap: wrap; gap: .5rem; }\n  #esi-examenes .status-bar .count { font-size: .82rem; color: var(--text-muted); }\n  #esi-examenes .status-bar .count strong { color: var(--text-strong); font-weight: 700; }\n  #esi-examenes .status-right { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; }\n  #esi-examenes .legend { display: flex; gap: 1rem; font-size: .73rem; color: var(--text-muted); flex-wrap: wrap; }\n  #esi-examenes .legend-item { display: flex; align-items: center; gap: .35rem; }\n  #esi-examenes .legend-dot { width: 10px; height: 10px; border-radius: 3px; border: 1.5px solid; }\n  #esi-examenes .legend-dot.oblig { background: var(--oblig-bg); border-color: var(--esi-blue); }\n  #esi-examenes .legend-dot.tech { background: var(--tech-bg); border-color: var(--tech-border); }\n  #esi-examenes .legend-dot.opt { background: var(--opt-bg); border-color: var(--opt-border); }\n  #esi-examenes .view-toggle { display: flex; gap: .25rem; background: #f0f1f3; border-radius: var(--radius); padding: 2px; border: 1px solid var(--border); }\n  #esi-examenes .view-btn { padding: .3rem .65rem; border: none; background: transparent; font-family: inherit; font-size: .73rem; font-weight: 600; color: var(--text-muted); border-radius: 4px; cursor: pointer; transition: all .15s; }\n  #esi-examenes .view-btn.active { background: var(--card); color: var(--text-strong); box-shadow: var(--shadow-sm); }\n\n  \/* ----- vista agenda: un bloque por d\u00eda ----- *\/\n  #esi-examenes .agenda { display: flex; flex-direction: column; gap: .75rem; }\n  #esi-examenes .day { display: grid; grid-template-columns: 92px 1fr; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm); }\n  #esi-examenes .day-date { background: var(--bg); border-right: 1px solid var(--border); display: flex; flex-direction: column; align-items: center; justify-content: center; padding: .8rem .4rem; text-align: center; gap: .1rem; position: relative; }\n  #esi-examenes .day-dow { font-size: .64rem; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--text-muted); }\n  #esi-examenes .day-num { font-size: 1.7rem; font-weight: 700; color: var(--esi-navy); line-height: 1.05; }\n  #esi-examenes .day-mon { font-size: .64rem; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; color: var(--text-muted); }\n  #esi-examenes .day.is-next { border-color: var(--next-border); }\n  #esi-examenes .day.is-next .day-date { background: var(--next-bg); border-right-color: #f0d9a8; }\n  #esi-examenes .day-flag { margin-top: .35rem; font-size: .55rem; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: #8a6200; }\n  #esi-examenes .day.is-past { opacity: .55; }\n  #esi-examenes .day.is-past:hover { opacity: 1; }\n  #esi-examenes .day-body { display: flex; flex-direction: column; }\n  #esi-examenes .slot { display: grid; grid-template-columns: 64px 1fr; border-top: 1px solid var(--border); }\n  #esi-examenes .slot:first-child { border-top: none; }\n  #esi-examenes .slot-time { font-size: .74rem; font-weight: 500; color: var(--text-muted); padding: .7rem 0 0 .8rem; }\n  #esi-examenes .slot-exams { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: .5rem; padding: .55rem .7rem .55rem 0; }\n\n  \/* ----- tarjeta de examen ----- *\/\n  #esi-examenes .exam-card { padding: .5rem .65rem .55rem; border: 1px solid #d6dbe0; border-left: 4px solid var(--esi-blue); border-radius: 4px; background: var(--oblig-bg); display: flex; flex-direction: column; gap: .25rem; transition: box-shadow .15s; }\n  #esi-examenes .exam-card:hover { box-shadow: var(--shadow-md); }\n  #esi-examenes .exam-card.tech { background: var(--tech-bg); border-color: #d6ebf6; border-left-color: var(--tech-border); }\n  #esi-examenes .exam-card.opt { background: var(--opt-bg); border-color: #ececec; border-left-color: var(--opt-border); }\n  #esi-examenes .exam-top { display: flex; align-items: center; gap: .3rem; flex-wrap: wrap; }\n  #esi-examenes .badge { display: inline-block; font-size: .58rem; font-weight: 700; padding: .12rem .38rem; border-radius: 3px; background: var(--esi-navy); color: #fff; letter-spacing: .03em; line-height: 1.3; }\n  #esi-examenes .badge.soft { background: transparent; color: var(--text-muted); border: 1px solid var(--border); }\n  #esi-examenes .exam-card.tech .badge.type { background: #0b7fb8; }\n  #esi-examenes .exam-card.opt .badge.type { background: transparent; color: var(--text-muted); border: 1px solid var(--opt-border); }\n  #esi-examenes .exam-subject { font-weight: 700; color: var(--esi-navy); font-size: .84rem; line-height: 1.3; }\n  #esi-examenes .exam-card.opt .exam-subject { color: #5a5f66; font-weight: 600; }\n  #esi-examenes .rooms { display: flex; flex-wrap: wrap; gap: .25rem; margin-top: .1rem; }\n  #esi-examenes .room { display: inline-flex; align-items: center; gap: .22rem; font-size: .64rem; line-height: 1; color: var(--text-muted); background: rgba(255,255,255,.7); border: 1px solid var(--border); border-radius: 999px; padding: .2rem .45rem; white-space: nowrap; }\n  #esi-examenes a.room { text-decoration: none; cursor: pointer; transition: color .15s, border-color .15s, background .15s; }\n  #esi-examenes a.room:hover { color: var(--esi-blue); border-color: var(--esi-blue); background: #fff; }\n  #esi-examenes a.room .pin { opacity: .5; transition: opacity .15s; }\n  #esi-examenes a.room:hover .pin { opacity: 1; }\n  #esi-examenes .room-link { color: inherit; text-decoration: none; border-bottom: 1px dashed rgba(0,0,0,.25); transition: color .15s, border-color .15s; }\n  #esi-examenes .room-link:hover { color: var(--esi-blue); border-bottom-color: var(--esi-blue); }\n  #esi-examenes .room-link svg { width: 10px; height: 10px; margin-left: .2rem; vertical-align: -1px; opacity: .55; stroke: currentColor; fill: none; stroke-width: 2; }\n  #esi-examenes .room svg { width: 10px; height: 10px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }\n\n  \/* ----- vista lista ----- *\/\n  #esi-examenes .list-table { width: 100%; border-collapse: collapse; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm); }\n  #esi-examenes .list-table th { background: var(--esi-blue); color: #fff; font-size: .73rem; font-weight: 700; padding: .65rem .7rem; text-align: left; letter-spacing: .02em; }\n  #esi-examenes .list-table td { font-size: .78rem; padding: .55rem .7rem; border-bottom: 1px solid var(--border); vertical-align: top; }\n  #esi-examenes .list-table tr:last-child td { border-bottom: none; }\n  #esi-examenes .list-table tbody tr:hover td { background: var(--bg); }\n  #esi-examenes .list-table tr.is-past td { color: var(--text-muted); }\n  #esi-examenes .list-table td.subj { font-weight: 700; color: var(--esi-navy); }\n  #esi-examenes .list-table td.nowrap { white-space: nowrap; }\n  #esi-examenes .list-table td .badge.type.tech { background: #0b7fb8; }\n  #esi-examenes .list-table td .badge.type.opt { background: transparent; color: var(--text-muted); border: 1px solid var(--opt-border); }\n  #esi-examenes .list-table tr.opt td.subj { color: #5a5f66; font-weight: 600; }\n\n  #esi-examenes .empty-state { text-align: center; padding: 3rem 2rem; color: var(--text-muted); background: var(--card); border: 1px dashed var(--border); border-radius: var(--radius-lg); }\n  #esi-examenes .empty-state h3 { font-family: inherit; font-size: 1.05rem; font-weight: 700; margin-bottom: .4rem; color: var(--text-strong); }\n  #esi-examenes .empty-state p { font-size: .85rem; }\n\n  \/* ----- carga ----- *\/\n  #esi-examenes .cargando { padding: .5rem 0 0; }\n  #esi-examenes .cargando-barra { height: 3px; background: #e8eaed; border-radius: 2px; overflow: hidden; }\n  #esi-examenes .cargando-barra span { display: block; height: 100%; width: 35%; background: var(--esi-blue); border-radius: 2px; animation: exCargaDesliza 1.1s ease-in-out infinite; }\n  #esi-examenes .cargando p { margin-top: .7rem; font-size: .85rem; color: var(--text-muted); }\n  #esi-examenes .cargando-bloques { margin-top: 1rem; display: flex; flex-direction: column; gap: .75rem; }\n  #esi-examenes .cargando-bloques i { display: block; height: 76px; border: 1px solid var(--border); border-radius: var(--radius-lg); background: linear-gradient(90deg, var(--card) 25%, #f1f3f5 37%, var(--card) 63%); background-size: 400% 100%; animation: exCargaBrillo 1.4s ease infinite; }\n  @keyframes exCargaDesliza { 0% { transform: translateX(-110%); } 100% { transform: translateX(320%); } }\n  @keyframes exCargaBrillo { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }\n  @keyframes exFadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }\n  #esi-examenes .fade-in { animation: exFadeIn .3s ease-out; }\n  @media (prefers-reduced-motion: reduce) {\n    #esi-examenes .cargando-barra span, #esi-examenes .cargando-bloques i, #esi-examenes .fade-in { animation: none; }\n  }\n\n  \/* ----- m\u00f3vil ----- *\/\n  @media (max-width: 760px) {\n    #esi-examenes .toolbar-sep { display: none; }\n    #esi-examenes .toolbar { gap: .5rem; }\n    #esi-examenes .btn-clear { margin-left: 0; }\n    #esi-examenes .filter-group, #esi-examenes .filter-group select, #esi-examenes .filter-group input { width: 100%; min-width: 0; }\n    #esi-examenes .filters-bar .filter-group.half { width: calc(50% - .7rem); }\n    #esi-examenes .status-bar { flex-direction: column; align-items: stretch; gap: .6rem; }\n    #esi-examenes .status-right { justify-content: space-between; gap: .6rem; }\n    #esi-examenes .legend { gap: .7rem; font-size: .68rem; }\n\n    #esi-examenes .day { grid-template-columns: 1fr; }\n    #esi-examenes .day-date { flex-direction: row; justify-content: flex-start; gap: .45rem; padding: .5rem .8rem; border-right: none; border-bottom: 1px solid var(--border); }\n    #esi-examenes .day.is-next .day-date { border-bottom-color: #f0d9a8; }\n    #esi-examenes .day-num { font-size: 1.05rem; }\n    #esi-examenes .day-dow, #esi-examenes .day-mon { font-size: .7rem; }\n    #esi-examenes .day-flag { margin: 0 0 0 auto; }\n    #esi-examenes .slot { grid-template-columns: 52px 1fr; }\n    #esi-examenes .slot-time { padding-left: .7rem; }\n    #esi-examenes .slot-exams { grid-template-columns: 1fr; padding-right: .6rem; }\n\n    #esi-examenes .list-table { display: block; background: transparent; border: none; box-shadow: none; border-radius: 0; }\n    #esi-examenes .list-table thead { display: none; }\n    #esi-examenes .list-table tbody { display: block; }\n    #esi-examenes .list-table tr { display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .5rem; background: var(--card); border: 1px solid var(--border); border-left: 3px solid var(--esi-blue); border-radius: var(--radius); padding: .65rem .8rem; margin-bottom: .5rem; }\n    #esi-examenes .list-table tr.tech { border-left-color: var(--tech-border); }\n    #esi-examenes .list-table tr.opt { border-left-color: var(--opt-border); }\n    #esi-examenes .list-table tbody tr:hover td { background: transparent; }\n    #esi-examenes .list-table td { display: block; border: none; padding: 0; font-size: .8rem; }\n    #esi-examenes .list-table td:nth-child(1) { order: 1; font-weight: 700; color: var(--text-strong); text-transform: uppercase; font-size: .7rem; letter-spacing: .04em; }\n    #esi-examenes .list-table td:nth-child(2) { order: 2; color: var(--text-muted); font-size: .72rem; }\n    #esi-examenes .list-table td:nth-child(4) { order: 3; flex: 0 0 100%; font-size: .92rem; margin: .15rem 0; }\n    #esi-examenes .list-table td:nth-child(3) { order: 4; }\n    #esi-examenes .list-table td:nth-child(5) { order: 5; }\n    #esi-examenes .list-table td:nth-child(6) { order: 6; flex: 0 0 100%; color: var(--text-muted); font-size: .76rem; }\n    #esi-examenes .list-table td:nth-child(6)::before { content: \"Aulas: \"; font-weight: 600; }\n  }\n<\/style>\n\n<div class=\"toolbar\">\n  <div class=\"mode-tabs\" id=\"exCuatriTabs\" role=\"tablist\" aria-label=\"Cuatrimestre\"><\/div>\n  <div class=\"toolbar-sep\"><\/div>\n  <div class=\"mode-tabs\" id=\"exConvTabs\" role=\"tablist\" aria-label=\"Convocatoria\"><\/div>\n<\/div>\n\n<div class=\"filters-bar\" id=\"exFilters\">\n  <div class=\"filter-group\">\n    <span class=\"flabel\">Curso<\/span>\n    <div class=\"filter-chip-row\" id=\"exCourseChips\"><\/div>\n  <\/div>\n  <div class=\"filter-group\">\n    <span class=\"flabel\">Tipo<\/span>\n    <div class=\"filter-chip-row\" id=\"exTypeChips\"><\/div>\n  <\/div>\n  <div class=\"filter-group half\">\n    <label for=\"exDay\">D\u00eda<\/label>\n    <select id=\"exDay\"><\/select>\n  <\/div>\n  <div class=\"filter-group half\">\n    <label for=\"exSearch\">Asignatura o aula<\/label>\n    <input id=\"exSearch\" type=\"search\" placeholder=\"Buscar\u2026\" autocomplete=\"off\">\n  <\/div>\n  <button class=\"btn-clear\" id=\"exClear\" type=\"button\">Limpiar filtros<\/button>\n<\/div>\n\n<div class=\"main\">\n  <div class=\"convo-head\" id=\"exHead\"><\/div>\n  <div class=\"status-bar\">\n    <div class=\"count\" id=\"exCount\"><\/div>\n    <div class=\"status-right\">\n      <div class=\"legend\">\n        <div class=\"legend-item\"><div class=\"legend-dot oblig\"><\/div>Obligatoria<\/div>\n        <div class=\"legend-item\"><div class=\"legend-dot tech\"><\/div>Tecnolog\u00eda espec\u00edfica<\/div>\n        <div class=\"legend-item\"><div class=\"legend-dot opt\"><\/div>Optativa<\/div>\n      <\/div>\n      <div class=\"view-toggle\">\n        <button class=\"view-btn active\" type=\"button\" data-view=\"agenda\">Calendario<\/button>\n        <button class=\"view-btn\" type=\"button\" data-view=\"list\">Lista<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n  <div id=\"exContent\">\n    <div class=\"cargando\" role=\"status\" aria-live=\"polite\">\n      <div class=\"cargando-barra\"><span><\/span><\/div>\n      <p>Cargando calendario de ex\u00e1menes\u2026<\/p>\n      <div class=\"cargando-bloques\"><i><\/i><i><\/i><i><\/i><\/div>\n    <\/div>\n  <\/div>\n<\/div>\n<\/div>\n\n<script>\n(function () {\n  'use strict';\n\n  const EXAMS_JSON_URL = 'https:\/\/esi.uclm.es\/TV\/hall\/examenes.json';\n\n  const TECH = {\n    IC: 'Ingenier\u00eda de Computadores',\n    CO: 'Computaci\u00f3n',\n    IS: 'Ingenier\u00eda del Software',\n    TI: 'Tecnolog\u00edas de la Informaci\u00f3n'\n  };\n  const DOW = ['Dom', 'Lun', 'Mar', 'Mi\u00e9', 'Jue', 'Vie', 'S\u00e1b'];\n  const MON = ['ene', 'feb', 'mar', 'abr', 'may', 'jun', 'jul', 'ago', 'sep', 'oct', 'nov', 'dic'];\n  const ICON_ROOM = '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M4 21h16M6 21V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v17\"\/><path d=\"M14 12h.01\"\/><\/svg>';\n\n  \/\/ Enlace al mapa interactivo: igual que en horarios.js, se guarda el id del aula\n  \/\/ en localStorage y el mapa la abre seleccionada.\n  const MAP_URL = 'https:\/\/esi.uclm.es\/index.php\/mapa-interactivo-de-aulas-y-laboratorios\/';\n  const MAP_STORAGE_KEY = 'esi-map-selected';\n  const ICON_PIN = '<svg class=\"pin\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M12 21s-7-6.5-7-12a7 7 0 1 1 14 0c0 5.5-7 12-7 12Z\"\/><circle cx=\"12\" cy=\"9\" r=\"2.5\"\/><\/svg>';\n  \/\/ id del mapa -> nombres y c\u00f3digos con los que aparece el aula.\n  const ROOMS = {\n    'p-0-07': ['Claude Shannon', '0.07'],\n    'p-0-05': ['Edsger W. Dijkstra', 'Edsger Dijkstra', '0.05+6', '0.05', '0.06'],\n    'p-0-02': ['Charles Babbage', '0.02+3', '0.02', '0.03'],\n    'p-0-04': ['Hedy Lamarr', '0.04'],\n    'fc-0-f01': ['Marvin Minsky', 'F0.1'],\n    'fc-0-f02': ['Steve Jobs', 'F0.2'],\n    'fc-0-grados': ['Ada Lovelace', 'Sal\u00f3n de Grados', 'Sal\u00f3n Grados'],\n    'fc-0-actos': ['Alan Turing', 'Sal\u00f3n de Actos', 'Sal\u00f3n Actos'],\n    'fc-0-anita': ['Anita Borg'],\n    'fc-1-f11': ['\u00c1ngela Ruiz Robles', 'F1.1'],\n    'fc-1-a11': ['John von Neumann', 'John Von Neuman', 'A1.1'],\n    'fc-1-a12': ['Tim Berners-Lee', 'A1.2'],\n    'fc-1-ld1': ['Ignacio Cirac', 'LD1'],\n    'fc-1-ld2': ['Dennis Ritchie', 'LD2'],\n    'fc-1-ld3': ['Bill Gates', 'LD3'],\n    'fc-2-ld4': ['John Carmack', 'LD4'],\n    'fc-2-a21': ['George Boole', 'A2.1'],\n    'fc-2-a22': ['Grace Murray Hopper', 'Grace Hopper', 'A2.2']\n  };\n  const ROOM_INDEX = {};\n  Object.keys(ROOMS).forEach(id => ROOMS[id].forEach(n => { ROOM_INDEX[roomKey(n)] = id; }));\n  function roomKey(n) {\n    return String(n || '').toLowerCase().normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '').replace(\/^aula\\s+\/, '').replace(\/[^a-z0-9.+]\/g, '');\n  }\n  function findRoomId(name) {\n    return ROOM_INDEX[roomKey(name)] || null;\n  }\n  function splitRooms(rooms) {\n    return String(rooms || '').split(',').map(r => r.trim()).filter(Boolean);\n  }\n\n  const root = document.getElementById('esi-examenes');\n  if (!root) return;\n  const $ = id => document.getElementById(id);\n\n  let metadata = {};\n  let convocatorias = [];\n  let nextConvoId = null;\n  const state = { convo: null, course: 'all', type: 'all', day: 'all', q: '', view: 'agenda' };\n  const todayStr = isoToday();\n\n  \/* ------------------------------------------------------------------ carga *\/\n  async function init() {\n    try {\n      const res = await fetch(EXAMS_JSON_URL, { cache: 'no-store' });\n      if (!res.ok) throw new Error('HTTP ' + res.status);\n      parseData(await res.json());\n    } catch (err) {\n      console.error('[ESI Ex\u00e1menes] Error al cargar el JSON:', err);\n      $('exContent').innerHTML = emptyState('No se ha podido cargar el calendario',\n        'Int\u00e9ntalo de nuevo en unos minutos. Si el problema persiste, avisa a la Secretar\u00eda de la ESI.');\n      return;\n    }\n    nextConvoId = pickDefaultConvocatoria();\n    readHash();\n    if (!convocatorias.some(c => c.id === state.convo)) state.convo = nextConvoId;\n    bindStatic();\n    renderAll();\n  }\n\n  function parseData(data) {\n    if (data && Array.isArray(data.convocatorias)) {\n      metadata = data.metadata || {};\n      convocatorias = data.convocatorias.map(c => ({ ...c, examenes: sortExams(c.examenes || []) }));\n    } else if (Array.isArray(data)) {\n      convocatorias = [wrapLegacy(data, {})];\n    } else if (data && Array.isArray(data.examenes)) {\n      metadata = data.metadata || {};\n      convocatorias = [wrapLegacy(data.examenes, metadata)];\n    } else {\n      throw new Error('Estructura de JSON no v\u00e1lida');\n    }\n    if (!convocatorias.length) throw new Error('Sin convocatorias');\n    convocatorias.sort((a, b) => String(a.fechaInicio).localeCompare(String(b.fechaInicio)));\n    convocatorias.forEach(c => {\n      c._cuatri = cuatriKey(c);\n      c._tipo = \/extra\/i.test(c.convocatoria || c.nombre || '') ? 'extra' : 'ord';\n    });\n  }\n\n  function wrapLegacy(list, meta) {\n    const sorted = sortExams(list);\n    const f = sorted.map(e => e.date).filter(Boolean);\n    return {\n      id: 'unica',\n      nombre: [meta.convocatoria, meta.cuatrimestre].filter(Boolean).join(' - ') || 'Ex\u00e1menes',\n      convocatoria: meta.convocatoria || '', cuatrimestre: meta.cuatrimestre || '',\n      fechaInicio: f[0] || '', fechaFin: f[f.length - 1] || '', examenes: sorted\n    };\n  }\n\n  function sortExams(list) {\n    return list.slice().sort((a, b) => {\n      const ka = (a.date || '') + ' ' + normTime(a.time), kb = (b.date || '') + ' ' + normTime(b.time);\n      return ka < kb ? -1 : ka > kb ? 1 : Number(a.id || 0) - Number(b.id || 0);\n    });\n  }\n\n  function cuatriKey(c) {\n    const s = (c.cuatrimestre || c.nombre || '').toLowerCase();\n    if (\/segundo|2\u00ba|2o|\\b2c\\b\/.test(s)) return '2C';\n    if (\/primer|1\u00ba|1o|1er|\\b1c\\b\/.test(s)) return '1C';\n    return '';\n  }\n\n  \/\/ Primera convocatoria cuya \u00faltima fecha a\u00fan no ha pasado; si todas pasaron, la \u00faltima.\n  function pickDefaultConvocatoria() {\n    const c = convocatorias.find(c => String(c.fechaFin || c.fechaInicio || '') >= todayStr);\n    return (c || convocatorias[convocatorias.length - 1]).id;\n  }\n\n  \/* ----------------------------------------------------------- utilidades *\/\n  function isoToday() {\n    const d = new Date();\n    return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0') + '-' + String(d.getDate()).padStart(2, '0');\n  }\n  function normTime(t) {\n    const p = String(t || '').split(':');\n    return String(p[0] || '0').padStart(2, '0') + ':' + String(p[1] || '00').padStart(2, '0');\n  }\n  function parseISO(s) {\n    const m = \/^(\\d{4})-(\\d{2})-(\\d{2})\/.exec(s || '');\n    return m ? new Date(+m[1], +m[2] - 1, +m[3]) : null;\n  }\n  function shortDate(s, withYear) {\n    const d = parseISO(s);\n    return d ? d.getDate() + ' ' + MON[d.getMonth()] + (withYear ? ' ' + d.getFullYear() : '') : '';\n  }\n  function esc(v) {\n    return String(v == null ? '' : v).replace(\/&\/g, '&amp;').replace(\/<\/g, '&lt;').replace(\/>\/g, '&gt;').replace(\/\"\/g, '&quot;').replace(\/'\/g, '&#039;');\n  }\n  function norm(s) {\n    return String(s || '').toLowerCase().normalize('NFD').replace(\/[\u0300-\u036f]\/g, '');\n  }\n  function typeClass(t) {\n    if (TECH[t]) return 'tech';\n    if (t === 'OP' || \/optativ\/i.test(t || '')) return 'opt';\n    return 'oblig';\n  }\n  function typeLabel(t) {\n    if (t === 'OP') return 'Optativa';\n    return t || '';\n  }\n  function typeTitle(t) {\n    if (TECH[t]) return 'Tecnolog\u00eda espec\u00edfica: ' + TECH[t];\n    if (t === 'OP') return 'Optativa';\n    return t || '';\n  }\n  function currentConvo() {\n    return convocatorias.find(c => c.id === state.convo) || convocatorias[0];\n  }\n\n  \/* ---------------------------------------------------------- estado\/URL *\/\n  function readHash() {\n    const h = new URLSearchParams((location.hash || '').replace(\/^#\/, ''));\n    if (h.get('conv')) state.convo = h.get('conv');\n    ['course', 'type', 'day', 'view'].forEach(k => { if (h.get(k)) state[k] = h.get(k); });\n  }\n  function writeHash() {\n    const p = new URLSearchParams();\n    if (state.convo !== nextConvoId) p.set('conv', state.convo);\n    if (state.course !== 'all') p.set('course', state.course);\n    if (state.type !== 'all') p.set('type', state.type);\n    if (state.day !== 'all') p.set('day', state.day);\n    if (state.view !== 'agenda') p.set('view', state.view);\n    const s = p.toString();\n    try { history.replaceState(null, '', s ? '#' + s : location.pathname + location.search); } catch (e) { \/* sin historial *\/ }\n  }\n\n  \/* ------------------------------------------------------------- eventos *\/\n  function bindStatic() {\n    root.addEventListener('click', ev => {\n      const a = ev.target.closest && ev.target.closest('[data-room-id]');\n      if (!a) return;\n      try { localStorage.setItem(MAP_STORAGE_KEY, a.dataset.roomId); } catch (e) { \/* sin almacenamiento *\/ }\n    });\n    $('exDay').addEventListener('change', e => { state.day = e.target.value; renderResults(); });\n    let t;\n    $('exSearch').addEventListener('input', e => {\n      clearTimeout(t);\n      t = setTimeout(() => { state.q = e.target.value.trim(); renderResults(); }, 120);\n    });\n    $('exClear').addEventListener('click', () => {\n      state.course = state.type = state.day = 'all'; state.q = '';\n      $('exSearch').value = '';\n      renderFilters(); renderResults();\n    });\n    root.querySelectorAll('.view-btn').forEach(b => b.addEventListener('click', () => {\n      state.view = b.dataset.view; renderResults();\n    }));\n  }\n\n  function selectConvo(id) {\n    if (!id || id === state.convo) return;\n    state.convo = id;\n    const days = new Set(currentConvo().examenes.map(e => e.date));\n    if (!days.has(state.day)) state.day = 'all';\n    renderAll();\n  }\n\n  \/* ------------------------------------------------------------- render *\/\n  function renderAll() {\n    renderTabs();\n    renderHead();\n    renderFilters();\n    renderResults();\n  }\n\n  function renderTabs() {\n    const cur = currentConvo();\n    const twoAxis = convocatorias.every(c => c._cuatri) &&\n      new Set(convocatorias.map(c => c._cuatri + c._tipo)).size === convocatorias.length;\n    const cTabs = $('exCuatriTabs'), vTabs = $('exConvTabs');\n\n    if (!twoAxis) {\n      \/\/ Estructura no reconocida: una pesta\u00f1a por convocatoria.\n      cTabs.innerHTML = convocatorias.map(c =>\n        `<button type=\"button\" class=\"mode-tab${c.id === cur.id ? ' active' : ''}\" data-id=\"${esc(c.id)}\">${esc(c.nombre || c.id)}<\/button>`).join('');\n      vTabs.style.display = 'none';\n      cTabs.nextElementSibling.style.display = 'none';\n      cTabs.querySelectorAll('button').forEach(b => b.addEventListener('click', () => selectConvo(b.dataset.id)));\n      return;\n    }\n\n    const find = (q, t) => convocatorias.find(c => c._cuatri === q && c._tipo === t);\n    const cuatris = [['1C', '1er Cuatrimestre'], ['2C', '2\u00ba Cuatrimestre']].filter(([k]) => convocatorias.some(c => c._cuatri === k));\n    cTabs.innerHTML = cuatris.map(([k, label]) =>\n      `<button type=\"button\" class=\"mode-tab${cur._cuatri === k ? ' active' : ''}\" data-q=\"${k}\">${label}<\/button>`).join('');\n    vTabs.innerHTML = [['ord', 'Ordinaria'], ['extra', 'Extraordinaria']].map(([k, label]) => {\n      const c = find(cur._cuatri, k);\n      return `<button type=\"button\" class=\"mode-tab${cur._tipo === k ? ' active' : ''}\" data-t=\"${k}\"${c ? '' : ' disabled'}>${label}<\/button>`;\n    }).join('');\n\n    cTabs.querySelectorAll('button').forEach(b => b.addEventListener('click', () => {\n      const q = b.dataset.q;\n      const target = find(q, cur._tipo) || find(q, 'ord') || find(q, 'extra');\n      if (target) selectConvo(target.id);\n    }));\n    vTabs.querySelectorAll('button').forEach(b => b.addEventListener('click', () => {\n      const target = find(cur._cuatri, b.dataset.t);\n      if (target) selectConvo(target.id);\n    }));\n  }\n\n  function renderHead() {\n    const c = currentConvo();\n    const parts = [];\n    if (c.convocatoria) parts.push('Convocatoria ' + c.convocatoria.toLowerCase());\n    if (c.cuatrimestre) parts.push(c.cuatrimestre.toLowerCase());\n    let title = parts.join(' \u00b7 ') || c.nombre || 'Ex\u00e1menes';\n    title = title.charAt(0).toUpperCase() + title.slice(1);\n    const y1 = (c.fechaInicio || '').slice(0, 4), y2 = (c.fechaFin || '').slice(0, 4);\n    const range = c.fechaInicio\n      ? `${shortDate(c.fechaInicio, y1 !== y2)} \u2013 ${shortDate(c.fechaFin || c.fechaInicio, true)}` : '';\n    const isNext = c.id === nextConvoId;\n    const nextC = convocatorias.find(x => x.id === nextConvoId);\n    $('exHead').innerHTML =\n      `<h2>${esc(title)}<\/h2>` +\n      (range ? `<span class=\"convo-range mono\">${esc(range)}<\/span>` : '') +\n      (isNext && String(c.fechaFin) >= todayStr ? '<span class=\"pill-next\">Pr\u00f3xima convocatoria<\/span>' : '') +\n      (!isNext && nextC && String(nextC.fechaFin) >= todayStr\n        ? `<button type=\"button\" class=\"link-next\" id=\"exGoNext\">Ir a la pr\u00f3xima convocatoria \u2192<\/button>` : '');\n    const go = $('exGoNext');\n    if (go) go.addEventListener('click', () => selectConvo(nextConvoId));\n  }\n\n  function renderFilters() {\n    const exams = currentConvo().examenes;\n\n    const courses = [...new Set(exams.map(e => String(e.course)).filter(Boolean))].sort((a, b) => a - b);\n    if (state.course !== 'all' && !courses.includes(state.course)) state.course = 'all';\n    $('exCourseChips').innerHTML = chip('all', 'Todos', state.course) +\n      courses.map(c => chip(c, c + '\u00ba', state.course)).join('');\n    bindChips('exCourseChips', v => { state.course = v; renderFilters(); renderResults(); });\n\n    const present = new Set(exams.map(e => e.type));\n    const types = [['all', 'Todos']];\n    if ([...present].some(t => typeClass(t) === 'oblig')) types.push(['oblig', 'Obligatorias']);\n    Object.keys(TECH).forEach(k => { if (present.has(k)) types.push([k, k]); });\n    if ([...present].some(t => typeClass(t) === 'opt')) types.push(['opt', 'Optativas']);\n    if (!types.some(([k]) => k === state.type)) state.type = 'all';\n    $('exTypeChips').innerHTML = types.map(([k, l]) => chip(k, l, state.type, TECH[k] ? TECH[k] : '')).join('');\n    bindChips('exTypeChips', v => { state.type = v; renderFilters(); renderResults(); });\n\n    const days = [];\n    const seen = new Set();\n    exams.forEach(e => { if (e.date && !seen.has(e.date)) { seen.add(e.date); days.push(e); } });\n    $('exDay').innerHTML = '<option value=\"all\">Todos los d\u00edas<\/option>' +\n      days.map(e => `<option value=\"${esc(e.date)}\"${e.date === state.day ? ' selected' : ''}>${esc(e.displayDate || e.date)}<\/option>`).join('');\n  }\n\n  function chip(value, label, active, title) {\n    return `<button type=\"button\" class=\"filter-chip${value === active ? ' active' : ''}\" data-v=\"${esc(value)}\"${title ? ` title=\"${esc(title)}\"` : ''}>${esc(label)}<\/button>`;\n  }\n  function bindChips(id, fn) {\n    $(id).querySelectorAll('.filter-chip').forEach(b => b.addEventListener('click', () => fn(b.dataset.v)));\n  }\n\n  function filtered() {\n    const q = norm(state.q);\n    return currentConvo().examenes.filter(e => {\n      if (state.course !== 'all' && String(e.course) !== state.course) return false;\n      if (state.type !== 'all') {\n        if (state.type === 'oblig' || state.type === 'opt') { if (typeClass(e.type) !== state.type) return false; }\n        else if (e.type !== state.type) return false;\n      }\n      if (state.day !== 'all' && e.date !== state.day) return false;\n      if (q && !norm(e.subject + ' ' + e.rooms).includes(q)) return false;\n      return true;\n    });\n  }\n\n  function renderResults() {\n    root.querySelectorAll('.view-btn').forEach(b => b.classList.toggle('active', b.dataset.view === state.view));\n    const list = filtered();\n    const total = currentConvo().examenes.length;\n    const nDays = new Set(list.map(e => e.date)).size;\n    $('exCount').innerHTML = list.length === total\n      ? `<strong>${total}<\/strong> ex\u00e1menes en <strong>${nDays}<\/strong> d\u00edas`\n      : `<strong>${list.length}<\/strong> de ${total} ex\u00e1menes \u00b7 ${nDays} ${nDays === 1 ? 'd\u00eda' : 'd\u00edas'}`;\n\n    writeHash();\n\n    const box = $('exContent');\n    if (!list.length) {\n      box.innerHTML = emptyState('Sin ex\u00e1menes para esta selecci\u00f3n', 'Prueba a cambiar el curso, el tipo o el d\u00eda, o pulsa \u00abLimpiar filtros\u00bb.');\n      return;\n    }\n    box.innerHTML = state.view === 'list' ? renderList(list) : renderAgenda(list);\n    box.firstElementChild.classList.add('fade-in');\n  }\n\n  function renderAgenda(list) {\n    const byDay = new Map();\n    list.forEach(e => {\n      if (!byDay.has(e.date)) byDay.set(e.date, new Map());\n      const slots = byDay.get(e.date), k = normTime(e.time);\n      if (!slots.has(k)) slots.set(k, []);\n      slots.get(k).push(e);\n    });\n    const firstUpcoming = [...byDay.keys()].find(d => d >= todayStr);\n\n    let html = '<div class=\"agenda\">';\n    byDay.forEach((slots, date) => {\n      const d = parseISO(date);\n      const cls = date < todayStr ? ' is-past' : date === firstUpcoming ? ' is-next' : '';\n      const flag = date === todayStr ? 'Hoy' : date === firstUpcoming ? 'Pr\u00f3ximo' : '';\n      html += `<section class=\"day${cls}\" aria-label=\"${esc(slots.values().next().value[0].displayDate || date)}\">\n        <div class=\"day-date\">\n          <span class=\"day-dow\">${d ? DOW[d.getDay()] : ''}<\/span>\n          <span class=\"day-num\">${d ? d.getDate() : esc(date)}<\/span>\n          <span class=\"day-mon\">${d ? MON[d.getMonth()] : ''}<\/span>\n          ${flag ? `<span class=\"day-flag\">${flag}<\/span>` : ''}\n        <\/div>\n        <div class=\"day-body\">`;\n      [...slots.keys()].sort().forEach(t => {\n        html += `<div class=\"slot\"><div class=\"slot-time mono\">${esc(slots.get(t)[0].time || t)}<\/div><div class=\"slot-exams\">` +\n          slots.get(t).map(card).join('') + '<\/div><\/div>';\n      });\n      html += '<\/div><\/section>';\n    });\n    return html + '<\/div>';\n  }\n\n  function card(e) {\n    const tc = typeClass(e.type);\n    const rooms = splitRooms(e.rooms);\n    return `<article class=\"exam-card ${tc}\">\n      <div class=\"exam-top\">\n        <span class=\"badge soft\">${esc(e.course)}\u00ba curso<\/span>\n        ${e.type ? `<span class=\"badge type\" title=\"${esc(typeTitle(e.type))}\">${esc(typeLabel(e.type))}<\/span>` : ''}\n      <\/div>\n      <div class=\"exam-subject\">${esc(e.subject)}<\/div>\n      ${rooms.length ? `<div class=\"rooms\" aria-label=\"Aulas\">${rooms.map(roomChip).join('')}<\/div>` : ''}\n    <\/article>`;\n  }\n\n  function renderList(list) {\n    return `<table class=\"list-table\">\n      <thead><tr><th>Fecha<\/th><th>Hora<\/th><th>Curso<\/th><th>Asignatura<\/th><th>Tipo<\/th><th>Aulas<\/th><\/tr><\/thead>\n      <tbody>${list.map(e => {\n        const tc = typeClass(e.type);\n        return `<tr class=\"${tc}${e.date < todayStr ? ' is-past' : ''}\">\n          <td class=\"nowrap\">${esc(e.displayDate || e.date)}<\/td>\n          <td class=\"nowrap mono\">${esc(e.time)}<\/td>\n          <td class=\"nowrap\">${esc(e.course)}\u00ba<\/td>\n          <td class=\"subj\">${esc(e.subject)}<\/td>\n          <td>${e.type ? `<span class=\"badge type ${tc}\" title=\"${esc(typeTitle(e.type))}\">${esc(typeLabel(e.type))}<\/span>` : ''}<\/td>\n          <td>${splitRooms(e.rooms).map(roomInline).join(' \u00b7 ')}<\/td>\n        <\/tr>`;\n      }).join('')}<\/tbody><\/table>`;\n  }\n\n  function roomChip(r) {\n    const id = findRoomId(r);\n    if (!id) return `<span class=\"room\">${ICON_ROOM}${esc(r)}<\/span>`;\n    return `<a class=\"room\" href=\"${MAP_URL}\" data-room-id=\"${id}\" title=\"Ver ${esc(r)} en el mapa interactivo\">${ICON_ROOM}${esc(r)}${ICON_PIN}<\/a>`;\n  }\n  function roomInline(r) {\n    const id = findRoomId(r);\n    if (!id) return esc(r);\n    return `<a class=\"room-link\" href=\"${MAP_URL}\" data-room-id=\"${id}\" title=\"Ver en el mapa interactivo\">${esc(r)}${ICON_PIN}<\/a>`;\n  }\n\n  function emptyState(title, text) {\n    return `<div class=\"empty-state\"><h3>${esc(title)}<\/h3><p>${esc(text)}<\/p><\/div>`;\n  }\n\n  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);\n  else init();\n})();\n<\/script>\n\n","protected":false},"excerpt":{"rendered":"<p>Curso Tipo D\u00eda Asignatura o aula Limpiar filtros Obligatoria Tecnolog\u00eda espec\u00edfica Optativa Calendario Lista Cargando calendario de ex\u00e1menes\u2026<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-22853","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM\" \/>\n<meta property=\"og:description\" content=\"Curso Tipo D\u00eda Asignatura o aula Limpiar filtros Obligatoria Tecnolog\u00eda espec\u00edfica Optativa Calendario Lista Cargando calendario de ex\u00e1menes\u2026\" \/>\n<meta property=\"og:url\" content=\"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/\" \/>\n<meta property=\"og:site_name\" content=\"Escuela Superior de Inform\u00e1tica de UCLM\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/Escuela-Superior-de-Informtica-543261809027158\" \/>\n<meta property=\"article:modified_time\" content=\"2026-09-20T07:27:04+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@esiuclm\" \/>\n<meta name=\"twitter:label1\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minuto\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\\\/\",\"url\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\\\/\",\"name\":\"Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/#website\"},\"datePublished\":\"2026-03-10T15:41:21+00:00\",\"dateModified\":\"2026-09-20T07:27:04+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Portada\",\"item\":\"https:\\\/\\\/esi.uclm.es\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/#website\",\"url\":\"https:\\\/\\\/esi.uclm.es\\\/\",\"name\":\"Escuela Superior de Inform\u00e1tica de UCLM en Ciudad Real, Castilla-La Mancha\",\"description\":\"La Escuela Superior de Inform\u00e1tica de Ciudad Real (Castilla-La Mancha), Universidad de Castilla-La Mancha es un centro universitario que imparte el ciclo completo de Ingenier\u00eda en Inform\u00e1tica: grado, m\u00e1ster y doctorado.\",\"publisher\":{\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/esi.uclm.es\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/#organization\",\"name\":\"Escuela Superior de Inform\u00e1tica de UCLM\",\"url\":\"https:\\\/\\\/esi.uclm.es\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/esi.uclm.es\\\/assets\\\/uploads\\\/2022\\\/03\\\/LogoESI_cabecera-1.png\",\"contentUrl\":\"https:\\\/\\\/esi.uclm.es\\\/assets\\\/uploads\\\/2022\\\/03\\\/LogoESI_cabecera-1.png\",\"width\":460,\"height\":184,\"caption\":\"Escuela Superior de Inform\u00e1tica de UCLM\"},\"image\":{\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/Escuela-Superior-de-Informtica-543261809027158\",\"https:\\\/\\\/x.com\\\/esiuclm\",\"https:\\\/\\\/www.instagram.com\\\/esiuclm\\\/\",\"https:\\\/\\\/www.youtube.com\\\/user\\\/esiuclm\",\"https:\\\/\\\/www.twitch.tv\\\/esiuclm\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/12656631\\\/admin\\\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/","og_locale":"es_ES","og_type":"article","og_title":"Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM","og_description":"Curso Tipo D\u00eda Asignatura o aula Limpiar filtros Obligatoria Tecnolog\u00eda espec\u00edfica Optativa Calendario Lista Cargando calendario de ex\u00e1menes\u2026","og_url":"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/","og_site_name":"Escuela Superior de Inform\u00e1tica de UCLM","article_publisher":"https:\/\/www.facebook.com\/Escuela-Superior-de-Informtica-543261809027158","article_modified_time":"2026-09-20T07:27:04+00:00","twitter_card":"summary_large_image","twitter_site":"@esiuclm","twitter_misc":{"Tiempo de lectura":"1 minuto"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/","url":"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/","name":"Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM","isPartOf":{"@id":"https:\/\/esi.uclm.es\/#website"},"datePublished":"2026-03-10T15:41:21+00:00","dateModified":"2026-09-20T07:27:04+00:00","breadcrumb":{"@id":"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/esi.uclm.es\/index.php\/consulta-de-proxima-convocatoria-de-examenes-grado-ing-informatica\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Portada","item":"https:\/\/esi.uclm.es\/"},{"@type":"ListItem","position":2,"name":"Consulta de pr\u00f3xima convocatoria de ex\u00e1menes &#8211; Grado Ing. Inform\u00e1tica"}]},{"@type":"WebSite","@id":"https:\/\/esi.uclm.es\/#website","url":"https:\/\/esi.uclm.es\/","name":"Escuela Superior de Inform\u00e1tica de UCLM en Ciudad Real, Castilla-La Mancha","description":"La Escuela Superior de Inform\u00e1tica de Ciudad Real (Castilla-La Mancha), Universidad de Castilla-La Mancha es un centro universitario que imparte el ciclo completo de Ingenier\u00eda en Inform\u00e1tica: grado, m\u00e1ster y doctorado.","publisher":{"@id":"https:\/\/esi.uclm.es\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/esi.uclm.es\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/esi.uclm.es\/#organization","name":"Escuela Superior de Inform\u00e1tica de UCLM","url":"https:\/\/esi.uclm.es\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/esi.uclm.es\/#\/schema\/logo\/image\/","url":"https:\/\/esi.uclm.es\/assets\/uploads\/2022\/03\/LogoESI_cabecera-1.png","contentUrl":"https:\/\/esi.uclm.es\/assets\/uploads\/2022\/03\/LogoESI_cabecera-1.png","width":460,"height":184,"caption":"Escuela Superior de Inform\u00e1tica de UCLM"},"image":{"@id":"https:\/\/esi.uclm.es\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/Escuela-Superior-de-Informtica-543261809027158","https:\/\/x.com\/esiuclm","https:\/\/www.instagram.com\/esiuclm\/","https:\/\/www.youtube.com\/user\/esiuclm","https:\/\/www.twitch.tv\/esiuclm","https:\/\/www.linkedin.com\/company\/12656631\/admin\/"]}]}},"_links":{"self":[{"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/pages\/22853","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/comments?post=22853"}],"version-history":[{"count":11,"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/pages\/22853\/revisions"}],"predecessor-version":[{"id":23898,"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/pages\/22853\/revisions\/23898"}],"wp:attachment":[{"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/media?parent=22853"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}