{"id":640,"date":"2026-03-03T06:27:58","date_gmt":"2026-03-03T05:27:58","guid":{"rendered":"https:\/\/highered-change.org\/?page_id=640"},"modified":"2026-04-07T13:12:17","modified_gmt":"2026-04-07T11:12:17","slug":"inventory-he-academic-programs","status":"publish","type":"page","link":"https:\/\/highered-change.org\/index.php\/inventory-he-academic-programs\/","title":{"rendered":"Inventory HE academic programs"},"content":{"rendered":"\n<!-- === GOHEC Centers: ONE unified embed block (NO iframes) === -->\n\n<style>\n  \/* Base Styles *\/\n  * {\n    margin: 0;\n    padding: 0;\n    box-sizing: border-box;\n    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n  }\n\n  .itBody {\n    color: #001e2c;\n    line-height: 1.6;\n    box-sizing: border-box;\n    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n  }\n\n  .container {\n    max-width: 1200px;\n    margin: 0 auto;\n    padding: 0 20px;\n  }\n\n  .site-header {\n    background-color: #001e2c;\n    color: white;\n    padding: 30px 0;\n    border-bottom: 4px solid #ec7c34;\n  }\n\n  .site-title {\n    font-size: 2.5rem;\n    text-align: center;\n    margin-bottom: 10px;\n  }\n\n  .site-description {\n    text-align: center;\n    opacity: 0.9;\n    max-width: 800px;\n    margin: 0 auto;\n  }\n\n  .tabs-container {\n    display: flex;\n    justify-content: center;\n    padding-bottom: 20px;\n  }\n\n  .tab-button {\n    padding: 12px 24px;\n    background-color: #4e7bc7;\n    color: white;\n    border: none;\n    margin: 0 10px;\n    cursor: pointer;\n    font-weight: bold;\n    border-radius: 5px;\n    transition: all 0.3s ease;\n  }\n\n  .tab-button.active {\n    background-color: #ec7c34;\n    transform: translateY(-5px);\n  }\n\n  .tab-button:hover {\n    opacity: 0.9;\n  }\n\n  .content-area {\n    padding: 40px 0;\n  }\n\n  .panel-content {\n    display: none;\n    margin: 0 14px;\n  }\n\n  .panel-content.active {\n    display: block;\n  }\n\n  .section-heading {\n    color: #4e7bc7;\n    margin-bottom: 20px;\n    border-bottom: 2px solid #ec7c34;\n    padding-bottom: 10px;\n    font-size: 2rem;\n  }\n\n  .content-paragraph {\n    margin-bottom: 20px;\n  }\n\n  .content-link {\n    color: #4e7bc7;\n    text-decoration: none;\n  }\n\n  .content-link:hover {\n    text-decoration: underline;\n    color: #ec7c34;\n  }\n\n  .map-container,\n  .table-container {\n    background-color: white;\n    padding: 20px;\n    border-radius: 8px;\n    box-shadow: 0 4px 12px rgba(0,0,0,0.1);\n    margin-bottom: 30px;\n  }\n\n  .map-iframe {\n    width: 100%;\n    height: 600px;\n    border: 2px solid white;\n    border-radius: 5px;\n  }\n\n  .table-iframe {\n    width: 100%;\n    border: none;\n  }\n\n  .cta-section {\n    background-color: #4e7bc7;\n    padding: 30px;\n    border-radius: 8px;\n    margin-top: 40px;\n    color: white;\n    text-align: center;\n  }\n\n  .cta-heading {\n    margin-bottom: 15px;\n    color: white;\n  }\n\n  .cta-button {\n    display: inline-block;\n    background-color: #ec7c34;\n    text-decoration: none;\n    color: white;\n    padding: 12px 24px;\n    border-radius: 5px;\n    font-weight: bold;\n    margin-top: 15px;\n    transition: all 0.3s ease;\n  }\n\n  .cta-button:hover {\n    transform: translateY(-3px);\n    box-shadow: 0 4px 12px rgba(0,0,0,0.2);\n    text-decoration: none;\n    color: white;\n  }\n\n  .text-highlight {\n    color: #ec7c34;\n    font-weight: bold;\n  }\n\n  .itBody p {\n    margin: 10px 0;\n  }\n\n  p a:where(:not(.wp-element-button)) {\n    color: blue;\n    font-weight: 500;\n  }\n\n  \/* DataTables cosmetics *\/\n  table.dataTable thead {\n    background-color: #4193cf;\n    color: white;\n  }\n\n  table.dataTable tbody tr:nth-child(even) {\n    background-color: #f2f2f2;\n  }\n\n  table.dataTable tbody tr:hover {\n    background-color: #ddd;\n  }\n\n  table.dataTable {\n    border-collapse: collapse;\n    width: 100%;\n  }\n\n  table.dataTable th,\n  table.dataTable td {\n    padding: 8px 12px;\n    text-align: left;\n    border: 1px solid #ddd;\n  }\n\n  .dataTables_length,\n  .dataTables_filter {\n    margin-bottom: 15px;\n  }\n\n  \/* Column filter inputs *\/\n  #he-centers-table thead tr:nth-child(2) th input {\n    width: 100%;\n    box-sizing: border-box;\n    padding: 4px;\n    border: 1px solid #ccc;\n    min-width: 140px;\n  }\n\n  \/* Table header + clear button *\/\n  .table-header-row {\n    display: flex;\n    align-items: center;\n    justify-content: space-between;\n    gap: 12px;\n    margin-bottom: 12px;\n    flex-wrap: wrap;\n  }\n\n  .clear-filters-btn {\n    display: none;\n    background-color: #ec7c34;\n    color: white;\n    border: none;\n    border-radius: 5px;\n    padding: 10px 14px;\n    font-weight: 600;\n    cursor: pointer;\n    transition: opacity 0.2s ease, transform 0.2s ease;\n  }\n\n  .clear-filters-btn.is-visible {\n    display: inline-block;\n  }\n\n  .clear-filters-btn:hover {\n    opacity: 0.92;\n    transform: translateY(-1px);\n  }\n\n  \/* Mobile-friendly table wrapper *\/\n  .table-scroll {\n    width: 100%;\n    overflow-x: auto;\n    -webkit-overflow-scrolling: touch;\n  }\n\n  #he-centers-table {\n    width: 100% !important;\n    min-width: 1100px;\n  }\n\n  \/* Table links *\/\n  #he-centers-table a,\n  #he-centers-table a:visited {\n    color: #1a73e8 !important;\n    font-weight: 500;\n    text-decoration: none;\n  }\n\n  #he-centers-table a:hover {\n    text-decoration: underline;\n  }\n\n  \/* Hidden searchable text for Website column *\/\n  .table-search-hidden {\n    display: none;\n  }\n\n  \/* Description clamp \/ expand *\/\n  #he-centers-table td.desc-cell {\n    white-space: normal !important;\n    min-width: 320px;\n    vertical-align: top;\n  }\n\n  .desc-wrap {\n    white-space: normal;\n  }\n\n  .desc-text {\n    display: -webkit-box;\n    -webkit-box-orient: vertical;\n    -webkit-line-clamp: 3;\n    overflow: hidden;\n    line-height: 1.45;\n    max-height: calc(1.45em * 3);\n    word-break: break-word;\n  }\n\n  .desc-wrap.expanded .desc-text {\n    display: block;\n    -webkit-line-clamp: unset;\n    max-height: none;\n    overflow: visible;\n  }\n\n  .desc-toggle {\n    display: inline-block;\n    margin-top: 6px;\n    padding: 0;\n    border: 0;\n    background: none;\n    color: #1a73e8;\n    cursor: pointer;\n    font-weight: 500;\n    text-decoration: none;\n  }\n\n  .desc-toggle:hover {\n    text-decoration: underline;\n  }\n\n  .desc-toggle.is-hidden {\n    display: none;\n  }\n\n  \/* WordPress spacing *\/\n  .has-text-align-center.wp-block-post-title.has-x-large-font-size {\n    margin-top: 30px !important;\n  }\n\n  .wp-block-group.has-global-padding.is-layout-constrained.wp-container-core-group-is-layout-5da90744.wp-block-group-is-layout-constrained {\n    margin-top: 30px !important;\n  }\n\n  @media (max-width: 768px) {\n    .site-title {\n      font-size: 2rem;\n    }\n\n    .tabs-container {\n      flex-direction: column;\n      align-items: center;\n    }\n\n    .tab-button {\n      margin: 5px 0;\n      width: 80%;\n    }\n\n    .map-iframe {\n      height: 400px;\n    }\n\n    .table-container {\n      padding: 12px;\n    }\n\n    table.dataTable th,\n    table.dataTable td {\n      padding: 6px 10px;\n      font-size: 14px;\n      white-space: nowrap;\n    }\n\n    #he-centers-table td.desc-cell {\n      white-space: normal !important;\n      min-width: 260px;\n    }\n  }\n<\/style>\n\n<!-- Libraries (once per page) -->\n<link rel=\"stylesheet\" href=\"https:\/\/unpkg.com\/leaflet\/dist\/leaflet.css\" \/>\n<link rel=\"stylesheet\" href=\"https:\/\/cdn.datatables.net\/1.11.5\/css\/jquery.dataTables.min.css\" \/>\n\n<script src=\"https:\/\/code.jquery.com\/jquery-3.6.0.min.js\"><\/script>\n<script src=\"https:\/\/unpkg.com\/leaflet\/dist\/leaflet.js\"><\/script>\n<script src=\"https:\/\/cdn.datatables.net\/1.11.5\/js\/jquery.dataTables.min.js\"><\/script>\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/PapaParse\/5.3.2\/papaparse.min.js\"><\/script>\n\n<main class=\"itBody\">\n  <p>In 2000, the <a href=\"http:\/\/www.bc.edu\/cihe\" target=\"_blank\">Center for International Higher Education<\/a> at Boston College, under the leadership of Philip G. Altbach, completed the first global inventory of higher education centers and programs around the world (Altbach &amp; Engberg, 2000). The CIHE inventory was updated in 2006 (Altbach et. al. 2006) and again in 2013 (Rumbley et al, 2014), the latter also including a partial inventory of journals publishing on issues related to higher education around the world. In 2024 and 2025, GOHEC worked with CIHE to revitalize the inventory project. The resulting Beta version, available here, is therefore the most current comprehensive global \u201cinventory\u201d of higher education research centers and degree-granting academic programs focused on higher education.<\/p>\n\n  <p>The Inventory of Academic Programs provides valuable insights into the global landscape of higher education capacity building, highlighting key trends and issues that shape the scholarly field of higher education worldwide. The accompanying map not only captures a \u201csnapshot\u201d of higher education academic programs but also serves as an exceptional resource to enhance communication and collaboration within the higher education research community.<\/p>\n\n  <p>The version of the inventory of 2026 was developed by a team that included: <i>Prof.A.Pausits, Prof. I.Frumin, Dr. A.Vorochkov, O. Mostafa<\/i>.<\/p>\n\n<p>Please cite as: Pausits, A., Frumin, I., Vorochkov, A., &#038; Mostafa, O. (2026). Inventory of Higher Education  Academic Programs [Data set]. DOOR, Universit\u00e4t f\u00fcr Weiterbildung Krems. <a https:\/\/doi.org\/10.48341\/0n4d-g853\">https:\/\/doi.org\/10.48341\/0n4d-g853<\/a> \n\nLicence: <a https:\/\/creativecommons.org\/licenses\/by-nc\/4.0\/>CC BY-NC 4.0 International<\/a><\/p> \n\n  <p>If you would like more information about our data collection methodology, please <a href=\"https:\/\/docs.google.com\/document\/d\/1f9RM97nWEe3qmSdtsxRWV7QQIwxUTjcASIIWwrjktrQ\/edit?usp=sharing\" target=\"_blank\">click here<\/a>.<\/p>\n\n  <p>If you have additional information, corrections, or know of any degree program in the field of higher education not yet listed, please kindly fill out the form linked below. You can contact us via email: <a href=\"mailto:inventory.gohec@donau-uni.ac.at\">inventory.gohec@donau-uni.ac.at<\/a><\/p>\n\n  <p><a href=\"https:\/\/docs.google.com\/spreadsheets\/d\/1JMrimCnvOy5sZruM1J-Qu0S1QyrMSzYSdfg4Ki-IqoA\" target=\"_blank\" rel=\"noopener\">Download Excel data<\/a><\/p>\n  <br>\n\n  <div class=\"map-container\">\n    <h3>Interactive Map of academic programs<\/h3>\n    <div id=\"he-centers-map\" class=\"map-iframe\"><\/div>\n  <\/div>\n\n  <div class=\"table-container\">\n    <div class=\"table-header-row\">\n      <h3>Table of academic programs<\/h3>\n      <button type=\"button\" id=\"clear-he-filters\" class=\"clear-filters-btn\">Clear filters<\/button>\n    <\/div>\n\n    <div class=\"table-scroll\">\n      <table id=\"he-centers-table\" class=\"display\" style=\"width:100%\">\n        <thead>\n          <tr>\n            <th>Program<\/th>\n            <th>University<\/th>\n            <th>Country<\/th>\n            <th>Website<\/th>\n            <th>Level<\/th>\n            <th>Description<\/th>\n          <\/tr>\n          <tr>\n            <th><input type=\"text\" placeholder=\"Filter Program\" \/><\/th>\n            <th><input type=\"text\" placeholder=\"Filter University\" \/><\/th>\n            <th><input type=\"text\" placeholder=\"Filter Country\" \/><\/th>\n            <th><input type=\"text\" placeholder=\"Filter Website\" \/><\/th>\n            <th><input type=\"text\" placeholder=\"Filter Level\" \/><\/th>\n            <th><input type=\"text\" placeholder=\"Filter Description\" \/><\/th>\n          <\/tr>\n        <\/thead>\n        <tbody><\/tbody>\n      <\/table>\n    <\/div>\n  <\/div>\n\n  <div class=\"cta-section\">\n    <h3 class=\"cta-heading\">Missing or Editing an academic program?<\/h3>\n    <p>Help us keep the map complete. If your academic program isn&#8217;t listed or you&#8217;d like to update its information, please fill out the form below.<\/p>\n    <a href=\"https:\/\/forms.office.com\/Pages\/ResponsePage.aspx?id=v3HXst56qUWhtClAjz3C5j66EepJPWVHnbXY_51bLcxURUhUVzFPRlk5TFczWTBWSVlNSkZWUFQ3Ry4u\" class=\"cta-button\" target=\"_blank\" rel=\"noopener\">Add academic program<\/a>\n  <\/div>\n\n  <!-- Optional panels if you use tabs -->\n  <div id=\"centers-panel\" class=\"panel-content active\"><\/div>\n  <div id=\"programs-panel\" class=\"panel-content\"><\/div>\n<\/main>\n\n<script>\n(function () {\n  const JSON_URL = '\/wp-content\/uploads\/json_and_csv\/he_academic.json';\n  const CSV_URL = '\/wp-content\/uploads\/json_and_csv\/he_academic.csv';\n\n  function escapeHtml(value) {\n    return String(value ?? '')\n      .replace(\/&\/g, '&amp;')\n      .replace(\/<\/g, '&lt;')\n      .replace(\/>\/g, '&gt;')\n      .replace(\/\"\/g, '&quot;')\n      .replace(\/'\/g, '&#039;');\n  }\n\n  function formatTextWithBreaks(value) {\n    return escapeHtml(value).replace(\/\\r?\\n\/g, '<br>');\n  }\n\n  function safeUrl(url) {\n    const value = String(url ?? '').trim();\n    if (!value) return '';\n\n    try {\n      const parsed = new URL(value, window.location.origin);\n      if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {\n        return parsed.href;\n      }\n    } catch (e) {}\n\n    return '';\n  }\n\n  function sanitizePopupHtml(html) {\n    const template = document.createElement('template');\n    template.innerHTML = String(html ?? '');\n\n    const allowedTags = new Set(['BR', 'B', 'STRONG', 'I', 'EM', 'U', 'A', 'P', 'UL', 'OL', 'LI']);\n    const elements = Array.from(template.content.querySelectorAll('*'));\n\n    elements.forEach(function (el) {\n      if (!allowedTags.has(el.tagName)) {\n        el.replaceWith(document.createTextNode(el.textContent || ''));\n        return;\n      }\n\n      const attrs = Array.from(el.attributes);\n      attrs.forEach(function (attr) {\n        const attrName = attr.name.toLowerCase();\n\n        if (el.tagName === 'A' && (attrName === 'href' || attrName === 'target' || attrName === 'rel')) {\n          return;\n        }\n\n        el.removeAttribute(attr.name);\n      });\n\n      if (el.tagName === 'A') {\n        const href = el.getAttribute('href') || '';\n        if (!\/^https?:\\\/\\\/\/i.test(href) && !\/^mailto:\/i.test(href)) {\n          el.removeAttribute('href');\n        }\n        el.setAttribute('target', '_blank');\n        el.setAttribute('rel', 'noopener');\n      }\n    });\n\n    return template.innerHTML;\n  }\n\n  function refreshDescriptionToggles(scope) {\n    const $root = scope ? jQuery(scope) : jQuery(document);\n\n    $root.find('.desc-wrap').each(function () {\n      const wrap = this;\n      const textEl = wrap.querySelector('.desc-text');\n      const btn = wrap.querySelector('.desc-toggle');\n\n      if (!textEl || !btn) return;\n\n      const wasExpanded = wrap.classList.contains('expanded');\n      if (wasExpanded) wrap.classList.remove('expanded');\n\n      const needsToggle = textEl.scrollHeight > textEl.clientHeight + 2;\n\n      if (!needsToggle) {\n        btn.classList.add('is-hidden');\n        btn.textContent = 'Show more';\n        wrap.classList.remove('expanded');\n      } else {\n        btn.classList.remove('is-hidden');\n        btn.textContent = wasExpanded ? 'Show less' : 'Show more';\n        if (wasExpanded) wrap.classList.add('expanded');\n      }\n    });\n  }\n\n  function getFilterInputs($table) {\n    return $table.find('thead tr:nth-child(2) th input');\n  }\n\n  function normalizePath(path) {\n    return String(path || '').replace(\/\\\/+$\/, '') || '\/';\n  }\n\n  function getUrlFilterValues(urlLike) {\n    const url = urlLike instanceof URL ? urlLike : new URL(urlLike, window.location.href);\n    return {\n      university: (url.searchParams.get('university') || '').trim(),\n      country: (url.searchParams.get('country') || '').trim()\n    };\n  }\n\n  function hasAnyActiveFilters($table) {\n    let active = false;\n    getFilterInputs($table).each(function () {\n      if (String(this.value || '').trim() !== '') {\n        active = true;\n        return false;\n      }\n    });\n    return active;\n  }\n\n  function updateClearFiltersButton($table) {\n    const btn = document.getElementById('clear-he-filters');\n    if (!btn) return;\n\n    if (hasAnyActiveFilters($table)) {\n      btn.classList.add('is-visible');\n    } else {\n      btn.classList.remove('is-visible');\n    }\n  }\n\n  function scrollToTable() {\n    const target = document.getElementById('he-centers-table');\n    if (!target) return;\n\n    target.scrollIntoView({\n      behavior: 'smooth',\n      block: 'start'\n    });\n  }\n\n  function syncUrlWithUniversityCountry($table, historyMode) {\n    const mode = historyMode || 'replace';\n    const $inputs = getFilterInputs($table);\n\n    const university = ($inputs.eq(1).val() || '').trim();\n    const country = ($inputs.eq(2).val() || '').trim();\n\n    const url = new URL(window.location.href);\n\n    if (university) {\n      url.searchParams.set('university', university);\n    } else {\n      url.searchParams.delete('university');\n    }\n\n    if (country) {\n      url.searchParams.set('country', country);\n    } else {\n      url.searchParams.delete('country');\n    }\n\n    if (university || country) {\n      url.hash = 'he-centers-table';\n    } else {\n      url.hash = '';\n    }\n\n    if (mode === 'push') {\n      window.history.pushState({}, '', url.toString());\n    } else {\n      window.history.replaceState({}, '', url.toString());\n    }\n  }\n\n  function clearAllTableFilters(dt, $table, historyMode) {\n    const $inputs = getFilterInputs($table);\n\n    $inputs.each(function () {\n      this.value = '';\n    });\n\n    dt.search('');\n    dt.columns().search('');\n    dt.draw();\n\n    syncUrlWithUniversityCountry($table, historyMode || 'replace');\n    updateClearFiltersButton($table);\n    refreshDescriptionToggles($table);\n  }\n\n  function applyUniversityCountryFilters(dt, $table, filters, options) {\n    const opts = options || {};\n    const $inputs = getFilterInputs($table);\n\n    const university = String(filters.university || '').trim();\n    const country = String(filters.country || '').trim();\n\n    dt.search('');\n    dt.columns().search('');\n\n    $inputs.each(function () {\n      this.value = '';\n    });\n\n    if (university) {\n      $inputs.eq(1).val(university);\n      dt.column(1).search(university);\n    }\n\n    if (country) {\n      $inputs.eq(2).val(country);\n      dt.column(2).search(country);\n    }\n\n    dt.draw();\n\n    if (opts.updateUrl !== false) {\n      syncUrlWithUniversityCountry($table, opts.historyMode || 'replace');\n    }\n\n    updateClearFiltersButton($table);\n    refreshDescriptionToggles($table);\n\n    if (opts.scrollToTable) {\n      setTimeout(scrollToTable, 60);\n    }\n  }\n\n  function applyFiltersFromCurrentUrl(dt, $table, options) {\n    const filters = getUrlFilterValues(window.location.href);\n\n    if (!filters.university && !filters.country) {\n      updateClearFiltersButton($table);\n      return;\n    }\n\n    applyUniversityCountryFilters(dt, $table, filters, {\n      updateUrl: false,\n      scrollToTable: !!(options && options.scrollToTable)\n    });\n  }\n\n  function installFilterLinksHandler(dt, $table) {\n    if (window.heFilterLinksHandlerInstalled) return;\n    window.heFilterLinksHandlerInstalled = true;\n\n    document.addEventListener('click', function (event) {\n      const link = event.target.closest('a[href]');\n      if (!link) return;\n\n      const href = link.getAttribute('href');\n      if (!href || href.startsWith('javascript:')) return;\n\n      let url;\n      try {\n        url = new URL(href, window.location.href);\n      } catch (e) {\n        return;\n      }\n\n      const sameOrigin = url.origin === window.location.origin;\n      const samePath = normalizePath(url.pathname) === normalizePath(window.location.pathname);\n      const filters = getUrlFilterValues(url);\n\n      if (!sameOrigin || !samePath) return;\n      if (!filters.university && !filters.country) return;\n\n      event.preventDefault();\n      window.history.pushState({}, '', url.toString());\n\n      applyUniversityCountryFilters(dt, $table, filters, {\n        updateUrl: false,\n        scrollToTable: true\n      });\n    });\n\n    window.addEventListener('popstate', function () {\n      const filters = getUrlFilterValues(window.location.href);\n\n      if (!filters.university && !filters.country) {\n        clearAllTableFilters(dt, $table, 'replace');\n        return;\n      }\n\n      applyUniversityCountryFilters(dt, $table, filters, {\n        updateUrl: false,\n        scrollToTable: false\n      });\n    });\n  }\n\n  function unwrapWpBlockCover() {\n    document.querySelectorAll('.wp-block-cover').forEach(function (cover) {\n      while (cover.firstChild) {\n        cover.parentNode.insertBefore(cover.firstChild, cover);\n      }\n      cover.remove();\n    });\n  }\n\n  function initTabsIfPresent() {\n    const centersTab = document.getElementById('centers-tab');\n    const programsTab = document.getElementById('programs-tab');\n    const centersPanel = document.getElementById('centers-panel');\n    const programsPanel = document.getElementById('programs-panel');\n\n    if (!centersTab || !programsTab || !centersPanel || !programsPanel) return;\n\n    centersTab.addEventListener('click', function () {\n      centersPanel.classList.add('active');\n      programsPanel.classList.remove('active');\n      centersTab.classList.add('active');\n      programsTab.classList.remove('active');\n      invalidateMapSizeSoon();\n      initCentersTable();\n    });\n\n    programsTab.addEventListener('click', function () {\n      centersPanel.classList.remove('active');\n      programsPanel.classList.add('active');\n      centersTab.classList.remove('active');\n      programsTab.classList.add('active');\n    });\n  }\n\n  function initCentersMap() {\n    if (window.heCentersMap) return window.heCentersMap;\n\n    const el = document.getElementById('he-centers-map');\n    if (!el || typeof L === 'undefined') return null;\n\n    const map = L.map(el, {\n      worldCopyJump: false,\n      maxBounds: [[-85, -180], [85, 180]],\n      maxBoundsViscosity: 1.0\n    }).setView([20, 0], 2);\n\n    L.tileLayer('https:\/\/{s}.tile.openstreetmap.org\/{z}\/{x}\/{y}.png', {\n      attribution: '\u00a9 OpenStreetMap contributors',\n      noWrap: true,\n      bounds: [[-85, -180], [85, 180]]\n    }).addTo(map);\n\n    window.heCentersMarkers = L.layerGroup().addTo(map);\n\n    map.on('drag', function () {\n      map.panInsideBounds(map.options.maxBounds, { animate: false });\n    });\n\n    window.heCentersMap = map;\n    return map;\n  }\n\n     function loadCentersMarkers() {\n      const map = initCentersMap();\n      if (!map) return;\n\n      if (window.heCentersMarkers) {\n        window.heCentersMarkers.clearLayers();\n      }\n\n      fetch(JSON_URL + '?v=' + Date.now())\n        .then(function (r) {\n          if (!r.ok) throw new Error(r.statusText);\n          return r.json();\n        })\n        .then(function (data) {\n          if (!Array.isArray(data) || !data.length) return;\n\n          data.forEach(function (u) {\n            const lat = Number(u.lat);\n            const lon = Number(u.lon);\n\n            if (!Number.isFinite(lat) || !Number.isFinite(lon)) return;\n\n            const rawName = String(u.name || 'Unnamed').trim();\n            const safeName = sanitizePopupHtml(rawName);\n            const descr = sanitizePopupHtml(u.description || '');\n\n            const titleHtml = \/<(b|strong)\\b\/i.test(safeName)\n              ? safeName\n              : '<strong>' + safeName + '<\/strong>';\n\n            const popupHtml = titleHtml + (descr ? '<br>' + descr : '');\n\n            L.marker([lat, lon])\n              .bindPopup(popupHtml)\n              .addTo(window.heCentersMarkers);\n          });\n        })\n        .catch(function (err) {\n          console.error('JSON load error:', err);\n        });\n    }\n\n  function invalidateMapSizeSoon() {\n    if (!window.heCentersMap) return;\n    setTimeout(function () {\n      window.heCentersMap.invalidateSize();\n    }, 150);\n  }\n\n  function initCentersTable() {\n    if (!window.jQuery || !jQuery.fn.dataTable || typeof Papa === 'undefined') return;\n\n    const $table = jQuery('#he-centers-table');\n    if (!$table.length) return;\n\n    if (jQuery.fn.dataTable.isDataTable('#he-centers-table')) {\n      const dtExisting = $table.DataTable();\n      setTimeout(function () {\n        dtExisting.columns.adjust().draw(false);\n        refreshDescriptionToggles($table);\n        updateClearFiltersButton($table);\n      }, 0);\n      return;\n    }\n\n    Papa.parse(CSV_URL + '?v=' + Date.now(), {\n      download: true,\n      header: true,\n      skipEmptyLines: true,\n      complete: function (results) {\n        const data = Array.isArray(results.data) ? results.data : [];\n        let rowsHtml = '';\n\n        data.forEach(function (row) {\n          const program = row['Program'] || '';\n          if (String(program).trim() === '') return;\n\n          const university = row['University'] || '';\n          const country = row['Country'] || '';\n          const website = row['Website'] || '';\n          const level = row['Level'] || '';\n          const description = row['Description'] || '';\n\n          const safeWebsite = safeUrl(website);\n          const websiteCell = safeWebsite\n            ? '<span class=\"table-search-hidden\">' + escapeHtml(website) + '<\/span><a href=\"' + escapeHtml(safeWebsite) + '\" target=\"_blank\" rel=\"noopener\">Website<\/a>'\n            : '';\n\n          const descriptionCell =\n            '<div class=\"desc-wrap\">' +\n              '<div class=\"desc-text\">' + formatTextWithBreaks(description) + '<\/div>' +\n              '<button type=\"button\" class=\"desc-toggle is-hidden\">Show more<\/button>' +\n            '<\/div>';\n\n          rowsHtml +=\n            '<tr>' +\n              '<td>' + escapeHtml(program) + '<\/td>' +\n              '<td>' + escapeHtml(university) + '<\/td>' +\n              '<td>' + escapeHtml(country) + '<\/td>' +\n              '<td>' + websiteCell + '<\/td>' +\n              '<td>' + escapeHtml(level) + '<\/td>' +\n              '<td class=\"desc-cell\">' + descriptionCell + '<\/td>' +\n            '<\/tr>';\n        });\n\n        $table.find('tbody').html(rowsHtml);\n\n        const dt = $table.DataTable({\n          autoWidth: false,\n          paging: true,\n          searching: true,\n          ordering: true,\n          info: true,\n          orderCellsTop: true,\n          order: [[2, 'asc'], [0, 'asc']],\n          pageLength: 50,\n          lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, 'All']]\n        });\n\n        $table.find('thead tr:nth-child(2) th input').each(function (colIndex) {\n          jQuery(this).on('input keyup change', function (e) {\n            e.stopPropagation();\n            dt.column(colIndex).search(this.value).draw();\n            syncUrlWithUniversityCountry($table, 'replace');\n            updateClearFiltersButton($table);\n          });\n        });\n\n        $table\n          .off('click.descToggle', '.desc-toggle')\n          .on('click.descToggle', '.desc-toggle', function (e) {\n            e.preventDefault();\n\n            const $btn = jQuery(this);\n            const $wrap = $btn.closest('.desc-wrap');\n\n            $wrap.toggleClass('expanded');\n            $btn.text($wrap.hasClass('expanded') ? 'Show less' : 'Show more');\n          });\n\n        jQuery('#clear-he-filters')\n          .off('click')\n          .on('click', function () {\n            clearAllTableFilters(dt, $table, 'replace');\n          });\n\n        installFilterLinksHandler(dt, $table);\n        applyFiltersFromCurrentUrl(dt, $table, { scrollToTable: true });\n\n        refreshDescriptionToggles($table);\n\n        dt.on('draw', function () {\n          refreshDescriptionToggles($table);\n          updateClearFiltersButton($table);\n        });\n\n        setTimeout(function () {\n          dt.columns.adjust().draw(false);\n          refreshDescriptionToggles($table);\n          updateClearFiltersButton($table);\n        }, 0);\n      },\n      error: function (err) {\n        console.error('CSV parse error:', err);\n      }\n    });\n  }\n\n  function boot() {\n    unwrapWpBlockCover();\n    initTabsIfPresent();\n    loadCentersMarkers();\n    initCentersTable();\n    invalidateMapSizeSoon();\n  }\n\n  if (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', boot, { once: true });\n  } else {\n    boot();\n  }\n\n  window.addEventListener('resize', function () {\n    if (!window.jQuery) return;\n\n    if (jQuery.fn.dataTable.isDataTable('#he-centers-table')) {\n      const dt = jQuery('#he-centers-table').DataTable();\n      dt.columns.adjust().draw(false);\n    }\n\n    refreshDescriptionToggles(jQuery('#he-centers-table'));\n    invalidateMapSizeSoon();\n  });\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>In 2000, the Center for International Higher Education at Boston College, under the leadership of Philip G. Altbach, completed the first global inventory of higher education centers and programs around the world (Altbach &amp; Engberg, 2000). The CIHE inventory was updated in 2006 (Altbach et. al. 2006) and again in 2013 (Rumbley et al, 2014), [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"ub_ctt_via":"","footnotes":""},"class_list":["post-640","page","type-page","status-publish","hentry"],"featured_image_src":null,"wps_subtitle":"","_links":{"self":[{"href":"https:\/\/highered-change.org\/index.php\/wp-json\/wp\/v2\/pages\/640","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/highered-change.org\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/highered-change.org\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/highered-change.org\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/highered-change.org\/index.php\/wp-json\/wp\/v2\/comments?post=640"}],"version-history":[{"count":17,"href":"https:\/\/highered-change.org\/index.php\/wp-json\/wp\/v2\/pages\/640\/revisions"}],"predecessor-version":[{"id":694,"href":"https:\/\/highered-change.org\/index.php\/wp-json\/wp\/v2\/pages\/640\/revisions\/694"}],"wp:attachment":[{"href":"https:\/\/highered-change.org\/index.php\/wp-json\/wp\/v2\/media?parent=640"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}