@urmzd/github-insights 2.0.0 → 2.1.0

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 (57) hide show
  1. package/.github/workflows/release.yml +5 -1
  2. package/CHANGELOG.md +40 -0
  3. package/README.md +0 -2
  4. package/assets/insights/index.svg +14 -0
  5. package/assets/insights/metrics-calendar.svg +14 -0
  6. package/{metrics → assets/insights}/metrics-complexity.svg +1 -1
  7. package/{metrics → assets/insights}/metrics-contributions.svg +1 -1
  8. package/assets/insights/metrics-expertise.svg +14 -0
  9. package/assets/insights/metrics-languages.svg +14 -0
  10. package/{metrics → assets/insights}/metrics-pulse.svg +1 -1
  11. package/examples/classic/README.md +2 -2
  12. package/examples/classic/index.svg +2 -2
  13. package/examples/classic/metrics-calendar.svg +1 -1
  14. package/examples/classic/metrics-complexity.svg +1 -1
  15. package/examples/classic/metrics-contributions.svg +1 -1
  16. package/examples/classic/metrics-expertise.svg +2 -2
  17. package/examples/classic/metrics-languages.svg +1 -1
  18. package/examples/classic/metrics-pulse.svg +1 -1
  19. package/examples/ecosystem/README.md +23 -24
  20. package/examples/ecosystem/index.svg +2 -2
  21. package/examples/ecosystem/metrics-calendar.svg +1 -1
  22. package/examples/ecosystem/metrics-complexity.svg +1 -1
  23. package/examples/ecosystem/metrics-contributions.svg +1 -1
  24. package/examples/ecosystem/metrics-expertise.svg +2 -2
  25. package/examples/ecosystem/metrics-languages.svg +1 -1
  26. package/examples/ecosystem/metrics-pulse.svg +1 -1
  27. package/examples/minimal/README.md +2 -2
  28. package/examples/minimal/index.svg +2 -2
  29. package/examples/minimal/metrics-calendar.svg +1 -1
  30. package/examples/minimal/metrics-complexity.svg +1 -1
  31. package/examples/minimal/metrics-contributions.svg +1 -1
  32. package/examples/minimal/metrics-expertise.svg +2 -2
  33. package/examples/minimal/metrics-languages.svg +1 -1
  34. package/examples/minimal/metrics-pulse.svg +1 -1
  35. package/examples/modern/README.md +36 -38
  36. package/examples/modern/index.svg +2 -2
  37. package/examples/modern/metrics-calendar.svg +1 -1
  38. package/examples/modern/metrics-complexity.svg +1 -1
  39. package/examples/modern/metrics-contributions.svg +1 -1
  40. package/examples/modern/metrics-expertise.svg +2 -2
  41. package/examples/modern/metrics-languages.svg +1 -1
  42. package/examples/modern/metrics-pulse.svg +1 -1
  43. package/package.json +5 -5
  44. package/src/api.ts +1 -1
  45. package/src/config.ts +6 -12
  46. package/src/index.ts +6 -0
  47. package/src/metrics.ts +16 -2
  48. package/src/readme.test.ts +31 -25
  49. package/src/templates.test.ts +110 -13
  50. package/src/templates.ts +38 -11
  51. package/src/types.ts +3 -0
  52. package/metrics/index.svg +0 -14
  53. package/metrics/metrics-calendar.svg +0 -14
  54. package/metrics/metrics-expertise.svg +0 -14
  55. package/metrics/metrics-languages.svg +0 -14
  56. /package/{metrics → assets/insights}/metrics-domains.svg +0 -0
  57. /package/{metrics → assets/insights}/metrics-tech-stack.svg +0 -0
