@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.
- package/.github/workflows/release.yml +5 -1
- package/CHANGELOG.md +40 -0
- package/README.md +0 -2
- package/assets/insights/index.svg +14 -0
- package/assets/insights/metrics-calendar.svg +14 -0
- package/{metrics → assets/insights}/metrics-complexity.svg +1 -1
- package/{metrics → assets/insights}/metrics-contributions.svg +1 -1
- package/assets/insights/metrics-expertise.svg +14 -0
- package/assets/insights/metrics-languages.svg +14 -0
- package/{metrics → assets/insights}/metrics-pulse.svg +1 -1
- package/examples/classic/README.md +2 -2
- package/examples/classic/index.svg +2 -2
- package/examples/classic/metrics-calendar.svg +1 -1
- package/examples/classic/metrics-complexity.svg +1 -1
- package/examples/classic/metrics-contributions.svg +1 -1
- package/examples/classic/metrics-expertise.svg +2 -2
- package/examples/classic/metrics-languages.svg +1 -1
- package/examples/classic/metrics-pulse.svg +1 -1
- package/examples/ecosystem/README.md +23 -24
- package/examples/ecosystem/index.svg +2 -2
- package/examples/ecosystem/metrics-calendar.svg +1 -1
- package/examples/ecosystem/metrics-complexity.svg +1 -1
- package/examples/ecosystem/metrics-contributions.svg +1 -1
- package/examples/ecosystem/metrics-expertise.svg +2 -2
- package/examples/ecosystem/metrics-languages.svg +1 -1
- package/examples/ecosystem/metrics-pulse.svg +1 -1
- package/examples/minimal/README.md +2 -2
- package/examples/minimal/index.svg +2 -2
- package/examples/minimal/metrics-calendar.svg +1 -1
- package/examples/minimal/metrics-complexity.svg +1 -1
- package/examples/minimal/metrics-contributions.svg +1 -1
- package/examples/minimal/metrics-expertise.svg +2 -2
- package/examples/minimal/metrics-languages.svg +1 -1
- package/examples/minimal/metrics-pulse.svg +1 -1
- package/examples/modern/README.md +36 -38
- package/examples/modern/index.svg +2 -2
- package/examples/modern/metrics-calendar.svg +1 -1
- package/examples/modern/metrics-complexity.svg +1 -1
- package/examples/modern/metrics-contributions.svg +1 -1
- package/examples/modern/metrics-expertise.svg +2 -2
- package/examples/modern/metrics-languages.svg +1 -1
- package/examples/modern/metrics-pulse.svg +1 -1
- package/package.json +5 -5
- package/src/api.ts +1 -1
- package/src/config.ts +6 -12
- package/src/index.ts +6 -0
- package/src/metrics.ts +16 -2
- package/src/readme.test.ts +31 -25
- package/src/templates.test.ts +110 -13
- package/src/templates.ts +38 -11
- package/src/types.ts +3 -0
- package/metrics/index.svg +0 -14
- package/metrics/metrics-calendar.svg +0 -14
- package/metrics/metrics-expertise.svg +0 -14
- package/metrics/metrics-languages.svg +0 -14
- /package/{metrics → assets/insights}/metrics-domains.svg +0 -0
- /package/{metrics → assets/insights}/metrics-tech-stack.svg +0 -0
package/src/templates.test.ts
CHANGED
|
@@ -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: "
|
|
21
|
+
svgs: [{ label: "GitHub Metrics", path: "assets/insights/index.svg" }],
|
|
22
22
|
sectionSvgs: {
|
|
23
|
-
pulse: "
|
|
24
|
-
calendar: "
|
|
25
|
-
expertise: "
|
|
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
|
"[](https://urmzd.dev)",
|
|
76
|
-
svgDir: "
|
|
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(".toContain("");
|
|
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("
|
|
301
|
-
expect(output).toContain("
|
|
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("
|
|
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(".toContain("");
|
|
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("
|
|
389
|
-
expect(output).toContain("
|
|
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("
|
|
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)
|
|
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(``);
|
|
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(``);
|
|
217
227
|
}
|
|
218
228
|
|
|
219
|
-
|
|
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
|
-
//
|
|
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)
|
|
257
|
-
|
|
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 & 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 & 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 & 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 & 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 & 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 & 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>
|