dirplot 0.3.3__tar.gz → 0.4.1__tar.gz

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 (163) hide show
  1. {dirplot-0.3.3 → dirplot-0.4.1}/.claude/settings.local.json +3 -1
  2. {dirplot-0.3.3 → dirplot-0.4.1}/.gitignore +1 -0
  3. dirplot-0.4.1/ANIMATION.md +27 -0
  4. dirplot-0.4.1/CHANGELOG.md +514 -0
  5. dirplot-0.4.1/LICENSE2 +21 -0
  6. dirplot-0.4.1/PKG-INFO +130 -0
  7. dirplot-0.4.1/README.md +80 -0
  8. dirplot-0.4.1/docs/API.md +72 -0
  9. dirplot-0.4.1/docs/CLI.md +359 -0
  10. {dirplot-0.3.3 → dirplot-0.4.1}/docs/EXAMPLES.md +27 -9
  11. dirplot-0.4.1/paths.txt +17 -0
  12. {dirplot-0.3.3 → dirplot-0.4.1}/pyproject.toml +21 -4
  13. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/__init__.py +1 -1
  14. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/archives.py +1 -1
  15. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/display.py +21 -3
  16. dirplot-0.4.1/src/dirplot/git_scanner.py +315 -0
  17. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/github.py +55 -5
  18. dirplot-0.4.1/src/dirplot/main.py +1899 -0
  19. dirplot-0.4.1/src/dirplot/pathlist.py +154 -0
  20. dirplot-0.3.3/src/dirplot/render.py → dirplot-0.4.1/src/dirplot/render_png.py +388 -35
  21. dirplot-0.4.1/src/dirplot/replay_scanner.py +174 -0
  22. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/scanner.py +12 -2
  23. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/svg_render.py +35 -18
  24. dirplot-0.4.1/src/dirplot/watch.py +319 -0
  25. dirplot-0.4.1/test_file.txt +0 -0
  26. dirplot-0.4.1/test_file2.txt +0 -0
  27. dirplot-0.4.1/tests/__init__.py +0 -0
  28. dirplot-0.4.1/tests/test_cli.py +681 -0
  29. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_drawing.py +1 -1
  30. dirplot-0.4.1/tests/test_git_github.py +48 -0
  31. dirplot-0.4.1/tests/test_git_local.py +322 -0
  32. dirplot-0.4.1/tests/test_git_scanner.py +360 -0
  33. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_github.py +69 -2
  34. dirplot-0.4.1/tests/test_pathlist.py +196 -0
  35. dirplot-0.3.3/tests/test_render.py → dirplot-0.4.1/tests/test_render_png.py +159 -1
  36. dirplot-0.4.1/tests/test_replay_scanner.py +286 -0
  37. dirplot-0.4.1/tests/test_watch_animate.py +497 -0
  38. {dirplot-0.3.3 → dirplot-0.4.1}/uv.lock +2 -4
  39. dirplot-0.3.3/CHANGELOG.md +0 -221
  40. dirplot-0.3.3/PKG-INFO +0 -318
  41. dirplot-0.3.3/README.md +0 -268
  42. dirplot-0.3.3/TASKS.md~ +0 -25
  43. dirplot-0.3.3/alpine-pod.png +0 -0
  44. dirplot-0.3.3/aws-lambda.png +0 -0
  45. dirplot-0.3.3/breadcrumbs_test.png +0 -0
  46. dirplot-0.3.3/demo.cast +0 -418
  47. dirplot-0.3.3/demo.yaml~ +0 -16
  48. dirplot-0.3.3/demo1.cast +0 -414
  49. dirplot-0.3.3/docs/dirplot.png +0 -0
  50. dirplot-0.3.3/docs/docker.png +0 -0
  51. dirplot-0.3.3/docs/fastapi.png +0 -0
  52. dirplot-0.3.3/docs/flask.png +0 -0
  53. dirplot-0.3.3/docs/k8s.png +0 -0
  54. dirplot-0.3.3/docs/pypy.png +0 -0
  55. dirplot-0.3.3/docs/python.png +0 -0
  56. dirplot-0.3.3/docs/s3.png +0 -0
  57. dirplot-0.3.3/foo.svg +0 -158
  58. dirplot-0.3.3/misc/scan/FILE-SCANNING.md +0 -72
  59. dirplot-0.3.3/misc/scan/compare.py +0 -58
  60. dirplot-0.3.3/misc/scan/scan_async.py +0 -93
  61. dirplot-0.3.3/misc/scan/scan_dir.py +0 -66
  62. dirplot-0.3.3/misc/scan/scan_rust.py +0 -33
  63. dirplot-0.3.3/misc/scan/scan_threaded.py +0 -90
  64. dirplot-0.3.3/misc/scan/scan_walk.py +0 -46
  65. dirplot-0.3.3/misc/watch/foo.txt +0 -2
  66. dirplot-0.3.3/misc/watch/watch_dir.py +0 -72
  67. dirplot-0.3.3/misc/watch/wordcloud1.png +0 -0
  68. dirplot-0.3.3/misc-watched.png +0 -0
  69. dirplot-0.3.3/openclaw.png +0 -0
  70. dirplot-0.3.3/pg.png +0 -0
  71. dirplot-0.3.3/scripts/animate_demo.py +0 -121
  72. dirplot-0.3.3/scripts/make_docs_images.sh +0 -16
  73. dirplot-0.3.3/scripts/make_fixtures.py +0 -340
  74. dirplot-0.3.3/scripts/open_terminals.sh +0 -71
  75. dirplot-0.3.3/src/dirplot/main.py +0 -648
  76. dirplot-0.3.3/src/dirplot/watch.py +0 -168
  77. dirplot-0.3.3/src-portrait.png +0 -0
  78. dirplot-0.3.3/src.pdf +0 -0
  79. dirplot-0.3.3/src.png +0 -0
  80. dirplot-0.3.3/src.svg +0 -382
  81. dirplot-0.3.3/test-animation.png +0 -0
  82. dirplot-0.3.3/tests/animation/README.md +0 -3
  83. dirplot-0.3.3/tests/animation/changelog.txt +0 -1
  84. dirplot-0.3.3/tests/animation/config.toml +0 -3
  85. dirplot-0.3.3/tests/animation/data/records.csv +0 -4
  86. dirplot-0.3.3/tests/animation/data/schema_v1.json +0 -1
  87. dirplot-0.3.3/tests/animation/src/lib/parser.py +0 -2
  88. dirplot-0.3.3/tests/animation/src/main.py +0 -7
  89. dirplot-0.3.3/tests/test_cli.py +0 -193
  90. {dirplot-0.3.3 → dirplot-0.4.1}/.dockerignore +0 -0
  91. {dirplot-0.3.3 → dirplot-0.4.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  92. {dirplot-0.3.3 → dirplot-0.4.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  93. {dirplot-0.3.3 → dirplot-0.4.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  94. {dirplot-0.3.3 → dirplot-0.4.1}/.github/dependabot.yml +0 -0
  95. {dirplot-0.3.3 → dirplot-0.4.1}/.github/workflows/ci.yml +0 -0
  96. {dirplot-0.3.3 → dirplot-0.4.1}/.github/workflows/publish.yml +0 -0
  97. {dirplot-0.3.3 → dirplot-0.4.1}/.ipynb_checkpoints/Untitled-checkpoint.ipynb +0 -0
  98. {dirplot-0.3.3 → dirplot-0.4.1}/.pre-commit-config.yaml +0 -0
  99. {dirplot-0.3.3 → dirplot-0.4.1}/.python-version +0 -0
  100. {dirplot-0.3.3 → dirplot-0.4.1}/CONTRIBUTING.md +0 -0
  101. {dirplot-0.3.3 → dirplot-0.4.1}/Dockerfile +0 -0
  102. {dirplot-0.3.3 → dirplot-0.4.1}/LICENSE +0 -0
  103. {dirplot-0.3.3 → dirplot-0.4.1}/Makefile +0 -0
  104. {dirplot-0.3.3 → dirplot-0.4.1}/SECURITY.md +0 -0
  105. {dirplot-0.3.3 → dirplot-0.4.1}/demo.yaml +0 -0
  106. {dirplot-0.3.3 → dirplot-0.4.1}/docs/ARCHIVES.md +0 -0
  107. {dirplot-0.3.3 → dirplot-0.4.1}/docs/SSH_DESIGN.md +0 -0
  108. /dirplot-0.3.3/src/dirplot/py.typed → /dirplot-0.4.1/echo +0 -0
  109. {dirplot-0.3.3 → dirplot-0.4.1}/gen_asciicast.py +0 -0
  110. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/__main__.py +0 -0
  111. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/colors.py +0 -0
  112. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/docker.py +0 -0
  113. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/fonts/JetBrainsMono-Bold.ttf +0 -0
  114. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/fonts/JetBrainsMono-BoldItalic.ttf +0 -0
  115. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/fonts/JetBrainsMono-Italic.ttf +0 -0
  116. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/fonts/JetBrainsMono-Regular.ttf +0 -0
  117. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/fonts/OFL.txt +0 -0
  118. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/k8s.py +0 -0
  119. /dirplot-0.3.3/tests/__init__.py → /dirplot-0.4.1/src/dirplot/py.typed +0 -0
  120. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/s3.py +0 -0
  121. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/ssh.py +0 -0
  122. {dirplot-0.3.3 → dirplot-0.4.1}/src/dirplot/terminal.py +0 -0
  123. {dirplot-0.3.3 → dirplot-0.4.1}/tests/conftest.py +0 -0
  124. {dirplot-0.3.3 → dirplot-0.4.1}/tests/example/bar/bar.py +0 -0
  125. {dirplot-0.3.3 → dirplot-0.4.1}/tests/example/bar/baz.json +0 -0
  126. {dirplot-0.3.3 → dirplot-0.4.1}/tests/example/foo/foo.md +0 -0
  127. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.7z +0 -0
  128. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.a +0 -0
  129. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.aab +0 -0
  130. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.apk +0 -0
  131. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.cpio +0 -0
  132. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.ear +0 -0
  133. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.epub +0 -0
  134. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.ipa +0 -0
  135. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.iso +0 -0
  136. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.jar +0 -0
  137. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.nupkg +0 -0
  138. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.rar +0 -0
  139. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.tar +0 -0
  140. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.tar.bz2 +0 -0
  141. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.tar.gz +0 -0
  142. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.tar.xz +0 -0
  143. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.tar.zst +0 -0
  144. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.tbz2 +0 -0
  145. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.tgz +0 -0
  146. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.txz +0 -0
  147. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.tzst +0 -0
  148. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.vsix +0 -0
  149. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.war +0 -0
  150. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.whl +0 -0
  151. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.xar +0 -0
  152. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.xpi +0 -0
  153. {dirplot-0.3.3 → dirplot-0.4.1}/tests/fixtures/sample.zip +0 -0
  154. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_archives.py +0 -0
  155. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_colors.py +0 -0
  156. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_display.py +0 -0
  157. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_docker.py +0 -0
  158. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_k8s.py +0 -0
  159. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_s3.py +0 -0
  160. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_scanner.py +0 -0
  161. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_ssh.py +0 -0
  162. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_svg_render.py +0 -0
  163. {dirplot-0.3.3 → dirplot-0.4.1}/tests/test_terminal.py +0 -0
@@ -7,7 +7,9 @@
7
7
  "Bash(git mv:*)",
8
8
  "Bash(LC_ALL=C sed:*)",
9
9
  "Bash(find:*)",
10
- "Bash(docker run:*)"
10
+ "Bash(docker run:*)",
11
+ "Bash(wc:*)",
12
+ "Bash(identify:*)"
11
13
  ]
12
14
  }
13
15
  }