@@ -18,11 +18,11 @@ const makeContext = (
18
18
  title: "Software Engineer",
19
19
  bio: "Building tools",
20
20
  preamble: "A software developer in Austin, TX.",
21
- svgs: [{ label: "GitHub Metrics", path: "metrics/index.svg" }],
21
+ svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
22
22
  sectionSvgs: {
23
- pulse: "metrics/metrics-pulse.svg",
24
- calendar: "metrics/metrics-calendar.svg",
25
- expertise: "metrics/metrics-expertise.svg",
23
+ pulse: "assets/insights/metrics-pulse.svg",
24
+ calendar: "assets/insights/metrics-calendar.svg",
25
+ expertise: "assets/insights/metrics-expertise.svg",
26
26
  },
27
27
  profile: makeUserProfile(),
28
28
  activeProjects: [
@@ -44,7 +44,9 @@ const makeContext = (
44
44
  },
45
45
  ],
46
46
  inactiveProjects: [],
47
+ archivedProjects: [],
47
48
  allProjects: [],
49
+ templateName: "classic",
48
50
  categorizedProjects: {
49
51
  Applications: [
50
52
  {
@@ -73,7 +75,7 @@ const makeContext = (
73
75
  contributionData: makeContributionData(),
74
76
  socialBadges:
75
77
  "[![urmzd.dev](https://img.shields.io/badge/urmzd.dev-4285F4?style=flat&logo=google-chrome&logoColor=white)](https://urmzd.dev)",
76
- svgDir: "metrics",
78
+ svgDir: "assets/insights",
77
79
  ...overrides,
78
80
  });
79
81
 
@@ -216,7 +218,7 @@ describe("classicTemplate", () => {
216
218
 
217
219
  it("includes SVG embeds", () => {
218
220
  const output = getTemplate("classic")(makeContext());
219
- expect(output).toContain("![GitHub Metrics](metrics/index.svg)");
221
+ expect(output).toContain("![GitHub Metrics](assets/insights/index.svg)");
220
222
  });
221
223
 
222
224
  it("includes social badges", () => {
@@ -241,6 +243,28 @@ describe("classicTemplate", () => {
241
243
  expect(output).toContain("/ˈʊrm.zəd/");
242
244
  });
243
245
 
246
+ it("includes archived section for archived projects", () => {
247
+ const output = getTemplate("classic")(
248
+ makeContext({
249
+ archivedProjects: [
250
+ {
251
+ name: "old-project",
252
+ url: "https://github.com/urmzd/old-project",
253
+ description: "An archived project",
254
+ stars: 2,
255
+ },
256
+ ],
257
+ }),
258
+ );
259
+ expect(output).toContain("## Archived");
260
+ expect(output).toContain("[old-project]");
261
+ });
262
+
263
+ it("omits archived section when no archived projects", () => {
264
+ const output = getTemplate("classic")(makeContext());
265
+ expect(output).not.toContain("## Archived");
266
+ });
267
+
244
268
  it("ends with trailing newline", () => {
245
269
  const output = getTemplate("classic")(makeContext());
246
270
  expect(output.endsWith("\n")).toBe(true);
@@ -297,14 +321,31 @@ describe("modernTemplate", () => {
297
321
  it("includes GitHub Stats section with pulse and calendar", () => {
298
322
  const output = getTemplate("modern")(makeContext());
299
323
  expect(output).toContain("## GitHub Stats");
300
- expect(output).toContain("metrics/metrics-pulse.svg");
301
- expect(output).toContain("metrics/metrics-calendar.svg");
324
+ expect(output).toContain("assets/insights/metrics-pulse.svg");
325
+ expect(output).toContain("assets/insights/metrics-calendar.svg");
302
326
  });
303
327
 
304
328
  it("includes expertise section", () => {
305
329
  const output = getTemplate("modern")(makeContext());
306
330
  expect(output).toContain("## Other Areas of Interest");
307
- expect(output).toContain("metrics/metrics-expertise.svg");
331
+ expect(output).toContain("assets/insights/metrics-expertise.svg");
332
+ });
333
+
334
+ it("includes archived section separate from active/maintained", () => {
335
+ const output = getTemplate("modern")(
336
+ makeContext({
337
+ archivedProjects: [
338
+ {
339
+ name: "legacy-lib",
340
+ url: "https://github.com/urmzd/legacy-lib",
341
+ description: "A legacy library",
342
+ stars: 1,
343
+ },
344
+ ],
345
+ }),
346
+ );
347
+ expect(output).toContain("## Archived");
348
+ expect(output).toContain("[legacy-lib]");
308
349
  });
309
350
 
310
351
  it("includes social badges", () => {
@@ -333,7 +374,7 @@ describe("minimalTemplate", () => {
333
374
 
334
375
  it("includes SVG embeds", () => {
335
376
  const output = getTemplate("minimal")(makeContext());
336
- expect(output).toContain("![GitHub Metrics](metrics/index.svg)");
377
+ expect(output).toContain("![GitHub Metrics](assets/insights/index.svg)");
337
378
  });
338
379
 
339
380
  it("includes social badges", () => {
@@ -346,6 +387,23 @@ describe("minimalTemplate", () => {
346
387
  expect(output).toContain("@urmzd/github-insights");
347
388
  });
348
389
 
390
+ it("includes archived section for archived projects", () => {
391
+ const output = getTemplate("minimal")(
392
+ makeContext({
393
+ archivedProjects: [
394
+ {
395
+ name: "old-util",
396
+ url: "https://github.com/urmzd/old-util",
397
+ description: "A retired utility",
398
+ stars: 0,
399
+ },
400
+ ],
401
+ }),
402
+ );
403
+ expect(output).toContain("## Archived");
404
+ expect(output).toContain("[old-util]");
405
+ });
406
+
349
407
  it("ends with trailing newline", () => {
350
408
  const output = getTemplate("minimal")(makeContext());
351
409
  expect(output.endsWith("\n")).toBe(true);
@@ -385,14 +443,14 @@ describe("ecosystemTemplate", () => {
385
443
  it("includes GitHub Stats section", () => {
386
444
  const output = getTemplate("ecosystem")(makeContext());
387
445
  expect(output).toContain("## GitHub Stats");
388
- expect(output).toContain("metrics/metrics-pulse.svg");
389
- expect(output).toContain("metrics/metrics-calendar.svg");
446
+ expect(output).toContain("assets/insights/metrics-pulse.svg");
447
+ expect(output).toContain("assets/insights/metrics-calendar.svg");
390
448
  });
391
449
 
392
450
  it("includes expertise section", () => {
393
451
  const output = getTemplate("ecosystem")(makeContext());
394
452
  expect(output).toContain("## Other Areas of Interest");
395
- expect(output).toContain("metrics/metrics-expertise.svg");
453
+ expect(output).toContain("assets/insights/metrics-expertise.svg");
396
454
  });
397
455
 
398
456
  it("includes social badges", () => {
@@ -405,6 +463,45 @@ describe("ecosystemTemplate", () => {
405
463
  expect(output).toContain("@urmzd/github-insights");
406
464
  });
407
465
 
466
+ it("separates archived projects from category tables", () => {
467
+ const output = getTemplate("ecosystem")(
468
+ makeContext({
469
+ archivedProjects: [
470
+ {
471
+ name: "old-app",
472
+ url: "https://github.com/urmzd/old-app",
473
+ description: "A retired application",
474
+ stars: 3,
475
+ category: "Applications",
476
+ },
477
+ ],
478
+ categorizedProjects: {
479
+ Applications: [
480
+ {
481
+ name: "resume-generator",
482
+ url: "https://github.com/urmzd/resume-generator",
483
+ description: "CLI tool for professional resumes",
484
+ stars: 42,
485
+ category: "Applications",
486
+ },
487
+ {
488
+ name: "old-app",
489
+ url: "https://github.com/urmzd/old-app",
490
+ description: "A retired application",
491
+ stars: 3,
492
+ category: "Applications",
493
+ },
494
+ ],
495
+ },
496
+ }),
497
+ );
498
+ expect(output).toContain("### Archived");
499
+ expect(output).toContain("[old-app]");
500
+ // old-app should NOT appear in the Applications table
501
+ const appSection = output.split("### Applications")[1].split("###")[0];
502
+ expect(appSection).not.toContain("old-app");
503
+ });
504
+
408
505
  it("ends with trailing newline", () => {
409
506
  const output = getTemplate("ecosystem")(makeContext());
410
507
  expect(output.endsWith("\n")).toBe(true);
package/src/templates.ts CHANGED
@@ -8,9 +8,9 @@ import type {
8
8
 
9
9
  // ── Helpers ────────────────────────────────────────────────────────────────
10
10
 
11
- function attribution(): string {
11
+ function attribution(templateName: string): string {
12
12
  const now = new Date().toISOString().split("T")[0];
13
- return `<sub>Last generated on ${now} using [@urmzd/github-insights](https://github.com/urmzd/github-insights)</sub>`;
13
+ return `<sub>Last generated on ${now} using [@urmzd/github-insights](https://github.com/urmzd/github-insights) · Template: \`${templateName}\`</sub>`;
14
14
  }
15
15
 
16
16
  export function extractFirstName(fullName: string): string {
@@ -131,11 +131,15 @@ function classicTemplate(ctx: TemplateContext): string {
131
131
  parts.push(`![${svg.label}](${svg.path})`);
132
132
  }
133
133
 
134
+ if (ctx.archivedProjects.length > 0) {
135
+ parts.push(renderProjectSection("Archived", ctx.archivedProjects));
136
+ }
137
+
134
138
  if (ctx.bio) {
135
139
  parts.push(`---\n\n<sub>${ctx.bio}</sub>`);
136
140
  }
137
141
 
138
- parts.push(attribution());
142
+ parts.push(attribution(ctx.templateName));
139
143
 
140
144
  return `${parts.join("\n\n")}\n`;
141
145
  }
@@ -173,6 +177,12 @@ function modernTemplate(ctx: TemplateContext): string {
173
177
  );
174
178
  if (inactiveSection) parts.push(inactiveSection);
175
179
 
180
+ const archivedSection = renderProjectSection(
181
+ "Archived",
182
+ ctx.archivedProjects,
183
+ );
184
+ if (archivedSection) parts.push(archivedSection);
185
+
176
186
  // GitHub Stats section: pulse + calendar
177
187
  const statsImages: string[] = [];
178
188
  if (ctx.sectionSvgs.pulse) {
@@ -192,7 +202,7 @@ function modernTemplate(ctx: TemplateContext): string {
192
202
  );
193
203
  }
194
204
 
195
- parts.push(attribution());
205
+ parts.push(attribution(ctx.templateName));
196
206
 
197
207
  return `${parts.join("\n\n")}\n`;
198
208
  }
@@ -216,7 +226,11 @@ function minimalTemplate(ctx: TemplateContext): string {
216
226
  parts.push(`![${svg.label}](${svg.path})`);
217
227
  }
218
228
 
219
- parts.push(attribution());
229
+ if (ctx.archivedProjects.length > 0) {
230
+ parts.push(renderProjectSection("Archived", ctx.archivedProjects));
231
+ }
232
+
233
+ parts.push(attribution(ctx.templateName));
220
234
 
221
235
  return `${parts.join("\n\n")}\n`;
222
236
  }
@@ -243,21 +257,34 @@ function ecosystemTemplate(ctx: TemplateContext): string {
243
257
  parts.push(ctx.socialBadges);
244
258
  }
245
259
 
246
- // Render project tables grouped by category
260
+ // Build a set of archived project names to filter them out of category tables
261
+ const archivedNames = new Set(ctx.archivedProjects.map((p) => p.name));
262
+
263
+ // Render project tables grouped by category (excluding archived)
247
264
  for (const category of CATEGORY_ORDER) {
248
- const projects = ctx.categorizedProjects[category];
265
+ const projects = ctx.categorizedProjects[category]?.filter(
266
+ (p) => !archivedNames.has(p.name),
267
+ );
249
268
  if (projects && projects.length > 0) {
250
269
  parts.push(renderProjectTable(category, projects));
251
270
  }
252
271
  }
253
272
 
254
- // Render any uncategorized projects that don't match known categories
273
+ // Render any uncategorized projects that don't match known categories (excluding archived)
255
274
  for (const [category, projects] of Object.entries(ctx.categorizedProjects)) {
256
- if (!CATEGORY_ORDER.includes(category) && projects.length > 0) {
257
- parts.push(renderProjectTable(category, projects));
275
+ if (!CATEGORY_ORDER.includes(category)) {
276
+ const nonArchived = projects.filter((p) => !archivedNames.has(p.name));
277
+ if (nonArchived.length > 0) {
278
+ parts.push(renderProjectTable(category, nonArchived));
279
+ }
258
280
  }
259
281
  }
260
282
 
283
+ // Render all archived projects in one consolidated section
284
+ if (ctx.archivedProjects.length > 0) {
285
+ parts.push(renderProjectTable("Archived", ctx.archivedProjects));
286
+ }
287
+
261
288
  // GitHub Stats section: pulse + calendar
262
289
  const statsImages: string[] = [];
263
290
  if (ctx.sectionSvgs.pulse) {
@@ -277,7 +304,7 @@ function ecosystemTemplate(ctx: TemplateContext): string {
277
304
  );
278
305
  }
279
306
 
280
- parts.push(attribution());
307
+ parts.push(attribution(ctx.templateName));
281
308
 
282
309
  return `${parts.join("\n\n")}\n`;
283
310
  }
package/src/types.ts CHANGED
@@ -29,6 +29,7 @@ export interface ProjectItem {
29
29
  languages?: string[];
30
30
  summary?: string;
31
31
  category?: string;
32
+ isArchived?: boolean;
32
33
  }
33
34
 
34
35
  // ── Bar chart generics ──────────────────────────────────────────────────────
@@ -217,12 +218,14 @@ export interface TemplateContext {
217
218
  title?: string;
218
219
  bio?: string;
219
220
  preamble?: string;
221
+ templateName: TemplateName;
220
222
  svgs: SvgEmbed[];
221
223
  sectionSvgs: Record<string, string>;
222
224
  profile: UserProfile;
223
225
  activeProjects: ProjectItem[];
224
226
  maintainedProjects: ProjectItem[];
225
227
  inactiveProjects: ProjectItem[];
228
+ archivedProjects: ProjectItem[];
226
229
  allProjects: ProjectItem[];
227
230
  categorizedProjects: Record<string, ProjectItem[]>;
228
231
  languages: LanguageItem[];
package/metrics/index.svg DELETED
@@ -1,14 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" width="808" height="1759" viewBox="0 0 808 1759"><defs><style>
2
- .t { font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif; }
3
- .t-h { font-size: 13px; fill: #c9d1d9; letter-spacing: 1.5px; font-weight: 600; }
4
- .t-sub { font-size: 11px; fill: #6e7681; }
5
- .t-label { font-size: 12px; fill: #8b949e; }
6
- .t-value { font-size: 11px; fill: #6e7681; }
7
- .t-subhdr { font-size: 11px; fill: #8b949e; letter-spacing: 1px; font-weight: 600; }
8
- .t-stat-label { font-size: 10px; fill: #8b949e; font-weight: 600; }
9
- .t-stat-value { font-size: 22px; font-weight: 700; }
10
- .t-card-title { font-size: 12px; fill: #58a6ff; font-weight: 700; }
11
- .t-card-detail { font-size: 11px; fill: #8b949e; }
12
- .t-pill { font-size: 11px; font-weight: 600; }
13
- .t-bullet { font-size: 12px; fill: #c9d1d9; }
14
- </style></defs><rect width="808" height="1759" rx="12" fill="#0d1117"/><text x="24" y="40" class="t t-h">AT A GLANCE</text><text x="24" y="56" class="t t-sub">Contribution activity over the past year</text><rect x="24" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="38" cy="82" r="4" fill="#58a6ff"/><text x="48" y="86" class="t t-stat-label">COMMITS</text><text x="94" y="118" fill="#58a6ff" class="t t-stat-value" text-anchor="middle">1,049</text><rect x="179" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="193" cy="82" r="4" fill="#3fb950"/><text x="203" y="86" class="t t-stat-label">PRS</text><text x="249" y="118" fill="#3fb950" class="t t-stat-value" text-anchor="middle">3</text><rect x="334" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="348" cy="82" r="4" fill="#d29922"/><text x="358" y="86" class="t t-stat-label">REVIEWS</text><text x="404" y="118" fill="#d29922" class="t t-stat-value" text-anchor="middle">5</text><rect x="489" y="66" width="140" height="72" rx="8" fill="#161b22" stroke="#30363d" stroke-width="1"/><circle cx="503" cy="82" r="4" fill="#bc8cff"/><text x="513" y="86" class="t t-stat-label">REPOS</text><text x="559" y="118" fill="#bc8cff" class="t t-stat-value" text-anchor="middle">24</text><text x="24" y="184" class="t t-h">LANGUAGES</text><text x="24" y="200" class="t t-sub">By bytes of code across all public repos</text><circle cx="114" cy="300" r="70" fill="none" stroke="#00ADD8" stroke-width="28" stroke-dasharray="124.03007796372502 315.792893538846" stroke-dashoffset="0" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#dea584" stroke-width="28" stroke-dasharray="109.07609693263761 330.7468745699334" stroke-dashoffset="-124.03007796372502" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#3178c6" stroke-width="28" stroke-dasharray="103.35839830310418 336.4645731994668" stroke-dashoffset="-233.10617489636263" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#3D6117" stroke-width="28" stroke-dasharray="20.231856689118267 419.59111481345275" stroke-dashoffset="-336.4645731994668" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#3572A5" stroke-width="28" stroke-dasharray="17.15309588860027 422.66987561397076" stroke-dashoffset="-356.6964298885851" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#89e051" stroke-width="28" stroke-dasharray="16.713272917097697 423.1096985854733" stroke-dashoffset="-373.84952577718536" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#a52a22" stroke-width="28" stroke-dasharray="7.916813487046279 431.90615801552474" stroke-dashoffset="-390.56279869428306" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#b07219" stroke-width="28" stroke-dasharray="6.597344572538565 433.22562693003243" stroke-dashoffset="-398.47961218132934" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#000080" stroke-width="28" stroke-dasharray="6.157521601035993 433.66544990153506" stroke-dashoffset="-405.07695675386793" transform="rotate(-90 114 300)" opacity="0.85"/><circle cx="114" cy="300" r="70" fill="none" stroke="#e34c26" stroke-width="28" stroke-dasharray="5.717698629533424 434.1052728730376" stroke-dashoffset="-411.2344783549039" transform="rotate(-90 114 300)" opacity="0.85"/><text x="114" y="305" class="t" fill="#c9d1d9" font-size="14" font-weight="700" text-anchor="middle">10</text><text x="114" y="320" class="t" fill="#6e7681" font-size="10" text-anchor="middle">languages</text><rect x="244" y="220" width="12" height="12" rx="2" fill="#00ADD8" opacity="0.85"/><text x="264" y="230" class="t t-label">Go</text><text x="444" y="230" class="t t-value" text-anchor="end">28.2%</text><rect x="244" y="244" width="12" height="12" rx="2" fill="#dea584" opacity="0.85"/><text x="264" y="254" class="t t-label">Rust</text><text x="444" y="254" class="t t-value" text-anchor="end">24.8%</text><rect x="244" y="268" width="12" height="12" rx="2" fill="#3178c6" opacity="0.85"/><text x="264" y="278" class="t t-label">TypeScript</text><text x="444" y="278" class="t t-value" text-anchor="end">23.5%</text><rect x="244" y="292" width="12" height="12" rx="2" fill="#3D6117" opacity="0.85"/><text x="264" y="302" class="t t-label">TeX</text><text x="444" y="302" class="t t-value" text-anchor="end">4.6%</text><rect x="244" y="316" width="12" height="12" rx="2" fill="#3572A5" opacity="0.85"/><text x="264" y="326" class="t t-label">Python</text><text x="444" y="326" class="t t-value" text-anchor="end">3.9%</text><rect x="244" y="340" width="12" height="12" rx="2" fill="#89e051" opacity="0.85"/><text x="264" y="350" class="t t-label">Shell</text><text x="444" y="350" class="t t-value" text-anchor="end">3.8%</text><rect x="244" y="364" width="12" height="12" rx="2" fill="#a52a22" opacity="0.85"/><text x="264" y="374" class="t t-label">Jinja</text><text x="444" y="374" class="t t-value" text-anchor="end">1.8%</text><rect x="244" y="388" width="12" height="12" rx="2" fill="#b07219" opacity="0.85"/><text x="264" y="398" class="t t-label">Java</text><text x="444" y="398" class="t t-value" text-anchor="end">1.5%</text><rect x="244" y="412" width="12" height="12" rx="2" fill="#000080" opacity="0.85"/><text x="264" y="422" class="t t-label">Lua</text><text x="444" y="422" class="t t-value" text-anchor="end">1.4%</text><rect x="244" y="436" width="12" height="12" rx="2" fill="#e34c26" opacity="0.85"/><text x="264" y="446" class="t t-label">HTML</text><text x="444" y="446" class="t t-value" text-anchor="end">1.3%</text><text x="24" y="516" class="t t-h">EXPERTISE</text><text x="24" y="532" class="t t-sub">Curated from dependencies, topics, and languages via AI analysis</text><text x="24" y="556" class="t t-subhdr">SYSTEMS PROGRAMMING &amp; CLI TOOLS</text><rect x="24" y="568" width="700" height="18" rx="4" fill="#58a6ff" fill-opacity="0.15"/><rect x="24" y="568" width="665" height="18" rx="4" fill="#58a6ff" fill-opacity="0.85"/><text x="734" y="581" class="t t-value">95%</text><text x="24" y="602" class="t t-card-detail">Go · Rust · Wails · Chezmoi · Nix</text><text x="24" y="630" class="t t-subhdr">MACHINE LEARNING &amp; AI</text><rect x="24" y="642" width="700" height="18" rx="4" fill="#3fb950" fill-opacity="0.15"/><rect x="24" y="642" width="630" height="18" rx="4" fill="#3fb950" fill-opacity="0.85"/><text x="734" y="655" class="t t-value">90%</text><text x="24" y="676" class="t t-card-detail">PyTorch · TensorFlow · Keras · Transformers · CNNs</text><text x="24" y="704" class="t t-subhdr">WEB DEVELOPMENT &amp; STATIC SITES</text><rect x="24" y="716" width="700" height="18" rx="4" fill="#d29922" fill-opacity="0.15"/><rect x="24" y="716" width="595" height="18" rx="4" fill="#d29922" fill-opacity="0.85"/><text x="734" y="729" class="t t-value">85%</text><text x="24" y="750" class="t t-card-detail">Astro · React · TypeScript · Tailwind CSS · MDX</text><text x="24" y="778" class="t t-subhdr">DEVOPS &amp; CI/CD AUTOMATION</text><rect x="24" y="790" width="700" height="18" rx="4" fill="#f85149" fill-opacity="0.15"/><rect x="24" y="790" width="560" height="18" rx="4" fill="#f85149" fill-opacity="0.85"/><text x="734" y="803" class="t t-value">80%</text><text x="24" y="824" class="t t-card-detail">GitHub Actions · Docker · Semantic Release · CI/CD · Embed-src</text><text x="24" y="852" class="t t-subhdr">KNOWLEDGE GRAPHS &amp; RETRIEVAL-AUGMENTED GENERATION</text><rect x="24" y="864" width="700" height="18" rx="4" fill="#bc8cff" fill-opacity="0.15"/><rect x="24" y="864" width="525" height="18" rx="4" fill="#bc8cff" fill-opacity="0.85"/><text x="734" y="877" class="t t-value">75%</text><text x="24" y="898" class="t t-card-detail">SurrealDB · Vector Search · RAG · kgdk · ragdk</text><text x="24" y="926" class="t t-subhdr">DESKTOP &amp; CROSS-PLATFORM APPS</text><rect x="24" y="938" width="700" height="18" rx="4" fill="#39d2c0" fill-opacity="0.15"/><rect x="24" y="938" width="489.99999999999994" height="18" rx="4" fill="#39d2c0" fill-opacity="0.85"/><text x="734" y="951" class="t t-value">70%</text><text x="24" y="972" class="t t-card-detail">JavaFX · Wails · React · Go · Rust</text><text x="24" y="1032" class="t t-h">SIGNATURE PROJECTS</text><text x="24" y="1048" class="t t-sub">Top projects by technical complexity</text><rect x="24" y="1058" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="1058" width="4" height="52" rx="2" fill="#58a6ff"/><text x="40" y="1076" class="t t-card-title">resume-generator</text><text x="768" y="1076" class="t t-value" text-anchor="end">★ 10</text><text x="40" y="1092" class="t t-card-detail">A data-driven CLI tool that converts YAML/JSON/TOML resume data into polished PDFs, DOCX,…</text><rect x="24" y="1120" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="1120" width="4" height="52" rx="2" fill="#3fb950"/><text x="40" y="1138" class="t t-card-title">lepus-classifier</text><text x="768" y="1138" class="t t-value" text-anchor="end">★ 2</text><text x="40" y="1154" class="t t-card-detail">A CNN research project exploring optimal image classification architectures for small dat…</text><rect x="24" y="1182" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="1182" width="4" height="52" rx="2" fill="#d29922"/><text x="40" y="1200" class="t t-card-title">linear-gp</text><text x="768" y="1200" class="t t-value" text-anchor="end">★ 2</text><text x="40" y="1216" class="t t-card-detail">A production-grade Rust framework for Linear Genetic Programming research, featuring modu…</text><rect x="24" y="1244" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="1244" width="4" height="52" rx="2" fill="#f85149"/><text x="40" y="1262" class="t t-card-title">homai</text><text x="768" y="1262" class="t t-value" text-anchor="end">★ 0</text><text x="40" y="1278" class="t t-card-detail">Local-first, privacy-focused smart home control system. Manage Zigbee devices through a R…</text><rect x="24" y="1306" width="760" height="52" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="1306" width="4" height="52" rx="2" fill="#bc8cff"/><text x="40" y="1324" class="t t-card-title">urmzd.com</text><text x="768" y="1324" class="t t-value" text-anchor="end">★ 0</text><text x="40" y="1340" class="t t-card-detail">Personal website and blog built with Astro, TypeScript, and MDX—featuring fast static sit…</text><text x="24" y="1404" class="t t-h">CONTRIBUTION CALENDAR</text><text x="24" y="1420" class="t t-sub">1,155 contributions in the last year</text><text x="54" y="1441" class="t t-value">Mar</text><text x="93" y="1441" class="t t-value">Apr</text><text x="145" y="1441" class="t t-value">May</text><text x="210" y="1441" class="t t-value">Jun</text><text x="262" y="1441" class="t t-value">Jul</text><text x="314" y="1441" class="t t-value">Aug</text><text x="379" y="1441" class="t t-value">Sep</text><text x="431" y="1441" class="t t-value">Oct</text><text x="483" y="1441" class="t t-value">Nov</text><text x="548" y="1441" class="t t-value">Dec</text><text x="600" y="1441" class="t t-value">Jan</text><text x="665" y="1441" class="t t-value">Feb</text><text x="717" y="1441" class="t t-value">Mar</text><text x="24" y="1469" class="t t-value">Mon</text><text x="24" y="1495" class="t t-value">Wed</text><text x="24" y="1521" class="t t-value">Fri</text><rect x="54" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="54" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="54" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="54" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="54" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="54" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="54" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="67" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="67" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="67" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="67" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="67" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="67" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="67" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="80" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="80" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="80" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="80" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="80" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="80" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="80" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="93" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="93" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="93" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="93" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="93" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="93" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="93" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="106" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="106" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="106" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="106" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="106" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="106" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="106" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="119" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="119" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="119" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="119" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="119" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="119" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="119" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="132" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="132" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="132" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="132" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="132" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="132" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="132" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="145" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="145" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="145" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="145" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="145" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="145" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="145" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="158" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="158" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="158" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="158" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="158" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="158" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="158" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="171" y="1446" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="171" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="171" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="171" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="171" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="171" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="171" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="184" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="184" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="184" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="184" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="184" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="184" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="184" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="197" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="197" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="197" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="197" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="197" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="197" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="197" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="210" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="210" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="210" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="210" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="210" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="210" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="210" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="223" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="223" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="223" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="223" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="223" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="223" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="223" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="236" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="236" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="236" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="236" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="236" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="236" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="236" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="249" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="249" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="249" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="249" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="249" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="249" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="249" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="262" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="262" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="262" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="262" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="262" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="262" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="262" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="275" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="275" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="275" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="275" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="275" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="275" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="275" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="288" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="288" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="288" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="288" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="288" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="288" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="288" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="301" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="301" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="301" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="301" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="301" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="301" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="301" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="314" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="314" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="314" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="314" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="314" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="314" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="314" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="327" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="327" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="327" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="327" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="327" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="327" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="327" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="340" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="340" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="340" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="340" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="340" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="340" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="340" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="353" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="353" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="353" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="353" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="353" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="353" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="353" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="366" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="366" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="366" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="366" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="366" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="366" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="366" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="379" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="379" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="379" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="379" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="379" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="379" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="379" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="392" y="1446" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="392" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="392" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="392" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="392" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="392" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="392" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="405" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="405" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="405" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="405" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="405" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="405" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="405" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="418" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="418" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="418" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="418" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="418" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="418" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="418" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="431" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="431" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="431" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="431" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="431" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="431" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="431" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="444" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="444" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="444" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="444" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="444" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="444" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="444" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="457" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="457" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="457" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="457" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="457" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="457" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="457" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="470" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="470" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="470" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="470" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="470" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="470" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="470" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="483" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="483" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="483" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="483" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="483" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="483" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="483" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="496" y="1446" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="496" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="496" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="496" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="496" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="496" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="496" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="509" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="509" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="509" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="509" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="509" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="509" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="509" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="522" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="522" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="522" y="1472" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="522" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="522" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="522" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="522" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="535" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="535" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="535" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="535" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="535" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="535" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="535" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="548" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="548" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="548" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="548" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="548" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="548" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="548" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="561" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="561" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="561" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="561" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="561" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="561" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="561" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="574" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="574" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="574" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="574" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="574" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="574" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="574" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="587" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="587" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="587" y="1472" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="587" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="587" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="587" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="587" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="600" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="600" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="600" y="1472" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="600" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="600" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="600" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="600" y="1524" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="613" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="613" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="613" y="1472" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="613" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="613" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="613" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="613" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="626" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="626" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="626" y="1472" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="626" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="626" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="626" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="626" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="639" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="639" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="639" y="1472" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="639" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="639" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="639" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="639" y="1524" width="11" height="11" rx="2" fill="#216e39"/><rect x="652" y="1446" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="652" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="652" y="1472" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="652" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="652" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="652" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="652" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="665" y="1446" width="11" height="11" rx="2" fill="#216e39"/><rect x="665" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="665" y="1472" width="11" height="11" rx="2" fill="#40c463"/><rect x="665" y="1485" width="11" height="11" rx="2" fill="#216e39"/><rect x="665" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="665" y="1511" width="11" height="11" rx="2" fill="#40c463"/><rect x="665" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="678" y="1446" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="678" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="678" y="1472" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="678" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="678" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="678" y="1511" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="678" y="1524" width="11" height="11" rx="2" fill="#40c463"/><rect x="691" y="1446" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="691" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="691" y="1472" width="11" height="11" rx="2" fill="#30a14e"/><rect x="691" y="1485" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="691" y="1498" width="11" height="11" rx="2" fill="#40c463"/><rect x="691" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="691" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="704" y="1446" width="11" height="11" rx="2" fill="#40c463"/><rect x="704" y="1459" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="704" y="1472" width="11" height="11" rx="2" fill="#30a14e"/><rect x="704" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="704" y="1498" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="704" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="704" y="1524" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="717" y="1446" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="717" y="1459" width="11" height="11" rx="2" fill="#40c463"/><rect x="717" y="1472" width="11" height="11" rx="2" fill="#40c463"/><rect x="717" y="1485" width="11" height="11" rx="2" fill="#ebedf0"/><rect x="717" y="1498" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="717" y="1511" width="11" height="11" rx="2" fill="#9be9a8"/><rect x="717" y="1524" width="11" height="11" rx="2" fill="#216e39"/><rect x="730" y="1446" width="11" height="11" rx="2" fill="#40c463"/><rect x="730" y="1459" width="11" height="11" rx="2" fill="#ebedf0"/><text x="24" y="1583" class="t t-h">OPEN SOURCE CONTRIBUTIONS</text><text x="24" y="1599" class="t t-sub">External repositories contributed to (all time)</text><rect x="24" y="1609" width="760" height="44" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="1609" width="4" height="44" rx="2" fill="#58a6ff"/><text x="40" y="1627" class="t t-card-title">MathisWellmann/gym-rs</text><text x="40" y="1643" class="t t-card-detail">★ 126 · Rust</text><rect x="24" y="1661" width="760" height="44" rx="6" fill="#161b22" stroke="#30363d" stroke-width="1"/><rect x="24" y="1661" width="4" height="44" rx="2" fill="#3fb950"/><text x="40" y="1679" class="t t-card-title">getzep/graphiti</text><text x="40" y="1695" class="t t-card-detail">★ 23,772 · Python</text></svg>