six-degrees 0.4.2 → 0.4.3

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.
Files changed (201) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +13 -13
  4. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  5. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  6. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_not-found/page.js +1 -1
  10. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  11. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  12. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  13. package/.next/standalone/.next/server/app/_not-found.rsc +18 -17
  14. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +18 -17
  15. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -13
  16. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  17. package/.next/standalone/.next/server/app/api/admin-delete/route.js.nft.json +1 -1
  18. package/.next/standalone/.next/server/app/api/admin-update/route.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/api/bridges/route.js.nft.json +1 -1
  20. package/.next/standalone/.next/server/app/api/bulk-import/route.js.nft.json +1 -1
  21. package/.next/standalone/.next/server/app/api/company-scores/legacy/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/company-scores/route.js.nft.json +1 -1
  23. package/.next/standalone/.next/server/app/api/connections/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/data/export/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/data/import/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/data/restart/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/data/reveal/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/data/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/delete-cluster/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/ingest/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/network/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/outreach/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/scraper/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/settings/sector-preview/route.js.nft.json +1 -1
  38. package/.next/standalone/.next/server/app/api/settings/sector-suggestions/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/setup-profile/route.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/api/unlock/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/api/update-images/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/users/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/avatars/[file]/route.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/import/page.js +1 -1
  46. package/.next/standalone/.next/server/app/import/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/import/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/import.html +1 -1
  49. package/.next/standalone/.next/server/app/import.rsc +22 -21
  50. package/.next/standalone/.next/server/app/import.segments/_full.segment.rsc +22 -21
  51. package/.next/standalone/.next/server/app/import.segments/_tree.segment.rsc +2 -2
  52. package/.next/standalone/.next/server/app/import.segments/import/__PAGE__.segment.rsc +16 -15
  53. package/.next/standalone/.next/server/app/index.html +1 -1
  54. package/.next/standalone/.next/server/app/index.rsc +20 -19
  55. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +16 -15
  56. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +20 -19
  57. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  58. package/.next/standalone/.next/server/app/launch/page.js +1 -1
  59. package/.next/standalone/.next/server/app/launch/page.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/launch/page_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/app/launch.html +2 -2
  62. package/.next/standalone/.next/server/app/launch.rsc +22 -21
  63. package/.next/standalone/.next/server/app/launch.segments/_full.segment.rsc +22 -21
  64. package/.next/standalone/.next/server/app/launch.segments/_tree.segment.rsc +2 -2
  65. package/.next/standalone/.next/server/app/launch.segments/launch/__PAGE__.segment.rsc +16 -15
  66. package/.next/standalone/.next/server/app/page.js +1 -1
  67. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  68. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  69. package/.next/standalone/.next/server/app/paths/page.js +1 -1
  70. package/.next/standalone/.next/server/app/paths/page.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/paths/page_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/paths.html +1 -1
  73. package/.next/standalone/.next/server/app/paths.rsc +22 -21
  74. package/.next/standalone/.next/server/app/paths.segments/_full.segment.rsc +22 -21
  75. package/.next/standalone/.next/server/app/paths.segments/_tree.segment.rsc +2 -2
  76. package/.next/standalone/.next/server/app/paths.segments/paths/__PAGE__.segment.rsc +16 -15
  77. package/.next/standalone/.next/server/app/profile/page.js +1 -1
  78. package/.next/standalone/.next/server/app/profile/page.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/profile/page_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/app/profile.html +1 -1
  81. package/.next/standalone/.next/server/app/profile.rsc +22 -21
  82. package/.next/standalone/.next/server/app/profile.segments/_full.segment.rsc +22 -21
  83. package/.next/standalone/.next/server/app/profile.segments/_tree.segment.rsc +2 -2
  84. package/.next/standalone/.next/server/app/profile.segments/profile/__PAGE__.segment.rsc +16 -15
  85. package/.next/standalone/.next/server/app/queue/page.js +1 -1
  86. package/.next/standalone/.next/server/app/queue/page.js.nft.json +1 -1
  87. package/.next/standalone/.next/server/app/queue/page_client-reference-manifest.js +1 -1
  88. package/.next/standalone/.next/server/app/queue.html +1 -1
  89. package/.next/standalone/.next/server/app/queue.rsc +22 -21
  90. package/.next/standalone/.next/server/app/queue.segments/_full.segment.rsc +22 -21
  91. package/.next/standalone/.next/server/app/queue.segments/_tree.segment.rsc +2 -2
  92. package/.next/standalone/.next/server/app/queue.segments/queue/__PAGE__.segment.rsc +16 -15
  93. package/.next/standalone/.next/server/app/scores/page.js +1 -1
  94. package/.next/standalone/.next/server/app/scores/page.js.nft.json +1 -1
  95. package/.next/standalone/.next/server/app/scores/page_client-reference-manifest.js +1 -1
  96. package/.next/standalone/.next/server/app/scores.html +1 -1
  97. package/.next/standalone/.next/server/app/scores.rsc +22 -21
  98. package/.next/standalone/.next/server/app/scores.segments/_full.segment.rsc +22 -21
  99. package/.next/standalone/.next/server/app/scores.segments/_tree.segment.rsc +2 -2
  100. package/.next/standalone/.next/server/app/scores.segments/scores/__PAGE__.segment.rsc +16 -15
  101. package/.next/standalone/.next/server/app/settings/page.js +1 -1
  102. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  103. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  104. package/.next/standalone/.next/server/app/settings.html +1 -1
  105. package/.next/standalone/.next/server/app/settings.rsc +22 -21
  106. package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +22 -21
  107. package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  108. package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +16 -15
  109. package/.next/standalone/.next/server/app/setup/page.js +1 -1
  110. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  111. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  112. package/.next/standalone/.next/server/app/setup.html +1 -1
  113. package/.next/standalone/.next/server/app/setup.rsc +22 -21
  114. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +22 -21
  115. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  116. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +16 -15
  117. package/.next/standalone/.next/server/chunks/_1_fynia._.js +5 -5
  118. package/.next/standalone/.next/server/chunks/_1itd1o_._.js +1 -1
  119. package/.next/standalone/.next/server/chunks/lib_db-client_15le7cw.js +1 -1
  120. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0d3vjsq._.js +3 -0
  121. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0m4vk0b._.js +3 -0
  122. package/.next/standalone/.next/server/chunks/ssr/{_15xuwkv._.js → _012mop3._.js} +2 -2
  123. package/.next/standalone/.next/server/chunks/ssr/_1163x49._.js +3 -0
  124. package/.next/standalone/.next/server/chunks/ssr/_1av11ws._.js +3 -0
  125. package/.next/standalone/.next/server/chunks/ssr/_1ig7em7._.js +3 -0
  126. package/.next/standalone/.next/server/chunks/ssr/app_page_1fazqbf.js +2 -2
  127. package/.next/standalone/.next/server/chunks/ssr/app_setup_page_1-282zx.js +1 -1
  128. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  129. package/.next/standalone/.next/server/middleware-manifest.json +5 -5
  130. package/.next/standalone/.next/server/pages/404.html +1 -1
  131. package/.next/standalone/.next/server/pages/500.html +1 -1
  132. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  133. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  134. package/.next/standalone/.next/static/chunks/{049vavjsmqgmn.js → 0_3ubivay59bq.js} +4 -4
  135. package/.next/standalone/.next/static/chunks/{2p6o90z0vgcwr.css → 0bo1dxn5gwzpk.css} +1 -1
  136. package/.next/standalone/.next/static/chunks/0f4ugd6v3ph0-.js +1 -0
  137. package/.next/standalone/.next/static/chunks/10ogurbcuf3nq.js +1 -0
  138. package/.next/standalone/.next/static/chunks/1489t7jrjojk_.js +1 -0
  139. package/.next/standalone/.next/static/chunks/{0ax_9zzboyv6d.js → 17-rhp8sg4m1b.js} +2 -2
  140. package/.next/standalone/.next/static/chunks/1zunq4tk-u3ng.js +1 -0
  141. package/.next/standalone/.next/static/chunks/1zwjy1mmpkdrg.js +6 -0
  142. package/.next/standalone/.next/static/chunks/2_wcobfqry2uj.js +1 -0
  143. package/.next/standalone/.next/static/chunks/2dwtoszeq91us.js +1 -0
  144. package/.next/standalone/.next/static/chunks/{0ljxa-wk_iu__.js → 2pyo4j84prgp6.js} +3 -3
  145. package/.next/{static/chunks/22x2_r768-u5i.js → standalone/.next/static/chunks/2wwmljnf7yn_5.js} +1 -1
  146. package/.next/{static/chunks/2xjho0lroiwlq.js → standalone/.next/static/chunks/3kllnkb3hof1s.js} +1 -1
  147. package/.next/standalone/CHANGELOG.md +27 -0
  148. package/.next/standalone/app/api/scraper/route.js +17 -0
  149. package/.next/standalone/app/components/FilterPanel.js +37 -5
  150. package/.next/standalone/app/components/OrbitGraph.js +17 -4
  151. package/.next/standalone/app/components/ScanStatusBar.js +82 -0
  152. package/.next/standalone/app/globals.css +4 -0
  153. package/.next/standalone/app/layout.js +3 -0
  154. package/.next/standalone/app/page.js +8 -4
  155. package/.next/standalone/app/setup/page.js +13 -1
  156. package/.next/standalone/lib/scraper-client.js +1 -0
  157. package/.next/standalone/package-lock.json +2 -2
  158. package/.next/standalone/package.json +1 -1
  159. package/.next/standalone/scripts/scrape.py +219 -5
  160. package/.next/static/chunks/{049vavjsmqgmn.js → 0_3ubivay59bq.js} +4 -4
  161. package/.next/static/chunks/{2p6o90z0vgcwr.css → 0bo1dxn5gwzpk.css} +1 -1
  162. package/.next/static/chunks/0f4ugd6v3ph0-.js +1 -0
  163. package/.next/static/chunks/10ogurbcuf3nq.js +1 -0
  164. package/.next/static/chunks/1489t7jrjojk_.js +1 -0
  165. package/.next/static/chunks/{0ax_9zzboyv6d.js → 17-rhp8sg4m1b.js} +2 -2
  166. package/.next/static/chunks/1zunq4tk-u3ng.js +1 -0
  167. package/.next/static/chunks/1zwjy1mmpkdrg.js +6 -0
  168. package/.next/static/chunks/2_wcobfqry2uj.js +1 -0
  169. package/.next/static/chunks/2dwtoszeq91us.js +1 -0
  170. package/.next/static/chunks/{0ljxa-wk_iu__.js → 2pyo4j84prgp6.js} +3 -3
  171. package/.next/{standalone/.next/static/chunks/22x2_r768-u5i.js → static/chunks/2wwmljnf7yn_5.js} +1 -1
  172. package/.next/{standalone/.next/static/chunks/2xjho0lroiwlq.js → static/chunks/3kllnkb3hof1s.js} +1 -1
  173. package/CHANGELOG.md +27 -0
  174. package/lib/scraper-client.js +1 -0
  175. package/package.json +1 -1
  176. package/scripts/scrape.py +219 -5
  177. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h1_f_2._.js +0 -3
  178. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__19ip1qq._.js +0 -3
  179. package/.next/standalone/.next/server/chunks/ssr/_06w_gl4._.js +0 -3
  180. package/.next/standalone/.next/server/chunks/ssr/_13kzrwv._.js +0 -3
  181. package/.next/standalone/.next/server/chunks/ssr/_1hgd5dp._.js +0 -3
  182. package/.next/standalone/.next/server/chunks/ssr/node_modules_1f8t_rp._.js +0 -23
  183. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_client_components_server-async-storage_0t1dato.js +0 -3
  184. package/.next/standalone/.next/static/chunks/0mp9b72fm-jp6.js +0 -6
  185. package/.next/standalone/.next/static/chunks/1pre1cotntk6-.js +0 -1
  186. package/.next/standalone/.next/static/chunks/28bu26ausqzmn.js +0 -1
  187. package/.next/standalone/.next/static/chunks/2jz311xl1pp_8.js +0 -1
  188. package/.next/standalone/.next/static/chunks/2ot61qsv6_0eq.js +0 -1
  189. package/.next/standalone/.next/static/chunks/3zs_6-nn0dapb.js +0 -1
  190. package/.next/static/chunks/0mp9b72fm-jp6.js +0 -6
  191. package/.next/static/chunks/1pre1cotntk6-.js +0 -1
  192. package/.next/static/chunks/28bu26ausqzmn.js +0 -1
  193. package/.next/static/chunks/2jz311xl1pp_8.js +0 -1
  194. package/.next/static/chunks/2ot61qsv6_0eq.js +0 -1
  195. package/.next/static/chunks/3zs_6-nn0dapb.js +0 -1
  196. /package/.next/standalone/.next/static/{wGVrXBkFLmEB4snfhtOcO → 814ehZBeFO2rUKle7mzX-}/_buildManifest.js +0 -0
  197. /package/.next/standalone/.next/static/{wGVrXBkFLmEB4snfhtOcO → 814ehZBeFO2rUKle7mzX-}/_clientMiddlewareManifest.js +0 -0
  198. /package/.next/standalone/.next/static/{wGVrXBkFLmEB4snfhtOcO → 814ehZBeFO2rUKle7mzX-}/_ssgManifest.js +0 -0
  199. /package/.next/static/{wGVrXBkFLmEB4snfhtOcO → 814ehZBeFO2rUKle7mzX-}/_buildManifest.js +0 -0
  200. /package/.next/static/{wGVrXBkFLmEB4snfhtOcO → 814ehZBeFO2rUKle7mzX-}/_clientMiddlewareManifest.js +0 -0
  201. /package/.next/static/{wGVrXBkFLmEB4snfhtOcO → 814ehZBeFO2rUKle7mzX-}/_ssgManifest.js +0 -0
