{"_id":"@aethereumdev/gitpulse","name":"@aethereumdev/gitpulse","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@aethereumdev/gitpulse","version":"1.0.0","description":"Generate beautiful developer profile report cards in the terminal from GitHub profiles","main":"dist/index.js","bin":{"gitpulse":"dist/index.js"},"scripts":{"build":"tsc","typecheck":"tsc -p tsconfig.test.json","dev":"ts-node src/index.ts","test":"vitest run","test:watch":"vitest","lint":"eslint src/","demo:record":"npm run build && node tools/record-demo.mjs","prepublishOnly":"npm run build"},"keywords":["github","developer","profile","terminal","cli","report-card","ascii-art","stats"],"author":{"name":"Bruno Jaamaa"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/br9704/gitpulse.git"},"homepage":"https://github.com/br9704/gitpulse#readme","bugs":{"url":"https://github.com/br9704/gitpulse/issues"},"dependencies":{"chalk":"^5.3.0","commander":"^12.1.0","ora":"^8.0.1"},"devDependencies":{"@types/node":"^20.11.0","@typescript-eslint/eslint-plugin":"^6.19.0","@typescript-eslint/parser":"^6.19.0","eslint":"^8.56.0","typescript":"^5.3.3","vitest":"^1.2.0"},"engines":{"node":">=20.0.0"},"type":"module","gitHead":"aa07847f5e8052bc57afab19601535972a8222a7","types":"./dist/index.d.ts","_id":"@aethereumdev/gitpulse@1.0.0","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-ZTHuR9Qp6UqezUO1cBxTrpTydvpk2P+Dl/AoskuF+1oil6Pi62rX7u0DqnXFZ3TbMmFSuB9q+aMp5zz16YdeVg==","shasum":"25db3b72705aec9812cb7a729b1532d0ab0dbe8b","tarball":"https://registry.npmjs.org/@aethereumdev/gitpulse/-/gitpulse-1.0.0.tgz","fileCount":80,"unpackedSize":269614,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCHeHBzdVFh+rwM+z8mWl24rxmf5ZeazsiCN8Hs0IpUMgIhAMLgUJd4X1bosqJ857izeoSGclP0GdR8TLcqsMzDUQ3f"}]},"_npmUser":{"name":"aethereum-dev","email":"mcfilms30@gmail.com"},"directories":{},"maintainers":[{"name":"aethereum-dev","email":"mcfilms30@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gitpulse_1.0.0_1786782927885_0.5230632107523874"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-15T08:35:27.697Z","1.0.0":"2026-08-15T08:35:28.036Z","modified":"2026-08-15T08:35:28.288Z"},"maintainers":[{"name":"aethereum-dev","email":"mcfilms30@gmail.com"}],"description":"Generate beautiful developer profile report cards in the terminal from GitHub profiles","homepage":"https://github.com/br9704/gitpulse#readme","keywords":["github","developer","profile","terminal","cli","report-card","ascii-art","stats"],"repository":{"type":"git","url":"git+https://github.com/br9704/gitpulse.git"},"author":{"name":"Bruno Jaamaa"},"bugs":{"url":"https://github.com/br9704/gitpulse/issues"},"license":"MIT","readme":"<div align=\"center\">\n\n<sub><code>~/GITPULSE</code></sub>\n\n# gitpulse\n\n<sub>TERMINAL REPORT CARD · GITHUB PROFILE · NO ACCOUNT</sub>\n\n**A GitHub profile, rendered as a report card in your terminal — where every number says which window it was measured over.**\n\n[![CI](https://github.com/br9704/gitpulse/actions/workflows/ci.yml/badge.svg)](https://github.com/br9704/gitpulse/actions/workflows/ci.yml)\n[![npm](https://img.shields.io/npm/v/%40aethereumdev%2Fgitpulse?style=flat)](https://www.npmjs.com/package/@aethereumdev/gitpulse)\n[![license](https://img.shields.io/github/license/br9704/gitpulse?style=flat)](LICENSE)\n\n<img src=\"https://raw.githubusercontent.com/br9704/gitpulse/master/assets/demo.svg\" alt=\"gitpulse rendering a developer report card in the terminal: wordmark, profile, statistics, language bars, ranked repositories, a code-activity heatmap, commit patterns, streak, and a hire-ability score\" width=\"800\">\n\n<sub>Recorded from <code>gitpulse --demo</code> with <a href=\"https://github.com/br9704/gitpulse/blob/master/tools/record-demo.mjs\"><code>tools/record-demo.mjs</code></a> — a real timed capture of the staged render, not a mock-up.</sub>\n\n</div>\n\n```bash\nnpx @aethereumdev/gitpulse torvalds\n```\n\n| | |\n|---|---|\n| runtime dependencies | **3** — `chalk`, `commander`, `ora` ([`package.json`](https://github.com/br9704/gitpulse/blob/master/package.json)) |\n| github endpoints hit | **3** — user, repos, public events ([`src/api/github.ts`](https://github.com/br9704/gitpulse/blob/master/src/api/github.ts)) |\n| install-time lifecycle scripts | **0** — no `preinstall`, `install`, `postinstall` or `prepare`, so `npx` works under npm v12 defaults |\n| works with no token, no network | `--demo` renders the whole report offline, and CI fails the build if it ever reaches the wire |\n| every number carries its window | the activity span is derived from the data, never assumed — that is the whole point of the tool |\n\n`~/`[install](#install) · `~/`[usage](#usage) · `~/`[architecture](#architecture) · `~/`[how-it-was-built](#how-it-was-built) · `~/`[limitations](#limitations) · `~/`[scoring](SCORING.md)\n\n---\n\n## What it does\n\nGitHub's own profile page is a scroll. It will tell you a follower count and a green calendar, and\nleave you to assemble everything else yourself across a dozen tabs. gitpulse renders the same public\ndata as one screen: profile, statistics, language share, ranked repositories, a code-activity\nheatmap, commit patterns by day and hour, coding streaks, and a 0–100 score with a letter grade.\n\nIt reads three public REST endpoints — the user, their repositories, their public events — and\ncomputes everything else locally. No scraping, no GraphQL, no telemetry, no account. Results cache\nfor 30 minutes under `~/.gitpulse/cache`, evicting at 50 profiles.\n\nWhat makes it different from the other terminal GitHub tools is not the rendering, it is the\nlabelling. GitHub's public Events API returns at most 300 events and reaches back a limited and\n*variable* period — often far less than 90 days for a busy account. Most tools built on it print a\nfixed \"last 90 days\" header over whatever they got. gitpulse derives the window from the oldest\nevent the feed actually returned and prints that window next to the number: `last 30 days of public\ncode events  2026-07-16 → 2026-08-14`. A streak carries `measured within the 30-day event window\nabove, not all-time`. When the label and the data would disagree, the label changes, not the data.\n\nThe output is the product, so the output is what is tested and what CI enforces. Committed snapshots\npin what every renderer emits, byte for byte. The report is staged rather than dumped — sections arrive\nin reading order over ≤2.5s, the stat values count up without shifting column widths, the heatmap\npaints column by column, and the grade letter lands last after a beat. `--no-anim` produces\nbyte-identical output to the staged path, and staging turns itself off automatically whenever the\noutput is piped, redirected, or run under `CI` or `NO_COLOR`.\n\nThe score is the part that needs a caveat rather than a feature bullet, so it has one. It reads\npublic metadata only — it never opens a line of anyone's code, and it cannot see private work.\n[SCORING.md](SCORING.md) documents every input, every weight, and, before any of the formulas, what\nthe score does not measure.\n\n## Install\n\n```bash\nnpm install -g @aethereumdev/gitpulse\ngitpulse torvalds\n\n# or run it without installing\nnpx @aethereumdev/gitpulse torvalds\n```\n\nThe package is scoped; the command is not. Once it is installed the binary is plain `gitpulse`.\nThe scope exists because npm's similarity filter reserves `gitpulse` against the existing\n[`git-pulse`](https://www.npmjs.com/package/git-pulse), which has not shipped since 2022.\n\nRequires **Node 20 or newer**. `npx` asks for confirmation the first time it downloads a package —\nthat prompt is npm, not a hang.\n\n### Set a token — you will want one\n\nGitHub allows **60 unauthenticated requests per hour, per IP**, and that budget is usually already\nspent by something else on your machine. A token raises it to 5,000/hour. **No scopes are required**\nfor public profile data — create the token with every box unchecked.\n\n```bash\n# 1. Create a token (no scopes needed):\n#    https://github.com/settings/tokens/new?description=gitpulse&scopes=\n\n# 2. Persist it — gitpulse reads GITHUB_TOKEN and GH_TOKEN automatically\necho 'export GITHUB_TOKEN=ghp_xxxxxxxx' >> ~/.zshrc && source ~/.zshrc\n\n# 3. Or pass it per run\ngitpulse torvalds --token ghp_xxxxxxxx\n```\n\nAlready using the [GitHub CLI](https://cli.github.com)? `export GITHUB_TOKEN=$(gh auth token)`.\n\nIf you hit the limit without a token, gitpulse prints these steps rather than a bare error. If you\nwould rather see the output before setting anything up, `gitpulse --demo` renders a bundled snapshot\noffline, with no token and no network calls at all.\n\n## Architecture\n\n```mermaid\nflowchart TD\n    CLI[\"<b>src/index.ts</b><br/>commander entry, flags\"]\n    CACHE{\"<b>src/api/cache.ts</b><br/>30-min TTL · 50 profiles\"}\n    FIX[\"<b>src/__fixtures__/demo-profile.ts</b><br/>captured snapshot\"]\n    API[\"<b>src/api/github.ts</b><br/>the only network surface\"]\n    E1[\"GET /users/:name\"]\n    E2[\"GET /users/:name/repos<br/>≤ 200, type=owner\"]\n    E3[\"GET /users/:name/events/public<br/>≤ 300, flaky-tolerant\"]\n    BUILD[\"<b>buildProfile()</b>\"]\n    SCORE[\"<b>src/utils/scoring.ts</b><br/>languages · activity window<br/>streak · patterns · score\"]\n    PROFILE[(\"UserProfile<br/>+ ContributionWindow\")]\n    UI[\"<b>src/ui/</b> — 9 renderers<br/>header · stats · languages · repos<br/>heatmap · score · compare · minimal · export\"]\n    ANIM[\"<b>src/utils/anim.ts</b><br/>paint · reveal · after\"]\n    OUT[\"stdout\"]\n\n    CLI --> CACHE\n    CLI -. \"--demo\" .-> FIX\n    CACHE -- hit --> BUILD\n    CACHE -- miss --> API\n    API --> E1\n    API --> E2\n    API --> E3\n    E1 --> BUILD\n    E2 --> BUILD\n    E3 --> BUILD\n    FIX --> BUILD\n    BUILD --> SCORE\n    SCORE --> PROFILE\n    PROFILE --> UI\n    UI --> ANIM\n    ANIM --> OUT\n    PROFILE -. \"--json · --export\" .-> OUT\n```\n\nTwo decisions shape that diagram.\n\n**`buildProfile()` is split out from `fetchUserProfile()`** so the bundled `--demo` fixture runs the\nexact same derivation the network path runs. The demo is therefore incapable of drifting from the\nproduct — it is not a mock-up of the output, it is the output, with the three fetches replaced by a\ncaptured snapshot. The same split made the whole pipeline testable without a network, and it forced\nan injectable clock: the fixture carries absolute timestamps, so without pinning `now` the demo\nwould have decayed into an empty heatmap within a few months.\n\n**Every animated renderer takes `progress: number = 1`, and `progress === 1` returns exactly the\nstring the static path returns.** The animation cannot diverge from the real output, because the\nlast frame *is* the real output. That turns MOTION.md's \"`--no-anim` must be byte-identical\"\nrequirement from something you verify after the fact into something the type signature enforces;\nfour unit tests assert the identity directly.\n\n## How it was built\n\nWork started from a measured audit ([RESEARCH-CONTEXT.md](https://github.com/br9704/gitpulse/blob/master/RESEARCH-CONTEXT.md)) rather than a\nfeature list, and the audit's verdict was that the tool worked and looked finished but its own\ndocumented first command did not run. `gitpulse torvalds` with no token hit GitHub's 60 req/hr\nunauthenticated cap, because only the `--token` flag was honoured and most people's per-IP budget is\nalready spent. A first-time user ran the README's command, got an error, and concluded the tool was\nbroken. That was the priority-one fix and it was about twenty lines: read `GITHUB_TOKEN`/`GH_TOKEN`\nfrom the environment, split the 403 branch into primary rate limit, secondary rate limit and bad\ncredentials so the message names the real problem, and ship `--demo` so the output is reachable with\nno setup at all.\n\nThen the numbers. `generateContributions` had been counting *every* public event type as a\n\"contribution\" under a hardcoded `Last 90 days:` header, while reporting an active-day count derived\nfrom a third window — three windows, one label, on a screen about a real person. Rewriting it to\ncount only code events and derive the span from real coverage exposed a bug in the plan for the\nrewrite: the first implementation widened the window to GitHub's nominal 90-day retention whenever\nthe 300-event cap was not hit, which rendered `torvalds` as a 90-day grid containing 60 days of\n*fabricated* inactivity for a feed that only reaches back 30. The sprint's own acceptance gate\ncaught it. Four more defects surfaced the same way, by rendering real profiles and reading the\nresult: `src/__tests__/cache.test.ts` was asserting an inline expression and importing no product\ncode at all, which meant two of the then-33 \"passing tests\" verified nothing; Sprint 4's test helpers\nwere compiling into `dist/` and would have shipped inside the packed tarball; `boxen` and `node-fetch` were\ndeclared as runtime dependencies and imported nowhere, worth 24 packages in the install tree of a\nproject whose first rule is zero runtime bloat; and three separate renderers stamped wall-clock time\ninto their output, so the same profile produced different bytes on every run.\n\nThe measurements changed the design twice. The first CI run failed on all three Node versions, and\nthe failure was real: `Math.sin`/`cos`/`sqrt`/`log2` are not required to be bit-identical across\nplatforms and are not, so the Three.js scene export produced `x = 4.044661788320042` on macOS and\n`…043` on Linux. A scene that differs between machines cannot be diffed or cached, which defeats the\npoint of a contract another tool consumes — every derived float is now quantised to 6dp with a\nregression test. And writing [SCORING.md](SCORING.md) meant checking the weights instead of\ndescribing them, which produced the most interesting correction in the project: the star sub-item\ncaps at **40 stars**, not the ~215 the first draft claimed. Above 40 stars that input stops\ndiscriminating entirely, so a 250,000-star repository scores identically to a 40-star one. The\ndocument now says so, because it materially changes how the number should be read.\n\n[masterplan.md](https://github.com/br9704/gitpulse/blob/master/masterplan.md) is the receipts — every sprint's acceptance gate, as-shipped delta,\nand deferral with its reason.\n\n## Verification\n\nThere are no benchmarks here. What there is instead is a CI job that refuses to let the output regress.\n[`.github/workflows/ci.yml`](https://github.com/br9704/gitpulse/blob/master/.github/workflows/ci.yml) runs on every push to every branch, on\n**Node 20, 22 and 24**:\n\n| Check | What it proves |\n|---|---|\n| `npm run lint` | 0 errors, 0 warnings |\n| `npm run typecheck` | `src/` **and** the tests type-check — the build config excludes tests, so `tsc` alone would not see them |\n| `npm run build` | `tsc` exit 0 |\n| `npm test` | every renderer and the network layer, pinned by committed snapshots |\n| `dist/__tests__` absent | test helpers cannot leak into the published tarball again |\n| `node dist/index.js --demo` | the product actually renders |\n| demo with `fetch` stubbed to throw | `--demo` makes **zero** network calls |\n| piped output scanned | no character with the Unicode `Emoji_Presentation` property, no ANSI escape |\n| `npm pack --dry-run` | package contents are what they should be |\n\nCoverage is by surface, not by line: every one of the nine renderers in `src/ui/` and `src/api/github.ts`\nhas at least one test. The network layer is tested against a mocked fetch across 200, 404, 403\nprimary, 403 secondary, 401, 429, 500, the pagination boundary, the flaky-Events-API path, and\nauth-header presence and absence. Colour is pinned off globally in `src/__tests__/setup.ts` so\nsnapshots are readable plain text and cannot pass locally while failing in CI.\n\n```bash\nnpm ci\nnpm run lint && npm run typecheck && npm run build && npm test\n```\n\n## Usage\n\n```bash\ngitpulse <username>                        # full report card\ngitpulse <username> --minimal              # five compact lines\ngitpulse <username> --compare <other>      # head to head\ngitpulse <username> --json                 # curated JSON, not a raw API dump\ngitpulse <username> --export               # Three.js scene graph\ngitpulse --demo                            # bundled fixture, offline\n```\n\n### Flags\n\n| Flag | Short | Description |\n|------|-------|-------------|\n| `--token <token>` | `-t` | GitHub personal access token |\n| `--json` | `-j` | Curated JSON output |\n| `--minimal` | `-m` | Compact output |\n| `--export` | `-e` | Three.js scene data |\n| `--compare <user>` | `-c` | Compare with another user |\n| `--demo` | | Bundled fixture, offline — no token, no network |\n| `--no-anim` | | Print instantly, with no staged reveal |\n| `--no-cache` | | Bypass the cache and fetch fresh |\n| `--clear-cache` | | Clear cached profiles |\n\n### Environment\n\n| Variable | Effect |\n|---|---|\n| `GITHUB_TOKEN` / `GH_TOKEN` | Token used when `--token` is not passed |\n| `GITPULSE_CACHE_DIR` | Cache location (default `~/.gitpulse/cache`) |\n| `NO_COLOR` | Disable all colour and staging |\n| `CI` | Disable staging and spinners |\n\nOutput is plain and instant whenever it is piped, redirected, or run in CI. Scripts get clean text.\n\n### What the output looks like\n\nThree sections of `gitpulse --demo --no-anim`, verbatim. `TOP REPOSITORIES` and `COMMIT PATTERNS`\nare elided for length and marked where they were cut:\n\n```\nLANGUAGES ────────────────────────────────────────────────────\n  > share of repositories by primary language, forks excluded\n\n  C                ██████████████████████████████  88.9% (8 repos)\n  OpenSCAD         ████░░░░░░░░░░░░░░░░░░░░░░░░░░  11.1% (1 repo)\n\n  ██████████████████████████████████████████████████\n  ▌ C  ▌ OpenSCAD\n\n      [ TOP REPOSITORIES — 26 lines, elided ]\n\nCODE ACTIVITY ────────────────────────────────────────────────\n  last 30 days of public code events  2026-07-16 → 2026-08-14\n\n        ▒ ▒ ▒ ▒\n  Mon   ░ ░ ▒ ▓\n        ░ ▒ ▓ ▒\n  Wed   ▒ ░ ▒ ░\n      ▒ ▒ ▒ ▓ ░\n  Fri ▒ ▓ ▒ ▓ ░\n      ░ ▒ ▒ ▒\n\n  less · ░ ▒ ▓ █ more\n  119 code events across 30 active days\n  > source: public Events API — push, pull-request and branch-creation events only\n  > the feed reaches no further back than this window; earlier activity is invisible, not absent\n\n      [ COMMIT PATTERNS — 14 lines, elided ]\n\nCODING STREAK ────────────────────────────────────────────────\n  current      30 days\n  longest      30 days\n  last active  2026-08-14\n  > measured within the 30-day event window above, not all-time\n```\n\n## Limitations\n\nThis is the credibility section. Every item is a real constraint, and most of them are printed in\nthe output itself rather than buried here.\n\n- **The activity window is narrow and variable.** The public Events API returns at most 300 events\n  and reaches back a limited period — often far less than 90 days for a busy account. Everything\n  derived from it (heatmap, commit patterns, streaks, two of the five score components) describes\n  that window and no more. Activity older than it is invisible to the tool, not absent from your\n  life. gitpulse prints the true window rather than assuming one, but it cannot widen it without\n  GraphQL, and staying on REST was a deliberate choice.\n- **\"Languages\" counts repositories, not lines of code.** Each non-fork repository contributes 1 to\n  its GitHub-assigned primary language, so a 300,000-line C project and a one-file C script count\n  the same. The section says so on screen, above the bars: `> share of repositories by primary\n  language, forks excluded`.\n- **The score reads no code and cannot see private work.** A staff engineer whose entire output is\n  private will score badly; that is a limit of the data, not a finding about them. It also stops\n  discriminating above 40 stars on one sub-item. [SCORING.md](SCORING.md) states all of this before\n  it states any formula.\n- **The bundled `--demo` fixture is `torvalds`** — entirely public data, and the profile the docs\n  already use as their example, but it is another person's profile shipping inside the package.\n- **MOTION.md's `> repos 34/61` fetch counter is not implemented.** It would need per-page progress\n  callbacks threaded out of the fetch layer, and the honest position is that the counter would be\n  fiction: the repo total is not known until the first page returns, and the repos endpoint\n  paginates at most twice.\n- **No end-to-end test drives the CLI as a subprocess.** The `--no-anim` byte-identity check does\n  exactly that, but it needs a forced TTY and lives outside the suite.\n- **Nothing enforces that `assets/demo.svg` is current.** `npm run demo:record` regenerates it from\n  a real run; remembering to is manual.\n\n## Alternatives\n\nEach of these was installed and run before being described here, in August 2026. Two of the four no\nlonger do what they say, which is itself the reason to check rather than to repeat a description.\n\n| Tool | What it does | State when run, Aug 2026 |\n|---|---|---|\n| [`git-stats`](https://github.com/IonicaBizau/git-stats) | Contribution calendar from **local** git history | **Actively maintained** (last commit 2025-11-09). Reads its own datastore, filled by a `post-commit` hook; backfilling an existing clone needs `git-stats-importer` first |\n| [`github-readme-stats`](https://github.com/anuraghazra/github-readme-stats) | SVG stat cards to embed in a profile README | **Deprecated 2026-06-30**, superseded by [github-stats-extended](https://github.com/stats-organization/github-stats-extended). Renders to the web, not a terminal |\n| [`github-stats`](https://github.com/IonicaBizau/github-stats) | Language breakdown as an ANSI pie chart | Last published 2020. No commit counts; its calendar sub-command returns 0 for every user |\n| [`ghcal`](https://github.com/IonicaBizau/ghcal) | The contribution calendar alone | **Renders an empty calendar for every user.** It scrapes `data-count` attributes GitHub's markup no longer emits, and reports `Commits in the last year: 0` |\n| **gitpulse** | A composed report card: stats, languages, heatmap, patterns, score | One screen, designed, with its methodology written down |\n\nIf you want a true contribution calendar including private and squashed work, `git-stats` against a\nlocal clone will beat anything built on the public Events API — including this. It is the one tool\nhere that gitpulse does not replace.\n\n## Status\n\nShipped: the CLI, its nine renderers, the staged render, `--demo`, `--json`, `--minimal`,\n`--compare`, the Three.js `--export`, `SCORING.md`, and green CI on Node 20/22/24. Owner-gated and\ntracked in [Sprint 7 of the masterplan](https://github.com/br9704/gitpulse/blob/master/masterplan.md#sprint-7--owner-gated-bruno-executes): moving\nnpm releases onto trusted publishing (OIDC) so every version after the first carries a provenance\nattestation and no long-lived token exists, a human confirmation that the heatmap's column paint\ndoes not flicker in Terminal.app at 52 columns — an agent cannot see flicker — and the decision of\nwhether the bundled demo fixture stays `torvalds` or becomes its author's own profile.\n\n## Development\n\n```bash\ngit clone https://github.com/br9704/gitpulse.git\ncd gitpulse\nnpm install\nnpm run build\nnpm test\nnpm run lint\nnpm run typecheck\n\nnode dist/index.js --demo\nnpm run demo:record   # regenerate assets/demo.svg from a real run\n```\n\nTypeScript strict, ESM, three runtime dependencies. The only lifecycle script is `prepublishOnly`,\nwhich runs at publish time on the author's machine — nothing runs on install, so `npx` is\nunaffected by npm v12 turning dependency lifecycle scripts off by default.\n\n## License · author\n\n```\n────────────────────────────────────────────────────────────────\n```\n\n`</bruno jaamaa>` · [MIT](LICENSE) · [brunojaamaa.dev ↗](https://brunojaamaa.dev) · [github ↗](https://github.com/br9704)\n","readmeFilename":"README.md","_rev":"1-e381da1b163d222b84c72d4be4e14a03"}