{"id":22820,"date":"2026-03-10T12:24:08","date_gmt":"2026-03-10T12:24:08","guid":{"rendered":"https:\/\/esi.uclm.es\/?page_id=22820"},"modified":"2026-03-13T10:13:40","modified_gmt":"2026-03-13T10:13:40","slug":"consulta-de-horarios-del-grado-en-ingenieria-informatica","status":"publish","type":"page","link":"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-informatica\/","title":{"rendered":"Consulta de Horarios del Grado en Ingenier\u00eda Inform\u00e1tica"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"es\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title font-color=\"white\">Horarios ESI \u2013 UCLM 2025\/26<\/title>\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700&#038;family=JetBrains+Mono:wght@400;500&#038;display=swap\" rel=\"stylesheet\">\n<style>\n  :root {\n    --esi-navy: #045e84;\n    --esi-blue: #0397d8;\n    --esi-light: #659bde;\n    --esi-accent: #e8a838;\n    --bg: #f4f5f7;\n    --card: #ffffff;\n    --text: #1a1a2e;\n    --text-muted: #6b7280;\n    --border: #e2e5ea;\n    --lab-bg: #eef4fb;\n    --lab-border: #b8d4f0;\n    --theory-bg: #ffffff;\n    --theory-border: #d1d5db;\n    --event-bg: #fdf0d5;\n    --event-border: #e8a838;\n    --shadow-sm: 0 1px 3px rgba(0,0,0,.06);\n    --shadow-md: 0 4px 12px rgba(0,0,0,.08);\n    --radius: 8px;\n    --radius-lg: 12px;\n  }\n  * { margin: 0; padding: 0; box-sizing: border-box; }\n  body {\n    font-family: 'DM Sans', sans-serif;\n    background: var(--bg); color: var(--text); line-height: 1.5; min-height: 100vh;\n  }\n  h1.titulo {\n    color: #ffffff !important;  \n    font-size: 1.5rem; \n    font-weight: 700; \n    letter-spacing: -.02em;\n  }\n  .header {\n    background: linear-gradient(135deg, var(--esi-navy), var(--esi-blue));\n    color: white; padding: 1.5rem 2rem;\n    display: flex; align-items: center; gap: 1.5rem; flex-wrap: wrap;\n  }\n  .header-brand { display: flex; flex-direction: column; gap: .15rem; flex-shrink: 0; }\n  .header-brand h1 { font-size: 1.35rem; font-weight: 700; letter-spacing: -.02em; }\n  .header-brand span { font-size: .8rem; opacity: .7; font-weight: 400; }\n  .header-sep { width: 1px; height: 40px; background: rgba(255,255,255,.2); flex-shrink: 0; }\n  .mode-tabs {\n    display: flex; gap: .35rem; background: rgba(0,0,0,.2);\n    border-radius: var(--radius); padding: 3px;\n  }\n  .mode-tab {\n    padding: .5rem 1.1rem; border: none; background: transparent;\n    color: rgba(255,255,255,.7); font-family: inherit; font-size: .85rem;\n    font-weight: 500; border-radius: 6px; cursor: pointer; transition: all .2s;\n  }\n  .mode-tab:hover { color: white; }\n  .mode-tab.active { background: rgba(255,255,255,.18); color: white; }\n  .filters-bar {\n    background: var(--card); border-bottom: 1px solid var(--border);\n    padding: 1rem 2rem; display: flex; align-items: center;\n    gap: 1rem; flex-wrap: wrap; box-shadow: var(--shadow-sm);\n  }\n  .filter-group { display: flex; flex-direction: column; gap: .25rem; }\n  .filter-group label {\n    font-size: .7rem; font-weight: 600; text-transform: uppercase;\n    letter-spacing: .06em; color: var(--text-muted);\n  }\n  .filter-group select {\n    font-family: inherit; font-size: .85rem; padding: .4rem .65rem;\n    border: 1.5px solid var(--border); border-radius: 6px;\n    background: var(--bg); color: var(--text); min-width: 140px; transition: border-color .2s;\n  }\n  .filter-group select:focus { outline: none; border-color: var(--esi-light); }\n  .filter-chip-row { display: flex; gap: .3rem; flex-wrap: wrap; }\n  .filter-chip {\n    padding: .35rem .7rem; font-family: inherit; font-size: .78rem; font-weight: 500;\n    border: 1.5px solid var(--border); border-radius: 20px;\n    background: var(--card); color: var(--text-muted); cursor: pointer;\n    transition: all .15s; white-space: nowrap;\n  }\n  .filter-chip:hover { border-color: var(--esi-light); color: var(--esi-blue); }\n  .filter-chip.active { background: var(--esi-navy); color: white; border-color: var(--esi-navy); }\n  .btn-clear {\n    margin-left: auto; padding: .4rem .9rem; font-family: inherit;\n    font-size: .78rem; font-weight: 500; border: 1.5px solid var(--border);\n    border-radius: 6px; background: var(--card); color: var(--text-muted);\n    cursor: pointer; transition: all .15s;\n  }\n  .btn-clear:hover { border-color: #e74c3c; color: #e74c3c; }\n  .main { padding: 1.5rem 2rem 3rem; max-width: 1440px; margin: 0 auto; }\n  .status-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; flex-wrap: wrap; gap: .5rem; }\n  .status-bar .count { font-size: .85rem; color: var(--text-muted); }\n  .status-bar .count strong { color: var(--text); font-weight: 600; }\n  .legend { display: flex; gap: 1rem; font-size: .75rem; color: var(--text-muted); }\n  .legend-item { display: flex; align-items: center; gap: .35rem; }\n  .legend-dot { width: 10px; height: 10px; border-radius: 3px; border: 1.5px solid; }\n  .legend-dot.theory { background: var(--theory-bg); border-color: var(--theory-border); }\n  .legend-dot.lab { background: var(--lab-bg); border-color: var(--lab-border); }\n  .legend-dot.event { background: var(--event-bg); border-color: var(--event-border); }\n  .timetable {\n    display: grid; grid-template-columns: 80px repeat(5, 1fr);\n    gap: 1px; background: var(--border); border-radius: var(--radius-lg);\n    overflow: hidden; box-shadow: var(--shadow-md);\n  }\n  .tt-header {\n    background: var(--esi-navy); color: white; font-size: .78rem;\n    font-weight: 600; text-align: center; padding: .7rem .3rem; letter-spacing: .03em;\n  }\n  .tt-time {\n    background: var(--esi-navy); color: rgba(255,255,255,.85);\n    font-size: .7rem; font-weight: 500; padding: .5rem .35rem;\n    text-align: center; display: flex; flex-direction: column;\n    justify-content: center; font-family: 'JetBrains Mono', monospace; line-height: 1.4;\n  }\n  .tt-cell {\n    background: var(--card); padding: 0; min-height: 72px;\n    display: flex; flex-direction: column; gap: 2px; overflow: hidden;\n  }\n  .session-card {\n    padding: .4rem .5rem; border-left: 3px solid; font-size: .72rem;\n    line-height: 1.35; flex: 1; display: flex; flex-direction: column; gap: .1rem;\n    transition: transform .1s, box-shadow .15s; cursor: default; position: relative;\n  }\n  .session-card:hover { transform: scale(1.02); box-shadow: var(--shadow-md); z-index: 2; }\n  .session-card.theory { background: var(--theory-bg); border-left-color: var(--esi-blue); }\n  .session-card.lab { background: var(--lab-bg); border-left-color: var(--lab-border); }\n  .session-card.event { background: var(--event-bg); border-left-color: var(--event-border); }\n  .session-subject { font-weight: 700; color: var(--esi-navy); font-size: .76rem; }\n  .session-card.event .session-subject { color: #a67c00; }\n  .session-detail { color: var(--text-muted); font-size: .67rem; }\n  .session-badge {\n    display: inline-block; font-size: .58rem; font-weight: 600;\n    padding: .1rem .35rem; border-radius: 3px; background: var(--esi-navy);\n    color: white; align-self: flex-start; letter-spacing: .03em;\n  }\n  .session-card.lab .session-badge { background: #3a7bd5; }\n\n  .sensor-tags {\n    margin-top: auto;\n    display: flex;\n    flex-wrap: wrap;\n    gap: .25rem;\n    padding-top: .35rem;\n  }\n  .sensor-tag {\n    display: inline-flex;\n    align-items: center;\n    gap: .2rem;\n    font-size: .58rem;\n    line-height: 1;\n    color: #6b7280;\n    background: #f3f4f6;\n    border: 1px solid #d1d5db;\n    border-radius: 999px;\n    padding: .16rem .36rem;\n    white-space: nowrap;\n  }\n  .sensor-tag svg {\n    width: 10px;\n    height: 10px;\n    stroke: currentColor;\n    fill: none;\n    stroke-width: 1.8;\n  }\n  .room-sensor-summary {\n    background: var(--card);\n    border: 1px solid var(--border);\n    border-radius: var(--radius-lg);\n    box-shadow: var(--shadow-sm);\n    padding: 1rem 1.1rem;\n    margin-bottom: 1rem;\n  }\n  .room-sensor-title {\n    display: flex;\n    align-items: center;\n    gap: .75rem;\n    flex-wrap: wrap;\n    margin-bottom: .55rem;\n  }\n  .room-sensor-title h2 {\n    font-size: 1rem;\n    font-weight: 700;\n    color: var(--esi-navy);\n  }\n  .room-sensor-summary .sensor-tags {\n    padding-top: 0;\n    gap: .4rem;\n  }\n  .room-sensor-summary .sensor-tag {\n    font-size: .72rem;\n    padding: .28rem .55rem;\n  }\n  .list-table {\n    width: 100%; border-collapse: collapse; background: var(--card);\n    border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-md);\n  }\n  .list-table th {\n    background: var(--esi-navy); color: white; font-size: .75rem;\n    font-weight: 600; padding: .65rem .7rem; text-align: left;\n    letter-spacing: .03em; position: sticky; top: 0; z-index: 3;\n  }\n  .list-table td {\n    font-size: .8rem; padding: .55rem .7rem;\n    border-bottom: 1px solid var(--border); vertical-align: top;\n  }\n  .list-table tr:last-child td { border-bottom: none; }\n  .list-table tr:hover td { background: #f8f9fb; }\n  .empty-state { text-align: center; padding: 4rem 2rem; color: var(--text-muted); }\n  .empty-state svg { width: 64px; height: 64px; margin-bottom: 1rem; opacity: .3; }\n  .empty-state h3 { font-size: 1.1rem; font-weight: 600; margin-bottom: .4rem; color: var(--text); }\n  .view-toggle {\n    display: flex; gap: .25rem; background: var(--bg);\n    border-radius: 6px; padding: 2px; border: 1.5px solid var(--border);\n  }\n  .view-btn {\n    padding: .3rem .6rem; border: none; background: transparent;\n    font-family: inherit; font-size: .75rem; font-weight: 500;\n    color: var(--text-muted); border-radius: 4px; cursor: pointer; transition: all .15s;\n  }\n  .view-btn.active { background: var(--card); color: var(--text); box-shadow: var(--shadow-sm); }\n  @media (max-width: 900px) {\n    .header { padding: 1rem; }\n    .filters-bar { padding: .8rem 1rem; }\n    .main { padding: 1rem; }\n    .timetable { grid-template-columns: 60px repeat(5, 1fr); font-size: .65rem; }\n    .session-card { padding: .3rem; }\n    .session-subject { font-size: .68rem; }\n    .filter-group select { min-width: 110px; }\n  }\n  @media (max-width: 640px) {\n    .timetable { overflow-x: auto; min-width: 700px; }\n    .main { overflow-x: auto; }\n  }\n  @keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }\n  .fade-in { animation: fadeIn .3s ease-out; }\n<\/style>\n<\/head>\n<body>\n<div class=\"header\">\n  <div class=\"header-brand\">\n    <img decoding=\"async\" src=\"https:\/\/esi.uclm.es\/assets\/uploads\/2022\/03\/LogoESI_cabecera-1-1.png\" alt=\"Logo ESI\" style=\"width:50%; filter:brightness(0) invert(1);\">\n    <h1 class=\"titulo\">Horarios ESI<\/h1>\n    <span>Grado Ing. Inform\u00e1tica \u00b7 UCLM 2025\/26 \u00b7 2\u00ba Cuatrimestre<\/span>\n  <\/div>\n  <div class=\"header-sep\"><\/div>\n  <div class=\"mode-tabs\">\n    <button class=\"mode-tab active\" data-mode=\"student\" onclick=\"setMode('student')\">Estudiante<\/button>\n    <!--<button class=\"mode-tab\" data-mode=\"professor\" onclick=\"setMode('professor')\">Profesor<\/button>-->\n    <button class=\"mode-tab\" data-mode=\"room\" onclick=\"setMode('room')\">Aula<\/button>\n  <\/div>\n<\/div>\n<div class=\"filters-bar\" id=\"filtersBar\"><\/div>\n<div class=\"main\">\n  <div class=\"status-bar\">\n    <div class=\"count\" id=\"statusCount\"><\/div>\n    <div style=\"display:flex; gap:1rem; align-items:center;\">\n      <div class=\"legend\">\n        <div class=\"legend-item\"><div class=\"legend-dot theory\"><\/div>Teor\u00eda<\/div>\n        <div class=\"legend-item\"><div class=\"legend-dot lab\"><\/div>Laboratorio<\/div>\n        <div class=\"legend-item\"><div class=\"legend-dot event\"><\/div>Evento<\/div>\n      <\/div>\n      <div class=\"view-toggle\">\n        <button class=\"view-btn active\" onclick=\"setView('grid')\">Cuadr\u00edcula<\/button>\n        <button class=\"view-btn\" onclick=\"setView('list')\">Lista<\/button>\n      <\/div>\n    <\/div>\n  <\/div>\n  <div id=\"content\"><\/div>\n<\/div>\n<script>\n\/\/ ---- STATE ----\nlet allSessions = [];\nlet currentMode = 'student';\nlet currentView = 'grid';\nlet filters = { grupo: null, dia: null, profesor: '', aula: null };\n\nlet sensorData = {};\nlet dbError = null;\n\nconst SENSORS_JSON_URL = 'https:\/\/federico.esi.uclm.es\/www\/jalbusac\/smartesi\/sensores.json';\nconst ENTITY_TO_AULA = {\n  'sensor.temperatura_shelly1': 'F0.1',\n  'sensor.humedad_shelly1': 'F0.1',\n  'sensor.temperatura_shelly4': 'F0.2',\n  'sensor.humedad_shelly4': 'F0.2',\n  'sensor.temperatura_shelly5': 'F1.1',\n  'sensor.humedad_shelly5': 'F1.1',\n  'air_quality.co2_3': 'A1.1',\n  'air_quality.co2_1': 'A1.2',\n  'air_quality.co2_2': 'A2.1',\n  'air_quality.co2_4': 'A2.2',\n  'sensor.temperatura_shelly14': 'LD1',\n  'sensor.humedad_shelly14': 'LD1',\n  'sensor.temperatura_shelly13': 'LD2',\n  'sensor.humedad_shelly13': 'LD2',\n  'sensor.temperatura_shelly2': 'LD3',\n  'sensor.humedad_shelly2': 'LD3',\n  'sensor.temperatura_shelly3': 'LD4',\n  'sensor.humedad_shelly3': 'LD4'\n};\n\nfunction extractRoomCode(entityId, attributes) {\n  if (ENTITY_TO_AULA[entityId]) return ENTITY_TO_AULA[entityId];\n  const friendlyName = String((attributes && attributes.friendly_name) || '').trim();\n  const m = friendlyName.match(\/\\b([A-Z]+\\d+(?:\\.\\d+)?)\\b\/u);\n  return m ? m[1].toUpperCase() : null;\n}\n\nfunction buildSensorData(payload) {\n  const rows = Array.isArray(payload?.sensors) ? payload.sensors : (Array.isArray(payload) ? payload : []);\n  const result = {};\n\n  rows.forEach((row) => {\n    if (!row || typeof row !== 'object') return;\n    const entityId = String(row.entity_id || '').trim();\n    if (!entityId) return;\n\n    let attributes = row.attributes || {};\n    if (typeof attributes === 'string') {\n      try { attributes = JSON.parse(attributes); } catch (_) { attributes = {}; }\n    }\n    if (!attributes || typeof attributes !== 'object') attributes = {};\n\n    const roomCode = extractRoomCode(entityId, attributes);\n    if (!roomCode) return;\n\n    if (!result[roomCode]) {\n      result[roomCode] = { temperatura: null, humedad: null, co2: null };\n    }\n\n    const state = Number(row.state);\n    const stateValue = Number.isFinite(state) ? state : null;\n\n    if (entityId.startsWith('air_quality.')) {\n      const t = Number(attributes.Temperature);\n      const h = Number(attributes.Humidity);\n      const c = Number(attributes.CO2);\n      if (Number.isFinite(t)) result[roomCode].temperatura = t;\n      if (Number.isFinite(h)) result[roomCode].humedad = h;\n      if (Number.isFinite(c)) result[roomCode].co2 = c;\n      else if (stateValue !== null) result[roomCode].co2 = stateValue;\n      return;\n    }\n\n    if (entityId.startsWith('sensor.temperatura_') && stateValue !== null) {\n      result[roomCode].temperatura = stateValue;\n    } else if (entityId.startsWith('sensor.humedad_') && stateValue !== null) {\n      result[roomCode].humedad = stateValue;\n    }\n  });\n\n  return result;\n}\n\nasync function loadSensorData() {\n  try {\n    const response = await fetch(SENSORS_JSON_URL, { cache: 'no-store' });\n    if (!response.ok) throw new Error('HTTP ' + response.status);\n    const payload = await response.json();\n    sensorData = buildSensorData(payload);\n    dbError = null;\n  } catch (err) {\n    sensorData = {};\n    dbError = (err && err.message) ? err.message : 'No se pudieron cargar los sensores';\n  }\n}\n\nconst SENSOR_ICONS = {\n  temperatura: '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M14 14.76V5a2 2 0 1 0-4 0v9.76a4 4 0 1 0 4 0Z\"><\/path><\/svg>',\n  humedad: '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M12 3s6 6.1 6 10a6 6 0 1 1-12 0c0-3.9 6-10 6-10Z\"><\/path><\/svg>',\n  co2: '<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M4 15c1.2-2.8 3.8-4.5 6.8-4.5 2 0 3.7.7 5.1 2.1\"><\/path><path d=\"M14 8h6\"><\/path><path d=\"M17 5v6\"><\/path><path d=\"M6 19h12\"><\/path><\/svg>'\n};\n\nconst DAYS = ['Lunes','Martes','Mi\u00e9rcoles','Jueves','Viernes'];\nconst TIME_SLOTS = [\n  '8:30-10:00','10:00-11:30','11:30-13:00','13:00-14:30',\n  '15:30-16:50','17:00-18:30','18:30-20:00','20:00-21:30'\n];\n\n\/\/ ---- LOAD DATA ----\nconst DATA_PATH = '\/TV\/hall\/horarios.json';\nfunction loadData() {\n  if (window.location.protocol === 'file:') {\n    try {\n      const xhr = new XMLHttpRequest();\n      xhr.open('GET', DATA_PATH, false);\n      xhr.send();\n      if (xhr.status === 0 || xhr.status === 200) {\n        allSessions = JSON.parse(xhr.responseText);\n        normalizeData();\n        setMode('student');\n        return Promise.resolve();\n      }\n    } catch(e) {}\n    document.getElementById('content').innerHTML = '<div class=\"empty-state\"><h3>Acceso bloqueado<\/h3><p>Abre con un servidor local: <code>python3 -m http.server 8000<\/code><\/p><\/div>';\n    return Promise.reject(new Error('Acceso bloqueado'));\n  }\n  return fetch(DATA_PATH)\n    .then(r => { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })\n    .then(data => { allSessions = data; normalizeData(); setMode('student'); })\n    .catch(err => {\n      document.getElementById('content').innerHTML =\n        '<div class=\"empty-state\"><h3>Error al cargar<\/h3><p>' + err.message + '. Aseg\u00farate de que <code>horarios.json<\/code> est\u00e1 junto a este HTML.<\/p><\/div>';\n      throw err;\n    });\n}\n\n\/\/ ---- NORMALIZE TRUNCATED NAMES ----\nfunction normalizeData() {\n  function buildMap(values) {\n    const unique = [...new Set(values)].filter(Boolean);\n    const sorted = [...unique].sort((a,b) => b.length - a.length);\n    const canon = {};\n    unique.forEach(v => canon[v] = v);\n    for (let pass = 0; pass < 3; pass++) {\n      for (const short of unique) {\n        const longer = sorted.filter(l => l !== short && l.startsWith(short));\n        if (longer.length === 1) {\n          canon[short] = canon[longer[0]];\n        } else if (longer.length > 1) {\n          const targets = new Set(longer.map(l => canon[l]));\n          if (targets.size === 1) canon[short] = [...targets][0];\n        }\n      }\n    }\n    return canon;\n  }\n  const pm = buildMap(allSessions.map(s => s.profesor));\n  const rm = buildMap(allSessions.map(s => s.aula));\n  allSessions.forEach(s => {\n    if (s.profesor && pm[s.profesor]) s.profesor = pm[s.profesor];\n    if (s.aula && rm[s.aula]) s.aula = rm[s.aula];\n  });\n}\n\nPromise.all([loadData(), loadSensorData()]).then(() => {\n  render();\n});\n\n\/\/ ---- HELPERS ----\nfunction unique(key) {\n  const v = new Set(); allSessions.forEach(s => { if (s[key]) v.add(s[key]); });\n  return [...v].sort((a,b) => a.localeCompare(b,'es'));\n}\nfunction uniqueProfs() {\n  const p = new Set(); allSessions.forEach(s => { if (s.profesor && s.tipo!=='evento') p.add(s.profesor); });\n  return [...p].sort((a,b) => a.localeCompare(b,'es'));\n}\nfunction uniqueRooms() {\n  const r = new Set(); allSessions.forEach(s => { if (s.aula && s.tipo!=='evento') r.add(s.aula); });\n  return [...r].sort((a,b) => a.localeCompare(b,'es'));\n}\n\nfunction setMode(mode) {\n  currentMode = mode;\n  document.querySelectorAll('.mode-tab').forEach(t => t.classList.toggle('active', t.dataset.mode === mode));\n  filters = { grupo: null, dia: null, profesor: '', aula: null };\n  buildFilters(); render();\n}\nfunction setView(v) {\n  currentView = v;\n  document.querySelectorAll('.view-btn').forEach(b => b.classList.toggle('active', b.textContent.trim() === (v==='grid'?'Cuadr\u00edcula':'Lista')));\n  render();\n}\n\nfunction buildFilters() {\n  const bar = document.getElementById('filtersBar');\n  bar.innerHTML = '';\n  if (currentMode === 'student') {\n    const fg = mkEl('div','filter-group'); fg.appendChild(mkLabel('Grupo'));\n    const sel = document.createElement('select');\n    sel.innerHTML = '<option value=\"\">Todos los grupos<\/option>';\n    unique('grupo').forEach(g => { const o = document.createElement('option'); o.value=g; o.textContent=g; if(filters.grupo===g) o.selected=true; sel.appendChild(o); });\n    sel.onchange = () => { filters.grupo = sel.value||null; render(); };\n    fg.appendChild(sel); bar.appendChild(fg);\n    bar.appendChild(buildDayFilter());\n  } else if (currentMode === 'professor') {\n    const fg = mkEl('div','filter-group'); fg.appendChild(mkLabel('Profesor'));\n    const sel = document.createElement('select');\n    sel.innerHTML = '<option value=\"\">Selecciona un profesor<\/option>';\n    uniqueProfs().forEach(p => { const o = document.createElement('option'); o.value=p; o.textContent=p; if(filters.profesor===p) o.selected=true; sel.appendChild(o); });\n    sel.onchange = () => { filters.profesor = sel.value||''; render(); };\n    fg.appendChild(sel); bar.appendChild(fg);\n    bar.appendChild(buildDayFilter());\n  } else if (currentMode === 'room') {\n    const fg = mkEl('div','filter-group'); fg.appendChild(mkLabel('Aula'));\n    const sel = document.createElement('select');\n    sel.innerHTML = '<option value=\"\">Selecciona un aula<\/option>';\n    uniqueRooms().forEach(r => { const o = document.createElement('option'); o.value=r; o.textContent=r; if(filters.aula===r) o.selected=true; sel.appendChild(o); });\n    sel.onchange = () => { filters.aula = sel.value||null; render(); };\n    fg.appendChild(sel); bar.appendChild(fg);\n    bar.appendChild(buildDayFilter());\n    const fg2 = mkEl('div','filter-group'); fg2.appendChild(mkLabel('Grupo'));\n    const sel2 = document.createElement('select');\n    sel2.innerHTML = '<option value=\"\">Todos<\/option>';\n    unique('grupo').forEach(g => { const o = document.createElement('option'); o.value=g; o.textContent=g; sel2.appendChild(o); });\n    sel2.onchange = () => { filters.grupo = sel2.value||null; render(); };\n    fg2.appendChild(sel2); bar.appendChild(fg2);\n  }\n  const btn = mkEl('button','btn-clear'); btn.textContent = 'Limpiar filtros';\n  btn.onclick = () => { filters = {grupo:null,dia:null,profesor:'',aula:null}; buildFilters(); render(); };\n  bar.appendChild(btn);\n  updateChips();\n}\n\nfunction buildDayFilter() {\n  const fg = mkEl('div','filter-group'); fg.appendChild(mkLabel('D\u00eda'));\n  const row = mkEl('div','filter-chip-row');\n  DAYS.forEach(d => {\n    const c = mkEl('button','filter-chip'); c.textContent=d; c.dataset.day=d;\n    c.onclick = () => { filters.dia = filters.dia===d?null:d; updateChips(); render(); };\n    row.appendChild(c);\n  });\n  fg.appendChild(row); return fg;\n}\nfunction updateChips() {\n  document.querySelectorAll('.filter-chip').forEach(c => {\n    const d = c.dataset.day; if(d) c.classList.toggle('active', filters.dia===d);\n  });\n}\n\nfunction getFiltered() {\n  return allSessions.filter(s => {\n    if (filters.grupo && s.grupo !== filters.grupo) return false;\n    if (filters.dia && s.dia !== filters.dia) return false;\n    if (filters.aula && s.aula !== filters.aula) return false;\n    if (filters.profesor && s.profesor !== filters.profesor) return false;\n    return true;\n  });\n}\n\n\nfunction findSensorForRoom(roomName) {\n  if (!roomName) return null;\n  const normalizedRoom = String(roomName).toLowerCase();\n  for (const [code, values] of Object.entries(sensorData || {})) {\n    if (normalizedRoom.includes(String(code).toLowerCase())) {\n      return { code, values };\n    }\n  }\n  return null;\n}\n\nfunction formatSensorValue(type, value) {\n  if (value === null || value === undefined || value === '') return null;\n  const num = Number(value);\n  if (Number.isNaN(num)) return null;\n  if (type === 'temperatura') return num.toFixed(1) + '\u00b0C';\n  if (type === 'humedad') return num.toFixed(1) + '%';\n  if (type === 'co2') return Math.round(num) + ' ppm';\n  return String(value);\n}\n\nfunction sensorTagsHTML(sensorValues) {\n  if (!sensorValues) return '';\n  const ordered = [\n    ['temperatura', 'Temperatura'],\n    ['humedad', 'Humedad'],\n    ['co2', 'CO\u2082']\n  ];\n  const tags = ordered\n    .map(([key, label]) => {\n      const formatted = formatSensorValue(key, sensorValues[key]);\n      if (!formatted) return '';\n      return '<span class=\"sensor-tag\">' + SENSOR_ICONS[key] + '<span>' + label + ': ' + formatted + '<\/span><\/span>';\n    })\n    .filter(Boolean)\n    .join('');\n  return tags ? '<div class=\"sensor-tags\">' + tags + '<\/div>' : '';\n}\n\nfunction roomSummaryHTML(roomName) {\n  const match = findSensorForRoom(roomName);\n  if (!match) return '';\n  const tags = sensorTagsHTML(match.values);\n  if (!tags) return '';\n  return '<div class=\"room-sensor-summary fade-in\"><div class=\"room-sensor-title\"><h2>'+esc(roomName)+'<\/h2><\/div>' + tags + '<\/div>';\n}\n\nfunction render() {\n  const sessions = getFiltered();\n  const noEv = sessions.filter(s => s.tipo!=='evento');\n  let statusHtml =\n    '<strong>'+noEv.length+'<\/strong> sesiones' +\n    (filters.grupo?' \u00b7 Grupo <strong>'+filters.grupo+'<\/strong>':'') +\n    (filters.dia?' \u00b7 <strong>'+filters.dia+'<\/strong>':'') +\n    (filters.profesor?' \u00b7 <strong>'+filters.profesor+'<\/strong>':'') +\n    (filters.aula?' \u00b7 <strong>'+esc(filters.aula)+'<\/strong>':'');\n  if (dbError) {\n    statusHtml += ' \u00b7 <strong style=\"color:#b91c1c\">Sensores no disponibles<\/strong>';\n  }\n  document.getElementById('statusCount').innerHTML = statusHtml;\n  if (!sessions.length) {\n    document.getElementById('content').innerHTML = '<div class=\"empty-state fade-in\"><h3>Sin resultados<\/h3><p>No hay sesiones para los filtros seleccionados.<\/p><\/div>';\n    return;\n  }\n  currentView==='grid' ? renderGrid(sessions) : renderList(sessions);\n}\n\nfunction renderGrid(sessions) {\n  const grid = {};\n  TIME_SLOTS.forEach(ts => { grid[ts]={}; DAYS.forEach(d => grid[ts][d]=[]); });\n  sessions.forEach(s => { const k=s.hora_inicio+'-'+s.hora_fin; if(grid[k]&&grid[k][s.dia]) grid[k][s.dia].push(s); });\n  let h = '';\n  if (currentMode === 'room' && filters.aula) {\n    h += roomSummaryHTML(filters.aula);\n  }\n  h += '<div class=\"timetable fade-in\"><div class=\"tt-header\"><\/div>';\n  DAYS.forEach(d => { h+='<div class=\"tt-header\"'+(filters.dia===d?' style=\"background:var(--esi-light)\"':'')+'>'+d+'<\/div>'; });\n  TIME_SLOTS.forEach(ts => {\n    const [s,e] = ts.split('-');\n    h += '<div class=\"tt-time\">'+s+'<br>'+e+'<\/div>';\n    DAYS.forEach(d => {\n      h += '<div class=\"tt-cell\">';\n      const items = grid[ts][d];\n      if(!items.length) h+='&nbsp;'; else items.forEach(s => h+=cardHTML(s));\n      h += '<\/div>';\n    });\n  });\n  h += '<\/div>';\n  document.getElementById('content').innerHTML = h;\n}\n\nfunction renderList(sessions) {\n  const dayOrd = Object.fromEntries(DAYS.map((d,i)=>[d,i]));\n  const sorted = [...sessions].filter(s=>s.tipo!=='evento').sort((a,b) => (dayOrd[a.dia]??9)-(dayOrd[b.dia]??9) || a.hora_inicio.localeCompare(b.hora_inicio));\n  let h = '<div class=\"fade-in\" style=\"overflow-x:auto\"><table class=\"list-table\"><thead><tr><th>D\u00eda<\/th><th>Hora<\/th><th>Asignatura<\/th><th>Tipo<\/th><th>Grupo<\/th><th>Aula<\/th><th>Profesor<\/th><th>Pr\u00e1cticas<\/th><\/tr><\/thead><tbody>';\n  sorted.forEach(s => {\n    const tc = s.tipo==='laboratorio'?'lab':s.tipo==='evento'?'event':'theory';\n    const bg = tc==='lab'?'#3a7bd5':tc==='event'?'#a67c00':'var(--esi-navy)';\n    h += '<tr><td>'+s.dia+'<\/td><td style=\"font-family:\\'JetBrains Mono\\',monospace;font-size:.78rem\">'+s.hora_inicio+'\u2013'+s.hora_fin+'<\/td><td><strong>'+esc(s.asignatura)+'<\/strong><\/td><td class=\"badge-cell\"><span class=\"session-badge\" style=\"background:'+bg+'\">'+s.tipo+'<\/span><\/td><td>'+esc(s.grupo)+'<\/td><td style=\"font-size:.75rem\">'+esc(s.aula)+'<\/td><td>'+esc(s.profesor)+'<\/td><td>'+esc(s.grupo_practicas)+'<\/td><\/tr>';\n  });\n  h += '<\/tbody><\/table><\/div>';\n  document.getElementById('content').innerHTML = h;\n}\n\nfunction cardHTML(s) {\n  const tc = s.tipo==='laboratorio'?'lab':s.tipo==='evento'?'event':'theory';\n  let d = ''; if(s.aula) d+='<div class=\"session-detail\">'+esc(s.aula)+'<\/div>';\n  if(s.profesor) d+='<div class=\"session-detail\">'+esc(s.profesor)+'<\/div>';\n  let b = '';\n  if(s.grupo_practicas) b='<span class=\"session-badge\">'+esc(s.grupo_practicas)+'<\/span>';\n  else if(currentMode!=='student'&&s.grupo) b='<span class=\"session-badge\">'+esc(s.grupo)+'<\/span>';\n  const sensorMatch = (currentMode !== 'room' && s.aula) ? findSensorForRoom(s.aula) : null;\n  const sensors = sensorMatch ? sensorTagsHTML(sensorMatch.values) : '';\n  return '<div class=\"session-card '+tc+'\"><div class=\"session-subject\">'+esc(s.asignatura)+'<\/div>'+d+b+sensors+'<\/div>';\n}\n\nfunction mkEl(t,c){const e=document.createElement(t);if(c)e.className=c;return e;}\nfunction mkLabel(t){const l=document.createElement('label');l.textContent=t;return l;}\nfunction esc(s){return s?s.replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;'):'';} \n<\/script>\n<\/body>\n<\/html>\n","protected":false},"excerpt":{"rendered":"<p>Horarios ESI \u2013 UCLM 2025\/26 Horarios ESI Grado Ing. Inform\u00e1tica \u00b7 UCLM 2025\/26 \u00b7 2\u00ba Cuatrimestre Estudiante Aula Teor\u00eda Laboratorio Evento Cuadr\u00edcula Lista<\/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-22820","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Consulta de Horarios del Grado en Ingenier\u00eda 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-horarios-del-grado-en-ingenieria-informatica\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Consulta de Horarios del Grado en Ingenier\u00eda Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM\" \/>\n<meta property=\"og:description\" content=\"Horarios ESI \u2013 UCLM 2025\/26 Horarios ESI Grado Ing. Inform\u00e1tica \u00b7 UCLM 2025\/26 \u00b7 2\u00ba Cuatrimestre Estudiante Aula Teor\u00eda Laboratorio Evento Cuadr\u00edcula Lista\" \/>\n<meta property=\"og:url\" content=\"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-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-03-13T10:13:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/esi.uclm.es\/assets\/uploads\/2022\/03\/LogoESI_cabecera-1-1.png\" \/>\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-horarios-del-grado-en-ingenieria-informatica\\\/\",\"url\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-horarios-del-grado-en-ingenieria-informatica\\\/\",\"name\":\"Consulta de Horarios del Grado en Ingenier\u00eda Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-horarios-del-grado-en-ingenieria-informatica\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-horarios-del-grado-en-ingenieria-informatica\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/esi.uclm.es\\\/assets\\\/uploads\\\/2022\\\/03\\\/LogoESI_cabecera-1-1.png\",\"datePublished\":\"2026-03-10T12:24:08+00:00\",\"dateModified\":\"2026-03-13T10:13:40+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-horarios-del-grado-en-ingenieria-informatica\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-horarios-del-grado-en-ingenieria-informatica\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-horarios-del-grado-en-ingenieria-informatica\\\/#primaryimage\",\"url\":\"https:\\\/\\\/esi.uclm.es\\\/assets\\\/uploads\\\/2022\\\/03\\\/LogoESI_cabecera-1-1.png\",\"contentUrl\":\"https:\\\/\\\/esi.uclm.es\\\/assets\\\/uploads\\\/2022\\\/03\\\/LogoESI_cabecera-1-1.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/esi.uclm.es\\\/index.php\\\/consulta-de-horarios-del-grado-en-ingenieria-informatica\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Portada\",\"item\":\"https:\\\/\\\/esi.uclm.es\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Consulta de Horarios del Grado en Ingenier\u00eda 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 Horarios del Grado en Ingenier\u00eda 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-horarios-del-grado-en-ingenieria-informatica\/","og_locale":"es_ES","og_type":"article","og_title":"Consulta de Horarios del Grado en Ingenier\u00eda Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM","og_description":"Horarios ESI \u2013 UCLM 2025\/26 Horarios ESI Grado Ing. Inform\u00e1tica \u00b7 UCLM 2025\/26 \u00b7 2\u00ba Cuatrimestre Estudiante Aula Teor\u00eda Laboratorio Evento Cuadr\u00edcula Lista","og_url":"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-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-03-13T10:13:40+00:00","og_image":[{"url":"https:\/\/esi.uclm.es\/assets\/uploads\/2022\/03\/LogoESI_cabecera-1-1.png","type":"","width":"","height":""}],"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-horarios-del-grado-en-ingenieria-informatica\/","url":"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-informatica\/","name":"Consulta de Horarios del Grado en Ingenier\u00eda Inform\u00e1tica - Escuela Superior de Inform\u00e1tica de UCLM","isPartOf":{"@id":"https:\/\/esi.uclm.es\/#website"},"primaryImageOfPage":{"@id":"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-informatica\/#primaryimage"},"image":{"@id":"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-informatica\/#primaryimage"},"thumbnailUrl":"https:\/\/esi.uclm.es\/assets\/uploads\/2022\/03\/LogoESI_cabecera-1-1.png","datePublished":"2026-03-10T12:24:08+00:00","dateModified":"2026-03-13T10:13:40+00:00","breadcrumb":{"@id":"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-informatica\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-informatica\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-informatica\/#primaryimage","url":"https:\/\/esi.uclm.es\/assets\/uploads\/2022\/03\/LogoESI_cabecera-1-1.png","contentUrl":"https:\/\/esi.uclm.es\/assets\/uploads\/2022\/03\/LogoESI_cabecera-1-1.png"},{"@type":"BreadcrumbList","@id":"https:\/\/esi.uclm.es\/index.php\/consulta-de-horarios-del-grado-en-ingenieria-informatica\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Portada","item":"https:\/\/esi.uclm.es\/"},{"@type":"ListItem","position":2,"name":"Consulta de Horarios del Grado en Ingenier\u00eda 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\/22820","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=22820"}],"version-history":[{"count":13,"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/pages\/22820\/revisions"}],"predecessor-version":[{"id":22884,"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/pages\/22820\/revisions\/22884"}],"wp:attachment":[{"href":"https:\/\/esi.uclm.es\/index.php\/wp-json\/wp\/v2\/media?parent=22820"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}