/* job-match.jsx — job description keyword analyzer */ var JM_STOP = {}; "a an and are as at be by do does did for from has have he her him his how i if in into is it its me my no not of on or our she so than that the their them then they this to up us was we were what when who will with you your been being also both but can even just like may more most much only other over re same see should since some such there these those through under very was well were which while".split(" ").forEach(function(w) { JM_STOP[w] = true; }); function jmTokenize(text) { return (text || "").toLowerCase().match(/[a-z][a-z0-9+#./\-]*/g) || []; } function jmExtractKeywords(text) { var words = jmTokenize(text); var freq = {}; words.forEach(function(w) { if (w.length > 2 && !JM_STOP[w]) freq[w] = (freq[w] || 0) + 1; }); // Bigrams for multi-word phrases for (var i = 0; i < words.length - 1; i++) { var a = words[i], b = words[i + 1]; if (a.length > 2 && b.length > 2 && !JM_STOP[a] && !JM_STOP[b]) { var bi = a + " " + b; freq[bi] = (freq[bi] || 0) + 0.5; } } return Object.entries(freq).sort(function(a, b) { return b[1] - a[1]; }).slice(0, 80).map(function(e) { return e[0]; }); } function jmResumeText(data) { var parts = []; var b = data.basics || {}; [b.name, b.title, b.location, b.summary].forEach(function(x) { if (x) parts.push(x); }); if (data.summary) parts.push(data.summary); (data.experience || []).forEach(function(x) { [x.role, x.company, x.location, x.detail].forEach(function(v) { if (v) parts.push(v); }); (x.bullets || []).forEach(function(bl) { if (bl) parts.push(bl); }); }); (data.projects || []).forEach(function(p) { [p.name, p.tech, p.detail].forEach(function(v) { if (v) parts.push(v); }); (p.bullets || []).forEach(function(bl) { if (bl) parts.push(bl); }); }); (data.education || []).forEach(function(e) { [e.degree, e.school, e.detail].forEach(function(v) { if (v) parts.push(v); }); }); (data.skills || []).forEach(function(g) { if (g.group) parts.push(g.group); (g.items || []).forEach(function(it) { if (it) parts.push(it); }); }); (data.certs || []).forEach(function(c) { if (c) parts.push(c); }); (data.custom || []).forEach(function(c) { if (c.heading) parts.push(c.heading); if (c.body) parts.push(c.body.replace(/<[^>]*>/g, " ")); }); return parts.join(" ").toLowerCase(); } function jmAnalyze(data, jdText) { if (!jdText || !jdText.trim()) return null; var keywords = jmExtractKeywords(jdText); var rtext = jmResumeText(data); var TOP = Math.min(keywords.length, 40); var topKw = keywords.slice(0, TOP); var matched = topKw.filter(function(kw) { return rtext.indexOf(kw) !== -1; }); var missing = topKw.filter(function(kw) { return rtext.indexOf(kw) === -1; }).slice(0, 24); var score = TOP > 0 ? Math.min(100, Math.round((matched.length / TOP) * 100)) : 0; return { score: score, matched: matched.slice(0, 20), missing: missing, total: TOP }; } function JobMatchDrawer({ data, onClose }) { var stateHook = React.useState(""); var jd = stateHook[0], setJd = stateHook[1]; var resultHook = React.useState(null); var result = resultHook[0], setResult = resultHook[1]; var busyHook = React.useState(false); var busy = busyHook[0], setBusy = busyHook[1]; var run = function() { if (!jd.trim()) return; setBusy(true); setTimeout(function() { setResult(jmAnalyze(data, jd)); setBusy(false); }, 200); }; var sc = result ? result.score : 0; var scColor = sc >= 80 ? "#16A36B" : sc >= 60 ? "#1C9BE6" : sc >= 40 ? "#E0A013" : "#E0533D"; var scLabel = sc >= 80 ? "Excellent match" : sc >= 60 ? "Good match" : sc >= 40 ? "Partial match" : "Low match"; return (

Job Match

Paste a job description to see how well your résumé aligns.