package/scripts/scrape.py CHANGED
@@ -27,11 +27,12 @@ in one session — LinkedIn detects automation and flags your account.
27
27
  import argparse
28
28
  import json
29
29
  import os
30
+ import re
30
31
  import signal
31
32
  import sys
32
33
  import time
33
34
  import requests
34
- from datetime import datetime
35
+ from datetime import datetime, timedelta
35
36
  from pathlib import Path
36
37
  from urllib.parse import parse_qs, urlparse
37
38
 
@@ -1274,6 +1275,17 @@ PAGE_PAUSE = 20 # seconds before each next page of results
1274
1275
  CHUNK_COOLDOWN = 60 # extra seconds after every SAVE_EVERY_PAGES pages
1275
1276
  LEGACY_PAGES_READ = 10 # how far every read before 0.1.6 went, at most
1276
1277
 
1278
+ # Experimental all-day pacing for Auto-Bridge (--experimental; item 44, Graph
1279
+ # Study §8). Openly slow, never disguised: fixed waits, no random "human" timing.
1280
+ # A sitting of SESSION_PAGES searches, then a long rest; searches only in the
1281
+ # daytime on this computer's clock; and at the daily budget it waits for the
1282
+ # budget to free up instead of stopping. Pages are saved one at a time.
1283
+ EXPERIMENT = {"on": False, "pages": 0, "wire": 0}
1284
+ SESSION_PAGES = 10 # searches in one sitting
1285
+ SESSION_REST = 45 * 60 # the rest after each sitting
1286
+ DRIP_HOURS = (9, 19) # searches only from 09:00 to 19:00, local time
1287
+ WIRE_SAMPLES = 5 # raw LinkedIn responses kept per run, for research
1288
+
1277
1289
 
1278
1290
  # Someone whose connections are hidden can never produce a 2nd-degree row. The
1279
1291
  # "who still needs bridging" query is "everyone with no 2nd-degree rows", so
@@ -1787,6 +1799,193 @@ def stop_requested():
1787
1799
  return _stop_requested
1788
1800
 
1789
1801
 
