six-degrees 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +14 -14
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js +1 -1
- package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/favicon.ico.body +0 -0
- package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/import.html +1 -1
- package/.next/standalone/.next/server/app/import.rsc +2 -2
- package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/launch.html +2 -2
- package/.next/standalone/.next/server/app/launch.rsc +2 -2
- package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/paths.html +1 -1
- package/.next/standalone/.next/server/app/paths.rsc +3 -3
- package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/profile.html +1 -1
- package/.next/standalone/.next/server/app/profile.rsc +3 -3
- package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/queue.html +1 -1
- package/.next/standalone/.next/server/app/queue.rsc +3 -3
- package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/scores.html +1 -1
- package/.next/standalone/.next/server/app/scores.rsc +2 -2
- package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/setup.html +1 -1
- package/.next/standalone/.next/server/app/setup.rsc +3 -3
- package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0e0fei3._.js +1 -1
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__03ydxxh._.js → [root-of-the-server]__20tmem7._.js} +1 -1
- package/.next/standalone/.next/server/chunks/_1_fynia._.js +6 -6
- package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1iwkh8t._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1mxn_lb._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +21 -7
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00d8snt._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00g61b8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__08lf3gy._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hg5gib._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ho-u0w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ze473p._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1194jps._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1cnxxc9._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ll97ry._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m0255u._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1w9z0zv._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_15xuwkv._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1hgd5dp._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_20w06i-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +4 -4
- package/.next/standalone/.next/server/chunks/ssr/app_paths_page_1ol90m7.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +6 -2
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware-manifest.json +5 -5
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/static/chunks/{3e8zg6ctvvb8p.js → 049vavjsmqgmn.js} +3 -3
- package/.next/standalone/.next/static/chunks/0ljxa-wk_iu__.js +18 -0
- package/.next/standalone/.next/static/chunks/0mp9b72fm-jp6.js +6 -0
- package/.next/standalone/.next/static/chunks/1pre1cotntk6-.js +1 -0
- package/.next/standalone/.next/static/chunks/{18xu0fbgo_qz-.js → 22x2_r768-u5i.js} +1 -1
- package/.next/standalone/.next/static/chunks/2p5yt1o9tnxjn.js +2 -0
- package/.next/standalone/.next/static/chunks/3zs_6-nn0dapb.js +1 -0
- package/.next/standalone/.next/static/media/favicon.0zdzw5kurn8m-.ico +0 -0
- package/.next/standalone/CHANGELOG.md +86 -0
- package/.next/standalone/app/api/admin-delete/route.js +3 -0
- package/.next/standalone/app/api/ingest/route.js +13 -0
- package/.next/standalone/app/api/scraper/route.js +10 -2
- package/.next/standalone/app/components/ChainView.js +76 -15
- package/.next/standalone/app/components/FilterPanel.js +37 -1
- package/.next/standalone/app/components/ForceGraph.js +144 -12
- package/.next/standalone/app/components/LinkedInLimits.js +20 -3
- package/.next/standalone/app/components/OrbitGraph.js +92 -30
- package/.next/standalone/app/components/Sidebar.js +37 -0
- package/.next/standalone/app/components/views.js +7 -5
- package/.next/standalone/app/favicon.ico +0 -0
- package/.next/standalone/app/page.js +24 -7
- package/.next/standalone/app/paths/page.js +8 -1
- package/.next/standalone/db/schema.js +14 -0
- package/.next/standalone/lib/brokerage.js +94 -0
- package/.next/standalone/lib/chain-layout.js +89 -0
- package/.next/standalone/lib/circle.js +23 -4
- package/.next/standalone/lib/degrees.js +30 -0
- package/.next/standalone/lib/dot-rings.js +21 -0
- package/.next/standalone/lib/ingest.js +3 -3
- package/.next/standalone/lib/linkedin-limits.js +9 -4
- package/.next/standalone/lib/reach.js +22 -1
- package/.next/standalone/lib/search-risk.js +38 -0
- package/.next/standalone/lib/ties.js +23 -0
- package/.next/standalone/package-lock.json +2 -2
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/scripts/scrape.py +50 -12
- package/.next/static/chunks/{3e8zg6ctvvb8p.js → 049vavjsmqgmn.js} +3 -3
- package/.next/static/chunks/0ljxa-wk_iu__.js +18 -0
- package/.next/static/chunks/0mp9b72fm-jp6.js +6 -0
- package/.next/static/chunks/1pre1cotntk6-.js +1 -0
- package/.next/static/chunks/{18xu0fbgo_qz-.js → 22x2_r768-u5i.js} +1 -1
- package/.next/static/chunks/2p5yt1o9tnxjn.js +2 -0
- package/.next/static/chunks/3zs_6-nn0dapb.js +1 -0
- package/.next/static/media/favicon.0zdzw5kurn8m-.ico +0 -0
- package/CHANGELOG.md +86 -0
- package/db/schema.js +14 -0
- package/lib/brokerage.js +94 -0
- package/lib/chain-layout.js +89 -0
- package/lib/circle.js +23 -4
- package/lib/degrees.js +30 -0
- package/lib/dot-rings.js +21 -0
- package/lib/ingest.js +3 -3
- package/lib/linkedin-limits.js +9 -4
- package/lib/reach.js +22 -1
- package/lib/search-risk.js +38 -0
- package/lib/ties.js +23 -0
- package/package.json +1 -1
- package/scripts/scrape.py +50 -12
- package/.next/standalone/.next/static/chunks/0w76iraw7ij3k.js +0 -18
- package/.next/standalone/.next/static/chunks/135n87ydxjrra.js +0 -2
- package/.next/standalone/.next/static/chunks/2pnbm1z6j7xab.js +0 -1
- package/.next/standalone/.next/static/chunks/3qh78g2aqhprd.js +0 -2
- package/.next/standalone/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
- package/.next/static/chunks/0w76iraw7ij3k.js +0 -18
- package/.next/static/chunks/135n87ydxjrra.js +0 -2
- package/.next/static/chunks/2pnbm1z6j7xab.js +0 -1
- package/.next/static/chunks/3qh78g2aqhprd.js +0 -2
- package/.next/static/media/favicon.2vob68tjqpejf.ico +0 -0
- /package/.next/standalone/.next/static/{WseE_5HuU-1q0ywC9CP3U → wGVrXBkFLmEB4snfhtOcO}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{WseE_5HuU-1q0ywC9CP3U → wGVrXBkFLmEB4snfhtOcO}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{WseE_5HuU-1q0ywC9CP3U → wGVrXBkFLmEB4snfhtOcO}/_ssgManifest.js +0 -0
- /package/.next/static/{WseE_5HuU-1q0ywC9CP3U → wGVrXBkFLmEB4snfhtOcO}/_buildManifest.js +0 -0
- /package/.next/static/{WseE_5HuU-1q0ywC9CP3U → wGVrXBkFLmEB4snfhtOcO}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{WseE_5HuU-1q0ywC9CP3U → wGVrXBkFLmEB4snfhtOcO}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,85957,e=>{"use strict";var t=e.i(43476),n=e.i(71645),i=e.i(18566),o=e.i(40996),r=e.i(19821),l=e.i(64745),s=e.i(7837),a=e.i(2776);e.i(47716);var d=e.i(36534),c=e.i(77899),p=e.i(17983),h=e.i(43079),f=e.i(23731),u=e.i(94657),g=e.i(89154);let y={S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"},x="1px solid rgba(255,255,255,0.1)",m=[...g.INDUSTRIES,g.UNKNOWN_INDUSTRY];function b(e){let t=0x811c9dc5;for(let n=0;n<e.length;n++)t=Math.imul(t^e.charCodeAt(n),0x1000193);return(t>>>0)%1e3/1e3}function k({value:e,onChange:n,options:i}){return(0,t.jsx)("div",{style:{display:"flex",borderRadius:7,overflow:"hidden",border:x},children:i.map(([i,o])=>(0,t.jsx)("button",{onClick:()=>n(i),style:{padding:"5px 10px",fontSize:11.5,fontWeight:600,border:"none",cursor:"pointer",background:e===i?"rgba(52,152,219,0.25)":"transparent",color:e===i?"#cfe6f7":"#8b9a9a"},children:o},i))})}function v(e,t){return("all"===t.degree||String(e.degree)===t.degree)&&("senior"!==t.seniority||!!(0,g.isSenior)(e.headline))&&("csuite"!==t.seniority||!((0,g.getSeniority)(e.headline).level<6))&&("SA"!==t.tier||"S"===e.tier||"A"===e.tier)}function j({d1:e=[],d2:i=[],d3:o=[],tab:r="map",onOpenCompany:l}){let[s,a]=(0,n.useState)({degree:"all",seniority:"all",tier:"all"}),[d,c]=(0,n.useState)(()=>new Set),[p,h]=(0,n.useState)(""),[f,u]=(0,n.useState)(null),y=(0,n.useMemo)(()=>[...e,...i,...o],[e,i,o]),x=(0,n.useMemo)(()=>(0,g.buildCompanyIndex)(y),[y]),b=(0,n.useMemo)(()=>(0,g.companyLinks)(e,i),[e,i]),k=(0,n.useMemo)(()=>{let e=p.trim().toLowerCase(),t=[];for(let n of x.values()){if(d.has(n.industry.key)||e&&!n.name.toLowerCase().includes(e))continue;let i=n.people.filter(e=>v(e,s));i.length&&t.push({...n,shown:i})}return t.sort((e,t)=>t.shown.length-e.shown.length)},[x,s,d,p]),C=(0,n.useMemo)(()=>{let e=new Map(m.map(e=>[e.key,{...e,people:[],companies:new Map}])),t=new Set;for(let n of y){let i=n.profile_url||`id:${n.id}`;if(t.has(i)||(t.add(i),!v(n,s)))continue;let o=(0,g.companyOf)(n),r=o?x.get(o)?.industry||(0,g.industryOf)(o,n.headline):(0,g.industryOf)(null,n.headline),l=e.get(r.key);l.people.push(n),o&&l.companies.set(o,(l.companies.get(o)||0)+1)}return[...e.values()].filter(e=>e.people.length).sort((e,t)=>t.people.length-e.people.length)},[y,x,s]),z=f?.kind==="company"?x.get(f.key):f?.kind==="industry"?C.find(e=>e.key===f.key):null;return(0,t.jsxs)("div",{style:{display:"flex",flex:1,minHeight:0},children:[(0,t.jsxs)("div",{style:{flex:1,minWidth:0,display:"flex",flexDirection:"column"},children:[(0,t.jsx)(S,{filters:s,setFilters:a,query:p,setQuery:h,industries:C,hidden:d,setHidden:c,onIndustry:e=>u({kind:"industry",key:e})}),"map"===r?(0,t.jsx)(w,{companies:k,links:b,focus:f,onCompany:e=>u({kind:"company",key:e}),onIndustry:e=>u({kind:"industry",key:e}),onClear:()=>u(null)}):(0,t.jsx)(M,{industries:C,index:x,d1:e,d2:i,onIndustry:e=>u({kind:"industry",key:e}),onCompany:e=>u({kind:"company",key:e})})]}),z&&(0,t.jsx)(B,{focus:f,data:z,index:x,links:b,d1:e,d2:i,filters:s,onClose:()=>u(null),onCompany:e=>u({kind:"company",key:e}),onOpenCompany:l})]})}function S({filters:e,setFilters:n,query:i,setQuery:o,industries:r,hidden:l,setHidden:s,onIndustry:a}){let d=(e,t)=>n(n=>({...n,[e]:t}));return(0,t.jsxs)("div",{style:{padding:"10px 16px",borderBottom:x,display:"flex",flexDirection:"column",gap:8},children:[(0,t.jsxs)("div",{style:{display:"flex",gap:8,flexWrap:"wrap",alignItems:"center"},children:[(0,t.jsx)("input",{value:i,onChange:e=>o(e.target.value),placeholder:"Find a company",style:{padding:"6px 10px",borderRadius:7,border:x,background:"rgba(255,255,255,0.05)",color:"#fff",fontSize:13,minWidth:170}}),(0,t.jsx)(k,{value:e.degree,onChange:e=>d("degree",e),options:[["all","All degrees"],["1","1st"],["2","2nd"],["3","3rd"]]}),(0,t.jsx)(k,{value:e.seniority,onChange:e=>d("seniority",e),options:[["all","Any level"],["senior","Director+"],["csuite","C-suite"]]}),(0,t.jsx)(k,{value:e.tier,onChange:e=>d("tier",e),options:[["all","All tiers"],["SA","S & A only"]]})]}),(0,t.jsxs)("div",{style:{display:"flex",gap:6,flexWrap:"wrap"},children:[r.map(e=>{let n=l.has(e.key);return(0,t.jsxs)("span",{style:{display:"inline-flex",borderRadius:14,border:`1px solid ${e.color}55`,overflow:"hidden",opacity:n?.4:1},children:[(0,t.jsx)("button",{title:n?"Show on the map":"Hide from the map",onClick:()=>s(t=>{let n=new Set(t);return n.has(e.key)?n.delete(e.key):n.add(e.key),n}),style:{padding:"3px 7px",border:"none",background:`${e.color}22`,cursor:"pointer",color:e.color,fontSize:11},children:"●"}),(0,t.jsxs)("button",{onClick:()=>a(e.key),title:"Analyse this industry",style:{padding:"3px 9px 3px 5px",border:"none",background:"transparent",cursor:"pointer",color:"#cfd8d8",fontSize:11.5},children:[e.label," ",(0,t.jsx)("span",{style:{color:"#778"},children:e.people.length})]})]},e.key)}),(0,t.jsx)("span",{style:{fontSize:11,color:"#667",alignSelf:"center"},children:"industries inferred from companies and headlines"})]})]})}function w({companies:e,links:i,focus:o,onCompany:r,onIndustry:l,onClear:s}){let a=(0,n.useRef)(null),{w:u,h:x}=function(e){let[t,i]=(0,n.useState)({w:0,h:0});return(0,n.useEffect)(()=>{let t=e.current;if(!t)return;let n=()=>{let e=t.getBoundingClientRect();i(t=>t.w===Math.round(e.width)&&t.h===Math.round(e.height)?t:{w:Math.round(e.width),h:Math.round(e.height)})};n();let o=new ResizeObserver(n);return o.observe(t),()=>o.disconnect()},[e]),t}(a),[m,k]=(0,n.useState)(null),v=(0,n.useMemo)(()=>{let t=e.slice(0,140),n=new Set(t.map(e=>e.name)),o=[...new Set(t.map(e=>e.industry.key))],r=new Map(o.map((e,t)=>{let n=t/Math.max(1,o.length)*Math.PI*2-Math.PI/2;return[e,{x:260*Math.cos(n),y:260*Math.sin(n)}]})),l=t.map(e=>({id:e.name,co:e,r:4+3.4*Math.sqrt(e.shown.length),x:r.get(e.industry.key).x+(b(e.name)-.5)*40,y:r.get(e.industry.key).y+(b(e.name+"#")-.5)*40})),s=i.filter(e=>n.has(e.a)&&n.has(e.b)).map(e=>({source:e.a,target:e.b,weight:e.weight,via:e.via.size})),a=(0,h.forceSimulation)(l).force("x",(function(e){var t,n,i,o=(0,f.default)(.1);function r(e){for(var o,r=0,l=t.length;r<l;++r)o=t[r],o.vx+=(i[r]-o.x)*n[r]*e}function l(){if(t){var r,l=t.length;for(n=Array(l),i=Array(l),r=0;r<l;++r)n[r]=isNaN(i[r]=+e(t[r],r,t))?0:+o(t[r],r,t)}}return"function"!=typeof e&&(e=(0,f.default)(null==e?0:+e)),r.initialize=function(e){t=e,l()},r.strength=function(e){return arguments.length?(o="function"==typeof e?e:(0,f.default)(+e),l(),r):o},r.x=function(t){return arguments.length?(e="function"==typeof t?t:(0,f.default)(+t),l(),r):e},r})(e=>r.get(e.co.industry.key).x).strength(.12)).force("y",(function(e){var t,n,i,o=(0,f.default)(.1);function r(e){for(var o,r=0,l=t.length;r<l;++r)o=t[r],o.vy+=(i[r]-o.y)*n[r]*e}function l(){if(t){var r,l=t.length;for(n=Array(l),i=Array(l),r=0;r<l;++r)n[r]=isNaN(i[r]=+e(t[r],r,t))?0:+o(t[r],r,t)}}return"function"!=typeof e&&(e=(0,f.default)(null==e?0:+e)),r.initialize=function(e){t=e,l()},r.strength=function(e){return arguments.length?(o="function"==typeof e?e:(0,f.default)(+e),l(),r):o},r.y=function(t){return arguments.length?(e="function"==typeof t?t:(0,f.default)(+t),l(),r):e},r})(e=>r.get(e.co.industry.key).y).strength(.12)).force("collide",(0,d.forceCollide)(e=>e.r+3)).force("charge",(0,p.forceManyBody)().strength(-25)).force("link",(0,c.forceLink)(s).id(e=>e.id).strength(e=>Math.min(.25,.03*e.weight)).distance(60)).stop();for(let e=0;e<320;e++)a.tick();let u=l.flatMap(e=>[e.x-e.r,e.x+e.r]),y=l.flatMap(e=>[e.y-e.r,e.y+e.r]),x=l.length?{x:Math.min(...u)-60,y:Math.min(...y)-40,w:Math.max(...u)-Math.min(...u)+120,h:Math.max(...y)-Math.min(...y)+80}:{x:-300,y:-300,w:600,h:600},m=o.map(e=>{let t=l.filter(t=>t.co.industry.key===e),n=t.reduce((e,t)=>e+t.x,0)/t.length,i=t.reduce((e,t)=>e+t.y,0)/t.length,o=Math.hypot(n,i)||1,r=n/o,s=i/o,a=Math.max(...t.map(e=>(e.x-n)*r+(e.y-i)*s+e.r));return{key:e,x:n+r*(a+16),y:i+s*(a+16)+4,anchor:r>.35?"start":r<-.35?"end":"middle",ind:(0,g.industryByKey)(e)}});for(let e of m){let t=7.5*e.ind.label.length,n="start"===e.anchor?e.x:"end"===e.anchor?e.x-t:e.x-t/2,i=Math.max(x.x+x.w,n+t+10);x.x=Math.min(x.x,n-10),x.w=i-x.x;let o=Math.max(x.y+x.h,e.y+12);x.y=Math.min(x.y,e.y-18),x.h=o-x.y}return x.h+=Math.max(60,.1*x.h),{nodes:l,edges:s,box:x,labels:m,cut:Math.max(0,e.length-t.length)}},[e,i]),j=m||(o?.kind==="company"?o.key:null),S=o?.kind==="industry"?o.key:null,C=(0,n.useMemo)(()=>{if(!j)return null;let e=new Set([j]);for(let t of v.edges)t.source.id===j&&e.add(t.target.id),t.target.id===j&&e.add(t.source.id);return e},[j,v]),M=(0,n.useMemo)(()=>new Set(v.nodes.slice(0,28).map(e=>e.id)),[v]);return(0,t.jsxs)("div",{ref:a,style:{flex:1,minHeight:360,position:"relative"},onClick:s,children:[u>0&&(0,t.jsxs)("svg",{width:u,height:x,viewBox:`${v.box.x} ${v.box.y} ${v.box.w} ${v.box.h}`,style:{display:"block"},children:[(0,t.jsx)("g",{children:v.edges.map((e,n)=>{let i=j&&(e.source.id===j||e.target.id===j);return(0,t.jsx)("line",{x1:e.source.x,y1:e.source.y,x2:e.target.x,y2:e.target.y,stroke:i?"#FF6B35":"#8fa6c0",strokeOpacity:i?.8:j?.04:.14,strokeWidth:i?1+Math.log2(1+e.weight):.4+.5*Math.log2(1+e.weight)},n)})}),v.labels.map(e=>(0,t.jsx)("text",{x:e.x,y:e.y,textAnchor:e.anchor,fontSize:13,fontWeight:800,fill:e.ind.color,opacity:S&&S!==e.key?.25:.85,style:{cursor:"pointer"},onClick:t=>{t.stopPropagation(),l(e.key)},children:e.ind.label},e.key)),v.nodes.map(e=>{let n=C&&!C.has(e.id)||S&&e.co.industry.key!==S,i=o?.kind==="company"&&o.key===e.id;return(0,t.jsxs)("g",{transform:`translate(${e.x},${e.y})`,style:{cursor:"pointer"},opacity:n?.18:1,onMouseEnter:()=>k(e.id),onMouseLeave:()=>k(null),onClick:t=>{t.stopPropagation(),r(e.id)},children:[(0,t.jsx)("title",{children:`${e.co.name} \xb7 ${e.co.industry.label} (inferred)
|
|
2
|
+
${e.co.d1} you know \xb7 ${e.co.d2} reachable${e.co.d3?` \xb7 ${e.co.d3} further`:""}`}),(0,t.jsx)("circle",{r:e.r,fill:e.co.industry.color,fillOpacity:.75,stroke:i?"#fff":e.co.S?y.S:"rgba(0,0,0,0.35)",strokeWidth:i?2.5:e.co.S?1.5:.6}),e.co.d1>0&&(0,t.jsx)("circle",{r:e.r*Math.sqrt(e.co.d1/Math.max(1,e.co.people.length)),fill:"#fff",fillOpacity:.35}),(M.has(e.id)||e.id===j||i)&&(0,t.jsx)("text",{y:e.r+11,textAnchor:"middle",fontSize:10,fill:"#e6edf0",style:{pointerEvents:"none"},children:e.co.name})]},e.id)})]}),(0,t.jsxs)("div",{style:{position:"absolute",left:12,bottom:10,fontSize:11,color:"#778",lineHeight:1.6,pointerEvents:"none"},children:["Bubble = a company, sized by your people there; white centre = the share you already know; gold ring = an S-tier person inside.",(0,t.jsx)("br",{}),"A line = one of your connections at one company knows people at the other.",v.cut?` Showing the 140 largest; ${v.cut} smaller companies are in Industries.`:""]})]})}function C({parts:e,total:n}){return(0,t.jsx)("div",{style:{display:"flex",height:6,borderRadius:3,overflow:"hidden",background:"rgba(255,255,255,0.06)"},children:e.map(([e,i],o)=>(0,t.jsx)("div",{style:{width:`${e/Math.max(1,n)*100}%`,background:i}},o))})}function M({industries:e,index:i,d1:o,d2:r,onIndustry:l,onCompany:s}){let a=(0,n.useMemo)(()=>{let e=new Map(o.map(e=>[e.id,e])),t=new Map;for(let e of r){let n=(0,g.companyOf)(e),o=n?i.get(n)?.industry.key:(0,g.industryOf)(null,e.headline).key;if(!o)continue;let r=t.get(o)||new Map;r.set(e.source_connection_id,(r.get(e.source_connection_id)||0)+1),t.set(o,r)}let n=new Map;for(let[i,o]of t){let[t,r]=[...o.entries()].sort((e,t)=>t[1]-e[1])[0]||[];e.get(t)&&n.set(i,{bridge:e.get(t),n:r})}return n},[i,o,r]);return(0,t.jsx)("div",{style:{flex:1,overflow:"auto",padding:16},children:(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(280px, 1fr))",gap:12},children:e.map(e=>{let n=e.people.filter(e=>1===e.degree).length,i=e.people.filter(e=>2===e.degree).length,o=e.people.filter(e=>(0,g.isSenior)(e.headline)).length,r=e.people.filter(e=>"S"===e.tier).length,d=[...e.companies.entries()].sort((e,t)=>t[1]-e[1]).slice(0,3),c=a.get(e.key);return(0,t.jsxs)("div",{onClick:()=>l(e.key),style:{padding:14,borderRadius:10,border:x,borderTop:`3px solid ${e.color}`,background:"rgba(255,255,255,0.03)",cursor:"pointer"},children:[(0,t.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"baseline"},children:[(0,t.jsx)("b",{style:{fontSize:14,color:e.color},children:e.label}),(0,t.jsx)("span",{style:{fontSize:20,fontWeight:800},children:e.people.length})]}),(0,t.jsxs)("div",{style:{fontSize:11.5,color:"#8b9a9a",margin:"4px 0 6px"},children:[n," you know · ",i," reachable · ",e.companies.size," companies · ",o," director+ · ",r," S-tier"]}),(0,t.jsx)(C,{total:e.people.length,parts:[[n,"#00ff88"],[i,"#FF6B35"]]}),d.length>0&&(0,t.jsx)("div",{style:{marginTop:8,display:"flex",gap:6,flexWrap:"wrap"},children:d.map(([e,n])=>(0,t.jsxs)("button",{onClick:t=>{t.stopPropagation(),s(e)},style:{padding:"2px 8px",borderRadius:10,border:x,background:"rgba(255,255,255,0.05)",color:"#dfe6e9",fontSize:11,cursor:"pointer"},children:[e," ",(0,t.jsx)("span",{style:{color:"#778"},children:n})]},e))}),c&&(0,t.jsxs)("div",{style:{marginTop:8,fontSize:11.5,color:"#aab7b7"},children:["Best way in: ",(0,t.jsx)("b",{style:{color:y[c.bridge.tier]||"#ccc"},children:c.bridge.name})," knows ",c.n," here"]})]},e.key)})})})}function z({p:e,note:n}){return(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,padding:"5px 0",fontSize:12.5},children:[(0,t.jsx)("span",{style:{width:7,height:7,borderRadius:"50%",background:y[e.tier]||"#667",flexShrink:0}}),(0,t.jsxs)("div",{style:{minWidth:0,flex:1},children:[(0,t.jsx)("div",{style:{fontWeight:600,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.name}),(0,t.jsx)("div",{style:{fontSize:11,color:"#8b9a9a",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:n||e.headline})]})]})}function B({focus:e,data:i,index:o,links:r,d1:l,d2:s,filters:a,onClose:d,onCompany:c,onOpenCompany:p}){let h,f,u,y="company"===e.kind,m=i.people.filter(e=>v(e,a)),b=(0,n.useMemo)(()=>{let e=new Map;for(let t of m){let n=(0,g.getSeniority)(t.headline);e.set(n.label,{n:(e.get(n.label)?.n||0)+1,level:n.level})}return[...e.entries()].sort((e,t)=>t[1].level-e[1].level)},[m]),k=(0,n.useMemo)(()=>y?(0,g.waysInto)(i.name,l,s):null,[y,i,l,s]),j=(0,n.useMemo)(()=>y?r.filter(e=>e.a===i.name||e.b===i.name).map(e=>({name:e.a===i.name?e.b:e.a,weight:e.weight})).sort((e,t)=>t.weight-e.weight).slice(0,8):[],[y,r,i]),S=[...m].sort((e,t)=>(Number(t.power_score)||0)-(Number(e.power_score)||0)).slice(0,6),w=y?i.industry:i,M=m.filter(e=>1===e.degree).length,W=m.filter(e=>2===e.degree).length,I=y?[]:[...i.companies.entries()].sort((e,t)=>t[1]-e[1]).slice(0,10);return(0,t.jsxs)("aside",{style:{width:360,flexShrink:0,borderLeft:x,overflow:"auto",padding:16,background:"rgba(255,255,255,0.02)"},children:[(0,t.jsx)("button",{onClick:d,style:{background:"none",border:"none",color:"#888",cursor:"pointer",fontSize:12,padding:0},children:"✕ Close"}),(0,t.jsxs)("div",{style:{fontSize:10,letterSpacing:1,color:"#8b9a9a",marginTop:8},children:[y?"COMPANY":"INDUSTRY"," ANALYZER"]}),(0,t.jsx)("h2",{style:{margin:"4px 0 6px",fontSize:20},children:y?i.name:i.label}),(0,t.jsxs)("span",{style:{fontSize:11,padding:"2px 8px",borderRadius:10,background:`${w.color}22`,color:w.color},children:[w.label,y?" · inferred":""]}),y&&(0,t.jsx)(R,{name:i.name}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"repeat(3, 1fr)",gap:8,margin:"14px 0"},children:[[M,"you know","#00ff88"],[W,"reachable","#FF6B35"],[m.filter(e=>(0,g.isSenior)(e.headline)).length,"director+","#FFD700"]].map(([e,n,i])=>(0,t.jsxs)("div",{style:{padding:8,borderRadius:8,background:"rgba(255,255,255,0.04)",textAlign:"center"},children:[(0,t.jsx)("div",{style:{fontSize:20,fontWeight:800,color:i},children:e}),(0,t.jsx)("div",{style:{fontSize:10.5,color:"#8b9a9a"},children:n})]},n))}),(0,t.jsx)(F,{title:"By level",children:b.map(([e,{n}])=>(0,t.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"110px 1fr 28px",gap:8,alignItems:"center",fontSize:11.5,marginBottom:4},children:[(0,t.jsx)("span",{style:{color:"#aab7b7"},children:e}),(0,t.jsx)(C,{total:m.length,parts:[[n,"#3498DB"]]}),(0,t.jsx)("span",{style:{color:"#778",textAlign:"right"},children:n})]},e))}),y&&k&&(0,t.jsxs)(F,{title:"Ways in",children:[k.direct.length>0&&(0,t.jsxs)("div",{style:{fontSize:11,color:"#00ff88",margin:"2px 0"},children:["You already know ",k.direct.length," here"]}),(h=new Map(k.bridges.map(({bridge:e,n:t})=>[e.id,t])),f=[...k.direct].sort((e,t)=>(h.get(t.id)||0)-(h.get(e.id)||0)).slice(0,4),u=new Set(k.direct.map(e=>e.id)),(0,t.jsxs)(t.Fragment,{children:[f.map(e=>(0,t.jsx)(z,{p:e,note:h.get(e.id)?`works here \xb7 knows ${h.get(e.id)} here`:`works here \xb7 ${e.headline||""}`},e.id)),k.bridges.filter(({bridge:e})=>!u.has(e.id)).slice(0,5).map(({bridge:e,n})=>(0,t.jsx)(z,{p:e,note:`knows ${n} ${1===n?"person":"people"} here`},e.id))]})),!k.direct.length&&!k.bridges.length&&(0,t.jsx)("div",{style:{fontSize:12,color:"#778"},children:"No one you know links here yet."})]}),(0,t.jsx)(F,{title:y?"Most powerful people here":"Most powerful people in this industry",children:S.map(e=>(0,t.jsx)(z,{p:e,note:`${1===e.degree?"you know them":2===e.degree?"2nd degree":"3rd+"} \xb7 ${e.headline||""}`},e.id))}),y&&j.length>0&&(0,t.jsx)(F,{title:"Connected companies",children:(0,t.jsx)("div",{style:{display:"flex",gap:6,flexWrap:"wrap"},children:j.map(e=>(0,t.jsxs)("button",{onClick:()=>c(e.name),style:{padding:"3px 9px",borderRadius:10,border:x,background:`${o.get(e.name)?.industry.color||"#666"}22`,color:"#dfe6e9",fontSize:11.5,cursor:"pointer"},children:[e.name," ",(0,t.jsx)("span",{style:{color:"#778"},children:e.weight})]},e.name))})}),!y&&(0,t.jsx)(F,{title:"Companies",children:I.map(([e,n])=>(0,t.jsxs)("div",{onClick:()=>c(e),style:{display:"grid",gridTemplateColumns:"1fr 60px 24px",gap:8,alignItems:"center",fontSize:12,padding:"3px 0",cursor:"pointer"},children:[(0,t.jsx)("span",{style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e}),(0,t.jsx)(C,{total:I[0][1],parts:[[n,w.color]]}),(0,t.jsx)("span",{style:{color:"#778",textAlign:"right"},children:n})]},e))}),y&&p&&(0,t.jsxs)("button",{onClick:()=>p(i),style:{marginTop:14,width:"100%",padding:"10px",borderRadius:8,border:"none",cursor:"pointer",fontWeight:700,background:"linear-gradient(135deg, #00ff88, #3498DB)",color:"#000"},children:["Path to the top of ",i.name," →"]})]})}function F({title:e,children:n}){return(0,t.jsxs)("div",{style:{marginTop:14},children:[(0,t.jsx)("div",{style:{fontSize:10.5,letterSpacing:.8,color:"#8b9a9a",fontWeight:700,marginBottom:6},children:e.toUpperCase()}),n]})}function R({name:e}){let{companies:n,setScore:i}=(0,u.useCompanyScores)(),o=n?.find(t=>t.name===e);if(!o)return null;let r={yours:"your score",known:"known list",network:"estimated",default:"unknown company"}[o.source];return(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8,marginTop:10,fontSize:12,color:"#aab7b7"},children:["Company score ",(0,t.jsx)("b",{style:{color:"#fff",fontSize:15},children:o.score}),"/10 · ",r,(0,t.jsx)("span",{style:{marginLeft:"auto"},children:(0,t.jsx)(u.ScorePicker,{company:o,onSet:i,compact:!0})})]})}var W=e.i(15812),I=e.i(30215),$=e.i(22016),D=e.i(36774);let A=[["map","Map"],["industries","Industries"],["companies","Companies"]];function T(){let{userId:e}=(0,W.useUser)(),[a,d]=(0,n.useState)([]),[c,p]=(0,n.useState)(null),[h,f]=(0,n.useState)([]),[u,y]=(0,n.useState)(!0),[x,m]=(0,n.useState)([]),[b,k]=(0,n.useState)([]),[v,S]=(0,n.useState)([]),w=(0,i.useSearchParams)().get("tab"),[C,M]=(0,n.useState)(()=>A.some(([e])=>e===w)?w:"map"),z=(0,i.useRouter)();(0,n.useEffect)(()=>{"scores"===w&&z.replace("/scores#companies")},[w,z]);let[B,F]=(0,n.useState)(0),[R,D]=(0,n.useState)(!1);(0,n.useEffect)(()=>{!l.IS_DEMO&&e&&t();async function t(){let t=(0,s.hasCsvNetwork)()?(0,s.loadCsvNetwork)():null;D(!!t);let n=[],i=[],o=[];if(t)n=t.degree1,i=t.degree2||[];else{let t=await (0,r.loadNetwork)(e);n=t.degree1,i=t.degree2,o=t.degree3}m(n),k(i),S(o||[]);let l={},a=new Set;[...n,...i,...o].forEach(e=>{if(a.has(e.profile_url))return;a.add(e.profile_url);let t=(0,g.companyOf)(e);t&&(l[t]||(l[t]={name:t,d1:0,d2:0,d3:0,sCount:0,aCount:0,people:[]}),1===e.degree?l[t].d1++:2===e.degree?l[t].d2++:l[t].d3++,"S"===e.tier&&l[t].sCount++,"A"===e.tier&&l[t].aCount++,l[t].people.push(e))}),d(Object.values(l).filter(e=>e.d1+e.d2+e.d3>=3).sort((e,t)=>3*t.sCount+2*t.aCount+t.d1+t.d2+t.d3-(3*e.sCount+2*e.aCount+e.d1+e.d2+e.d3))),y(!1)}},[e,B]);let[T,O]=(0,n.useState)(!1),[N,L]=(0,n.useState)([]),E=(0,I.default)(),U=!T&&E.running?(0,o.busyReason)(E):null;function P(e){let t=new Set(x.map(e=>e.profile_url)),n=new Set([...x,...b].map(e=>e.profile_url));return e.map(i=>({...i,connected:t.has(i.profile_url||i.profileUrl),known:n.has(i.profile_url||i.profileUrl),seniority:(0,g.getSeniority)(i.headline),mutualCount:e.filter(e=>t.has(e.profile_url||e.profileUrl)&&e.id!==i.id).length}))}function H(e){p(e),f(P(e.people))}async function Y(){if(l.IS_DEMO||R||!c)return;let e=!1;try{e="1"===localStorage.getItem("six-degrees-company-scan-ok")}catch{}if(!e){if(!window.confirm("Company scans are experimental: they have not been tested against live LinkedIn yet, so the results may be incomplete. Like any scan, it opens a Chrome window and counts toward the profile views LinkedIn watches.\n\nRun it anyway?"))return;try{localStorage.setItem("six-degrees-company-scan-ok","1")}catch{}}O(!0),L(["Checking the scanner..."]);let t=(0,o.notReadyMessage)(await (0,o.scraperStatus)().catch(()=>null));if(t){L([t]),O(!1);return}try{let e=await (0,o.runScrape)("company",{name:c.name,onLog:L});if(0===e.exitCode){L(e=>[...e,"Loading the new people..."]);let e=await fetch(`/api/connections?scanned_company=${encodeURIComponent(c.name)}&limit=500`),t=(await e.json()).connections||[];t.length?(f(P(t)),L(e=>[...e,`${t.length} people at ${c.name}.`])):L(e=>[...e,"Nothing new was found."])}}catch(e){L([e.message||"Failed to start the scan"])}finally{O(!1)}}let K={},q=0;h.forEach(e=>{let t=e.seniority.key;K[t]||(K[t]={...e.seniority,people:[]}),e.connected&&q++;let n=Math.min(90,12*e.mutualCount);e.seniority.level<=1?n+=20:e.seniority.level<=2?n+=10:e.seniority.level>=5&&(n-=10),n=Math.max(5,Math.min(95,n)),e.connected&&(n=100);let i=null;if(2===e.degree&&e.source_connection_id){let t=x.find(t=>t.id===e.source_connection_id);t&&(i=t.name)}let o={0:5,1:10,2:20,3:35,4:50,5:75,6:100}[e.seniority.level]||10;K[t].people.push({...e,likelihood:n,bridgeName:i,xp:o})}),Object.values(K).forEach(e=>e.people.sort((e,t)=>t.likelihood-e.likelihood));let X=Object.values(K).sort((e,t)=>t.level-e.level);return l.IS_DEMO?(0,t.jsxs)("div",{style:{minHeight:"100vh",display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:12,background:"#0a0a1a",color:"rgba(255,255,255,0.7)",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},children:[(0,t.jsx)("h1",{style:{fontSize:20,fontWeight:700,margin:0,color:"#fff"},children:"Not part of the demo"}),(0,t.jsx)("p",{style:{fontSize:13,margin:0},children:"The public demo includes the Network Circle and Degrees views only."}),(0,t.jsx)($.default,{href:"/",style:{fontSize:13,color:"#888",textDecoration:"none"},children:"← Back to the network"})]}):u?(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff"},children:"Loading..."}):(0,t.jsxs)("div",{style:{height:"100vh",background:"#0a0a1a",color:"#fff",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',display:"flex",flexDirection:"column",overflow:"hidden"},children:[(0,t.jsx)("header",{style:{padding:"14px 24px",borderBottom:"1px solid rgba(255,255,255,0.1)",flexShrink:0},children:(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:12},children:[(0,t.jsxs)($.default,{href:"/",style:{display:"flex",alignItems:"center",gap:6,color:"#888",textDecoration:"none",fontSize:13,fontWeight:600,padding:"6px 14px",borderRadius:6,background:"rgba(255,255,255,0.06)",border:"1px solid rgba(255,255,255,0.1)"},children:[(0,t.jsx)("span",{style:{fontSize:16},children:"←"})," Map"]}),(0,t.jsx)("h1",{style:{fontSize:20,fontWeight:700,margin:0,background:"linear-gradient(135deg, #00ff88, #3498DB)",WebkitBackgroundClip:"text",WebkitTextFillColor:"transparent"},children:"Paths"}),!c&&(0,t.jsx)("div",{style:{display:"flex",gap:4,marginLeft:8,padding:3,borderRadius:8,background:"rgba(255,255,255,0.05)"},children:A.map(([e,n])=>(0,t.jsx)("button",{onClick:()=>M(e),style:{padding:"5px 12px",borderRadius:6,border:"none",cursor:"pointer",fontSize:12.5,fontWeight:700,background:C===e?"linear-gradient(135deg, #00ff88, #3498DB)":"transparent",color:C===e?"#000":"#aab"},children:n},e))}),c&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("button",{onClick:()=>{p(null),f([])},style:{background:"none",border:"none",color:"#888",cursor:"pointer",fontSize:12},children:"← Companies"}),(0,t.jsx)("span",{style:{fontSize:13,fontWeight:600},children:c.name}),(0,t.jsxs)("span",{style:{fontSize:11,color:"#888"},children:[q,"/",h.length," connected"]}),R?(0,t.jsx)("span",{style:{marginLeft:"auto",fontSize:11,color:"#888"},children:"Scanning needs your own network"}):(0,t.jsx)("button",{onClick:Y,disabled:T||!!U,title:U?`${U}. One scan at a time.`:void 0,style:{marginLeft:"auto",padding:"5px 12px",borderRadius:6,border:"none",cursor:T||U?"not-allowed":"pointer",background:T||U?"#333":"rgba(0,255,136,0.15)",color:T||U?"#555":"#00ff88",fontSize:11,fontWeight:600},children:T?"Scanning...":U?"Scanner busy":"+ Scan Full Company"}),(0,t.jsx)("span",{title:"Not yet tested against live LinkedIn. Results may be incomplete.",style:{fontSize:9.5,fontWeight:800,letterSpacing:.6,padding:"3px 7px",borderRadius:20,border:"1px solid rgba(255,215,0,0.45)",color:"#FFD700"},children:"EXPERIMENTAL"})]})]})}),c||"companies"===C?(0,t.jsx)("div",{style:{flex:1,overflow:"auto",padding:"16px 24px"},children:(0,t.jsxs)("div",{style:{maxWidth:700,margin:"0 auto"},children:[!c&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("p",{style:{fontSize:13,color:"#888",marginBottom:16},children:["Pick a company to see your path to the top. Based on ",x.length+b.length," people in your network."]}),(0,t.jsx)("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:10},children:a.slice(0,60).map(e=>(0,t.jsxs)("button",{onClick:()=>H(e),style:{padding:"14px",borderRadius:10,border:"none",cursor:"pointer",textAlign:"left",background:"rgba(255,255,255,0.04)",transition:"background 0.15s",borderLeft:`3px solid ${e.sCount>0?"#FFD700":e.aCount>0?"#9B59B6":"#3498DB"}`},onMouseEnter:e=>e.currentTarget.style.background="rgba(255,255,255,0.08)",onMouseLeave:e=>e.currentTarget.style.background="rgba(255,255,255,0.04)",children:[(0,t.jsx)("div",{style:{fontSize:14,fontWeight:700,color:"#fff",marginBottom:4},children:e.name}),(0,t.jsxs)("div",{style:{display:"flex",gap:8,fontSize:10,color:"#888"},children:[(0,t.jsxs)("span",{style:{color:"#00ff88"},children:[e.d1," connected"]}),(0,t.jsxs)("span",{children:[e.d2+e.d3," locked"]})]}),(0,t.jsxs)("div",{style:{display:"flex",gap:6,marginTop:4,fontSize:9},children:[e.sCount>0&&(0,t.jsxs)("span",{style:{color:"#FFD700",fontWeight:600},children:[e.sCount,"S"]}),e.aCount>0&&(0,t.jsxs)("span",{style:{color:"#9B59B6",fontWeight:600},children:[e.aCount,"A"]}),(0,t.jsxs)("span",{style:{color:"#555"},children:[e.d1+e.d2," total"]})]}),(0,t.jsx)("div",{style:{height:3,background:"rgba(255,255,255,0.08)",borderRadius:2,marginTop:6},children:(0,t.jsx)("div",{style:{height:"100%",borderRadius:2,width:`${e.d1/Math.max(e.d1+e.d2+e.d3,1)*100}%`,background:e.sCount>0?"#FFD700":"#00ff88"}})})]},e.name))})]}),T&&(0,t.jsxs)("div",{style:{padding:"10px",borderRadius:8,background:"rgba(0,255,136,0.06)",border:"1px solid rgba(0,255,136,0.2)",marginBottom:12},children:[(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:6,marginBottom:4},children:[(0,t.jsx)("div",{style:{width:6,height:6,borderRadius:"50%",background:"#00ff88",animation:"pulse 1s infinite"}}),(0,t.jsx)("span",{style:{fontSize:10,fontWeight:600,color:"#00ff88"},children:"Scanning LinkedIn..."})]}),(0,t.jsx)("div",{style:{fontFamily:"monospace",fontSize:9,color:"#777",maxHeight:60,overflow:"auto"},children:N.map((e,n)=>(0,t.jsx)("div",{children:e},n))})]}),c&&X.map(e=>(0,t.jsxs)("div",{style:{marginBottom:16},children:[(0,t.jsxs)("div",{style:{padding:"8px 12px",borderRadius:6,marginBottom:4,background:e.level>=5?"rgba(255,215,0,0.08)":e.level>=3?"rgba(155,89,182,0.08)":"rgba(52,152,219,0.08)",borderLeft:`3px solid ${e.level>=5?"#FFD700":e.level>=3?"#9B59B6":"#3498DB"}`,display:"flex",justifyContent:"space-between",alignItems:"center"},children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{style:{fontSize:12,fontWeight:700,color:e.level>=5?"#FFD700":e.level>=3?"#9B59B6":"#3498DB"},children:e.label}),e.level>=5&&(0,t.jsx)("span",{style:{fontSize:9,color:"#FF6B35",marginLeft:8,fontWeight:700},children:"TARGET"})]}),(0,t.jsxs)("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[(0,t.jsxs)("span",{style:{fontSize:9,color:"#FF6B35",fontWeight:600},children:["+",e.people.filter(e=>!e.connected).reduce((e,t)=>e+(t.xp||0),0)," XP"]}),(0,t.jsxs)("span",{style:{fontSize:10,color:"#666"},children:[e.people.filter(e=>e.connected).length,"/",e.people.length]})]})]}),e.people.map((n,i)=>(0,t.jsx)(_,{p:n,level:e,companyPeople:h,d1Data:x,selectedCompany:c},n.id||i))]},e.key))]})}):(0,t.jsx)(j,{d1:x,d2:b,d3:v,tab:C,onOpenCompany:e=>H({...e,sCount:e.S,aCount:e.A})})]})}function _({p:e,level:i,companyPeople:o,d1Data:r,selectedCompany:l}){let[s,a]=(0,n.useState)(!1),d=new Set(r.map(e=>e.profile_url));o.filter(e=>d.has(e.profile_url||e.profileUrl));let c=o.filter(t=>(0,g.getSeniority)(t.headline).level>e.seniority.level&&!d.has(t.profile_url||t.profileUrl)),p=o.filter(t=>(0,g.getSeniority)(t.headline).level===e.seniority.level&&t.id!==e.id),h=[];if(!e.connected){let t=c.length;t>0&&h.push({icon:"⬆️",text:`Adding them gives you a mutual with ${t} people above in the hierarchy`,color:"#00ff88"});let n=p.filter(e=>d.has(e.profile_url||e.profileUrl)).length;n>0?h.push({icon:"🤝",text:`${n} people at their level already connected — high social proof`,color:"#FFD700"}):h.push({icon:"🎯",text:"First connection at this level — opens a new layer",color:"#3498DB"}),e.bridgeName&&h.push({icon:"🔗",text:`Reachable through ${e.bridgeName} — warm intro possible`,color:"#FF6B35"}),e.seniority.level>=5?h.push({icon:"👑",text:`${e.seniority.label} — decision maker, high strategic value but low accept rate`,color:"#FFD700"}):e.seniority.level>=3?h.push({icon:"📊",text:`${e.seniority.label} — middle management, good balance of access and accept rate`,color:"#9B59B6"}):h.push({icon:"✅",text:`${e.seniority.label} — highest accept rate, builds mutual foundation for people above`,color:"#00ff88"}),e.likelihood>=60?h.push({icon:"🔥",text:`${e.likelihood}% likely to accept — strong mutual overlap + approachable role`,color:"#00ff88"}):e.likelihood>=30?h.push({icon:"⚡",text:`${e.likelihood}% likely — moderate chance, add more people at their level first`,color:"#FFD700"}):h.push({icon:"🔒",text:`${e.likelihood}% likely — low chance right now, build more connections below them first`,color:"#ff5050"})}return(0,t.jsxs)("div",{style:{borderBottom:"1px solid rgba(255,255,255,0.03)"},children:[(0,t.jsxs)("div",{onClick:()=>a(!s),style:{display:"flex",alignItems:"center",gap:8,padding:"6px 8px",cursor:"pointer",opacity:e.connected?.7:1},onMouseEnter:e=>e.currentTarget.style.background="rgba(255,255,255,0.04)",onMouseLeave:e=>e.currentTarget.style.background="transparent",children:[(0,t.jsx)("span",{style:{fontSize:8,color:"#555",flexShrink:0,width:10},children:s?"▾":"▸"}),(0,t.jsx)("div",{style:{width:18,height:18,borderRadius:"50%",flexShrink:0,fontSize:8,display:"flex",alignItems:"center",justifyContent:"center",background:e.connected?"rgba(0,255,136,0.2)":"rgba(255,255,255,0.05)",color:e.connected?"#00ff88":"#555",border:`1px solid ${e.connected?"rgba(0,255,136,0.3)":"rgba(255,255,255,0.1)"}`},children:e.connected?"✓":"🔒"}),(0,D.localPhoto)(e.profile_image_url||e.imageUrl)?(0,t.jsx)("img",{src:(0,D.localPhoto)(e.profile_image_url||e.imageUrl),alt:"",style:{width:26,height:26,borderRadius:"50%",objectFit:"cover",flexShrink:0},onError:e=>e.target.style.display="none"}):(0,t.jsx)("div",{style:{width:26,height:26,borderRadius:"50%",flexShrink:0,fontSize:10,fontWeight:700,background:"#333",color:"#888",display:"flex",alignItems:"center",justifyContent:"center"},children:e.name?.charAt(0)}),(0,t.jsxs)("div",{style:{flex:1,minWidth:0},children:[(0,t.jsx)("div",{style:{fontSize:11,fontWeight:600,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.name}),(0,t.jsx)("div",{style:{fontSize:8,color:"#666",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.headline?.substring(0,45)})]}),!e.connected&&e.bridgeName&&(0,t.jsxs)("span",{style:{fontSize:8,color:"#FF6B35",flexShrink:0,maxWidth:55,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:["via ",e.bridgeName.split(" ")[0]]}),!e.connected&&(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:6,flexShrink:0},children:[(0,t.jsxs)("span",{style:{fontSize:8,fontWeight:700,color:"#FF6B35"},children:["+",e.xp]}),(0,t.jsxs)("div",{style:{fontSize:9,fontWeight:700,minWidth:30,textAlign:"right",color:e.likelihood>=60?"#00ff88":e.likelihood>=30?"#FFD700":"#ff5050"},children:[e.likelihood,"%"]})]}),!e.connected&&(0,t.jsx)("a",{href:e.profile_url||e.profileUrl,target:"_blank",rel:"noopener noreferrer",onClick:e=>e.stopPropagation(),style:{padding:"3px 7px",borderRadius:4,fontSize:8,fontWeight:700,background:"#0077B5",color:"#fff",textDecoration:"none",flexShrink:0},children:"Add"})]}),s&&(0,t.jsxs)("div",{style:{padding:"8px 12px 10px 44px",background:"rgba(255,255,255,0.02)",borderTop:"1px solid rgba(255,255,255,0.04)"},children:[(0,t.jsx)("div",{style:{fontSize:11,color:"#aaa",marginBottom:8},children:e.headline||"No headline available"}),(0,t.jsxs)("div",{style:{display:"flex",gap:6,alignItems:"center",marginBottom:8,flexWrap:"wrap"},children:[(0,t.jsxs)("div",{style:{display:"inline-block",padding:"2px 8px",borderRadius:4,fontSize:9,fontWeight:600,background:e.seniority.level>=5?"rgba(255,215,0,0.1)":e.seniority.level>=3?"rgba(155,89,182,0.1)":"rgba(52,152,219,0.1)",color:e.seniority.level>=5?"#FFD700":e.seniority.level>=3?"#9B59B6":"#3498DB",border:`1px solid ${e.seniority.level>=5?"rgba(255,215,0,0.2)":e.seniority.level>=3?"rgba(155,89,182,0.2)":"rgba(52,152,219,0.2)"}`},children:[e.seniority.label," · Level ",e.seniority.level]}),!e.connected&&(0,t.jsxs)("div",{style:{display:"inline-block",padding:"2px 8px",borderRadius:4,fontSize:9,fontWeight:700,background:"rgba(255,107,53,0.1)",color:"#FF6B35",border:"1px solid rgba(255,107,53,0.2)"},children:["+",e.xp," XP"]})]}),!e.connected&&h.length>0&&(0,t.jsxs)("div",{style:{marginTop:4},children:[(0,t.jsx)("div",{style:{fontSize:9,fontWeight:700,color:"#888",letterSpacing:.5,marginBottom:4},children:"STRATEGIC VALUE"}),h.map((e,n)=>(0,t.jsxs)("div",{style:{display:"flex",gap:6,alignItems:"flex-start",padding:"2px 0",fontSize:10,color:"#bbb"},children:[(0,t.jsx)("span",{style:{fontSize:11,lineHeight:1},children:e.icon}),(0,t.jsx)("span",{style:{color:e.color},children:e.text})]},n))]}),e.connected&&(0,t.jsxs)("div",{style:{fontSize:10,color:"#00ff88",fontWeight:600},children:["✓ Already connected — contributes as mutual for others at ",l?.name]})]})]})}e.s(["default",0,function(){return(0,t.jsx)(a.default,{children:(0,t.jsx)(n.Suspense,{children:(0,t.jsx)(T,{})})})}],85957)}]);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,94657,e=>{"use strict";var t=e.i(43476),n=e.i(71645),r=e.i(7837);let o=e=>`${e.name} ${e.was} → ${e.estimated?"estimated":e.now}`,a=e=>({padding:"6px 12px",borderRadius:7,cursor:"pointer",fontSize:12,fontWeight:700,border:e?"none":"1px solid rgba(255,255,255,0.15)",background:e?"linear-gradient(135deg, #00ff88, #3498DB)":"transparent",color:e?"#000":"#cfd8d8"});function i({onAnswered:e}){var s;let l,c,[u,d]=(0,n.useState)(null),[p,f]=(0,n.useState)(!1),[h,g]=(0,n.useState)(()=>new Set),[y,m]=(0,n.useState)(!1),[b,w]=(0,n.useState)(null);if((0,n.useEffect)(()=>{if((0,r.csvNetworkSource)())return;let e=!1;return fetch("/api/company-scores/legacy").then(e=>e.json()).then(t=>{!e&&t.offer?.companies?.length&&(d(t.offer),g(new Set(t.offer.companies.map(e=>e.name))))}).catch(()=>{}),()=>{e=!0}},[]),!u)return null;let x=async t=>{m(!0),w(null);try{let n=await fetch("/api/company-scores/legacy",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({keep:t})}),r=await n.json();if(!n.ok&&!r.kept)throw Error(r.error||"Could not save your answer.");d(null),e?.({kept:r.kept||[],scored:r.scored||0,error:n.ok?null:r.error})}catch(e){w(e.message)}finally{m(!1)}};return(0,t.jsxs)("section",{"aria-label":"Built-in scores changed",style:{marginBottom:14,padding:14,borderRadius:10,border:"1px solid rgba(255,215,0,0.35)",background:"rgba(255,215,0,0.06)",fontSize:12.5,color:"#cfd8d8",lineHeight:1.6},children:[(0,t.jsx)("b",{style:{color:"#fff"},children:"Built-in scores changed in this version:"})," ",(l=(s=u.companies).slice(0,3).map(o).join(", "),(c=s.length-3)>0?`${l} and ${c} more`:l),"."," ","Keep any of the old ones as your own?",(0,t.jsx)("div",{style:{marginTop:4,color:"#8b9a9a"},children:"The built-in list now holds only companies most professionals would recognise, scored the same for everyone; anything else is estimated from your network. A score you keep is yours, like one you set below, and Auto hands it back."}),p&&(0,t.jsx)("ul",{style:{listStyle:"none",padding:0,margin:"10px 0 0",display:"grid",gap:4},children:u.companies.map(e=>(0,t.jsx)("li",{children:(0,t.jsxs)("label",{style:{display:"flex",gap:8,alignItems:"baseline",cursor:"pointer"},children:[(0,t.jsx)("input",{type:"checkbox",checked:h.has(e.name),disabled:y,onChange:()=>{let t;return t=e.name,g(e=>{let n=new Set(e);return n.has(t)?n.delete(t):n.add(t),n})}}),(0,t.jsxs)("span",{children:[(0,t.jsx)("b",{style:{color:"#fff"},children:e.name})," ",e.was," → ",e.estimated?`estimated (${e.now})`:e.now,(0,t.jsxs)("span",{style:{color:"#778"},children:[` \xb7 ${e.people} ${1===e.people?"person":"people"} there now`,e.names.length>1&&` \xb7 for ${e.names.join(", ")}`]})]})]})},e.name))}),(0,t.jsxs)("div",{style:{display:"flex",gap:8,marginTop:10,flexWrap:"wrap"},children:[p?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsxs)("button",{disabled:y||!h.size,onClick:()=>x([...h]),style:{...a(!0),opacity:y||!h.size?.5:1},children:["Keep ",h.size," ",1===h.size?"score":"scores"]}),(0,t.jsx)("button",{disabled:y,onClick:()=>f(!1),style:a(!1),children:"Back"})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("button",{disabled:y,onClick:()=>x(u.companies.map(e=>e.name)),style:a(!0),children:"Keep all"}),(0,t.jsx)("button",{disabled:y,onClick:()=>f(!0),style:a(!1),children:"Choose…"})]}),(0,t.jsx)("button",{disabled:y,onClick:()=>x([]),style:a(!1),children:"No thanks"})]}),b&&(0,t.jsx)("div",{role:"alert",style:{marginTop:8,color:"#e74c3c"},children:b})]})}let s="1px solid rgba(255,255,255,0.1)",l={yours:{label:"your score",color:"#00ff88"},known:{label:"known list",color:"#3498DB"},data:{label:"public data",color:"#1abc9c"},network:{label:"estimated: many of your people",color:"#FF6B35"},default:{label:"unknown company",color:"#778"}};async function c(){let e=await fetch("/api/company-scores"),t=await e.json();if(!e.ok)throw Error(t.error||"Could not load company scores");return t.companies}function u(){let[e,t]=(0,n.useState)(null),[r,o]=(0,n.useState)(null);return(0,n.useEffect)(()=>{let e=!1;return c().then(n=>{e||t(n)}).catch(t=>{e||o(t.message)}),()=>{e=!0}},[]),{companies:e,error:r,setScore:(0,n.useCallback)(async(e,n)=>{let r=await fetch("/api/company-scores",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,score:n})}),o=await r.json();if(!r.ok)throw Error(o.error||"Could not save");return t(await c()),o},[]),reload:(0,n.useCallback)(async()=>t(await c()),[])}}function d({company:e,onSet:r,compact:o}){let[a,i]=(0,n.useState)(!1),l=async t=>{i(!0);try{await r(e.name,"auto"===t?null:Number(t))}finally{i(!1)}};return(0,t.jsxs)("select",{disabled:a,value:"yours"===e.source?String(e.score):"auto",onChange:e=>l(e.target.value),title:"Set this company's score. Auto uses the known list or an estimate.",style:{padding:o?"2px 4px":"4px 6px",borderRadius:6,border:s,background:"#11131c",color:"#dfe6e9",fontSize:12},children:[(0,t.jsxs)("option",{value:"auto",children:["Auto (","yours"===e.source?e.suggested??"est.":e.score,")"]}),[10,9,8,7,6,5,4,3,2,1].map(e=>(0,t.jsx)("option",{value:e,children:e},e))]})}e.s(["ScorePicker",0,d,"default",0,function({onRescored:e,version:r=0}){let{companies:o,error:a,setScore:c,reload:p}=u();(0,n.useEffect)(()=>{r&&p().catch(()=>{})},[r,p]);let[f,h]=(0,n.useState)(""),[g,y]=(0,n.useState)("all"),[m,b]=(0,n.useState)(150),[w,x]=(0,n.useState)(null),k=e=>{x(e),setTimeout(()=>x(null),3500)},v=async(t,n)=>{let r=await c(t,n);k(`${t}: ${null==n?"back to auto":`set to ${n}`} \xb7 rescored ${r.scored} people`),e?.()},S=async({kept:t,scored:n,error:r})=>{if(!t.length)return k("Keeping the new built-in scores.");k(r||`Kept ${t.length} old ${1===t.length?"score":"scores"} as your own \xb7 rescored ${n} people`),await p().catch(()=>{}),e?.()},j=(0,n.useMemo)(()=>{if(!o)return[];let e=f.trim().toLowerCase();return o.filter(t=>(!e||t.name.toLowerCase().includes(e))&&("all"===g||t.source===g))},[o,f,g]);if(a)return(0,t.jsx)("div",{style:{padding:24,color:"#e74c3c"},children:a});if(!o)return(0,t.jsx)("div",{style:{padding:24,color:"#778"},children:"Loading companies…"});let C=e=>o.filter(t=>t.source===e).length;return(0,t.jsxs)("div",{style:{flex:1,overflow:"auto",padding:16},children:[(0,t.jsxs)("div",{style:{maxWidth:980,margin:"0 auto"},children:[(0,t.jsx)(i,{onAnswered:S}),(0,t.jsxs)("div",{style:{padding:14,borderRadius:10,border:s,background:"rgba(255,255,255,0.03)",fontSize:12.5,color:"#cfd8d8",lineHeight:1.6},children:[(0,t.jsx)("b",{style:{color:"#fff"},children:"How a power score works."})," power = ",(0,t.jsx)("b",{children:"title"})," × ",(0,t.jsx)("b",{children:"company weight"})," + bonus. The title (student 1 … founder or C-suite 10) comes from someone’s roles, with former roles at 70%; an audience of their own counts like a title (1M+ followers like a director). The company weight runs from 0.725 for a company we don’t know (or none found), the middle of the scale, to 1.0 (a company scored 10), so seniority counts for more at a bigger company. The bonus is at most +1.5, for investor, YC, an audience in the millions or the top award of any field, and counts half at an unknown company. A 1st-degree person whose circle is unusually strong gets up to +2 more: up to +1 for a high share of it at A or S, or +1 for every 25 people there. Tiers are graded on your network’s curve unless you choose the fixed scale (",(0,t.jsx)("a",{href:"#tiers",style:{color:"#3498DB"},children:"Tiers"}),", above): your top 3% are S, the next 12% A, the next 25% B (it only lifts, and never lifts anyone under 4 into S or A). On the fixed scale, S ≥ 7.5 · A ≥ 5.5 · B ≥ 4 · C ≥ 2.5.",(0,t.jsxs)("div",{style:{marginTop:6,color:"#8b9a9a"},children:["So a VP at a 10 scores 9.0, a founder at an unknown company 7.3, a director at an unknown company 5.4, and an intern at a 10 scores 2.0. Set a company’s score below and everyone there is rescored. Companies in the sectors you pick (",(0,t.jsx)("a",{href:"#sector",style:{color:"#3498DB"},children:"Your sector"}),", above) get +1 or +2; a score you set is never changed."]})]}),(0,t.jsxs)("div",{style:{display:"flex",gap:8,alignItems:"center",flexWrap:"wrap",margin:"14px 0 10px"},children:[(0,t.jsx)("input",{value:f,onChange:e=>h(e.target.value),placeholder:"Find a company",style:{padding:"6px 10px",borderRadius:7,border:s,background:"rgba(255,255,255,0.05)",color:"#fff",fontSize:13,minWidth:180}}),[["all",`All ${o.length}`],["known",`Known list ${C("known")}`],["data",`Public data ${C("data")}`],["yours",`Yours ${C("yours")}`],["network",`Estimated ${C("network")}`],["default",`Unknown ${C("default")}`]].map(([e,n])=>(0,t.jsx)("button",{onClick:()=>y(e),style:{padding:"5px 10px",borderRadius:7,border:s,cursor:"pointer",fontSize:11.5,fontWeight:600,background:g===e?"rgba(52,152,219,0.25)":"transparent",color:g===e?"#cfe6f7":"#8b9a9a"},children:n},e))]}),(0,t.jsxs)("div",{style:{borderRadius:10,border:s,overflow:"hidden"},children:[(0,t.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"1fr 70px 70px 70px 60px 180px 110px",gap:8,padding:"8px 12px",fontSize:10.5,letterSpacing:.6,color:"#8b9a9a",background:"rgba(255,255,255,0.04)"},children:[(0,t.jsx)("span",{children:"COMPANY"}),(0,t.jsx)("span",{style:{textAlign:"right"},children:"PEOPLE"}),(0,t.jsx)("span",{style:{textAlign:"right"},children:"YOU KNOW"}),(0,t.jsx)("span",{style:{textAlign:"right"},children:"DIRECTOR+"}),(0,t.jsx)("span",{style:{textAlign:"right"},children:"SCORE"}),(0,t.jsx)("span",{children:"SOURCE"}),(0,t.jsx)("span",{children:"SET"})]}),j.slice(0,m).map(e=>(0,t.jsxs)("div",{style:{display:"grid",gridTemplateColumns:"1fr 70px 70px 70px 60px 180px 110px",gap:8,padding:"7px 12px",alignItems:"center",borderTop:"1px solid rgba(255,255,255,0.05)",fontSize:12.5},children:[(0,t.jsxs)("span",{style:{display:"flex",alignItems:"center",gap:8,minWidth:0},children:[(0,t.jsx)("span",{title:`${e.industry.label} (inferred)`,style:{width:8,height:8,borderRadius:"50%",background:e.industry.color,flexShrink:0}}),(0,t.jsx)("span",{style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.name})]}),(0,t.jsx)("span",{style:{textAlign:"right"},children:e.people}),(0,t.jsx)("span",{style:{textAlign:"right",color:e.d1?"#00ff88":"#556"},children:e.d1}),(0,t.jsx)("span",{style:{textAlign:"right",color:e.senior?"#FFD700":"#556"},children:e.senior}),(0,t.jsx)("b",{style:{textAlign:"right",fontSize:15},children:e.score}),(0,t.jsxs)("span",{style:{fontSize:11,color:l[e.source]?.color},children:[l[e.source]?.label,e.sectorBonus>0&&(0,t.jsxs)("span",{style:{color:"#00ff88"},children:[" + ",e.sectorBonus," your sector"]})]}),(0,t.jsx)(d,{company:e,onSet:v,compact:!0})]},e.name))]}),j.length>m&&(0,t.jsxs)("button",{onClick:()=>b(e=>e+300),style:{marginTop:10,padding:"7px 14px",borderRadius:8,border:s,background:"rgba(255,255,255,0.05)",color:"#dfe6e9",cursor:"pointer",fontSize:12},children:["Show more (",j.length-m," left)"]})]}),w&&(0,t.jsx)("div",{role:"status",style:{position:"fixed",bottom:24,left:"50%",transform:"translateX(-50%)",padding:"10px 18px",borderRadius:24,background:"linear-gradient(135deg, #00ff88, #3498DB)",color:"#000",fontWeight:800,fontSize:13,zIndex:50},children:w})]})},"useCompanyScores",0,u],94657)},2776,e=>{"use strict";var t=e.i(43476),n=e.i(15812);e.s(["default",0,function({children:e}){let{userId:r,ready:o}=(0,n.useUser)();return o&&r?e:(0,t.jsx)("div",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#0a0a1a",color:"#fff",padding:24,textAlign:"center",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'},children:o?(0,t.jsxs)("div",{style:{maxWidth:420},children:[(0,t.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,t.jsx)("div",{style:{color:"#888",fontSize:14,lineHeight:1.6},children:"The page loaded but the app behind it is not answering. If you started it from a terminal, check that window for an error, then reload this page."})]}):(0,t.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},89154,e=>{"use strict";var t=e.i(90179);function n(e){let n=(0,t.readTitle)(e);return{key:n.key,label:n.label,level:n.level}}function r(e){return(0,t.currentCompany)(e)}let o=[{key:"defense",label:"Government, Defense & Aerospace",color:"#7f8c8d",words:/\b(government|federal|state of|county|city of|defen[cs]e|army|navy|air force|marine corps|military|dod|nasa|aerospace|lockheed|northrop|boeing|raytheon|l3harris|leidos|blue origin|spacex|public sector)\b/i},{key:"finance",label:"Finance & Investing",color:"#2ecc71",words:/\b(bank|banking|capital|ventures?|vc|investments?|investor|fund|private equity|growth equity|asset management|wealth|trading|trader|hedge|crypto|blockchain|web3|defi|fintech|stripe|coinbase|blackrock|robinhood|goldman|morgan stanley|jpmorgan|chase|bny|mellon|wells fargo|citi|citigroup|capital one|fidelity|vanguard|schwab|visa|mastercard|amex|american express|paypal|insurance|accounting|cpa|financial)\b/i},{key:"health",label:"Healthcare & Biotech",color:"#e74c3c",words:/\b(health|healthcare|medical|medicine|hospital|clinic|pharma|pharmaceutical|biotech|nurse|nursing|physician|doctor|dental|therapy|therapist|wellness)\b/i},{key:"education",label:"Education",color:"#f1c40f",words:/\b(university|college|school|education|student|professor|teacher|academy|phd|faculty|alumni)\b/i},{key:"media",label:"Marketing & Media",color:"#e67e22",words:/\b(marketing|brand|branding|advertising|agency|media|content|social media|creative|creator|influencer|pr|public relations|communications|tiktok|pinterest|youtube|growth marketing)\b/i},{key:"entertainment",label:"Entertainment & Gaming",color:"#9b59b6",words:/\b(entertainment|film|movie|music|records|gaming|games?|esports|studio|studios|netflix|disney|spotify|hollywood|theater|theatre|sports)\b/i},{key:"tech",label:"Tech, Software & AI",color:"#3498db",words:/\b(software|saas|engineer|engineering|developer|tech|technology|technologies|ai|artificial intelligence|machine learning|ml|data|cloud|cyber|security|devops|product manager|google|microsoft|apple|meta|amazon|nvidia|openai|anthropic|palantir|salesforce|oracle|ibm|intel|app|apps|startup|platform|labs?)\b/i},{key:"consulting",label:"Consulting, Legal & Services",color:"#1abc9c",words:/\b(consulting|consultant|consultancy|deloitte|accenture|mckinsey|kpmg|pwc|ey|bain|bcg|legal|law|lawyer|attorney|paralegal|recruiting|recruiter|staffing|talent)\b/i},{key:"realestate",label:"Real Estate & Construction",color:"#d35400",words:/\b(real estate|realtor|realty|property|properties|construction|architecture|architect|mortgage|homes|housing|builders?)\b/i},{key:"consumer",label:"Retail, Consumer & Hospitality",color:"#ff79c6",words:/\b(retail|e-?commerce|shopify|consumer|cpg|fashion|apparel|beauty|cosmetics|food|beverage|restaurant|hospitality|hotel|travel|tourism|coca-cola|nike|store|shop)\b/i},{key:"industry",label:"Manufacturing, Energy & Logistics",color:"#95a5a6",words:/\b(manufacturing|energy|oil|gas|solar|utilities|automotive|tesla|siemens|ge|general electric|honeywell|3m|logistics|supply chain|shipping|freight|fedex|ups|industrial|mining|chemicals?)\b/i},{key:"nonprofit",label:"Nonprofit & Community",color:"#bdc3c7",words:/\b(nonprofit|non-profit|foundation|charity|ngo|church|ministry|volunteer)\b/i}],a={key:"unknown",label:"Unclear",color:"#555c66"},i=Object.fromEntries([...o,a].map(e=>[e.key,e])),s=e=>i[e]||a;function l(e,t){for(let n of[e,t]){if(!n)continue;let e=o.find(e=>e.words.test(n));if(e)return e}return a}let c=(e,t)=>l(e,t).key,u=e=>n(e).level>=4;e.s(["INDUSTRIES",0,o,"UNKNOWN_INDUSTRY",0,a,"buildCompanyIndex",0,function(e=[]){let n=new Map,r=e=>(n.has(e)||n.set(e,(0,t.rolesWithCompanies)(e)),n.get(e)),{industries:o}=(0,t.networkCompanies)(e,{industryOf:c,rolesOf:r}),a=new Map;for(let t of e){let e=t.profile_url||`id:${t.id}`,n=a.get(e);(!n||(t.degree||9)<(n.degree||9))&&a.set(e,t)}let i=new Map;for(let e of a.values()){let t=r(e).find(e=>!e.former)?.company;if(!t)continue;let n=i.get(t);n||(n={name:t,people:[],d1:0,d2:0,d3:0,S:0,A:0,senior:0},i.set(t,n)),n.people.push(e),1===e.degree?n.d1++:2===e.degree?n.d2++:n.d3++,"S"===e.tier&&n.S++,"A"===e.tier&&n.A++,u(e.headline)&&n.senior++}for(let e of i.values())e.industry=s(o.get(e.name));return i},"companyLinks",0,function(e=[],t=[]){let n=new Map;for(let t of e){let e=r(t);e&&n.set(t.id,e)}let o=new Map;for(let e of t){let t=n.get(e.source_connection_id),a=r(e);if(!t||!a||t===a)continue;let[i,s]=t<a?[t,a]:[a,t],l=`${i}\u0000${s}`,c=o.get(l);c||(c={a:i,b:s,weight:0,via:new Set},o.set(l,c)),c.weight++,c.via.add(e.source_connection_id)}return[...o.values()]},"companyOf",0,r,"getSeniority",0,n,"industryByKey",0,s,"industryOf",0,l,"isSenior",0,u,"waysInto",0,function(e,t=[],n=[]){let o=t.filter(t=>r(t)===e),a=new Map;for(let t of n)r(t)===e&&a.set(t.source_connection_id,(a.get(t.source_connection_id)||0)+1);let i=new Map(t.map(e=>[e.id,e]));return{direct:o,bridges:[...a.entries()].map(([e,t])=>({bridge:i.get(e),n:t})).filter(e=>e.bridge).sort((e,t)=>t.n-e.n||(Number(t.bridge.power_score)||0)-(Number(e.bridge.power_score)||0))}}])},19821,e=>{"use strict";async function t(e){let t=e?`/api/network?userId=${encodeURIComponent(e)}`:"/api/network",n=await fetch(t);if(!n.ok)throw Error(`Failed to load network (${n.status})`);let r=await n.json();return{degree1:r.degree1||[],degree2:r.degree2||[],degree3:r.degree3||[]}}e.s(["loadNetwork",0,t])},36774,e=>{"use strict";let t=/^[A-Za-z0-9_-]+\.(webp|jpg|jpeg|png)$/,n="/avatars/";e.s(["localPhoto",0,function(e){return"string"==typeof e&&e.startsWith(n)&&t.test(e.slice(n.length))?e:null}])},40996,e=>{"use strict";async function t(){let e=await fetch("/api/scraper");if(!e.ok)throw Error("Could not reach the app.");return e.json()}async function n(e,t,r={}){let o=await fetch("/api/scraper",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:e,...t?{name:t}:{},...r})}),a=await o.json().catch(()=>({}));if(!o.ok)throw Error(a.error||"Could not start the scanner.");return a}async function r(e){let t=await fetch(`/api/scraper?resume=${encodeURIComponent(e)}`);return t.ok?(await t.json()).resume??null:null}Symbol.for("six-degrees.scan-state");let o=Object.freeze({skips:[],read:[]});async function a(){try{let e=await fetch("/api/scraper?reach=1");if(!e.ok)return o;let t=await e.json();return{skips:Array.isArray(t.skips)?t.skips:[],read:Array.isArray(t.read)?t.read:[]}}catch{return o}}async function i(e){let t=await fetch(`/api/scraper?person=${encodeURIComponent(e)}`);return t.ok?t.json():{person:null}}async function s(){await fetch("/api/scraper",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"cancel"})})}let l=Object.freeze({known:!1,running:!1,pending:!1,action:null,target:null,startedAt:null,progress:null,log:[],finished:[]}),c=new Set,u=l,d=JSON.stringify(u),p=null,f=null,h=0,g=!1,y=new Set;function m(e){let t=JSON.stringify(e);if(t!==d)for(let n of(d=t,u=Object.freeze(e),[...c]))n()}async function b(){(!("u">typeof document&&document.hidden)||u.running)&&await function(){if(f&&f.epoch===h)return f.promise;let e=h,t=fetch("/api/scraper?job=1").then(e=>e.ok?e.json():null).then(t=>{e===h&&function(e){if(!e||"object"!=typeof e)return;let t=!0===e.running;t&&null!=e.startedAt&&y.add(e.startedAt);let n=(Array.isArray(e.recent)?e.recent:[]).filter(e=>y.has(e.startedAt)).map(n=>({...n,log:!t&&n.startedAt===e.startedAt&&Array.isArray(e.log)?e.log:[]}));m({known:!0,running:t||g,pending:g&&!t,action:t?e.action??null:g?u.action:null,target:t?e.target??null:g?u.target:null,startedAt:t?e.startedAt??null:null,progress:t?e.progress??null:null,log:t&&Array.isArray(e.log)?e.log:[],finished:n})}(t)}).catch(()=>{}).finally(()=>{f?.promise===t&&(f=null)});return f={epoch:e,promise:t},t}(),clearTimeout(p),p=c.size?setTimeout(b,u.running?1500:5e3):null}function w(e){return c.add(e),1===c.size&&b(),()=>{c.delete(e),c.size||(clearTimeout(p),p=null)}}async function x(e,{name:t,id:r,onLog:o,...a}={}){let i;h++,g=!0,m({...u,known:!0,running:!0,pending:!0,action:e,target:t||r?{id:r??null,name:t??null}:null,startedAt:null,progress:null,log:[]});try{i=await n(e,t,{...r?{id:r}:{},...a})}catch(e){throw g=!1,h++,u.pending&&m({...u,running:!1,pending:!1,action:null,target:null,log:[]}),b(),e}g=!1,h++;let s=i?.startedAt??null;null!=s&&y.add(s);let l=new Promise(e=>{let t=w(()=>{u.running&&u.startedAt===s&&o?.(u.log);let n=null==s?u.running?null:{exitCode:null,failure:null,log:[]}:u.finished.find(e=>e.startedAt===s);n&&(t(),n.log.length&&o?.(n.log),e(n))});b()});return{startedAt:s,ended:l}}function k(e){return!!e?.target&&["bridge","rescrape","resume"].includes(e.action)}e.s(["NO_SCAN_NOTES",0,o,"SCANNER_UNKNOWN",0,l,"beginScrape",0,x,"busyReason",0,function(e=u){if(!e?.running)return null;let t=e.target?.name;switch(e.action){case"bridge":case"rescrape":case"resume":return t?`${t}’s circle is being scanned`:"A circle is being scanned";case"company":return t?`${t} is being scanned`:"A company is being scanned";case"auto-bridge":case"auto-bridge-retry":case"resume-all":return"Your bridges are being mapped, one by one";case"full":case"refresh":return"Your own connections are being scanned";default:switch(e.action){case"install":return"The scanner's packages are being installed";case"setup":return"The scanner is being set up";case"login":return"The LinkedIn sign-in window is open";case"photos":return"Profile photos are being saved";default:return"A scan is running"}}},"isCircleScan",0,k,"loadScanNotes",0,a,"notReadyMessage",0,function(e){if(!e)return"Could not reach the app.";let t=e.checks||{};return t.scriptsFound?t.dependencies?t.chrome?null:"Google Chrome is not installed.":t.python||t.download?"The scanner is not set up yet — open Scan to set it up.":"No Python 3.10 to 3.14 is installed on this machine.":"The scanner files are missing from this install."},"pickedPerson",0,i,"resumePoint",0,r,"runScrape",0,function(e,t={}){return x(e,t).then(e=>e.ended)},"scannerNow",0,function(){return u},"scansCircleOf",0,function(e,t){if(!k(e)||!t)return!1;let{id:n,name:r}=e.target;return n&&t.id?n===t.id:!!r&&r===t.name},"scraperStatus",0,t,"stopScrape",0,s,"watchScanner",0,w],40996)},22016,(e,t,n)=>{"use strict";e.i(47167),Object.defineProperty(n,"__esModule",{value:!0});var r={default:function(){return m},useLinkStatus:function(){return w}};for(var o in r)Object.defineProperty(n,o,{enumerable:!0,get:r[o]});let a=e.r(90809),i=e.r(43476),s=a._(e.r(71645)),l=e.r(95057),c=e.r(8372),u=e.r(18581),d=e.r(18967),p=e.r(5550),f=e.r(88540),h=e.r(91949),g=e.r(73668),y=e.r(9396);function m(t){var n;let r,o,a,[m,w]=(0,s.useOptimistic)(h.IDLE_LINK_STATUS),x=(0,s.useRef)(null),{href:k,as:v,children:S,prefetch:j=null,passHref:C,replace:A,shallow:T,scroll:O,onClick:E,onMouseEnter:P,onTouchStart:N,legacyBehavior:_=!1,onNavigate:R,transitionTypes:$,ref:I,unstable_dynamicOnHover:z,...M}=t;r=S,_&&("string"==typeof r||"number"==typeof r)&&(r=(0,i.jsx)("a",{children:r}));let U=s.default.useContext(c.AppRouterContext),B=!1!==j,L=!1===j?"none":!0===j?"full":"auto",F="none"!==L?"auto"===L?y.FetchStrategy.PPR:y.FetchStrategy.Full:y.FetchStrategy.PPR,D="string"==typeof(n=v||k)?n:(0,l.formatUrl)(n);if(_){if(r?.$$typeof===Symbol.for("react.lazy"))throw Object.defineProperty(Error("`<Link legacyBehavior>` received a direct child that is either a Server Component, or JSX that was loaded with React.lazy(). This is not supported. Either remove legacyBehavior, or make the direct child a Client Component that renders the Link's `<a>` tag."),"__NEXT_ERROR_CODE",{value:"E863",enumerable:!1,configurable:!0});o=s.default.Children.only(r)}let K=_?o&&"object"==typeof o&&o.ref:I,W,J=s.default.useCallback(e=>(null!==U&&(x.current=(0,h.mountLinkInstance)(e,D,U,F,B,w,W)),()=>{x.current&&((0,h.unmountLinkForCurrentNavigation)(x.current),x.current=null),(0,h.unmountPrefetchableInstance)(e)}),[B,D,U,F,w,W]),Y={ref:(0,u.useMergedRef)(J,K),onClick(t){_||"function"!=typeof E||E(t),_&&o.props&&"function"==typeof o.props.onClick&&o.props.onClick(t),!U||t.defaultPrevented||function(t,n,r,o,a,i,l,c="none"){if("u">typeof window){let u,{nodeName:d}=t.currentTarget;if("A"===d.toUpperCase()&&((u=t.currentTarget.getAttribute("target"))&&"_self"!==u||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||t.nativeEvent&&2===t.nativeEvent.which)||t.currentTarget.hasAttribute("download"))return;if(!(0,g.isLocalURL)(n)){o&&(t.preventDefault(),location.replace(n));return}if(t.preventDefault(),i){let e=!1;if(i({preventDefault:()=>{e=!0}}),e)return}let{dispatchNavigateAction:p}=e.r(99781);s.default.startTransition(()=>{p(n,o?"replace":"push",!1===a?f.ScrollBehavior.NoScroll:f.ScrollBehavior.Default,r.current,l,c)})}}(t,D,x,A,O,R,$,L)},onMouseEnter(e){_||"function"!=typeof P||P(e),_&&o.props&&"function"==typeof o.props.onMouseEnter&&o.props.onMouseEnter(e),U&&B&&(0,h.onNavigationIntent)(e.currentTarget,!0===z)},onTouchStart:function(e){_||"function"!=typeof N||N(e),_&&o.props&&"function"==typeof o.props.onTouchStart&&o.props.onTouchStart(e),U&&B&&(0,h.onNavigationIntent)(e.currentTarget,!0===z)}};return(0,d.isAbsoluteUrl)(D)?Y.href=D:_&&!C&&("a"!==o.type||"href"in o.props)||(Y.href=(0,p.addBasePath)(D)),a=_?s.default.cloneElement(o,Y):(0,i.jsx)("a",{...M,...Y,children:r}),(0,i.jsx)(b.Provider,{value:m,children:a})}let b=(0,s.createContext)(h.IDLE_LINK_STATUS),w=()=>(0,s.useContext)(b);("function"==typeof n.default||"object"==typeof n.default&&null!==n.default)&&void 0===n.default.__esModule&&(Object.defineProperty(n.default,"__esModule",{value:!0}),Object.assign(n.default,n),t.exports=n.default)},18581,(e,t,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"useMergedRef",{enumerable:!0,get:function(){return o}});let r=e.r(71645);function o(e,t){let n=(0,r.useRef)(null),o=(0,r.useRef)(null);return(0,r.useCallback)(r=>{if(null===r){let e=n.current;e&&(n.current=null,e());let t=o.current;t&&(o.current=null,t())}else e&&(n.current=a(e,r)),t&&(o.current=a(t,r))},[e,t])}function a(e,t){if("function"!=typeof e)return e.current=t,()=>{e.current=null};{let n=e(t);return"function"==typeof n?n:()=>e(null)}}("function"==typeof n.default||"object"==typeof n.default&&null!==n.default)&&void 0===n.default.__esModule&&(Object.defineProperty(n.default,"__esModule",{value:!0}),Object.assign(n.default,n),t.exports=n.default)},18967,(e,t,n)=>{"use strict";e.i(47167),Object.defineProperty(n,"__esModule",{value:!0});var r={DecodeError:function(){return m},MiddlewareNotFoundError:function(){return k},MissingStaticPage:function(){return x},NormalizeError:function(){return b},PageNotFoundError:function(){return w},SP:function(){return g},ST:function(){return y},WEB_VITALS:function(){return a},execOnce:function(){return i},getDisplayName:function(){return d},getLocationOrigin:function(){return c},getURL:function(){return u},isAbsoluteUrl:function(){return l},isResSent:function(){return p},loadGetInitialProps:function(){return h},normalizeRepeatedSlashes:function(){return f},stringifyError:function(){return v}};for(var o in r)Object.defineProperty(n,o,{enumerable:!0,get:r[o]});let a=["CLS","FCP","FID","INP","LCP","TTFB"];function i(e){let t,n=!1;return(...r)=>(n||(n=!0,t=e(...r)),t)}let s=/^[a-zA-Z][a-zA-Z\d+\-.]*?:/,l=e=>{let t=e.charCodeAt(0);return!!(t>=65&&t<=90||t>=97&&t<=122)&&s.test(e)};function c(){let{protocol:e,hostname:t,port:n}=window.location;return`${e}//${t}${n?":"+n:""}`}function u(){let{href:e}=window.location,t=c();return e.substring(t.length)}function d(e){return"string"==typeof e?e:e.displayName||e.name||"Unknown"}function p(e){return e.finished||e.headersSent}function f(e){let t=e.split("?");return t[0].replace(/\\/g,"/").replace(/\/\/+/g,"/")+(t[1]?`?${t.slice(1).join("?")}`:"")}async function h(e,t){let n=t.res||t.ctx&&t.ctx.res;if(!e.getInitialProps)return t.ctx&&t.Component?{pageProps:await h(t.Component,t.ctx)}:{};let r=await e.getInitialProps(t);if(n&&p(n))return r;if(!r)throw Object.defineProperty(Error(`"${d(e)}.getInitialProps()" should resolve to an object. But found "${r}" instead.`),"__NEXT_ERROR_CODE",{value:"E1025",enumerable:!1,configurable:!0});return r}let g="u">typeof performance,y=g&&["mark","measure","getEntriesByName"].every(e=>"function"==typeof performance[e]);class m extends Error{}class b extends Error{}class w extends Error{constructor(e){super(),this.code="ENOENT",this.name="PageNotFoundError",this.message=`Cannot find module for page: ${e}`}}class x extends Error{constructor(e,t){super(),this.message=`Failed to load static file for page: ${e} ${t}`}}class k extends Error{constructor(){super(),this.code="ENOENT",this.message="Cannot find the middleware module"}}function v(e){return JSON.stringify({message:e.message,stack:e.stack})}},73668,(e,t,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0}),Object.defineProperty(n,"isLocalURL",{enumerable:!0,get:function(){return a}});let r=e.r(18967),o=e.r(52817);function a(e){if(!(0,r.isAbsoluteUrl)(e))return!0;try{let t=(0,r.getLocationOrigin)(),n=new URL(e,t);return n.origin===t&&(0,o.hasBasePath)(n.pathname)}catch(e){return!1}}},98183,(e,t,n)=>{"use strict";Object.defineProperty(n,"__esModule",{value:!0});var r={assign:function(){return l},searchParamsToUrlQuery:function(){return a},urlQueryToSearchParams:function(){return s}};for(var o in r)Object.defineProperty(n,o,{enumerable:!0,get:r[o]});function a(e){let t={};for(let[n,r]of e.entries()){let e=t[n];void 0===e?t[n]=r:Array.isArray(e)?e.push(r):t[n]=[e,r]}return t}function i(e){return"string"==typeof e?e:("number"!=typeof e||isNaN(e))&&"boolean"!=typeof e?"":String(e)}function s(e){let t=new URLSearchParams;for(let[n,r]of Object.entries(e))if(Array.isArray(r))for(let e of r)t.append(n,i(e));else t.set(n,i(r));return t}function l(e,...t){for(let n of t){for(let t of n.keys())e.delete(t);for(let[t,r]of n.entries())e.append(t,r)}return e}},95057,(e,t,n)=>{"use strict";e.i(47167),Object.defineProperty(n,"__esModule",{value:!0});var r={formatUrl:function(){return s},formatWithValidation:function(){return c},urlObjectKeys:function(){return l}};for(var o in r)Object.defineProperty(n,o,{enumerable:!0,get:r[o]});let a=e.r(90809)._(e.r(98183)),i=/https?|ftp|gopher|file/;function s(e){let{auth:t,hostname:n}=e,r=e.protocol||"",o=e.pathname||"",s=e.hash||"",l=e.query||"",c=!1;t=t?encodeURIComponent(t).replace(/%3A/i,":")+"@":"",e.host?c=t+e.host:n&&(c=t+(~n.indexOf(":")?`[${n}]`:n),e.port&&(c+=":"+e.port)),l&&"object"==typeof l&&(l=String(a.urlQueryToSearchParams(l)));let u=e.search||l&&`?${l}`||"";return r&&!r.endsWith(":")&&(r+=":"),e.slashes||(!r||i.test(r))&&!1!==c?(c="//"+(c||""),o&&"/"!==o[0]&&(o="/"+o)):c||(c=""),s&&"#"!==s[0]&&(s="#"+s),u&&"?"!==u[0]&&(u="?"+u),o=o.replace(/[?#]/g,encodeURIComponent),u=u.replace("#","%23"),`${r}${c}${o}${u}${s}`}let l=["auth","hash","host","hostname","href","path","pathname","port","protocol","query","search","slashes"];function c(e){return s(e)}},18566,(e,t,n)=>{t.exports=e.r(76562)}]);
|
|
Binary file
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,92 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.4.2] - 2026-09-29
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Orbit goes past 2nd degree.** Someone you added through a circle, whose own circle is
|
|
13
|
+
scanned, now sits in the fan of the circle they came from, green-ringed, and their people fan
|
|
14
|
+
out behind them a band further out, fainter, with a faint line to each. Their added people's
|
|
15
|
+
circles go further out again, to 6th degree. Before, they sat on the ring as one more bridge,
|
|
16
|
+
and Orbit showed only 2nd degree.
|
|
17
|
+
- **A ring round each connection's dot.** Five thin bars show how much of their circle is
|
|
18
|
+
scanned: all five once their list is read to the end, and part-way the pages read against
|
|
19
|
+
LinkedIn's own count of the list, which scans now keep (no extra traffic). Lists read before
|
|
20
|
+
scans kept a count show two. A small badge counts the people in their circle ready to scan,
|
|
21
|
+
and a catalyst is the green outline on the dot. It's on the Galaxy and on Bridge Chains'
|
|
22
|
+
bridges.
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
- **The Galaxy in bands when more than your connections are drawn.** With 2nd (or 3rd) degree
|
|
26
|
+
on, your connections sit on a tighter inner ring, their circles in a band outside it, and past
|
|
27
|
+
someone you added through a circle, their people further out again. Each band is sorted by
|
|
28
|
+
tier, S nearest, and has a faint label. Lines follow the chain: from you to your connections,
|
|
29
|
+
from each connection to their circle, and from someone you added to theirs. Your connections
|
|
30
|
+
alone keep the roomier tier rings.
|
|
31
|
+
|
|
32
|
+
### Removed
|
|
33
|
+
- **The "N only here" line under each bridge in Bridge Chains.** Their card still says who is
|
|
34
|
+
reached only through them.
|
|
35
|
+
|
|
36
|
+
## [0.4.1] - 2026-09-29
|
|
37
|
+
|
|
38
|
+
### Added
|
|
39
|
+
- **Which connections open the same doors.** A card says whose circle overlaps theirs most, when
|
|
40
|
+
it's real (15% or more, and at least 3 people): "Opens the same doors as Tom: 62% of the
|
|
41
|
+
people either reaches, both do". Bridge Chains' Degrees box adds how much of your 2nd degree
|
|
42
|
+
you reach two or more ways.
|
|
43
|
+
- **Circle scans keep who among your connections knows whom.** Your own connections turn up in
|
|
44
|
+
other people's lists, and were set aside there and forgotten. Each is now kept as a tie
|
|
45
|
+
between the two, in a new table, with no extra LinkedIn traffic, since the scan read them
|
|
46
|
+
anyway. Nothing shows them yet: they're what clusters and communities will be built from.
|
|
47
|
+
Deleting someone deletes their ties too.
|
|
48
|
+
- **Who only one connection reaches.** In Bridge Chains, each connection with a scanned circle
|
|
49
|
+
shows how many of its people none of your other connections reach ("746 only here"), and
|
|
50
|
+
their card says it in a line: those people are reached through them alone. It's their
|
|
51
|
+
exclusive reach, counted across every circle you've scanned (`lib/brokerage.js`).
|
|
52
|
+
- **Network Circle's Filter picks degrees.** *1st*, *2nd* and *3rd* chips choose who the
|
|
53
|
+
Galaxy draws: your connections, anyone in a scanned circle, and anyone only a company scan
|
|
54
|
+
found. Any mix works, and 2nd without 1st shows who's valuable outside your own
|
|
55
|
+
connections. Each person counts once, at the nearest degree. Further out is drawn a little
|
|
56
|
+
smaller and fainter, gathered near the connection whose circle they're in, and the tier
|
|
57
|
+
counts follow what's drawn. It opens on your connections alone, as before.
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
- **The Galaxy marks its tier bands.** A faint dashed ring, labelled S to D, sits where each
|
|
61
|
+
tier's dots settle, so the bands read at a glance, most of all with a filter on. Not on a
|
|
62
|
+
phone, whose layout has no rings.
|
|
63
|
+
- **Degrees opens on Bridge Chains,** then Separation, then Orbit, in the menu too. Orbit
|
|
64
|
+
used to come first.
|
|
65
|
+
- **Orbit is in Degrees only.** Network Circle's Orbit was slow on a big network and showed
|
|
66
|
+
nothing the Galaxy doesn't; a Network Circle left on it opens the Galaxy.
|
|
67
|
+
- **A new app icon: Orbits.** Your tier rings round you, with one bridge reaching out through
|
|
68
|
+
them. It's the Mac app's icon, the website's tab icon and its home-screen icon.
|
|
69
|
+
- **The Scan page asks before a risky search budget.** Picking more than 100 searches a
|
|
70
|
+
day, or no monthly cap, now asks first, because a real account was restricted after 373
|
|
71
|
+
searches in 24 hours, run back to back (it had opened only 7 profiles that day). While
|
|
72
|
+
the budget stays that high, a note under it says so, with a button back to 50 a day and
|
|
73
|
+
250 a month. Lowering a budget, or anything up to 100 a day, is never asked about.
|
|
74
|
+
|
|
75
|
+
### Fixed
|
|
76
|
+
- **A card's circle map never draws a degree as a solid line.** A big circle, or the people
|
|
77
|
+
behind someone you added packed into their slice, used to run together into one line or
|
|
78
|
+
band. When a slice holds more than fit, its dots now take a few rows, neighbours
|
|
79
|
+
alternating between them, each still behind whoever they hang off, and the dots are sized
|
|
80
|
+
for the most crowded slice.
|
|
81
|
+
- **Bridge Chains: a hover preview no longer draws over the bridges.** With many bridges the
|
|
82
|
+
overview grows extra rings, and a bridge's circle, previewed on hover, landed on top of
|
|
83
|
+
them. It now starts beyond the outermost ring of bridges.
|
|
84
|
+
- **Stop during a re-map's wait keeps the circle.** Re-mapping someone deleted their circle
|
|
85
|
+
first and then waited out the minute between profile views, so a Stop in that minute left
|
|
86
|
+
it deleted and unread. It now waits first and deletes only once the read can start.
|
|
87
|
+
- **A profile-view cap typed into `scan-limits.json` by hand stays within the choices.** It
|
|
88
|
+
counts as the largest offered choice under it (10, 25, 50 or 100), in the scanner and on
|
|
89
|
+
the Scan page alike; before, 1,000 was honoured and the picker showed a different number.
|
|
90
|
+
- **The Filter menu highlights the view that's showing.** After *View Bridge →* from the
|
|
91
|
+
Galaxy, Orbit showed but no view was highlighted.
|
|
92
|
+
- **No *Scan Full Company* on the sample or a CSV import.** Paths offered it there, and it
|
|
93
|
+
searched LinkedIn for a network that isn't saved. A line says scanning needs your own network.
|
|
94
|
+
|
|
9
95
|
## [0.4.0] - 2026-09-28
|
|
10
96
|
|
|
11
97
|
### Added
|
package/db/schema.js
CHANGED
|
@@ -134,6 +134,20 @@ CREATE TABLE IF NOT EXISTS company_scores (
|
|
|
134
134
|
|
|
135
135
|
-- Small key/value facts about this install, e.g. which scoring model the
|
|
136
136
|
-- stored scores were computed with.
|
|
137
|
+
-- Two of your own connections who know each other, seen when a circle scan
|
|
138
|
+
-- found one of them in the other's list (they're dropped from that circle,
|
|
139
|
+
-- being yours already). By profile URL, the smaller first, so a pair is one
|
|
140
|
+
-- row whichever circle showed it. No extra LinkedIn traffic: the scan read
|
|
141
|
+
-- them anyway. For clustering and communities later (lib/ties.js).
|
|
142
|
+
CREATE TABLE IF NOT EXISTS connection_ties (
|
|
143
|
+
id TEXT, -- lib/db.js gives every row one
|
|
144
|
+
user_id TEXT NOT NULL,
|
|
145
|
+
a_url TEXT NOT NULL,
|
|
146
|
+
b_url TEXT NOT NULL,
|
|
147
|
+
seen_at TEXT DEFAULT (datetime('now')),
|
|
148
|
+
PRIMARY KEY (user_id, a_url, b_url)
|
|
149
|
+
);
|
|
150
|
+
|
|
137
151
|
CREATE TABLE IF NOT EXISTS app_meta (
|
|
138
152
|
key TEXT PRIMARY KEY,
|
|
139
153
|
value TEXT
|
package/lib/brokerage.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Who is irreplaceable among your bridges.
|
|
2
|
+
//
|
|
3
|
+
// A bridge's exclusive reach: for each person in their circle, 1 ÷ how many of
|
|
4
|
+
// your bridges reach that person, added up. Someone only Maya reaches counts 1
|
|
5
|
+
// to her; someone three bridges reach counts a third to each. It's ego
|
|
6
|
+
// betweenness (Everett & Borgatti 2005), which on this network's shape (you →
|
|
7
|
+
// your connections → their circles) gives Brandes' betweenness, in one pass.
|
|
8
|
+
// `only` is how many nobody else reaches: "212 of your people only through
|
|
9
|
+
// Maya". People who are your connections already need no bridge, so they
|
|
10
|
+
// don't count.
|
|
11
|
+
//
|
|
12
|
+
// Plain functions, no React; tests/brokerage.test.mjs.
|
|
13
|
+
|
|
14
|
+
import { keyFor } from './separation.js';
|
|
15
|
+
|
|
16
|
+
/** Map of bridge id → { reach, only, total }, from the rows the views already have. */
|
|
17
|
+
export function exclusiveReach(degree2 = [], connections = []) {
|
|
18
|
+
const yours = new Set((connections || []).map(keyFor));
|
|
19
|
+
const bridgesOf = new Map(); // person → the bridges who reach them
|
|
20
|
+
for (const row of degree2 || []) {
|
|
21
|
+
const bridge = row?.source_connection_id;
|
|
22
|
+
if (bridge == null) continue;
|
|
23
|
+
const key = keyFor(row);
|
|
24
|
+
if (yours.has(key)) continue;
|
|
25
|
+
let set = bridgesOf.get(key);
|
|
26
|
+
if (!set) bridgesOf.set(key, (set = new Set()));
|
|
27
|
+
set.add(bridge);
|
|
28
|
+
}
|
|
29
|
+
const out = new Map();
|
|
30
|
+
for (const set of bridgesOf.values()) {
|
|
31
|
+
for (const bridge of set) {
|
|
32
|
+
const r = out.get(bridge) || { reach: 0, only: 0, total: 0 };
|
|
33
|
+
r.reach += 1 / set.size;
|
|
34
|
+
r.total += 1;
|
|
35
|
+
if (set.size === 1) r.only += 1;
|
|
36
|
+
out.set(bridge, r);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Which of your connections open the same doors: for each, the one whose
|
|
44
|
+
* circle overlaps theirs most, as the share of people either reaches that both
|
|
45
|
+
* do (Jaccard). "Maya and Tom open the same doors (62%)". Pairs are counted
|
|
46
|
+
* from the people reached two or more ways, so it stays quick.
|
|
47
|
+
*
|
|
48
|
+
* @returns Map of bridge id → { with, share, shared }
|
|
49
|
+
*/
|
|
50
|
+
export function bridgeOverlap(degree2 = [], connections = []) {
|
|
51
|
+
const reach = exclusiveReach(degree2, connections);
|
|
52
|
+
const yours = new Set((connections || []).map(keyFor));
|
|
53
|
+
const bridgesOf = new Map();
|
|
54
|
+
for (const row of degree2 || []) {
|
|
55
|
+
const bridge = row?.source_connection_id;
|
|
56
|
+
if (bridge == null) continue;
|
|
57
|
+
const key = keyFor(row);
|
|
58
|
+
if (yours.has(key)) continue;
|
|
59
|
+
let set = bridgesOf.get(key);
|
|
60
|
+
if (!set) bridgesOf.set(key, (set = new Set()));
|
|
61
|
+
set.add(bridge);
|
|
62
|
+
}
|
|
63
|
+
const shared = new Map(); // "a|b" → people both reach
|
|
64
|
+
for (const set of bridgesOf.values()) {
|
|
65
|
+
if (set.size < 2) continue;
|
|
66
|
+
const list = [...set];
|
|
67
|
+
for (let i = 0; i < list.length; i++) {
|
|
68
|
+
for (let j = i + 1; j < list.length; j++) {
|
|
69
|
+
const k = list[i] < list[j] ? `${list[i]}|${list[j]}` : `${list[j]}|${list[i]}`;
|
|
70
|
+
shared.set(k, (shared.get(k) || 0) + 1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const best = new Map();
|
|
75
|
+
for (const [k, both] of shared) {
|
|
76
|
+
const [a, b] = k.split('|');
|
|
77
|
+
const union = reach.get(a).total + reach.get(b).total - both;
|
|
78
|
+
const share = union ? both / union : 0;
|
|
79
|
+
for (const [me, other] of [[a, b], [b, a]]) {
|
|
80
|
+
const cur = best.get(me);
|
|
81
|
+
if (!cur || share > cur.share) best.set(me, { with: other, share, shared: both });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return best;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Of everyone you reach through a circle, the share you reach two or more ways. */
|
|
88
|
+
export function redundancy(degree2 = [], connections = []) {
|
|
89
|
+
const reach = exclusiveReach(degree2, connections);
|
|
90
|
+
let people = 0;
|
|
91
|
+
let only = 0;
|
|
92
|
+
for (const r of reach.values()) { people += r.reach; only += r.only; }
|
|
93
|
+
return people ? 1 - only / people : 0;
|
|
94
|
+
}
|
package/lib/chain-layout.js
CHANGED
|
@@ -137,3 +137,92 @@ export function dotRadius(spacing, tier) {
|
|
|
137
137
|
const scale = tier === 'S' ? 1 : tier === 'A' ? 0.86 : tier === 'B' ? 0.72 : 0.6;
|
|
138
138
|
return Math.max(1.4, Math.min(7, spacing * 0.42 * scale));
|
|
139
139
|
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Where a bridge's circle is previewed on hover: a band beyond every ring of
|
|
143
|
+
* bridges. With many bridges the overview grows extra rings, past where the
|
|
144
|
+
* preview used to start, and it drew over them. `clear` leaves room for a
|
|
145
|
+
* hovered bridge's dot (20) and its name under it.
|
|
146
|
+
*/
|
|
147
|
+
export function previewBand(maxR, bridgeRings = [], clear = 34) {
|
|
148
|
+
const edge = Math.max(0, ...bridgeRings.map((r) => r.radius));
|
|
149
|
+
const inner = Math.max(maxR * 0.66, edge ? edge + clear : 0);
|
|
150
|
+
return { inner, outer: Math.max(maxR * 0.8, inner + maxR * 0.14) };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const TIER_BANDS = ['S', 'A', 'B', 'C', 'D'];
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* An opened circle's people in tier bands round the person: S nearest, then A,
|
|
157
|
+
* B, C and D, with a gap between bands like Network Circle's tier orbits, so a
|
|
158
|
+
* big circle reads as layers instead of one clump. Points come back in the
|
|
159
|
+
* order of `rows`, each with `slot`: the angle its ring gives each dot. The
|
|
160
|
+
* spacing closes up, down to `minSpacing`, until every band fits inside
|
|
161
|
+
* `outer`; past that the bands carry on outwards and zooming out shows them.
|
|
162
|
+
*
|
|
163
|
+
* @returns {{ spacing: number, edge: number, bands: { tier: string, inner: number, outer: number }[],
|
|
164
|
+
* points: { x: number, y: number, angle: number, slot: number }[] }}
|
|
165
|
+
*/
|
|
166
|
+
export function tierBandLayout(rows, { inner, outer, spacing, minSpacing = spacing / 3, gap = spacing }) {
|
|
167
|
+
const groups = TIER_BANDS.map((tier) => ({ tier, idx: [] }));
|
|
168
|
+
rows.forEach((row, i) => {
|
|
169
|
+
const t = TIER_BANDS.indexOf(row?.tier);
|
|
170
|
+
groups[t < 0 ? 4 : t].idx.push(i); // no tier: with D
|
|
171
|
+
});
|
|
172
|
+
const used = groups.filter((g) => g.idx.length);
|
|
173
|
+
const place = (s) => {
|
|
174
|
+
const points = new Array(rows.length);
|
|
175
|
+
const bands = [];
|
|
176
|
+
let r = inner;
|
|
177
|
+
for (const g of used) {
|
|
178
|
+
const l = ringLayout(g.idx.length, { inner: r, outer: Infinity, spacing: s, minSpacing: s });
|
|
179
|
+
g.idx.forEach((rowIndex, j) => {
|
|
180
|
+
const p = l.points[j];
|
|
181
|
+
points[rowIndex] = { x: p.x, y: p.y, angle: p.angle, slot: TAU / l.rings[p.ring].count };
|
|
182
|
+
});
|
|
183
|
+
const edge = Math.max(r, ...l.rings.map((x) => x.radius));
|
|
184
|
+
bands.push({ tier: g.tier, inner: r, outer: edge });
|
|
185
|
+
r = edge + gap * (s / spacing);
|
|
186
|
+
}
|
|
187
|
+
return { spacing: s, points, bands, edge: bands.length ? bands[bands.length - 1].outer : inner };
|
|
188
|
+
};
|
|
189
|
+
let best = place(spacing);
|
|
190
|
+
if (best.edge <= outer) return best;
|
|
191
|
+
let lo = minSpacing;
|
|
192
|
+
let hi = spacing;
|
|
193
|
+
best = place(lo);
|
|
194
|
+
if (best.edge > outer) return best;
|
|
195
|
+
for (let i = 0; i < 20; i++) {
|
|
196
|
+
const mid = (lo + hi) / 2;
|
|
197
|
+
const tryMid = place(mid);
|
|
198
|
+
if (tryMid.edge <= outer) { lo = mid; best = tryMid; } else hi = mid;
|
|
199
|
+
}
|
|
200
|
+
return best;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* The people behind each person in an opened circle: their own circle, drawn
|
|
205
|
+
* as a fan of small dots beyond `from`, centred on that person's angle and no
|
|
206
|
+
* wider than their slot (at most a sixth of the circle), so each fan sits
|
|
207
|
+
* behind its own person. At most `cap` dots a fan and about `total` in all, so
|
|
208
|
+
* a big network stays quick; `more` is how many weren't drawn.
|
|
209
|
+
*
|
|
210
|
+
* @param {{ angle: number, slot: number, count: number }[]} anchors
|
|
211
|
+
* @returns {({ points: { x: number, y: number }[], more: number } | null)[]}
|
|
212
|
+
*/
|
|
213
|
+
export function outerFans(anchors, { from, spacing = 7, cap = 40, total = 1200 } = {}) {
|
|
214
|
+
const fans = anchors.filter((a) => a?.count > 0).length;
|
|
215
|
+
const each = Math.max(6, Math.min(cap, Math.floor(total / Math.max(1, fans))));
|
|
216
|
+
return anchors.map((a) => {
|
|
217
|
+
if (!(a?.count > 0)) return null;
|
|
218
|
+
const n = Math.min(a.count, each);
|
|
219
|
+
// Only as wide as the dots need at `spacing`, never wider than their slot:
|
|
220
|
+
// more rows once it's full, so a small fan stays a tight cluster.
|
|
221
|
+
const room = Math.min(a.slot || TAU, TAU / 6);
|
|
222
|
+
const width = Math.min(room, Math.max((spacing * 3) / from, (n * spacing) / from));
|
|
223
|
+
const l = ringLayout(n, {
|
|
224
|
+
inner: from, outer: Infinity, spacing, minSpacing: spacing, start: a.angle - width / 2, sweep: width,
|
|
225
|
+
});
|
|
226
|
+
return { points: l.points.map(({ x, y }) => ({ x, y })), more: a.count - n };
|
|
227
|
+
});
|
|
228
|
+
}
|
package/lib/circle.js
CHANGED
|
@@ -137,17 +137,34 @@ export function circleLayout(rings = [], size = 240) {
|
|
|
137
137
|
for (let k = 0; k < R; k++) {
|
|
138
138
|
const radius = radiusOf(k);
|
|
139
139
|
const people = rings[k].people;
|
|
140
|
-
|
|
140
|
+
// More than their slice holds without the dots touching: rows, neighbours
|
|
141
|
+
// alternating between them, so a big circle never draws as a solid line.
|
|
142
|
+
// Each keeps its angle behind who they hang off. Rows go out towards the
|
|
143
|
+
// next ring, or for the outermost, in towards the one before (less than
|
|
144
|
+
// half way either side, so two rings' rows never meet).
|
|
145
|
+
const gap = Math.max(2.4, size / 100);
|
|
146
|
+
const inward = k === R - 1 && R > 1;
|
|
147
|
+
const band = (inward ? radius - radiusOf(k - 1) : (k + 1 < R ? radiusOf(k + 1) : half * 0.97) - radius) * 0.45;
|
|
148
|
+
const maxRows = Math.max(1, Math.floor(band / gap) + 1);
|
|
149
|
+
const rowGap = maxRows > 1 ? (inward ? -1 : 1) * Math.min(gap * 1.2, band / (maxRows - 1)) : 0;
|
|
150
|
+
const rowsFor = (count, arc) => clamp(Math.ceil((count * gap) / Math.max(1e-9, radius * arc)), 1, maxRows);
|
|
151
|
+
let rows = 1;
|
|
152
|
+
let room = Infinity; // the least room any one dot gets along its row
|
|
141
153
|
const items = [];
|
|
142
154
|
for (const [parentId, group] of byParent[k]) {
|
|
143
155
|
const [a0, a1] = k === 0 ? [START, START + 2 * Math.PI] : span.get(parentId) || [START, START + 2 * Math.PI];
|
|
144
156
|
const total = group.reduce((s, p) => s + weight.get(p), 0);
|
|
157
|
+
const groupRows = rowsFor(group.length, a1 - a0);
|
|
158
|
+
rows = Math.max(rows, groupRows);
|
|
159
|
+
room = Math.min(room, (radius * (a1 - a0) * groupRows) / Math.max(1, group.length));
|
|
160
|
+
let n = 0;
|
|
145
161
|
let a = a0;
|
|
146
162
|
for (const p of group) {
|
|
147
163
|
const w = ((a1 - a0) * weight.get(p)) / total;
|
|
148
164
|
const angle = a + w / 2;
|
|
149
|
-
const
|
|
150
|
-
const
|
|
165
|
+
const r = radius + (n++ % groupRows) * rowGap;
|
|
166
|
+
const x = half + r * Math.cos(angle);
|
|
167
|
+
const y = half + r * Math.sin(angle);
|
|
151
168
|
items.push({ ...p, angle, x, y });
|
|
152
169
|
if (p.state === 'connected') span.set(p.row.id, [a, a + w]);
|
|
153
170
|
a += w;
|
|
@@ -163,7 +180,9 @@ export function circleLayout(rings = [], size = 240) {
|
|
|
163
180
|
spokes.push({ x1: it.x, y1: it.y, x2: half + nextR * Math.cos(mid), y2: half + nextR * Math.sin(mid) });
|
|
164
181
|
}
|
|
165
182
|
}
|
|
166
|
-
|
|
183
|
+
// Sized by the most crowded slice, and never wider than the gap between rows.
|
|
184
|
+
const dotR = clamp(Math.min(room * 0.32, rows > 1 ? Math.abs(rowGap) * 0.42 : Infinity), 0.8, size / 60);
|
|
185
|
+
out.push({ degree: rings[k].degree, radius, dotR, rows, items });
|
|
167
186
|
}
|
|
168
187
|
return { size, center: { x: half, y: half }, rings: out, spokes };
|
|
169
188
|
}
|
package/lib/degrees.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Everyone the app knows, by degree, for Network Circle's degree filter.
|
|
2
|
+
//
|
|
3
|
+
// 1st: your connections. 2nd: anyone in a scanned circle, including the people
|
|
4
|
+
// behind someone you added, since you're connected to them now. 3rd: anyone a
|
|
5
|
+
// company scan found who is neither. Each person counts once, at the nearest
|
|
6
|
+
// degree they're found (by profile, lib/separation.js keyFor), whichever
|
|
7
|
+
// circle or scan found them first.
|
|
8
|
+
|
|
9
|
+
import { keyFor } from './separation.js';
|
|
10
|
+
|
|
11
|
+
export function peopleByDegree(degree1 = [], degree2 = [], degree3 = []) {
|
|
12
|
+
const seen = new Set();
|
|
13
|
+
const take = (rows, degree) => {
|
|
14
|
+
const out = [];
|
|
15
|
+
for (const row of rows || []) {
|
|
16
|
+
const key = keyFor(row);
|
|
17
|
+
if (seen.has(key)) continue;
|
|
18
|
+
seen.add(key);
|
|
19
|
+
out.push(row.degree === degree ? row : { ...row, degree });
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
};
|
|
23
|
+
return { 1: take(degree1, 1), 2: take(degree2, 2), 3: take(degree3, 3) };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function tierCountsOf(rows = []) {
|
|
27
|
+
const counts = {};
|
|
28
|
+
for (const row of rows) counts[row.tier] = (counts[row.tier] || 0) + 1;
|
|
29
|
+
return counts;
|
|
30
|
+
}
|
package/lib/dot-rings.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// The thin ring of five bars round a person's dot: how much of their circle is
|
|
2
|
+
// scanned (lib/reach.js scanBars). Blake's pick, design C: thin bars, a
|
|
3
|
+
// catalyst's green outline on the dot itself, a small count badge.
|
|
4
|
+
//
|
|
5
|
+
// Plain path strings, so the Galaxy (d3) and Bridge Chains (React) draw the
|
|
6
|
+
// same shape. Bars run clockwise from the top.
|
|
7
|
+
|
|
8
|
+
const GAP = 0.32; // radians between bars
|
|
9
|
+
|
|
10
|
+
/** Five arcs of radius r around (0, 0): [{ d, i }] */
|
|
11
|
+
export function ringSegments(r) {
|
|
12
|
+
const span = (2 * Math.PI - 5 * GAP) / 5;
|
|
13
|
+
return Array.from({ length: 5 }, (_, i) => {
|
|
14
|
+
const a0 = -Math.PI / 2 + GAP / 2 + i * (span + GAP);
|
|
15
|
+
const a1 = a0 + span;
|
|
16
|
+
const p = (a) => `${(r * Math.cos(a)).toFixed(2)} ${(r * Math.sin(a)).toFixed(2)}`;
|
|
17
|
+
return { i, d: `M${p(a0)} A${r} ${r} 0 0 1 ${p(a1)}` };
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const RING = { filled: '#1abc9c', empty: 'rgba(255,255,255,0.16)', badge: '#7F77DD' };
|
package/lib/ingest.js
CHANGED
|
@@ -31,12 +31,12 @@ export function uniqueByProfile(records) {
|
|
|
31
31
|
*/
|
|
32
32
|
export function splitAlreadyConnected(records, firstDegreeUrls) {
|
|
33
33
|
const keep = [];
|
|
34
|
-
|
|
34
|
+
const connected = []; // their profile URLs: ties between your connections (lib/ties.js)
|
|
35
35
|
for (const r of records) {
|
|
36
|
-
if (firstDegreeUrls.has(r.profile_url))
|
|
36
|
+
if (firstDegreeUrls.has(r.profile_url)) connected.push(r.profile_url);
|
|
37
37
|
else keep.push(r);
|
|
38
38
|
}
|
|
39
|
-
return { keep, alreadyConnected };
|
|
39
|
+
return { keep, alreadyConnected: connected.length, connected };
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const MONTHS = ['january', 'february', 'march', 'april', 'may', 'june', 'july',
|