# ljar — guide
> **Class:** `guide` · **Function:** `ljar`. Build, run, tune. The shape is in
> [`ljar-design.md`](ljar-design.md); the why in [`ljar-reasoning.md`](ljar-reasoning.md).
> The ZIP-superset twin is [`lzip-parallel-guide.md`](lzip-parallel-guide.md).
## Build
```sh
CARGO_TARGET_DIR=/mnt/work4t/cargo-target/zoomies cargo build --release -p ljar
```
Binary lands at `target/release/ljar`.
## Run
```sh
ljar app.jar # extract every entry into ./ (each its own file)
ljar app.jar -o out/ # extract into a target dir
ljar app.jar --filter pom.xml # only entries whose name contains the needle
```
Any file `jar`/`zip` wrote decodes — ljar reads the stock ZIP container (JAR ⊂ ZIP).
Entries are extracted to independent files by the parallel writer
(`gatling::parwrite::extract_entries_unordered`, `ljar/src/bin/ljar.rs:146`); a `--filter`
excludes non-matching entries at the Central Directory level, so they are never read or
inflated.
## Tune
- Worker count defaults to physical cores; the balanced fan-out self-dispatches with no
barrier, so a skewed archive still fills every core (heaviest entry claimed first).
- Streaming decode holds only one 64-entry batch of output live at a time
(`BATCH_SIZE`, `ljar/src/reader.rs:20`) — peak RAM stays bounded on huge JARs.
## Library
```rust
// in-memory decode (parallel; streams internally above 10 MB):
let entries = ljar::decompress_jar(&bytes)?; // ljar/src/lib.rs:65
// only entries containing a needle (filtered before inflate):
let poms = ljar::decompress_jar_filter(&bytes, "pom.xml")?; // ljar/src/lib.rs:83
// stream any Read+Seek without loading the file into RAM:
let f = std::fs::File::open("app.jar")?;
let entries: Vec<_> = ljar::decompress_jar_stream(f)?; // ljar/src/lib.rs:98
```
## Bench
Driven by nornir through the shared harness — see
[`decompressors-guide.md`](decompressors-guide.md#run-the-heavy-bake-off). HEAVY only
(no smoke): `nornir bench run znippy-zoomies`, then `nornir docs book znippy-zoomies`
to fill the A/B/C mashup.