1802
+ # LinkedIn's own data (experimental, with --experimental). While a circle is
1803
+ # read, the responses the browser already gets from LinkedIn's own API are kept
1804
+ # and read for the same people the page shows: the same traffic, no extra
1805
+ # requests. The page text stays in charge. This fills blanks for people both
1806
+ # found and gives the list's real total; people only in LinkedIn's data are
1807
+ # logged, not added, since a results page can carry other boxes ("People you
1808
+ # may know"). Each page logs how the two compare, and a few raw responses are
1809
+ # kept in the data folder (wire-samples/) to tune it from real ones.
1810
+ _WIRE = {"page": None, "responses": []}
1811
+
1812
+
1813
+ def _wire_tap(page):
1814
+ if _WIRE["page"] is page:
1815
+ return
1816
+ _WIRE["page"], _WIRE["responses"] = page, []
1817
+
1818
+ def keep(response):
1819
+ url = response.url
1820
+ if "/voyager/api/" in url and ("search" in url.lower() or "graphql" in url):
1821
+ _WIRE["responses"].append(response)
1822
+ page.on("response", keep)
1823
+
1824
+
1825
+ def mutual_count_text(text):
1826
+ """LinkedIn's mutual line as a number, as the page reader's mutualCount reads it; None otherwise."""
1827
+ line = re.sub(r"\s+", " ", str(text or "")).strip()
1828
+ if not re.search(r"\bmutual connections?$", line, re.I) or len(line) > 300:
1829
+ return None
1830
+ num = lambda v: int(str(v).replace(",", ""))
1831
+ names = lambda v: len([p for p in re.split(r"\s*,\s*|\s+and\s+", v) if p])
1832
+ m = re.match(r"^([\d,]+) mutual connections?$", line, re.I)
1833
+ if m:
1834
+ return num(m.group(1))
1835
+ m = re.match(r"^(.*?)\s*\band ([\d,]+) others? mutual connections?$", line, re.I)
1836
+ if m:
1837
+ return max(1, names(m.group(1))) + num(m.group(2))
1838
+ if re.search(r"\bis a mutual connection$", line, re.I):
1839
+ return 1
1840
+ m = re.match(r"^(.+?)\s+are mutual connections$", line, re.I)
1841
+ return names(m.group(1)) if m else None
1842
+
1843
+
1844
+ def voyager_people(payload):
1845
+ """Everyone in a LinkedIn API response who looks like a search result: anything with a
1846
+ title and a link to a profile, wherever it sits in the response."""
1847
+ out, seen = [], set()
1848
+ text = lambda v: (v.get("text") if isinstance(v, dict) else v if isinstance(v, str) else "") or ""
1849
+
1850
+ def photo(x):
1851
+ try:
1852
+ for a in (x.get("image") or {}).get("attributes") or []:
1853
+ vi = ((a.get("detailData") or {}).get("nonEntityProfilePicture") or {}).get("vectorImage") or a.get("vectorImage")
1854
+ if vi and vi.get("rootUrl") and vi.get("artifacts"):
1855
+ best = max(vi["artifacts"], key=lambda f: f.get("width") or 0)
1856
+ return vi["rootUrl"] + (best.get("fileIdentifyingUrlPathSegment") or "")
1857
+ except Exception:
1858
+ pass
1859
+ return ""
1860
+
1861
+ def walk(x):
1862
+ if isinstance(x, dict):
1863
+ nav = x.get("navigationUrl")
1864
+ if isinstance(nav, str) and "/in/" in nav and isinstance(x.get("title"), dict):
1865
+ url = nav.split("?")[0].split("#")[0].rstrip("/") + "/"
1866
+ name = text(x.get("title")).strip()
1867
+ if name and name != "LinkedIn Member" and url not in seen:
1868
+ seen.add(url)
1869
+ mutual = None
1870
+ for ins in x.get("insightsResolutionResults") or []:
1871
+ mutual = mutual_count_text(text(((ins or {}).get("simpleInsight") or {}).get("title")))
1872
+ if mutual:
1873
+ break
1874
+ out.append({"name": name, "headline": text(x.get("primarySubtitle")).strip(),
1875
+ "profileUrl": url, "imageUrl": photo(x), "mutualCount": mutual})
1876
+ for v in x.values():
1877
+ walk(v)
1878
+ elif isinstance(x, list):
1879
+ for v in x:
1880
+ walk(v)
1881
+ walk(payload)
1882
+ return out
1883
+
1884
+
1885
+ def voyager_total(payload):
1886
+ """The list's length, when a response says it (totalResultCount); None otherwise."""
1887
+ stack = [payload]
1888
+ while stack:
1889
+ x = stack.pop()
1890
+ if isinstance(x, dict):
1891
+ v = x.get("totalResultCount")
1892
+ if isinstance(v, int) and v > 0:
1893
+ return v
1894
+ stack.extend(x.values())
1895
+ elif isinstance(x, list):
1896
+ stack.extend(x)
1897
+ return None
1898
+
1899
+
1900
+ def _wire_sample(data):
1901
+ if EXPERIMENT["wire"] >= WIRE_SAMPLES:
1902
+ return
1903
+ try:
1904
+ raw = json.dumps(data)
1905
+ if len(raw) > 500_000:
1906
+ return
1907
+ folder = _home() / "wire-samples"
1908
+ folder.mkdir(parents=True, exist_ok=True)
1909
+ (folder / f"{int(time.time() * 1000)}.json").write_text(raw)
1910
+ EXPERIMENT["wire"] += 1
1911
+ except Exception:
1912
+ pass
1913
+
1914
+
1915
+ def _wire_merge(page, profile_url, page_results):
1916
+ """Fill blanks in this page's people from LinkedIn's own data, and log how the two compare."""
1917
+ got, _WIRE["responses"] = _WIRE["responses"], []
1918
+ people, total = [], None
1919
+ for response in got:
1920
+ try:
1921
+ data = response.json()
1922
+ except Exception:
1923
+ continue
1924
+ _wire_sample(data)
1925
+ people.extend(voyager_people(data))
1926
+ total = total or voyager_total(data)
1927
+ if total:
1928
+ _LIST_TOTALS[profile_url] = int(total)
1929
+ own = (profile_url or "").rstrip("/").split("/")[-1]
1930
+ by_url = {c.get("profileUrl"): c for c in page_results}
1931
+ only_wire = 0
1932
+ for w in people:
1933
+ if own and own in w["profileUrl"]:
1934
+ continue
1935
+ c = by_url.get(w["profileUrl"])
1936
+ if c is None:
1937
+ only_wire += 1
1938
+ continue
1939
+ for k in ("name", "headline", "imageUrl"):
1940
+ if not c.get(k) and w.get(k):
1941
+ c[k] = w[k]
1942
+ if c.get("mutualCount") is None and w.get("mutualCount") is not None:
1943
+ c["mutualCount"] = w["mutualCount"]
1944
+ print(f" LinkedIn's own data: {len(people)} people, {only_wire} not in the page text"
1945
+ + (f", list of about {total:,}" if total else ""), flush=True)
1946
+ return page_results
1947
+
1948
+
1949
+ def _drip_wait(label, seconds):
1950
+ """Wait `seconds` for an experimental rest, saying when it ends, a line a minute. False if stopped."""
1951
+ seconds = max(1, int(seconds))
1952
+ until = datetime.fromtimestamp(time.time() + seconds).strftime("%H:%M")
1953
+ print(f" {label}. Carrying on at {until}.", flush=True)
1954
+ return interruptible_sleep(seconds, on_tick=lambda left: print(f" {label}: {max(1, left // 60)} min to go", flush=True), step=60)
1955
+
1956
+
1957
+ def _seconds_until_search_frees(now=None):
1958
+ """How long until the oldest search in the last 24 hours drops out of the daily budget."""
1959
+ now = now if now is not None else time.time()
1960
+ recent = sorted(t for t in _read_activity()["searches"] if now - DAY_SECONDS < t <= now)
1961
+ return (recent[0] + DAY_SECONDS - now + 5) if recent else 5
1962
+
1963
+
1964
+ def _drip_before_search():
1965
+ """Experimental pacing, before a search: rest after a sitting, sleep through the
1966
+ night, and wait for a used daily budget to free up. True to go ahead, False if stopped."""
1967
+ while True:
1968
+ if EXPERIMENT["pages"] >= SESSION_PAGES:
1969
+ EXPERIMENT["pages"] = 0
1970
+ if not _drip_wait(f"Resting after {SESSION_PAGES} pages", SESSION_REST):
1971
+ return False
1972
+ continue
1973
+ now = datetime.fromtimestamp(time.time())
1974
+ if not (DRIP_HOURS[0] <= now.hour < DRIP_HOURS[1]):
1975
+ start = now.replace(hour=DRIP_HOURS[0], minute=0, second=0, microsecond=0)
1976
+ if now.hour >= DRIP_HOURS[1]:
1977
+ start += timedelta(days=1)
1978
+ if not _drip_wait("Resting overnight", (start - now).total_seconds()):
1979
+ return False
1980
+ continue
1981
+ left, kind = searches_left()
1982
+ if left <= 0 and kind == "daily":
1983
+ if not _drip_wait("Today's searches are used", _seconds_until_search_frees()):
1984
+ return False
1985
+ continue
1986
+ return True
1987
+
1988
+
1790
1989
  def interruptible_sleep(seconds, on_tick=None, step=5):
1791
1990
  """Sleep, but notice a stop request. Returns False if we were interrupted."""
1792
1991
  waited = 0