@@ -38,3 +38,4 @@ Thumbs.db
38
38
  NOTES.md
39
39
  TASKS.md
40
40
  tests/example_dirplot.png
41
+ demo/
@@ -0,0 +1,27 @@
1
+ # Animation design notes
2
+
3
+ ## `dirplot watch` — is non-animated mode useful?
4
+
5
+ The watch command has two modes:
6
+
7
+ - **Non-animated** (`dirplot watch . --output treemap.png`): regenerates and overwrites the
8
+ PNG on every debounced filesystem change. Useful paired with an auto-refreshing image
9
+ viewer (e.g. `feh --reload` on Linux) as a live dashboard.
10
+ - **Animated** (`dirplot watch . --output treemap.mp4 --animate`): each debounced render
11
+ becomes one frame; the complete APNG or MP4 is written on Ctrl-C.
12
+
13
+ The non-animated mode is a niche use case. The compelling reason to use `dirplot watch`
14
+ at all — vs. running `dirplot map .` on demand — is the animation: a timelapse of how
15
+ the filesystem changed over time.
16
+
17
+ The current design is also asymmetric: `--animate` produces a file *on exit*, while
18
+ non-animated produces a file *on every change*. They're almost opposite behaviours on
19
+ the same command.
20
+
21
+ ### Options to consider
22
+
23
+ 1. **Keep as-is**, but lead the docs with `--animate` as the primary use case.
24
+ 2. **Make `--animate` the default** for `watch`, keeping `--no-animate` for the
25
+ live-refresh use case — but this is a breaking change.
26
+ 3. **Document the live-refresh pattern explicitly** so non-animated mode doesn't look
27
+ like a half-baked feature.
@@ -0,0 +1,514 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.4.1] - 2026-04-03
11
+
12
+ ### Added
13
+
14
+ - **`--last PERIOD`** for `dirplot git` — filter commits by a relative time period instead
15
+ of (or in addition to) `--max-commits`. Accepts a number followed by a unit:
16
+ `m` (minutes), `h` (hours), `d` (days), `w` (weeks), `mo` (months = 30 days).
17
+ For GitHub URLs, uses `git clone --shallow-since` for an efficient date-bounded shallow
18
+ clone. `--last` and `--max-commits` may be combined (date filter + count cap both apply).
19
+ ```bash
20
+ dirplot git . -o history.mp4 --animate --last 30d
21
+ dirplot git . -o history.mp4 --animate --last 24h
22
+ dirplot git github://owner/repo -o history.mp4 --animate --last 2w --max-commits 10
23
+ ```
24
+
25
+ - **`dirplot demo` command** — new subcommand that runs a curated set of example commands
26
+ and saves outputs to a folder. Useful for first-time walkthroughs or verifying that
27
+ everything works in a given environment. Accepts `--output` (default: `demo/`),
28
+ `--github-url` (default: `https://github.com/deeplook/dirplot`), and
29
+ `--interactive` / `-i` to step through and confirm each command individually. Output
30
+ uses rich formatting with colour, section rules, and status indicators.
31
+ ```bash
32
+ dirplot demo # run all examples, save to ./demo/
33
+ dirplot demo --output ~/dp-demo --interactive
34
+ ```
35
+
36
+ - **`--fade-out` for animated output** — appends a fade-out sequence at the end of
37
+ animations produced by `dirplot git --animate`, `dirplot watch --animate`, and
38
+ `dirplot replay`. Four flags control the effect:
39
+ - `--fade-out` / `--no-fade-out` — enable/disable (default: off)
40
+ - `--fade-out-duration SECS` — total fade length in seconds (default: 1.0)
41
+ - `--fade-out-frames N` — number of blend steps; defaults to 4 per second of duration
42
+ so longer fades are automatically finer-grained
43
+ - `--fade-out-color COLOR` — target colour: `auto` (black in dark mode, white in light
44
+ mode), `transparent` (PNG/APNG only; fades to fully transparent), any CSS colour
45
+ name, or hex code (e.g. `"#1a1a2e"`)
46
+ ```bash
47
+ dirplot git . -o history.png --animate --fade-out
48
+ dirplot git . -o history.mp4 --animate --fade-out --fade-out-duration 2.0
49
+ dirplot git . -o history.png --animate --fade-out --fade-out-color transparent
50
+ ```
51
+
52
+ - **`--dark` / `--light` mode** for all treemap commands — controls background and border
53
+ colours. Dark mode (default) uses a near-black canvas with white directory labels; light
54
+ mode uses a white canvas with black labels. Available on `map`, `git`, `watch`, and
55
+ `replay`.
56
+ ```bash
57
+ dirplot map . --light
58
+ dirplot git . -o history.mp4 --animate --light
59
+ ```
60
+
61
+ - **Metadata in MP4/MOV output** — `dirplot git`, `dirplot watch`, and `dirplot replay`
62
+ now embed the same dirplot metadata (date, software version, OS, Python version,
63
+ executed command) into MP4/MOV files that was previously only written to PNG and SVG.
64
+ `dirplot read-meta` reads it back via `ffprobe`.
65
+
66
+ - **Automatic `gh` CLI credential fallback** — if `--github-token` and `GITHUB_TOKEN`
67
+ are both absent, dirplot silently runs `gh auth token`. Users authenticated with the
68
+ [GitHub CLI](https://cli.github.com/) (`gh auth login`) can access private repositories
69
+ with no extra configuration. Token resolution order: `--github-token` →
70
+ `$GITHUB_TOKEN` → `gh auth token`.
71
+
72
+ ### Changed
73
+
74
+ - `--fade-out-frames` defaults dynamically to `round(fade_out_duration × 4)` rather than
75
+ a fixed 4, so a 2-second fade automatically uses 8 frames and a 0.5-second fade uses 2.
76
+
77
+ ### Fixed
78
+
79
+ - **`--total-duration` overshooting the target length** — when many commits fell within
80
+ a burst (closely-spaced timestamps), their proportional frame durations would each be
81
+ raised to the 200 ms floor, inflating the total well beyond the requested duration
82
+ (e.g. 34 s instead of 30 s). The floor is still applied for readability, but the
83
+ non-floored frames are now scaled down to compensate so the sum always matches
84
+ `--total-duration` exactly.
85
+
86
+ ### Docs
87
+
88
+ - Added `## dirplot read-meta` section to `docs/CLI.md` (previously undocumented).
89
+ - Documented external tool requirements: `git` (required by `dirplot git`), `ffmpeg`
90
+ (required for MP4 output), `ffprobe` (required by `read-meta` on MP4 files) — in both
91
+ `README.md` and `docs/CLI.md`.
92
+
93
+ ## [0.4.0] - 2026-03-28
94
+
95
+ ### Added
96
+
97
+ - **MP4 video output** — all three animation commands (`watch --animate`, `git --animate`,
98
+ `replay`) now write MP4 video when the output path ends in `.mp4` or `.mov`. Quality is
99
+ controlled via `--crf` (Constant Rate Factor: 0 = lossless, 51 = worst, default 23) and
100
+ `--codec` (`libx264` H.264 or `libx265` H.265). MP4 files are typically 10–100× smaller
101
+ than equivalent APNGs. Requires `ffmpeg` on PATH.
102
+ ```bash
103
+ dirplot git . -o history.mp4 --animate
104
+ dirplot git . -o history.mp4 --animate --crf 18 --codec libx265
105
+ dirplot replay events.jsonl -o replay.mp4 --total-duration 30
106
+ dirplot watch . -o treemap.mp4 --animate
107
+ ```
108
+ - **`@ref` suffix for `dirplot git`**: local repository paths now accept an optional
109
+ `@ref` suffix to target a specific branch, tag, or commit SHA without needing
110
+ `--range` (e.g. `dirplot git .@my-branch -o out.apng --animate`). `--range` takes
111
+ precedence when both are provided.
112
+ - **`dirplot git` subcommand** — replays a git repository's commit history as an
113
+ animated treemap. Each commit becomes one frame; changed tiles receive the same
114
+ colour-coded highlight borders as `watch --animate` (green = created, blue = modified,
115
+ red = deleted). The commit SHA and local timestamp are shown in the root tile header,
116
+ and a progress bar at the top of each frame advances as the animation plays.
117
+ ```bash
118
+ # Animate all commits, write APNG
119
+ dirplot git . --output history.apng --animate --exclude .git
120
+
121
+ # Last 50 commits on main, 30-second animation with time-proportional frame durations
122
+ dirplot git . --output history.apng --animate \
123
+ --range main~50..main --total-duration 30
124
+
125
+ # Live-updating static PNG (last frame wins; useful with an auto-refreshing viewer)
126
+ dirplot git /path/to/repo --output treemap.png --max-commits 100
127
+ ```
128
+ - **`--range`** (`-r`): git revision range passed directly to `git log`
129
+ (e.g. `main~50..main`, `v1.0..HEAD`). Defaults to the full history of the current branch.
130
+ - **`--max-commits`** (`-n`): cap the number of commits processed.
131
+ - **`--frame-duration`**: fixed frame display time in ms when `--total-duration` is not set
132
+ (default: 1000 ms).
133
+ - **`--total-duration`**: target total animation length in seconds. Frame durations are
134
+ scaled proportionally to the real elapsed time between commits, so quiet periods in
135
+ development history map to longer pauses and burst activity to rapid flips. A 200 ms
136
+ floor prevents very fast commits from being invisible; durations are capped at 65 535 ms
137
+ (APNG uint16 limit). A summary line reports the actual range:
138
+ `Proportional timing: 200–7553 ms/frame (total ~30.1s)`.
139
+ - **`--workers`** (`-w`): number of parallel render workers in animate mode (default: all
140
+ CPU cores). Rendering is memory-bandwidth bound, so 4–8 workers is typically optimal;
141
+ use this flag to tune for your hardware.
142
+ - **Time-proportional progress bar**: a 2 px bar at the top of each frame advances in
143
+ proportion to animation time consumed, not frame count — so a burst of closely-spaced
144
+ commits produces only a small movement while a long quiet period advances it visibly.
145
+ With fixed `--frame-duration` the bar is linear as before.
146
+
147
+ - **Debounced watch** (`--debounce SECONDS`, default `0.5`): the `watch` subcommand now
148
+ collects rapid file-system event bursts and regenerates the treemap once per quiet
149
+ period instead of on every raw event. A `git checkout` touching 100 files triggers
150
+ exactly one render after the activity settles. Pass `--debounce 0` to restore the
151
+ old immediate-fire behaviour.
152
+ ```bash
153
+ dirplot watch . --output treemap.png # 500 ms debounce (default)
154
+ dirplot watch . --output treemap.png --debounce 1.0 # 1 s quiet window
155
+ dirplot watch . --output treemap.png --debounce 0 # immediate, as before
156
+ ```
157
+ - **Event log** (`--event-log FILE`): on Ctrl-C exit, all raw file-system events
158
+ recorded during the session are written as newline-delimited JSON (JSONL) to the
159
+ given file. Each line has `timestamp`, `type`, `path`, and `dest_path` fields.
160
+ The log is written only if there are events to record.
161
+ ```bash
162
+ dirplot watch src --output treemap.png --event-log events.jsonl
163
+ # Ctrl-C, then:
164
+ cat events.jsonl | python3 -m json.tool
165
+ ```
166
+ - **File-change highlights** (`--animate`): each APNG frame now draws colour-coded
167
+ borders around tiles that changed since the previous frame — green for created,
168
+ blue for modified, red for deleted, orange for moved. Deleted files are highlighted
169
+ retroactively on the *previous* frame (since the tile no longer exists in the current
170
+ one), so the animation clearly shows both the disappearance and the appearance of files.
171
+ Moved files appear as a deletion at the old path and a creation at the new path.
172
+ - **Graceful finalization**: Ctrl-C now flushes any pending debounced render before
173
+ stopping the observer, so the output file always reflects the final state of the
174
+ watched tree. A second Ctrl-C during APNG writing is ignored so the file can finish
175
+ being written.
176
+ - **Tree comment stripping**: trailing `# comments` in `tree` output are now ignored
177
+ by the path-list parser, so annotated tree listings (e.g. `├── config.json # app config`)
178
+ are parsed correctly. Filenames containing `#` without a leading space are preserved.
179
+ - **`scripts/apng_frames.py`**: utility script to list frame durations, dimensions, and
180
+ offsets in an APNG file.
181
+ - **`scripts/watch_events.py`**: utility script to watch directories and log filesystem
182
+ events to a CSV file (or stdout) in real time using watchdog.
183
+ - **`--depth` for `watch`**: the `watch` subcommand now accepts `--depth N` to limit
184
+ recursion depth, matching the behaviour of `dirplot map`.
185
+ ```bash
186
+ dirplot watch . --output treemap.png --depth 3
187
+ ```
188
+ - **`dirplot replay` subcommand** — replays a JSONL filesystem event log (as produced
189
+ by `dirplot watch --event-log`) as an animated treemap APNG. Events are grouped into
190
+ time buckets (one frame per bucket, default 60 s), with colour-coded highlight borders
191
+ matching `watch --animate`. Only files referenced in the event log appear in the
192
+ treemap; the common ancestor of all paths is used as the tree root. Frame durations
193
+ can be uniform (`--frame-duration`, default 500 ms) or proportional to the real time
194
+ gaps between buckets (`--total-duration`). Frames are rendered in parallel.
195
+ ```bash
196
+ # Replay an event log with 60-second buckets, 30-second total animation
197
+ dirplot replay events.jsonl --output replay.apng --total-duration 30
198
+
199
+ # Smaller buckets for fine-grained activity, fixed frame duration
200
+ dirplot replay events.jsonl --output replay.apng --bucket 10 --frame-duration 200
201
+ ```
202
+
203
+ - **`dirplot git` accepts GitHub URLs** — pass a `github://owner/repo[@branch]` or
204
+ `https://github.com/owner/repo` URL directly to `dirplot git`. dirplot clones the
205
+ repository into a temporary directory (shallow when `--max-commits` is set, full
206
+ otherwise), runs the full history pipeline locally, and removes the clone on exit.
207
+ No permanent local copy is created.
208
+ ```bash
209
+ # Animate the last 50 commits of a GitHub repo — no local clone needed
210
+ dirplot git github://owner/repo --output history.png --animate --max-commits 50
211
+
212
+ # Specific branch
213
+ dirplot git github://owner/repo@main --output history.png --animate --max-commits 50
214
+ ```
215
+ - **Total commit count shown** — `dirplot git` now reports the total number of commits
216
+ available alongside the number being animated, so you can gauge how much history
217
+ exists before committing to a longer run:
218
+ ```
219
+ Replaying 20 of 147 commit(s) (increase --max-commits to process more) ...
220
+ ```
221
+ For GitHub URLs the count is fetched with a single cheap API request (one commit
222
+ object + `Link` header). For local repos `git rev-list --count HEAD` is used.
223
+ - **`--github-token`** (`$GITHUB_TOKEN`): added to `dirplot git` for private GitHub
224
+ repos or to raise the API rate limit when fetching the total commit count.
225
+
226
+ ### Changed
227
+
228
+ - **`libarchive-c` is now an optional dependency.** Install it with
229
+ `pip install 'dirplot[libarchive]'` (plus the system library:
230
+ `brew install libarchive` / `apt install libarchive-dev`) to enable
231
+ `.iso`, `.cpio`, `.rpm`, `.cab`, `.lha`, `.xar`, `.pkg`, `.dmg`, `.a`, `.ar`,
232
+ and `.tar.zst` / `.tzst` support. The base install works without it; a clear
233
+ error is shown if you try to open one of these formats without the extra.
234
+
235
+ - **`--animate` writes the APNG once on exit** instead of reading and rewriting the
236
+ entire file on every render. Frames are accumulated as raw PNG bytes in memory and
237
+ flushed as a single multi-frame APNG when the watcher stops (Ctrl-C). This removes
238
+ an O(N²) disk-I/O pattern where frame K required reading a K-frame APNG just to
239
+ append one more frame. Status output during a session now reads `Captured frame N`;
240
+ the final `Wrote N-frame APNG → …` line confirms the file was written on exit.
241
+
242
+ ### Fixed
243
+
244
+ - **Initial scan progress**: the `watch` subcommand now prints `Scanning <roots> …`
245
+ before the first render and starts the filesystem observer only after the initial
246
+ treemap has been generated, avoiding spurious events during the first scan.
247
+ - **`--animate` race condition**: the debounce timer thread was marked as daemon,
248
+ causing an in-progress render to be killed when the main thread exited after
249
+ `observer.join()`. The timer is no longer a daemon thread; `flush()` joins any
250
+ in-flight render before stopping.
251
+ - **`--animate` Pillow APNG regression**: passing `pnginfo` alongside `save_all=True`
252
+ caused Pillow to silently write a static PNG instead of an APNG. The `pnginfo`
253
+ argument is now omitted from multi-frame saves (cross-process timing metadata is
254
+ no longer needed since frames are held in memory for the lifetime of the process).
255
+ - **APNG frame duration overflow**: restoring the inter-session frame duration from
256
+ stored metadata could produce a value exceeding 65 535 ms — the maximum expressible
257
+ by APNG's uint16 `delay_num` field when `delay_den = 1000` — causing Pillow to raise
258
+ `cannot write duration`. Durations are now capped at 65 535 ms (≈ 65 s).
259
+
260
+ - **Path-list input from `tree` / `find`** (`--paths-from FILE` or stdin pipe): the `map`
261
+ subcommand now accepts a list of paths produced by `tree` or `find` — either piped via
262
+ stdin or read from a file with `--paths-from`. Format is auto-detected: `tree` output
263
+ (detected by `├──` / `└──` box-drawing characters) or `find` output (one path per line).
264
+ Handles `tree -s` / `tree -h` (size columns), `tree -f` (full embedded paths), and the
265
+ default indented name format. Ancestor/descendant duplicates are collapsed automatically
266
+ so only the minimal set of roots is passed to the scanner.
267
+ ```bash
268
+ # Implicit stdin — no flag needed
269
+ tree src/ | dirplot map
270
+ tree -s src/ | dirplot map # with file sizes in tree output
271
+ find . -name "*.py" | dirplot map
272
+
273
+ # Explicit file
274
+ tree src/ > paths.txt && dirplot map --paths-from paths.txt
275
+
276
+ # Explicit stdin
277
+ tree src/ | dirplot map --paths-from -
278
+ ```
279
+ Positional path arguments and path-list input are mutually exclusive — combining them
280
+ exits with a clear error. Only local paths are supported (remote backends such as
281
+ `docker://`, `s3://`, `ssh://` remain positional-arg only).
282
+
283
+ - **`dirplot watch` accepts multiple directories**: the `watch` subcommand now takes
284
+ one or more positional path arguments and schedules a filesystem observer for each,
285
+ regenerating the treemap from all roots on every change.
286
+ ```bash
287
+ dirplot watch src tests --output treemap.png
288
+ ```
289
+ - **`dirplot map` accepts multiple file paths as roots**: previously, multi-root mode
290
+ required every argument to be a directory. Individual files can now be passed as roots;
291
+ each is treated as a leaf node and displayed under the common parent directory.
292
+ ```bash
293
+ dirplot map src/main.py src/util.py --no-show
294
+ ```
295
+ - **stdout output** (`--output -`): passing `-` as the output path writes the PNG or SVG
296
+ bytes to stdout, enabling piping to other tools. Header and progress lines are
297
+ automatically redirected to stderr to keep the binary stream clean.
298
+ ```bash
299
+ dirplot map . --output - --no-show | convert - -resize 50% small.png
300
+ dirplot map . --output - --format svg --no-show > treemap.svg
301
+ ```
302
+
303
+ ## [0.3.3] - 2026-03-14
304
+
305
+ ### Added
306
+
307
+ - **Breadcrumbs mode** (`--breadcrumbs/--no-breadcrumbs`, `-b/-B`, on by default): directories
308
+ that form a single-child chain (one subdirectory, no files) are collapsed into a single tile
309
+ whose header shows the full path separated by ` / ` (e.g. `src / dirplot / fonts`). When the
310
+ label is too wide, middle segments are replaced with `…` (`src / … / fonts`). The root tile
311
+ is never collapsed. Disable with `-B` or `--no-breadcrumbs`.
312
+ - **Tree depth in root label**: the root tile header now includes `depth: N` alongside the
313
+ file, directory, and size summary (e.g. `myproject — 124 files, 18 dirs, 4.0 MB (…), depth: 6`).
314
+ The depth reflects the original tree structure and is invariant to whether breadcrumbs mode
315
+ is active.
316
+
317
+ ## [0.3.2] - 2026-03-13
318
+
319
+ ### Added
320
+
321
+ - **`dirplot watch`** subcommand — watches a directory and regenerates the treemap
322
+ on every file-system change using watchdog (FSEvents on macOS, inotify on Linux,
323
+ kqueue on BSD). Requires `watchdog`, now a core dependency.
324
+ ```bash
325
+ dirplot watch . --output treemap.png
326
+ dirplot watch . --output treemap.png --animate # APNG, one frame per change
327
+ ```
328
+ - **Vertical file labels**: file tiles that are at least twice as tall as wide now
329
+ display their label rotated 90° CCW, letting the text span the full tile height
330
+ instead of being squeezed into the narrow width.
331
+ - **Scan and render timing** shown in header output:
332
+ `Found 1,414 files … [2.3s]` and `Saved dirplot to out.png [0.4s]`.
333
+ - **Multiple local roots**: `dirplot map src tests` accepts two or more local
334
+ directory paths, finds their common parent, and shows only those subtrees.
335
+ - **`--subtree` / `-s`** option (repeatable) — allowlist complement to `--exclude`:
336
+ keep only the named direct children of the root after scanning. Supports nested
337
+ paths such as `--subtree src/dirplot/fonts`.
338
+
339
+ ### Fixed
340
+
341
+ - `--exclude` on pod and Docker backends now prunes entire subtrees — previously only
342
+ the exact path was matched, so all children leaked through.
343
+ - Clearer error for distroless pods: exit code 126 from `kubectl exec` now surfaces as
344
+ an actionable message explaining that the container has no shell or `find` utility.
345
+ - Adaptive file-label font size is now computed with a single `textbbox` measurement
346
+ (one call per tile) instead of stepping down one pixel at a time — eliminates an
347
+ O(font_size × n_tiles) bottleneck that caused near-blocking on large trees such as
348
+ `.venv` directories.
349
+
350
+ ### Changed
351
+
352
+ - `-s` short alias reassigned from `--font-size` to `--subtree`. `--font-size` still
353
+ works as before; it just no longer has a single-letter alias.
354
+
355
+ ## [0.3.1] - 2026-03-11
356
+
357
+ ### Added
358
+
359
+ - `github://` URI now accepts an optional subpath after the repository name, letting
360
+ you scan a subdirectory directly:
361
+ - `github://owner/repo/sub/path` — subpath on the default branch
362
+ - `github://owner/repo@ref/sub/path` — subpath on a specific branch, tag, or commit SHA
363
+ - `https://github.com/owner/repo/tree/branch/sub/path` — full GitHub URL form
364
+ - Tags and commit SHAs are supported wherever a branch ref was previously accepted
365
+ (e.g. `github://torvalds/linux@v6.12`), as the GitHub trees API accepts any git ref.
366
+ - `--legend N` replaces the old boolean `--legend/--no-legend` flag. It now shows a
367
+ **file-count legend** — a sorted list of the top N extensions by number of files,
368
+ with a coloured swatch and the file count for each entry:
369
+ - Pass `--legend` alone to use the default of 20 entries.
370
+ - Pass `--legend 10` for a custom limit.
371
+ - Omit the flag entirely to show no legend.
372
+ - The number of rows is also capped automatically so the box never overflows the
373
+ image, based on available vertical space and the current `--font-size`.
374
+ - Extensions with the same count are sorted alphabetically as a tiebreaker.
375
+ - When the total number of extensions exceeds the limit, a `(+N more)` line is
376
+ appended at the bottom of the box.
377
+
378
+ - The root tile header now includes a summary of the scanned tree after an em-dash
379
+ separator: `myproject — 124 files, 18 dirs, 4.0 MB (4,231,680 bytes)`.
380
+ Applies to both PNG and SVG output. The label is truncated with `…` when the tile
381
+ is too narrow to fit the full string.
382
+
383
+ - Greatly expanded archive format support via the new `libarchive-c` core dependency
384
+ (wraps the system libarchive C library):
385
+ - **New formats**: `.iso`, `.cpio`, `.xar`, `.pkg`, `.dmg`, `.img`, `.rpm`, `.cab`,
386
+ `.lha`, `.lzh`, `.a`, `.ar`, `.tar.zst`, `.tzst`
387
+ - **New ZIP aliases**: `.nupkg` (NuGet), `.vsix` (VS Code extension), `.ipa` (iOS app),
388
+ `.aab` (Android App Bundle)
389
+ - `.tar.zst` / `.tzst` routed through libarchive for consistent behaviour across all
390
+ supported Python versions (stdlib `tarfile` only gained zstd support in 3.12).
391
+ - `libarchive-c>=5.0` added as a core dependency alongside `py7zr` and `rarfile`.
392
+ Requires the system libarchive library:
393
+ `brew install libarchive` / `apt install libarchive-dev`.
394
+ - See [ARCHIVES.md](docs/ARCHIVES.md) for the full format table, platform notes, and
395
+ intentionally unsupported formats (`.deb`, UDIF `.dmg`).
396
+ - Encrypted archive handling:
397
+ - `--password` CLI option passes a passphrase upfront.
398
+ - If an archive turns out to be encrypted and no password was given, dirplot prompts
399
+ interactively (`Password:` hidden-input prompt) and retries — no need to re-run with a flag.
400
+ - A wrong password exits cleanly with `Error: incorrect password.`
401
+ - `PasswordRequired` exception exported from `dirplot.archives` for programmatic use.
402
+ - **Encryption behaviour by format** (since dirplot reads metadata only, never extracts):
403
+ - ZIP and 7z: central directory / file list is unencrypted by default → readable without
404
+ a password even for encrypted archives.
405
+ - RAR with header encryption (`-hp`): listing is hidden without password;
406
+ wrong password raises `PasswordRequired`.
407
+
408
+ ### Fixed
409
+
410
+ - `--version` moved back to the top-level `dirplot` command (was accidentally scoped
411
+ to `dirplot map` after the CLI was restructured into subcommands).
412
+
413
+ ## [0.3.0] - 2026-03-10
414
+
415
+ ### Added
416
+
417
+ - Kubernetes pod scanning via `pod://pod-name/path` syntax — uses `kubectl exec` and
418
+ `find` to build the tree without copying files out of the pod. Works on any running
419
+ pod that has a POSIX shell and `find` (GNU or BusyBox). No extra dependency; only
420
+ `kubectl` is required.
421
+ - Namespace can be specified inline (`pod://pod-name@namespace:/path`) or via
422
+ `--k8s-namespace`.
423
+ - Container can be selected for multi-container pods via `--k8s-container`.
424
+ - `-xdev` is intentionally omitted so mounted volumes (emptyDir, PVC, etc.) within
425
+ the scanned path are traversed — the common case in k8s where images declare
426
+ `VOLUME` entries that are always mounted on a separate filesystem.
427
+ - Automatically falls back to a portable `sh` + `stat` loop on BusyBox/Alpine pods.
428
+ - Docker container scanning via `docker://container:/path` syntax — uses `docker exec`
429
+ and `find` to build the tree without copying files out of the container. Works on any
430
+ running container that has a POSIX shell and `find` (GNU or BusyBox). No extra
431
+ dependency; only the `docker` CLI is required.
432
+ - Automatically detects BusyBox `find` (Alpine-based images) and falls back to a
433
+ portable `sh` + `stat` loop when GNU `-printf` is unavailable.
434
+ - Virtual filesystems (`/proc`, `/sys`, `/dev`) are skipped via `-xdev`.
435
+ - Supports `--exclude`, `--depth`, `--log`, and all other standard options.
436
+ - `Dockerfile` and `.dockerignore` added so the project itself can be used as a
437
+ scan target.
438
+ - SVG output format via `--format svg` or by saving to a `.svg`-suffixed path with `--output`.
439
+ The output is a fully self-contained, interactive SVG file:
440
+ - **CSS hover highlight** — file tiles brighten and gain a soft glow; directory headers
441
+ brighten on mouse-over (`.tile` / `.dir-tile` classes, no JavaScript needed).
442
+ - **Floating tooltip panel** — a JavaScript-driven semi-transparent panel tracks the cursor
443
+ and shows the file or directory name, human-readable size, and file-type / item count.
444
+ No external scripts or stylesheets — the panel logic is embedded in the SVG itself.
445
+ - **Van Wijk cushion shading** — approximated via a single diagonal `linearGradient`
446
+ overlay (`gradientUnits="objectBoundingBox"`), defined once and shared across all tiles.
447
+ Matches the ×1.20 highlight / ×0.80 shadow range of the PNG renderer.
448
+ Disabled with `--no-cushion`.
449
+ - `--format png|svg` CLI option; format is also auto-detected from the `--output` file
450
+ extension.
451
+ - `create_treemap_svg()` added to the public Python API (`from dirplot import create_treemap_svg`).
452
+ - `drawsvg>=2.4` added as a core dependency.
453
+ - Rename the treemap command to `map` (dirplot map <root>).
454
+ - Add `termsize` subcommand and restructure CLI as multi-command app.
455
+ - Add `--depht` parameter to limit the scanning of large file trees.
456
+ - Support for SSH remote directory scanning (`pip install dirplot[ssh]`).
457
+ - Support for AWS S3 buckets in the cloud (`pip install dirplot[s3]`).
458
+ - Support for local archive files, .zip, tgz, .tar.xz, .rar, .7z, etc.
459
+ - Include example archives for 17 different extentions for testing.
460
+ - Comprehensive documentation.
461
+ - `github://owner/repo[@branch]` URI scheme for GitHub repository scanning. The old
462
+ `github:owner/repo` shorthand has been removed.
463
+ - File tiles now have a 1-px dark outline (60/255 below fill colour per channel) so
464
+ adjacent same-coloured tiles — e.g. a directory full of extension-less files — are
465
+ always visually distinct rather than blending into a single flat block.
466
+
467
+ ### Changed
468
+
469
+ - `docs/REMOTE-ACCESS.md` renamed to `docs/EXAMPLES.md`; Docker and Kubernetes pod
470
+ sections added; images with captions added for all remote backends.
471
+
472
+ ### Fixed
473
+
474
+ - SVG tooltips now show the original byte count when `--log` is active, not the
475
+ log-transformed layout value. `Node.original_size` is populated by `apply_log_sizes`
476
+ for both file and directory nodes and is used by the SVG renderer for `data-size`.
477
+ - GitHub error messages are now clear and actionable.
478
+
479
+ ## [0.2.0] - 2026-03-09
480
+
481
+ ### Added
482
+
483
+ - Support for Windows, incl. full test suite
484
+
485
+ ### Fixed
486
+
487
+ - Improved README, Makefile
488
+
489
+ ## [0.1.2] - 2026-03-06
490
+
491
+ ### Fixed
492
+
493
+ - Partly incorrect `uvx install dirplot` command
494
+ - Wrong version number in `uv.lock`
495
+
496
+ ## [0.1.1] - 2026-03-06
497
+
498
+ ### Fixed
499
+
500
+ - Typing complaints
501
+ - Improved README with better install/run commands
502
+
503
+ ## [0.1.0] - 2026-03-06
504
+
505
+ ### Added
506
+
507
+ - Nested squarified treemap rendered as a PNG at the exact pixel dimensions of the terminal window.
508
+ - Inline terminal display via iTerm2 and Kitty graphics protocols, auto-detected at runtime; supports iTerm2, WezTerm, Warp, Hyper, Kitty, and Ghostty.
509
+ - System-viewer fallback (`open` / `xdg-open`) as the default display mode.
510
+ - File-extension colours from the GitHub Linguist palette (~500 known extensions); unknown extensions fall back to a stable MD5-derived colour from the chosen colormap.
511
+ - Van Wijk quadratic cushion shading giving each tile a raised 3-D look (`--cushion`, on by default).
512
+ - Bundled JetBrains Mono fonts for crisp directory labels at any size.
513
+ - CLI options: `--output`, `--show/--no-show`, `--inline`, `--legend`, `--font-size`, `--colormap`, `--exclude`, `--size`, `--header/--no-header`, `--cushion/--no-cushion`, `--log`.
514
+ - Full test suite (65 tests), strict mypy, ruff linting, pre-commit hooks, and CI on Python 3.10–3.13.
dirplot-0.4.1/LICENSE2 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dinu Gherman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.