// PublicationsView — full publications page with tabs: // In Press · Articles · Proceedings · Book Chapters. // Entries grouped by year, color-coded topic tags, DOI + BibTeX actions. // Data parsed from the .bib (window.WINTEL_PUBLICATIONS); arXiv excluded. const PV = window.WINTELAcademicDesignSystem_045d4f; const CONF = { 'IEEECONF': 'Asilomar Conf. Signals, Syst., Comput.', 'ACSSC': 'Asilomar Conf. Signals, Syst., Comput.', 'ICC': 'IEEE Int. Conf. Commun. (ICC)', 'ICC Workshops': 'IEEE ICC Workshops', 'GLOBECOM': 'IEEE Global Commun. Conf. (GLOBECOM)', 'GLOBECOM (Workshops)': 'IEEE GLOBECOM Workshops', 'GLOBECOM Workshops': 'IEEE GLOBECOM Workshops', 'PIMRC': 'IEEE Int. Symp. Pers., Indoor Mobile Radio Commun. (PIMRC)', 'WCNC': 'IEEE Wireless Commun. Netw. Conf. (WCNC)', 'SPAWC': 'IEEE Int. Workshop Signal Process. Adv. Wireless Commun. (SPAWC)', 'SAM': 'IEEE Sensor Array Multichannel Signal Process. Workshop (SAM)', 'ICCSPA': 'Int. Conf. Commun., Signal Process., Appl. (ICCSPA)', 'EMBC': 'IEEE Eng. Med. Biol. Soc. Conf. (EMBC)', 'HealthCom': 'IEEE Int. Conf. E-Health Netw., Appl. Services (HealthCom)', 'BSN': 'IEEE Body Sensor Networks Conf. (BSN)', 'VTC Spring': 'IEEE Veh. Technol. Conf. (VTC-Spring)', 'VTC Fall': 'IEEE Veh. Technol. Conf. (VTC-Fall)', 'CCNC': 'IEEE Consum. Commun. Netw. Conf. (CCNC)', 'ISCAS': 'IEEE Int. Symp. Circuits Syst. (ISCAS)', 'MWSCAS': 'IEEE Int. Midwest Symp. Circuits Syst. (MWSCAS)', 'ICTC': 'Int. Conf. ICT Convergence (ICTC)', 'ICASSP': 'IEEE Int. Conf. Acoust., Speech, Signal Process. (ICASSP)', 'ICNC': 'Int. Conf. Comput., Netw. Commun. (ICNC)', }; // ---- Topic taxonomy (order = priority; each pub shows up to 3) ---- const TOPICS = [ { label: 'ISAC', color: '#0ea5e9', re: /\bISAC\b|integrated sensing|sensing and communication|joint .*sensing|beam-?squint/i }, { label: 'RIS', color: '#2563eb', re: /\bRIS\b|reconfigurable intelligent surface|star-?ris|intelligent surface/i }, { label: 'AI-Native', color: '#8b5cf6', re: /\bAI\b|deep learning|machine learning|\bDRL\b|\bGAN\b|\bLLM\b|explainabl|generative|neural|\bXAI\b|agentic|autoencoder|reinforcement/i }, { label: 'Near-Field', color: '#d97706', re: /near-?field|beamfocus|polar-?domain|spatial degrees of freedom|\bURA\b|\bUCA\b|circular array/i }, { label: 'NTN', color: '#059669', re: /\bNTN\b|non-?terrestrial|\bUAV\b|airborne|satellite|aerial|drone/i }, { label: 'OWC', color: '#4f46e5', re: /optical wireless|\bOWC\b|opto-?acoustic|underwater|visible light|\bVLC\b|\blaser\b|photonic/i }, { label: 'IoB', color: '#84cc16', re: /internet of bodies|body communication|human body|\bIoB\b|\bHBC\b|biomedical|\bECG\b|wearable|implant/i }, { label: 'NOMA', color: '#0d9488', re: /\bNOMA\b|non-?orthogonal|multiple access|rate splitting|\bRSMA\b|\bSWIPT\b/i }, { label: 'mMIMO', color: '#ca8a04', re: /massive mimo|\bmMIMO\b|beamforming|codebook|channel estimation|cell-?free|\bMIMO\b|mmwave/i }, { label: 'Security', color: '#dc2626', re: /physical layer security|\bsecurity\b|\bsecure\b|protected zone|jamming|eavesdrop/i }, { label: 'CRN', color: '#c026d3', re: /cognitive radio|\bCRN\b|spectrum sensing|spectrum sharing|\bcognitive\b/i }, { label: 'IoT', color: '#65a30d', re: /internet of things|\bIoT\b|device-?to-?device|\bD2D\b|machine-?type|\bM2M\b/i }, ]; // ---- Journal venue short codes (short label + full title for tooltip) ---- const JOURNAL_VENUE = { 'IEEE Trans. Wirel. Commun.': ['IEEE TWC', 'IEEE Transactions on Wireless Communications'], 'IEEE Trans. Commun.': ['IEEE TCOM', 'IEEE Transactions on Communications'], 'IEEE Trans. Mob. Comput.': ['IEEE TMC', 'IEEE Transactions on Mobile Computing'], 'IEEE Trans. Cogn. Commun. Netw.': ['IEEE TCCN', 'IEEE Transactions on Cognitive Communications and Networking'], 'IEEE Trans. Green Commun. Netw.': ['IEEE TGCN', 'IEEE Transactions on Green Communications and Networking'], 'IEEE Trans. Netw. Serv. Manag.': ['IEEE TNSM', 'IEEE Transactions on Network and Service Management'], 'IEEE Trans. Circuits Syst. I Regul. Pap.': ['IEEE TCAS-I', 'IEEE Transactions on Circuits and Systems I: Regular Papers'], 'IEEE Trans. Biomed. Eng.': ['IEEE TBME', 'IEEE Transactions on Biomedical Engineering'], 'IEEE Trans. Instrum. Meas.': ['IEEE TIM', 'IEEE Transactions on Instrumentation and Measurement'], 'IEEE J. Sel. Top. Signal Process.': ['IEEE JSTSP', 'IEEE Journal of Selected Topics in Signal Processing'], 'IEEE Open J. Commun. Soc.': ['IEEE OJ-COMS', 'IEEE Open Journal of the Communications Society'], 'IEEE Trans. Mach. Learn. Commun. Netw.': ['IEEE TMLCN', 'IEEE Transactions on Machine Learning in Communications and Networking'], 'Nat. Rev. Electr. Eng.': ['Nat. Rev. EE', 'Nature Reviews Electrical Engineering'], 'Results Eng.': ['Results Eng.', 'Results in Engineering (Elsevier)'], 'Smart Health': ['Smart Health', 'Smart Health (Elsevier)'], 'Balkan J. Elect. Comp. Eng.': ['BAJECE', 'Balkan Journal of Electrical and Computer Engineering'], 'IEEE Commun. Mag.': ['IEEE ComMag', 'IEEE Communications Magazine'], 'IEEE Commun. Stand. Mag.': ['IEEE StdMag', 'IEEE Communications Standards Magazine'], 'IEEE Commun. Lett.': ['IEEE ComLett', 'IEEE Communications Letters'], 'IEEE Commun. Surv. Tutorials': ['IEEE COMST', 'IEEE Communications Surveys & Tutorials'], 'IEEE Wirel. Commun.': ['IEEE WCM', 'IEEE Wireless Communications'], 'IEEE Wirel. Commun. Lett.': ['IEEE WCL', 'IEEE Wireless Communications Letters'], 'IEEE Wireless Commun. Lett.': ['IEEE WCL', 'IEEE Wireless Communications Letters'], 'IEEE Signal Process. Mag.': ['IEEE SPM', 'IEEE Signal Processing Magazine'], 'IEEE Internet Things J.': ['IEEE IoT-J', 'IEEE Internet of Things Journal'], 'IEEE Sensors J.': ['IEEE SensJ', 'IEEE Sensors Journal'], 'IEEE Internet Things Mag.': ['IEEE IoT-M', 'IEEE Internet of Things Magazine'], 'IEEE Veh. Technol. Mag.': ['IEEE VTM', 'IEEE Vehicular Technology Magazine'], 'IEEE Syst. J.': ['IEEE SysJ', 'IEEE Systems Journal'], 'IEEE Access': ['IEEE Access', 'IEEE Access'], 'Ad Hoc Networks': ['AdHocNet', 'Ad Hoc Networks (Elsevier)'], 'IET Commun.': ['IET COM', 'IET Communications'], 'Sci. China Inf. Sci.': ['SCIS', 'Science China Information Sciences'], 'Sensors': ['Sensors', 'Sensors (MDPI)'], }; // ---- Journal quartile ranking (Scimago / SJR, current) ---- // Keyed by the same venue string as pub.v. Source: scimagojr.com. // >>> VERIFY / EDIT THESE to match your preferred ranking (Scimago vs JCR) <<< // Use 'Q1'..'Q4', or null / omit for unranked or too-new venues (no badge shown). const QUARTILE = { 'IEEE Trans. Wirel. Commun.': 'Q1', 'IEEE Trans. Commun.': 'Q1', 'IEEE Trans. Mob. Comput.': 'Q1', 'IEEE Trans. Cogn. Commun. Netw.': 'Q1', 'IEEE Trans. Green Commun. Netw.': 'Q1', 'IEEE Trans. Netw. Serv. Manag.': 'Q1', 'IEEE Trans. Circuits Syst. I Regul. Pap.': 'Q1', 'IEEE Trans. Biomed. Eng.': 'Q1', 'IEEE Trans. Instrum. Meas.': 'Q1', 'IEEE J. Sel. Top. Signal Process.': 'Q1', 'IEEE Open J. Commun. Soc.': 'Q1', 'IEEE Trans. Mach. Learn. Commun. Netw.': null, // too new for an SJR quartile 'Nat. Rev. Electr. Eng.': 'Q1', 'Results Eng.': 'Q1', 'Smart Health': 'Q2', 'Balkan J. Elect. Comp. Eng.': null, // not indexed in Scimago 'IEEE Commun. Mag.': 'Q1', 'IEEE Commun. Stand. Mag.': 'Q1', 'IEEE Commun. Lett.': 'Q2', 'IEEE Commun. Surv. Tutorials': 'Q1', 'IEEE Wirel. Commun.': 'Q1', 'IEEE Wirel. Commun. Lett.': 'Q1', 'IEEE Wireless Commun. Lett.': 'Q1', 'IEEE Signal Process. Mag.': 'Q1', 'IEEE Internet Things J.': 'Q1', 'IEEE Sensors J.': 'Q1', 'IEEE Internet Things Mag.': 'Q1', 'IEEE Veh. Technol. Mag.': 'Q1', 'IEEE Syst. J.': 'Q1', 'IEEE Access': 'Q1', 'Ad Hoc Networks': 'Q1', 'IET Commun.': 'Q2', 'Sci. China Inf. Sci.': 'Q1', 'Sensors': 'Q1', 'Nature Sensors': 'Q1', 'Nature Reviews Electrical Engineering': 'Q1', }; const QUARTILE_COLOR = { Q1: '#059669', // emerald Q2: '#2563eb', // blue Q3: '#d97706', // amber Q4: '#6b7280', // slate }; // Quartile only applies to journal articles (not conferences, not book chapters). function quartileFor(pub) { if (pub.conf || pub.chapter) return null; return QUARTILE[pub.v] || null; } function QuartileTag({ q }) { const color = QUARTILE_COLOR[q] || '#6b7280'; return ( {q} ); } function venueTag(pub) { if (pub.chapter) return { short: 'Book Ch.', full: pub.v + (pub.pub ? ' · ' + pub.pub : '') }; if (!pub.conf) { const m = JOURNAL_VENUE[pub.v]; return m ? { short: m[0], full: m[1] } : { short: pub.v, full: pub.v }; } if (CONF[pub.v]) { const full = CONF[pub.v]; const abbr = (full.match(/\(([^)]+)\)/) || [])[1] || pub.v; return { short: abbr, full }; } if (/asilomar/i.test(pub.v)) { return { short: 'ASILOMAR', full: 'Asilomar Conference on Signals, Systems, and Computers, Pacific Grove' }; } const KW = [ [/globecom workshop|glocomw|gcwkshp|gc wkshp/i, 'GC Wkshps', 'IEEE GLOBECOM Workshops'], [/globecom|glocom/i, 'GLOBECOM', 'IEEE Global Communications Conference (GLOBECOM)'], [/icc workshop|iccw/i, 'ICC Wkshps', 'IEEE ICC Workshops'], ]; for (const [re, short, full] of KW) { if (re.test(pub.v)) return { short, full }; } const abbr = (pub.v.match(/\(([^)]+)\)/) || [])[1]; return { short: abbr || 'Conf.', full: pub.v.split(',')[0] }; } function VenueTag({ info }) { return ( {info.short} ); } function topicsFor(pub) { const hay = (pub.t || '') + ' ' + (pub.v || ''); return TOPICS.filter((t) => t.re.test(hay)).slice(0, 3); } // Country → flag emoji for conference locations (matched against loc + venue string). const COUNTRY_FLAGS = [ [/\bU\.?S\.?A\.?\b|United States/i, '\uD83C\uDDFA\uD83C\uDDF8'], [/\bUK\b|United Kingdom|England|Scotland|Glasgow|London|Manchester|Guildford|Southampton/i, '\uD83C\uDDEC\uD83C\uDDE7'], [/\bUAE\b|United Arab Emirates|Dubai|Abu Dhabi/i, '\uD83C\uDDE6\uD83C\uDDEA'], [/Saudi Arabia|Jeddah|Dammam|Riyadh|Thuwal/i, '\uD83C\uDDF8\uD83C\uDDE6'], [/T\u00fcrkiye|Turkey|Istanbul|Ankara/i, '\uD83C\uDDF9\uD83C\uDDF7'], [/Canada|Ottawa|Montreal|Toronto/i, '\uD83C\uDDE8\uD83C\uDDE6'], [/Macau|Macao/i, '\uD83C\uDDF2\uD83C\uDDF4'], [/\bChina\b|Beijing|Shanghai|Shenzhen/i, '\uD83C\uDDE8\uD83C\uDDF3'], [/Sweden|Stockholm|Gothenburg/i, '\uD83C\uDDF8\uD83C\uDDEA'], [/Italy|Bologna|Padova|Padua|Rome|Milan/i, '\uD83C\uDDEE\uD83C\uDDF9'], [/Egypt|Alexandria|Cairo/i, '\uD83C\uDDEA\uD83C\uDDEC'], [/South Africa|Cape Town|Johannesburg/i, '\uD83C\uDDFF\uD83C\uDDE6'], [/Malaysia|Kuala Lumpur/i, '\uD83C\uDDF2\uD83C\uDDFE'], [/Singapore/i, '\uD83C\uDDF8\uD83C\uDDEC'], [/South Korea|\bKorea\b|Seoul|Busan/i, '\uD83C\uDDF0\uD83C\uDDF7'], [/Germany|Berlin|Munich|Hamburg/i, '\uD83C\uDDE9\uD83C\uDDEA'], [/France|Paris/i, '\uD83C\uDDEB\uD83C\uDDF7'], [/Spain|Barcelona|Madrid/i, '\uD83C\uDDEA\uD83C\uDDF8'], [/Greece|Athens/i, '\uD83C\uDDEC\uD83C\uDDF7'], [/Japan|Tokyo|Osaka/i, '\uD83C\uDDEF\uD83C\uDDF5'], [/Australia|Sydney|Melbourne/i, '\uD83C\uDDE6\uD83C\uDDFA'], [/\bIndia\b|Delhi|Mumbai|Bangalore/i, '\uD83C\uDDEE\uD83C\uDDF3'], [/Finland|Helsinki/i, '\uD83C\uDDEB\uD83C\uDDEE'], [/Morocco|Marrakech|Marrakesh|Rabat/i, '\uD83C\uDDF2\uD83C\uDDE6'], [/Kazakhstan|Astana|Almaty/i, '\uD83C\uDDF0\uD83C\uDDFF'], [/Brazil|Rio de Janeiro|S\u00e3o Paulo|Sao Paulo/i, '\uD83C\uDDE7\uD83C\uDDF7'], ]; function flagForText(str) { const hay = str || ''; for (const [re, flag] of COUNTRY_FLAGS) { if (re.test(hay)) return flag; } return null; } function flagFor(pub) { if (!pub.conf) return null; return flagForText((pub.loc || '') + ' ' + (pub.v || '')); } function TopicTag({ topic }) { return ( {topic.label} ); } // ---- BibTeX synthesis ---- function bibKey(pub) { const first = (pub.a && pub.a[0] && pub.a[0].name) || 'celik'; const last = first.replace(/\./g, '').trim().split(/\s+/).pop().toLowerCase().replace(/[^a-z]/g, ''); const word = (pub.t || '').toLowerCase().replace(/[^a-z0-9 ]/g, '').split(/\s+/).find((w) => w.length > 3) || 'paper'; return last + (pub.y || '') + word; } function bibtex(pub) { const type = pub.conf ? 'inproceedings' : (pub.chapter ? 'incollection' : 'article'); const authors = (pub.a || []).map((x) => x.name).join(' and '); const doi = pub.u ? pub.u.replace(/^https?:\/\/doi\.org\//, '') : null; const L = [`@${type}{${bibKey(pub)},`]; L.push(` author = {${authors}},`); L.push(` title = {${pub.t || ''}},`); if (pub.conf) { L.push(` booktitle = {Proc. ${CONF[pub.v] || pub.v}},`); if (pub.loc) L.push(` address = {${pub.loc}},`); } else if (pub.chapter) { L.push(` booktitle = {${pub.v}},`); L.push(` chapter = {${pub.chapter}},`); } else { L.push(` journal = {${pub.v || ''}},`); } if (pub.vol) L.push(` volume = {${pub.vol}},`); if (pub.no) L.push(` number = {${pub.no}},`); if (pub.p) L.push(` pages = {${String(pub.p).replace(/–/g, '--')}},`); if (pub.y) L.push(` year = {${pub.y}},`); if (doi) L.push(` doi = {${doi}},`); if (pub.ip) L.push(` note = {in press},`); L.push(` publisher = {${pub.pub || 'IEEE'}},`); L.push(`}`); return L.join('\n'); } function AuthorList({ list }) { return ( {list.map((au, i) => { let sep = ''; if (i > 0) sep = i === list.length - 1 ? (list.length > 2 ? ', and ' : ' and ') : ', '; return ( {sep} {au.name} ); })} ); } function Citation({ pub, index, onBib }) { const isConf = pub.conf; const topics = topicsFor(pub); const venue = venueTag(pub); const quartile = quartileFor(pub); const flag = flagFor(pub); return (
  • {index}.

    {', \u201C'} {pub.t} {',\u201D '} {isConf ? (pub.full ? in Proc. {pub.v}{pub.p ? , pp. {pub.p} : null}. : in Proc. {CONF[pub.v] || pub.v}{pub.loc ? , {pub.loc} : null}, {pub.y}{pub.ip ? [in press] : (pub.p ? , pp. {pub.p} : null)}.) : pub.chapter ? in {pub.v}, ch. {pub.chapter}{pub.pub ? . {pub.pub} : null}{pub.p ? , pp. {pub.p} : null}, {pub.y}. : pub.ip ? {pub.v}, [in press]. : {pub.v}{pub.vol ? , vol. {pub.vol} : null}{pub.no ? , no. {pub.no} : null}{pub.p ? , pp. {pub.p} : null}, {pub.y}.} {flag ? {flag} : null}

    {pub.u ? ( DOI ) : null} onBib(pub)} aria-label="Extract BibTeX" style={{ height: '1.85rem', padding: '0 0.6rem', fontSize: 'var(--text-xs)', fontFamily: 'var(--font-mono)', letterSpacing: '0.03em' }}> BibTeX {quartile ? : null} {topics.map((t) => )}
  • ); } function groupByYear(list) { const groups = {}; list.forEach((p) => { const y = p.y || 'Forthcoming'; (groups[y] = groups[y] || []).push(p); }); return Object.keys(groups) .sort((a, b) => (a === 'Forthcoming' ? -1 : b === 'Forthcoming' ? 1 : Number(b) - Number(a))) .map((y) => ({ year: y, items: groups[y] })); } // ============================================================================ // Publication analytics // ============================================================================ // >>> EDIT THESE WITH YOUR EXACT GOOGLE SCHOLAR FIGURES <<< // Source: https://scholar.google.com/citations?user=Xp0rnxQAAAAJ // `citationsByYear` is the "Cited by" histogram; h-index / i10-index are the // current all-time values shown in the metrics box. const SCHOLAR_METRICS = { hIndex: 38, i10Index: 81, totalCitations: 4700, asOf: 'Jun 22, 2026', placeholder: false, // set to false once you've entered your real numbers profileUrl: 'https://scholar.google.com/citations?user=Xp0rnxQAAAAJ&hl=en', citationsByYear: [ { year: 2017, c: 32 }, { year: 2018, c: 104 }, { year: 2019, c: 204 }, { year: 2020, c: 295 }, { year: 2021, c: 366 }, { year: 2022, c: 517 }, { year: 2023, c: 579 }, { year: 2024, c: 804 }, { year: 2025, c: 1167 }, { year: 2026, c: 550 }, ], }; // Live chart accent — tracks the --accent token so the accent tweak recolors charts/map. function chartAccent() { try { const v = getComputedStyle(document.documentElement).getPropertyValue('--accent').trim(); if (v) return v; } catch (e) {} return '#2563eb'; } function tallyVenues(P) { const all = [...(P.inPress || []), ...(P.articles || []), ...(P.proceedings || []), ...(P.bookChapters || [])]; const counts = {}; all.forEach((p) => { const v = venueTag(p); if (!counts[v.short]) counts[v.short] = { short: v.short, full: v.full, n: 0 }; counts[v.short].n += 1; }); return Object.values(counts).sort((a, b) => b.n - a.n); } function tallyTopics(P) { const all = [...(P.inPress || []), ...(P.articles || []), ...(P.proceedings || []), ...(P.bookChapters || [])]; const counts = {}; TOPICS.forEach((t) => { counts[t.label] = { label: t.label, color: t.color, n: 0 }; }); all.forEach((p) => { topicsFor(p).forEach((t) => { counts[t.label].n += 1; }); }); return Object.values(counts).filter((t) => t.n > 0).sort((a, b) => b.n - a.n); } // Journals & magazines only (conferences and book chapters excluded). function tallyJournalVenues(P) { const all = [...(P.inPress || []), ...(P.articles || [])]; const counts = {}; all.forEach((p) => { if (p.conf || p.chapter) return; const v = venueTag(p); counts[v.short] = counts[v.short] || { short: v.short, full: v.full, n: 0 }; counts[v.short].n += 1; }); return Object.values(counts).sort((a, b) => b.n - a.n); } // --- Conference geography: city gazetteer (lat/lon + ISO3) for the world map --- const CITIES = { 'Glasgow': { lat: 55.8642, lon: -4.2518, iso: 'GBR', country: 'United Kingdom' }, 'Pacific Grove': { lat: 36.6177, lon: -121.9166, iso: 'USA', country: 'United States' }, 'Montreal': { lat: 45.5019, lon: -73.5674, iso: 'CAN', country: 'Canada' }, 'Istanbul': { lat: 41.0082, lon: 28.9784, iso: 'TUR', country: 'T\u00fcrkiye' }, 'Orlando': { lat: 28.5383, lon: -81.3792, iso: 'USA', country: 'United States' }, 'Cape Town': { lat: -33.9249, lon: 18.4241, iso: 'ZAF', country: 'South Africa' }, 'Nara': { lat: 34.6851, lon: 135.8048, iso: 'JPN', country: 'Japan' }, 'Corvallis': { lat: 44.5646, lon: -123.262, iso: 'USA', country: 'United States' }, 'Valencia': { lat: 39.4699, lon: -0.3763, iso: 'ESP', country: 'Spain' }, 'Lucca': { lat: 43.8430, lon: 10.5079, iso: 'ITA', country: 'Italy' }, 'Dubai': { lat: 25.2048, lon: 55.2708, iso: 'ARE', country: 'United Arab Emirates' }, 'Las Vegas': { lat: 36.1699, lon: -115.1398, iso: 'USA', country: 'United States' }, 'Kuala Lumpur': { lat: 3.1390, lon: 101.6869, iso: 'MYS', country: 'Malaysia' }, 'Rome': { lat: 41.9028, lon: 12.4964, iso: 'ITA', country: 'Italy' }, 'Monterey': { lat: 36.6002, lon: -121.8947, iso: 'USA', country: 'United States' }, 'Tempe': { lat: 33.4255, lon: -111.9400, iso: 'USA', country: 'United States' }, 'Ioannina': { lat: 39.6650, lon: 20.8537, iso: 'GRC', country: 'Greece' }, 'Seoul': { lat: 37.5665, lon: 126.9780, iso: 'KOR', country: 'South Korea' }, 'Helsinki': { lat: 60.1699, lon: 24.9384, iso: 'FIN', country: 'Finland' }, 'London': { lat: 51.5074, lon: -0.1278, iso: 'GBR', country: 'United Kingdom' }, 'Madrid': { lat: 40.4168, lon: -3.7038, iso: 'ESP', country: 'Spain' }, 'Jeju': { lat: 33.4996, lon: 126.5312, iso: 'KOR', country: 'South Korea' }, 'Marrakesh': { lat: 31.6295, lon: -7.9811, iso: 'MAR', country: 'Morocco' }, 'Abu Dhabi': { lat: 24.4539, lon: 54.3773, iso: 'ARE', country: 'United Arab Emirates' }, 'Calgary': { lat: 51.0447, lon: -114.0719, iso: 'CAN', country: 'Canada' }, 'Kansas City': { lat: 39.0997, lon: -94.5786, iso: 'USA', country: 'United States' }, 'Kalamata': { lat: 37.0366, lon: 22.1144, iso: 'GRC', country: 'Greece' }, 'Barcelona': { lat: 41.3851, lon: 2.1734, iso: 'ESP', country: 'Spain' }, 'Singapore': { lat: 1.3521, lon: 103.8198, iso: 'SGP', country: 'Singapore' }, 'Paris': { lat: 48.8566, lon: 2.3522, iso: 'FRA', country: 'France' }, 'Toronto': { lat: 43.6532, lon: -79.3832, iso: 'CAN', country: 'Canada' }, 'Washington': { lat: 38.9072, lon: -77.0369, iso: 'USA', country: 'United States' }, 'Garden Grove': { lat: 33.7739, lon: -117.9414, iso: 'USA', country: 'United States' }, 'Austin': { lat: 30.2672, lon: -97.7431, iso: 'USA', country: 'United States' }, 'Ottawa': { lat: 45.4215, lon: -75.6972, iso: 'CAN', country: 'Canada' }, 'Stockholm': { lat: 59.3293, lon: 18.0686, iso: 'SWE', country: 'Sweden' }, 'Gothenburg': { lat: 57.7089, lon: 11.9746, iso: 'SWE', country: 'Sweden' }, 'Bologna': { lat: 44.4949, lon: 11.3426, iso: 'ITA', country: 'Italy' }, 'Padova': { lat: 45.4064, lon: 11.8768, iso: 'ITA', country: 'Italy' }, 'Santa Cruz': { lat: 36.9741, lon: -122.0308, iso: 'USA', country: 'United States' }, 'Irvine': { lat: 33.6846, lon: -117.8265, iso: 'USA', country: 'United States' }, 'Ankara': { lat: 39.9334, lon: 32.8597, iso: 'TUR', country: 'T\u00fcrkiye' }, 'Jeddah': { lat: 21.4858, lon: 39.1925, iso: 'SAU', country: 'Saudi Arabia' }, 'Dammam': { lat: 26.4207, lon: 50.0888, iso: 'SAU', country: 'Saudi Arabia' }, 'Ames': { lat: 42.0308, lon: -93.6319, iso: 'USA', country: 'United States' }, 'Macau': { lat: 22.1987, lon: 113.5439, iso: 'CHN', country: 'China' }, 'Alexandria': { lat: 31.2001, lon: 29.9187, iso: 'EGY', country: 'Egypt' }, 'Manchester': { lat: 53.4808, lon: -2.2426, iso: 'GBR', country: 'United Kingdom' }, 'Southampton': { lat: 50.9097, lon: -1.4044, iso: 'GBR', country: 'United Kingdom' }, 'Guildford': { lat: 51.2362, lon: -0.5704, iso: 'GBR', country: 'United Kingdom' }, 'Astana': { lat: 51.1605, lon: 71.4704, iso: 'KAZ', country: 'Kazakhstan' }, 'Rio de Janeiro': { lat: -22.9068, lon: -43.1729, iso: 'BRA', country: 'Brazil' }, 'Cairo': { lat: 30.0444, lon: 31.2357, iso: 'EGY', country: 'Egypt' }, 'San Antonio': { lat: 29.4241, lon: -98.4936, iso: 'USA', country: 'United States' }, 'San Francisco': { lat: 37.7749, lon: -122.4194, iso: 'USA', country: 'United States' }, }; function resolveCity(pub) { const hay = ((pub.v || '') + ' ' + (pub.loc || '')).toLowerCase(); for (const key of Object.keys(CITIES)) { if (hay.includes(key.toLowerCase())) return Object.assign({ key }, CITIES[key]); } return null; } // Extra map locations that aren't tied to a talk/paper entry (e.g. award trips). // Shown as pins + country fill on BOTH the conference and dissemination maps. const EXTRA_PINS = [ { key: 'Rio de Janeiro', n: 1 }, ]; function mergeExtraGeo(geo) { const countries = geo.countries.map((c) => ({ ...c })); const cities = geo.cities.map((c) => ({ ...c })); const isoIndex = {}; countries.forEach((c) => { isoIndex[c.iso] = c; }); const cityIndex = {}; cities.forEach((c) => { cityIndex[c.key] = c; }); EXTRA_PINS.forEach((e) => { const loc = CITIES[e.key]; if (!loc) return; const n = e.n || 1; if (isoIndex[loc.iso]) { isoIndex[loc.iso].n += n; } else { const o = { iso: loc.iso, name: loc.country, n }; isoIndex[loc.iso] = o; countries.push(o); } if (cityIndex[e.key]) { cityIndex[e.key].n += n; } else { const o = { key: e.key, lon: loc.lon, lat: loc.lat, country: loc.country, n }; cityIndex[e.key] = o; cities.push(o); } }); return { countries: countries.sort((a, b) => b.n - a.n), cities }; } function tallyConfGeo(P) { const counts = {}; const cities = {}; (P.proceedings || []).forEach((p) => { const c = resolveCity(p); if (!c) return; counts[c.iso] = counts[c.iso] || { iso: c.iso, name: c.country, n: 0 }; counts[c.iso].n += 1; cities[c.key] = cities[c.key] || { key: c.key, lon: c.lon, lat: c.lat, country: c.country, n: 0 }; cities[c.key].n += 1; }); return mergeExtraGeo({ countries: Object.values(counts), cities: Object.values(cities) }); } const SERIES = [ [/globecom/i, 'GLOBECOM'], [/\bICC\b|International Conference on Communications/i, 'ICC'], [/PIMRC|Personal, Indoor and Mobile/i, 'PIMRC'], [/WCNC|Wireless Communications and Networking/i, 'WCNC'], [/SPAWC|Signal Processing Advances/i, 'SPAWC'], [/asilomar|ACSSC/i, 'ASILOMAR'], [/Vehicular Technology|\bVTC\b/i, 'VTC'], [/Medicine and Biology|EMBC/i, 'EMBC'], [/E-?health|HealthCom/i, 'HealthCom'], [/Body Sensor|\bBSN\b/i, 'BSN'], [/Consumer Communications|CCNC/i, 'CCNC'], [/Midwest|MWSCAS/i, 'MWSCAS'], [/ISCAS|Symposium on Circuits/i, 'ISCAS'], [/ICASSP|Acoustics, Speech/i, 'ICASSP'], [/ICT Convergence|ICTC/i, 'ICTC'], [/Computing, Networking|ICNC/i, 'ICNC'], [/ICCSPA/i, 'ICCSPA'], [/Sensor Array|\bSAM\b/i, 'SAM'], [/Middle East Conf|MECOM/i, 'MECOM'], [/Biomedical Circuits|BIOCAS|BioCAS/i, 'BIOCAS'], [/Radar Conf|RadarConf/i, 'RadarConf'], [/\bSPIE\b|Photonics West/i, 'SPIE'], [/Biomedical and Healthcare|\bBHI\b/i, 'BHI'], ]; function seriesFor(pub) { const hay = (pub.v || '') + ' ' + (pub.loc || ''); for (const [re, s] of SERIES) { if (re.test(hay)) return s; } return (pub.v || 'Other').split(',')[0].slice(0, 16); } function tallyConfSeries(P) { const counts = {}; (P.proceedings || []).forEach((p) => { const s = seriesFor(p); counts[s] = counts[s] || { key: s, n: 0 }; counts[s].n += 1; }); return Object.values(counts).sort((a, b) => b.n - a.n); } function WorldMap({ countries, cities, title, hint }) { const [geo, setGeo] = React.useState(null); const [failed, setFailed] = React.useState(false); React.useEffect(() => { const CK = 'wintel_world_geo_v1'; try { const c = localStorage.getItem(CK); if (c) { setGeo(JSON.parse(c)); return; } } catch (e) {} fetch('https://cdn.jsdelivr.net/gh/johan/world.geo.json@master/countries.geo.json') .then((r) => r.ok ? r.json() : Promise.reject()) .then((g) => { setGeo(g); try { localStorage.setItem(CK, JSON.stringify(g)); } catch (e) {} }) .catch(() => setFailed(true)); }, []); const countByIso = {}; countries.forEach((c) => { countByIso[c.iso] = c.n; }); const max = Math.max(1, ...countries.map((c) => c.n)); const proj = (lon, lat) => [lon + 180, 90 - lat]; const pathFor = (geom) => { const polys = geom.type === 'Polygon' ? [geom.coordinates] : geom.coordinates; let d = ''; polys.forEach((poly) => poly.forEach((ring) => { ring.forEach((pt, i) => { const xy = proj(pt[0], pt[1]); d += (i === 0 ? 'M' : 'L') + xy[0].toFixed(2) + ' ' + xy[1].toFixed(2); }); d += 'Z'; })); return d; }; // --- pan & zoom --- const BASE = { x: 0, y: 16, w: 360, h: 124 }; const clampVB = (x, y, w, h) => ({ x: Math.max(0, Math.min(360 - w, x)), y: Math.max(0, Math.min(180 - h, y)), w, h }); const [vb, setVb] = React.useState(BASE); const [dragging, setDragging] = React.useState(false); const svgRef = React.useRef(null); const vbRef = React.useRef(vb); vbRef.current = vb; const dragRef = React.useRef(null); React.useEffect(() => { const svg = svgRef.current; if (!svg) return; const onWheel = (e) => { e.preventDefault(); const rect = svg.getBoundingClientRect(); const px = (e.clientX - rect.left) / rect.width, py = (e.clientY - rect.top) / rect.height; const v = vbRef.current; const factor = e.deltaY < 0 ? 0.85 : 1 / 0.85; const nw = Math.max(24, Math.min(360, v.w * factor)); const nh = nw * (BASE.h / BASE.w); const cx = v.x + px * v.w, cy = v.y + py * v.h; setVb(clampVB(cx - px * nw, cy - py * nh, nw, nh)); }; svg.addEventListener('wheel', onWheel, { passive: false }); return () => svg.removeEventListener('wheel', onWheel); }, []); const zoomBy = (factor) => setVb((v) => { const nw = Math.max(24, Math.min(360, v.w * factor)); const nh = nw * (BASE.h / BASE.w); const cx = v.x + v.w / 2, cy = v.y + v.h / 2; return clampVB(cx - nw / 2, cy - nh / 2, nw, nh); }); const onPointerDown = (e) => { dragRef.current = { x: e.clientX, y: e.clientY, vb: vbRef.current, rect: e.currentTarget.getBoundingClientRect() }; setDragging(true); e.currentTarget.setPointerCapture(e.pointerId); }; const onPointerMove = (e) => { const d = dragRef.current; if (!d) return; const dx = (e.clientX - d.x) / d.rect.width * d.vb.w; const dy = (e.clientY - d.y) / d.rect.height * d.vb.h; setVb(clampVB(d.vb.x - dx, d.vb.y - dy, d.vb.w, d.vb.h)); }; const onPointerUp = () => { dragRef.current = null; setDragging(false); }; const vbStr = vb.x.toFixed(2) + ' ' + vb.y.toFixed(2) + ' ' + vb.w.toFixed(2) + ' ' + vb.h.toFixed(2); const mapBtn = { width: '1.6rem', height: '1.6rem', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 0, borderRadius: 'var(--radius-sm)', border: '1px solid var(--border-default)', background: 'var(--surface-card)', color: 'var(--text-body)', cursor: 'pointer', fontSize: 15, lineHeight: 1 }; return (
    {!geo ? [30, 60, 90, 120].map((y) => ) : null} {geo ? geo.features.map((f, i) => { const n = countByIso[f.id] || 0; return ( {n ? {f.properties.name + ': ' + n + ' paper' + (n > 1 ? 's' : '')} : null} ); }) : null} {cities.map((c, i) => { const xy = proj(c.lon, c.lat); const r = (0.9 + Math.sqrt(c.n) * 1.0) * (vb.w / BASE.w); return ( {c.key + ', ' + c.country + ': ' + c.n + ' paper' + (c.n > 1 ? 's' : '')} ); })}
    {failed ? Country outlines need a connection; showing city markers only. : null}
    ); } function ChartPanel({ title, hint, children }) { return (

    {title}

    {hint ? {hint} : null}
    {children}
    ); } function StatBox({ value, label }) { return (
    {value} {label}
    ); } function CitationsChart() { const m = SCHOLAR_METRICS; const max = Math.max(...m.citationsByYear.map((d) => d.c)); const fmt = (n) => n >= 1000 ? (n / 1000).toFixed(n >= 10000 ? 0 : 1).replace(/\.0$/, '') + 'k' : String(n); return (
    {m.citationsByYear.map((d) => (
    {fmt(d.c)}
    {String(d.year).slice(2)}
    ))}
    {m.profileUrl ? (
    View on Google Scholar
    ) : null} ); } // Count journal articles (not conf / chapters) by quartile. function tallyQuartiles(P) { const all = [...(P.inPress || []), ...(P.articles || [])]; const counts = { Q1: 0, Q2: 0, Q3: 0, Q4: 0 }; let unranked = 0; all.forEach((p) => { if (p.conf || p.chapter) return; const q = QUARTILE[p.v]; if (q && counts[q] !== undefined) counts[q] += 1; else unranked += 1; }); return { counts, unranked }; } function QuartilePie() { const P = window.WINTEL_PUBLICATIONS || {}; const { counts, unranked } = tallyQuartiles(P); const order = ['Q1', 'Q2', 'Q3', 'Q4']; const data = order.map((q) => ({ q, n: counts[q], color: QUARTILE_COLOR[q] })).filter((d) => d.n > 0); const total = data.reduce((s, d) => s + d.n, 0); const cx = 80, cy = 80, R = 62, r = 38; let angle = -Math.PI / 2; const arcs = data.map((d) => { const frac = d.n / total; const a0 = angle, a1 = angle + frac * 2 * Math.PI - (data.length > 1 ? 0.015 : 0); angle += frac * 2 * Math.PI; const large = (a1 - a0) > Math.PI ? 1 : 0; const p = (ang, rad) => [cx + rad * Math.cos(ang), cy + rad * Math.sin(ang)]; const [x0, y0] = p(a0, R), [x1, y1] = p(a1, R), [xi1, yi1] = p(a1, r), [xi0, yi0] = p(a0, r); const dPath = `M${x0.toFixed(2)} ${y0.toFixed(2)} A${R} ${R} 0 ${large} 1 ${x1.toFixed(2)} ${y1.toFixed(2)} L${xi1.toFixed(2)} ${yi1.toFixed(2)} A${r} ${r} 0 ${large} 0 ${xi0.toFixed(2)} ${yi0.toFixed(2)} Z`; return { ...d, dPath, pct: Math.round(frac * 100) }; }); return (
    {arcs.length === 0 ? ( ) : arcs.map((a) => ( {a.q + ': ' + a.n + ' (' + a.pct + '%)'} ))} {total} RANKED
    {data.map((d) => (
    {d.q} {d.n} · {Math.round(d.n / total * 100)}%
    ))} {unranked ? + {unranked} unranked / too new : null}
    ); } function HBarChart({ title, hint, rows, total, colorFor }) { const max = Math.max(...rows.map((r) => r.n), 1); return (
    {rows.map((r) => (
    {r.key}
    {r.n}
    ))}
    ); } function PubStatBoxes() { const m = SCHOLAR_METRICS; const P = window.WINTEL_PUBLICATIONS || {}; const fmt = (n) => n >= 1000 ? (n / 1000).toFixed(n >= 10000 ? 0 : 1).replace(/\.0$/, '') + 'k' : String(n); const journals = (P.inPress || []).length + (P.articles || []).length; const proceedings = (P.proceedings || []).length; const chapters = (P.bookChapters || []).length; const totalPubs = journals + proceedings + chapters; return (
    ); } function PubStats() { const P = window.WINTEL_PUBLICATIONS; const journalVenues = React.useMemo(() => tallyJournalVenues(P).slice(0, 12).map((v) => ({ ...v, key: v.short })), [P]); const topics = React.useMemo(() => tallyTopics(P).map((t) => ({ ...t, key: t.label })), [P]); const geo = React.useMemo(() => tallyConfGeo(P), [P]); const series = React.useMemo(() => tallyConfSeries(P), [P]); const countryRows = geo.countries.map((c) => ({ key: c.name, full: c.name, n: c.n })); return (
    chartAccent()} /> r.color} />
    chartAccent()} /> chartAccent()} />
    ); } function BibModal({ pub, onClose }) { const [copied, setCopied] = React.useState(false); const text = React.useMemo(() => bibtex(pub), [pub]); React.useEffect(() => { const onKey = (e) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('keydown', onKey); return () => document.removeEventListener('keydown', onKey); }, [onClose]); const copy = () => { navigator.clipboard.writeText(text).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1600); }); }; const download = () => { const blob = new Blob([text], { type: 'text/plain;charset=utf-8' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = bibKey(pub) + '.bib'; a.click(); setTimeout(() => URL.revokeObjectURL(a.href), 1000); }; return (
    e.stopPropagation()} style={{ width: '100%', maxWidth: '640px', background: 'var(--surface-card)', border: '1px solid var(--border-default)', borderRadius: 'var(--radius-xl)', boxShadow: 'var(--shadow-lg, 0 20px 50px rgba(0,0,0,0.3))', display: 'flex', flexDirection: 'column', maxHeight: '80vh', overflow: 'hidden' }}>

    BibTeX record

    {text}
    Download .bib {copied ? 'Copied' : 'Copy'}
    ); } function PublicationsView({ data, onNavigate }) { const P = window.WINTEL_PUBLICATIONS; const tabs = [ { key: 'articles', label: 'Articles', list: [...(P.inPress || []), ...P.articles] }, { key: 'proceedings', label: 'Proceedings', list: P.proceedings }, { key: 'bookChapters', label: 'Book Chapters', list: P.bookChapters }, ]; const [active, setActive] = React.useState('articles'); const [bibPub, setBibPub] = React.useState(null); const [showStats, setShowStats] = React.useState(false); const current = tabs.find((t) => t.key === active); const grouped = groupByYear(current.list); let counter = 0; return (
    {showStats ? : null}
    {tabs.map((t) => ( setActive(t.key)}> {t.label} {t.list.length} ))}
    {current.list.length === 0 ? (

    No {current.label.toLowerCase()} in the provided bibliography.

    ) : (
    {grouped.map((g) => (

    {g.year === 'Forthcoming' ? 'In Press' : g.year}

    {g.items.length}
      {g.items.map((pub, i) => { counter += 1; return ( ); })}
    ))}
    )} {bibPub ? setBibPub(null)} /> : null}
    ); } Object.assign(window, { PublicationsView, topicsFor, TopicTag, flagForText, TOPICS, WorldMap, ChartPanel, HBarChart, StatBox, chartAccent, resolveCity, mergeExtraGeo, venueTag, VenueTag });