@@ -2402,6 +2601,12 @@ def _scrape_one_bridge(page, bridge_name, bridge_id, profile_url, max_pages=LINK
2402
2601
  # 1st, 2nd and 3rd+ — all of them; the app drops your own connections when
2403
2602
  # it saves. It used to be announced as a "3rd+ filter", which it never was.
2404
2603
  search_url = f"https://www.linkedin.com/search/results/people/?network=%5B%22F%22%2C%22S%22%2C%22O%22%5D&connectionOf=%5B%22{urn}%22%5D"
2604
+ if EXPERIMENT["on"] and not _drip_before_search():
2605
+ reach["more"] = True
2606
+ print(" Stopped before their list opened; the next run carries on from there.")
2607
+ return [], "stopped", reach
2608
+ if EXPERIMENT["on"]:
2609
+ _wire_tap(page)
2405
2610
  left, kind = searches_left()
2406
2611
  if left <= 0:
2407
2612
  reach["budget"] = kind
@@ -2547,6 +2752,9 @@ def _scrape_one_bridge(page, bridge_name, bridge_id, profile_url, max_pages=LINK
2547
2752
  break
2548
2753
 
2549
2754
  page_results = [c for c in page_results if slug not in c.get("profileUrl", "")]
2755
+ if EXPERIMENT["on"]:
2756
+ page_results = _wire_merge(page, profile_url, page_results)
2757
+ EXPERIMENT["pages"] += 1
2550
2758
  chunk.extend(page_results)
2551
2759
  chunk_pages += 1
2552
2760
  reach["last"] = pg
@@ -2569,7 +2777,7 @@ def _scrape_one_bridge(page, bridge_name, bridge_id, profile_url, max_pages=LINK
2569
2777
  # own path: through the page-limit branch, a missing Next button would
2570
2778
  # have marked the list finished.
2571
2779
  left, kind = searches_left()
2572
- if left <= 0:
2780
+ if left <= 0 and not (EXPERIMENT["on"] and kind == "daily"):
2573
2781
  # Looking for Next costs nothing. No Next on a live page of results
2574
2782
  # means the list is finished — not paused at the next page forever.
2575
2783
  if _find_next(page) is None and not _window_closed(page) and _result_links(page):
@@ -2582,10 +2790,10 @@ def _scrape_one_bridge(page, bridge_name, bridge_id, profile_url, max_pages=LINK
2582
2790
 
2583
2791
  # Rest before the next search, and longer after every SAVE_EVERY_PAGES.
2584
2792
  rest = PAGE_PAUSE
2585
- if (pg - start_page + 1) % SAVE_EVERY_PAGES == 0:
2793
+ if not EXPERIMENT["on"] and (pg - start_page + 1) % SAVE_EVERY_PAGES == 0:
2586
2794
  rest += CHUNK_COOLDOWN
2587
2795
  print(f" {SAVE_EVERY_PAGES} pages read; resting {rest}s before the next search.")
2588
- if not interruptible_sleep(rest) or _window_closed(page):
2796
+ if not interruptible_sleep(rest) or _window_closed(page) or (EXPERIMENT["on"] and not _drip_before_search()):
2589
2797
  reach["more"] = True
2590
2798
  print(f" Stopped before page {pg + 1}; the next run carries on from there.")
2591
2799
  break
@@ -2610,7 +2818,7 @@ def _scrape_one_bridge(page, bridge_name, bridge_id, profile_url, max_pages=LINK
2610
2818
 
2611
2819
  # Save as it goes, so a stop, a crash or the search limit costs at most
2612
2820
  # the last few pages rather than the whole list.
2613
- if on_save and chunk_pages >= SAVE_EVERY_PAGES:
2821
+ if on_save and chunk_pages >= (1 if EXPERIMENT["on"] else SAVE_EVERY_PAGES):
2614
2822
  on_save(_dedupe(chunk), reach["last"], True, reach["urn"])
2615
2823
  chunk, chunk_pages = [], 0
2616
2824
 
@@ -3752,6 +3960,9 @@ Examples:
3752
3960
  parser.add_argument("--bridge", type=str, help="Name of one bridge person to scrape")
3753
3961
  parser.add_argument("--rescrape", type=str, help="Delete + re-scrape a bridge's cluster from scratch")
3754
3962
  parser.add_argument("--company", type=str, help="Scan everyone the app can see at one company")
3963
+ parser.add_argument("--experimental", action="store_true",
3964
+ help="Auto-Bridge, experimental: all-day pacing (sittings, rests, daytime only, "
3965
+ "waits for the daily budget) and reading LinkedIn's own data beside the page text")
3755
3966
  parser.add_argument("--auto-bridge", action="store_true",
3756
3967
  help="Map every bridge in turn, highest tier first")
3757
3968
  parser.add_argument("--retry-private", action="store_true",
@@ -3783,6 +3994,9 @@ Examples:
3783
3994
  "(every scan also does this at its end)")
3784
3995
  parser.add_argument("--headless", action="store_true", help="Run browser in headless mode")
3785
3996
  args = parser.parse_args()
3997
+ if getattr(args, "experimental", False):
3998
+ EXPERIMENT["on"] = True
3999
+ print("Experimental Auto-Bridge: all-day pacing, and LinkedIn's own data read beside the page text.")
3786
4000
  args.max_pages = max(1, min(LINKEDIN_MAX_PAGES, args.max_pages))
3787
4001
 
3788
4002
  # A failed save ends the run with its reason, not a traceback (TRAPS §32).
@@ -1,3 +0,0 @@
1
- module.exports=[9272,a=>{a.v({className:"geist_2ae47f08-module__h69qWW__className",variable:"geist_2ae47f08-module__h69qWW__variable"})},79474,a=>{a.v({className:"geist_mono_eb58308d-module__w_p2Lq__className",variable:"geist_mono_eb58308d-module__w_p2Lq__variable"})},61143,a=>{"use strict";a.s(["default",()=>b]);let b=(0,a.i(11857).registerClientReference)(function(){throw Error("Attempted to call the default export of [project]/app/components/StaleServerBanner.js from the server, but it's on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/app/components/StaleServerBanner.js","default")},42041,a=>{"use strict";var b=a.i(61143);a.n(b)},62925,a=>{"use strict";var b=a.i(7997),c=a.i(9272);let d={className:c.default.className,style:{fontFamily:"'Geist', 'Geist Fallback'",fontStyle:"normal"}};null!=c.default.variable&&(d.variable=c.default.variable);var e=a.i(79474);let f={className:e.default.className,style:{fontFamily:"'Geist Mono', 'Geist Mono Fallback'",fontStyle:"normal"}};null!=e.default.variable&&(f.variable=e.default.variable);var g=a.i(68354),h=a.i(42041);a.s(["default",0,function({children:a}){return(0,b.jsx)("html",{lang:"en",className:`${d.variable} ${f.variable}`,children:(0,b.jsx)("body",{style:{margin:0,padding:0,background:"#0a0a1a"},children:(0,b.jsxs)(g.default,{children:[a,(0,b.jsx)(h.default,{})]})})})},"metadata",0,{title:"Six Degrees",description:"Maps your LinkedIn network: who you know, who they know, and the shortest path to someone you haven't met. Runs on your own computer; nothing is uploaded.",viewport:"width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"}],62925)},19325,function(a){a.n(a.i(62925))},69067,a=>{"use strict";a.s(["default",()=>c,"useUser",()=>d]);var b=a.i(11857);let c=(0,b.registerClientReference)(function(){throw Error("Attempted to call the default export of [project]/app/components/UserProvider.js from the server, but it's on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/app/components/UserProvider.js","default"),d=(0,b.registerClientReference)(function(){throw Error("Attempted to call useUser() from the server but useUser is on the client. It's not possible to invoke a client function from the server, it can only be rendered as a Component or passed to props of a Client Component.")},"[project]/app/components/UserProvider.js","useUser")},68354,a=>{"use strict";var b=a.i(69067);a.n(b)}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__0h1_f_2._.js.map
@@ -1,3 +0,0 @@
1
- module.exports=[18622,(a,b,c)=>{b.exports=a.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},20635,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},24725,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},43285,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/dynamic-access-async-storage.external.js",()=>require("next/dist/server/app-render/dynamic-access-async-storage.external.js"))},56704,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},59043,(a,b,c)=>{b.exports=a.x("next/dist/server/runtime-reacts.external.js",()=>require("next/dist/server/runtime-reacts.external.js"))},17372,a=>{"use strict";var b=a.i(87924),c=a.i(72131);a.s(["default",0,function(){let[a,d]=(0,c.useState)(null);return((0,c.useEffect)(()=>{let a=!0;return fetch("/api/update").then(a=>a.json()).then(b=>{a&&b?.restartNeeded&&d(b)}).catch(()=>{}),()=>{a=!1}},[]),a)?(0,b.jsxs)("div",{role:"status",style:{position:"fixed",left:0,right:0,bottom:0,zIndex:9999,background:"linear-gradient(90deg, #FFD700, #FF6B35)",color:"#1a1200",padding:"9px 16px",fontSize:13,fontWeight:600,lineHeight:1.5,display:"flex",alignItems:"center",justifyContent:"center",gap:10,flexWrap:"wrap",textAlign:"center"},children:[(0,b.jsxs)("span",{children:["You have newer code on disk (",a.sha,") than this server is running (",a.bootSha,"). Restart it to see the changes — ",(0,b.jsx)("code",{style:{background:"rgba(0,0,0,0.16)",padding:"1px 6px",borderRadius:4},children:"Ctrl-C"})," in the terminal, then ",(0,b.jsx)("code",{style:{background:"rgba(0,0,0,0.16)",padding:"1px 6px",borderRadius:4},children:"npm run dev"}),"."]}),(0,b.jsx)("button",{onClick:()=>d(null),style:{border:"none",background:"rgba(0,0,0,0.18)",color:"#1a1200",borderRadius:6,padding:"3px 10px",fontWeight:700,cursor:"pointer"},children:"Dismiss"})]}):null}])},75857,58834,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(73167),e=a.i(42510);let f="true"===process.env.NEXT_PUBLIC_DEMO_MODE,g={id:"synthetic-demo-user",name:"You",headline:"Sample network"},h=null;async function i(){if(h)return h;let a=await fetch("/demo-data.json",{cache:"no-cache"});if(!a.ok)throw Error("demo-data.json not found — run: node scripts/gen-synthetic.mjs");let b=await a.json();return h={degree1:b.degree1||[],degree2:b.degree2||[]}}async function j(){let a=await i();return(0,e.saveSessionNetwork)({degree1:a.degree1,degree2:a.degree2,source:"sample"}),{degree1:a.degree1.length,degree2:a.degree2.length}}a.s(["DEMO_USER",0,g,"IS_DEMO",0,f,"loadDemoNetwork",0,i,"loadSampleIntoSession",0,j],58834);let k=(0,c.createContext)({userId:null,userName:null,userProfile:null,ready:!1});a.s(["default",0,function({children:a}){let[h,i]=(0,c.useState)(null),[j,l]=(0,c.useState)(null),[m,n]=(0,c.useState)(null),[o,p]=(0,c.useState)(!1);return(0,c.useEffect)(()=>{if(f){i(g.id),l(g.name),n({name:g.name,headline:g.headline,role:"",company:"",industry:"",sectors:[],goals:[],linkedin_url:""}),p(!0);return}if((0,e.hasCsvNetwork)()){i(e.CSV_USER.id),l(e.CSV_USER.name),n({name:e.CSV_USER.name,headline:"Imported from your LinkedIn CSV",role:"",company:"",industry:"",sectors:[],goals:[],linkedin_url:""}),p(!0);return}fetch("/api/users?me=1").then(a=>a.json()).then(a=>{let b=a.user;if(!b)throw Error("no profile");(0,d.setUser)(b.id,b.name),i(b.id),l(b.name),n({name:b.name,headline:b.headline||"",role:b.role||"",company:b.company||"",industry:b.industry||"",sectors:b.sectors||[],goals:b.goals||[],linkedin_url:b.linkedin_url||""})}).catch(()=>{(0,d.hasUser)()&&(i((0,d.getUserId)()),l((0,d.getUserName)()))}).finally(()=>p(!0))},[]),(0,b.jsx)(k.Provider,{value:{userId:h,userName:j,userProfile:m,ready:o,login:(a,b)=>{(0,d.setUser)(a,b),i(a),l(b),fetch(`/api/users?id=${a}`).then(a=>a.json()).then(a=>{a.user&&n({name:a.user.name,headline:a.user.headline||"",role:a.user.role||"",company:a.user.company||"",industry:a.user.industry||"",sectors:a.user.sectors||[],goals:a.user.goals||[],linkedin_url:a.user.linkedin_url||""})}).catch(()=>{})}},children:a})},"useUser",0,function(){return(0,c.useContext)(k)}],75857)},42602,(a,b,c)=>{"use strict";b.exports=a.r(18622)},9270,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.AppRouterContext},36313,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.HooksClientContext},18341,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.ServerInsertedHtml},35112,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactDOM},87924,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactJsxRuntime},38783,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactServerDOMTurbopackClient},72131,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].React}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__19ip1qq._.js.map
@@ -1,3 +0,0 @@
1
- module.exports=[16874,a=>{"use strict";var b=a.i(87924);let c="1px solid rgba(255,255,255,0.1)";function d({children:a,style:c}){return(0,b.jsx)("div",{style:{fontSize:13.5,color:"#8b9a9a",lineHeight:1.6,marginTop:4,...c},children:a})}a.s(["Body",0,d,"Btn",0,function({children:a,onClick:d,disabled:e,primary:f,tone:g,type:h="button"}){return(0,b.jsx)("button",{type:h,onClick:d,disabled:e,style:{padding:"9px 18px",borderRadius:7,fontSize:13.5,fontWeight:650,color:e?"#667":"#fff",border:c,background:e?"rgba(255,255,255,0.05)":"bad"===g?"rgba(255,80,80,0.15)":f?"linear-gradient(135deg, #9B59B6, #3498DB)":"rgba(255,255,255,0.08)",cursor:e?"not-allowed":"pointer"},children:a})},"FONT",0,'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',"LINE",0,c,"Mono",0,function({children:a}){return(0,b.jsx)("code",{style:{background:"rgba(255,255,255,0.08)",padding:"1px 5px",borderRadius:4,wordBreak:"break-all"},children:a})},"Section",0,function({id:a,title:e,intro:f,children:g}){return(0,b.jsxs)("section",{id:a,style:{padding:"24px 0",borderBottom:c,scrollMarginTop:16},children:[(0,b.jsx)("h2",{style:{fontSize:16,fontWeight:650,margin:"0 0 6px"},children:e}),f&&(0,b.jsx)(d,{style:{marginTop:0,marginBottom:12},children:f}),g]})},"Status",0,function({children:a,tone:c}){return(0,b.jsxs)("div",{role:"status",style:{marginTop:10,padding:"10px 14px",borderRadius:8,fontSize:13.5,lineHeight:1.6,color:"ok"===c?"#00ff88":"bad"===c?"#ff7676":"#e8e8ee",background:"ok"===c?"rgba(0,255,136,0.08)":"bad"===c?"rgba(255,80,80,0.08)":"rgba(255,255,255,0.05)",border:`1px solid ${"ok"===c?"rgba(0,255,136,0.3)":"bad"===c?"rgba(255,80,80,0.3)":"rgba(255,255,255,0.12)"}`},children:["ok"===c&&"✓ ",a]})}])},9282,a=>{"use strict";var b=a.i(30889);function c(a){let c=(0,b.readTitle)(a);return{key:c.key,label:c.label,level:c.level}}function d(a){return(0,b.currentCompany)(a)}let e=[{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}],f={key:"unknown",label:"Unclear",color:"#555c66"},g=Object.fromEntries([...e,f].map(a=>[a.key,a])),h=a=>g[a]||f;function i(a,b){for(let c of[a,b]){if(!c)continue;let a=e.find(a=>a.words.test(c));if(a)return a}return f}let j=(a,b)=>i(a,b).key,k=a=>c(a).level>=4;a.s(["INDUSTRIES",0,e,"UNKNOWN_INDUSTRY",0,f,"buildCompanyIndex",0,function(a=[]){let c=new Map,d=a=>(c.has(a)||c.set(a,(0,b.rolesWithCompanies)(a)),c.get(a)),{industries:e}=(0,b.networkCompanies)(a,{industryOf:j,rolesOf:d}),f=new Map;for(let b of a){let a=b.profile_url||`id:${b.id}`,c=f.get(a);(!c||(b.degree||9)<(c.degree||9))&&f.set(a,b)}let g=new Map;for(let a of f.values()){let b=d(a).find(a=>!a.former)?.company;if(!b)continue;let c=g.get(b);c||(c={name:b,people:[],d1:0,d2:0,d3:0,S:0,A:0,senior:0},g.set(b,c)),c.people.push(a),1===a.degree?c.d1++:2===a.degree?c.d2++:c.d3++,"S"===a.tier&&c.S++,"A"===a.tier&&c.A++,k(a.headline)&&c.senior++}for(let a of g.values())a.industry=h(e.get(a.name));return g},"companyLinks",0,function(a=[],b=[]){let c=new Map;for(let b of a){let a=d(b);a&&c.set(b.id,a)}let e=new Map;for(let a of b){let b=c.get(a.source_connection_id),f=d(a);if(!b||!f||b===f)continue;let[g,h]=b<f?[b,f]:[f,b],i=`${g}\u0000${h}`,j=e.get(i);j||(j={a:g,b:h,weight:0,via:new Set},e.set(i,j)),j.weight++,j.via.add(a.source_connection_id)}return[...e.values()]},"companyOf",0,d,"getSeniority",0,c,"industryByKey",0,h,"industryOf",0,i,"isSenior",0,k,"waysInto",0,function(a,b=[],c=[]){let e=b.filter(b=>d(b)===a),f=new Map;for(let b of c)d(b)===a&&f.set(b.source_connection_id,(f.get(b.source_connection_id)||0)+1);let g=new Map(b.map(a=>[a.id,a]));return{direct:e,bridges:[...f.entries()].map(([a,b])=>({bridge:g.get(a),n:b})).filter(a=>a.bridge).sort((a,b)=>b.n-a.n||(Number(b.bridge.power_score)||0)-(Number(a.bridge.power_score)||0))}}])},54919,a=>{"use strict";var b=a.i(9282);let c=new Map(b.INDUSTRIES.map(a=>[a.key,a.color])),d=new Map([...b.INDUSTRIES.map(a=>[a.key,Object.freeze({key:a.key,label:a.label,color:a.color,group:a.key,kind:"industry"})]),...Object.entries({software:["Software & SaaS","tech","function"],"ai-data":["AI & Data","tech","function"],cybersecurity:["Cybersecurity","tech","function"],telecom:["Telecom","tech","industry"],fintech:["Fintech & Payments","finance","industry"],banking:["Banking & Lending","finance","industry"],"vc-pe":["Venture Capital & Private Equity","finance","industry"],wealth:["Wealth & Asset Management","finance","industry"],insurance:["Insurance","finance","industry"],accounting:["Accounting & Tax","finance","function"],crypto:["Crypto & Web3","finance","industry"],hospitals:["Hospitals & Clinics","health","industry"],dental:["Dental","health","industry"],"pharma-biotech":["Pharma & Biotech","health","industry"],"medical-devices":["Medical Devices","health","industry"],"mental-health":["Mental Health","health","industry"],"fitness-wellness":["Fitness & Wellness","health","industry"],veterinary:["Veterinary & Animal Care","health","industry"],k12:["K-12 Education","education","industry"],"higher-ed":["Higher Education","education","industry"],"marketing-advertising":["Marketing & Advertising","media","function"],"pr-comms":["PR & Communications","media","function"],"media-publishing":["Media & Publishing","media","industry"],"creator-economy":["Creator Economy","media","industry"],"film-tv-music":["Film, TV & Music","entertainment","industry"],"gaming-esports":["Gaming & Esports","entertainment","industry"],sports:["Sports","entertainment","industry"],"ecommerce-retail":["E-commerce & Retail","consumer","industry"],"consumer-goods":["Consumer Goods","consumer","industry"],restaurants:["Restaurants & Food Service","consumer","industry"],"hospitality-travel":["Hospitality & Travel","consumer","industry"],"beauty-personal-care":["Beauty & Personal Care","consumer","industry"],logistics:["Logistics & Supply Chain","industry","industry"],manufacturing:["Manufacturing","industry","industry"],energy:["Energy & Utilities","industry","industry"],automotive:["Automotive","industry","industry"],agriculture:["Agriculture & Farming","industry","industry"],"aerospace-defense":["Aerospace & Defense","defense","industry"],military:["Military","defense","industry"],government:["Government & Public Sector","defense","industry"],legal:["Legal","consulting","function"],"management-consulting":["Management Consulting","consulting","function"],"hr-recruiting":["HR & Recruiting","consulting","function"],"security-services":["Security Services","consulting","function"],"real-estate":["Real Estate","realestate","industry"],"construction-trades":["Construction & Trades","realestate","industry"],charities:["Nonprofits & Charities","nonprofit","industry"],"social-work":["Social Work & Human Services","nonprofit","industry"],faith:["Faith & Ministry","nonprofit","industry"]}).map(([a,[d,e,f]])=>[a,Object.freeze({key:a,label:d,color:c.get(e)||b.UNKNOWN_INDUSTRY.color,group:e,kind:f})])]);a.s(["sectorByKey",0,function(a){return d.get(a)||{key:a,label:b.UNKNOWN_INDUSTRY.label,color:b.UNKNOWN_INDUSTRY.color,group:null,kind:null}}])}];
2
-
3
- //# sourceMappingURL=_06w_gl4._.js.map
@@ -1,3 +0,0 @@
1
- module.exports=[36839,a=>{"use strict";var b=a.i(87924),c=a.i(75857);a.s(["default",0,function({children:a}){let{userId:d,ready:e}=(0,c.useUser)();return e&&d?a:(0,b.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:e?(0,b.jsxs)("div",{style:{maxWidth:420},children:[(0,b.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,b.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,b.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},23310,a=>{"use strict";async function b(a){let b=a?`/api/network?userId=${encodeURIComponent(a)}`:"/api/network",c=await fetch(b);if(!c.ok)throw Error(`Failed to load network (${c.status})`);let d=await c.json();return{degree1:d.degree1||[],degree2:d.degree2||[],degree3:d.degree3||[]}}a.s(["loadNetwork",0,b])},56377,a=>{"use strict";let b=/^[A-Za-z0-9_-]+\.(webp|jpg|jpeg|png)$/,c="/avatars/";a.s(["localPhoto",0,function(a){return"string"==typeof a&&a.startsWith(c)&&b.test(a.slice(c.length))?a:null}])},37732,a=>{"use strict";async function b(){let a=await fetch("/api/scraper");if(!a.ok)throw Error("Could not reach the app.");return a.json()}async function c(a,b,d={}){let e=await fetch("/api/scraper",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:a,...b?{name:b}:{},...d})}),f=await e.json().catch(()=>({}));if(!e.ok)throw Error(f.error||"Could not start the scanner.");return f}async function d(a){let b=await fetch(`/api/scraper?resume=${encodeURIComponent(a)}`);return b.ok?(await b.json()).resume??null:null}Symbol.for("six-degrees.scan-state");let e=Object.freeze({skips:[],read:[]});async function f(){try{let a=await fetch("/api/scraper?reach=1");if(!a.ok)return e;let b=await a.json();return{skips:Array.isArray(b.skips)?b.skips:[],read:Array.isArray(b.read)?b.read:[]}}catch{return e}}async function g(a){let b=await fetch(`/api/scraper?person=${encodeURIComponent(a)}`);return b.ok?b.json():{person:null}}async function h(){await fetch("/api/scraper",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"cancel"})})}let i=Object.freeze({known:!1,running:!1,pending:!1,action:null,target:null,startedAt:null,progress:null,log:[],finished:[]}),j=new Set,k=i,l=JSON.stringify(k),m=null,n=null,o=0,p=!1,q=new Set;function r(a){let b=JSON.stringify(a);if(b!==l)for(let c of(l=b,k=Object.freeze(a),[...j]))c()}async function s(){(!("u">typeof document&&document.hidden)||k.running)&&await function(){if(n&&n.epoch===o)return n.promise;let a=o,b=fetch("/api/scraper?job=1").then(a=>a.ok?a.json():null).then(b=>{a===o&&function(a){if(!a||"object"!=typeof a)return;let b=!0===a.running;b&&null!=a.startedAt&&q.add(a.startedAt);let c=(Array.isArray(a.recent)?a.recent:[]).filter(a=>q.has(a.startedAt)).map(c=>({...c,log:!b&&c.startedAt===a.startedAt&&Array.isArray(a.log)?a.log:[]}));r({known:!0,running:b||p,pending:p&&!b,action:b?a.action??null:p?k.action:null,target:b?a.target??null:p?k.target:null,startedAt:b?a.startedAt??null:null,progress:b?a.progress??null:null,log:b&&Array.isArray(a.log)?a.log:[],finished:c})}(b)}).catch(()=>{}).finally(()=>{n?.promise===b&&(n=null)});return n={epoch:a,promise:b},b}(),clearTimeout(m),m=j.size?setTimeout(s,k.running?1500:5e3):null}function t(a){return j.add(a),1===j.size&&s(),()=>{j.delete(a),j.size||(clearTimeout(m),m=null)}}async function u(a,{name:b,id:d,onLog:e,...f}={}){let g;o++,p=!0,r({...k,known:!0,running:!0,pending:!0,action:a,target:b||d?{id:d??null,name:b??null}:null,startedAt:null,progress:null,log:[]});try{g=await c(a,b,{...d?{id:d}:{},...f})}catch(a){throw p=!1,o++,k.pending&&r({...k,running:!1,pending:!1,action:null,target:null,log:[]}),s(),a}p=!1,o++;let h=g?.startedAt??null;null!=h&&q.add(h);let i=new Promise(a=>{let b=t(()=>{k.running&&k.startedAt===h&&e?.(k.log);let c=null==h?k.running?null:{exitCode:null,failure:null,log:[]}:k.finished.find(a=>a.startedAt===h);c&&(b(),c.log.length&&e?.(c.log),a(c))});s()});return{startedAt:h,ended:i}}function v(a){return!!a?.target&&["bridge","rescrape","resume"].includes(a.action)}a.s(["NO_SCAN_NOTES",0,e,"SCANNER_UNKNOWN",0,i,"beginScrape",0,u,"busyReason",0,function(a=k){if(!a?.running)return null;let b=a.target?.name;switch(a.action){case"bridge":case"rescrape":case"resume":return b?`${b}’s circle is being scanned`:"A circle is being scanned";case"company":return b?`${b} 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(a.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,v,"loadScanNotes",0,f,"notReadyMessage",0,function(a){if(!a)return"Could not reach the app.";let b=a.checks||{};return b.scriptsFound?b.dependencies?b.chrome?null:"Google Chrome is not installed.":b.python||b.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,g,"resumePoint",0,d,"runScrape",0,function(a,b={}){return u(a,b).then(a=>a.ended)},"scannerNow",0,function(){return k},"scansCircleOf",0,function(a,b){if(!v(a)||!b)return!1;let{id:c,name:d}=a.target;return c&&b.id?c===b.id:!!d&&d===b.name},"scraperStatus",0,b,"stopScrape",0,h,"watchScanner",0,t],37732)},69789,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={actionAsyncStorage:function(){return f.actionAsyncStorage},workAsyncStorage:function(){return g.workAsyncStorage},workUnitAsyncStorage:function(){return h.workUnitAsyncStorage}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(20635),g=a.r(56704),h=a.r(32319);("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)}];
2
-
3
- //# sourceMappingURL=_13kzrwv._.js.map
@@ -1,3 +0,0 @@
1
- module.exports=[36839,a=>{"use strict";var b=a.i(87924),c=a.i(75857);a.s(["default",0,function({children:a}){let{userId:d,ready:e}=(0,c.useUser)();return e&&d?a:(0,b.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:e?(0,b.jsxs)("div",{style:{maxWidth:420},children:[(0,b.jsx)("div",{style:{fontSize:18,fontWeight:700,marginBottom:8},children:"Can’t reach Six Degrees’ local server"}),(0,b.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,b.jsx)("div",{style:{fontSize:18,fontWeight:600},children:"Loading…"})})}])},56377,a=>{"use strict";let b=/^[A-Za-z0-9_-]+\.(webp|jpg|jpeg|png)$/,c="/avatars/";a.s(["localPhoto",0,function(a){return"string"==typeof a&&a.startsWith(c)&&b.test(a.slice(c.length))?a:null}])},91443,90231,a=>{"use strict";var b=a.i(56377);let c={S:0,A:1,B:2,C:3,D:4};function d(a){let b=parseFloat(a?.power_score);return Number.isFinite(b)?b:0}function e(a){return Math.round(10*d(a))/10}function f(a){return String(a?.profile_url||"").split(/[?#]/)[0].replace(/\/+$/,"")||`id:${a?.id}`}let g=(a,b)=>String(a??"").localeCompare(String(b??""),void 0,{numeric:!0});function h(a,b){return(c[a.tier]??9)-(c[b.tier]??9)||d(b)-d(a)||String(a.name||"").localeCompare(String(b.name||""))||g(a.id,b.id)}function i(a,b){return a.bridge&&b.bridge?h(a.bridge,b.bridge):a.bridge?-1:b.bridge?1:g(a.id,b.id)}function j(a,b){return b.score-a.score||b.waysIn-a.waysIn||i(a.routes[0]||k,b.routes[0]||k)||String(a.person.name||"").localeCompare(String(b.person.name||""))||(a.key<b.key?-1:+(a.key>b.key))}let k={id:null,bridge:null};function l(a){let b=String(a||"").trim().split(/\s+/).filter(Boolean);return b.length<2?b[0]||"":`${b[0]} ${b[b.length-1].charAt(0)}.`}function m(a,b){let c=String(a||"");return b<=1?c?"…":"":c.length>b?`${c.slice(0,b-1)}…`:c}function n(a,b){return a?b.scanned.has(a.id)||a.profile_url&&b.read?.has(f(a))?"scanned":a.profile_url&&b.hidden.has(f(a))?"hidden":"todo":"todo"}function o(a,b){if(!a||1!==a.degree||null==a.unlocked_from_bridge_id)return null;let c=n(a,b);return"todo"===c?"ready":c}a.s(["TIERS",0,["S","A","B","C","D"],"compareBridges",0,h,"compareWaysIn",0,function(a,b){return b.waysIn-a.waysIn||j(a,b)},"keyFor",0,f,"routeIndex",0,function(a=[]){let b=new Map;for(let c of a||[]){let a=f(c),d=b.get(a);d||(d=new Set,b.set(a,d)),d.add(c.source_connection_id??null)}return b},"routesFor",0,function(a,b,c){return a?[...b?.get(f(a))??(null!=a.source_connection_id?new Set([a.source_connection_id]):new Set)].map(a=>({id:a,bridge:c?.get(a)??null})).sort(i):[]},"score",0,d,"score1",0,e,"separationPeople",0,function(a=[],c=[]){let d=new Map;for(let a of c||[])d.set(a.id,a);let h=new Map,k=new Map;for(let c of a||[]){let a=f(c);k.set(c.id,a);let d=h.get(a);d?function(a,c){let d=e(a)-e(c);if(d)return d>0;let f=!!(0,b.localPhoto)(a.profile_image_url);return!!(0,b.localPhoto)(c.profile_image_url)!==f?f:0>g(a.id,c.id)}(c,d.person)&&(d.person=c):(d={key:a,person:c,rowIds:[],routeIds:new Set},h.set(a,d)),d.rowIds.push(c.id),d.routeIds.add(c.source_connection_id??null)}let l={people:h.size,byTier:{S:0,A:0,B:0,C:0,D:0},multi:0,bridges:0,unresolvedIds:0,peopleOnlyUnresolved:0,onlyUnresolvedVia:0},m=new Set,n=new Set,o=new Set,p=[];for(let a of h.values()){let b=[...a.routeIds].map(a=>({id:a,bridge:d.get(a)??null}));b.sort(i);let c=b.filter(a=>a.bridge);for(let a of b)(a.bridge?m:n).add(a.id);if(!c.length)for(let a of(l.peopleOnlyUnresolved++,b))o.add(a.id);let{person:f}=a,g=f.tier;void 0!==l.byTier[g]&&l.byTier[g]++,b.length>1&&l.multi++,p.push({key:a.key,person:f,score:e(f),tier:g,routes:b,waysIn:b.length,rowIds:a.rowIds,haystack:[f.name,f.headline,f.company,f.role,...c.map(a=>a.bridge.name)].filter(Boolean).join("\n").toLowerCase(),rank:0,tied:!1})}return l.bridges=m.size,l.unresolvedIds=n.size,l.onlyUnresolvedVia=o.size,p.sort(j),function(a){for(let b=0;b<a.length;b++){let c=a[b],d=a[b-1],e=d&&d.score===c.score&&d.waysIn===c.waysIn;c.rank=e?d.rank:b+1,e&&(c.tied=!0,d.tied=!0)}}(p),{people:p,rowToKey:k,summary:l}},"shortName",0,l,"summitLayout",0,function(a=[],b=800,c=!1){let d=c?36:26,e=Math.round(.42*b),f=Math.round(.58*b),g=a.map((a,c)=>{var e;return{key:a.key,p:a,x:f,y:16+c*d,r:(e=a.waysIn)>=4?8.5:3===e?7:2===e?5.5:4,label:m(`#${a.rank}${a.tied?"=":""} ${a.person.name||""}`,Math.floor((b-f-60)/6.2))}}),i=new Map,j="\0unresolved";for(let a of g)for(let b of a.p.routes){let c=b.bridge?b.id:j,d=i.get(c);d||(d={id:b.bridge?b.id:null,bridge:b.bridge,unresolved:!b.bridge,ys:[],count:0},i.set(c,d)),d.count++,d.ys.push(a.y)}let k=[...i.values()].map(a=>({...a,bary:a.ys.reduce((a,b)=>a+b,0)/a.ys.length}));k.sort((a,b)=>a.bary-b.bary||a.unresolved-b.unresolved||(a.bridge&&b.bridge?h(a.bridge,b.bridge):0));let n=g.length?g[g.length-1].y:16,o=k.length>1?Math.max(18,(n-16)/(k.length-1)):0,p=Math.max(4,Math.floor((e-10-42)/6));k.forEach((a,b)=>{if(a.x=e,a.y=1===k.length?(16+n)/2:16+b*o,a.r=5,a.unresolved)a.label=m(`can't be named (${a.count})`,p);else{let b=a.bridge.name||"";a.label=b.length<=p?b:m(l(b),p)}delete a.ys});let q=new Map(k.map(a=>[a.unresolved?j:a.id,a])),r=[];for(let a of g){let b=new Set;a.p.routes.forEach((c,d)=>{let e=c.bridge?c.id:j;if(b.has(e))return;b.add(e);let f=q.get(e);r.push({key:a.key,bridgeId:f.id,primary:0===d&&!f.unresolved,unresolved:f.unresolved,tier:f.bridge?.tier??null,x1:f.x,y1:f.y,x2:a.x,y2:a.y})})}let s=Math.max(n,k.length?k[k.length-1].y:0),t=g.length?Math.ceil(s+16):0,u={x:20,y:g.length?(16+Math.max(n,s))/2:16,r:14},v=k.map(a=>({id:a.id,x1:u.x,y1:u.y,x2:a.x,y2:a.y}));return{width:b,height:t,you:u,people:g,bridges:k,links:r,spokes:v}}],90231),a.s(["circleScanCost",0,function(a=100){let b=Math.max(1,Math.min(100,Math.round(a)||100));return{profileViews:1,searches:b,minutes:b>=100?55:Math.max(5,Math.round(.55*b))}},"circleState",0,n,"reachIndex",0,function(a=[],b=[],c={}){let d=new Set;for(let a of b||[])a?.source_connection_id!=null&&d.add(a.source_connection_id);let e=new Set;for(let a of c?.skips||[])a?.profileUrl&&e.add(f({profile_url:a.profileUrl}));let g=new Set;for(let a of c?.read||[])a&&g.add(f({profile_url:a}));let h=new Map;for(let[a,b]of Object.entries(c?.lists||{}))a&&b&&h.set(f({profile_url:a}),b);let i=new Map;for(let b of a||[]){let a=b?.unlocked_from_bridge_id;if(null==a||1!==b.degree)continue;let c=i.get(a);c||i.set(a,c=[]),c.push(b)}return{scanned:d,read:g,hidden:e,reachedFrom:i,lists:h}},"reachState",0,o,"readyByCircle",0,function(a){let b=new Map;for(let[c,d]of a.reachedFrom){let e=d.filter(b=>"ready"===o(b,a)).length;e&&b.set(c,e)}return b},"readyToScan",0,function(a,b){return(a||[]).filter(a=>"ready"===o(a,b)).sort(h)},"scanBars",0,function(a,b){let c=n(a,b),d=a?.profile_url?b.lists?.get(f(a)):null;return"hidden"===c?null:d?d.more?d.total?Math.max(1,Math.min(4,Math.round(5*Math.min(1,10*d.pages/d.total)))):2:5:"scanned"===c?2:null}],91443)},37732,a=>{"use strict";async function b(){let a=await fetch("/api/scraper");if(!a.ok)throw Error("Could not reach the app.");return a.json()}async function c(a,b,d={}){let e=await fetch("/api/scraper",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:a,...b?{name:b}:{},...d})}),f=await e.json().catch(()=>({}));if(!e.ok)throw Error(f.error||"Could not start the scanner.");return f}async function d(a){let b=await fetch(`/api/scraper?resume=${encodeURIComponent(a)}`);return b.ok?(await b.json()).resume??null:null}Symbol.for("six-degrees.scan-state");let e=Object.freeze({skips:[],read:[]});async function f(){try{let a=await fetch("/api/scraper?reach=1");if(!a.ok)return e;let b=await a.json();return{skips:Array.isArray(b.skips)?b.skips:[],read:Array.isArray(b.read)?b.read:[]}}catch{return e}}async function g(a){let b=await fetch(`/api/scraper?person=${encodeURIComponent(a)}`);return b.ok?b.json():{person:null}}async function h(){await fetch("/api/scraper",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"cancel"})})}let i=Object.freeze({known:!1,running:!1,pending:!1,action:null,target:null,startedAt:null,progress:null,log:[],finished:[]}),j=new Set,k=i,l=JSON.stringify(k),m=null,n=null,o=0,p=!1,q=new Set;function r(a){let b=JSON.stringify(a);if(b!==l)for(let c of(l=b,k=Object.freeze(a),[...j]))c()}async function s(){(!("u">typeof document&&document.hidden)||k.running)&&await function(){if(n&&n.epoch===o)return n.promise;let a=o,b=fetch("/api/scraper?job=1").then(a=>a.ok?a.json():null).then(b=>{a===o&&function(a){if(!a||"object"!=typeof a)return;let b=!0===a.running;b&&null!=a.startedAt&&q.add(a.startedAt);let c=(Array.isArray(a.recent)?a.recent:[]).filter(a=>q.has(a.startedAt)).map(c=>({...c,log:!b&&c.startedAt===a.startedAt&&Array.isArray(a.log)?a.log:[]}));r({known:!0,running:b||p,pending:p&&!b,action:b?a.action??null:p?k.action:null,target:b?a.target??null:p?k.target:null,startedAt:b?a.startedAt??null:null,progress:b?a.progress??null:null,log:b&&Array.isArray(a.log)?a.log:[],finished:c})}(b)}).catch(()=>{}).finally(()=>{n?.promise===b&&(n=null)});return n={epoch:a,promise:b},b}(),clearTimeout(m),m=j.size?setTimeout(s,k.running?1500:5e3):null}function t(a){return j.add(a),1===j.size&&s(),()=>{j.delete(a),j.size||(clearTimeout(m),m=null)}}async function u(a,{name:b,id:d,onLog:e,...f}={}){let g;o++,p=!0,r({...k,known:!0,running:!0,pending:!0,action:a,target:b||d?{id:d??null,name:b??null}:null,startedAt:null,progress:null,log:[]});try{g=await c(a,b,{...d?{id:d}:{},...f})}catch(a){throw p=!1,o++,k.pending&&r({...k,running:!1,pending:!1,action:null,target:null,log:[]}),s(),a}p=!1,o++;let h=g?.startedAt??null;null!=h&&q.add(h);let i=new Promise(a=>{let b=t(()=>{k.running&&k.startedAt===h&&e?.(k.log);let c=null==h?k.running?null:{exitCode:null,failure:null,log:[]}:k.finished.find(a=>a.startedAt===h);c&&(b(),c.log.length&&e?.(c.log),a(c))});s()});return{startedAt:h,ended:i}}function v(a){return!!a?.target&&["bridge","rescrape","resume"].includes(a.action)}a.s(["NO_SCAN_NOTES",0,e,"SCANNER_UNKNOWN",0,i,"beginScrape",0,u,"busyReason",0,function(a=k){if(!a?.running)return null;let b=a.target?.name;switch(a.action){case"bridge":case"rescrape":case"resume":return b?`${b}’s circle is being scanned`:"A circle is being scanned";case"company":return b?`${b} 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(a.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,v,"loadScanNotes",0,f,"notReadyMessage",0,function(a){if(!a)return"Could not reach the app.";let b=a.checks||{};return b.scriptsFound?b.dependencies?b.chrome?null:"Google Chrome is not installed.":b.python||b.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,g,"resumePoint",0,d,"runScrape",0,function(a,b={}){return u(a,b).then(a=>a.ended)},"scannerNow",0,function(){return k},"scansCircleOf",0,function(a,b){if(!v(a)||!b)return!1;let{id:c,name:d}=a.target;return c&&b.id?c===b.id:!!d&&d===b.name},"scraperStatus",0,b,"stopScrape",0,h,"watchScanner",0,t],37732)},76939,a=>{"use strict";a.s(["TIER_COLORS",0,{S:"#f6c344",A:"#a78bfa",B:"#60a5fa",C:"#94a3b8",D:"#6b7280"},"TIER_COLORS_CLASSIC",0,{S:"#FFD700",A:"#9B59B6",B:"#3498DB",C:"#95A5A6",D:"#BDC3C7"},"TIER_ORDER",0,["S","A","B","C","D"],"TIER_RING_RADIUS",0,{S:150,A:230,B:310,C:390,D:470},"initialsFor",0,function(a){let b=String(a||"").trim().split(/\s+/).filter(Boolean);return 0===b.length?"?":(b[0].charAt(0)+(b.length>1?b[b.length-1].charAt(0):"")).toUpperCase()}])},69789,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={actionAsyncStorage:function(){return f.actionAsyncStorage},workAsyncStorage:function(){return g.workAsyncStorage},workUnitAsyncStorage:function(){return h.workUnitAsyncStorage}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(20635),g=a.r(56704),h=a.r(32319);("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)}];
2
-
3
- //# sourceMappingURL=_1hgd5dp._.js.map